|
25 | 25 | #include <Framework/AnalysisDataModel.h> |
26 | 26 | #include <Framework/AnalysisHelpers.h> |
27 | 27 | #include <Framework/AnalysisTask.h> |
28 | | -#include <Framework/Concepts.h> |
29 | 28 | #include <Framework/Configurable.h> |
30 | 29 | #include <Framework/HistogramRegistry.h> |
31 | 30 | #include <Framework/HistogramSpec.h> |
32 | 31 | #include <Framework/InitContext.h> |
| 32 | +#include <Framework/Logger.h> |
33 | 33 | #include <Framework/runDataProcessing.h> |
34 | 34 |
|
35 | 35 | #include <TH1.h> |
|
48 | 48 | #include <map> |
49 | 49 | #include <string_view> |
50 | 50 | #include <unordered_map> |
| 51 | +#include <unordered_set> |
51 | 52 | #include <vector> |
52 | 53 |
|
53 | 54 | using namespace o2; |
@@ -97,6 +98,10 @@ struct AssociateMCInfoPhoton { |
97 | 98 | 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!"}; |
98 | 99 | Configurable<bool> useIsEOI{"useIsEOI", true, "flag to enable the usage of the EOI table"}; |
99 | 100 |
|
| 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 | + |
100 | 105 | HistogramRegistry registry{"EMMCEvent"}; |
101 | 106 |
|
102 | 107 | void init(o2::framework::InitContext&) |
@@ -133,6 +138,19 @@ struct AssociateMCInfoPhoton { |
133 | 138 | registry.add<TH2>(Form("Generated/h2PtY_Accepted_%s", ParticleNames[i].data()), Form("Generated %s", ParticleNames[i].data()), kTH2F, {axisPt, axisRapidity}, true); |
134 | 139 | } |
135 | 140 |
|
| 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 | + |
136 | 154 | // reserve space for generated vectors if that process enabled |
137 | 155 | auto hBinFinder = registry.get<TH2>(HIST("Generated/h2PtY_Pi0")); |
138 | 156 | LOGF(info, "Binned generated processing enabled. Initialising with %i elements...", hBinFinder->GetNcells()); |
@@ -230,6 +248,108 @@ struct AssociateMCInfoPhoton { |
230 | 248 | } // end of mother chain loop |
231 | 249 | } |
232 | 250 |
|
| 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 | + |
233 | 353 | template <uint8_t system, typename TTracks, typename TFwdTracks, typename TPCMs, typename TPCMLegs, typename TPHOSs, typename TEMCs, typename TEMPrimaryElectrons> |
234 | 354 | 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) |
235 | 355 | { |
@@ -258,6 +378,33 @@ struct AssociateMCInfoPhoton { |
258 | 378 | // mc collision iter |
259 | 379 | auto mcCollisionIter = mcCollisions.begin(); |
260 | 380 |
|
| 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 | + |
261 | 408 | for (const auto& collision : collisions) { |
262 | 409 | registry.fill(HIST("hEventCounter"), 1); |
263 | 410 |
|
@@ -320,6 +467,9 @@ struct AssociateMCInfoPhoton { |
320 | 467 |
|
321 | 468 | // make an entry for this MC event only if it was not already added to the table |
322 | 469 | if (!fEventLabels.contains(mcCollisionIter.globalIndex())) { |
| 470 | + if (fillBremsChain) { |
| 471 | + fillBremsChainTruth(groupedMcParticles, mcParticles, recoPhotons); |
| 472 | + } |
323 | 473 | mcevents(mcCollisionIter.globalIndex(), mcCollisionIter.generatorsID(), mcCollisionIter.posX(), mcCollisionIter.posY(), mcCollisionIter.posZ(), mcCollisionIter.impactParameter(), mcCollisionIter.eventPlaneAngle()); |
324 | 474 | fEventLabels[mcCollisionIter.globalIndex()] = fCounter.events; |
325 | 475 | fCounter.events++; |
|
0 commit comments