ATLAS Offline Software
Loading...
Searching...
No Matches
MakeSystematicsVector.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8//
9// includes
10//
11
13
16#include <TRandom3.h>
17#include <TRegexp.h>
18#include <cstdint>
19#include <map>
20#include <memory>
21#include <stdexcept>
22
23//
24// method implementations
25//
26
27namespace CP
28{
29 namespace
30 {
41 uint32_t hash_string (const std::string& str)
42 {
43 uint32_t hash = 0;
44
45 for (char ch : str)
46 {
47 hash += ch;
48 hash += (hash << 10);
49 hash ^= (hash >> 6);
50 }
51
52 hash += (hash << 3);
53 hash ^= (hash >> 11);
54 hash += (hash << 15);
55
56 return hash;
57 }
58 }
59
60
61
62 void MakeSystematicsVector ::
63 testInvariant () const
64 {
65 RCU_INVARIANT (!m_config.empty());
66 }
67
68
69
70 MakeSystematicsVector ::
71 MakeSystematicsVector ()
72 : m_config (1)
73 {
74 RCU_NEW_INVARIANT (this);
75 }
76
77
78
79 const std::vector<SystematicSet>& MakeSystematicsVector ::
80 result (const std::string& label) const
81 {
82 RCU_READ_INVARIANT (this);
83 RCU_REQUIRE2 (!m_result.empty(), "calculate() has been called");
84 auto iter = m_result.find (label);
85 if (iter == m_result.end())
86 throw std::runtime_error ("unknown systematics group: " + label);
87 return iter->second;
88 }
89
90
91
92 void MakeSystematicsVector ::
93 calc (const SystematicSet& sysList)
94 {
96
97 auto baseSys = calcBaseSys (sysList);
98
99 std::map<std::string,std::vector<SystematicSet>> myresult;
100 myresult[m_useForNominal].push_back (SystematicSet ());
101 for (std::size_t group = 0; group != m_config.size(); ++ group)
102 {
103 const auto& config = m_config[group];
104
105 // note: this is not just a short-cut, but also makes sure that
106 // we have an entry for each label, even if there are no
107 // systematics for the label
108 auto& subresult = myresult[config.label];
109
110 // this skips groups that don't match any requested systematics,
111 // which is mainly important for toy systematics as you wouldn't
112 // want to generate a bunch of empty systematics
113 if (baseSys[group].empty())
114 continue;
115
116 if (config.toys == 0)
117 {
118 for (auto sys : baseSys[group])
119 {
120 RCU_ASSERT (!sys.second.empty());
121 RCU_ASSERT (!sys.second.front().isToyEnsemble());
122 if (sys.second.front().isContinuousEnsemble())
123 {
124 // for continuous systematics
125 subresult.push_back(CP::SystematicSet());
126 subresult.back().insert (CP::SystematicVariation (sys.first, config.sigma));
127 subresult.push_back(CP::SystematicSet());
128 subresult.back().insert (CP::SystematicVariation (sys.first, -config.sigma));
129 } else if (sys.second.front().isEnsemble())
130 {
131 // we must have added a new kind of ensemble after I wrote
132 // this code
133 throw std::runtime_error ("unsupported ensemble systematic: " + sys.first);
134 } else
135 {
136 // otherwise just add all of them flat
137 for (const auto & mysys : sys.second)
138 {
139 subresult.push_back(CP::SystematicSet());
140 subresult.back().insert(mysys);
141 }
142 }
143 }
144 } else
145 {
146 std::vector<CP::SystematicSet> toys (config.toys);
147
148 for (auto sys : baseSys[group])
149 {
150 RCU_ASSERT (!sys.second.empty());
151 RCU_ASSERT (sys.second.front().isEnsemble());
152
153 if (sys.second.front().isContinuousEnsemble())
154 {
155 std::unique_ptr<TRandom3> random (new TRandom3);
156 random->SetSeed (hash_string (sys.first));
157
158 for (auto& toy : toys)
159 toy.insert (CP::SystematicVariation (sys.first, random->Gaus (0, config.sigma)));
160 } else if (sys.second.front().isToyEnsemble())
161 {
162 for (unsigned toy = 0; toy != config.toys; ++ toy)
163 toys[toy].insert (CP::SystematicVariation::makeToyVariation (sys.first, toy + 1, config.sigma));
164 } else
165 {
166 // we must have added a new kind of ensemble after I
167 // wrote this code
168 throw std::runtime_error ("unsupported ensemble systematic for toys: " + sys.first);
169 }
170 }
171 for (auto& toy : toys)
172 subresult.push_back (std::move (toy));
173 }
174 }
175
176 m_result = std::move(myresult);
177 }
178
179
180
181 void MakeSystematicsVector ::
182 addGroup (const std::string& val_label)
183 {
185 GroupConfig config;
186 config.label = val_label;
187 m_config.push_back (std::move(config));
188 }
189
190
191
192 void MakeSystematicsVector ::
193 setPattern (const std::string& val_pattern)
194 {
196 m_config.back().pattern = val_pattern;
197 }
198
199
200
201 void MakeSystematicsVector ::
202 setSigma (float val_sigma)
203 {
205 RCU_REQUIRE (val_sigma > 0);
206 m_config.back().sigma = val_sigma;
207 }
208
209
210
211 void MakeSystematicsVector ::
212 setToys (unsigned val_toys)
213 {
215 RCU_REQUIRE (val_toys > 0);
216 m_config.back().toys = val_toys;
217 }
218
219
220
221 void MakeSystematicsVector ::
222 useForNominal ()
223 {
225 m_useForNominal = m_config.back().label;
226 }
227
228
229
230 std::vector<std::map<std::string,std::vector<SystematicVariation>>>
231 MakeSystematicsVector ::
232 calcBaseSys (const SystematicSet& sysList)
233 {
234 std::map<std::string,std::vector<SystematicVariation> > basesys;
235 for (const auto & sys : sysList)
236 {
237 basesys[sys.basename()].push_back (sys);
238 }
239 std::vector<std::map<std::string,std::vector<SystematicVariation> >>
240 basesysList (m_config.size());
241 for (auto sys : basesys)
242 {
243 // extract the ensemble if we have one
244 SystematicVariation ensemble;
245 for (const auto & mysys : sys.second)
246 {
247 if (mysys.isEnsemble())
248 {
249 if (!ensemble.empty())
250 throw std::runtime_error ("inconsistent ensembles requested: " + ensemble.name() + " " + mysys.name());
251 ensemble = mysys;
252 }
253 }
254
255 // setting this beyond the valid groups in case none matches
256 std::size_t group = m_config.size();
257 for (std::size_t iter = 0; iter != m_config.size(); ++ iter)
258 {
259 if (m_config[iter].pattern.empty())
260 {
261 // only use empty patterns if no previous pattern already took this
262 if (group == m_config.size())
263 {
264 if (m_config[iter].toys > 0)
265 {
266 if (ensemble.isToyEnsemble())
267 group = iter;
268 } else
269 {
270 if (!ensemble.isToyEnsemble())
271 group = iter;
272 }
273 }
274 } else if (RCU::match_expr (std::regex (m_config[iter].pattern.c_str()), sys.first))
275 {
276 if (m_config[iter].toys > 0 && ensemble.empty())
277 throw std::runtime_error ("toys only supported for ensemble systematics");
278 group = iter;
279 }
280 }
281 if (group == m_config.size())
282 throw std::runtime_error ("no systematics group for systematic: " + sys.first);
283
284 if (!ensemble.empty())
285 {
286 basesysList[group][sys.first].push_back (std::move(ensemble));
287 } else
288 {
289 basesysList[group][sys.first] = std::move (sys.second);
290 }
291 }
292 return basesysList;
293 }
294}
#define RCU_REQUIRE2(x, y)
Definition Assert.h:198
#define RCU_INVARIANT(x)
Definition Assert.h:187
#define RCU_ASSERT(x)
Definition Assert.h:210
#define RCU_CHANGE_INVARIANT(x)
Definition Assert.h:219
#define RCU_NEW_INVARIANT(x)
Definition Assert.h:221
#define RCU_REQUIRE(x)
Definition Assert.h:196
#define RCU_READ_INVARIANT(x)
Definition Assert.h:217
static const Attributes_t empty
std::string m_useForNominal
the group for which useForNominal was set
std::vector< std::map< std::string, std::vector< SystematicVariation > > > calcBaseSys(const SystematicSet &sysList)
make the list of base systematics for calc
std::vector< GroupConfig > m_config
the configuration on a per-group basis
std::map< std::string, std::vector< SystematicSet > > m_result
the value of result
Class to wrap a set of SystematicVariations.
static SystematicVariation makeToyVariation(const std::string &basename, unsigned toyIndex, float toyScale)
constructor for toy systematics
bool isToyEnsemble() const
whether this represents a toy ensemble
bool empty() const
returns: whether this is an empty systematic, i.e.
const std::string & name() const
description: the full systematics name, for use in strings, etc.
std::string label(const std::string &format, int i)
Definition label.h:19
Select isolated Photons, Electrons and Muons.
bool match_expr(const std::regex &expr, std::string_view str)
returns: whether we can match the entire string with the regular expression guarantee: strong failure...
std::string str(const TrigT2MbtsBits_v1 &trigT2MbtsBits)
setEventNumber uint32_t
the configuration for the given group