Skip to content

Commit 2ad8976

Browse files
authored
[PWGCF] CF task multiplicity correlations and outlier cuts (#12631)
1 parent 288f0f5 commit 2ad8976

File tree

1 file changed

+76
-11
lines changed

1 file changed

+76
-11
lines changed

PWGCF/Tasks/correlations.cxx

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@
3636

3737
#include <TDirectory.h>
3838
#include <TFile.h>
39+
#include <TFormula.h>
3940
#include <TH1F.h>
4041
#include <THn.h>
4142
#include <TVector2.h>
4243

4344
#include <cmath>
4445
#include <experimental/type_traits>
46+
#include <memory>
4547
#include <string>
4648
#include <tuple>
4749
#include <utility>
@@ -87,6 +89,8 @@ struct CorrelationTask {
8789
O2_DEFINE_CONFIGURABLE(cfgCentBinsForMC, int, 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC steps");
8890
O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task");
8991
O2_DEFINE_CONFIGURABLE(cfgMultCorrelationsMask, uint16_t, 0, "Selection bitmask for the multiplicity correlations. This should match the filter selection cfgEstimatorBitMask.")
92+
O2_DEFINE_CONFIGURABLE(cfgMultCutFormula, std::string, "", "Multiplicity correlations cut formula. A result greater than zero results in accepted event. Parameters: [cFT0C] FT0C centrality, [mFV0A] V0A multiplicity, [mGlob] global track multiplicity, [mPV] PV track multiplicity")
93+
9094
// Suggested values: Photon: 0.004; K0 and Lambda: 0.005
9195
Configurable<LabeledArray<float>> cfgPairCut{"cfgPairCut", {kCfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"};
9296

@@ -142,6 +146,9 @@ struct CorrelationTask {
142146
std::vector<float> efficiencyAssociatedCache;
143147
std::vector<int> p2indexCache;
144148

149+
std::unique_ptr<TFormula> multCutFormula;
150+
std::array<uint, 4> multCutFormulaParamIndex;
151+
145152
struct Config {
146153
bool mPairCuts = false;
147154
THn* mEfficiencyTrigger = nullptr;
@@ -184,11 +191,11 @@ struct CorrelationTask {
184191
if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C)
185192
multAxes.emplace_back(100, 0, 100, "FT0C centrality");
186193
if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A)
187-
multAxes.emplace_back(100, 0, 100000, "V0A multiplicity");
194+
multAxes.emplace_back(10000, 0, 100000, "V0A multiplicity");
188195
if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV)
189-
multAxes.emplace_back(100, 0, 1000, "Nch PV");
196+
multAxes.emplace_back(1000, 0, 1000, "Nch PV");
190197
if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal)
191-
multAxes.emplace_back(100, 0, 1000, "Nch Global");
198+
multAxes.emplace_back(1000, 0, 1000, "Nch Global");
192199
registry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes});
193200
}
194201
registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}});
@@ -218,6 +225,26 @@ struct CorrelationTask {
218225

219226
// --- OBJECT INIT ---
220227

228+
if (!cfgMultCutFormula.value.empty()) {
229+
multCutFormula = std::make_unique<TFormula>("multCutFormula", cfgMultCutFormula.value.c_str());
230+
std::fill_n(multCutFormulaParamIndex.begin(), std::size(multCutFormulaParamIndex), ~0u);
231+
std::array<std::string, 4> pars = {"cFT0C", "mFV0A", "mPV", "mGlob"}; // must correspond the order of MultiplicityEstimators
232+
for (uint i = 0, n = multCutFormula->GetNpar(); i < n; ++i) {
233+
auto m = std::find(pars.begin(), pars.end(), multCutFormula->GetParName(i));
234+
if (m == pars.end()) {
235+
236+
LOGF(warning, "Unknown parameter in cfgMultCutFormula: %s", multCutFormula->GetParName(i));
237+
continue;
238+
}
239+
if ((cfgMultCorrelationsMask.value & (1u << i)) == 0) {
240+
LOGF(warning, "The centrality/multiplicity estimator %s is not available to be used in cfgMultCutFormula. Ensure cfgMultCorrelationsMask is correct and matches the CFMultSets in derived data.");
241+
} else {
242+
multCutFormulaParamIndex[std::distance(pars.begin(), m)] = i;
243+
LOGF(info, "Multiplicity cut parameter %s in use.", m->c_str());
244+
}
245+
}
246+
}
247+
221248
std::vector<AxisSpec> corrAxis = {{axisDeltaEta, "#Delta#eta"},
222249
{axisPtAssoc, "p_{T} (GeV/c)"},
223250
{axisPtTrigger, "p_{T} (GeV/c)"},
@@ -426,6 +453,24 @@ struct CorrelationTask {
426453
template <class T>
427454
using HasPartDaugh1Id = decltype(std::declval<T&>().cfParticleDaugh1Id());
428455

456+
/*
457+
OO outlier cut (requires mask 15):
458+
(567.785+172.715*[mGlob]+0.77888*[mGlob]*[mGlob]+-0.00693466*[mGlob]*[mGlob]*[mGlob]+1.40564e-05*[mGlob]*[mGlob]*[mGlob]*[mGlob] + 3.5*(679.853+66.8068*[mGlob]+-0.444332*[mGlob]*[mGlob]+0.00115002*[mGlob]*[mGlob]*[mGlob]+-4.92064e-07*[mGlob]*[mGlob]*[mGlob]*[mGlob])) > [mFV0A] && (567.785+172.715*[mGlob]+0.77888*[mGlob]*[mGlob]+-0.00693466*[mGlob]*[mGlob]*[mGlob]+1.40564e-05*[mGlob]*[mGlob]*[mGlob]*[mGlob] - 3.0*(679.853+66.8068*[mGlob]+-0.444332*[mGlob]*[mGlob]+0.00115002*[mGlob]*[mGlob]*[mGlob]+-4.92064e-07*[mGlob]*[mGlob]*[mGlob]*[mGlob])) < [mFV0A] && (172.406 + -4.50219*[cFT0C] + 0.0543038*[cFT0C]*[cFT0C] + -0.000373213*[cFT0C]*[cFT0C]*[cFT0C] + 1.15322e-06*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] + 4.0*(49.7503 + -1.29008*[cFT0C] + 0.0160059*[cFT0C]*[cFT0C] + -7.86846e-05*[cFT0C]*[cFT0C]*[cFT0C])) > [mPV] && (172.406 + -4.50219*[cFT0C] + 0.0543038*[cFT0C]*[cFT0C] + -0.000373213*[cFT0C]*[cFT0C]*[cFT0C] + 1.15322e-06*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] - 2.5*(49.7503 + -1.29008*[cFT0C] + 0.0160059*[cFT0C]*[cFT0C] + -7.86846e-05*[cFT0C]*[cFT0C]*[cFT0C])) < [mPV] && (125.02 + -3.30255*[cFT0C] + 0.0398663*[cFT0C]*[cFT0C] + -0.000271942*[cFT0C]*[cFT0C]*[cFT0C] + 8.34098e-07*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] + 4.0*(37.0244 + -0.949883*[cFT0C] + 0.0116622*[cFT0C]*[cFT0C] + -5.71117e-05*[cFT0C]*[cFT0C]*[cFT0C])) > [mGlob] && (125.02 + -3.30255*[cFT0C] + 0.0398663*[cFT0C]*[cFT0C] + -0.000271942*[cFT0C]*[cFT0C]*[cFT0C] + 8.34098e-07*[cFT0C]*[cFT0C]*[cFT0C]*[cFT0C] - 2.5*(37.0244 + -0.949883*[cFT0C] + 0.0116622*[cFT0C]*[cFT0C] + -5.71117e-05*[cFT0C]*[cFT0C]*[cFT0C])) < [mGlob] && (-0.223013 + 0.715849*[mPV] + 3*(0.664242 + 0.0829653*[mPV] + -0.000503733*[mPV]*[mPV] + 1.21185e-06*[mPV]*[mPV]*[mPV])) > [mGlob]
459+
*/
460+
template <class CollType>
461+
bool passOutlier(CollType const& collision)
462+
{
463+
if (cfgMultCutFormula.value.empty())
464+
return true;
465+
for (uint i = 0; i < 4; ++i) {
466+
if ((cfgMultCorrelationsMask.value & (1u << i)) == 0 || multCutFormulaParamIndex[i] == ~0u)
467+
continue;
468+
auto estIndex = std::popcount(cfgMultCorrelationsMask.value & ((1u << i) - 1));
469+
multCutFormula->SetParameter(multCutFormulaParamIndex[i], collision.multiplicities()[estIndex]);
470+
}
471+
return multCutFormula->Eval() > 0.0f;
472+
}
473+
429474
template <typename T>
430475
std::tuple<bool, float> getV0Rapidity(const T& track)
431476
{
@@ -770,6 +815,7 @@ struct CorrelationTask {
770815
template <class CollType, class TTracks1, class TTracks2>
771816
void processSameDerivedT(CollType const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2)
772817
{
818+
using BinningTypeDerived = ColumnBinningPolicy<aod::collision::PosZ, aod::cfcollision::Multiplicity>;
773819
BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1.
774820
if (cfgVerbosity > 0) {
775821
LOGF(info, "processSameDerivedT: Tracks for collision: %d/%d | Vertex: %.1f | Multiplicity/Centrality: %.1f", tracks1.size(), tracks2.size(), collision.posZ(), collision.multiplicity());
@@ -807,6 +853,8 @@ struct CorrelationTask {
807853

808854
void processSameDerivedMultSet(soa::Filtered<soa::Join<aod::CFCollisions, aod::CFMultSets>>::iterator const& collision, soa::Filtered<aod::CFTracks> const& tracks)
809855
{
856+
if (!passOutlier(collision))
857+
return;
810858
processSameDerivedT(collision, tracks, tracks);
811859
}
812860
PROCESS_SWITCH(CorrelationTask, processSameDerivedMultSet, "Process same event on derived data with multiplicity sets", false);
@@ -878,21 +926,32 @@ struct CorrelationTask {
878926
}
879927
PROCESS_SWITCH(CorrelationTask, processMixedAOD, "Process mixed events on AOD", false);
880928

881-
using BinningTypeDerived = ColumnBinningPolicy<aod::collision::PosZ, aod::cfcollision::Multiplicity>;
882-
883-
template <typename... TrackTypes>
884-
void processMixedDerivedT(DerivedCollisions const& collisions, TrackTypes&&... tracks)
929+
template <class CollType, typename... TrackTypes>
930+
void processMixedDerivedT(CollType const& collisions, TrackTypes&&... tracks)
885931
{
886-
BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1.
887-
// Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1
932+
auto getMultiplicity =
933+
[this](auto& col) {
934+
if constexpr (std::experimental::is_detected<HasMultSet, CollType>::value) {
935+
if (!passOutlier(col))
936+
return -1.0f;
937+
} else {
938+
(void)this; // fix compile error on unused 'this' capture
939+
}
940+
return col.multiplicity();
941+
};
942+
943+
using BinningTypeDerived = FlexibleBinningPolicy<std::tuple<decltype(getMultiplicity)>, aod::collision::PosZ, decltype(getMultiplicity)>;
944+
BinningTypeDerived configurableBinningDerived{{getMultiplicity}, {axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1.
945+
// Strictly upper categorised collisions, for cfgNoMixedEvents combinations per bin, skipping those in entry -1
888946
auto tracksTuple = std::make_tuple(std::forward<TrackTypes>(tracks)...);
889947
using TA = std::tuple_element<0, decltype(tracksTuple)>::type;
890948
using TB = std::tuple_element<std::tuple_size_v<decltype(tracksTuple)> - 1, decltype(tracksTuple)>::type;
891-
Pair<DerivedCollisions, TA, TB, BinningTypeDerived> pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip
949+
Pair<CollType, TA, TB, BinningTypeDerived> pairs{configurableBinningDerived, cfgNoMixedEvents, -1, collisions, tracksTuple, &cache}; // -1 is the number of the bin to skip
892950

893951
for (auto it = pairs.begin(); it != pairs.end(); it++) {
894952
auto& [collision1, tracks1, collision2, tracks2] = *it;
895-
int bin = configurableBinningDerived.getBin({collision1.posZ(), collision1.multiplicity()});
953+
float multiplicity = getMultiplicity(collision1);
954+
int bin = configurableBinningDerived.getBin(std::tuple(collision1.posZ(), multiplicity));
896955
float eventWeight = 1.0f / it.currentWindowNeighbours();
897956
int field = 0;
898957
if (cfgTwoTrackCut > 0) {
@@ -930,6 +989,12 @@ struct CorrelationTask {
930989
}
931990
PROCESS_SWITCH(CorrelationTask, processMixedDerived, "Process mixed events on derived data", false);
932991

992+
void processMixedDerivedMultSet(soa::Filtered<soa::Join<aod::CFCollisions, aod::CFMultSets>> const& collisions, DerivedTracks const& tracks)
993+
{
994+
processMixedDerivedT(collisions, tracks);
995+
}
996+
PROCESS_SWITCH(CorrelationTask, processMixedDerivedMultSet, "Process mixed events on derived data with multiplicity sets", false);
997+
933998
void processMixed2ProngDerived(DerivedCollisions const& collisions, DerivedTracks const& tracks, soa::Filtered<aod::CF2ProngTracks> const& p2tracks)
934999
{
9351000
processMixedDerivedT(collisions, p2tracks, tracks);

0 commit comments

Comments
 (0)