ATLAS Offline Software
Loading...
Searching...
No Matches
MetadataAlg.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#include <src/MetadataAlg.h>
6
7#include "HDF5Utils/Writer.h"
9#include <boost/histogram.hpp>
10
16
17#include <regex>
18#include <fstream>
19#include <boost/json.hpp>
20
21//
22// method implementations
23//
24
25namespace {
26
27 // name for top level object in json or h5
28 static const std::string top_group = "cutBookkeeper";
29
30 void addCounts(H5::Group& grp, const OriginalAodCounts& counts){
32#define ADD(NAME) \
33 cons.add(#NAME,[](const OriginalAodCounts& c) {return c.NAME;})
34 ADD(nEventsProcessed);
35 ADD(sumOfWeights);
36 ADD(sumOfWeightsSquared);
37#undef ADD
39 writer.fill(counts);
40 }
41 void addCounts(boost::json::object& grp, const OriginalAodCounts& counts) {
42 grp["counts"] = {
43#define ADD(NAME) {#NAME, counts.NAME}
44 ADD(nEventsProcessed),
45 ADD(sumOfWeights),
46 ADD(sumOfWeightsSquared),
47#undef ADD
48 };
49 }
50
51 OriginalAodCounts getCounts(const xAOD::CutBookkeeper& cbk)
52 {
54 counts.nEventsProcessed = cbk.nAcceptedEvents();
55 counts.sumOfWeights = cbk.sumOfEventWeights();
56 counts.sumOfWeightsSquared = cbk.sumOfEventWeightsSquared();
57 return counts;
58 }
59
60}
61
62namespace ftag {
63
65 const std::string& name,
66 ISvcLocator* pSvcLocator):
67 AthAlgorithm(name, pSvcLocator),
68 m_inputMetaStore("StoreGateSvc/InputMetaDataStore", name)
69 {
70 }
71
73 {
74 return cbk.name() == "AllExecutedEvents"
75 && m_allowed_streams.value().contains(cbk.inputStream());
76 }
77
79 {
80 // register with incident service
81 ServiceHandle<IIncidentSvc> incSvc( "IncidentSvc", name() );
82 CHECK( incSvc.retrieve() );
83 // remove first to make sure it's not called twice
84 incSvc->removeListener( this, IncidentType::BeginInputFile );
85 incSvc->addListener( this, IncidentType::BeginInputFile, 0, true );
86
87 CHECK(m_truthWeightTool.retrieve());
88
89 if (!m_output_svc.empty()) {
90 ATH_CHECK(m_output_svc.retrieve());
91 }
92 if (!m_hist_output_svc.empty()) {
93 ATH_CHECK(m_hist_output_svc.retrieve());
94 }
95
96 return StatusCode::SUCCESS;
97 }
98
100 {
101 return StatusCode::SUCCESS;
102 }
103
104 void MetadataAlg::handle(const Incident& inc)
105 {
106
107 // skip all incidents beyond the start of input files
108 if (inc.type() != IncidentType::BeginInputFile) return;
109
110 ATH_MSG_DEBUG("Updating CutBookkeeper information");
111
112 // Retrieve complete CutBookkeeperContainer
113 const xAOD::CutBookkeeperContainer *completeCBC{};
114 auto rc = m_inputMetaStore->retrieve(completeCBC, "CutBookkeepers");
115 if (!rc.isSuccess()) throw std::runtime_error(
116 "could not retrieve CutBookkeepers");
117
118 // Find the max cycle
119 int maxCycle{-1};
120 const xAOD::CutBookkeeper *allEvents{};
121 for (const xAOD::CutBookkeeper *cbk : *completeCBC)
122 {
124 "Complete cbk name: " << cbk->name() <<
125 " - stream: " << cbk->inputStream()
126 );
127
128 if (cbk->cycle() > maxCycle && isGoodBook(*cbk))
129 {
130 allEvents = cbk;
131 maxCycle = cbk->cycle();
132 }
133 }
134
135 if (allEvents == nullptr)
136 {
137 throw std::runtime_error(
138 "Could not find AllExecutedEvents CutBookkeeper information.");
139 }
140
141 for (const xAOD::CutBookkeeper *cbk : *completeCBC)
142 {
143 if (cbk->cycle() == maxCycle && isGoodBook(*cbk))
144 {
145 static const std::regex re("AllExecutedEvents.*_([0-9]+)");
146 // Get the CBK index
147 size_t index{0};
148 std::smatch match;
149 if (std::regex_match(cbk->name(), match, re))
150 {
151 index = std::stoi(match[1]);
152 }
153 m_weights[index] += getCounts(*cbk);
154 }
155 }
156
157 // now try systematics-aware containers
158 for (size_t index{1}; index < m_truthWeightTool->getWeightNames().size(); ++index)
159 {
160 std::string cbkName = "CutBookkeepers_weight_" + std::to_string(index);
161 if (!m_inputMetaStore->contains<xAOD::CutBookkeeperContainer>(cbkName))
162 {
163 ATH_MSG_VERBOSE("No container named " << cbkName << "available");
164 continue;
165 }
166
167 if (!m_inputMetaStore->retrieve(completeCBC, cbkName).isSuccess()) {
168 throw std::runtime_error("could not retrieve " + cbkName);
169 }
170 for (const xAOD::CutBookkeeper *cbk : *completeCBC)
171 {
172 if (cbk->cycle() == maxCycle && isGoodBook(*cbk))
173 {
174 m_weights[index] += getCounts(*cbk);
175 }
176 }
177 }
178 }
179
180
182 {
183
184 if (m_weights.empty()) {
185 ATH_MSG_WARNING("No CutBookkeeper weights collected; skipping output.");
186 return StatusCode::SUCCESS;
187 }
188
189 std::vector<CP::SystematicSet> systematics;
190 systematics.emplace_back(); // nominal always first
192 for (const CP::SystematicVariation& v :
193 m_truthWeightTool->affectingSystematics()) {
195 "using systematic " << CP::SystematicSet({v}).name());
196 systematics.emplace_back(CP::SystematicSet({v}));
197 }
198 }
199
200 std::optional<H5::Group> h5_cbk;
201 if (!m_output_svc.empty()) {
202 h5_cbk = H5::Group(m_output_svc->group()->createGroup(top_group));
203 }
204 std::optional<boost::json::object> json_cbk;
205 if (!m_json_output.empty()) {
206 json_cbk = boost::json::object{};
207 }
208
209 for (const CP::SystematicSet &sys : systematics)
210 {
211 const std::string sysname = sys.name().empty() ? "nominal": sys.name();
213 m_truthWeightTool->getSysWeightIndex(sys));
214
215 if (h5_cbk) {
216 H5::Group sysgroup(h5_cbk->createGroup(sysname));
217 addCounts(sysgroup, weights);
218 }
219 if (json_cbk) {
220 boost::json::object& cbk_root = *json_cbk;
221 addCounts(cbk_root[sysname].emplace_object(), weights);
222 }
223 }
224 if (json_cbk) {
225 std::ofstream out(m_json_output.value());
226 boost::json::object jroot {
227 {top_group, *json_cbk}
228 };
229 out << jroot << std::endl;
230 }
231
232 if (!m_hist_output_svc.empty()) {
233 namespace bh = boost::histogram;
234
235 // Build index->name map and index list in one pass.
236 using sys_map_t = std::map<size_t, std::string>;
237 sys_map_t sys_map;
238 std::vector<size_t> indices;
239 for (const CP::SystematicSet& sys : systematics) {
240 size_t idx = m_truthWeightTool->getSysWeightIndex(sys);
241 sys_map[idx] = sys.name().empty() ? "nominal" : sys.name();
242 indices.push_back(idx);
243 }
244
245 // Categorical axis: bin value = index, metadata = map for labels.
246 using map_meta_t = std::pair<std::string, sys_map_t>;
247 using sys_ax_t = bh::axis::category<size_t, map_meta_t>;
248 const sys_ax_t ax(indices, map_meta_t{"systematic", sys_map});
249
250 // Weighted histogram: bin=(sumOfWeights, sumOfWeightsSquared).
251 auto h_w = bh::make_weighted_histogram(ax);
252
253 // Integer histogram: nEventsProcessed.
254 using int64_storage = bh::dense_storage<int64_t>;
255 auto h_n = bh::make_histogram_with(int64_storage{}, ax);
256
257 // Fill by systematic index.
258 for (size_t idx : indices) {
259 const auto& w = m_weights.at(idx);
260 const auto bin = ax.index(idx);
261 h_w.at(bin) =
262 bh::accumulators::weighted_sum<double>(
263 w.sumOfWeights, w.sumOfWeightsSquared);
264 h_n.at(bin) =
265 static_cast<int64_t>(w.nEventsProcessed);
266 }
267
268 H5::Group hist_grp(
269 m_hist_output_svc->group()
270 ->createGroup("cutBookkeeperHists"));
272 hist_grp, h_w, "sumOfWeights");
274 hist_grp, h_n, "nEventsProcessed");
275 }
276
277 return StatusCode::SUCCESS;
278 }
279
280}
const boost::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
std::shared_ptr< HepMC3::Writer > writer
static Double_t rc
#define ADD(NAME)
static const std::vector< std::string > systematics
size_t size() const
Number of registered mappings.
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
Class to wrap a set of SystematicVariations.
std::string name() const
returns: the systematics joined into a single string.
Writer.
Definition Writer.h:351
ToolHandle< PMGTools::IPMGTruthWeightTool > m_truthWeightTool
Definition MetadataAlg.h:40
Gaudi::Property< bool > m_enable_systematics
Definition MetadataAlg.h:51
std::unordered_map< size_t, OriginalAodCounts > m_weights
Definition MetadataAlg.h:60
Gaudi::Property< std::set< std::string > > m_allowed_streams
Definition MetadataAlg.h:54
bool isGoodBook(const xAOD::CutBookkeeper &cbk) const
ServiceHandle< IH5GroupSvc > m_output_svc
Definition MetadataAlg.h:43
Gaudi::Property< std::string > m_json_output
Definition MetadataAlg.h:45
void handle(const Incident &) override
ServiceHandle< IH5GroupSvc > m_hist_output_svc
Definition MetadataAlg.h:48
StatusCode initialize() override
MetadataAlg(const std::string &name, ISvcLocator *pSvcLocator)
ServiceHandle< StoreGateSvc > m_inputMetaStore
Definition MetadataAlg.h:38
StatusCode execute() override
StatusCode finalize() override
double sumOfEventWeightsSquared() const
Get the sum-of-(event-weights-squared) that this CutBookkeeper has seen.
int cycle() const
Get the skimming cycle that this CutBookkeeper was running in.
const std::string & inputStream() const
Get the name of the input-file stream object that was seen by this CutBookkeeper.
double sumOfEventWeights() const
Get the sum-of-event-weights that this CutBookkeeper has seen.
const std::string & name() const
Get the name of this CutBookkeeper.
uint64_t nAcceptedEvents() const
Get the number of accepted events that this CutBookkeeper has seen.
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:359
void write_hist_to_group(H5::Group &group, const T &hist, const std::string &name)
Definition index.py:1
CutBookkeeper_v1 CutBookkeeper
Define the latest version of the CutBookkeeper class.
CutBookkeeperContainer_v1 CutBookkeeperContainer
Define the latest version of the CutBookkeeperContainer class.