ATLAS Offline Software
Loading...
Searching...
No Matches
HIEventSelectionToolRun3.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
5
6#include <fstream>
7#include <nlohmann/json.hpp>
8
10
11std::string HI::toString(HI::IonDataType period) {
12#define ENUMDEF(_N) \
13 case HI::IonDataType::_N: \
14 return #_N;
15 switch (period) {
25 default:
26 return std::string("UNKNOWN HI DATA TAKING PERIOD ") +
27 std::to_string(static_cast<uint8_t>(period));
28 }
29#undef ENUMDEF
30}
31
32std::string HI::toString(HI::PileupVariation variation) {
33#define ENUMDEF(_N) \
34 case HI::PileupVariation::_N: \
35 return #_N;
36
37 switch (variation) {
38 ENUMDEF(Nominal)
39 ENUMDEF(Tight)
40 ENUMDEF(Loose)
41 default:
42 return std::string("UNKNOWN PU VARIATION ") +
43 std::to_string(static_cast<uint8_t>(variation));
44 }
45#undef ENUMDEF
46}
47
49#define ENUMDEF(_N) \
50 case HI::SelectionMask::_N: \
51 return #_N;
52
53 switch (m) {
63 default:
64 return std::string("UNKNOWN mask bit ") +
65 std::to_string(static_cast<unsigned int>(m));
66 }
67#undef ENUMDEF
68}
69
70static const double MeV = 1.;
71static const double GeV = 1e3;
72static const double TeV = 1e6;
73
74std::unique_ptr<TH1D> loadHist(const std::string& file) {
75 const std::string path =
76 PathResolver::find_file(std::string("HIEventUtils/") + file, "DATAPATH");
77 std::ifstream i(path);
78 if (not i) {
79 throw std::runtime_error(path + " does nto exist");
80 }
81
82 nlohmann::json j;
83 i >> j;
84 i.close();
85
86 const size_t nbins = j.at("fNbins").get<size_t>();
87
88 auto h = std::make_unique<TH1D>(j.at("fName").get<std::string>().c_str(),
89 j.at("fTitle").get<std::string>().c_str(),
90 nbins, j.at("fXmin").get<double>(),
91 j.at("fXmax").get<double>());
92 const std::vector<double> bins = j.at("fArray").get<std::vector<double>>();
93 if (bins.size() != j.at("fNbins").get<size_t>() + 2) {
94 throw std::runtime_error(
95 "Histogram " + j.at("fName").get<std::string>() +
96 " has inconsistent number of bins and fNbins (should +2) value " +
97 std::to_string(bins.size()) + " and " + std::to_string(nbins));
98 }
99
100 for (size_t bin = 0; bin < nbins + 2; bin++) {
101 h->SetBinContent(bin, bins[bin]);
102 }
103 h->SetDirectory(0);
104 return h;
105}
106
109
111 ATH_MSG_INFO("Initializing HIEventSelectionToolRun3");
112 // add printout of overall selection that is configured
113 if (!m_trackSelectionTool.empty())
115
116 //----------------------------------------------------------------------
117 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
118 // also See Figure 2.6 of
119 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
120 m_ZDCEt_UpperCut_5p5Sigma_OO = loadHist("PUFCalVsZDCNominalOO2025.json");
121
122 //----------------------------------------------------------------------
123
124 //----------------------------------------------------------------------
125 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
126 // also See Figure 2.6 of
127 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
128 m_ZDCEt_UpperCut_4p0Sigma_NeNe = loadHist("PUFCalVsZDCNominalNeNe2025.json");
129
130
131 //----------------------------------------------------------------------
132 // https://atlas-heavy-ions.docs.cern.ch/CorrFluc/centrality/
133 // https://cds.cern.ch/record/2921744 ATL-COM-PHYS-2025-033
134
135 m_ZDCEt_UpperCut_5Sigma_PbPb2023 = loadHist("PUFCalVsZDCNominalPbPb2023.json");
136
137 return StatusCode::SUCCESS;
138}
139
141 const xAOD::EventInfo* eventInfo) const {
142 if (!eventInfo)
143 return false;
144
145 // Standard ATLAS error checks
147 return false;
149 return false;
151 return false;
153 return false;
154
155 return true;
156}
157
160 float et = 0;
161 for (auto slice : *es) {
162 const static std::set fcalLayers({21, 22, 23});
163 if (fcalLayers.contains(slice->layer()))
164 et += slice->et();
165 }
166 return et * MeV / GeV; // we operate in GeV
167}
168
170 HI::IonDataType, const xAOD::ZdcModuleContainer* zdcModules) const {
171 float e = 0;
172 static const SG::ConstAccessor<float> calibEnergyAccessor("CalibEnergy");
173 for (auto module : *zdcModules) {
174 e += calibEnergyAccessor(*module);
175 }
176 return e * MeV / GeV; // we operate in GeV
177}
178
181 const xAOD::ZdcModuleContainer* zdcModules,
182 HI::PileupVariation variation) const {
183 return noPUZDCvsFCal(period, fcalEt(period, es), zdcE(period, zdcModules),
184 variation);
185}
186
188 HI::IonDataType period, float fcalEt, float zdcE,
189 HI::PileupVariation variation) const {
190 const float cut = zdcCutValue(period, fcalEt, variation);
191 return zdcE < cut;
192}
193
196 const xAOD::VertexContainer* vertices, const double min_pt_cut) const {
197 const xAOD::Vertex* pv = 0;
198 for (const xAOD::Vertex* vx : *vertices) {
199 if (vx->vertexType() == xAOD::VxType::PriVtx) {
200 pv = vx;
201 break;
202 }
203 }
204
205 int count = 0;
206 for (const xAOD::TrackParticle* trk : *tracks) {
207 if (m_trackSelectionTool->accept(*trk, pv)) {
208 if(trk->pt()<min_pt_cut) continue;
209 count++;
210 }
211 }
212 return count;
213}
214
217 const xAOD::TrackParticleContainer* tracks,
218 const xAOD::VertexContainer* vertices, PileupVariation variation) const {
219
220 double min_pt_cut=-1;
221 if (period == HI::IonDataType::OO2025 || period == HI::IonDataType::NeNe2025) {
222 min_pt_cut=500;//https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/#fcal-sumet-ntrk-correlation-cut
223 }
224
225 return noPUFCalVsNtracks(period, fcalEt(period, es),
226 nTrk(period, tracks, vertices,min_pt_cut), variation);
227}
228
230 HI::IonDataType period, float fcalEt, int ntrk, HI::PileupVariation) const {
231 ATH_MSG_DEBUG("cutting puFCalVsNtracks: fcalEt " << fcalEt << " ntracks "
232 << ntrk);
233 // for reference, thes numbers are taken from:
234 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/#fcal-sumet-ntrk-correlation-cut
235 // and more is here:
236 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
237 if (period == HI::IonDataType::OO2025) {
238 if (ntrk < (-80 + fcalEt * 0.6))
239 return false;
240 if (ntrk < (-30 + fcalEt * 0.4))
241 return false;
242 if (ntrk > (100 + fcalEt * 1.7))
243 return false;
244 return true;
245 } else if (period == HI::IonDataType::NeNe2025) {
246 if (ntrk < (-70 + fcalEt * 0.6))
247 return false;
248 if (ntrk < (-20 + fcalEt * 0.35))
249 return false;
250 if (ntrk > (100 + fcalEt * 1.7))
251 return false;
252 return true;
253 }
254 throw std::runtime_error(std::string("puFCalVsNtracks for period of id ") +
255 HI::toString(period) + " is not handled (yet)");
256
257 return false; // for unimplemented periods
258}
259
261 const xAOD::ZdcModuleContainer* zdcModules) const {
262 float PreSamplerAmp_A = 0;
263 float PreSamplerAmp_C = 0;
264 static const SG::ConstAccessor<float> accPreSampleAmp("PreSampleAmp");
265 for (const auto module : *zdcModules) {
266
267 if (module->zdcType() != 0)
268 continue;
269 if (module->zdcSide() > 0)
270 PreSamplerAmp_C += accPreSampleAmp(*module);
271 if (module->zdcSide() < 0)
272 PreSamplerAmp_A += accPreSampleAmp(*module);
273 }
274 return {PreSamplerAmp_A, PreSamplerAmp_C};
275}
276
278 HI::IonDataType period, const xAOD::ZdcModuleContainer* zdcModules,
279 HI::PileupVariation variation) const {
280 auto [PreSamplerAmp_A, PreSamplerAmp_C] = ZDCPresamplerAmps(zdcModules);
281 return noPUZDCPresampler(period, PreSamplerAmp_A, PreSamplerAmp_C, variation);
282}
283
285 HI::IonDataType period, float presamplerA, float presamplerC,
286 HI::PileupVariation variation) const {
287 if (period == HI::IonDataType::PbPb2023) {
288 // from ATL-COM-PHYS-2025-033 + priv. communication F.Pauwels
289 const float peakPositionA = -56;
290 const float peakPositionC = -156;
291 const float peakWidthA = 51.8;
292 const float peakWidthC = 51.8;
293 float sigma = 7;
294 if (variation == HI::PileupVariation::Tight) {
295 sigma = 8;
296 }
297 if (variation == HI::PileupVariation::Loose) {
298 sigma = 6;
299 }
300 if (presamplerA > (peakPositionA + sigma * peakWidthA) and
301 presamplerC > (peakPositionC + sigma * peakWidthC)) {
302 return false; // it is pileup
303 }
304 return true;
305 }
306 throw std::runtime_error(std::string("ZDC PreSampleAmp for period of id ") +
307 HI::toString(period) + " is not handled (yet)");
308}
309
311 HI::IonDataType, const xAOD::VertexContainer* vertices) const {
312
313 // This is probably redundant as the vx->vertexType() should not be
314 // xAOD::VxType::PriVtx for the dummy vertex
315 if (vertices->size() <= 1) {
316 ATH_MSG_DEBUG("Only dummy vertex present, returning false");
317 return false;
318 }
319
320 unsigned int nPrimary = 0;
321 unsigned int nSplit = 0;
322 // count primary vertices with sigma_z^2 < threshold
323 // documentation: https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
324 int num_vtx_tot=vertices->size()-1;//exclude dummy vertex
325 int vtx_counter=0;
326 for (const xAOD::Vertex* vx : *vertices) {
327 vtx_counter++;
328 if(vtx_counter>num_vtx_tot) break;
329
330 // check Primary vertices to see if there are some of good quality
331 AmgSymMatrix(3) vtx_err = vx->covariancePosition();
332 const double sigmaZSq = vtx_err(2, 2);
333 if (sigmaZSq >= 0.02) // cut in mm^2
334 ++nSplit;
335 else
336 ++nPrimary;
337 }
338 ATH_MSG_DEBUG("nPrimary " << nPrimary << ", nSplit " << nSplit);
339
340 // If all vertices were classified as split, then we consider one of them to
341 // be a real vertex
342 if (nSplit > 0 && nPrimary == 0) {
343 ATH_MSG_DEBUG("Returning true as all vertices classified as split");
344 return true;
345 }
346
347 return nPrimary == 1;
348}
349
351 HI::IonDataType period, float fcalEt, HI::PileupVariation variation) const {
352
353 if (period == HI::IonDataType::PbPb2023) {
354 // the cut is expressed in TeV for 23 data
355 float fcalEtTeV = fcalEt * GeV / TeV;
356
357 // float cut = cutFunction(fcalEtTeV);
358 if (fcalEtTeV <= 1.0) // below 1 TeV use value at 1 TeV
359 fcalEtTeV = 1.0;
360 if (fcalEtTeV >= 4.0) // above4 TeV use value at 4 TeV
361 fcalEtTeV = 1.0;
362
363 int refbin = m_ZDCEt_UpperCut_5Sigma_PbPb2023->FindFixBin(fcalEtTeV);
364 float cut = m_ZDCEt_UpperCut_5Sigma_PbPb2023->GetBinContent(refbin);
365
366 if (variation == HI::PileupVariation::Tight) {
367 cut *= 1.02;
368 }
369 if (variation == HI::PileupVariation::Loose) {
370 cut *= 0.98;
371 }
372 return cut;
373 }
374
375 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
376 // also See Figure 2.6 of
377 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
378 if (period == HI::IonDataType::OO2025) {
379 int refbin = m_ZDCEt_UpperCut_5p5Sigma_OO->FindFixBin(fcalEt);
380 if (refbin < 1)
381 refbin = 1;
382
383 return m_ZDCEt_UpperCut_5p5Sigma_OO->GetBinContent(refbin);
384 }
385
386 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
387 // also See Figure 2.6 of
388 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
389 if (period == HI::IonDataType::NeNe2025) {
390 int refbin = m_ZDCEt_UpperCut_4p0Sigma_NeNe->FindFixBin(fcalEt);
391 if (refbin < 1)
392 refbin = 1;
393
394 return m_ZDCEt_UpperCut_4p0Sigma_NeNe->GetBinContent(refbin);
395 }
396
397 throw std::runtime_error(
398 std::string("zdcCutValue needed in FCal vs ZDC E for period of id ") +
399 HI::toString(period) + " is not handled (yet)");
400
401 return 0;
402}
403
408
413
415 uint32_t run) const {
416 if (run < 365498)
417 throw std::runtime_error(std::to_string(run) +
418 " not handled by selection tool");
419 if (run <= 367384)
421 if (run <= 463427)
423 if (run <= 489691)
425 if (run <= 490223)
427 if (run <= 501969)
429 if (run <= 502008)
431 if (run <= 512049)
433 // fill it up with 2026
434 throw std::runtime_error(std::to_string(run) +
435 " not handled by selection tool");
436}
437
439 HI::IonDataType period) const {
440 if (period == HI::IonDataType::OO2025 or
441 period == HI::IonDataType::NeNe2025) {
442 return static_cast<unsigned int>(HI::SelectionMask::OODefault);
443 }
444 // this will likely evolve
445 return static_cast<unsigned int>(HI::SelectionMask::PBDefault);
446}
447
448// } // namespace HI
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
#define AmgSymMatrix(dim)
static const double TeV
#define ENUMDEF(_N)
static const double MeV
std::unique_ptr< TH1D > loadHist(const std::string &file)
static const std::vector< std::string > bins
Header file for AthHistogramAlgorithm.
size_type size() const noexcept
Returns the number of elements in the collection.
virtual float zdcE(HI::IonDataType period, const xAOD::ZdcModuleContainer *zdcModules) const override
virtual std::pair< float, float > ZDCPresamplerAmps(const xAOD::ZdcModuleContainer *zdcModules) const override
obtain presampler amplitudes
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
virtual int nTrk(HI::IonDataType dataType, const xAOD::TrackParticleContainer *tracks, const xAOD::VertexContainer *vertices, const double min_pt_cut=-1) const override
virtual float fcalEt(HI::IonDataType period, const xAOD::HIEventShapeContainer *es) const override
float zdcCutValue(IonDataType, float fcalEt, PileupVariation) const
ToolHandle< InDet::IInDetTrackSelectionTool > m_trackSelectionTool
virtual unsigned int defaultMaskForPeriod(IonDataType period) const override
provides default set of cuts for given period
std::unique_ptr< TH1D > m_ZDCEt_UpperCut_4p0Sigma_NeNe
virtual bool noPUOOVertexCuts(IonDataType dataType, const xAOD::VertexContainer *vertices) const override
true if this is NOT pileup event
virtual bool noDetectorError(const xAOD::EventInfo *eventInfo) const override
Checks basic event flags.
float ntrkCutValue(IonDataType, float fcalEt, PileupVariation) const
virtual bool noPUFCalVsNtracks(IonDataType dataType, const xAOD::HIEventShapeContainer *es, const xAOD::TrackParticleContainer *tracks, const xAOD::VertexContainer *vertices, PileupVariation variation=PileupVariation::Nominal) const override
true if this is NOT pileup event The fool performs track selection
virtual bool noPUZDCvsFCal(HI::IonDataType period, const xAOD::HIEventShapeContainer *es, const xAOD::ZdcModuleContainer *zdcModules, HI::PileupVariation variation) const override
true if this is NOT pileup event It computes necessary quantities and invokes method defined next to ...
HIEventSelectionToolRun3(const std::string &name)
std::unique_ptr< TH1D > m_ZDCEt_UpperCut_5p5Sigma_OO
virtual IonDataType toDataType(const xAOD::EventInfo *eventInfo) const override
translates info in EV into HI data type
IonDataType runNumberToDataType(uint32_t run) const
std::unique_ptr< TH1D > m_ZDCEt_UpperCut_5Sigma_PbPb2023
virtual bool noPUZDCPresampler(HI::IonDataType period, const xAOD::ZdcModuleContainer *zdcModules, HI::PileupVariation variation) const override
true if this is NOT pileup event
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
Helper class to provide constant type-safe access to aux data.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
@ Tile
The Tile calorimeter.
@ Pixel
The pixel tracker.
@ LAr
The LAr calorimeter.
@ Error
The sub-detector issued an error.
uint32_t runNumber() const
The current event's run number.
EventFlagErrorState errorState(EventFlagSubDet subDet) const
Get the error state for a particular sub-detector.
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
std::string toString(IonDataType)
@ PriVtx
Primary vertex.
ZdcModuleContainer_v1 ZdcModuleContainer
EventInfo_v1 EventInfo
Definition of the latest event info version.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
HIEventShapeContainer_v2 HIEventShapeContainer
Define the latest version of the container.
Extra patterns decribing particle interation process.
TFile * file
int run(int argc, char *argv[])