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
10using namespace HI;
11
12std::string HI::toString(IonDataType period) {
13#define ENUMDEF(_N) \
14 case IonDataType::_N: \
15 return #_N;
16 switch (period) {
26 default:
27 return std::string("UNKNOWN HI DATA TAKING PERIOD ") +
28 std::to_string(static_cast<uint8_t>(period));
29 }
30#undef ENUMDEF
31}
32
33std::string HI::toString(PileupVariation variation) {
34#define ENUMDEF(_N) \
35 case PileupVariation::_N: \
36 return #_N;
37
38 switch (variation) {
42 default:
43 return std::string("UNKNOWN PU VARIATION ") +
44 std::to_string(static_cast<uint8_t>(variation));
45 }
46#undef ENUMDEF
47}
48
50#define ENUMDEF(_N) \
51 case HI::SelectionMask::_N: \
52 return #_N;
53
54 switch (m) {
65 default:
66 return std::string("UNKNOWN mask bit ") +
67 std::to_string(static_cast<unsigned int>(m));
68 }
69#undef ENUMDEF
70}
71
72static const double MeV = 1.;
73static const double GeV = 1e3;
74static const double TeV = 1e6;
75
76std::unique_ptr<TH1D> loadHist(const std::string& file) {
77 const std::string path =
78 PathResolver::find_file(std::string("HIEventUtils/") + file, "DATAPATH");
79 std::ifstream i(path);
80 if (not i) {
81 throw std::runtime_error(path + " does nto exist");
82 }
83
84 nlohmann::json j;
85 i >> j;
86 i.close();
87
88 const size_t nbins = j.at("fNbins").get<size_t>();
89
90 auto h = std::make_unique<TH1D>(j.at("fName").get<std::string>().c_str(),
91 j.at("fTitle").get<std::string>().c_str(),
92 nbins, j.at("fXmin").get<double>(),
93 j.at("fXmax").get<double>());
94 const std::vector<double> bins = j.at("fArray").get<std::vector<double>>();
95 if (bins.size() != j.at("fNbins").get<size_t>() + 2) {
96 throw std::runtime_error(
97 "Histogram " + j.at("fName").get<std::string>() +
98 " has inconsistent number of bins and fNbins (should +2) value " +
99 std::to_string(bins.size()) + " and " + std::to_string(nbins));
100 }
101
102 for (size_t bin = 0; bin < nbins + 2; bin++) {
103 h->SetBinContent(bin, bins[bin]);
104 }
105 h->SetDirectory(0);
106 return h;
107}
108
111
113 ATH_MSG_INFO("Initializing HIEventSelectionToolRun3");
114 // add printout of overall selection that is configured
115 if (!m_trackSelectionTool.empty())
117
118 //----------------------------------------------------------------------
119 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
120 // also See Figure 2.6 of
121 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
122 m_ZDCEt_UpperCut_5p5Sigma_OO = loadHist("PUFCalVsZDCNominalOO2025.json");
123
124 //----------------------------------------------------------------------
125
126 //----------------------------------------------------------------------
127 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
128 // also See Figure 2.6 of
129 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
130 m_ZDCEt_UpperCut_4p0Sigma_NeNe = loadHist("PUFCalVsZDCNominalNeNe2025.json");
131
132 //----------------------------------------------------------------------
133 // https://atlas-heavy-ions.docs.cern.ch/CorrFluc/centrality/
134 // https://cds.cern.ch/record/2921744 ATL-COM-PHYS-2025-033
135
137 loadHist("PUFCalVsZDCNominalPbPb2023.json");
138
139 return StatusCode::SUCCESS;
140}
141
143 const xAOD::EventInfo* eventInfo) const {
144 if (!eventInfo)
145 return false;
146
147 // Standard ATLAS error checks
149 return false;
151 return false;
153 return false;
155 return false;
156
157 return true;
158}
159
161 IonDataType, const xAOD::HIEventShapeContainer* es) const {
162 float et = 0;
163 for (auto slice : *es) {
164 const static std::set fcalLayers({21, 22, 23});
165 if (fcalLayers.contains(slice->layer()))
166 et += slice->et();
167 }
168 return et * MeV / GeV; // we operate in GeV
169}
170
172 IonDataType, const xAOD::ZdcModuleContainer* zdcModules) const {
173 float e = 0;
174 static const SG::ConstAccessor<float> calibEnergyAccessor("CalibEnergy");
175 for (auto module : *zdcModules) {
176 e += calibEnergyAccessor(*module);
177 }
178 return e * MeV / GeV; // we operate in GeV
179}
180
183 const xAOD::ZdcModuleContainer* zdcModules,
184 PileupVariation variation) const {
185 return noPUZDCvsFCal(period, fcalEt(period, es), zdcE(period, zdcModules),
186 variation);
187}
188
190 IonDataType period, float fcalEt, float zdcE,
191 PileupVariation variation) const {
192 const float cut = zdcCutValue(period, fcalEt, variation);
193 return zdcE < cut;
194}
195
198 const xAOD::VertexContainer* vertices, const double min_pt_cut) const {
199 const xAOD::Vertex* pv = 0;
200 for (const xAOD::Vertex* vx : *vertices) {
201 if (vx->vertexType() == xAOD::VxType::PriVtx) {
202 pv = vx;
203 break;
204 }
205 }
206
207 int count = 0;
208 for (const xAOD::TrackParticle* trk : *tracks) {
209 if (m_trackSelectionTool->accept(*trk, pv)) {
210 if (trk->pt() < min_pt_cut)
211 continue;
212 count++;
213 }
214 }
215 return count;
216}
217
220 const xAOD::TrackParticleContainer* tracks,
221 const xAOD::VertexContainer* vertices, PileupVariation variation) const {
222
223 double min_pt_cut = -1;
224 if (period == IonDataType::OO2025 ||
225 period == IonDataType::NeNe2025) {
226 min_pt_cut =
227 500; // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/#fcal-sumet-ntrk-correlation-cut
228 }
229
230 return noPUFCalVsNtracks(period, fcalEt(period, es),
231 nTrk(period, tracks, vertices, min_pt_cut),
232 variation);
233}
234
236 IonDataType period, float fcalEt, int ntrk, PileupVariation) const {
237 ATH_MSG_DEBUG("cutting puFCalVsNtracks: fcalEt " << fcalEt << " ntracks "
238 << ntrk);
239 // for reference, thes numbers are taken from:
240 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/#fcal-sumet-ntrk-correlation-cut
241 // and more is here:
242 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
243 if (period == IonDataType::OO2025) {
244 if (ntrk < (-80 + fcalEt * 0.6))
245 return false;
246 if (ntrk < (-30 + fcalEt * 0.4))
247 return false;
248 if (ntrk > (100 + fcalEt * 1.7))
249 return false;
250 return true;
251 } else if (period == IonDataType::NeNe2025) {
252 if (ntrk < (-70 + fcalEt * 0.6))
253 return false;
254 if (ntrk < (-20 + fcalEt * 0.35))
255 return false;
256 if (ntrk > (100 + fcalEt * 1.7))
257 return false;
258 return true;
259 }
260 throw std::runtime_error(std::string("puFCalVsNtracks for period of id ") +
261 HI::toString(period) + " is not handled (yet)");
262
263 return false; // for unimplemented periods
264}
265
267 const xAOD::ZdcModuleContainer* zdcModules) const {
268 float PreSamplerAmp_A = 0;
269 float PreSamplerAmp_C = 0;
270 static const SG::ConstAccessor<float> accPreSampleAmp("PreSampleAmp");
271 for (const auto module : *zdcModules) {
272
273 if (module->zdcType() != 0)
274 continue;
275 if (module->zdcSide() > 0)
276 PreSamplerAmp_C += accPreSampleAmp(*module);
277 if (module->zdcSide() < 0)
278 PreSamplerAmp_A += accPreSampleAmp(*module);
279 }
280 return {PreSamplerAmp_A, PreSamplerAmp_C};
281}
282
284 IonDataType period, const xAOD::ZdcModuleContainer* zdcModules,
285 PileupVariation variation) const {
286 auto [PreSamplerAmp_A, PreSamplerAmp_C] = ZDCPresamplerAmps(zdcModules);
287 return noPUZDCPresampler(period, PreSamplerAmp_A, PreSamplerAmp_C, variation);
288}
289
291 IonDataType period, float presamplerA, float presamplerC,
292 PileupVariation variation) const {
293 if (period == IonDataType::PbPb2023) {
294 // from ATL-COM-PHYS-2025-033 + priv. communication F.Pauwels
295 const float peakPositionA = -56;
296 const float peakPositionC = -156;
297 const float peakWidthA = 51.8;
298 const float peakWidthC = 51.8;
299 float sigma = 7;
300 if (variation == PileupVariation::Tight) {
301 sigma = 8;
302 }
303 if (variation == PileupVariation::Loose) {
304 sigma = 6;
305 }
306 if (presamplerA > (peakPositionA + sigma * peakWidthA) and
307 presamplerC > (peakPositionC + sigma * peakWidthC)) {
308 return false; // it is pileup
309 }
310 return true;
311 }
312 throw std::runtime_error(std::string("ZDC PreSampleAmp for period of id ") +
313 HI::toString(period) + " is not handled (yet)");
314}
315
317 IonDataType, const xAOD::VertexContainer* vertices) const {
318
319 // This is probably redundant as the vx->vertexType() should not be
320 // xAOD::VxType::PriVtx for the dummy vertex
321 if (vertices->size() <= 1) {
322 ATH_MSG_DEBUG("Only dummy vertex present, returning false");
323 return false;
324 }
325
326 unsigned int nPrimary = 0;
327 unsigned int nSplit = 0;
328 // count primary vertices with sigma_z^2 < threshold
329 // documentation: https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
330 int num_vtx_tot = vertices->size() - 1; // exclude dummy vertex
331 int vtx_counter = 0;
332 for (const xAOD::Vertex* vx : *vertices) {
333 vtx_counter++;
334 if (vtx_counter > num_vtx_tot)
335 break;
336
337 // check Primary vertices to see if there are some of good quality
338 AmgSymMatrix(3) vtx_err = vx->covariancePosition();
339 const double sigmaZSq = vtx_err(2, 2);
340 if (sigmaZSq >= 0.02) // cut in mm^2
341 ++nSplit;
342 else
343 ++nPrimary;
344 }
345 ATH_MSG_DEBUG("nPrimary " << nPrimary << ", nSplit " << nSplit);
346
347 // If all vertices were classified as split, then we consider one of them to
348 // be a real vertex
349 if (nSplit > 0 && nPrimary == 0) {
350 ATH_MSG_DEBUG("Returning true as all vertices classified as split");
351 return true;
352 }
353
354 return nPrimary == 1;
355}
356
358 IonDataType period, float fcalEt, PileupVariation variation) const {
359
360 if (period == IonDataType::PbPb2023) {
361 // the cut is expressed in TeV for 23 data
362 float fcalEtTeV = fcalEt * GeV / TeV;
363
364 // float cut = cutFunction(fcalEtTeV);
365 if (fcalEtTeV <= 1.0) // below 1 TeV use value at 1 TeV
366 fcalEtTeV = 1.0;
367 if (fcalEtTeV >= 4.0) // above4 TeV use value at 4 TeV
368 fcalEtTeV = 1.0;
369
370 int refbin = m_ZDCEt_UpperCut_5Sigma_PbPb2023->FindFixBin(fcalEtTeV);
371 float cut = m_ZDCEt_UpperCut_5Sigma_PbPb2023->GetBinContent(refbin);
372
373 if (variation == PileupVariation::Tight) {
374 cut *= 1.02;
375 }
376 if (variation == PileupVariation::Loose) {
377 cut *= 0.98;
378 }
379 return cut;
380 }
381
382 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
383 // also See Figure 2.6 of
384 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
385 if (period == IonDataType::OO2025) {
386 int refbin = m_ZDCEt_UpperCut_5p5Sigma_OO->FindFixBin(fcalEt);
387 if (refbin < 1)
388 refbin = 1;
389
390 return m_ZDCEt_UpperCut_5p5Sigma_OO->GetBinContent(refbin);
391 }
392
393 // https://atlas-heavy-ions.docs.cern.ch/analyzes/2025/
394 // also See Figure 2.6 of
395 // https://cds.cern.ch/record/2930965/files/ATL-COM-PHYS-2025-347.pdf
396 if (period == IonDataType::NeNe2025) {
397 int refbin = m_ZDCEt_UpperCut_4p0Sigma_NeNe->FindFixBin(fcalEt);
398 if (refbin < 1)
399 refbin = 1;
400
401 return m_ZDCEt_UpperCut_4p0Sigma_NeNe->GetBinContent(refbin);
402 }
403
404 throw std::runtime_error(
405 std::string("zdcCutValue needed in FCal vs ZDC E for period of id ") +
406 HI::toString(period) + " is not handled (yet)");
407
408 return 0;
409}
410
412 IonDataType, const xAOD::CaloClusterContainer* topos) const {
413 int negSideCount = 0;
414 int posSideCount = 0;
415 for (auto topo : *topos) {
416 if (topo->pt() < 400. * MeV)
417 continue;
418 // 3.1 |eta | < 4.9 is FCal range
419 if (topo->eta() > 3.1) {
420 posSideCount++;
421 }
422 if (topo->eta() < -3.1) {
423 negSideCount++;
424 }
425 }
426 return posSideCount > 0 && negSideCount > 0;
427}
428
430 PileupVariation) const {
431 return 0;
432}
433
435 const xAOD::EventInfo* eventInfo) const {
436 return runNumberToDataType(eventInfo->runNumber());
437}
438
440 uint32_t run) const {
441 if (run < 365498)
442 throw std::runtime_error(std::to_string(run) +
443 " not handled by selection tool");
444 if (run <= 367384)
446 if (run <= 463427)
448 if (run <= 489691)
450 if (run <= 490223)
452 if (run <= 501969)
453 return IonDataType::OO2025;
454 if (run <= 502008)
456 if (run <= 512049)
458 // fill it up with 2026
459 throw std::runtime_error(std::to_string(run) +
460 " not handled by selection tool");
461}
462
464 IonDataType period) const {
465 if (period == IonDataType::OO2025 or
466 period == IonDataType::NeNe2025) {
467 return static_cast<unsigned int>(HI::SelectionMask::OODefault);
468 }
469 // this will likely evolve
470 return static_cast<unsigned int>(HI::SelectionMask::PBDefault);
471}
472
473// } // 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 tcInFCalPresent(IonDataType dataType, const xAOD::CaloClusterContainer *topos) const override
checks if topo cluster (TC) presence in FCal requirement passes
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 ...
virtual IonDataType toDataType(const xAOD::EventInfo *eventInfo) const override
translates info in EV into HI data type
HIEventSelectionToolRun3(const std::string &name)
IonDataType runNumberToDataType(uint32_t run) const
std::unique_ptr< TH1D > m_ZDCEt_UpperCut_5p5Sigma_OO
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.
CaloClusterContainer_v1 CaloClusterContainer
Define the latest version of the calorimeter cluster container.
Extra patterns decribing particle interation process.
TFile * file
int run(int argc, char *argv[])