Skip to content

Commit c1d81ff

Browse files
committed
Add poissonian sampling of efficiency to corrected multiplicity estimate
1 parent c49c25a commit c1d81ff

1 file changed

Lines changed: 36 additions & 6 deletions

File tree

‎PWGCF/TableProducer/filterCorrelations.cxx‎

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include <experimental/type_traits> // required for is_detected
5656
#include <limits>
5757
#include <memory>
58+
#include <random>
5859
#include <string>
5960
#include <type_traits>
6061
#include <vector>
@@ -120,6 +121,8 @@ struct FilterCF {
120121
O2_DEFINE_CONFIGURABLE(cfgEfficiencyMultiplicity, std::string, "", "Multiplicity efficiency (RecoAll / MC): CCDB path or local ROOT file with a 4D ccdb_object (eta, pT, multiplicity, z-vtx); empty disables CFCollisionsExtra output");
121122
O2_DEFINE_CONFIGURABLE(cfgLocalEfficiency, int, 0, "0 = CCDB efficiency, 1 = local ROOT efficiency");
122123
O2_DEFINE_CONFIGURABLE(cfgMultiplicityTrackBitMask, uint16_t, 0, "Required track-type bits for corrected multiplicity; match cfgTrackBitMask used to produce the efficiency (0 = all stored tracks)");
124+
O2_DEFINE_CONFIGURABLE(cfgMultiplicityPoisson, bool, false, "Use (reproducibly) seeded 1 + Poisson(sum(1/eff - 1)) for multiplicity correction; skips eff > 1 tracks");
125+
O2_DEFINE_CONFIGURABLE(cfgMultiplicityPoissonSeed, uint32_t, 1, "Base seed for reproducible per-collision Poisson multiplicity sampling");
123126

124127
// Filters and input definitions
125128
Filter collisionZVtxFilter = nabs(aod::collision::posZ) < cfgCutVertex;
@@ -160,6 +163,7 @@ struct FilterCF {
160163
// Own local histograms independently of their input file. CCDB owns its objects.
161164
std::unique_ptr<THn> localMultiplicityEfficiency;
162165
THn* mEfficiency = nullptr;
166+
std::mt19937_64 mMultiplicityGenerator;
163167
static constexpr int MultiplicityEfficiencyDimensions = 4;
164168

165169
// persistent caches
@@ -389,11 +393,12 @@ struct FilterCF {
389393
}
390394

391395
template <typename TCollision, typename TTracks>
392-
float getCorrectedMultiplicity(const TCollision& collision, const TTracks& tracks, uint64_t timestamp)
396+
float getCorrectedMultiplicity(const TCollision& collision, const TTracks& tracks, uint64_t timestamp, uint64_t globalBC, int runNumber)
393397
{
394398
auto* efficiency = loadMultiplicityEfficiency(timestamp);
395399
double correctedMultiplicity = 0.;
396400
size_t skippedTracks = 0;
401+
double totalMeanMissing = 0.;
397402
for (const auto& track : tracks) {
398403
// Match the tracks written by the corresponding data/MC producer path.
399404
if (!isTrackSelected(track, true)) {
@@ -403,14 +408,39 @@ struct FilterCF {
403408
// Keep the original estimator as the map coordinate, including for centrality.
404409
const std::array<double, MultiplicityEfficiencyDimensions> values{track.eta(), track.pt(), collision.multiplicity(), collision.posZ()};
405410
const double eff = efficiency->GetBinContent(efficiency->GetBin(values.data()));
406-
if (!std::isfinite(eff) || eff <= 0.) {
411+
if (!std::isfinite(eff) || eff <= 0. || (cfgMultiplicityPoisson && eff > 1.)) {
407412
++skippedTracks;
408413
continue;
409414
}
410-
correctedMultiplicity += 1. / eff;
415+
if (cfgMultiplicityPoisson) {
416+
correctedMultiplicity += 1.;
417+
totalMeanMissing += 1. / eff - 1.;
418+
} else {
419+
correctedMultiplicity += 1. / eff;
420+
}
421+
}
422+
if (cfgMultiplicityPoisson) {
423+
if (!std::isfinite(totalMeanMissing) || totalMeanMissing >= static_cast<double>(std::numeric_limits<uint64_t>::max())) {
424+
LOGF(fatal, "Poisson multiplicity mean exceeds the sampling range: %g", totalMeanMissing);
425+
return 0.f;
426+
}
427+
// Sample from sum of missing count (Poisson sum rule)
428+
if (totalMeanMissing > 0.) {
429+
// Reseed per collision
430+
const auto collisionIndex = static_cast<uint64_t>(collision.globalIndex());
431+
std::seed_seq seed{cfgMultiplicityPoissonSeed.value, static_cast<uint32_t>(runNumber),
432+
static_cast<uint32_t>(globalBC), static_cast<uint32_t>(globalBC >> 32),
433+
static_cast<uint32_t>(collisionIndex), static_cast<uint32_t>(collisionIndex >> 32)};
434+
// Speed up the seeding by creating one 64bit seed from the event information
435+
std::array<uint32_t, 2> seedWords{};
436+
seed.generate(seedWords.begin(), seedWords.end());
437+
const uint64_t eventSeed = (static_cast<uint64_t>(seedWords[0]) << std::numeric_limits<uint32_t>::digits) | seedWords[1];
438+
mMultiplicityGenerator.seed(eventSeed);
439+
correctedMultiplicity += std::poisson_distribution<uint64_t>(totalMeanMissing)(mMultiplicityGenerator);
440+
}
411441
}
412442
if (cfgVerbosity > 0 && skippedTracks > 0) {
413-
LOGF(warning, "Skipped %zu tracks with invalid efficiency while correcting collision %lld", skippedTracks, static_cast<int64_t>(collision.globalIndex()));
443+
LOGF(warning, "Skipped %zu tracks with invalid or unsupported efficiency while correcting collision %lld", skippedTracks, static_cast<int64_t>(collision.globalIndex()));
414444
}
415445
if (!std::isfinite(correctedMultiplicity) || correctedMultiplicity > std::numeric_limits<float>::max()) {
416446
LOGF(fatal, "Corrected multiplicity cannot be represented as a float: %g", correctedMultiplicity);
@@ -454,7 +484,7 @@ struct FilterCF {
454484
auto bc = collision.template bc_as<aod::BCsWithTimestamps>();
455485
outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp());
456486
if (!cfgEfficiencyMultiplicity.value.empty()) {
457-
outputCollisionsExtra(getCorrectedMultiplicity(collision, tracks, bc.timestamp()));
487+
outputCollisionsExtra(getCorrectedMultiplicity(collision, tracks, bc.timestamp(), bc.globalBC(), bc.runNumber()));
458488
}
459489

460490
if constexpr (std::experimental::is_detected<HasMultTables, C1>::value) {
@@ -652,7 +682,7 @@ struct FilterCF {
652682
// NOTE works only when we store all MC collisions (as we do here)
653683
outputCollisions(bc.runNumber(), collision.posZ(), collision.multiplicity(), bc.timestamp());
654684
if (!cfgEfficiencyMultiplicity.value.empty()) {
655-
outputCollisionsExtra(getCorrectedMultiplicity(collision, groupedTracks, bc.timestamp()));
685+
outputCollisionsExtra(getCorrectedMultiplicity(collision, groupedTracks, bc.timestamp(), bc.globalBC(), bc.runNumber()));
656686
}
657687

658688
const auto mcCollisionId = collision.mcCollisionId();

0 commit comments

Comments
 (0)