ATLAS Offline Software
Loading...
Searching...
No Matches
Database.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
9
10#include <fstream>
11#include <sstream>
12#include <algorithm>
13#include <regex>
14#include <limits>
15#include <functional>
16#include <cmath>
17
18#include "TFile.h"
19#include "TKey.h"
20#include "TH1.h"
21#include "TH2.h"
22
23using namespace FakeBkgTools;
24using namespace CP;
25
26Database::Database(Client client, bool useGeV, bool convertWhenMissing) :
27 m_useGeV(useGeV),
29 m_convertWhenMissing(convertWhenMissing)
30{
31 reset();
32}
33
35{
36 m_tables.clear();
37 m_systs.clear();
38 m_stats.clear();
39 m_params.clear();
40 m_params.emplace_back("eta", Param::Type::PREDEFINED_FLOAT, Param::Level::PARTICLE);
41 m_params.emplace_back("|eta|", Param::Type::PREDEFINED_FLOAT, Param::Level::PARTICLE);
42 m_params.emplace_back("pt", Param::Type::PREDEFINED_FLOAT, Param::Level::PARTICLE);
43 m_params.emplace_back("phi", Param::Type::PREDEFINED_FLOAT, Param::Level::PARTICLE);
44}
45
46bool Database::ready() const
47{
49 for(auto& kv : m_tables)
50 {
51 if(kv.second.size()) return true;
52 }
53 return false;
54}
55
57{
58 for(auto& param : m_params)
59 {
60 if(param.level == Param::Level::EVENT) return true;
61 }
62 return false;
63}
64
65bool Database::fillEfficiencies(ParticleData& pd, const xAOD::IParticle& p, const xAOD::EventInfo* eventInfo, std::string& error) const
66{
67 std::map<unsigned, EfficiencyTable::BoundType> cachedParamVals;
69 for(int wt=0;wt<N_EFFICIENCY_TYPES;++wt)
70 {
71 EfficiencyType wantedType = static_cast<EfficiencyType>(wt);
72 if(!m_typesToFill[wantedType]) continue;
73 Efficiency* eff = selectEfficiency(pd, p, wantedType);
74 if(!eff) continue;
75
77 EfficiencyType type = getSourceType(wantedType);
78
79 bool found_central = false;
80 eff->nominal = 1.f;
81 eff->uncertainties.clear();
82
83 auto relevantTables = m_tables.find(type);
84 if(relevantTables == m_tables.end())
85 {
86 error = "missing table for " + getTypeAsString(type);
87 return false;
88 }
89
91 for(auto& table : relevantTables->second)
92 {
93 int status = readEfficiencyFromTable(*eff, table, cachedParamVals, p, eventInfo, error);
94 if(status < 0) return false;
95 if(status == 1)
96 {
97 if(found_central)
98 {
99 error = "while retrieving " + getTypeAsString(type) + ", found two non-orthogonal tables providing the central value";
100 return false;
101 }
102 found_central = true;
103 }
104 }
105 if(!found_central)
106 {
107 error = "didn't find central value for " + getTypeAsString(type);
108 return false;
109 }
111 if(type != wantedType)
112 {
113 if(eff == &pd.fake_factor)
114 {
115 float f = eff->nominal/(1.f-eff->nominal), k = pow(f/eff->nominal, 2);
116 eff->nominal = f;
117 for(auto& kv : eff->uncertainties) kv.second *= k;
118 }
119 else if(eff == &pd.fake_efficiency)
120 {
121 float e = eff->nominal/(1.f+eff->nominal), k = pow(e/eff->nominal, 2);
122 eff->nominal = e;
123 for(auto& kv : eff->uncertainties) kv.second *= k;
124 }
125 }
126 }
127 return true;
128}
129
130int Database::readEfficiencyFromTable(Efficiency& eff, const EfficiencyTable& table, std::map<unsigned, EfficiencyTable::BoundType>& cachedParamVals, const xAOD::IParticle& p, const xAOD::EventInfo* eventInfo, std::string& error) const
131{
133 int bin = 0;
134 for(const auto& dim : table.m_dimensions)
135 {
136 auto& param = m_params[dim.paramUID];
137 auto ins = cachedParamVals.emplace(dim.paramUID, EfficiencyTable::BoundType{});
138 auto& val = ins.first->second;
139 if(ins.second)
140 {
141 if(!retrieveParameterValue(p, eventInfo, param, val))
142 {
143 error = "can't retrieve value of parameter \"" + param.name + "\"";
144 return -1;
145 }
146 }
147 auto first = table.m_bounds.begin()+dim.iMinBound, last = first+dim.nBounds;
148 auto ubound = std::upper_bound(first, last, val,
149 [=](auto x, auto y){ return param.integer() ? (x.as_int<y.as_int) : (x.as_float<y.as_float); });
150 if(ubound==first || ubound==last)
151 {
152 bin = -1;
153 break;
154 }
155 bin = bin * (dim.nBounds-1) + (ubound - first - 1);
156 }
157 if(bin < 0) return 0;
158
160 if(table.inputType != InputType::CENTRAL_VALUE && table.inputType != InputType::CORRECTION)
161 {
162 error = "unknown table type (tool implementation incomplete!)";
163 return -1;
164 }
165 auto& ref = table.m_efficiencies[bin];
166 for(auto& kv : eff.uncertainties) kv.second *= ref.nominal;
167 for(auto& kv : ref.uncertainties)
168 {
170 {
171 if(!eff.uncertainties.emplace(kv.first, eff.nominal*kv.second).second)
172 {
173 error = "central values and corrections must use different systematic uncertainties";
174 return -1;
175 }
176 }
177 }
178 eff.nominal *= ref.nominal;
179 return (table.inputType==InputType::CENTRAL_VALUE)? 1 : 2;
180}
181
182/*
183 * Loading from XML
184 */
185
186void Database::importXML(std::string filename)
187{
188 if (filename[0] != '/')
189 filename = PathResolverFindCalibFile(filename);
190
191 std::ifstream xml;
192 xml.open(filename, std::ios_base::binary);
193 auto begpos = xml.tellg();
194 xml.seekg(0, std::ios_base::end);
195 std::size_t bufferSize = 1.05 * static_cast<std::size_t>(xml.tellg() - begpos);
197 if(bufferSize > 0x100000) bufferSize = 0x100000;
198 xml.close();
199
200 xml.open(filename, std::ios_base::in);
201 if(!xml.is_open()) throw(GenericError() << "unable to open file " << filename);
202
203 std::string line;
204 m_xmlBuffer.reserve(bufferSize);
205 m_lineOffset.clear();
206 m_lineOffset.push_back(0);
207 while(std::getline(xml, line))
208 {
209 while(line.length() && (line.back()=='\n' || line.back()=='\r')) line.pop_back();
210 m_xmlBuffer += line + ' ';
211 m_lineOffset.push_back(m_xmlBuffer.length());
212 }
213 xml.close();
214
217
218 AttributesMap attributes;
219 resetAttributes(attributes);
220 StringRef stream(m_xmlBuffer.data(), m_xmlBuffer.length()), contents, tag;
221 while(stream.length())
222 {
223 readNextTag(stream, tag, attributes, contents);
224 if(tag=="electron" || tag=="muon" || tag=="tau") addTables(tag, attributes, contents);
225 else if(tag=="param") addParams(tag, contents, attributes);
226 else if(tag=="syst") addSysts(tag, contents, attributes);
227 else if(tag=="ROOT") importCustomROOT(tag, contents, attributes);
228 else throw(XmlError(stream) << "unknown/unexpected XML tag \"" << tag.str() << "\"");
229 }
230 m_lineOffset.clear();
231 m_lineOffset.shrink_to_fit();
232 m_xmlBuffer.clear();
233 m_xmlBuffer.shrink_to_fit();
234}
235
237{
238 tag.clear();
239 contents.clear();
240 for(auto& kv : attributes) kv.second.clear();
242 std::string pattern = "^\\s*(<([[:alnum:]]+)((?:\\s+\\|?[_[:alnum:]]+\\|?\\s*=\\s*\"[_[:alnum:]\\s,-\\[\\]\\.\\|]+\")*)\\s*>)(.*?)</\\2>\\s*";
243 std::cmatch cmr;
244 if(!std::regex_search(stream.ptr, stream.endptr, cmr, std::regex(pattern)))
245 {
247 throw(XmlError(stream) << "unable to find next tag");
248 }
249 tag.set(stream.ptr+cmr.position(2), cmr.length(2));
250
251 readTagAttributes(StringRef(stream.ptr+cmr.position(3), cmr.length(3)), tag.str(), attributes);
252
253 auto cpos = cmr.size()-1;
254 contents.set(stream.ptr+cmr.position(cpos), cmr.length(cpos));
255
256 stream.ptr += cmr.length();
257}
258
259void Database::readTagAttributes(StringRef stream, const std::string& tag, AttributesMap& attributes)
260{
261 auto nAttr = std::count(stream.ptr, stream.endptr, '=');
262 if(!nAttr) return;
263
264 std::string pattern = "";
265 for(int i=0;i<nAttr;++i) pattern += "\\s+(\\|?[_[:alnum:]]+\\|?)\\s*=\\s*\"([_[:alnum:]\\s,-\\[\\]\\.\\|]+)\"";
266
267 std::cmatch cmr;
268 if(!std::regex_match(stream.ptr, stream.endptr, cmr, std::regex(pattern)))
269 {
270 throw(XmlError(stream) << "unexpected error (internal))");
271 }
272 for(unsigned i=1;i<cmr.size();i+=2)
273 {
274 auto attr = cmr[i].str();
275 auto itr = attributes.find(tag + '/' + attr);
276 if(itr == attributes.end())
277 {
278 throw(XmlError(stream.ptr+cmr.position(i), attr.length()) << "invalid attribute \"" << attr << "\"");
279 }
280 if(!cmr.length(i+1))
281 {
282 throw(XmlError(stream.ptr+cmr.position(i), attr.length()) << "empty value for attribute \"" << attr << "\"");
283 }
284 auto& attrVal = itr->second;
285 if(attrVal) throw(XmlError(stream.ptr+cmr.position(i), attr.length()) << "the attribute \"" << attr << "\" has already been specified for that tag");
286 attrVal.set(stream.ptr+cmr.position(i+1), cmr.length(i+1));
287 }
288}
289
290void Database::dropXmlComments(std::string& buffer)
291{
292 std::regex rx("<!--.*?-->");
293 std::smatch smr;
294 while(std::regex_search(buffer, smr, rx))
295 {
296 std::size_t pos = smr.position(0), length = smr.length(), endpos = pos + length;
297 for(auto& offset : m_lineOffset)
298 {
299 if(offset > endpos) offset -= length;
300 else if(offset > pos) offset = pos;
301 }
302 buffer = smr.prefix().str() + smr.suffix().str();
303 }
304}
305
306void Database::dropRootTag(std::string& buffer)
307{
308 const std::vector<std::string> keys = {"<efficiencies>", "</efficiencies>"};
309 for(const auto& key : keys)
310 {
311 std::size_t ipos;
312 while((ipos = buffer.find(key)) != std::string::npos)
313 {
314 buffer.erase(ipos, key.length()-1);
315 buffer[ipos] = ' ';
316 }
317 }
318}
319
320std::vector<std::string> Database::getListOfNames(const StringRef& stream)
321{
322 std::vector<std::string> words;
323 std::stringstream ss(std::string(stream.ptr, stream.endptr));
324 std::string w;
325 while(std::getline(ss, w, ','))
326 {
327 std::size_t i = w.find_first_not_of(" \t");
328 std::size_t j = w.find_last_not_of(" \t");
329 if(i == std::string::npos)
330 {
331 throw(XmlError(stream) << "this should be a comma-separated list of names");
332 }
333 words.push_back(w.substr(i, j-i+1));
334 }
335 return words;
336}
337
338template<typename ReturnValue>
339ReturnValue Database::getAttribute(const StringRef& attr, const char* ref, ReturnValue rv)
340{
341 if(attr.str() == ref) return rv;
342 throw(XmlError(attr) << "unsupported parameter type \"" << attr.str() << "\"");
343}
344
345template<typename ReturnValue, typename... Args>
346ReturnValue Database::getAttribute(const StringRef& attr, const char* ref, ReturnValue rv, Args... args)
347{
348 if(attr.str() == ref) return rv;
349 return getAttribute(attr, args...);
350}
351
352template<typename ReturnValue, typename... Args>
353ReturnValue Database::getAttribute(const StringRef& tag, const AttributesMap& attributes, const std::string& type, const char* ref, ReturnValue rv, Args... args)
354{
355 std::string attrname = tag.str() + "/" + type;
356 auto& attr = attributes.at(attrname);
357 if(!attr) throw(XmlError(tag) << "unspecified value for attribute \"" << type << "\"");
358 return getAttribute(attr, ref, rv, args...);
359}
360
361void Database::addParams(const StringRef& tag, const StringRef& contents, AttributesMap& attributes)
362{
363 auto type = getAttribute(tag, attributes, "type", "int", Param::Type::CUSTOM_INT, "float", Param::Type::CUSTOM_FLOAT);
364 auto level = getAttribute(tag, attributes, "level", "particle", Param::Level::PARTICLE, "event", Param::Level::EVENT);
365
366 for(auto& name: getListOfNames(contents))
367 {
368 if(std::any_of(m_params.begin(), m_params.end(), [&](const Param& p){ return p.name == name; }))
369 {
370 throw(XmlError(contents) << "parameter \"" << name << "\" was already declared");
371 }
372 m_params.emplace_back(name, type, level);
373 attributes["bin/" + name];
374 attributes["table/" + name];
375 }
376}
377
378void Database::addSysts(const StringRef& tag, const StringRef& contents, const AttributesMap& attributes)
379{
380 std::bitset<N_EFFICIENCY_TYPES> affects;
381 for(auto& target : getListOfNames(attributes.at("syst/affects")))
382 {
383 auto targetMatches = [&](const char* a, const char* b) -> bool
384 { return target==a || target==b || target==std::string(a)+'-'+b; };
385 int matched = 0;
386 if(targetMatches("electron", "real-efficiency")) { affects.set(ELECTRON_REAL_EFFICIENCY); ++matched; }
387 if(targetMatches("muon", "real-efficiency")) { affects.set(MUON_REAL_EFFICIENCY); ++matched; }
388 if(targetMatches("tau", "real-efficiency")) { affects.set(TAU_REAL_EFFICIENCY); ++matched; }
389 if(targetMatches("electron", "fake-efficiency")) { affects.set(ELECTRON_FAKE_EFFICIENCY); ++matched; }
390 if(targetMatches("muon", "fake-efficiency")) { affects.set(MUON_FAKE_EFFICIENCY); ++matched; }
391 if(targetMatches("tau", "fake-efficiency")) { affects.set(TAU_FAKE_EFFICIENCY); ++matched; }
392 if(targetMatches("electron", "fake-factor")) { affects.set(ELECTRON_FAKE_FACTOR); ++matched; }
393 if(targetMatches("muon", "fake-factor")) { affects.set(MUON_FAKE_FACTOR); ++matched; }
394 if(targetMatches("tau", "fake-factor")) { affects.set(TAU_FAKE_FACTOR); ++matched; }
395 if(!matched) throw(XmlError(tag) << "the value \"" << target << "\" specified for the attribute \"affects\" is not recognized");
396 }
397 if(affects.none()) throw(XmlError(tag) << "missing or empty attribute \"affects\"");
398 for(auto& name: getListOfNames(contents))
399 {
400 if(name == "stat") throw(XmlError(contents) << "systematics can't be named \"stat\"");
401 if(std::any_of(m_systs.begin(), m_systs.end(), [&](const SystDef& s){ return s.name==name && (affects&s.affects).any(); }))
402 {
403 throw(XmlError(contents) << "the systematic \"" << name << "\" was already declared previously; duplicates are only allowed if their \"affects\" attributes do not overlap, which is not the case here");
404 }
405 if(m_systs.size() >= maxIndex()) throw(XmlError(contents) << "exceeded max number of systematic uncertainties");
406 m_systs.emplace_back(name, affects);
407 }
408}
409
411{
412 if(m_stats.size() >= maxIndex())
413 {
414 if(pos) throw(XmlError(pos) << "exceeded max number of statistical uncertainties");
415 else throw(GenericError() << "exceeded max number of statistical uncertainties");
416 }
417 m_stats.emplace_back(1 << type);
418 return statIndexToUID(m_stats.size() - 1);
419}
420
421void Database::addTables(const StringRef& particle, const AttributesMap& attributes, const StringRef& contents, TFile* source)
422{
424 if(particle == "muon") type = getAttribute(particle, attributes, "type",
425 "real-efficiency", MUON_REAL_EFFICIENCY, "fake-efficiency", MUON_FAKE_EFFICIENCY, "fake-factor", MUON_FAKE_FACTOR);
426 else if(particle == "electron") type = getAttribute(particle, attributes, "type",
427 "real-efficiency", ELECTRON_REAL_EFFICIENCY, "fake-efficiency", ELECTRON_FAKE_EFFICIENCY, "fake-factor", ELECTRON_FAKE_FACTOR);
428 else if(particle == "tau") type = getAttribute(particle, attributes, "type",
429 "real-efficiency", TAU_REAL_EFFICIENCY, "fake-efficiency", TAU_FAKE_EFFICIENCY, "fake-factor", TAU_FAKE_FACTOR);
430 else throw(XmlError(particle) << "unexpected error: unsupported particle type " << particle.str());
431 auto statMode = attributes.at(particle.str()+"/stat") ? getAttribute(particle, attributes, "stat",
433 auto inputType = getAttribute(particle, attributes, "input", "central-value", InputType::CENTRAL_VALUE, "correction", InputType::CORRECTION);
434
435 unsigned short globalStatUID = 0;
436
437 AttributesMap subattributes;
438 StringRef stream = contents, subcontents;
439 while(stream.length())
440 {
441 StringRef tag;
442 resetAttributes(subattributes);
443 readNextTag(stream, tag, subattributes, subcontents);
444 const TH1* hist = nullptr;
445 if(tag=="bin" || tag=="table" || tag=="TH1")
446 {
447 if(tag == "TH1")
448 {
449 if(!source) throw(XmlError(tag) << "histograms can only be imported inside <ROOT>...</ROOT> blocks!");
450 if(!subattributes.at("TH1/X")) throw(XmlError(tag) << "the attribute 'X' should be specified (as well as 'Y' for 2D histograms, 'Z' for 3D histograms)");
451 auto name = subcontents.trim();
452 hist = static_cast<const TH1*>(source->Get(name.c_str()));
453 if(!hist) throw(XmlError(subcontents) << "can't find any histogram named \"" << name << "\" in the file " << source->GetName());
454 auto& norm = subattributes.at("TH1/norm");
455 if(inputType!=InputType::CORRECTION && (norm && norm!="none"))
456 throw(XmlError(norm) << "normalization of input histograms is only accepted for 'input=\"correction\"'");
457 float scale = getNormalizationFactor(hist, type, norm, subcontents);
458 importNominalTH1(hist, type, subattributes.at("TH1/X"), subattributes.at("TH1/Y"), subattributes.at("TH1/Z"), scale, statMode, globalStatUID, subcontents);
459 }
460 else m_tables[type].emplace_back();
461 auto& table = m_tables[type].back();
462 table.inputType = inputType;
463
464 auto initialNumberOfBins = table.numberOfBins();
465 std::map<StringRef, unsigned> dimBins;
466 for(unsigned uid=0; uid<m_params.size(); ++uid)
467 {
468 auto& binning = subattributes.at(tag + "/" + m_params[uid].name);
469 if(binning) dimBins.emplace(binning, uid);
470 }
471 for(auto& kv : dimBins) addDimension(table, kv.second, kv.first);
472
473 if(tag != "TH1")
474 {
475 if(tag == "bin" && table.numberOfBins() > 1) throw(XmlError(tag) << "use a <table> instead of a <bin> tag to hold several values");
476 addValues(subcontents, table, type, statMode, globalStatUID);
477 }
478 else if(table.numberOfBins() != initialNumberOfBins) throw(XmlError(tag) << "extra binned dimensions do not make sense");
479 if(tag=="TH1" || tag=="bin")
480 {
481 auto& label = subattributes.at(tag + "/label");
482 if(label)
483 {
484 float normFactor {0};
485 if(tag == "TH1") normFactor = 1.f / getWeightedAverage(hist, stream);
486 else
487 {
488 assert (tag == "bin");
489 normFactor = 1.f / table.m_efficiencies[0].nominal;
490 }
491 if(!std::isnormal(normFactor) || normFactor<=0.) throw(XmlError(label) << "computed normalization factor is 0 / NaN / infinite / negative");
492 if(!m_normFactors.emplace(label.str()+"-"+std::to_string(type), normFactor).second)
493 throw(XmlError(label) << "label \"" << label.str() << "\" has already been used");
494 }
495 }
496 }
497 else throw(XmlError(tag) << "unknown/unexpected XML tag \"" << tag.str() << "\"");
498 }
499}
500
501void Database::assertNoLeftover(std::stringstream& ss, const StringRef& pos)
502{
503 ss >> std::ws;
504 if(!ss.eof())
505 {
506 std::string line;
507 std::getline(ss, line);
508 throw(XmlError(pos) << "unexpected parsing error (leftover data \"" << line << "\")");
509 }
510}
511
512void Database::addDimension(EfficiencyTable& table, unsigned paramUID, const StringRef& contents)
513{
514 if(!contents) return;
515 auto& param = m_params[paramUID];
516 const bool integer = param.integer();
517 const std::string fp = "[+-]?[0-9]*\\.?[0-9]+(?:[Ee][+-]?[0-9]+)?";
518 const std::string pattern = "^\\s*\\[\\s*(?:(?:-inf\\s*,\\s*|-?)inf|(?:-inf\\s*,\\s*)?"
519 + fp + "(?:\\s*,\\s*" + fp + ")*(?:\\s*,\\s*inf)?)\\s*\\]\\s*$";
520 if(!std::regex_match(contents.ptr, contents.endptr, std::regex(pattern)))
521 {
523 if(!integer || !std::regex_match(contents.ptr, contents.endptr, std::regex("\\s*[+-]?[0-9]+\\s*")))
524 {
525 throw(XmlError(contents) << "invalid format for the range of the parameter " << param.name);
526 }
527 }
528
529 auto& bounds = table.m_bounds;
530 table.m_dimensions.emplace_back();
531 auto& dim = table.m_dimensions.back();
532 dim.paramUID = paramUID;
533 dim.iMinBound = table.m_bounds.size();
534 auto line = contents.str();
535 dim.nBounds = std::count(line.begin(), line.end(), ',') + 1;
536 if(integer && dim.nBounds < 1) throw(XmlError(contents) << "should specify at least one bin boundary for parameter " << param.name);
537 if(!integer && (dim.nBounds < 2)) throw(XmlError(contents) << "should specify at least two bin boundaries for parameter " << param.name);
538 for(auto&c : line) if(c==',' || c=='[' || c==']') c = ' ';
539 std::stringstream ss(line);
540 for(int i=0;i<dim.nBounds;++i)
541 {
543 if(integer) ss >> x.as_int;
544 else ss >> x.as_float;
545 if(ss.fail())
546 {
547 if(i==0 || i==(dim.nBounds-1))
548 {
549 ss.clear();
550 ss.unget();
551 ss.clear();
552 std::string x_s;
553 ss >> x_s;
554 if(x_s=="inf" || x_s=="-inf")
555 {
556 bool defMax = (x_s.front() != '-');
557 if(integer) x.as_int = defMax ? std::numeric_limits<int>::max() : std::numeric_limits<int>::min();
558 else x.as_float = defMax ? std::numeric_limits<float>::max() : std::numeric_limits<float>::lowest();
559 }
560 else throw(XmlError(contents) << "parsing error (invalid 'inf' string)");
561 }
562 if(ss.fail()) throw(XmlError(contents) << "parsing error (can't read int/float boundary)");
563 }
564 if(i)
565 {
566 if(integer ? (bounds.back().as_int > x.as_int) : (bounds.back().as_float > x.as_float))
567 {
568 throw(XmlError(contents) << "bin boundaries must be sorted in increasing order");
569 }
570 }
571 bounds.push_back(x);
572 }
574 if(integer && dim.nBounds==1)
575 {
576 dim.nBounds = 2;
577 bounds.push_back(bounds.back());
578 bounds.back().as_int += 1;
579 }
580}
581
582void Database::addValues(const StringRef& contents, EfficiencyTable& table, EfficiencyType type, StatMode statMode, unsigned short& globalStatUID)
583{
584 const std::string fpv = "(?:[0-9]+\\.)?[0-9]+(?:[Ee][+-]?[0-9]+)?", fpu = fpv + "\\s*\\%?";
585 const std::string pattern = "^\\s*" + fpv + "(?:\\s*(?:\\+(?:\\s*" + fpu + "\\s*)?-|-(?:\\s*" + fpu + "\\s*)?\\+)\\s*" + fpu + "\\s*\\([_[:alnum:]]+\\))*\\s*";
586 auto rxValidFormat = std::regex(pattern);
587 std::stringstream ssCSV(contents.str()), ss;
588 const char* ptr = contents.ptr;
589
590 if(statMode==StatMode::GLOBAL && !globalStatUID) globalStatUID = addStat(type, contents);
591
592 while(ptr && ptr<contents.endptr)
593 {
594 std::cmatch cm;
595 if(!std::regex_search(ptr, contents.endptr, cm, rxValidFormat))
596 {
597 StringRef lineref{ptr, contents.endptr};
598 throw(XmlError(lineref) << "the central value(s) and uncertainties are not in the expected format; first issue found with value " << lineref.str().substr(0, 32) << " [...]");
599 }
600 StringRef valref{ptr, static_cast<std::size_t>(cm.length())};
601 ptr += cm.length();
602 std::string value = valref.str();
603 value.erase(std::remove_if(value.begin(), value.end(), [](char c){ return std::isspace(c); }), value.end());
604 unsigned nErrs = std::count(value.begin(), value.end(), '(');
605 for(auto& c : value) if(c=='(' || c==')') c = ' ';
606 ss.clear();
607 ss.str(value);
608 table.m_efficiencies.emplace_back();
609 auto& eff = table.m_efficiencies.back();
610 ss >> eff.nominal;
611 bool foundStat = false;
612 for(unsigned i=0;i<nErrs;++i)
613 {
615 std::string sysname;
616 ss >> std::ws;
617 auto c1 = ss.get();
618 auto c2 = ss.peek();
619 if(c2=='+' || c2=='-')
620 {
621 ss >> c2 >> uncval.up >> sysname;
622 if(sysname == "%")
623 {
624 uncval.up *= 0.01f * eff.nominal;
625 ss >> sysname;
626 }
627 uncval.down = uncval.up;
628 }
629 else
630 {
631 ss >> uncval.up >> c2;
632 if(c2 == '%')
633 {
634 uncval.up *= 0.01f * eff.nominal;
635 ss >> c2;
636 }
637 ss >> uncval.down >> sysname;
638 if(sysname == "%")
639 {
640 uncval.down *= 0.01f * eff.nominal;
641 ss >> sysname;
642 }
643 }
644 if(ss.bad()) throw(XmlError(valref) << "unexpected parsing error");
645 if(std::signbit(uncval.up) != std::signbit(uncval.down)) throw(XmlError(valref) << "one-sided up/down errors");
646 if(c1 == '-')
647 {
648 uncval.up = -uncval.up;
649 uncval.down = -uncval.down;
650 }
651
653 if(sysname == "stat")
654 {
655 if(foundStat) throw(XmlError(valref) << "there can be only one source of statistical uncertainty per bin");
656 if(statMode==StatMode::UNSPECIFIED || statMode==StatMode::NONE) throw(XmlError(valref) << "when using statistical uncertainties, the \"stat\" attribute must be specified (and not set to \"none\")");
657 foundStat = true;
658 uid = (statMode == StatMode::GLOBAL)? globalStatUID : addStat(type, contents);
659 }
660 else
661 {
662 auto sys = std::find_if(m_systs.begin(), m_systs.end(),
663 [&](const SystDef& sd){ return sd.name==sysname && sd.affects[type]; });
664 if(sys == m_systs.end()) throw(XmlError(valref) << "the systematic \"" << sysname << "\" has either not been defined, or does not affect this type of efficiency");
665 unsigned index = sys - m_systs.begin();
667 }
668 if(!eff.uncertainties.emplace(uid, uncval).second)
669 {
670 throw(XmlError(valref) << "source of uncertainty \"" << sysname << "\" specified twice");
671 }
672 }
674 }
675 if(table.m_efficiencies.size() != table.numberOfBins())
676 {
677 throw(XmlError(contents) << "the number of tabulated efficiencies (" << table.m_efficiencies.size()
678 << ") is inconsistent with the number of bins (" << table.numberOfBins() << ")");
679 }
680}
681
682void Database::importCustomROOT(const StringRef& rootTag, const StringRef& contents, const AttributesMap& attributes)
683{
684 std::string filename = attributes.at("ROOT/source").str();
685 if(!filename.length()) throw(XmlError(rootTag) << "the 'file' attribute must be specified!");
686 filename = PathResolverFindCalibFile(filename);
687
688 TFile* file = TFile::Open(filename.c_str(), "READ");
689 if(!file || !file->IsOpen())
690 {
691 delete file;
692 throw(XmlError(rootTag) << "unable to locate/open the file " << filename);
693 }
694
695 AttributesMap subattributes;
696 StringRef stream = contents, tag, subcontents;
697 while(stream.length())
698 {
699 resetAttributes(subattributes);
700 readNextTag(stream, tag, subattributes, subcontents);
701 if(tag=="electron" || tag=="muon" || tag=="tau") addTables(tag, subattributes, subcontents, file);
702 else throw(XmlError(stream) << "unknown/unexpected XML tag \"" << tag << "\"");
703 }
704
705 file->Close();
706 delete file;
707}
708
710{
711 attributes["ROOT/source"];
712 attributes["param/type"];
713 attributes["param/level"];
714 attributes["syst/affects"];
715
716 const std::vector<std::string> parts = {"electron", "muon", "tau"};
717 for(const auto& p : parts)
718 {
719 attributes[p + "/type"];
720 attributes[p + "/input"];
721 attributes[p + "/stat"];
722 }
723 attributes["TH1/X"];
724 attributes["TH1/Y"];
725 attributes["TH1/Z"];
726 attributes["TH1/label"];
727 attributes["bin/label"];
728 attributes["TH1/norm"];
729 for(auto& p : m_params)
730 {
731 attributes["bin/" + p.name];
732 attributes["table/" + p.name];
733 attributes["TH1/" + p.name];
736 }
737}
738
739/*
740 * Loading from ROOT
741 */
742
743void Database::importDefaultROOT(std::string filename)
744{
745 const std::string prefix = "^(FakeFactor|FakeEfficiency|RealEfficiency|FakeRate|FakeRateSF)", suffix = "_([[:w:]][^_]+)(__[[:w:]]+)?$";
746 const std::regex rxTH1(prefix + "_(el|mu|tau|e2y)" + suffix);
747 const std::regex rxTH2(prefix + "2D_(el|mu|tau|e2y)_([[:alnum:]]+)" + suffix);
748 const std::regex rxTH3(prefix + "3D_(el|mu|tau)_([[:alnum:]]+)_([[:alnum:]]+)" + suffix);
749
750 if (filename[0] != '/')
751 filename = PathResolverFindCalibFile(filename);
752
753 TFile* file = TFile::Open(filename.c_str(), "READ");
754 if(!file || !file->IsOpen())
755 {
756 throw(GenericError() << "unable to locate/open the file " << filename);
757 }
758
759 auto keys = file->GetListOfKeys();
760 if(!keys) throw(GenericError() << "unable to list keys in the file " << filename << " (corrupted?)");
761
762 const StringRef nullStream;
763 unsigned short dummy;
764 for(unsigned step=0;step<2;++step)
765 {
768 for(int i=0;i<keys->GetSize();++i)
769 {
770 TKey* key = static_cast<TKey*>(keys->At(i));
771 std::cmatch mr;
772 std::string keyType = key->GetClassName();
773 unsigned nDims = 0;
774 if(keyType=="TH1F" || keyType=="TH1D") nDims = 1 * std::regex_match(key->GetName(), mr, rxTH1);
775 else if(keyType=="TH2F" || keyType=="TH2D") nDims = 2 * std::regex_match(key->GetName(), mr, rxTH2);
776 else if(keyType=="TH3F" || keyType=="TH3D") nDims = 3 * std::regex_match(key->GetName(), mr, rxTH3);
777 else continue;
778 if(nDims < 1) throw(GenericError() << "don't know what to do with histogram named \"" << key->GetName() << "\" (please check naming conventions)");
779 TH1* hist = static_cast<TH1*>(key->ReadObj());
781 std::string sss = mr[1].str() + "-" + mr[2].str();
782 auto type = getAttribute(StringRef(sss.data(), sss.length()),
783 "FakeFactor-el", ELECTRON_FAKE_FACTOR, "FakeFactor-mu", MUON_FAKE_FACTOR, "FakeFactor-tau", TAU_FAKE_FACTOR,
784 "FakeEfficiency-el", ELECTRON_FAKE_EFFICIENCY, "FakeEfficiency-mu", MUON_FAKE_EFFICIENCY, "FakeEfficiency-tau", TAU_FAKE_EFFICIENCY,
785 "RealEfficiency-el", ELECTRON_REAL_EFFICIENCY, "RealEfficiency-mu", MUON_REAL_EFFICIENCY, "RealEfficiency-tau", TAU_REAL_EFFICIENCY,
786 "FakeRate-e2y", PHOTON_ELE_FAKE_FACTOR, "FakeRateSF-e2y", PHOTON_ELE_FAKE_FACTOR_SF
787 );
788 bool systTH1 = (mr[mr.size()-1].str() != "");
789 if(step==0 && !systTH1)
790 {
791 StringRef paramX = StringRef(mr[3].first, mr[3].second);
792 StringRef paramY = (nDims>1) ? StringRef(mr[4].first, mr[4].second) : StringRef();
793 StringRef paramZ = (nDims>2) ? StringRef(mr[5].first, mr[5].second) : StringRef();
794 importNominalTH1(hist, type, paramX, paramY, paramZ, 1.f, StatMode::PER_BIN, dummy, nullStream);
795 m_tables[type].back().inputType = InputType::CENTRAL_VALUE;
796 }
797 else if(step==1 && systTH1) importSystTH1(hist, type, mr[nDims+3].str().substr(2));
798 else continue;
799 }
800 }
801
802 file->Close();
803 delete file;
804}
805
806float Database::getWeightedAverage(const TH1* hist, const StringRef& xmlStream)
807{
808 float avg = 1.f;
809 if(hist->GetNbinsX()!=1 || hist->GetNbinsY()!=1 || hist->GetNbinsZ()!=1)
810 {
812 double sum = 0., denom = 0.;
813 for(int i=1;i<=hist->GetNbinsX();++i)
814 for(int j=1;j<=hist->GetNbinsY();++j)
815 for(int k=1;k<=hist->GetNbinsZ();++k)
816 {
817 double x = hist->GetBinContent(i, j, k);
818 if(x == 0.) continue;
819 double w = hist->GetBinError(i, j, k);
820 if(w == 0.) throw(XmlError(xmlStream) << "bin with error = 0 encountered when trying to normalize histogram " << hist->GetName() << " to weighted bins average");
821 w = 1./(w*w);
822 sum += w * x;
823 denom += w;
824 }
825 if (denom > 0.) avg = sum / denom;
826 }
827 else avg = 1. / hist->GetBinContent(1);
828 if(!std::isnormal(avg) || avg<=0.) throw(XmlError(xmlStream) << "something bad happened when trying to compute the weighted average of histogram \""
829 << hist->GetName() << "\" bins, the result ended up 0 / NaN / infinite / negative");
830 return avg;
831}
832
833float Database::getNormalizationFactor(const TH1* hist, EfficiencyType type, const StringRef& norm, const StringRef& xmlStream)
834{
836 if(!norm) return 1.f;
837 auto normType = norm.str();
838 if(normType == "auto") return 1.f / getWeightedAverage(hist, xmlStream);
839 else if(normType != "none")
840 {
841 auto itr = m_normFactors.find(normType + "-" + std::to_string(type));
842 if(itr == m_normFactors.end()) throw(XmlError(norm) << "unknown normalization tag \"" << normType << "\"");
843 return itr->second;
844 }
845 return 1.f;
846}
847
848void Database::importNominalTH1(const TH1* hist, EfficiencyType type, const StringRef& paramX, const StringRef& paramY, const StringRef& paramZ,
849 float scale, StatMode statMode, unsigned short& globalStatUID, const StringRef& xmlStream)
850{
851 const bool useDefaults = !xmlStream;
852
853 if(useDefaults && m_tables[type].size()) throw(GenericError() << "already filled that table, please use an XML to describe how to interpret the more complex ROOT files");
854 m_tables[type].emplace_back();
855 auto& table = m_tables[type].back();
856
857 const int nDims = paramZ? 3 : paramY? 2 : 1;
858 if(hist->GetDimension() != nDims)
859 {
860 if(xmlStream) throw(XmlError(xmlStream) << "histogram " << hist->GetName() << " doesn't have the expected dimension");
861 else throw(GenericError() << "histogram " << hist->GetName() << " doesn't have the expected dimension");
862 }
863
865 for(int j=0;j<nDims;++j)
866 {
867 std::string name = ((j==2)? paramZ : (j==1)? paramY : paramX).str();
868 const TAxis* axis = (j==2)? hist->GetZaxis() : (j==1)? hist->GetYaxis() : hist->GetXaxis();
869 if(useDefaults && name == "eta" && axis->GetBinLowEdge(1) >= 0) name = "|eta|";
870 table.m_dimensions.emplace_back();
871 auto& dim = table.m_dimensions.back();
872 auto itr = std::find_if(m_params.begin(), m_params.end(), [&](const Param& p){ return p.name == name; });
873 bool integer;
874 if(itr == m_params.end())
875 {
876 if(useDefaults)
877 {
878 dim.paramUID = m_params.size();
879 m_params.emplace_back(name, Param::Type::CUSTOM_FLOAT, Param::Level::PARTICLE);
880 integer = false;
881 }
882 else throw(XmlError(j? paramY : paramX) << "parameter \"" << name << "\" has not been defined beforehand");
883 }
884 else
885 {
886 dim.paramUID = itr - m_params.begin();
887 integer = itr->integer();
888 }
889 dim.iMinBound = table.m_bounds.size();
890 dim.nBounds = axis->GetNbins() + 1;
892 table.m_bounds.emplace_back();
893 if(integer) table.m_bounds.back().as_int = std::numeric_limits<int>::min();
894 else table.m_bounds.back().as_float = std::numeric_limits<float>::lowest();
895 for(int k=1;k<dim.nBounds-1;++k)
896 {
897 table.m_bounds.emplace_back();
898 if(integer) table.m_bounds.back().as_int = std::ceil(axis->GetBinUpEdge(k));
899 else table.m_bounds.back().as_float = axis->GetBinUpEdge(k);
900 }
901 table.m_bounds.emplace_back();
902 if(integer) table.m_bounds.back().as_int = std::numeric_limits<int>::max();
903 else table.m_bounds.back().as_float = std::numeric_limits<float>::max();
904 }
905
907 if(statMode==StatMode::GLOBAL && !globalStatUID) globalStatUID = addStat(type, xmlStream);
908 const unsigned xmax = table.m_dimensions.front().nBounds;
909 const unsigned ymax = table.m_dimensions.size()>1? table.m_dimensions[1].nBounds : 2;
910 const unsigned zmax = table.m_dimensions.size()>2? table.m_dimensions[2].nBounds : 2;
911 for(unsigned x=1;x<xmax;++x)
912 for(unsigned y=1;y<ymax;++y)
913 for(unsigned z=1;z<zmax;++z)
914 {
915 table.m_efficiencies.emplace_back();
916 auto& eff = table.m_efficiencies.back();
917 eff.nominal = scale * hist->GetBinContent(x, y, z);
918 if(statMode != StatMode::NONE)
919 {
920 uint16_t uid = (statMode==StatMode::GLOBAL)? globalStatUID : addStat(type, xmlStream);
921 float err = hist->GetBinError(x, y, z);
922 FakeBkgTools::Uncertainty uncdata{scale*err, scale*err};
923 eff.uncertainties.emplace(uid, uncdata);
924 }
925 }
926}
927
928void Database::importSystTH1(const TH1* hist, EfficiencyType type, const std::string& sysname)
929{
930 if(!m_tables[type].size()) throw(GenericError() << "there should be another histogram containing central values to accompany the histogram " << hist->GetName());
931 auto& table = m_tables[type].back();
932 const int xmax = table.m_dimensions.front().nBounds;
933 const int ymax = table.m_dimensions.size()>1? table.m_dimensions[1].nBounds : 2;
934 const int zmax = table.m_dimensions.size()>2? table.m_dimensions[2].nBounds : 2;
935 if(xmax!=hist->GetNbinsX()+1 || ymax!=hist->GetNbinsY()+1 || zmax!=hist->GetNbinsZ()+1)
936 {
937 throw(GenericError() << "binning mismatch between the nominal histogram and " << hist->GetName());
938 }
939
941 auto itr = std::find_if(m_systs.begin(), m_systs.end(), [&](const SystDef& sys){ return sys.name==sysname; });
942 if(itr != m_systs.end())
943 {
944 uid = systIndexToUID(itr - m_systs.begin());
945 itr->affects.set(type);
946 }
947 else
948 {
949 uid = systIndexToUID(m_systs.size());
950 m_systs.emplace_back(sysname, (1 << type));
951 }
952
953 //loop through all bins once, to check whether all bins are zero error,
954 //or have the same central value as the nominal
955
956 bool syst_central_equal_nom_central = true;
957 bool syst_errors_equal_zero = true;
958 bool syst_errors_equal_nom_errors = true;
959
960 auto eff = table.m_efficiencies.begin();
961 for(int x=1;x<xmax;++x)
962 for(int y=1;y<ymax;++y)
963 for(int z=1;z<zmax;++z)
964 {
965 if (fabs ((float)eff->nominal - (float)hist->GetBinContent(x, y, z)) > 0.001 ){ syst_central_equal_nom_central = false;}
966 if ( hist->GetBinError(x, y, z) != 0 ) { syst_errors_equal_zero = false;}
967 float stat_up = 0;
968 for(auto& kv : eff->uncertainties)
969 {
970 if(!isStatUID(kv.first)) continue;
971 stat_up = kv.second.up; break;
972 }
973 if ( fabs((float) hist->GetBinError(x, y, z) - (float) stat_up ) > 0.001) { syst_errors_equal_nom_errors = false;}
974 ++eff;
975 }
976
977 // loop bins a second time and determine proceedure using above heuristics
978 eff = table.m_efficiencies.begin();
979 for(int x=1;x<xmax;++x)
980 for(int y=1;y<ymax;++y)
981 for(int z=1;z<zmax;++z)
982 {
983
984 float err =0;
985 //want to support several possible notations:
986 // a) central values are not the same as nominal: then we can assume
987 // that the central values of the syst histos are the errors,
988 // (default nomenclature from the documentation)
989 // b) if the central values for nominal and this hist are the same
990 // then probably the errors are to be taken from the error bars!
991 // but need to watch out for ambiguous cases
992 //
993 if (syst_central_equal_nom_central){ //central values are the same in nom and sys
994 if (syst_errors_equal_nom_errors ){ // this case is ambiguous. Is it a 100% uncertainty?
995 throw(GenericError() << "The central values and uncertainties for this systematic are identical to the nominal+stat uncertainties. This is ambiguous: did you mean to assign a 100% uncertainty? If so, please set all (unused) error bars to zero. ");
996 } else if (syst_errors_equal_zero ) { //assume here that it was intended as 100% uncertainty
997 err = hist->GetBinContent(x, y, z);
998 } else {
999 err = hist->GetBinError(x, y, z);
1000 }
1001 } else { // central values are different in nom and sys
1002 err = hist->GetBinContent(x, y, z);
1003 }
1004
1005
1006 FakeBkgTools::Uncertainty uncdata{err, err};
1007 if(!eff->uncertainties.emplace(uid, uncdata).second)
1008 {
1009 throw(GenericError() << "unexpected error: tried filling twice the same systematic");
1010 }
1011 ++eff;
1012 }
1013}
1014
1016{
1017 #ifdef FAKEBKGTOOLS_ATLAS_ENVIRONMENT
1018 float energy_scale = (m_useGeV? 0.001f : 1.f);
1019 #else
1020 float energy_scale = 1;
1021 #endif
1022 if(param.level == Param::Level::PARTICLE)
1023 {
1024 if(param.type==Param::Type::PREDEFINED_FLOAT || param.type==Param::Type::PREDEFINED_INT)
1025 {
1026 if(param.name=="pt") val.as_float = energy_scale * p.pt();
1027 else if(param.name=="eta") val.as_float = p.eta();
1028 else if(param.name=="|eta|") val.as_float = fabs(p.eta());
1029 else if(param.name=="phi") val.as_float = p.phi();
1030 else return false;
1031 }
1032 else if(param.type == Param::Type::CUSTOM_FLOAT) {
1034 val.as_float = acc(p);
1035 }
1036 else if(param.type == Param::Type::CUSTOM_INT) {
1038 val.as_int = acc(p);
1039 }
1040 else return false;
1041 }
1042 else if(param.level == Param::Level::EVENT)
1043 {
1044 if (!eventInfo) {
1045 throw(GenericError() << "unexpected error: No EventInfo, but asked for event parameter");
1046 }
1047 if(param.type == Param::Type::CUSTOM_FLOAT) {
1049 val.as_float = acc(*eventInfo);
1050 }
1051 else if(param.type == Param::Type::CUSTOM_INT) {
1053 val.as_int = acc(*eventInfo);
1054 }
1055 else return false;
1056 }
1057 else return false;
1058 return true;
1059}
1060
1062{
1063 switch(p.type())
1064 {
1066 if(type==ELECTRON_FAKE_FACTOR) return &pd.fake_factor;
1067 else if(type==ELECTRON_FAKE_EFFICIENCY) return &pd.fake_efficiency;
1068 else if(type==ELECTRON_REAL_EFFICIENCY) return &pd.real_efficiency;
1069 else if(type==PHOTON_ELE_FAKE_FACTOR) return &pd.fake_factor;
1070 break;
1071 case xAOD::Type::Muon:
1072 if(type==MUON_FAKE_FACTOR) return &pd.fake_factor;
1073 else if(type==MUON_FAKE_EFFICIENCY) return &pd.fake_efficiency;
1074 else if(type==MUON_REAL_EFFICIENCY) return &pd.real_efficiency;
1075 break;
1076 case xAOD::Type::Tau:
1077 if(type==TAU_FAKE_FACTOR) return &pd.fake_factor;
1078 else if(type==TAU_FAKE_EFFICIENCY) return &pd.fake_efficiency;
1079 else if(type==TAU_REAL_EFFICIENCY) return &pd.real_efficiency;
1080 break;
1081 case xAOD::Type::Photon:
1082 if(type==PHOTON_ELE_FAKE_FACTOR_SF) return &pd.fake_factor;
1083 break;
1084 default:;
1085 }
1086 return nullptr;
1087}
1088
1090auto Database::selectTypesToFill(Client client) -> std::bitset<N_EFFICIENCY_TYPES>
1091{
1092 std::bitset<N_EFFICIENCY_TYPES> result;
1093 if(client==Client::MATRIX_METHOD || client==Client::ALL_METHODS)
1094 {
1095 result[ELECTRON_REAL_EFFICIENCY] = true;
1096 result[MUON_REAL_EFFICIENCY] = true;
1097 result[TAU_REAL_EFFICIENCY] = true;
1098 result[ELECTRON_FAKE_EFFICIENCY] = true;
1099 result[MUON_FAKE_EFFICIENCY] = true;
1100 result[TAU_FAKE_EFFICIENCY] = true;
1101 }
1102 if(client==Client::FAKE_FACTOR || client==Client::ALL_METHODS)
1103 {
1104 result[ELECTRON_FAKE_FACTOR] = true;
1105 result[MUON_FAKE_FACTOR] = true;
1106 result[TAU_FAKE_FACTOR] = true;
1107 }
1108 if(client==Client::E2Y_FAKE || client==Client::ALL_METHODS)
1109 {
1110 result[PHOTON_ELE_FAKE_FACTOR] = true;
1111 result[PHOTON_ELE_FAKE_FACTOR_SF] = true;
1112 }
1113 if(result.none()) throw(GenericError() << "unrecognized client type, implementation incomplete");
1114 return result;
1115}
1116
1118{
1119 auto tables = m_tables.find(wantedType);
1120 if((tables==m_tables.end() || !tables->second.size()) && m_convertWhenMissing)
1121 {
1122 switch(wantedType)
1123 {
1132 default:;
1133 }
1134 }
1135 return wantedType;
1136}
1137
1138unsigned Database::getXmlLineNumber(const char* pos) const
1139{
1140 if(!pos || !m_xmlBuffer.size() || !m_lineOffset.size()) return 0;
1141 if(pos < m_xmlBuffer.data()) return 0;
1142 unsigned offset = pos - m_xmlBuffer.data();
1143 if(offset >= m_xmlBuffer.size()) return 0;
1144 return std::upper_bound(m_lineOffset.begin(), m_lineOffset.end(), offset) - m_lineOffset.begin();
1145}
1146
1148{
1150 switch(type)
1151 {
1152 case ELECTRON_REAL_EFFICIENCY: return "real efficiency (electrons)";
1153 case ELECTRON_FAKE_EFFICIENCY: return "fake efficiency (electrons)";
1154 case ELECTRON_FAKE_FACTOR: return "fake factor (electrons)";
1155 case MUON_REAL_EFFICIENCY: return "real efficiency (muons)";
1156 case MUON_FAKE_EFFICIENCY: return "fake efficiency (muons)";
1157 case MUON_FAKE_FACTOR: return "fake factor (muons)";
1158 case TAU_REAL_EFFICIENCY: return "real efficiency (taus)";
1159 case TAU_FAKE_EFFICIENCY: return "fake efficiency (taus)";
1160 case TAU_FAKE_FACTOR: return "fake factor (taus)";
1161 case PHOTON_ELE_FAKE_FACTOR: return "fake rate (electrons->photons)";
1162 case PHOTON_ELE_FAKE_FACTOR_SF: return "fake rate SF(electrons->photons)";
1163 default:;
1164 }
1165 return "???";
1166}
1167
1168std::string Database::StringRef::trim() const
1169{
1170 if(!ptr) return "";
1171 auto beg=ptr, end=endptr-1;
1172 while(std::isspace(*beg) && beg<end) ++beg;
1173 while(std::isspace(*end) && end>beg) --end;
1174 return std::string(beg, end+1);
1175}
const std::regex ref(r_ef)
Helper class to provide constant type-safe access to aux data.
double length(const pvec &v)
static Double_t a
static Double_t ss
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
size_t size() const
Number of registered mappings.
#define y
#define x
#define z
std::string m_xmlBuffer
Temporary buffers (only used while importing data).
Definition Database.h:254
void importDefaultROOT(std::string filename)
Definition Database.cxx:743
float getNormalizationFactor(const TH1 *hist, EfficiencyType type, const StringRef &norm, const StringRef &xmlStream)
Definition Database.cxx:833
std::map< std::string, StringRef > AttributesMap
Definition Database.h:175
static FakeBkgTools::Efficiency * selectEfficiency(FakeBkgTools::ParticleData &pd, const xAOD::IParticle &p, EfficiencyType type)
Methods used to fill efficiencies.
void importNominalTH1(const TH1 *hist, EfficiencyType type, const StringRef &paramX, const StringRef &paramY, const StringRef &paramZ, float scale, StatMode statMode, unsigned short &globalStatUID, const StringRef &xmlStream)
Methods used to load from ROOT files.
Definition Database.cxx:848
void addValues(const StringRef &contents, EfficiencyTable &table, EfficiencyType type, StatMode statMode, unsigned short &globalStatUID)
Definition Database.cxx:582
float getWeightedAverage(const TH1 *hist, const StringRef &xmlStream)
Definition Database.cxx:806
void readNextTag(StringRef &stream, StringRef &tag, AttributesMap &attributes, StringRef &contents)
Definition Database.cxx:236
std::vector< std::string > getListOfNames(const StringRef &stream)
Definition Database.cxx:320
EfficiencyType getSourceType(EfficiencyType wantedType) const
static constexpr unsigned short systIndexToUID(unsigned short index)
Definition Database.h:220
static constexpr unsigned short statIndexToUID(unsigned short index)
Definition Database.h:221
bool retrieveParameterValue(const xAOD::IParticle &p, const xAOD::EventInfo *eventInfo, const Param &param, EfficiencyTable::BoundType &val) const
unsigned getXmlLineNumber(const char *pos) const
std::vector< Param > m_params
Permanent buffers.
Definition Database.h:248
std::vector< StatDef > m_stats
Definition Database.h:250
static constexpr bool isStatUID(unsigned short uid)
Definition Database.h:223
static void assertNoLeftover(std::stringstream &ss, const StringRef &pos)
Definition Database.cxx:501
void importXML(std::string filename)
Definition Database.cxx:186
void importSystTH1(const TH1 *hist, EfficiencyType type, const std::string &sysname)
Definition Database.cxx:928
void addTables(const StringRef &particleType, const AttributesMap &attributes, const StringRef &contents, TFile *source=nullptr)
Definition Database.cxx:421
static std::string getTypeAsString(EfficiencyType type)
const std::bitset< N_EFFICIENCY_TYPES > m_typesToFill
Definition Database.h:242
int readEfficiencyFromTable(Efficiency &eff, const EfficiencyTable &table, std::map< unsigned, EfficiencyTable::BoundType > &cachedParamVals, const xAOD::IParticle &p, const xAOD::EventInfo *eventInfo, std::string &error) const
Definition Database.cxx:130
bool needEventInfo() const
Definition Database.cxx:56
void readTagAttributes(StringRef stream, const std::string &tag, AttributesMap &attributes)
Definition Database.cxx:259
bool fillEfficiencies(ParticleData &pd, const xAOD::IParticle &p, const xAOD::EventInfo *eventInfo, std::string &error) const
Definition Database.cxx:65
static std::bitset< N_EFFICIENCY_TYPES > selectTypesToFill(Client client)
This function is only called by the Database constructor.
std::map< std::string, float > m_normFactors
Definition Database.h:256
unsigned short addStat(EfficiencyType type, const StringRef &pos=StringRef())
Definition Database.cxx:410
void addSysts(const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
Definition Database.cxx:378
void dropXmlComments(std::string &buffer)
Methods used to parse XML files.
Definition Database.cxx:290
std::map< int, std::vector< EfficiencyTable > > m_tables
Definition Database.h:251
const bool m_convertWhenMissing
Definition Database.h:244
static ReturnValue getAttribute(const StringRef &tag, const AttributesMap &attributes, const std::string &type, const char *ref, ReturnValue rv, Args... args)
Helper methods.
Definition Database.cxx:353
Database(Client client, bool useGeV, bool convertWhenMissing)
Definition Database.cxx:26
void addParams(const StringRef &tag, const StringRef &contents, AttributesMap &attributes)
Definition Database.cxx:361
void addDimension(EfficiencyTable &table, unsigned paramUID, const StringRef &contents)
Definition Database.cxx:512
std::vector< std::size_t > m_lineOffset
Definition Database.h:255
void dropRootTag(std::string &buffer)
Definition Database.cxx:306
void resetAttributes(AttributesMap &attributes)
Definition Database.cxx:709
void importCustomROOT(const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
Definition Database.cxx:682
std::vector< SystDef > m_systs
Definition Database.h:249
static constexpr unsigned short maxIndex()
Definition Database.h:209
Helper class to provide constant type-safe access to aux data.
Class providing the definition of the 4-vector interface.
void contents(std::vector< std::string > &keys, TDirectory *td, const std::string &directory, const std::string &pattern, const std::string &path)
std::string label(const std::string &format, int i)
Definition label.h:19
double xmax
Definition listroot.cxx:61
double ymax
Definition listroot.cxx:64
Select isolated Photons, Electrons and Muons.
Definition index.py:1
DataModel_detail::iterator< DVL > remove_if(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end, Predicate pred)
Specialization of remove_if for DataVector/List.
@ Photon
The object is a photon.
Definition ObjectType.h:47
@ Muon
The object is a muon.
Definition ObjectType.h:48
@ Electron
The object is an electron.
Definition ObjectType.h:46
@ Tau
The object is a tau (jet).
Definition ObjectType.h:49
EventInfo_v1 EventInfo
Definition of the latest event info version.
setWord1 uint16_t
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
c *Fortran *type rwl_lhe_block sequence integer rad_kinreg real aqcdup integer
Definition pwhg_rwl.h:7
This propagates an error message.
Definition Database.h:136
Note: the following structure is used (instead of a simple std::string) so that XML line numbers can ...
Definition Database.h:96
This propagates an error message + the reference to the faulty piece of XML when an exception is rais...
Definition Database.h:124
a structure to hold an efficiency together with a variable number of uncertainties
TFile * file