ATLAS Offline Software
Loading...
Searching...
No Matches
PileUpMTAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// PileUpMT includes
6#include "PileUpMTAlg.h"
7
8#include <CxxUtils/XXH.h>
9#include <unistd.h>
10
11#include <boost/core/demangle.hpp>
12#include <range/v3/all.hpp>
13
14#include <chrono>
15#include <format>
16
18#include "EventInfo/EventInfo.h"
19#include <tuple>
20
22#include "CLHEP/Random/RandPoisson.h"
23#include "CLHEP/Random/RandomEngine.h"
31
33namespace rv = ranges::views;
34// namespace ra = ranges::actions;
35
36inline std::string CLIDToString(const CLID& clid) {
37 return boost::core::demangle(CLIDRegistry::CLIDToTypeinfo(clid)->name());
38}
39
40PileUpMTAlg::PileUpMTAlg(const std::string& name, ISvcLocator* pSvcLocator)
41 : AthAlgorithm(name, pSvcLocator) {}
42
44
46 std::unique_ptr<const xAOD::EventInfo>& ei_,
47 std::unique_ptr<xAOD::EventAuxInfo>& ei_aux_,
48 bool pileup) const {
49 std::string key = pileup ? "EventInfo" : "HSEventInfo";
50 auto newEi = std::make_unique<xAOD::EventInfo>();
51 auto eiAux = std::make_unique<xAOD::EventAuxInfo>();
52 newEi->setStore(eiAux.get());
53 SG::ReadHandle<xAOD::EventInfo> ei_h(key, sg.name());
54 const xAOD::EventInfo* ei = ei_h.get();
55 if (ei != nullptr) {
56 *newEi = *ei;
57 } else {
58 ATH_MSG_ERROR("Couldn't find xAOD::EventInfo. " << sg.name());
59 ATH_MSG_ERROR(sg.dump());
60 return StatusCode::FAILURE;
61 }
62 // Use attribute list if EventInfo doesn't have event numbers set
63 if (newEi->eventNumber() == 0) {
64 const auto* attr_list_p = sg.tryConstRetrieve<AthenaAttributeList>("Input");
65 if (attr_list_p != nullptr) {
66 if (attr_list_p->size() <= 6) {
67 ATH_MSG_WARNING("Read Input attribute list but size <= 6");
68 } else {
69 const AthenaAttributeList& attr_list = *attr_list_p;
70 const auto runNum = attr_list["RunNumber"].data<unsigned>();
71 const auto evtNum = attr_list["EventNumber"].data<unsigned long long>();
72 const auto lbNum = attr_list["LumiBlockN"].data<unsigned>();
73 newEi->setRunNumber(runNum);
74 newEi->setLumiBlock(lbNum);
75 newEi->setEventNumber(evtNum);
76 }
77 } else {
79 "Could not read Input attribute list and EventInfo has no event "
80 "number");
81 }
82 }
83 newEi->setEvtStore(&sg);
84 ei_ = std::move(newEi);
85 ei_aux_ = std::move(eiAux);
86 return StatusCode::SUCCESS;
87}
88
90 const std::vector<std::uint32_t>& bcid,
94 int bc, const EventContext& ctx, unsigned long subevt_id,
95 std::vector<std::uint64_t>& trace) {
96 // Keep the code to add and process a subevent in one place
97 const unsigned int bc_idx = bc - m_earliestDeltaBC;
98 StoreGateSvc* sg = mbSvc->getMinbias(ctx, subevt_id);
99 std::unique_ptr<const xAOD::EventInfo> ei;
100 std::unique_ptr<xAOD::EventAuxInfo> eiAux;
101 ATH_CHECK(get_ei(*sg, ei, eiAux, true));
102 xAOD::EventInfo mb_to_modify(*ei);
103 if (m_writeTrace) {
104 trace.push_back(mb_to_modify.eventNumber());
105 }
106 mb_to_modify.setBCID(bcid[bc_idx]);
107 try {
108 addSubEvent(overlaidEvt.ptr(), &mb_to_modify, bc * m_BCSpacing, puType,
109 puCont.ptr(), m_evtInfoContKey.key(), sg);
110 } catch (const std::exception& e) {
111 ATH_MSG_ERROR("Caught exception adding subevent: " << e.what());
112 return StatusCode::FAILURE;
113 }
114 return StatusCode::SUCCESS;
115}
116
118 using namespace std::chrono;
119 ATH_MSG_DEBUG("Initializing " << name() << "...");
120 if (m_writeTrace) {
121 std::string filename = std::format("pileup_trace_skipping-{}_{:%Y-%m-%dT%H%M}.txt",
122 m_skippedHSEvents.value(),
123 system_clock::now());
124 if (!m_pileupTrace.init(filename)) {
125 ATH_MSG_ERROR("Cannot append to file " << filename);
126 return StatusCode::FAILURE;
127 }
128 }
129 ATH_CHECK(m_skipEventIdxSvc.retrieve());
130 ATH_CHECK(m_rngSvc.retrieve());
131 if (m_fracLowPt != 0) {
132 ATH_CHECK(m_lowptMBSvc.retrieve());
133 }
134 if (m_fracHighPt != 0) {
135 ATH_CHECK(m_highptMBSvc.retrieve());
136 }
137 if (m_numCavern != 0) {
138 ATH_CHECK(m_cavernMBSvc.retrieve());
139 }
140 if (m_numBeamGas != 0) {
141 ATH_CHECK(m_beamgasMBSvc.retrieve());
142 }
143 if (m_numBeamHalo != 0) {
144 ATH_CHECK(m_beamhaloMBSvc.retrieve());
145 }
146 ATH_CHECK(m_beamInt.retrieve());
147 ATH_CHECK(m_beamLumi.retrieve());
148 ATH_CHECK(m_puTools.retrieve());
149
150 m_evtInfoContKey = "PileUpEventInfo";
151 ATH_CHECK(m_evtInfoKey.initialize());
152 ATH_CHECK(m_evtInfoContKey.initialize());
153 ATH_CHECK(m_beamSpotKey.initialize());
154
155 // Trace skipped events
156 if (m_writeTrace) {
158 ISkipEventIdxSvc::EvtIter end) -> StatusCode {
159 std::string trace_buf{};
160 auto trace = std::back_inserter(trace_buf);
161 for (; it != end; ++it) {
162 std::format_to(trace, "SKIPPING Run: {} LB: {} EVT: {} HS ID: {}\n",
163 it->runNum, it->lbNum, it->evtNum, it->evtIdx);
164 }
165 m_pileupTrace.print(trace_buf);
166 return StatusCode::SUCCESS;
167 };
168 if (!m_skiptrace_written) {
169 ATH_CHECK(m_skipEventIdxSvc->registerCallback(handler));
170 m_skiptrace_written = true;
171 }
172 }
173 return StatusCode::SUCCESS;
174}
175
177 ATH_MSG_DEBUG("Finalizing " << name() << "...");
178 //
179 // Things that happen once at the end of the event loop go here
180 //
181
182 return StatusCode::SUCCESS;
183}
184
185StatusCode PileUpMTAlg::execute(const EventContext& ctx) {
186 using PUType = xAOD::EventInfo::PileUpType;
187 std::string trace_buf{}; // Hold trace of events.
188 auto trace = std::back_inserter(trace_buf);
189 ATH_MSG_DEBUG("Executing " << name() << "...");
190 const auto& evtID = ctx.eventID();
191
192 ATH_CHECK(evtStore().retrieve());
193 setFilterPassed(false, ctx); // optional: start with algorithm not passed
194
195 // Code based on PileUpEventLoopMgr and PileUpToolsAlg (trying to extract the
196 // core merging code) Read hard scatter
197 std::unique_ptr<const xAOD::EventInfo> hsEvt = nullptr;
198 std::unique_ptr<xAOD::EventAuxInfo> hsEvtAux = nullptr;
199 ATH_CHECK(get_ei(*evtStore(), hsEvt, hsEvtAux));
200
201 // Setup overlaid event
203 ATH_CHECK(overlaidEvt.record(std::make_unique<xAOD::EventInfo>(),
204 std::make_unique<xAOD::EventAuxInfo>()));
205 *overlaidEvt = *hsEvt; // copy in hard scatter
206 overlaidEvt->setEvtStore(evtStore().get());
207 overlaidEvt->clearSubEvents();
208
209 // This was the problem. Need to fix overlaidEvt using context run and lb
210 // number
211 overlaidEvt->setRunNumber(evtID.run_number());
212 overlaidEvt->setLumiBlock(evtID.lumi_block());
213 overlaidEvt->setEventNumber(evtID.event_number());
214 overlaidEvt->setBCID(evtID.bunch_crossing_id());
215 overlaidEvt->setTimeStamp(evtID.time_stamp());
216 overlaidEvt->setTimeStampNSOffset(evtID.time_stamp_ns_offset());
217 // Set beam spot info
219 if (!beamSpotHandle.isValid()) {
220 ATH_MSG_ERROR("Beam spot information not valid");
221 return StatusCode::FAILURE;
222 }
223
224 overlaidEvt->setBeamPos(beamSpotHandle->beamPos()[Amg::x],
225 beamSpotHandle->beamPos()[Amg::y],
226 beamSpotHandle->beamPos()[Amg::z]);
227 overlaidEvt->setBeamPosSigma(beamSpotHandle->beamSigma(0),
228 beamSpotHandle->beamSigma(1),
229 beamSpotHandle->beamSigma(2));
230 overlaidEvt->setBeamPosSigmaXY(beamSpotHandle->beamSigmaXY());
231 overlaidEvt->setBeamTiltXZ(beamSpotHandle->beamTilt(0));
232 overlaidEvt->setBeamTiltYZ(beamSpotHandle->beamTilt(1));
233 overlaidEvt->setBeamStatus(beamSpotHandle->beamStatus());
234
235 // Pileup container
237 ATH_CHECK(puCont.record(std::make_unique<xAOD::EventInfoContainer>(),
238 std::make_unique<xAOD::EventInfoAuxContainer>()));
239
240 // Get crossing number
241 m_beamInt->selectT0(ctx);
242 overlaidEvt->setBCID(m_beamInt->getCurrentT0BunchCrossing());
243
244 // Set simulation bit
245 overlaidEvt->setEventTypeBitmask(hsEvt->eventTypeBitmask() |
247
248 // Set properties
249 bool sf_updated = false;
250 float lumi_sf = m_beamLumi->scaleFactor(evtID.run_number(),
251 evtID.lumi_block(), sf_updated);
252 float cur_avg_mu = lumi_sf * m_avgMu;
253 overlaidEvt->setAverageInteractionsPerCrossing(cur_avg_mu);
254 overlaidEvt->setActualInteractionsPerCrossing(m_beamInt->normFactor(0) *
255 cur_avg_mu);
256
257 // Trace
258 if (m_writeTrace) {
259 std::format_to(trace,
260 "Idx: {} Run: {} LB: {} EVT: {} "
261 "HS ID: {}\n",
262 ctx.evt(), evtID.run_number(), evtID.lumi_block(),
263 evtID.event_number(), m_lowptMBSvc->get_hs_id(ctx));
264 auto bunch_pattern =
265 rv::closed_iota(m_earliestDeltaBC.value(), m_latestDeltaBC.value()) |
266 rv::transform(
267 [this](int bc) { return int(m_beamInt->normFactor(bc)); }) |
268#if RANGE_V3_VERSION >= 1200
269 rv::chunk_by(std::equal_to{}) |
270#else
271 rv::group_by(std::equal_to{}) |
272#endif
273 rv::transform([](const auto& rng) {
274 return std::format("{}{}", rng.size(), rng[0] == 0 ? 'E' : 'F');
275 }) |
276 ranges::to<std::vector<std::string>>;
277 // Manual join using std::ostringstream as std::format does not support ranges
278 std::string joined_pattern;
279 for (size_t i = 0; i < bunch_pattern.size(); ++i) {
280 joined_pattern += bunch_pattern[i];
281 if (i + 1 < bunch_pattern.size()) {
282 joined_pattern += " ";
283 }
284 }
285
286 std::format_to(trace,
287 "mu = {}, central BCID = {}, bunch pattern = [{}]\n",
288 cur_avg_mu, m_beamInt->getCurrentT0BunchCrossing(),
289 joined_pattern);
290 }
291 // Copy subevents
292 if (!hsEvt->subEvents().empty()) {
293 for (const SubEvent& se : hsEvt->subEvents()) {
294 addSubEvent(overlaidEvt.ptr(), se, puCont.ptr(), m_evtInfoContKey.key(),
295 evtStore().get());
296 }
297 } else {
298 // if no subevents, add original event
299 addSubEvent(overlaidEvt.ptr(), hsEvt.get(), 0, xAOD::EventInfo::Signal,
300 puCont.ptr(), m_evtInfoContKey.key(), evtStore().get());
301 }
302
303 // Initialize MinbiasSvcs
304 if (m_fracLowPt != 0) {
305 ATH_CHECK(m_lowptMBSvc->beginHardScatter(ctx));
306 }
307 if (m_fracHighPt != 0) {
308 ATH_CHECK(m_highptMBSvc->beginHardScatter(ctx));
309 }
310 if (m_numCavern != 0) {
311 ATH_CHECK(m_cavernMBSvc->beginHardScatter(ctx));
312 }
313 if (m_numBeamHalo != 0) {
314 ATH_CHECK(m_beamhaloMBSvc->beginHardScatter(ctx));
315 }
316 if (m_numBeamGas != 0) {
317 ATH_CHECK(m_beamgasMBSvc->beginHardScatter(ctx));
318 }
319
320 std::uint32_t central_bcid = overlaidEvt->bcid();
321 std::vector<std::uint32_t> bcid{};
322 bcid.reserve(m_latestDeltaBC - m_earliestDeltaBC + 1);
323
324 for (int bc = m_earliestDeltaBC; bc <= m_latestDeltaBC; ++bc) {
325 bcid.push_back(get_BCID(bc, central_bcid));
326 }
327
328 // Setup tools
329 for (auto&& tool : m_puTools) {
330 // Reset filter -- Don't know if this is necessary
331 tool->resetFilter();
332 }
333
334 // Now add the events
335 std::uint64_t low_pt_count = 0;
336 std::uint64_t high_pt_count = 0;
337 std::uint64_t cavern_count = 0;
338 std::uint64_t beam_halo_count = 0;
339 std::uint64_t beam_gas_count = 0;
340 auto now = std::chrono::high_resolution_clock::now();
341 for (int bc = m_earliestDeltaBC; bc <= m_latestDeltaBC; ++bc) {
342 if (m_beamInt->normFactor(bc) == 0.) {
343 // skip empty bunch crossings
344 continue;
345 }
346 std::vector<std::uint64_t> subevts_vec{};
347 if (m_fracLowPt != 0) {
348 if (m_writeTrace) {
349 std::format_to(trace, "\tBC {:03} : LOW PT {} ", bc,
350 m_lowptMBSvc->getNumForBunch(ctx, bc));
351 }
352 for (std::size_t i = 0; i < m_lowptMBSvc->getNumForBunch(ctx, bc); ++i) {
353 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_lowptMBSvc,
354 PUType::MinimumBias, bc, ctx, low_pt_count,
355 subevts_vec));
356 ++low_pt_count;
357 }
358 }
359 if (m_fracHighPt != 0) {
360 if (m_writeTrace) {
361 std::format_to(trace, "HIGH PT {} | ",
362 m_highptMBSvc->getNumForBunch(ctx, bc));
363 }
364 for (std::size_t i = 0; i < m_highptMBSvc->getNumForBunch(ctx, bc); ++i) {
365 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_highptMBSvc,
366 PUType::HighPtMinimumBias, bc, ctx, high_pt_count,
367 subevts_vec));
368 ++high_pt_count;
369 }
370 }
371 if (m_numCavern != 0) {
372 if (m_writeTrace) {
373 std::format_to(trace, "CAVERN {} | ",
374 m_cavernMBSvc->getNumForBunch(ctx, bc));
375 }
376 for (std::size_t i = 0; i < m_cavernMBSvc->getNumForBunch(ctx, bc); ++i) {
377 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_cavernMBSvc,
378 PUType::Cavern, bc, ctx, cavern_count,
379 subevts_vec));
380 ++cavern_count;
381 }
382 }
383 if (m_numBeamHalo != 0) {
384 if (m_writeTrace) {
385 std::format_to(trace, "BEAM HALO {} | ",
386 m_beamhaloMBSvc->getNumForBunch(ctx, bc));
387 }
388 for (std::size_t i = 0; i < m_beamhaloMBSvc->getNumForBunch(ctx, bc);
389 ++i) {
390 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_beamhaloMBSvc,
391 PUType::HaloGas, bc, ctx, beam_halo_count,
392 subevts_vec));
393 ++beam_halo_count;
394 }
395 }
396 if (m_numBeamGas != 0) {
397 if (m_writeTrace) {
398 std::format_to(trace, "BEAM GAS {} | ",
399 m_beamgasMBSvc->getNumForBunch(ctx, bc));
400 }
401 for (std::size_t i = 0; i < m_beamgasMBSvc->getNumForBunch(ctx, bc);
402 ++i) {
403 ATH_CHECK(add_subevt(bcid, overlaidEvt, puCont, m_beamgasMBSvc,
404 PUType::HaloGas, bc, ctx, beam_gas_count,
405 subevts_vec));
406 ++beam_gas_count;
407 }
408 }
409 if (m_writeTrace) {
410 std::format_to(trace, "TOTAL {} | HASH {:08X}\n", subevts_vec.size(),
411 xxh3::hash64(subevts_vec));
412 }
413 }
414 if (m_writeTrace) {
415 std::format_to(trace, "\n");
416 m_pileupTrace.print(trace_buf);
417 }
418
419 for (auto&& tool : m_puTools) {
420 try {
421 ATH_CHECK(tool->processAllSubEvents(ctx));
422 } catch (const std::exception& e) {
423 ATH_MSG_ERROR("Caught exception running " << tool.name() << ": "
424 << e.what());
425 return StatusCode::FAILURE;
426 }
427 // Propagate filter result
428 if (!tool->filterPassed()) {
429 setFilterPassed(false, ctx);
430 }
431 }
432 ATH_MSG_DEBUG(std::format("***** Took {:%OMm %OSs} to process all subevents",
433 std::chrono::high_resolution_clock::now() - now));
434 //
435 // Save hash (direct copy from PileUpEventLoopMgr)
436 PileUpHashHelper pileUpHashHelper;
437 pileUpHashHelper.addToHashSource(overlaidEvt.cptr());
438 ATH_MSG_VERBOSE("Pile-up hash source:" << pileUpHashHelper.hashSource());
439
440 // Calculate and set hash
441 uuid_t pileUpHash;
442 pileUpHashHelper.calculateHash(pileUpHash);
443 overlaidEvt->setPileUpMixtureID(
445 ATH_MSG_DEBUG("PileUpMixtureID = " << overlaidEvt->pileUpMixtureID());
446
447 setFilterPassed(true, ctx); // if got here, assume that means algorithm passed
448 if (m_fracLowPt != 0) {
449 ATH_CHECK(m_lowptMBSvc->endHardScatter(ctx));
450 }
451 if (m_fracHighPt != 0) {
452 ATH_CHECK(m_highptMBSvc->endHardScatter(ctx));
453 }
454 if (m_numCavern != 0) {
455 ATH_CHECK(m_cavernMBSvc->endHardScatter(ctx));
456 }
457 if (m_numBeamHalo != 0) {
458 ATH_CHECK(m_beamhaloMBSvc->endHardScatter(ctx));
459 }
460 if (m_numBeamGas != 0) {
461 ATH_CHECK(m_beamgasMBSvc->endHardScatter(ctx));
462 }
463 return StatusCode::SUCCESS;
464}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
uint32_t CLID
The Class ID type.
An AttributeList represents a logical row of attributes in a metadata table.
A helper class to compute a hash of pile-up events.
xAOD::EventInfo::SubEvent SubEvent
std::string CLIDToString(const CLID &clid)
xAOD::EventInfo * addSubEvent(xAOD::EventInfo *targetEv, const xAOD::EventInfo::SubEvent &subev, xAOD::EventInfoContainer *eiContainer, const std::string &eiContKey, StoreGateSvc *subev_store=nullptr)
C++ native wrapper for the C xxhash API.
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
virtual void setFilterPassed(bool state, const EventContext &ctx) const
ServiceHandle< StoreGateSvc > & evtStore()
An AttributeList represents a logical row of attributes in a metadata table.
static const std::type_info * CLIDToTypeinfo(CLID clid)
Translate between CLID and type_info.
std::vector< EvtId >::const_iterator EvtIter
std::string hashSource() const
Get the current hash base.
void addToHashSource(const std::string &string)
Add a plain string to the stream.
void calculateHash(uuid_t &hash) const
Calculate the hash.
static xAOD::EventInfo::PileUpMixtureID uuidToPileUpMixtureId(const uuid_t &hash)
Convert uuid_t to xAOD::EventInfo::PileUpMixtureID.
Gaudi::Property< int > m_earliestDeltaBC
virtual StatusCode initialize() override
uncomment and implement methods as required
Gaudi::Property< int > m_latestDeltaBC
Gaudi::Property< bool > m_writeTrace
Gaudi::Property< float > m_avgMu
PileUpMTAlg(const std::string &name, ISvcLocator *pSvcLocator)
Gaudi::Property< float > m_numCavern
unsigned int get_BCID(int bc, unsigned int central_BCID) const
virtual ~PileUpMTAlg()
Gaudi::Property< float > m_fracLowPt
ServiceHandle< IBeamLuminosity > m_beamLumi
ToolHandleArray< IPileUpTool > m_puTools
SG::WriteHandleKey< xAOD::EventInfoContainer > m_evtInfoContKey
ServiceHandle< IAthRNGSvc > m_rngSvc
SG::ReadCondHandleKey< InDet::BeamSpotData > m_beamSpotKey
StatusCode get_ei(StoreGateSvc &sg, std::unique_ptr< const xAOD::EventInfo > &ei, std::unique_ptr< xAOD::EventAuxInfo > &eiAux, bool pileup=false) const
ServiceHandle< IMinbiasSvc > m_beamgasMBSvc
ServiceHandle< IMinbiasSvc > m_highptMBSvc
ServiceHandle< IMinbiasSvc > m_cavernMBSvc
Gaudi::Property< float > m_fracHighPt
SG::WriteHandleKey< xAOD::EventInfo > m_evtInfoKey
ServiceHandle< IBeamIntensity > m_beamInt
ServiceHandle< ISkipEventIdxSvc > m_skipEventIdxSvc
Gaudi::Property< int > m_skippedHSEvents
ServiceHandle< IMinbiasSvc > m_lowptMBSvc
Other useful methods provided by base class are: evtStore() : ServiceHandle to main event data storeg...
Gaudi::Property< float > m_numBeamGas
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
Gaudi::Property< float > m_numBeamHalo
virtual StatusCode finalize() override
StatusCode add_subevt(const std::vector< std::uint32_t > &bcid, SG::WriteHandle< xAOD::EventInfo > &overlaidEvt, SG::WriteHandle< xAOD::EventInfoContainer > &puCont, ServiceHandle< IMinbiasSvc > &mbSvc, xAOD::EventInfo::PileUpType puType, int bc, const EventContext &ctx, unsigned long subevt_id, std::vector< std::uint64_t > &trace)
ServiceHandle< IMinbiasSvc > m_beamhaloMBSvc
Gaudi::Property< int > m_BCSpacing
const_pointer_type get() const
Dereference the pointer, but don't cache anything.
const_pointer_type cptr() const
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
The Athena Transient Store API.
std::string dump() const
dump objects in store.
const T * tryConstRetrieve() const
Class describing the properties of one pileup sub-event.
void setBCID(uint32_t value)
Set the bunch crossing ID of the event.
PileUpType
Enumerator describing the types of pileup events.
@ Signal
The signal event.
@ IS_SIMULATION
true: simulation, false: data
uint64_t eventNumber() const
The current event's event number.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
EventInfo_v1 EventInfo
Definition of the latest event info version.
std::uint64_t hash64(const void *data, std::size_t size)
Passthrough to XXH3_64bits.
Definition XXH.cxx:9
void handler(int sig)
signal handler
Definition rmain.cxx:99