ATLAS Offline Software
Loading...
Searching...
No Matches
FakeBkgTools::Database Class Reference

#include <Database.h>

Collaboration diagram for FakeBkgTools::Database:

Classes

struct  EfficiencyTable
struct  GenericError
 This propagates an error message. More...
struct  Param
struct  StatDef
 could try to keep track of the bin number, for the description More...
struct  StringRef
 Note: the following structure is used (instead of a simple std::string) so that XML line numbers can be printed in the error message, which requires keeping track of the position of the string in the original file. More...
struct  SystDef
struct  XmlError
 This propagates an error message + the reference to the faulty piece of XML when an exception is raised. More...

Public Types

enum  EfficiencyType {
  ELECTRON_REAL_EFFICIENCY = 0 , ELECTRON_FAKE_EFFICIENCY , ELECTRON_FAKE_FACTOR , MUON_REAL_EFFICIENCY ,
  MUON_FAKE_EFFICIENCY , MUON_FAKE_FACTOR , TAU_REAL_EFFICIENCY , TAU_FAKE_EFFICIENCY ,
  TAU_FAKE_FACTOR , PHOTON_ELE_FAKE_FACTOR , PHOTON_ELE_FAKE_FACTOR_SF , N_EFFICIENCY_TYPES
}
enum class  InputType { CENTRAL_VALUE , CORRECTION }
enum class  StatMode { GLOBAL , PER_BIN , NONE , UNSPECIFIED }

Public Member Functions

 Database (Client client, bool useGeV, bool convertWhenMissing)
void importXML (std::string filename)
void importDefaultROOT (std::string filename)
bool ready () const
void reset ()
bool needEventInfo () const
bool fillEfficiencies (ParticleData &pd, const xAOD::IParticle &p, const xAOD::EventInfo &eventInfo, std::string &error) const
unsigned getXmlLineNumber (const char *pos) const
unsigned numberOfStats () const
unsigned numberOfSysts () const
const SystDeffindSyst (unsigned short uid) const
const StatDeffindStat (unsigned short uid) const

Static Public Member Functions

static constexpr unsigned short indexFromUID (unsigned short uid)
static constexpr unsigned short systIndexToUID (unsigned short index)
static constexpr unsigned short statIndexToUID (unsigned short index)
static constexpr bool isSystUID (unsigned short uid)
static constexpr bool isStatUID (unsigned short uid)

Protected Types

using AttributesMap = std::map<std::string, StringRef>

Protected Member Functions

void dropXmlComments (std::string &buffer)
 Methods used to parse XML files.
void dropRootTag (std::string &buffer)
void readNextTag (StringRef &stream, StringRef &tag, AttributesMap &attributes, StringRef &contents)
void readTagAttributes (StringRef stream, const std::string &tag, AttributesMap &attributes)
void resetAttributes (AttributesMap &attributes)
void importCustomROOT (const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
void addParams (const StringRef &tag, const StringRef &contents, AttributesMap &attributes)
void addSysts (const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
unsigned short addStat (EfficiencyType type, const StringRef &pos=StringRef())
void addTables (const StringRef &particleType, const AttributesMap &attributes, const StringRef &contents, TFile *source=nullptr)
void addDimension (EfficiencyTable &table, unsigned paramUID, const StringRef &contents)
void addValues (const StringRef &contents, EfficiencyTable &table, EfficiencyType type, StatMode statMode, unsigned short &globalStatUID)
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.
void importSystTH1 (const TH1 *hist, EfficiencyType type, const std::string &sysname)
float getWeightedAverage (const TH1 *hist, const StringRef &xmlStream)
float getNormalizationFactor (const TH1 *hist, EfficiencyType type, const StringRef &norm, const StringRef &xmlStream)
bool retrieveParameterValue (const xAOD::IParticle &p, const xAOD::EventInfo &eventInfo, const Param &param, EfficiencyTable::BoundType &val) const
EfficiencyType getSourceType (EfficiencyType wantedType) const
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
std::vector< std::string > getListOfNames (const StringRef &stream)

Static Protected Member Functions

static FakeBkgTools::EfficiencyselectEfficiency (FakeBkgTools::ParticleData &pd, const xAOD::IParticle &p, EfficiencyType type)
 Methods used to fill efficiencies.
template<typename ReturnValue, typename... Args>
static ReturnValue getAttribute (const StringRef &tag, const AttributesMap &attributes, const std::string &type, const char *ref, ReturnValue rv, Args... args)
 Helper methods.
static void assertNoLeftover (std::stringstream &ss, const StringRef &pos)
static constexpr unsigned short maxIndex ()
static std::string getTypeAsString (EfficiencyType type)
static std::bitset< N_EFFICIENCY_TYPESselectTypesToFill (Client client)
 This function is only called by the Database constructor.

Protected Attributes

const bool m_useGeV
const std::bitset< N_EFFICIENCY_TYPESm_typesToFill
const bool m_convertWhenMissing
bool m_storeAllUncertainties = true
std::vector< Paramm_params
 Permanent buffers.
std::vector< SystDefm_systs
std::vector< StatDefm_stats
std::map< int, std::vector< EfficiencyTable > > m_tables
std::string m_xmlBuffer
 Temporary buffers (only used while importing data)
std::vector< std::size_t > m_lineOffset
std::map< std::string, float > m_normFactors

Static Private Member Functions

template<typename ReturnValue>
static ReturnValue getAttribute (const StringRef &attr, const char *ref, ReturnValue rv)
 don't call these methods directly, use getAttribute(AttributesMap, string, ...) instead
template<typename ReturnValue, typename... Args>
static ReturnValue getAttribute (const StringRef &attr, const char *ref, ReturnValue rv, Args... args)

Detailed Description

Definition at line 28 of file Database.h.

Member Typedef Documentation

◆ AttributesMap

using FakeBkgTools::Database::AttributesMap = std::map<std::string, StringRef>
protected

Definition at line 175 of file Database.h.

Member Enumeration Documentation

◆ EfficiencyType

Enumerator
ELECTRON_REAL_EFFICIENCY 
ELECTRON_FAKE_EFFICIENCY 
ELECTRON_FAKE_FACTOR 
MUON_REAL_EFFICIENCY 
MUON_FAKE_EFFICIENCY 
MUON_FAKE_FACTOR 
TAU_REAL_EFFICIENCY 
TAU_FAKE_EFFICIENCY 
TAU_FAKE_FACTOR 
PHOTON_ELE_FAKE_FACTOR 
PHOTON_ELE_FAKE_FACTOR_SF 
N_EFFICIENCY_TYPES 

Definition at line 42 of file Database.h.

◆ InputType

Enumerator
CENTRAL_VALUE 
CORRECTION 

Definition at line 58 of file Database.h.

59 {
60 CENTRAL_VALUE, CORRECTION
61 };

◆ StatMode

Enumerator
GLOBAL 
PER_BIN 
NONE 
UNSPECIFIED 

Definition at line 62 of file Database.h.

63 {
64 GLOBAL, PER_BIN, NONE, UNSPECIFIED
65 };

Constructor & Destructor Documentation

◆ Database()

Database::Database ( Client client,
bool useGeV,
bool convertWhenMissing )

Definition at line 26 of file Database.cxx.

26 :
27 m_useGeV(useGeV),
29 m_convertWhenMissing(convertWhenMissing)
30{
31 reset();
32}
const std::bitset< N_EFFICIENCY_TYPES > m_typesToFill
Definition Database.h:242
static std::bitset< N_EFFICIENCY_TYPES > selectTypesToFill(Client client)
This function is only called by the Database constructor.
const bool m_convertWhenMissing
Definition Database.h:244

Member Function Documentation

◆ addDimension()

void Database::addDimension ( EfficiencyTable & table,
unsigned paramUID,
const StringRef & contents )
protected

Also accept a simpler syntax for integers (e.g. nJets = "2")

the stream might have consumed the leading '-' in its failed attempt to read a number, so recover it

Definition at line 511 of file Database.cxx.

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}
static Double_t ss
#define x
#define min(a, b)
Definition cfImp.cxx:40
std::vector< Param > m_params
Permanent buffers.
Definition Database.h:248
static void assertNoLeftover(std::stringstream &ss, const StringRef &pos)
Definition Database.cxx:500
void contents(std::vector< std::string > &keys, TDirectory *td, const std::string &directory, const std::string &pattern, const std::string &path)
setRawEt setRawPhi int
This propagates an error message + the reference to the faulty piece of XML when an exception is rais...
Definition Database.h:124

◆ addParams()

void Database::addParams ( const StringRef & tag,
const StringRef & contents,
AttributesMap & attributes )
protected

Definition at line 360 of file Database.cxx.

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}
std::vector< std::string > getListOfNames(const StringRef &stream)
Definition Database.cxx:319
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

◆ addStat()

unsigned short Database::addStat ( EfficiencyType type,
const StringRef & pos = StringRef() )
protected

Definition at line 409 of file Database.cxx.

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}
static constexpr unsigned short statIndexToUID(unsigned short index)
Definition Database.h:221
std::vector< StatDef > m_stats
Definition Database.h:250
static constexpr unsigned short maxIndex()
Definition Database.h:209
This propagates an error message.
Definition Database.h:136

◆ addSysts()

void Database::addSysts ( const StringRef & tag,
const StringRef & contents,
const AttributesMap & attributes )
protected

Definition at line 377 of file Database.cxx.

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}
static Double_t a
std::vector< SystDef > m_systs
Definition Database.h:249

◆ addTables()

void Database::addTables ( const StringRef & particleType,
const AttributesMap & attributes,
const StringRef & contents,
TFile * source = nullptr )
protected

using the StringRef as map key ensures that dimensions will be listed in the same order as they were written

Definition at line 420 of file Database.cxx.

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",
431 "global", StatMode::GLOBAL, "per-bin", StatMode::PER_BIN, "none", StatMode::NONE) : StatMode::UNSPECIFIED;
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 {
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}
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
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::map< std::string, float > m_normFactors
Definition Database.h:256
std::map< int, std::vector< EfficiencyTable > > m_tables
Definition Database.h:251
void addDimension(EfficiencyTable &table, unsigned paramUID, const StringRef &contents)
Definition Database.cxx:511
void resetAttributes(AttributesMap &attributes)
Definition Database.cxx:708
std::string label(const std::string &format, int i)
Definition label.h:19
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Note: the following structure is used (instead of a simple std::string) so that XML line numbers can ...
Definition Database.h:96

◆ addValues()

void Database::addValues ( const StringRef & contents,
EfficiencyTable & table,
EfficiencyType type,
StatMode statMode,
unsigned short & globalStatUID )
protected

Definition at line 581 of file Database.cxx.

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 {
613 FakeBkgTools::Uncertainty uncval;
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();
665 uid = systIndexToUID(index);
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}
static constexpr unsigned short systIndexToUID(unsigned short index)
Definition Database.h:220
unsigned short addStat(EfficiencyType type, const StringRef &pos=StringRef())
Definition Database.cxx:409
str index
Definition DeMoScan.py:362
void * ptr(T *p)
Definition SGImplSvc.cxx:74
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.
setWord1 uint16_t

◆ assertNoLeftover()

void Database::assertNoLeftover ( std::stringstream & ss,
const StringRef & pos )
inlinestaticprotected

Definition at line 500 of file Database.cxx.

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}

◆ dropRootTag()

void Database::dropRootTag ( std::string & buffer)
protected

Definition at line 305 of file Database.cxx.

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}

◆ dropXmlComments()

void Database::dropXmlComments ( std::string & buffer)
protected

Methods used to parse XML files.

Definition at line 289 of file Database.cxx.

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}
double length(const pvec &v)
std::vector< std::size_t > m_lineOffset
Definition Database.h:255

◆ fillEfficiencies()

bool Database::fillEfficiencies ( ParticleData & pd,
const xAOD::IParticle & p,
const xAOD::EventInfo & eventInfo,
std::string & error ) const

Loop over all the type of efficiencies (real, fake, fake factor) that were requested to be filled

pointer to the proper member of ParticleData that needs to be filled

The efficiency tables to look for might be for a different type (if a Fake efficiency <--> Fake factor conversion is needed)

Loop over all the tables found for that type of efficiency

an error occurred

this table contained the central values

only a single table should be providing central values (the other tables might provide corrections)

Transform the fake efficiency into fake factor (or reciprocally)

Definition at line 65 of file Database.cxx.

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}
constexpr int pow(int base, int exp) noexcept
static FakeBkgTools::Efficiency * selectEfficiency(FakeBkgTools::ParticleData &pd, const xAOD::IParticle &p, EfficiencyType type)
Methods used to fill efficiencies.
EfficiencyType getSourceType(EfficiencyType wantedType) const
static std::string getTypeAsString(EfficiencyType type)
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
status
Definition merge.py:16

◆ findStat()

const StatDef * FakeBkgTools::Database::findStat ( unsigned short uid) const
inline

Definition at line 232 of file Database.h.

233 {
234 if(!isStatUID(uid)) return nullptr;
235 unsigned index = indexFromUID(uid);
236 return (index<m_stats.size())? &m_stats[index] : nullptr;
237 }
static constexpr unsigned short indexFromUID(unsigned short uid)
Definition Database.h:219
static constexpr bool isStatUID(unsigned short uid)
Definition Database.h:223

◆ findSyst()

const SystDef * FakeBkgTools::Database::findSyst ( unsigned short uid) const
inline

Definition at line 226 of file Database.h.

227 {
228 if(!isSystUID(uid)) return nullptr;
229 unsigned index = indexFromUID(uid);
230 return (index<m_systs.size())? &m_systs[index] : nullptr;
231 }
static constexpr bool isSystUID(unsigned short uid)
Definition Database.h:222

◆ getAttribute() [1/3]

template<typename ReturnValue>
ReturnValue Database::getAttribute ( const StringRef & attr,
const char * ref,
ReturnValue rv )
inlinestaticprivate

don't call these methods directly, use getAttribute(AttributesMap, string, ...) instead

Definition at line 338 of file Database.cxx.

339{
340 if(attr.str() == ref) return rv;
341 throw(XmlError(attr) << "unsupported parameter type \"" << attr.str() << "\"");
342}
const boost::regex ref(r_ef)

◆ getAttribute() [2/3]

template<typename ReturnValue, typename... Args>
ReturnValue Database::getAttribute ( const StringRef & attr,
const char * ref,
ReturnValue rv,
Args... args )
inlinestaticprivate

Definition at line 345 of file Database.cxx.

346{
347 if(attr.str() == ref) return rv;
348 return getAttribute(attr, args...);
349}

◆ getAttribute() [3/3]

template<typename ReturnValue, typename... Args>
ReturnValue Database::getAttribute ( const StringRef & tag,
const AttributesMap & attributes,
const std::string & type,
const char * ref,
ReturnValue rv,
Args... args )
inlinestaticprotected

Helper methods.

Definition at line 352 of file Database.cxx.

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}

◆ getListOfNames()

std::vector< std::string > Database::getListOfNames ( const StringRef & stream)
protected

Definition at line 319 of file Database.cxx.

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}

◆ getNormalizationFactor()

float Database::getNormalizationFactor ( const TH1 * hist,
EfficiencyType type,
const StringRef & norm,
const StringRef & xmlStream )
protected

Should be called only when processing XMLs

in principle the denominator has been checked not to be 0

Definition at line 830 of file Database.cxx.

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}

◆ getSourceType()

Database::EfficiencyType Database::getSourceType ( EfficiencyType wantedType) const
protected

Definition at line 1111 of file Database.cxx.

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}

◆ getTypeAsString()

std::string Database::getTypeAsString ( EfficiencyType type)
staticprotected

This function is only meant to be used to display meaningful error messages

Definition at line 1141 of file Database.cxx.

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}

◆ getWeightedAverage()

float Database::getWeightedAverage ( const TH1 * hist,
const StringRef & xmlStream )
protected

compute weighted average of all bins

central value of the correction will be 1, but uncertainties may matter, so this is also a valid case

Definition at line 803 of file Database.cxx.

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}
avg(a, b)
Definition Recovery.py:79

◆ getXmlLineNumber()

unsigned Database::getXmlLineNumber ( const char * pos) const

Definition at line 1132 of file Database.cxx.

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}
std::string m_xmlBuffer
Temporary buffers (only used while importing data)
Definition Database.h:254

◆ importCustomROOT()

void Database::importCustomROOT ( const StringRef & tag,
const StringRef & contents,
const AttributesMap & attributes )
protected

Definition at line 681 of file Database.cxx.

682{
683 std::string filename = attributes.at("ROOT/source").str();
684 if(!filename.length()) throw(XmlError(rootTag) << "the 'file' attribute must be specified!");
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}
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
void addTables(const StringRef &particleType, const AttributesMap &attributes, const StringRef &contents, TFile *source=nullptr)
Definition Database.cxx:420
TFile * file

◆ importDefaultROOT()

void Database::importDefaultROOT ( std::string filename)

step 0 = central value + stats step 1 = systs

Efficiency type

Definition at line 742 of file Database.cxx.

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
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}
void importSystTH1(const TH1 *hist, EfficiencyType type, const std::string &sysname)
Definition Database.cxx:925

◆ importNominalTH1()

void Database::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 )
protected

Methods used to load from ROOT files.

Parameters and ranges

Copy, and include under/overflow into first/last bin:

Efficiencies + stat uncertainties

Definition at line 845 of file Database.cxx.

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}
#define y
#define z
double xmax
Definition listroot.cxx:61
double ymax
Definition listroot.cxx:64

◆ importSystTH1()

void Database::importSystTH1 ( const TH1 * hist,
EfficiencyType type,
const std::string & sysname )
protected

Definition at line 925 of file Database.cxx.

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}

◆ importXML()

void Database::importXML ( std::string filename)

not guaranteed that the above works, so truncating the buffer to a reasonable size if seemingly too large

Definition at line 186 of file Database.cxx.

187{
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
218 resetAttributes(attributes);
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}
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
void addParams(const StringRef &tag, const StringRef &contents, AttributesMap &attributes)
Definition Database.cxx:360
void dropRootTag(std::string &buffer)
Definition Database.cxx:305
void importCustomROOT(const StringRef &tag, const StringRef &contents, const AttributesMap &attributes)
Definition Database.cxx:681

◆ indexFromUID()

constexpr unsigned short FakeBkgTools::Database::indexFromUID ( unsigned short uid)
inlinestaticconstexpr

Definition at line 219 of file Database.h.

219{ return uid&0x3FFF; }

◆ isStatUID()

constexpr bool FakeBkgTools::Database::isStatUID ( unsigned short uid)
inlinestaticconstexpr

Definition at line 223 of file Database.h.

223{ return ((uid&0xC000) == 0x8000); }

◆ isSystUID()

constexpr bool FakeBkgTools::Database::isSystUID ( unsigned short uid)
inlinestaticconstexpr

Definition at line 222 of file Database.h.

222{ return ((uid&0xC000) == 0x4000); }

◆ maxIndex()

constexpr unsigned short FakeBkgTools::Database::maxIndex ( )
inlinestaticconstexprprotected

Definition at line 209 of file Database.h.

209{ return 0x4000; }

◆ needEventInfo()

bool Database::needEventInfo ( ) const

will no longer work if some event-level parameteres are predefined

Definition at line 56 of file Database.cxx.

57{
58 for(auto& param : m_params)
59 {
60 if(param.level == Param::Level::EVENT) return true;
61 }
62 return false;
63}

◆ numberOfStats()

unsigned FakeBkgTools::Database::numberOfStats ( ) const
inline

Definition at line 224 of file Database.h.

224{ return m_stats.size(); }

◆ numberOfSysts()

unsigned FakeBkgTools::Database::numberOfSysts ( ) const
inline

Definition at line 225 of file Database.h.

225{ return m_systs.size(); }

◆ readEfficiencyFromTable()

int 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
protected

Check if the particle falls in one bin of this table

if not, return

Yes! So read the central value / correction / uncertainties

=> tool will return weight + all uncertainties at once

Definition at line 130 of file Database.cxx.

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}
bool retrieveParameterValue(const xAOD::IParticle &p, const xAOD::EventInfo &eventInfo, const Param &param, EfficiencyTable::BoundType &val) const
bool first
Definition DeMoScan.py:534

◆ readNextTag()

void Database::readNextTag ( StringRef & stream,
StringRef & tag,
AttributesMap & attributes,
StringRef & contents )
protected

Note: when modifying the pattern, make sure to also change readTagAttributes() if required!

Perhaps here do some looser pattern-matching to figure out where the format was not good: missing quotation marks? missing attribute value? no closing tag?

Definition at line 235 of file Database.cxx.

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}
void readTagAttributes(StringRef stream, const std::string &tag, AttributesMap &attributes)
Definition Database.cxx:258

◆ readTagAttributes()

void Database::readTagAttributes ( StringRef stream,
const std::string & tag,
AttributesMap & attributes )
protected

Definition at line 258 of file Database.cxx.

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}

◆ ready()

bool Database::ready ( ) const

Could do some more careful check here; for the moment just check that there's at least one table

Definition at line 46 of file Database.cxx.

47{
49 for(auto& kv : m_tables)
50 {
51 if(kv.second.size()) return true;
52 }
53 return false;
54}

◆ reset()

void Database::reset ( )

Definition at line 34 of file Database.cxx.

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}

◆ resetAttributes()

void Database::resetAttributes ( AttributesMap & attributes)
protected

for now only a TH1 attribute

NB. the list of attributes allowed for bin or table tags can be further extended by new param tags. This is done inside addParams().

Definition at line 708 of file Database.cxx.

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}

◆ retrieveParameterValue()

bool Database::retrieveParameterValue ( const xAOD::IParticle & p,
const xAOD::EventInfo & eventInfo,
const Param & param,
EfficiencyTable::BoundType & val ) const
protected

Definition at line 1012 of file Database.cxx.

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) {
1030 SG::ConstAccessor<float> acc(param.name);
1031 val.as_float = acc(p);
1032 }
1033 else if(param.type == Param::Type::CUSTOM_INT) {
1034 SG::ConstAccessor<int> acc(param.name);
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) {
1042 SG::ConstAccessor<float> acc(param.name);
1043 val.as_float = acc(eventInfo);
1044 }
1045 else if(param.type == Param::Type::CUSTOM_INT) {
1046 SG::ConstAccessor<int> acc(param.name);
1047 val.as_int = acc(eventInfo);
1048 }
1049 else return false;
1050 }
1051 else return false;
1052 return true;
1053}
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.

◆ selectEfficiency()

Efficiency * Database::selectEfficiency ( FakeBkgTools::ParticleData & pd,
const xAOD::IParticle & p,
EfficiencyType type )
staticprotected

Methods used to fill efficiencies.

Definition at line 1055 of file Database.cxx.

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}
@ 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

◆ selectTypesToFill()

auto Database::selectTypesToFill ( Client client)
staticprotected

This function is only called by the Database constructor.

Definition at line 1084 of file Database.cxx.

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}

◆ statIndexToUID()

constexpr unsigned short FakeBkgTools::Database::statIndexToUID ( unsigned short index)
inlinestaticconstexpr

Definition at line 221 of file Database.h.

221{ return 0x8000 | index; }

◆ systIndexToUID()

constexpr unsigned short FakeBkgTools::Database::systIndexToUID ( unsigned short index)
inlinestaticconstexpr

Definition at line 220 of file Database.h.

220{ return 0x4000 | index; }

Member Data Documentation

◆ m_convertWhenMissing

const bool FakeBkgTools::Database::m_convertWhenMissing
protected

Definition at line 244 of file Database.h.

◆ m_lineOffset

std::vector<std::size_t> FakeBkgTools::Database::m_lineOffset
protected

Definition at line 255 of file Database.h.

◆ m_normFactors

std::map<std::string, float> FakeBkgTools::Database::m_normFactors
protected

Definition at line 256 of file Database.h.

◆ m_params

std::vector<Param> FakeBkgTools::Database::m_params
protected

Permanent buffers.

Definition at line 248 of file Database.h.

◆ m_stats

std::vector<StatDef> FakeBkgTools::Database::m_stats
protected

Definition at line 250 of file Database.h.

◆ m_storeAllUncertainties

bool FakeBkgTools::Database::m_storeAllUncertainties = true
protected

Definition at line 245 of file Database.h.

◆ m_systs

std::vector<SystDef> FakeBkgTools::Database::m_systs
protected

Definition at line 249 of file Database.h.

◆ m_tables

std::map<int, std::vector<EfficiencyTable> > FakeBkgTools::Database::m_tables
protected

Definition at line 251 of file Database.h.

◆ m_typesToFill

const std::bitset<N_EFFICIENCY_TYPES> FakeBkgTools::Database::m_typesToFill
protected

Definition at line 242 of file Database.h.

◆ m_useGeV

const bool FakeBkgTools::Database::m_useGeV
protected

Definition at line 241 of file Database.h.

◆ m_xmlBuffer

std::string FakeBkgTools::Database::m_xmlBuffer
protected

Temporary buffers (only used while importing data)

Definition at line 254 of file Database.h.


The documentation for this class was generated from the following files: