ATLAS Offline Software
SkipEventIdxSvc.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023, 2025 CERN for the benefit of the ATLAS collaboration.
3  */
4 #include "SkipEventIdxSvc.h"
5 
6 #include <GaudiKernel/DataIncident.h> // This header contains ContextIncident
7 #include <GaudiKernel/IEvtSelector.h>
8 #include <GaudiKernel/IIncidentSvc.h>
9 
10 #include <boost/core/typeinfo.hpp>
11 #include <range/v3/to_container.hpp>
12 #include <range/v3/view.hpp>
13 #include <string>
14 
18 
19 using namespace std::literals;
20 namespace rv = ranges::views;
21 
22 namespace {
23 template <typename propType, typename T>
24 const Gaudi::Property<propType>&
25 getProp(SmartIF<T>& iface, const std::string& name)
26 {
27  auto prop_iface = iface.template as<IProperty>();
28  const auto& prop = prop_iface->getProperty(name);
29  try {
30  const auto& conv_prop =
31  dynamic_cast<const Gaudi::Property<propType>&>(prop);
32  return conv_prop;
33  } catch (const std::bad_cast&) {
34  std::string if_name = "UNKNOWN";
35  try {
36  if_name = iface.template as<INamedInterface>()->name();
37  } catch (...) {
38  }
39  const std::string what = std::format(
40  "The {} object's {} property has type {} not Gaudi::Property<{}>",
41  if_name, name, boost::core::demangled_name(typeid(prop)),
42  boost::core::demangled_name(typeid(propType)));
43  throw std::logic_error(what);
44  }
45 }
46 
47 template <typename T>
48 StatusCode setProp(SmartIF<T>& iface, const std::string& name,
49  const std::string& val) {
50  auto prop_iface = iface.template as<IProperty>();
51  return prop_iface->setProperty(name, val);
52 }
53 } // namespace
54 
55 SkipEventIdxSvc::SkipEventIdxSvc(const std::string& name, ISvcLocator* svc)
56  : base_class(name, svc) {}
57 
59  // This is a special service that runs through all the input events ahead of
60  // time, and records the run and lb numbers
61  ATH_MSG_INFO("Initializing SkipEventIdxSvc");
62  SmartIF<IProperty> propMgr(serviceLocator());
63  std::string evt_sel_name{};
64  ATH_CHECK(propMgr->getProperty("EvtSel", evt_sel_name));
65  if (evt_sel_name.empty()) {
66  // No event selector
67  //
68  ATH_MSG_WARNING("No event selector");
69  m_started = true;
70  return StatusCode::SUCCESS;
71  }
72  auto sg = serviceLocator()->service<StoreGateSvc>("StoreGateSvc/StoreGateSvc",
73  false);
74  auto evtSel = serviceLocator()->service<IEvtSelector>(std::move(evt_sel_name), false);
75  if (!sg.isValid() || !evtSel.isValid()) {
76  ATH_MSG_WARNING("Event selector or storegate is invalid");
77  return StatusCode::FAILURE;
78  }
79 
80  auto modSvc = serviceLocator()->service<IEvtIdModifierSvc>(
81  "EvtIdModifierSvc/EvtIdModifierSvc", false);
82  std::uint64_t evts_skipped_before_mod = 0;
83  std::vector<EvtId> modifier_evts{};
84  if (modSvc.isValid()) {
85  // Steal it's configuration
86  try {
87  evts_skipped_before_mod =
88  getProp<std::uint64_t&>(modSvc, "SkipEvents").value();
89  ATH_MSG_INFO("Skipping " << evts_skipped_before_mod
90  << " events before modifying");
91  std::vector<std::uint64_t> lst =
92  getProp<std::vector<std::uint64_t>&>(modSvc, "Modifiers").value();
93  ATH_MSG_DEBUG("Printing EvtId modifier config. There are "
94  << lst.size() / 6 << " entries.");
95  std::string config_str{};
96  auto config_str_iter = std::back_inserter(config_str);
97  modifier_evts =
98  lst | rv::chunk(6) |
99  rv::for_each([&config_str_iter](const auto& rec) {
100  const int mod_bitset = rec[5];
101  const bool mod_run_num = mod_bitset & 1;
102  const bool mod_evt_num = mod_bitset & (1 << 1);
103  const bool mod_lb_num = mod_bitset & (1 << 3);
104 
105  const std::uint64_t runNum = mod_run_num ? rec[0] : 0;
106  const std::uint64_t evtNum = mod_evt_num ? rec[1] : 0;
107  const std::uint64_t lbNum = mod_lb_num ? rec[3] : 0;
108  const std::uint64_t numEvts = rec[4];
109 
110  std::format_to(config_str_iter,
111  "Run: {} [{:c}] LB: {} [{:c}] EVT: {} [{:c}] "
112  "NumEvts: {}\n",
113  runNum, mod_run_num ? 'Y' : 'N', lbNum,
114  mod_lb_num ? 'Y' : 'N', evtNum,
115  mod_evt_num ? 'Y' : 'N', numEvts);
116  return ranges::yield_from(
117  rv::repeat_n(EvtId{static_cast<uint32_t>(runNum),
118  static_cast<uint32_t>(lbNum), evtNum},
119  numEvts));
120  }) |
121  ranges::to<std::vector<EvtId>>;
122  ATH_MSG_DEBUG(config_str);
123  } catch (const std::bad_cast&) {
124  ATH_MSG_ERROR("Wrong type for property of EvtIdModifierSvc.");
125  }
126  } else {
127  ATH_MSG_INFO("No EvtIdModifierSvc found");
128  }
129 
130  m_initial_skip_events = getProp<int>(evtSel, "SkipEvents");
131  ATH_CHECK(setProp(evtSel, "SkipEvents", "0"));
132  IEvtSelector::Context* ctx = nullptr;
133  ATH_CHECK(sg->clearStore());
134  ATH_CHECK(evtSel->createContext(ctx));
135 
136  std::uint64_t idx = 0;
137  Service* evtSelSvc = dynamic_cast<Service*>(evtSel.get());
138  if (!evtSelSvc) {
139  ATH_MSG_FATAL("Cannot cast to Service");
140  return StatusCode::FAILURE;
141  }
142  ATH_CHECK(evtSelSvc->start());
143  while (evtSel->next(*ctx).isSuccess()) {
144  EvtId evt_id{};
145  // Load event
146  IOpaqueAddress* addr = nullptr;
147  ATH_CHECK(evtSel->createAddress(*ctx, addr));
148  ATH_CHECK(sg->recordAddress(addr));
149  ATH_CHECK(sg->loadEventProxies());
150 
151  // Read EventInfo
152  // We don't look for the legacy EventInfo, only an Input attribute list and
153  // if that doesn't exist, and xAOD::EventInfo
154  std::vector<std::string> attr_lists;
155  sg->keys<AthenaAttributeList> (attr_lists);
156  const auto* attr_list_p =
157  sg->tryConstRetrieve<AthenaAttributeList>("Input");
158  if (attr_list_p != nullptr && attr_list_p->size() > 6) {
159  try {
160  const AthenaAttributeList& attr_list = *attr_list_p;
161  const auto runNum = attr_list["RunNumber"].data<unsigned>();
162  const auto evtNum = attr_list["EventNumber"].data<unsigned long long>();
163  const auto lbNum = attr_list["LumiBlockN"].data<unsigned>();
164  evt_id = EvtId{runNum, lbNum, evtNum};
165  } catch (...) {
166  }
167  }
168  ATH_CHECK(sg->clearStore());
169  if (idx >= evts_skipped_before_mod && !modifier_evts.empty()) {
170  const std::size_t mod_idx =
171  (idx - evts_skipped_before_mod) % modifier_evts.size();
172  evt_id.runNum = modifier_evts[mod_idx].runNum != 0U
173  ? modifier_evts[mod_idx].runNum
174  : evt_id.runNum;
175  evt_id.lbNum = modifier_evts[mod_idx].lbNum != 0U
176  ? modifier_evts[mod_idx].lbNum
177  : evt_id.lbNum;
178  evt_id.evtNum = modifier_evts[mod_idx].evtNum != 0U
179  ? modifier_evts[mod_idx].evtNum
180  : evt_id.evtNum;
181  }
182  evt_id.evtIdx = idx;
183  m_events.push_back(evt_id);
184  ++idx;
185  }
186 
187  // reset current storegate
188  ATH_MSG_INFO("Setting SkipEvents back to " << m_initial_skip_events
189  << " and rewinding");
190  ATH_CHECK(
191  setProp(evtSel, "SkipEvents", std::format("{}", m_initial_skip_events)));
192  ATH_CHECK(evtSel->rewind(*ctx));
193  ATH_MSG_INFO("Recorded a total of " << m_events.size() << " events");
194 
195  // Register as incident handler
196  ServiceHandle<IIncidentSvc> incident_svc("IncidentSvc", name());
197  ATH_CHECK(incident_svc.retrieve());
198  incident_svc->addListener(this, "BeginRun");
199  incident_svc->addListener(this, "SkipEvents");
200  return StatusCode::SUCCESS;
201 }
202 
204  ATH_MSG_INFO("Starting SkipEventIdxSvc");
205  // Call callbacks if any have already been added
206  for (auto&& callback : m_callbacks) {
207  auto begin = m_events.cbegin();
208  auto end = m_events.cbegin() + m_initial_skip_events;
209  ATH_CHECK(std::invoke(callback, begin, end));
210  }
211  m_started = true;
212  return StatusCode::SUCCESS;
213 }
214 
216  std::function<StatusCode(EvtIter, EvtIter)>&& callback) {
217  m_callbacks.push_back(callback);
218  // Call callback immediately for events skipped in EventSelector if already
219  // started
220  if (m_started && !m_events.empty()) {
221  auto begin = m_events.cbegin();
222  auto end = m_events.cbegin() +
223  std::min(std::size_t(m_initial_skip_events), m_events.size());
224  ATH_CHECK(std::invoke(callback, begin, end));
225  }
226  return StatusCode::SUCCESS;
227 }
228 
229 void SkipEventIdxSvc::handle(const Incident& inc) {
230  if (inc.type() != "BeginRun"s && inc.type() != "SkipEvents"s) {
231  return;
232  }
233  ATH_MSG_DEBUG("Received incident of type " << inc.type() << " from "
234  << inc.source());
235  if (inc.type() == "SkipEvents"s) {
236  ATH_MSG_DEBUG("Running callbacks");
237  const auto& cInc =
238  dynamic_cast<const ContextIncident<std::tuple<int, int>>&>(inc);
239  auto begin = m_events.cbegin() + std::get<0>(cInc.tag());
240  auto end = m_events.cbegin() + std::get<1>(cInc.tag()) +
241  1; // plus 1 for 1 after end
242  for (auto&& fn : m_callbacks) {
243  if (!std::invoke(fn, begin, end).isSuccess()) {
244  throw std::runtime_error(
245  "A skipEvent callback returned a failure error code!");
246  }
247  }
248  }
249 }
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
vtune_athena.format
format
Definition: vtune_athena.py:14
ATH_MSG_INFO
#define ATH_MSG_INFO(x)
Definition: AthMsgStreamMacros.h:31
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
PlotCalibFromCool.begin
begin
Definition: PlotCalibFromCool.py:94
runLayerRecalibration.callback
callback
Definition: runLayerRecalibration.py:64
athena.value
value
Definition: athena.py:124
skel.runNum
runNum
Definition: skel.ABtoEVGEN.py:137
IEvtIdModifierSvc
Definition: IEvtIdModifierSvc.h:37
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:92
SkipEventIdxSvc::m_initial_skip_events
int m_initial_skip_events
Definition: SkipEventIdxSvc.h:26
IEvtIdModifierSvc.h
python.getCurrentFolderTag.fn
fn
Definition: getCurrentFolderTag.py:79
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
SkipEventIdxSvc::handle
void handle(const Incident &inc) override
Definition: SkipEventIdxSvc.cxx:229
SkipEventIdxSvc::start
StatusCode start() override
Definition: SkipEventIdxSvc.cxx:203
SkipEventIdxSvc::m_callbacks
std::vector< std::function< StatusCode(EvtIter, EvtIter)> > m_callbacks
Definition: SkipEventIdxSvc.h:28
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
AthenaAttributeList
An AttributeList represents a logical row of attributes in a metadata table. The name and type of eac...
Definition: PersistentDataModel/PersistentDataModel/AthenaAttributeList.h:45
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
SkipEventIdxSvc::SkipEventIdxSvc
SkipEventIdxSvc(const std::string &name, ISvcLocator *svc)
Definition: SkipEventIdxSvc.cxx:55
python.getProblemFolderFromLogs.lst
lst
Definition: getProblemFolderFromLogs.py:44
python.ExitCodes.what
def what(code)
Definition: ExitCodes.py:73
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
SkipEventIdxSvc::initialize
StatusCode initialize() override
Definition: SkipEventIdxSvc.cxx:58
SkipEventIdxSvc::registerCallback
StatusCode registerCallback(std::function< StatusCode(EvtIter, EvtIter)> &&callback) override
Definition: SkipEventIdxSvc.cxx:215
dq_make_web_display.rv
def rv
Definition: dq_make_web_display.py:218
AthenaAttributeList.h
An AttributeList represents a logical row of attributes in a metadata table. The name and type of eac...
EventInfo.h
CxxUtils::to
CONT to(RANGE &&r)
Definition: ranges.h:39
hydjet.StoreGateSvc
StoreGateSvc
Definition: hydjet.minbias.pbpb5520.r12345.job.py:40
SkipEventIdxSvc::m_events
std::vector< EvtId > m_events
Definition: SkipEventIdxSvc.h:27
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
LArNewCalib_DelayDump_OFC_Cali.idx
idx
Definition: LArNewCalib_DelayDump_OFC_Cali.py:69
python.SystemOfUnits.s
float s
Definition: SystemOfUnits.py:147
SkipEventIdxSvc::m_started
bool m_started
Definition: SkipEventIdxSvc.h:29
SkipEventIdxSvc.h
ServiceHandle< IIncidentSvc >