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) {
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
70std::unique_ptr<TH1D> loadHist(const std::string& file) {
71 const std::string path =
72 PathResolver::find_file(std::string("HIEventUtils/") + file, "DATAPATH");
73 std::ifstream i(path);
74 if (not i) {
75 throw std::runtime_error(path + " does nto exist");
76 }
77
78 nlohmann::json j;
79 i >> j;
80 i.close();
81
82 const size_t nbins = j.at("fNbins").get<size_t>();
83
84 auto h = std::make_unique<TH1D>(j.at("fName").get<std::string>().c_str(),
85 j.at("fTitle").get<std::string>().c_str(),
86 nbins, j.at("fXmin").get<double>(),
87 j.at("fXmax").get<double>());
88 const std::vector<double> bins = j.at("fArray").get<std::vector<double>>();
89 if (bins.size() != j.at("fNbins").get<size_t>() + 2) {
90 throw std::runtime_error(
91 "Histogram " + j.at("fName").get<std::string>() +
92 " has inconsistent number of bins and fNbins (should +2) value " +
93 std::to_string(bins.size()) + " and " + std::to_string(nbins));
94 }
95
96 for (size_t bin = 0; bin < nbins + 2; bin++) {
97 h->SetBinContent(bin, bins[bin]);
98 }
99 h->SetDirectory(0);
100 return h;
101}
102
105
107 ATH_MSG_INFO("Initializing HIEventSelectionToolRun3");
108 // add printout of overall selection that is configured
109 if (!m_trackSelectionTool.empty())
111
112 //----------------------------------------------------------------------
113 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
114 // also See Figure 2.6 of
115 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
116 m_ZDCEt_UpperCut_5p5Sigma_OO = loadHist("PUFCalVsZDCNominalOO2025.json");
117
118 //----------------------------------------------------------------------
119
120 //----------------------------------------------------------------------
121 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
122 // also See Figure 2.6 of
123 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
124 m_ZDCEt_UpperCut_4p0Sigma_NeNe = loadHist("PUFCalVsZDCNominalNeNe2025.json");
125 return StatusCode::SUCCESS;
126}
127
129 const xAOD::EventInfo* eventInfo) const {
130 if (!eventInfo)
131 return false;
132
133 // Standard ATLAS error checks
135 return false;
137 return false;
139 return false;
141 return false;
142
143 return true;
144}
145
148 float et = 0;
149 for (auto slice : *es) {
150 const static std::set fcalLayers({21, 22, 23});
151 if (fcalLayers.contains(slice->layer()))
152 et += slice->et();
153 }
154 return et * 1e-6; // we operate in TeV
155}
156
158 HI::IonDataType, const xAOD::ZdcModuleContainer* zdcModules) const {
159 float e = 0;
160 static const SG::ConstAccessor<float> calibEnergyAccessor("CalibEnergy");
161 for (auto module : *zdcModules) {
162 e += calibEnergyAccessor(*module);
163 }
164 return e * 1e-3; // we operate in GeV
165}
166
169 const xAOD::ZdcModuleContainer* zdcModules,
170 HI::PileupVariation variation) const {
171 return puZDCvsFCal(period, fcalEt(period, es), zdcE(period, zdcModules), variation);
172}
173
175 HI::IonDataType period, float fcalEt, float zdcE,
176 HI::PileupVariation variation) const {
177 const float cut = zdcCutValue(period, fcalEt, variation);
178 return zdcE < cut;
179}
180
182 const xAOD::TrackParticleContainer* tracks,
183 const xAOD::VertexContainer* vertices) const {
184 const xAOD::Vertex* pv = 0;
185 for (const xAOD::Vertex* vx : *vertices) {
186 if (vx->vertexType() == xAOD::VxType::PriVtx) {
187 pv = vx;
188 break;
189 }
190 }
191
192 int count = 0;
193 for (const xAOD::TrackParticle* trk : *tracks) {
194 if (m_trackSelectionTool->accept(*trk, pv)) {
195 count++;
196 }
197 }
198 return count;
199}
200
203 const xAOD::TrackParticleContainer* tracks,
204 const xAOD::VertexContainer* vertices, PileupVariation variation) const {
205 return puFCalVsNtracks(period, fcalEt(period, es), nTrk(period, tracks, vertices), variation);
206}
207
209 float fcalEt, int ntrk,
210 HI::PileupVariation) const {
211 ATH_MSG_DEBUG("cutting puFCalVsNtracks: fcalEt " << fcalEt << " ntracks "
212 << ntrk);
213 // for reference, thes numbers are taken from:
214 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/#fcal-sumet-ntrk-correlation-cut
215 // and more is here:
216 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
217 if (period == HI::IonDataType::OO2025) {
218 if (ntrk < (-80 + fcalEt * 600))
219 return false;
220 if (ntrk < (-30 + fcalEt * 400))
221 return false;
222 if (ntrk > (100 + fcalEt * 1700))
223 return false;
224 return true;
225 } else if (period == HI::IonDataType::NeNe2025) {
226 if (ntrk < (-70 + fcalEt * 600))
227 return false;
228 if (ntrk < (-20 + fcalEt * 350))
229 return false;
230 if (ntrk > (100 + fcalEt * 1700))
231 return false;
232 return true;
233 }
234 return false; // for unimplemented periods
235}
236
238 HI::IonDataType period, const xAOD::ZdcModuleContainer* zdcModules,
239 HI::PileupVariation variation) const {
240 float PreSamplerAmp_A = 0;
241 float PreSamplerAmp_C = 0;
242 static const SG::ConstAccessor<float> accPreSampleAmp("PreSampleAmp");
243 for (const auto module : *zdcModules) {
244 if (module->zdcType() != 0)
245 continue;
246 if (module->zdcSide() > 0)
247 PreSamplerAmp_C += accPreSampleAmp(*module);
248 if (module->zdcSide() < 0)
249 PreSamplerAmp_A += accPreSampleAmp(*module);
250 }
251 return puZDCPresampler(period, PreSamplerAmp_A, PreSamplerAmp_C, variation);
252}
253
255 HI::IonDataType period, float presamplerA, float presamplerC,
256 HI::PileupVariation variation) const {
257 // not sure if fcalEt will be involved i.e. apply this cut only above certain
258 // fcalEt
259
260 if (period == HI::IonDataType::PbPb2023) {
261 // from ATL-COM-PHYS-2025-033 + priv. communication F.Pauwels
262 const float peakPositionA = -56;
263 const float peakPositionC = -156;
264 const float peakWidthA = 51.8;
265 const float peakWidthC = 51.8;
266 float sigma = 7;
267 if (variation == HI::PileupVariation::Tight) {
268 sigma = 8;
269 }
270 if (variation == HI::PileupVariation::Loose) {
271 sigma = 6;
272 }
273 if (presamplerA > (peakPositionA + sigma * peakWidthA) and
274 presamplerC > (peakPositionC + sigma * peakWidthC)) {
275 return true; // it is pileup
276 }
277 }
278 return false;
279}
280
282 HI::IonDataType, const xAOD::VertexContainer* vertices) const {
283
284 // This is probably redundant as the vx->vertexType() should not be
285 // xAOD::VxType::PriVtx for the dummy vertex
286 if (vertices->size() <= 1) {
287 ATH_MSG_DEBUG("Only dummy vertex present, returning false");
288 return false;
289 }
290
291 unsigned int nPrimary = 0;
292 unsigned int nSplit = 0;
293 unsigned int nOther = 0;
294 // count primary vertices with sigma_z^2 < threshold
295 // documentation: https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
296 for (const xAOD::Vertex* vx : *vertices) {
297 if (vx->vertexType() == xAOD::VxType::PriVtx) {
298 // check Primary vertices to see if there are some of good quality
299 AmgSymMatrix(3) vtx_err = vx->covariancePosition();
300 const double sigmaZSq = vtx_err(2, 2);
301 if (sigmaZSq >= 0.02) // cut in mm^2
302 ++nSplit;
303 else
304 ++nPrimary;
305 }
306 // vertices that are not PV, note that dummy vertex probably will get
307 // assigned here
308 else
309 ++nOther;
310 }
311 ATH_MSG_DEBUG("n primary " << nPrimary << ", nSplit " << nSplit
312 << ", nOther " << nOther);
313
314 // If all vertices were classified as split, then we consider one of them to
315 // be a real vertex
316 if (nSplit > 0 && nPrimary == 0) {
317 ATH_MSG_DEBUG("Returning true as all vertices classified as split");
318 return true;
319 }
320
321 return nPrimary == 1;
322}
323
325 HI::IonDataType period, float fcalEt, HI::PileupVariation variation) const {
326 if (fcalEt > 100.0)
327 throw std::runtime_error(
328 std::to_string(fcalEt) +
329 " the energy that is given to zdcCutValue is well above 100 TeV?, "
330 "likely you call it not converting energy to TeV");
331
332 if (period == HI::IonDataType::PbPb2023) {
333
334 auto cutFunction = [](float et) {
335 const static double a = 334.29, b = -20.39,
336 c = -2.38; // from ATL-COM-PHYS-2025-033
337 return a + b * et + c * et * et;
338 };
339
340 float cut = cutFunction(fcalEt);
341 if (fcalEt <= 1.0) // below 1 TeV use flat
342 cut = cutFunction(1.0);
343 if (fcalEt >= 4.0) // below 1 TeV use flat
344 cut = cutFunction(4.0);
345
346 if (variation == HI::PileupVariation::Tight) {
347 cut *= 1.02;
348 }
349 if (variation == HI::PileupVariation::Loose) {
350 cut *= 0.98;
351 }
352 return cut;
353 }
354
355 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
356 // also See Figure 2.6 of
357 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
358 if (period == HI::IonDataType::OO2025) {
359 //*1e3 below to convert fcalEt from TeV to GeV
360 int refbin = m_ZDCEt_UpperCut_5p5Sigma_OO->FindFixBin(fcalEt * 1e3);
361 if (refbin < 1)
362 refbin = 1;
363
364 //*1e3 below to convert Zdc value in histogram from TeV to GeV
365 return m_ZDCEt_UpperCut_5p5Sigma_OO->GetBinContent(refbin) * 1e3;
366 }
367
368 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
369 // also See Figure 2.6 of
370 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
371 if (period == HI::IonDataType::NeNe2025) {
372 //*1e3 below to convert fcalEt from TeV to GeV
373 int refbin = m_ZDCEt_UpperCut_4p0Sigma_NeNe->FindFixBin(fcalEt * 1e3);
374 if (refbin < 1)
375 refbin = 1;
376
377 //*1e3 below to convert Zdc value in histogram from TeV to GeV
378 return m_ZDCEt_UpperCut_4p0Sigma_NeNe->GetBinContent(refbin) * 1e3;
379 }
380
381 throw std::runtime_error(std::string("period of id ") + HI::toString(period) +
382 " is not handled (yet)");
383
384 return 0;
385}
386
391
396
398 uint32_t run) const {
399 if (run < 365498)
400 throw std::runtime_error(std::to_string(run) +
401 " not handled by selection tool");
402 if (run <= 367384)
404 if (run <= 463427)
406 if (run <= 489691)
408 if (run <= 490223)
410 if (run <= 501969)
412 if (run <= 502008)
414 if (run <= 512049)
416 // fill it up with 2026
417 throw std::runtime_error(std::to_string(run) +
418 " not handled by selection tool");
419}
420
422 HI::IonDataType period) const {
423 if (period == HI::IonDataType::OO2025 or
424 period == HI::IonDataType::NeNe2025) {
425 return static_cast<unsigned int>(HI::SelectionMask::OODefault);
426 }
427 // this will likely evolve
428 return static_cast<unsigned int>(HI::SelectionMask::PBDefault);
429}
430
431// } // 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)
#define ENUMDEF(_N)
std::unique_ptr< TH1D > loadHist(const std::string &file)
static Double_t a
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 int nTrk(HI::IonDataType dataType, const xAOD::TrackParticleContainer *tracks, const xAOD::VertexContainer *vertices) const override
virtual float zdcE(HI::IonDataType period, const xAOD::ZdcModuleContainer *zdcModules) const override
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
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 bool puFCalVsNtracks(IonDataType dataType, const xAOD::HIEventShapeContainer *es, const xAOD::TrackParticleContainer *tracks, const xAOD::VertexContainer *vertices, PileupVariation variation=PileupVariation::Nominal) const override
true if this is pileup event The fool performs track selection
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 puZDCPresampler(HI::IonDataType period, const xAOD::ZdcModuleContainer *zdcModules, HI::PileupVariation variation) 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
HIEventSelectionToolRun3(const std::string &name)
std::unique_ptr< TH1D > m_ZDCEt_UpperCut_5p5Sigma_OO
virtual bool puOOVertexCuts(IonDataType dataType, const xAOD::VertexContainer *vertices) const override
true if this is pileup event
virtual IonDataType toDataType(const xAOD::EventInfo *eventInfo) const override
translates info in EV into HI data type
IonDataType runNumberToDataType(uint32_t run) const
virtual bool puZDCvsFCal(HI::IonDataType period, const xAOD::HIEventShapeContainer *es, const xAOD::ZdcModuleContainer *zdcModules, HI::PileupVariation variation) const override
true if this is pileup event It computes necessary quantities and invokes method defined next to perf...
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:146
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[])