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 static const std::vector<std::string> allowed_streams{
61 "StreamAOD", "StreamEVGEN", "StreamEVNT"};
62 bool isGoodBook(const xAOD::CutBookkeeper& cbk) {
63 const auto& s = allowed_streams;
64 return cbk.name() == "AllExecutedEvents"
65 && std::find(s.begin(), s.end(), cbk.inputStream()) != s.end();
66 }
67
68}
69
70namespace ftag {
71
73 const std::string& name,
74 ISvcLocator* pSvcLocator):
75 AthAlgorithm(name, pSvcLocator),
76 m_inputMetaStore("StoreGateSvc/InputMetaDataStore", name)
77 {
78 }
79
81 {
82 // register with incident service
83 ServiceHandle<IIncidentSvc> incSvc( "IncidentSvc", name() );
84 CHECK( incSvc.retrieve() );
85 // remove first to make sure it's not called twice
86 incSvc->removeListener( this, IncidentType::BeginInputFile );
87 incSvc->addListener( this, IncidentType::BeginInputFile, 0, true );
88
89 CHECK(m_truthWeightTool.retrieve());
90
91 if (!m_output_svc.empty()) {
92 ATH_CHECK(m_output_svc.retrieve());
93 }
94 if (!m_hist_output_svc.empty()) {
95 ATH_CHECK(m_hist_output_svc.retrieve());
96 }
97
98 return StatusCode::SUCCESS;
99 }
100
102 {
103 return StatusCode::SUCCESS;
104 }
105
106 void MetadataAlg::handle(const Incident& inc)
107 {
108
109 // skip all incidents beyond the start of input files
110 if (inc.type() != IncidentType::BeginInputFile) return;
111
112 ATH_MSG_DEBUG("Updating CutBookkeeper information");
113
114 // Retrieve complete CutBookkeeperContainer
115 const xAOD::CutBookkeeperContainer *completeCBC{};
116 auto rc = m_inputMetaStore->retrieve(completeCBC, "CutBookkeepers");
117 if (!rc.isSuccess()) throw std::runtime_error(
118 "could not retrieve CutBookkeepers");
119
120 // Find the max cycle
121 int maxCycle{-1};
122 const xAOD::CutBookkeeper *allEvents{};
123 for (const xAOD::CutBookkeeper *cbk : *completeCBC)
124 {
126 "Complete cbk name: " << cbk->name() <<
127 " - stream: " << cbk->inputStream()
128 );
129
130 if (cbk->cycle() > maxCycle && isGoodBook(*cbk))
131 {
132 allEvents = cbk;
133 maxCycle = cbk->cycle();
134 }
135 }
136
137 if (allEvents == nullptr)
138 {
139 std::string error(
140 "Could not find AllExecutedEvents CutBookkeeper information.");
141 throw std::runtime_error(error);
142 }
143
144 for (const xAOD::CutBookkeeper *cbk : *completeCBC)
145 {
146 if (cbk->cycle() == maxCycle && isGoodBook(*cbk))
147 {
148 static const std::regex re("AllExecutedEvents.*_([0-9]+)");
149 // Get the CBK index
150 size_t index{0};
151 std::smatch match;
152 if (std::regex_match(cbk->name(), match, re))
153 {
154 index = std::stoi(match[1]);
155 }
156 m_weights[index] += getCounts(*cbk);
157 }
158 }
159
160 // now try systematics-aware containers
161 for (size_t index{1}; index < m_truthWeightTool->getWeightNames().size(); ++index)
162 {
163 std::string cbkName = "CutBookkeepers_weight_" + std::to_string(index);
164 if (!m_inputMetaStore->contains<xAOD::CutBookkeeperContainer>(cbkName))
165 {
166 ATH_MSG_VERBOSE("No container named " << cbkName << "available");
167 continue;
168 }
169
170 if (!m_inputMetaStore->retrieve(completeCBC, cbkName).isSuccess()) {
171 throw std::runtime_error("could not retrieve " + cbkName);
172 }
173 for (const xAOD::CutBookkeeper *cbk : *completeCBC)
174 {
175 if (cbk->cycle() == maxCycle && isGoodBook(*cbk))
176 {
177 m_weights[index] += getCounts(*cbk);
178 }
179 }
180 }
181 }
182
183
185 {
186
187 std::vector<CP::SystematicSet> systematics;
188 systematics.emplace_back(); // nominal always first
190 for (const CP::SystematicVariation& v :
191 m_truthWeightTool->affectingSystematics()) {
193 "using systematic " << CP::SystematicSet({v}).name());
194 systematics.emplace_back(CP::SystematicSet({v}));
195 }
196 }
197
198 std::optional<H5::Group> h5_cbk;
199 if (!m_output_svc.empty()) {
200 h5_cbk = H5::Group(m_output_svc->group()->createGroup(top_group));
201 }
202 std::optional<boost::json::object> json_cbk;
203 if (!m_json_output.empty()) {
204 json_cbk = boost::json::object{};
205 }
206
207 for (const CP::SystematicSet &sys : systematics)
208 {
209 const std::string sysname = sys.name().empty() ? "nominal": sys.name();
211 m_truthWeightTool->getSysWeightIndex(sys));
212
213 if (h5_cbk) {
214 H5::Group sysgroup(h5_cbk->createGroup(sysname));
215 addCounts(sysgroup, weights);
216 }
217 if (json_cbk) {
218 boost::json::object& cbk_root = *json_cbk;
219 addCounts(cbk_root[sysname].emplace_object(), weights);
220 }
221 }
222 if (json_cbk) {
223 std::ofstream out(m_json_output.value());
224 boost::json::object jroot {
225 {top_group, *json_cbk}
226 };
227 out << jroot << std::endl;
228 }
229
230 if (!m_hist_output_svc.empty()) {
231 namespace bh = boost::histogram;
232
233 // Build index->name map and index list in one pass.
234 using sys_map_t = std::map<size_t, std::string>;
235 sys_map_t sys_map;
236 std::vector<size_t> indices;
237 for (const CP::SystematicSet& sys : systematics) {
238 size_t idx = m_truthWeightTool->getSysWeightIndex(sys);
239 sys_map[idx] = sys.name().empty() ? "nominal" : sys.name();
240 indices.push_back(idx);
241 }
242
243 // Categorical axis: bin value = index, metadata = map for labels.
244 using map_meta_t = std::pair<std::string, sys_map_t>;
245 using sys_ax_t = bh::axis::category<size_t, map_meta_t>;
246 const sys_ax_t ax(indices, map_meta_t{"systematic", sys_map});
247
248 // Weighted histogram: bin=(sumOfWeights, sumOfWeightsSquared).
249 auto h_w = bh::make_weighted_histogram(ax);
250
251 // Integer histogram: nEventsProcessed.
252 using int64_storage = bh::dense_storage<int64_t>;
253 auto h_n = bh::make_histogram_with(int64_storage{}, ax);
254
255 // Fill by systematic index.
256 for (size_t idx : indices) {
257 const auto& w = m_weights.at(idx);
258 const auto bin = ax.index(idx);
259 h_w.at(bin) =
260 bh::accumulators::weighted_sum<double>(
261 w.sumOfWeights, w.sumOfWeightsSquared);
262 h_n.at(bin) =
263 static_cast<int64_t>(w.nEventsProcessed);
264 }
265
266 H5::Group hist_grp(
267 m_hist_output_svc->group()
268 ->createGroup("cutBookkeeperHists"));
270 hist_grp, h_w, "sumOfWeights");
272 hist_grp, h_n, "nEventsProcessed");
273 }
274
275 return StatusCode::SUCCESS;
276 }
277
278}
const boost::regex re(r_e)
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_VERBOSE(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
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:37
Gaudi::Property< bool > m_enable_systematics
Definition MetadataAlg.h:48
std::unordered_map< size_t, OriginalAodCounts > m_weights
Definition MetadataAlg.h:51
ServiceHandle< IH5GroupSvc > m_output_svc
Definition MetadataAlg.h:40
Gaudi::Property< std::string > m_json_output
Definition MetadataAlg.h:42
void handle(const Incident &) override
ServiceHandle< IH5GroupSvc > m_hist_output_svc
Definition MetadataAlg.h:45
StatusCode initialize() override
MetadataAlg(const std::string &name, ISvcLocator *pSvcLocator)
ServiceHandle< StoreGateSvc > m_inputMetaStore
Definition MetadataAlg.h:35
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:357
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.