ATLAS Offline Software
Loading...
Searching...
No Matches
Database.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 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 filename = PathResolverFindCalibFile(filename);
189
190 std::ifstream xml;
191 xml.open(filename, std::ios_base::binary);
192 auto begpos = xml.tellg();
193 xml.seekg(0, std::ios_base::end);
194 std::size_t bufferSize = 1.05 * static_cast<std::size_t>(xml.tellg() - begpos);
196 if(bufferSize > 0x100000) bufferSize = 0x100000;
197 xml.close();
198
199 xml.open(filename, std::ios_base::in);
200 if(!xml.is_open()) throw(GenericError() << "unable to open file " << filename);
201
202 std::string line;
203 m_xmlBuffer.reserve(bufferSize);
204 m_lineOffset.clear();
205 m_lineOffset.push_back(0);
206 while(std::getline(xml, line))
207 {
208 while(line.length() && (line.back()=='\n' || line.back()=='\r')) line.pop_back();
209 m_xmlBuffer += line + ' ';
210 m_lineOffset.push_back(m_xmlBuffer.length());
211 }
212 xml.close();
213
216
217 AttributesMap attributes;
218 resetAttributes(attributes);
219 StringRef stream(m_xmlBuffer.data(), m_xmlBuffer.length()), contents, tag;
220 while(stream.length())
221 {
222 readNextTag(stream, tag, attributes, contents);
223 if(tag=="electron" || tag=="muon" || tag=="tau") addTables(tag, attributes, contents);
224 else if(tag=="param") addParams(tag, contents, attributes);
225 else if(tag=="syst") addSysts(tag, contents, attributes);
226 else if(tag=="ROOT") importCustomROOT(tag, contents, attributes);
227 else throw(XmlError(stream) << "unknown/unexpected XML tag \"" << tag.str() << "\"");
228 }
229 m_lineOffset.clear();
230 m_lineOffset.shrink_to_fit();
231 m_xmlBuffer.clear();
232 m_xmlBuffer.shrink_to_fit();
233}
234
236{
237 tag.clear();
238 contents.clear();
239 for(auto& kv : attributes) kv.second.clear();
241 std::string pattern = "^\\s*(<([[:alnum:]]+)((?:\\s+\\|?[_[:alnum:]]+\\|?\\s*=\\s*\"[_[:alnum:]\\s,-\\[\\]\\.\\|]+\")*)\\s*>)(.*?)</\\2>\\s*";
242 std::cmatch cmr;
243 if(!std::regex_search(stream.ptr, stream.endptr, cmr, std::regex(pattern)))
244 {
246 throw(XmlError(stream) << "unable to find next tag");
247 }
248 tag.set(stream.ptr+cmr.position(2), cmr.length(2));
249
250 readTagAttributes(StringRef(stream.ptr+cmr.position(3), cmr.length(3)), tag.str(), attributes);
251
252 auto cpos = cmr.size()-1;
253 contents.set(stream.ptr+cmr.position(cpos), cmr.length(cpos));
254
255 stream.ptr += cmr.length();
256}
257
258void Database::readTagAttributes(StringRef stream, const std::string& tag, AttributesMap& attributes)
259{
260 auto nAttr = std::count(stream.ptr, stream.endptr, '=');
261 if(!nAttr) return;
262
263 std::string pattern = "";
264 for(int i=0;i<nAttr;++i) pattern += "\\s+(\\|?[_[:alnum:]]+\\|?)\\s*=\\s*\"([_[:alnum:]\\s,-\\[\\]\\.\\|]+)\"";
265
266 std::cmatch cmr;
267 if(!std::regex_match(stream.ptr, stream.endptr, cmr, std::regex(pattern)))
268 {
269 throw(XmlError(stream) << "unexpected error (internal))");
270 }
271 for(unsigned i=1;i<cmr.size();i+=2)
272 {
273 auto attr = cmr[i].str();
274 auto itr = attributes.find(tag + '/' + attr);
275 if(itr == attributes.end())
276 {
277 throw(XmlError(stream.ptr+cmr.position(i), attr.length()) << "invalid attribute \"" << attr << "\"");
278 }
279 if(!cmr.length(i+1))
280 {
281 throw(XmlError(stream.ptr+cmr.position(i), attr.length()) << "empty value for attribute \"" << attr << "\"");
282 }
283 auto& attrVal = itr->second;
284 if(attrVal) throw(XmlError(stream.ptr+cmr.position(i), attr.length()) << "the attribute \"" << attr << "\" has already been specified for that tag");
285 attrVal.set(stream.ptr+cmr.position(i+1), cmr.length(i+1));
286 }
287}
288
289void Database::dropXmlComments(std::string& buffer)
290{
291 std::regex rx("<!--.*?-->");
292 std::smatch smr;
293 while(std::regex_search(buffer, smr, rx))
294 {
295 std::size_t pos = smr.position(0), length = smr.length(), endpos = pos + length;
296 for(auto& offset : m_lineOffset)
297 {
298 if(offset > endpos) offset -= length;
299 else if(offset > pos) offset = pos;
300 }
301 buffer = smr.prefix().str() + smr.suffix().str();
302 }
303}
304
305void Database::dropRootTag(std::string& buffer)
306{
307 const std::vector<std::string> keys = {"<efficiencies>", "</efficiencies>"};
308 for(const auto& key : keys)
309 {
310 std::size_t ipos;
311 while((ipos = buffer.find(key)) != std::string::npos)
312 {
313 buffer.erase(ipos, key.length()-1);
314 buffer[ipos] = ' ';
315 }
316 }
317}
318
319std::vector<std::string> Database::getListOfNames(const StringRef& stream)
320{
321 std::vector<std::string> words;
322 std::stringstream ss(std::string(stream.ptr, stream.endptr));
323 std::string w;
324 while(std::getline(ss, w, ','))
325 {
326 std::size_t i = w.find_first_not_of(" \t");
327 std::size_t j = w.find_last_not_of(" \t");
328 if(i == std::string::npos)
329 {
330 throw(XmlError(stream) << "this should be a comma-separated list of names");
331 }
332 words.push_back(w.substr(i, j-i+1));
333 }
334 return words;
335}
336
337template<typename ReturnValue>
338ReturnValue Database::getAttribute(const StringRef& attr, const char* ref, ReturnValue rv)
339{
340 if(attr.str() == ref) return rv;
341 throw(XmlError(attr) << "unsupported parameter type \"" << attr.str() << "\"");
342}
343
344template<typename ReturnValue, typename... Args>
345ReturnValue Database::getAttribute(const StringRef& attr, const char* ref, ReturnValue rv, Args... args)
346{
347 if(attr.str() == ref) return rv;
348 return getAttribute(attr, args...);
349}
350
351template<typename ReturnValue, typename... Args>
352ReturnValue Database::getAttribute(const StringRef& tag, const AttributesMap& attributes, const std::string& type, const char* ref, ReturnValue rv, Args... args)
353{
354 std::string attrname = tag.str() + "/" + type;
355 auto& attr = attributes.at(attrname);
356 if(!attr) throw(XmlError(tag) << "unspecified value for attribute \"" << type << "\"");
357 return getAttribute(attr, ref, rv, args...);
358}
359
360void Database::addParams(const StringRef& tag, const StringRef& contents, AttributesMap& attributes)
361{
362 auto type = getAttribute(tag, attributes, "type", "int", Param::Type::CUSTOM_INT, "float", Param::Type::CUSTOM_FLOAT);
363 auto level = getAttribute(tag, attributes, "level", "particle", Param::Level::PARTICLE, "event", Param::Level::EVENT);
364
365 for(auto& name: getListOfNames(contents))
366 {
367 if(std::any_of(m_params.begin(), m_params.end(), [&](const Param& p){ return p.name == name; }))
368 {
369 throw(XmlError(contents) << "parameter \"" << name << "\" was already declared");
370 }
371 m_params.emplace_back(name, type, level);
372 attributes["bin/" + name];
373 attributes["table/" + name];
374 }
375}
376
377void Database::addSysts(const StringRef& tag, const StringRef& contents, const AttributesMap& attributes)
378{
379 std::bitset<N_EFFICIENCY_TYPES> affects;
380 for(auto& target : getListOfNames(attributes.at("syst/affects")))
381 {
382 auto targetMatches = [&](const char* a, const char* b) -> bool
383 { return target==a || target==b || target==std::string(a)+'-'+b; };
384 int matched = 0;
385 if(targetMatches("electron", "real-efficiency")) { affects.set(ELECTRON_REAL_EFFICIENCY); ++matched; }
386 if(targetMatches("muon", "real-efficiency")) { affects.set(MUON_REAL_EFFICIENCY); ++matched; }
387 if(targetMatches("tau", "real-efficiency")) { affects.set(TAU_REAL_EFFICIENCY); ++matched; }
388 if(targetMatches("electron", "fake-efficiency")) { affects.set(ELECTRON_FAKE_EFFICIENCY); ++matched; }
389 if(targetMatches("muon", "fake-efficiency")) { affects.set(MUON_FAKE_EFFICIENCY); ++matched; }
390 if(targetMatches("tau", "fake-efficiency")) { affects.set(TAU_FAKE_EFFICIENCY); ++matched; }
391 if(targetMatches("electron", "fake-factor")) { affects.set(ELECTRON_FAKE_FACTOR); ++matched; }
392 if(targetMatches("muon", "fake-factor")) { affects.set(MUON_FAKE_FACTOR); ++matched; }
393 if(targetMatches("tau", "fake-factor")) { affects.set(TAU_FAKE_FACTOR); ++matched; }
394 if(!matched) throw(XmlError(tag) << "the value \"" << target << "\" specified for the attribute \"affects\" is not recognized");
395 }
396 if(affects.none()) throw(XmlError(tag) << "missing or empty attribute \"affects\"");
397 for(auto& name: getListOfNames(contents))
398 {
399 if(name == "stat") throw(XmlError(contents) << "systematics can't be named \"stat\"");
400 if(std::any_of(m_systs.begin(), m_systs.end(), [&](const SystDef& s){ return s.name==name && (affects&s.affects).any(); }))
401 {
402 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");
403 }
404 if(m_systs.size() >= maxIndex()) throw(XmlError(contents) << "exceeded max number of systematic uncertainties");
405 m_systs.emplace_back(name, affects);
406 }
407}
408
410{
411 if(m_stats.size() >= maxIndex())
412 {
413 if(pos) throw(XmlError(pos) << "exceeded max number of statistical uncertainties");
414 else throw(GenericError() << "exceeded max number of statistical uncertainties");
415 }
416 m_stats.emplace_back(1 << type);
417 return statIndexToUID(m_stats.size() - 1);
418}
419
420void Database::addTables(const StringRef& particle, const AttributesMap& attributes, const StringRef& contents, TFile* source)
421{
423 if(particle == "muon") type = getAttribute(particle, attributes, "type",
424 "real-efficiency", MUON_REAL_EFFICIENCY, "fake-efficiency", MUON_FAKE_EFFICIENCY, "fake-factor", MUON_FAKE_FACTOR);
425 else if(particle == "electron") type = getAttribute(particle, attributes, "type",
426 "real-efficiency", ELECTRON_REAL_EFFICIENCY, "fake-efficiency", ELECTRON_FAKE_EFFICIENCY, "fake-factor", ELECTRON_FAKE_FACTOR);
427 else if(particle == "tau") type = getAttribute(particle, attributes, "type",
428 "real-efficiency", TAU_REAL_EFFICIENCY, "fake-efficiency", TAU_FAKE_EFFICIENCY, "fake-factor", TAU_FAKE_FACTOR);
429 else throw(XmlError(particle) << "unexpected error: unsupported particle type " << particle.str());
430 auto statMode = attributes.at(particle.str()+"/stat") ? getAttribute(particle, attributes, "stat",
432 auto inputType = getAttribute(particle, attributes, "input", "central-value", InputType::CENTRAL_VALUE, "correction", InputType::CORRECTION);
433
434 unsigned short globalStatUID = 0;
435
436 AttributesMap subattributes;
437 StringRef stream = contents, subcontents;
438 while(stream.length())
439 {
440 StringRef tag;
441 resetAttributes(subattributes);
442 readNextTag(stream, tag, subattributes, subcontents);
443 const TH1* hist = nullptr;
444 if(tag=="bin" || tag=="table" || tag=="TH1")
445 {
446 if(tag == "TH1")
447 {
448 if(!source) throw(XmlError(tag) << "histograms can only be imported inside <ROOT>...</ROOT> blocks!");
449 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)");
450 auto name = subcontents.trim();
451 hist = static_cast<const TH1*>(source->Get(name.c_str()));
452 if(!hist) throw(XmlError(subcontents) << "can't find any histogram named \"" << name << "\" in the file " << source->GetName());
453 auto& norm = subattributes.at("TH1/norm");
454 if(inputType!=InputType::CORRECTION && (norm && norm!="none"))
455 throw(XmlError(norm) << "normalization of input histograms is only accepted for 'input=\"correction\"'");
456 float scale = getNormalizationFactor(hist, type, norm, subcontents);
457 importNominalTH1(hist, type, subattributes.at("TH1/X"), subattributes.at("TH1/Y"), subattributes.at("TH1/Z"), scale, statMode, globalStatUID, subcontents);
458 }
459 else m_tables[type].emplace_back();
460 auto& table = m_tables[type].back();
461 table.inputType = inputType;
462
463 auto initialNumberOfBins = table.numberOfBins();
464 std::map<StringRef, unsigned> dimBins;
465 for(unsigned uid=0; uid<m_params.size(); ++uid)
466 {
467 auto& binning = subattributes.at(tag + "/" + m_params[uid].name);
468 if(binning) dimBins.emplace(binning, uid);
469 }
470 for(auto& kv : dimBins) addDimension(table, kv.second, kv.first);
471
472 if(tag != "TH1")
473 {
474 if(tag == "bin" && table.numberOfBins() > 1) throw(XmlError(tag) << "use a <table> instead of a <bin> tag to hold several values");
475 addValues(subcontents, table, type, statMode, globalStatUID);
476 }
477 else if(table.numberOfBins() != initialNumberOfBins) throw(XmlError(tag) << "extra binned dimensions do not make sense");
478 if(tag=="TH1" || tag=="bin")
479 {
480 auto& label = subattributes.at(tag + "/label");
481 if(label)
482 {
483 float normFactor {0};
484 if(tag == "TH1") normFactor = 1.f / getWeightedAverage(hist, stream);
485 else
486 {
487 assert (tag == "bin");
488 normFactor = 1.f / table.m_efficiencies[0].nominal;
489 }
490 if(!std::isnormal(normFactor) || normFactor<=0.) throw(XmlError(label) << "computed normalization factor is 0 / NaN / infinite / negative");
491 if(!m_normFactors.emplace(label.str()+"-"+std::to_string(type), normFactor).second)
492 throw(XmlError(label) << "label \"" << label.str() << "\" has already been used");
493 }
494 }
495 }
496 else throw(XmlError(tag) << "unknown/unexpected XML tag \"" << tag.str() << "\"");
497 }
498}
499
500void Database::assertNoLeftover(std::stringstream& ss, const StringRef& pos)
501{
502 ss >> std::ws;
503 if(!ss.eof())
504 {
505 std::string line;
506 std::getline(ss, line);
507 throw(XmlError(pos) << "unexpected parsing error (leftover data \"" << line << "\")");
508 }
509}
510
511void Database::addDimension(EfficiencyTable& table, unsigned paramUID, const StringRef& contents)
512{
513 if(!contents) return;
514 auto& param = m_params[paramUID];
515 const bool integer = param.integer();
516 const std::string fp = "[+-]?[0-9]*\\.?[0-9]+(?:[Ee][+-]?[0-9]+)?";
517 const std::string pattern = "^\\s*\\[\\s*(?:(?:-inf\\s*,\\s*|-?)inf|(?:-inf\\s*,\\s*)?"
518 + fp + "(?:\\s*,\\s*" + fp + ")*(?:\\s*,\\s*inf)?)\\s*\\]\\s*$";
519 if(!std::regex_match(contents.ptr, contents.endptr, std::regex(pattern)))
520 {
522 if(!integer || !std::regex_match(contents.ptr, contents.endptr, std::regex("\\s*[+-]?[0-9]+\\s*")))
523 {
524 throw(XmlError(contents) << "invalid format for the range of the parameter " << param.name);
525 }
526 }
527
528 auto& bounds = table.m_bounds;
529 table.m_dimensions.emplace_back();
530 auto& dim = table.m_dimensions.back();
531 dim.paramUID = paramUID;
532 dim.iMinBound = table.m_bounds.size();
533 auto line = contents.str();
534 dim.nBounds = std::count(line.begin(), line.end(), ',') + 1;
535 if(integer && dim.nBounds < 1) throw(XmlError(contents) << "should specify at least one bin boundary for parameter " << param.name);
536 if(!integer && (dim.nBounds < 2)) throw(XmlError(contents) << "should specify at least two bin boundaries for parameter " << param.name);
537 for(auto&c : line) if(c==',' || c=='[' || c==']') c = ' ';
538 std::stringstream ss(line);
539 for(int i=0;i<dim.nBounds;++i)
540 {
542 if(integer) ss >> x.as_int;
543 else ss >> x.as_float;
544 if(ss.fail())
545 {
546 if(i==0 || i==(dim.nBounds-1))
547 {
548 ss.clear();
549 ss.unget();
550 ss.clear();
551 std::string x_s;
552 ss >> x_s;
553 if(x_s=="inf" || x_s=="-inf")
554 {
555 bool defMax = (x_s.front() != '-');
556 if(integer) x.as_int = defMax ? std::numeric_limits<int>::max() : std::numeric_limits<int>::min();
557 else x.as_float = defMax ? std::numeric_limits<float>::max() : std::numeric_limits<float>::lowest();
558 }
559 else throw(XmlError(contents) << "parsing error (invalid 'inf' string)");
560 }
561 if(ss.fail()) throw(XmlError(contents) << "parsing error (can't read int/float boundary)");
562 }
563 if(i)
564 {
565 if(integer ? (bounds.back().as_int > x.as_int) : (bounds.back().as_float > x.as_float))
566 {
567 throw(XmlError(contents) << "bin boundaries must be sorted in increasing order");
568 }
569 }
570 bounds.push_back(x);
571 }
573 if(integer && dim.nBounds==1)
574 {
575 dim.nBounds = 2;
576 bounds.push_back(bounds.back());
577 bounds.back().as_int += 1;
578 }
579}
580
581void Database::addValues(const StringRef& contents, EfficiencyTable& table, EfficiencyType type, StatMode statMode, unsigned short& globalStatUID)
582{
583 const std::string fpv = "(?:[0-9]+\\.)?[0-9]+(?:[Ee][+-]?[0-9]+)?", fpu = fpv + "\\s*\\%?";
584 const std::string pattern = "^\\s*" + fpv + "(?:\\s*(?:\\+(?:\\s*" + fpu + "\\s*)?-|-(?:\\s*" + fpu + "\\s*)?\\+)\\s*" + fpu + "\\s*\\([_[:alnum:]]+\\))*\\s*";
585 auto rxValidFormat = std::regex(pattern);
586 std::stringstream ssCSV(contents.str()), ss;
587 const char* ptr = contents.ptr;
588
589 if(statMode==StatMode::GLOBAL && !globalStatUID) globalStatUID = addStat(type, contents);
590
591 while(ptr && ptr<contents.endptr)
592 {
593 std::cmatch cm;
594 if(!std::regex_search(ptr, contents.endptr, cm, rxValidFormat))
595 {
596 StringRef lineref{ptr, contents.endptr};
597 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) << " [...]");
598 }
599 StringRef valref{ptr, static_cast<std::size_t>(cm.length())};
600 ptr += cm.length();
601 std::string value = valref.str();
602 value.erase(std::remove_if(value.begin(), value.end(), [](char c){ return std::isspace(c); }), value.end());
603 unsigned nErrs = std::count(value.begin(), value.end(), '(');
604 for(auto& c : value) if(c=='(' || c==')') c = ' ';
605 ss.clear();
606 ss.str(value);
607 table.m_efficiencies.emplace_back();
608 auto& eff = table.m_efficiencies.back();
609 ss >> eff.nominal;
610 bool foundStat = false;
611 for(unsigned i=0;i<nErrs;++i)
612 {
614 std::string sysname;
615 ss >> std::ws;
616 auto c1 = ss.get();
617 auto c2 = ss.peek();
618 if(c2=='+' || c2=='-')
619 {
620 ss >> c2 >> uncval.up >> sysname;
621 if(sysname == "%")
622 {
623 uncval.up *= 0.01f * eff.nominal;
624 ss >> sysname;
625 }
626 uncval.down = uncval.up;
627 }
628 else
629 {
630 ss >> uncval.up >> c2;
631 if(c2 == '%')
632 {
633 uncval.up *= 0.01f * eff.nominal;
634 ss >> c2;
635 }
636 ss >> uncval.down >> sysname;
637 if(sysname == "%")
638 {
639 uncval.down *= 0.01f * eff.nominal;
640 ss >> sysname;
641 }
642 }
643 if(ss.bad()) throw(XmlError(valref) << "unexpected parsing error");
644 if(std::signbit(uncval.up) != std::signbit(uncval.down)) throw(XmlError(valref) << "one-sided up/down errors");
645 if(c1 == '-')
646 {
647 uncval.up = -uncval.up;
648 uncval.down = -uncval.down;
649 }
650
652 if(sysname == "stat")
653 {
654 if(foundStat) throw(XmlError(valref) << "there can be only one source of statistical uncertainty per bin");
655 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\")");
656 foundStat = true;
657 uid = (statMode == StatMode::GLOBAL)? globalStatUID : addStat(type, contents);
658 }
659 else
660 {
661 auto sys = std::find_if(m_systs.begin(), m_systs.end(),
662 [&](const SystDef& sd){ return sd.name==sysname && sd.affects[type]; });
663 if(sys == m_systs.end()) throw(XmlError(valref) << "the systematic \"" << sysname << "\" has either not been defined, or does not affect this type of efficiency");
664 unsigned index = sys - m_systs.begin();
666 }
667 if(!eff.uncertainties.emplace(uid, uncval).second)
668 {
669 throw(XmlError(valref) << "source of uncertainty \"" << sysname << "\" specified twice");
670 }
671 }
673 }
674 if(table.m_efficiencies.size() != table.numberOfBins())
675 {
676 throw(XmlError(contents) << "the number of tabulated efficiencies (" << table.m_efficiencies.size()
677 << ") is inconsistent with the number of bins (" << table.numberOfBins() << ")");
678 }
679}
680
681void Database::importCustomROOT(const StringRef& rootTag, const StringRef& contents, const AttributesMap& attributes)
682{
683 std::string filename = attributes.at("ROOT/source").str();
684 if(!filename.length()) throw(XmlError(rootTag) << "the 'file' attribute must be specified!");
685 filename = PathResolverFindCalibFile(filename);
686
687 TFile* file = TFile::Open(filename.c_str(), "READ");
688 if(!file || !file->IsOpen())
689 {
690 delete file;
691 throw(XmlError(rootTag) << "unable to locate/open the file " << filename);
692 }
693
694 AttributesMap subattributes;
695 StringRef stream = contents, tag, subcontents;
696 while(stream.length())
697 {
698 resetAttributes(subattributes);
699 readNextTag(stream, tag, subattributes, subcontents);
700 if(tag=="electron" || tag=="muon" || tag=="tau") addTables(tag, subattributes, subcontents, file);
701 else throw(XmlError(stream) << "unknown/unexpected XML tag \"" << tag << "\"");
702 }
703
704 file->Close();
705 delete file;
706}
707
709{
710 attributes["ROOT/source"];
711 attributes["param/type"];
712 attributes["param/level"];
713 attributes["syst/affects"];
714
715 const std::vector<std::string> parts = {"electron", "muon", "tau"};
716 for(const auto& p : parts)
717 {
718 attributes[p + "/type"];
719 attributes[p + "/input"];
720 attributes[p + "/stat"];
721 }
722 attributes["TH1/X"];
723 attributes["TH1/Y"];
724 attributes["TH1/Z"];
725 attributes["TH1/label"];
726 attributes["bin/label"];
727 attributes["TH1/norm"];
728 for(auto& p : m_params)
729 {
730 attributes["bin/" + p.name];
731 attributes["table/" + p.name];
732 attributes["TH1/" + p.name];
735 }
736}
737
738/*
739 * Loading from ROOT
740 */
741
742void Database::importDefaultROOT(std::string filename)
743{
744 const std::string prefix = "^(FakeFactor|FakeEfficiency|RealEfficiency|FakeRate|FakeRateSF)", suffix = "_([[:w:]][^_]+)(__[[:w:]]+)?$";
745 const std::regex rxTH1(prefix + "_(el|mu|tau|e2y)" + suffix);
746 const std::regex rxTH2(prefix + "2D_(el|mu|tau|e2y)_([[:alnum:]]+)" + suffix);
747 const std::regex rxTH3(prefix + "3D_(el|mu|tau)_([[:alnum:]]+)_([[:alnum:]]+)" + suffix);
748
749 filename = PathResolverFindCalibFile(filename);
750 TFile* file = TFile::Open(filename.c_str(), "READ");
751 if(!file || !file->IsOpen())
752 {
753 throw(GenericError() << "unable to locate/open the file " << filename);
754 }
755
756 auto keys = file->GetListOfKeys();
757 if(!keys) throw(GenericError() << "unable to list keys in the file " << filename << " (corrupted?)");
758
759 const StringRef nullStream;
760 unsigned short dummy;
761 for(unsigned step=0;step<2;++step)
762 {
765 for(int i=0;i<keys->GetSize();++i)
766 {
767 TKey* key = static_cast<TKey*>(keys->At(i));
768 std::cmatch mr;
769 std::string keyType = key->GetClassName();
770 unsigned nDims = 0;
771 if(keyType=="TH1F" || keyType=="TH1D") nDims = 1 * std::regex_match(key->GetName(), mr, rxTH1);
772 else if(keyType=="TH2F" || keyType=="TH2D") nDims = 2 * std::regex_match(key->GetName(), mr, rxTH2);
773 else if(keyType=="TH3F" || keyType=="TH3D") nDims = 3 * std::regex_match(key->GetName(), mr, rxTH3);
774 else continue;
775 if(nDims < 1) throw(GenericError() << "don't know what to do with histogram named \"" << key->GetName() << "\" (please check naming conventions)");
776 TH1* hist = static_cast<TH1*>(key->ReadObj());
778 std::string sss = mr[1].str() + "-" + mr[2].str();
779 auto type = getAttribute(StringRef(sss.data(), sss.length()),
780 "FakeFactor-el", ELECTRON_FAKE_FACTOR, "FakeFactor-mu", MUON_FAKE_FACTOR, "FakeFactor-tau", TAU_FAKE_FACTOR,
781 "FakeEfficiency-el", ELECTRON_FAKE_EFFICIENCY, "FakeEfficiency-mu", MUON_FAKE_EFFICIENCY, "FakeEfficiency-tau", TAU_FAKE_EFFICIENCY,
782 "RealEfficiency-el", ELECTRON_REAL_EFFICIENCY, "RealEfficiency-mu", MUON_REAL_EFFICIENCY, "RealEfficiency-tau", TAU_REAL_EFFICIENCY,
783 "FakeRate-e2y", PHOTON_ELE_FAKE_FACTOR, "FakeRateSF-e2y", PHOTON_ELE_FAKE_FACTOR_SF
784 );
785 bool systTH1 = (mr[mr.size()-1].str() != "");
786 if(step==0 && !systTH1)
787 {
788 StringRef paramX = StringRef(mr[3].first, mr[3].second);
789 StringRef paramY = (nDims>1) ? StringRef(mr[4].first, mr[4].second) : StringRef();
790 StringRef paramZ = (nDims>2) ? StringRef(mr[5].first, mr[5].second) : StringRef();
791 importNominalTH1(hist, type, paramX, paramY, paramZ, 1.f, StatMode::PER_BIN, dummy, nullStream);
792 m_tables[type].back().inputType = InputType::CENTRAL_VALUE;
793 }
794 else if(step==1 && systTH1) importSystTH1(hist, type, mr[nDims+3].str().substr(2));
795 else continue;
796 }
797 }
798
799 file->Close();
800 delete file;
801}
802
803float Database::getWeightedAverage(const TH1* hist, const StringRef& xmlStream)
804{
805 float avg = 1.f;
806 if(hist->GetNbinsX()!=1 || hist->GetNbinsY()!=1 || hist->GetNbinsZ()!=1)
807 {
809 double sum = 0., denom = 0.;
810 for(int i=1;i<=hist->GetNbinsX();++i)
811 for(int j=1;j<=hist->GetNbinsY();++j)
812 for(int k=1;k<=hist->GetNbinsZ();++k)
813 {
814 double x = hist->GetBinContent(i, j, k);
815 if(x == 0.) continue;
816 double w = hist->GetBinError(i, j, k);
817 if(w == 0.) throw(XmlError(xmlStream) << "bin with error = 0 encountered when trying to normalize histogram " << hist->GetName() << " to weighted bins average");
818 w = 1./(w*w);
819 sum += w * x;
820 denom += w;
821 }
822 avg = sum / denom;
823 }
824 else avg = 1. / hist->GetBinContent(1);
825 if(!std::isnormal(avg) || avg<=0.) throw(XmlError(xmlStream) << "something bad happened when trying to compute the weighted average of histogram \""
826 << hist->GetName() << "\" bins, the result ended up 0 / NaN / infinite / negative");
827 return avg;
828}
829
830float Database::getNormalizationFactor(const TH1* hist, EfficiencyType type, const StringRef& norm, const StringRef& xmlStream)
831{
833 if(!norm) return 1.f;
834 auto normType = norm.str();
835 if(normType == "auto") return 1.f / getWeightedAverage(hist, xmlStream);
836 else if(normType != "none")
837 {
838 auto itr = m_normFactors.find(normType + "-" + std::to_string(type));
839 if(itr == m_normFactors.end()) throw(XmlError(norm) << "unknown normalization tag \"" << normType << "\"");
840 return itr->second;
841 }
842 return 1.f;
843}
844
845void Database::importNominalTH1(const TH1* hist, EfficiencyType type, const StringRef& paramX, const StringRef& paramY, const StringRef& paramZ,
846 float scale, StatMode statMode, unsigned short& globalStatUID, const StringRef& xmlStream)
847{
848 const bool useDefaults = !xmlStream;
849
850 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");
851 m_tables[type].emplace_back();
852 auto& table = m_tables[type].back();
853
854 const int nDims = paramZ? 3 : paramY? 2 : 1;
855 if(hist->GetDimension() != nDims)
856 {
857 if(xmlStream) throw(XmlError(xmlStream) << "histogram " << hist->GetName() << " doesn't have the expected dimension");
858 else throw(GenericError() << "histogram " << hist->GetName() << " doesn't have the expected dimension");
859 }
860
862 for(int j=0;j<nDims;++j)
863 {
864 std::string name = ((j==2)? paramZ : (j==1)? paramY : paramX).str();
865 const TAxis* axis = (j==2)? hist->GetZaxis() : (j==1)? hist->GetYaxis() : hist->GetXaxis();
866 if(useDefaults && name == "eta" && axis->GetBinLowEdge(1) >= 0) name = "|eta|";
867 table.m_dimensions.emplace_back();
868 auto& dim = table.m_dimensions.back();
869 auto itr = std::find_if(m_params.begin(), m_params.end(), [&](const Param& p){ return p.name == name; });
870 bool integer;
871 if(itr == m_params.end())
872 {
873 if(useDefaults)
874 {
875 dim.paramUID = m_params.size();
876 m_params.emplace_back(name, Param::Type::CUSTOM_FLOAT, Param::Level::PARTICLE);
877 integer = false;
878 }
879 else throw(XmlError(j? paramY : paramX) << "parameter \"" << name << "\" has not been defined beforehand");
880 }
881 else
882 {
883 dim.paramUID = itr - m_params.begin();
884 integer = itr->integer();
885 }
886 dim.iMinBound = table.m_bounds.size();
887 dim.nBounds = axis->GetNbins() + 1;
889 table.m_bounds.emplace_back();
890 if(integer) table.m_bounds.back().as_int = std::numeric_limits<int>::min();
891 else table.m_bounds.back().as_float = std::numeric_limits<float>::lowest();
892 for(int k=1;k<dim.nBounds-1;++k)
893 {
894 table.m_bounds.emplace_back();
895 if(integer) table.m_bounds.back().as_int = std::ceil(axis->GetBinUpEdge(k));
896 else table.m_bounds.back().as_float = axis->GetBinUpEdge(k);
897 }
898 table.m_bounds.emplace_back();
899 if(integer) table.m_bounds.back().as_int = std::numeric_limits<int>::max();
900 else table.m_bounds.back().as_float = std::numeric_limits<float>::max();
901 }
902
904 if(statMode==StatMode::GLOBAL && !globalStatUID) globalStatUID = addStat(type, xmlStream);
905 const unsigned xmax = table.m_dimensions.front().nBounds;
906 const unsigned ymax = table.m_dimensions.size()>1? table.m_dimensions[1].nBounds : 2;
907 const unsigned zmax = table.m_dimensions.size()>2? table.m_dimensions[2].nBounds : 2;
908 for(unsigned x=1;x<xmax;++x)
909 for(unsigned y=1;y<ymax;++y)
910 for(unsigned z=1;z<zmax;++z)
911 {
912 table.m_efficiencies.emplace_back();
913 auto& eff = table.m_efficiencies.back();
914 eff.nominal = scale * hist->GetBinContent(x, y, z);
915 if(statMode != StatMode::NONE)
916 {
917 uint16_t uid = (statMode==StatMode::GLOBAL)? globalStatUID : addStat(type, xmlStream);
918 float err = hist->GetBinError(x, y, z);
919 FakeBkgTools::Uncertainty uncdata{scale*err, scale*err};
920 eff.uncertainties.emplace(uid, uncdata);
921 }
922 }
923}
924
925void Database::importSystTH1(const TH1* hist, EfficiencyType type, const std::string& sysname)
926{
927 if(!m_tables[type].size()) throw(GenericError() << "there should be another histogram containing central values to accompany the histogram " << hist->GetName());
928 auto& table = m_tables[type].back();
929 const int xmax = table.m_dimensions.front().nBounds;
930 const int ymax = table.m_dimensions.size()>1? table.m_dimensions[1].nBounds : 2;
931 const int zmax = table.m_dimensions.size()>2? table.m_dimensions[2].nBounds : 2;
932 if(xmax!=hist->GetNbinsX()+1 || ymax!=hist->GetNbinsY()+1 || zmax!=hist->GetNbinsZ()+1)
933 {
934 throw(GenericError() << "binning mismatch between the nominal histogram and " << hist->GetName());
935 }
936
938 auto itr = std::find_if(m_systs.begin(), m_systs.end(), [&](const SystDef& sys){ return sys.name==sysname; });
939 if(itr != m_systs.end())
940 {
941 uid = systIndexToUID(itr - m_systs.begin());
942 itr->affects.set(type);
943 }
944 else
945 {
946 uid = systIndexToUID(m_systs.size());
947 m_systs.emplace_back(sysname, (1 << type));
948 }
949
950 //loop through all bins once, to check whether all bins are zero error,
951 //or have the same central value as the nominal
952
953 bool syst_central_equal_nom_central = true;
954 bool syst_errors_equal_zero = true;
955 bool syst_errors_equal_nom_errors = true;
956
957 auto eff = table.m_efficiencies.begin();
958 for(int x=1;x<xmax;++x)
959 for(int y=1;y<ymax;++y)
960 for(int z=1;z<zmax;++z)
961 {
962 if (fabs ((float)eff->nominal - (float)hist->GetBinContent(x, y, z)) > 0.001 ){ syst_central_equal_nom_central = false;}
963 if ( hist->GetBinError(x, y, z) != 0 ) { syst_errors_equal_zero = false;}
964 float stat_up = 0;
965 for(auto& kv : eff->uncertainties)
966 {
967 if(!isStatUID(kv.first)) continue;
968 stat_up = kv.second.up; break;
969 }
970 if ( fabs((float) hist->GetBinError(x, y, z) - (float) stat_up ) > 0.001) { syst_errors_equal_nom_errors = false;}
971 ++eff;
972 }
973
974 // loop bins a second time and determine proceedure using above heuristics
975 eff = table.m_efficiencies.begin();
976 for(int x=1;x<xmax;++x)
977 for(int y=1;y<ymax;++y)
978 for(int z=1;z<zmax;++z)
979 {
980
981 float err =0;
982 //want to support several possible notations:
983 // a) central values are not the same as nominal: then we can assume
984 // that the central values of the syst histos are the errors,
985 // (default nomenclature from the documentation)
986 // b) if the central values for nominal and this hist are the same
987 // then probably the errors are to be taken from the error bars!
988 // but need to watch out for ambiguous cases
989 //
990 if (syst_central_equal_nom_central){ //central values are the same in nom and sys
991 if (syst_errors_equal_nom_errors ){ // this case is ambiguous. Is it a 100% uncertainty?
992 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. ");
993 } else if (syst_errors_equal_zero ) { //assume here that it was intended as 100% uncertainty
994 err = hist->GetBinContent(x, y, z);
995 } else {
996 err = hist->GetBinError(x, y, z);
997 }
998 } else { // central values are different in nom and sys
999 err = hist->GetBinContent(x, y, z);
1000 }
1001
1002
1003 FakeBkgTools::Uncertainty uncdata{err, err};
1004 if(!eff->uncertainties.emplace(uid, uncdata).second)
1005 {
1006 throw(GenericError() << "unexpected error: tried filling twice the same systematic");
1007 }
1008 ++eff;
1009 }
1010}
1011
1013{
1014 #ifdef FAKEBKGTOOLS_ATLAS_ENVIRONMENT
1015 float energy_scale = (m_useGeV? 0.001f : 1.f);
1016 #else
1017 float energy_scale = 1;
1018 #endif
1019 if(param.level == Param::Level::PARTICLE)
1020 {
1021 if(param.type==Param::Type::PREDEFINED_FLOAT || param.type==Param::Type::PREDEFINED_INT)
1022 {
1023 if(param.name=="pt") val.as_float = energy_scale * p.pt();
1024 else if(param.name=="eta") val.as_float = p.eta();
1025 else if(param.name=="|eta|") val.as_float = fabs(p.eta());
1026 else if(param.name=="phi") val.as_float = p.phi();
1027 else return false;
1028 }
1029 else if(param.type == Param::Type::CUSTOM_FLOAT) {
1031 val.as_float = acc(p);
1032 }
1033 else if(param.type == Param::Type::CUSTOM_INT) {
1035 val.as_int = acc(p);
1036 }
1037 else return false;
1038 }
1039 else if(param.level == Param::Level::EVENT)
1040 {
1041 if(param.type == Param::Type::CUSTOM_FLOAT) {
1043 val.as_float = acc(eventInfo);
1044 }
1045 else if(param.type == Param::Type::CUSTOM_INT) {
1047 val.as_int = acc(eventInfo);
1048 }
1049 else return false;
1050 }
1051 else return false;
1052 return true;
1053}
1054
1056{
1057 switch(p.type())
1058 {
1060 if(type==ELECTRON_FAKE_FACTOR) return &pd.fake_factor;
1061 else if(type==ELECTRON_FAKE_EFFICIENCY) return &pd.fake_efficiency;
1062 else if(type==ELECTRON_REAL_EFFICIENCY) return &pd.real_efficiency;
1063 else if(type==PHOTON_ELE_FAKE_FACTOR) return &pd.fake_factor;
1064 break;
1065 case xAOD::Type::Muon:
1066 if(type==MUON_FAKE_FACTOR) return &pd.fake_factor;
1067 else if(type==MUON_FAKE_EFFICIENCY) return &pd.fake_efficiency;
1068 else if(type==MUON_REAL_EFFICIENCY) return &pd.real_efficiency;
1069 break;
1070 case xAOD::Type::Tau:
1071 if(type==TAU_FAKE_FACTOR) return &pd.fake_factor;
1072 else if(type==TAU_FAKE_EFFICIENCY) return &pd.fake_efficiency;
1073 else if(type==TAU_REAL_EFFICIENCY) return &pd.real_efficiency;
1074 break;
1075 case xAOD::Type::Photon:
1076 if(type==PHOTON_ELE_FAKE_FACTOR_SF) return &pd.fake_factor;
1077 break;
1078 default:;
1079 }
1080 return nullptr;
1081}
1082
1084auto Database::selectTypesToFill(Client client) -> std::bitset<N_EFFICIENCY_TYPES>
1085{
1086 std::bitset<N_EFFICIENCY_TYPES> result;
1087 if(client==Client::MATRIX_METHOD || client==Client::ALL_METHODS)
1088 {
1095 }
1096 if(client==Client::FAKE_FACTOR || client==Client::ALL_METHODS)
1097 {
1099 result[MUON_FAKE_FACTOR] = true;
1100 result[TAU_FAKE_FACTOR] = true;
1101 }
1102 if(client==Client::E2Y_FAKE || client==Client::ALL_METHODS)
1103 {
1106 }
1107 if(result.none()) throw(GenericError() << "unrecognized client type, implementation incomplete");
1108 return result;
1109}
1110
1112{
1113 auto tables = m_tables.find(wantedType);
1114 if((tables==m_tables.end() || !tables->second.size()) && m_convertWhenMissing)
1115 {
1116 switch(wantedType)
1117 {
1126 default:;
1127 }
1128 }
1129 return wantedType;
1130}
1131
1132unsigned Database::getXmlLineNumber(const char* pos) const
1133{
1134 if(!pos || !m_xmlBuffer.size() || !m_lineOffset.size()) return 0;
1135 if(pos < m_xmlBuffer.data()) return 0;
1136 unsigned offset = pos - m_xmlBuffer.data();
1137 if(offset >= m_xmlBuffer.size()) return 0;
1138 return std::upper_bound(m_lineOffset.begin(), m_lineOffset.end(), offset) - m_lineOffset.begin();
1139}
1140
1142{
1144 switch(type)
1145 {
1146 case ELECTRON_REAL_EFFICIENCY: return "real efficiency (electrons)";
1147 case ELECTRON_FAKE_EFFICIENCY: return "fake efficiency (electrons)";
1148 case ELECTRON_FAKE_FACTOR: return "fake factor (electrons)";
1149 case MUON_REAL_EFFICIENCY: return "real efficiency (muons)";
1150 case MUON_FAKE_EFFICIENCY: return "fake efficiency (muons)";
1151 case MUON_FAKE_FACTOR: return "fake factor (muons)";
1152 case TAU_REAL_EFFICIENCY: return "real efficiency (taus)";
1153 case TAU_FAKE_EFFICIENCY: return "fake efficiency (taus)";
1154 case TAU_FAKE_FACTOR: return "fake factor (taus)";
1155 case PHOTON_ELE_FAKE_FACTOR: return "fake rate (electrons->photons)";
1156 case PHOTON_ELE_FAKE_FACTOR_SF: return "fake rate SF(electrons->photons)";
1157 default:;
1158 }
1159 return "???";
1160}
1161
1162std::string Database::StringRef::trim() const
1163{
1164 if(!ptr) return "";
1165 auto beg=ptr, end=endptr-1;
1166 while(std::isspace(*beg) && beg<end) ++beg;
1167 while(std::isspace(*end) && end>beg) --end;
1168 return std::string(beg, end+1);
1169}
const boost::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)
#define y
#define x
#define z
constexpr int pow(int base, int exp) noexcept
std::string m_xmlBuffer
Temporary buffers (only used while importing data)
Definition Database.h:254
void importDefaultROOT(std::string filename)
Definition Database.cxx:742
float getNormalizationFactor(const TH1 *hist, EfficiencyType type, const StringRef &norm, const StringRef &xmlStream)
Definition Database.cxx:830
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:845
void addValues(const StringRef &contents, EfficiencyTable &table, EfficiencyType type, StatMode statMode, unsigned short &globalStatUID)
Definition Database.cxx:581
float getWeightedAverage(const TH1 *hist, const StringRef &xmlStream)
Definition Database.cxx:803
void readNextTag(StringRef &stream, StringRef &tag, AttributesMap &attributes, StringRef &contents)
Definition Database.cxx:235
std::vector< std::string > getListOfNames(const StringRef &stream)
Definition Database.cxx:319
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
unsigned getXmlLineNumber(const char *pos) const
std::vector< Param > m_params
Permanent buffers.
Definition Database.h:248
bool retrieveParameterValue(const xAOD::IParticle &p, const xAOD::EventInfo &eventInfo, const Param &param, EfficiencyTable::BoundType &val) const
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:500
void importXML(std::string filename)
Definition Database.cxx:186
void importSystTH1(const TH1 *hist, EfficiencyType type, const std::string &sysname)
Definition Database.cxx:925
void addTables(const StringRef &particleType, const AttributesMap &attributes, const StringRef &contents, TFile *source=nullptr)
Definition Database.cxx:420
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:258
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:409
void addSysts(const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
Definition Database.cxx:377
void dropXmlComments(std::string &buffer)
Methods used to parse XML files.
Definition Database.cxx:289
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:352
bool fillEfficiencies(ParticleData &pd, const xAOD::IParticle &p, const xAOD::EventInfo &eventInfo, std::string &error) const
Definition Database.cxx:65
Database(Client client, bool useGeV, bool convertWhenMissing)
Definition Database.cxx:26
void addParams(const StringRef &tag, const StringRef &contents, AttributesMap &attributes)
Definition Database.cxx:360
void addDimension(EfficiencyTable &table, unsigned paramUID, const StringRef &contents)
Definition Database.cxx:511
std::vector< std::size_t > m_lineOffset
Definition Database.h:255
void dropRootTag(std::string &buffer)
Definition Database.cxx:305
void resetAttributes(AttributesMap &attributes)
Definition Database.cxx:708
void importCustomROOT(const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
Definition Database.cxx:681
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.
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
setWord1 uint16_t
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