ATLAS Offline Software
Loading...
Searching...
No Matches
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
19using namespace std::literals;
20namespace rv = ranges::views;
21
22namespace {
23template <typename propType, typename T>
24const Gaudi::Property<propType>&
25getProp(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
47template <typename T>
48StatusCode 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
55SkipEventIdxSvc::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
229void 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}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
An AttributeList represents a logical row of attributes in a metadata table.
An AttributeList represents a logical row of attributes in a metadata table.
StatusCode initialize() override
void handle(const Incident &inc) override
std::vector< std::function< StatusCode(EvtIter, EvtIter)> > m_callbacks
StatusCode start() override
SkipEventIdxSvc(const std::string &name, ISvcLocator *svc)
std::vector< EvtId > m_events
StatusCode registerCallback(std::function< StatusCode(EvtIter, EvtIter)> &&callback) override
The Athena Transient Store API.
::StatusCode StatusCode
StatusCode definition for legacy code.