|
36 | 36 |
|
37 | 37 | #include <TDirectory.h> |
38 | 38 | #include <TFile.h> |
| 39 | +#include <TFormula.h> |
39 | 40 | #include <TH1F.h> |
40 | 41 | #include <THn.h> |
41 | 42 | #include <TVector2.h> |
42 | 43 |
|
43 | 44 | #include <cmath> |
44 | 45 | #include <experimental/type_traits> |
| 46 | +#include <memory> |
45 | 47 | #include <string> |
46 | 48 | #include <tuple> |
47 | 49 | #include <utility> |
@@ -87,6 +89,8 @@ struct CorrelationTask { |
87 | 89 | O2_DEFINE_CONFIGURABLE(cfgCentBinsForMC, int, 0, "0 = OFF and 1 = ON for data like multiplicity/centrality bins for MC steps"); |
88 | 90 | O2_DEFINE_CONFIGURABLE(cfgTrackBitMask, uint16_t, 0, "BitMask for track selection systematics; refer to the enum TrackSelectionCuts in filtering task"); |
89 | 91 | 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 | + |
90 | 94 | // Suggested values: Photon: 0.004; K0 and Lambda: 0.005 |
91 | 95 | Configurable<LabeledArray<float>> cfgPairCut{"cfgPairCut", {kCfgPairCutDefaults[0], 5, {"Photon", "K0", "Lambda", "Phi", "Rho"}}, "Pair cuts on various particles"}; |
92 | 96 |
|
@@ -142,6 +146,9 @@ struct CorrelationTask { |
142 | 146 | std::vector<float> efficiencyAssociatedCache; |
143 | 147 | std::vector<int> p2indexCache; |
144 | 148 |
|
| 149 | + std::unique_ptr<TFormula> multCutFormula; |
| 150 | + std::array<uint, 4> multCutFormulaParamIndex; |
| 151 | + |
145 | 152 | struct Config { |
146 | 153 | bool mPairCuts = false; |
147 | 154 | THn* mEfficiencyTrigger = nullptr; |
@@ -184,11 +191,11 @@ struct CorrelationTask { |
184 | 191 | if (cfgMultCorrelationsMask & aod::cfmultset::CentFT0C) |
185 | 192 | multAxes.emplace_back(100, 0, 100, "FT0C centrality"); |
186 | 193 | if (cfgMultCorrelationsMask & aod::cfmultset::MultFV0A) |
187 | | - multAxes.emplace_back(100, 0, 100000, "V0A multiplicity"); |
| 194 | + multAxes.emplace_back(10000, 0, 100000, "V0A multiplicity"); |
188 | 195 | if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksPV) |
189 | | - multAxes.emplace_back(100, 0, 1000, "Nch PV"); |
| 196 | + multAxes.emplace_back(1000, 0, 1000, "Nch PV"); |
190 | 197 | if (cfgMultCorrelationsMask & aod::cfmultset::MultNTracksGlobal) |
191 | | - multAxes.emplace_back(100, 0, 1000, "Nch Global"); |
| 198 | + multAxes.emplace_back(1000, 0, 1000, "Nch Global"); |
192 | 199 | registry.add("multCorrelations", "Multiplicity correlations", {HistType::kTHnSparseF, multAxes}); |
193 | 200 | } |
194 | 201 | registry.add("multiplicity", "event multiplicity", {HistType::kTH1F, {{1000, 0, 100, "/multiplicity/centrality"}}}); |
@@ -218,6 +225,26 @@ struct CorrelationTask { |
218 | 225 |
|
219 | 226 | // --- OBJECT INIT --- |
220 | 227 |
|
| 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 | + |
221 | 248 | std::vector<AxisSpec> corrAxis = {{axisDeltaEta, "#Delta#eta"}, |
222 | 249 | {axisPtAssoc, "p_{T} (GeV/c)"}, |
223 | 250 | {axisPtTrigger, "p_{T} (GeV/c)"}, |
@@ -426,6 +453,24 @@ struct CorrelationTask { |
426 | 453 | template <class T> |
427 | 454 | using HasPartDaugh1Id = decltype(std::declval<T&>().cfParticleDaugh1Id()); |
428 | 455 |
|
| 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 | + |
429 | 474 | template <typename T> |
430 | 475 | std::tuple<bool, float> getV0Rapidity(const T& track) |
431 | 476 | { |
@@ -770,6 +815,7 @@ struct CorrelationTask { |
770 | 815 | template <class CollType, class TTracks1, class TTracks2> |
771 | 816 | void processSameDerivedT(CollType const& collision, TTracks1 const& tracks1, TTracks2 const& tracks2) |
772 | 817 | { |
| 818 | + using BinningTypeDerived = ColumnBinningPolicy<aod::collision::PosZ, aod::cfcollision::Multiplicity>; |
773 | 819 | BinningTypeDerived configurableBinningDerived{{axisVertex, axisMultiplicity}, true}; // true is for 'ignore overflows' (true by default). Underflows and overflows will have bin -1. |
774 | 820 | if (cfgVerbosity > 0) { |
775 | 821 | 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 { |
807 | 853 |
|
808 | 854 | void processSameDerivedMultSet(soa::Filtered<soa::Join<aod::CFCollisions, aod::CFMultSets>>::iterator const& collision, soa::Filtered<aod::CFTracks> const& tracks) |
809 | 855 | { |
| 856 | + if (!passOutlier(collision)) |
| 857 | + return; |
810 | 858 | processSameDerivedT(collision, tracks, tracks); |
811 | 859 | } |
812 | 860 | PROCESS_SWITCH(CorrelationTask, processSameDerivedMultSet, "Process same event on derived data with multiplicity sets", false); |
@@ -878,21 +926,32 @@ struct CorrelationTask { |
878 | 926 | } |
879 | 927 | PROCESS_SWITCH(CorrelationTask, processMixedAOD, "Process mixed events on AOD", false); |
880 | 928 |
|
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) |
885 | 931 | { |
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 |
888 | 946 | auto tracksTuple = std::make_tuple(std::forward<TrackTypes>(tracks)...); |
889 | 947 | using TA = std::tuple_element<0, decltype(tracksTuple)>::type; |
890 | 948 | 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 |
892 | 950 |
|
893 | 951 | for (auto it = pairs.begin(); it != pairs.end(); it++) { |
894 | 952 | 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)); |
896 | 955 | float eventWeight = 1.0f / it.currentWindowNeighbours(); |
897 | 956 | int field = 0; |
898 | 957 | if (cfgTwoTrackCut > 0) { |
@@ -930,6 +989,12 @@ struct CorrelationTask { |
930 | 989 | } |
931 | 990 | PROCESS_SWITCH(CorrelationTask, processMixedDerived, "Process mixed events on derived data", false); |
932 | 991 |
|
| 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 | + |
933 | 998 | void processMixed2ProngDerived(DerivedCollisions const& collisions, DerivedTracks const& tracks, soa::Filtered<aod::CF2ProngTracks> const& p2tracks) |
934 | 999 | { |
935 | 1000 | processMixedDerivedT(collisions, p2tracks, tracks); |
|
0 commit comments