3838
3939#include < algorithm>
4040#include < cmath>
41+ #include < limits>
4142#include < string>
4243#include < vector>
4344
@@ -95,6 +96,32 @@ struct TrackEfficiency {
9596
9697 Configurable<bool > useTrueTrackWeight{" useTrueTrackWeight" , true , " test configurable, should be set to 1 then config removed once well tested" };
9798
99+ // Normalization FT0 by means
100+ struct FT0A : ConfigurableGroup {
101+ std::string prefix = " ft0a" ;
102+ Configurable<float > mean{" mean" , 3499 ., " Mean FT0A signal" };
103+ Configurable<float > meanMCDetLevel{" meanMCDetLevel" , 2640 ., " Mean FT0A signal at MC detector level" };
104+ } ft0a;
105+
106+ struct FT0C : ConfigurableGroup {
107+ std::string prefix = " ft0c" ;
108+ Configurable<float > mean{" mean" , 844.6 , " Mean FT0C signal" };
109+ Configurable<float > meanMCDetLevel{" meanMCDetLevel" , 802.9 , " Mean FT0C signal at MC detector level" };
110+ } ft0c;
111+
112+ // FT0C event activity thresholds
113+ struct Hist : ConfigurableGroup {
114+ std::string prefix = " hist" ;
115+
116+ // Raw data
117+ ConfigurableAxis multFT0CThresh{" multFT0CThresh" , {VARIABLE_WIDTH , 0.0 , 0.109421 , 0.215022 , 0.343214 , 0.50515 , 0.712277 , 0.978245 , 1.3189 , 1.75744 , 2.36001 , 3.59696 , 25 .}, " Percentiles of scaled FT0C: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%" };
118+ ConfigurableAxis multFT0MThresh{" multFT0MThresh" , {VARIABLE_WIDTH , 0.0 , 0.130987 , 0.237916 , 0.36664 , 0.528441 , 0.734705 , 0.996611 , 1.32785 , 1.74896 , 2.31024 , 3.37852 , 25 .}, " Percentiles of scaled FT0M: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%" };
119+
120+ // MC detector-level data
121+ ConfigurableAxis multFT0CThreshMCDetLevel{" multFT0CThreshMCDetLevel" , {VARIABLE_WIDTH , 0.0 , 0.124992 , 0.243769 , 0.380291 , 0.543998 , 0.748078 , 1.00424 , 1.3237 , 1.72648 , 2.27373 , 3.43144 , 25 .}, " Percentiles of scaled FT0C: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%" };
122+ ConfigurableAxis multFT0MThreshMCDetLevel{" multFT0MThreshMCDetLevel" , {VARIABLE_WIDTH , 0.0 , 0.142622 , 0.262095 , 0.397069 , 0.558622 , 0.762008 , 1.01685 , 1.33219 , 1.72377 , 2.24008 , 3.26309 , 25 .}, " Percentiles of scaled FT0M: 100%, 90%, 80%, 70%, 60%, 50%, 40%, 30%, 20%, 10%, 1%" };
123+ } hist;
124+
98125 // systematics variation - Run 2 guidelines: https://twiki.cern.ch/twiki/bin/view/ALICE/AliDPGtoolsTrackSystematicUncertainty
99126 TrackSelection customTrackSelection;
100127 Configurable<bool > useCustomTrackSelection{" useCustomTrackSelection" , false , " whether to use the custom cuts (used for cut variation for tracking efficiency systematics)" };
@@ -117,6 +144,11 @@ struct TrackEfficiency {
117144 SplitOkCheckFirstAssocCollOnly // 2
118145 };
119146
147+ enum class TrackSample {
148+ Data,
149+ MCDetLevel
150+ };
151+
120152 template <typename TJetTrack>
121153 bool isAcceptedTrack (TJetTrack const & jetTrack)
122154 {
@@ -147,19 +179,20 @@ struct TrackEfficiency {
147179 return std::abs (charge) >= chargeUnit;
148180 }
149181
150- template <typename TCollision, typename TJetTracks>
182+ template <TrackSample sample, typename TCollision, typename TJetTracks>
151183 void fillTrackHistograms (TCollision const & collision, TJetTracks const & jetTracks, float weight = 1.0 )
152184 {
185+ const float meanFT0A = sample == TrackSample::Data ? ft0a.mean .value : ft0a.meanMCDetLevel .value ;
186+ const float meanFT0C = sample == TrackSample::Data ? ft0c.mean .value : ft0c.meanMCDetLevel .value ;
187+ const auto ft0Metrics = getFT0Metrics (collision, meanFT0A, meanFT0C);
188+ const auto scaledFT0C = ft0Metrics.scaledFT0C ;
189+ const auto scaledFT0M = ft0Metrics.scaledFT0M ;
190+
153191 for (auto const & track : jetTracks) {
154192 if (!isAcceptedTrack (track)) {
155193 continue ;
156194 }
157195
158- float pTHat = simPtRef / (std::pow (weight, 1.0 / pTHatExponent));
159- if (track.pt () > pTHatMaxFractionMCD * pTHat) {
160- continue ;
161- }
162-
163196 float centrality = checkCentFT0M ? collision.centFT0M () : collision.centFT0C ();
164197
165198 registry.fill (HIST (" h2_centrality_track_pt" ), centrality, track.pt (), weight);
@@ -172,6 +205,14 @@ struct TrackEfficiency {
172205 registry.fill (HIST (" h2_track_pt_high_track_sigmapt" ), track.pt (), track.sigma1Pt () * track.pt (), weight);
173206 registry.fill (HIST (" h3_intrate_centrality_track_pt" ), collision.hadronicRate (), centrality, track.pt (), weight);
174207 registry.fill (HIST (" h3_track_pt_track_eta_track_phi" ), track.pt (), track.eta (), track.phi (), weight);
208+
209+ if constexpr (sample == TrackSample::Data) {
210+ registry.fill (HIST (" hScaledFT0CTrackPt" ), scaledFT0C, track.pt (), weight);
211+ registry.fill (HIST (" hScaledFT0MTrackPt" ), scaledFT0M, track.pt (), weight);
212+ } else {
213+ registry.fill (HIST (" hScaledFT0CTrackPt_MCDetLevel" ), scaledFT0C, track.pt (), weight);
214+ registry.fill (HIST (" hScaledFT0MTrackPt_MCDetLevel" ), scaledFT0M, track.pt (), weight);
215+ }
175216 }
176217 }
177218
@@ -205,6 +246,12 @@ struct TrackEfficiency {
205246 LOGP (fatal, " Configurable acceptSplitCollisions has wrong input value; stopping workflow" );
206247 }
207248
249+ constexpr float minFT0Mean = std::numeric_limits<float >::epsilon ();
250+ if (std::fabs (ft0a.mean .value ) <= minFT0Mean || std::fabs (ft0c.mean .value ) <= minFT0Mean ||
251+ std::fabs (ft0a.meanMCDetLevel .value ) <= minFT0Mean || std::fabs (ft0c.meanMCDetLevel .value ) <= minFT0Mean) {
252+ LOGP (fatal, " FT0A and FT0C means must have magnitude greater than {} to avoid near-zero denominators; stopping workflow" , minFT0Mean);
253+ }
254+
208255 eventSelectionBits = jetderiveddatautilities::initialiseEventSelectionBits (static_cast <std::string>(eventSelections));
209256 trackSelection = jetderiveddatautilities::initialiseTrackSelection (static_cast <std::string>(trackSelections));
210257
@@ -254,6 +301,10 @@ struct TrackEfficiency {
254301 AxisSpec etaAxisEff{etaEffBinning, " #eta" };
255302 AxisSpec phiAxisEff{phiEffBinning, " #phi" };
256303 AxisSpec centAxis = {centralityBinning, " centrality (%)" };
304+ AxisSpec scaledFT0C{hist.multFT0CThresh , " FT0C / #LT FT0C #GT" };
305+ AxisSpec scaledFT0M{hist.multFT0MThresh , " FT0M^{*}" };
306+ AxisSpec scaledFT0CMCDetLevel{hist.multFT0CThreshMCDetLevel , " FT0C / #LT FT0C #GT" };
307+ AxisSpec scaledFT0MMCDetLevel{hist.multFT0MThreshMCDetLevel , " FT0M^{*}" };
257308 AxisSpec intRateAxis = {intRateBinning, " int. rate (kHz)" };
258309 AxisSpec occupancyAxis = {140 , -0.5 , 13999.5 , " occupancy" };
259310 AxisSpec nTracksAxis = {16001 , -1 ., 16000 , " n tracks" };
@@ -346,6 +397,12 @@ struct TrackEfficiency {
346397 registry.add (" h2_track_pt_high_track_sigma1overpt" , " #sigma(1/#it{p}_{T}); #it{p}_{T,track} (GeV/#it{c})" , {HistType::kTH2F , {{90 , 10 ., 100 .}, {10000 , 0.0 , 1.0 }}});
347398 registry.add (" h3_intrate_centrality_track_pt" , " interaction rate vs centrality vs track pT; int. rate; centrality; #it{p}_{T,track} (GeV/#it{c})" , {HistType::kTH3F , {intRateAxis, centAxis, {200 , 0 ., 200 .}}});
348399 registry.add (" h3_track_pt_track_eta_track_phi" , " track pT vs track #eta vs track #varphi; #it{p}_{T,track} (GeV/#it{c}); #eta_{track}; #varphi_{track}" , {HistType::kTH3F , {{200 , 0 ., 200 .}, {100 , -1.0 , 1.0 }, {160 , -1.0 , 7 .}}});
400+
401+ // EA analysis
402+ registry.add (" hScaledFT0CTrackPt" , " scaled FT0C vs track pT; FT0C / #LT FT0C #GT; #it{p}_{T,track} (GeV/#it{c})" , {HistType::kTH2F , {scaledFT0C, {200 , 0 ., 200 .}}});
403+ registry.add (" hScaledFT0MTrackPt" , " scaled FT0M vs track pT; FT0M^{*}; #it{p}_{T,track} (GeV/#it{c})" , {HistType::kTH2F , {scaledFT0M, {200 , 0 ., 200 .}}});
404+ registry.add (" hScaledFT0CTrackPt_MCDetLevel" , " MC detector-level scaled FT0C vs track pT; FT0C / #LT FT0C #GT; #it{p}_{T,track} (GeV/#it{c})" , {HistType::kTH2F , {scaledFT0CMCDetLevel, {200 , 0 ., 200 .}}});
405+ registry.add (" hScaledFT0MTrackPt_MCDetLevel" , " MC detector-level scaled FT0M vs track pT; FT0M^{*}; #it{p}_{T,track} (GeV/#it{c})" , {HistType::kTH2F , {scaledFT0MMCDetLevel, {200 , 0 ., 200 .}}});
349406 }
350407
351408 if (doprocessParticles || doprocessParticlesWeighted) {
@@ -853,7 +910,7 @@ struct TrackEfficiency {
853910 return ;
854911 }
855912
856- fillTrackHistograms (collision, jetTracks);
913+ fillTrackHistograms<TrackSample::Data> (collision, jetTracks);
857914 }
858915 PROCESS_SWITCH (TrackEfficiency, processTracksFromData, " QA for charged tracks in data" , false );
859916
@@ -881,22 +938,26 @@ struct TrackEfficiency {
881938 return ;
882939 }
883940
884- fillTrackHistograms (collision, jetTracks);
941+ fillTrackHistograms<TrackSample::MCDetLevel> (collision, jetTracks);
885942 }
886943 PROCESS_SWITCH (TrackEfficiency, processTracksFromMc, " QA for charged tracks in MC without weights" , false );
887944
888- void processTracksFromMcWeighted (soa::Filtered<soa::Join<aod::JetCollisions, aod::JMcCollisionLbs>>::iterator const & collision,
945+ void processTracksFromMcWeighted (soa::Filtered<soa::Join<aod::JetCollisions, aod::JMcCollisionLbs, aod::JCollisionOutliers >>::iterator const & collision,
889946 aod::JetMcCollisions const &,
890947 soa::Filtered<soa::Join<aod::JetTracksMCD, aod::JTrackExtras, aod::JTrackPIs>> const & jetTracks,
891948 soa::Join<aod::Tracks, aod::TracksExtra, aod::TracksDCA> const &)
892949 {
893950 if (!collision.has_mcCollision ()) { // the collision is fake and has no associated mc coll; skip as .mccollision() cannot be called
894951 return ;
895952 }
896- float eventWeight = collision.mcCollision ().weight ();
897953 if (!jetderiveddatautilities::selectCollision (collision, eventSelectionBits, skipMBGapEvents, applyRCTSelections, rctSelection)) {
898954 return ;
899955 }
956+
957+ if (collision.isOutlier ()) {
958+ return ;
959+ }
960+
900961 float centrality = checkCentFT0M ? collision.centFT0M () : collision.centFT0C ();
901962 if (cutCentrality && (centrality < centralityMin || centralityMax < centrality)) {
902963 return ;
@@ -905,12 +966,13 @@ struct TrackEfficiency {
905966 return ;
906967 }
907968
969+ float eventWeight = collision.mcCollision ().weight ();
908970 float pTHat = collision.mcCollision ().ptHard () < pTHatSettingSentinelValue ? collision.mcCollision ().ptHard () : simPtRef / (std::pow (eventWeight, 1.0 / pTHatExponent));
909971 if (pTHat < ptHatMin || pTHat > ptHatMax) { // only allows mcCollisions with weight in between min and max
910972 return ;
911973 }
912974
913- fillTrackHistograms (collision, jetTracks, eventWeight);
975+ fillTrackHistograms<TrackSample::MCDetLevel> (collision, jetTracks, eventWeight);
914976 }
915977 PROCESS_SWITCH (TrackEfficiency, processTracksFromMcWeighted, " QA for charged tracks in weighted MC" , false );
916978
@@ -1711,6 +1773,44 @@ struct TrackEfficiency {
17111773 }
17121774 }
17131775 PROCESS_SWITCH (TrackEfficiency, processQcCheck, " Histograms for QC checks" , false );
1776+
1777+ // FT0 event activity helpers
1778+ struct FT0Metrics {
1779+ float multFT0A = 0 .f;
1780+ float multFT0C = 0 .f;
1781+ float multFT0M = 0 .f;
1782+ float scaledFT0A = 0 .f;
1783+ float scaledFT0C = 0 .f;
1784+ float scaledFT0M = 0 .f;
1785+ };
1786+
1787+ float getScaledFT0 (const float & multFT0, const float & meanFT0)
1788+ {
1789+ return multFT0 / meanFT0;
1790+ }
1791+
1792+ float getScaledFT0M (const float & scaledMultFT0A, const float & scaledMultFT0C)
1793+ {
1794+ return 0.5 * (scaledMultFT0A + scaledMultFT0C);
1795+ }
1796+
1797+ FT0Metrics makeFT0Metrics (float multFT0A, float multFT0C, float meanFT0A, float meanFT0C)
1798+ {
1799+ FT0Metrics values;
1800+ values.multFT0A = multFT0A;
1801+ values.multFT0C = multFT0C;
1802+ values.multFT0M = multFT0A + multFT0C;
1803+ values.scaledFT0A = getScaledFT0 (values.multFT0A , meanFT0A);
1804+ values.scaledFT0C = getScaledFT0 (values.multFT0C , meanFT0C);
1805+ values.scaledFT0M = getScaledFT0M (values.scaledFT0A , values.scaledFT0C );
1806+ return values;
1807+ }
1808+
1809+ template <typename Collision>
1810+ FT0Metrics getFT0Metrics (const Collision& collision, float meanFT0A, float meanFT0C)
1811+ {
1812+ return makeFT0Metrics (collision.multFT0A (), collision.multFT0C (), meanFT0A, meanFT0C);
1813+ }
17141814};
17151815
17161816WorkflowSpec defineDataProcessing (ConfigContext const & cfgc)
0 commit comments