6#include "CaloGeoHelpers/CaloSampling.h"
23#define MSGSOURCE "EgEfficiencyCorr_dumpNPs"
29 std::string
str(
const bool abs_eta=
false)
const;
49 "AsgElectronEfficiencyCorrectionTool/tool"};
58using map_t = std::map<NP, std::vector<std::size_t>>;
66 const map_t::mapped_type& affected_bins,
67 Domain& bounds,
bool& abs_eta,
bool& holes);
72 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.1f,
73 1.15f, 1.2f, 1.3f, 1.37f, 1.52f, 1.6f, 1.65f, 1.7f, 1.8f, 1.9f, 2.0f,
74 2.1f, 2.2f, 2.3f, 2.37f, 2.4f, 2.47f};
77 45e2f, 7e3f, 1e4f, 15e3f, 2e4f, 25e3f, 3e4f, 35e3f, 4e4f, 45e3f, 5e4f,
78 6e4f, 8e4f, 15e4f, 25e4f, 5e5f, 1e7f};
85int main(
int argc,
char* argv[])
87 using namespace asg::msgUserCode;
89 #ifdef XAOD_STANDALONE
90 StatusCode::enableFailure();
101 const bool duplicates_eta{
103 const bool duplicates_pt{
105 if (duplicates_eta || duplicates_pt) {
106 Error(
MSGSOURCE,
"Duplicated values in the specified bin edges.");
118 std::set<std::string> recorded;
119 for (
const auto& var : allsysts) {
120 std::string name(var.basename());
121 if (!recorded.emplace(name).second)
continue;
123 if (name.find(
"UncorrUncertainty") != std::string::npos) {
125 }
else if (name.find(
"CorrUncertainty") != std::string::npos) {
128 throw std::invalid_argument(
"");
130 np.index = std::stoul(name.substr(name.find(
"NP") + 2));
133 }
catch (std::invalid_argument&) {
134 Error(
MSGSOURCE,
"The pattern of the SystematicVariation names seems to have changed.");
137 std::sort(cfg.systematics.begin(), cfg.systematics.end(),
138 [](
auto&
x,
auto&
y) { return std::get<NP>(x) < std::get<NP>(y); });
140 if (cfg.analysis_mode) {
141 for (
const int year : {2015, 2016, 2017, 2018}) {
146 Info(
MSGSOURCE,
"Relevant nuisance parameters for the year %i:", year);
161 using namespace asg::msgUserCode;
164 Info(
MSGSOURCE,
"Usage (1): EgEfficiencyCorr_dumpNPs Year=<value> IdKey=<value> <property1=value1> ... <property N=value N>");
165 Info(
MSGSOURCE,
" ++ prints eta x pt region of influence of each nuisance parameter for the chosen year");
166 Info(
MSGSOURCE,
"Usage (2): EgEfficiencyCorr_dumpNPs AnalysisEta=<list> AnalysisPt=<list> IdKey=<value> <property1=value1> ... <property N=value N>");
167 Info(
MSGSOURCE,
" ++ prints a short list of all NPs relevant in the selected eta x pt (in MeV) region");
168 Info(
MSGSOURCE,
" ++ e.g. EgEfficiencyCorr_dumpNPs AnalysisEta=-2.0..2.0,nocrack AnalysisPt=20e3..150e3");
169 Info(
MSGSOURCE,
" ++ one of the Analysis* arguments can be omitted, in which case the full range is scanned");
170 Info(
MSGSOURCE,
" ++ several intervals can be specified, separated by commas, e.g. AnalysisEta=0..0.6,0.8..1.37");
171 Info(
MSGSOURCE,
" ++ recognized aliases: 'nocrack' (crack veto), 'sym' (duplicates for eta<0), 'barrel', 'endcap'");
173 Info(
MSGSOURCE,
" ++ for other SFs, IdKey can be replaced by RecoKey/IsoKey/TriggerKey");
174 Info(
MSGSOURCE,
" ++ CorrectionFileNameList can also be used instead of keys");
175 Info(
MSGSOURCE,
" ++ optional arguments are other configurable properties of the AsgElectronEfficiencyCorrectionTool.");
176 Info(
MSGSOURCE,
" ++ e.g. EgEfficiencyCorr_dumpNPs Year=2015 IdKey=Tight CorrelationModel=SIMPLIFIED UncorrEtaBinsUser=0,1.37,2.47");
180 if (argc < 2)
help();
182 const std::set<std::string> string_properties{
183 "MapFilePath",
"RecoKey",
"IdKey",
"IsoKey",
"TriggerKey",
185 const std::set<std::string> int_properties{
"ForceDataType"};
186 const std::set<std::string> vector_properties{
187 "UncorrEtaBinsUser",
"UncorrEtBinsUser"};
196 std::vector<int8_t> eta_flags(
eta_edges.size()-1, 0);
197 std::vector<int8_t> pt_flags(
pt_edges.size()-1, 0);
199 for (
int i=1; i<argc; ++i) {
200 std::string key{argv[i]};
201 const std::size_t pos{key.find(
'=')};
202 if (pos == std::string::npos)
help();
203 std::string val(key.substr(pos + 1));
205 if (!key.length() || !val.length())
help();
206 if (key ==
"CorrectionFileNameList") {
207 std::vector<std::string>
files{val};
209 }
else if (key ==
"Year") {
211 }
else if (string_properties.count(key)) {
213 }
else if (int_properties.count(key)) {
215 }
else if (vector_properties.count(key)) {
216 std::vector<float>
bins;
219 }
else if (key ==
"AnalysisEta") {
222 }
else if (key ==
"AnalysisPt") {
226 Error(
MSGSOURCE,
"Unrecognized property %s", key.c_str());
234 "When Analysis* arguments are provided, "
238 Error(
MSGSOURCE,
"Command-line arguments must include Year");
243 for (std::size_t i{0}; i<eta_flags.size(); ++i) {
244 if (eta_flags[i] != 2)
continue;
247 const auto j =
static_cast<std::size_t
>(
248 std::upper_bound(eeb, eee, -
z) - eeb - 1);
249 if (i == j)
continue;
251 eta_flags[i] = eta_flags[j];
255 auto efb{eta_flags.begin()}, efe{eta_flags.end()};
256 if (!std::count(efb, efe, 1)) {
257 std::replace(efb, efe, 0, 1);
259 auto pfb{pt_flags.begin()}, pfe{pt_flags.end()};
260 if (!std::count(pfb, pfe, 1)) {
261 std::fill(pfb, pfe, 1);
265 for (std::size_t i{0}; i<eta_flags.size(); ++i) {
266 if (eta_flags[i] < 1)
continue;
267 for (std::size_t j{0}; j<pt_flags.size(); ++j) {
268 if (pt_flags[j] < 1)
continue;
281 using namespace asg::msgUserCode;
283 static int display_count{-1};
284 if (!++display_count) {
286 "Scanning the eta/pt plane, this will take a bit of time...");
292 const auto *asgtool =
dynamic_cast<RealTool*
>(&*cfg.tool);
294 const std::size_t dmax{cfg.domains.size()};
295 for (std::size_t d{0}; d<dmax; ++d) {
296 const auto& dom = cfg.domains[d];
297 std::bitset<1024> zero_uncorr{}, nonzero_uncorr{}, expected_uncorr{};
298 std::bitset<256> zero_corr{}, nonzero_corr{};
299 bool multi_np{
false};
300 for (std::size_t j{1}; j<jmax; ++j) {
301 const float eta{((jmax-j)*dom.etamin + j*dom.etamax) / jmax};
302 for (std::size_t k{1}; k<kmax; ++k) {
303 const float pt{((kmax-k)*dom.ptmin + k*dom.ptmax) / kmax};
306 ANA_CHECK( store.retrieve(electrons,
"MyElectrons") );
308 double sf_nom{}, sf{};
309 ANA_CHECK( cfg.tool->applySystematicVariation({}) );
310 ANA_CHECK( cfg.tool->getEfficiencyScaleFactor(electron, sf_nom) );
311 int vi{asgtool->systUncorrVariationIndex(electron)};
312 expected_uncorr.set(vi);
313 unsigned n_nonzero_uncorr{0};
314 for (
const auto& s : cfg.systematics) {
315 const auto& sys = std::get<CP::SystematicSet>(s);
316 ANA_CHECK( cfg.tool->applySystematicVariation(sys) );
317 ANA_CHECK( cfg.tool->getEfficiencyScaleFactor(electron, sf) );
318 const double delta{sf - sf_nom};
319 const NP np{std::get<NP>(s)};
322 nonzero_uncorr.set(np.index);
325 else nonzero_corr.set(np.index);
327 if (np.uncorr) zero_uncorr.set(np.index);
328 else zero_corr.set(np.index);
331 multi_np = multi_np || (n_nonzero_uncorr > 1);
336 std::string w(
"several uncorrelated NPs seem to affect the bin at "
339 }
else if (nonzero_uncorr.count() > 1) {
340 std::string w{
"the binning used for the scan is unadapted at " +
341 dom.str() +
" (too coarse?)."};
344 if ((zero_uncorr & nonzero_uncorr).any() ||
345 (zero_corr & nonzero_corr).any()) {
346 std::string w(
"the binning used for the scan is unadapted at " +
347 dom.str() +
" (wrong boundaries?).");
350 if ((nonzero_uncorr!=expected_uncorr) && nonzero_uncorr.any()) {
352 for (std::size_t i{0}; i<nonzero_uncorr.size(); ++i) {
353 std::string
x{std::to_string(i) +
','};
354 if (nonzero_uncorr[i] && !expected_uncorr[i]) snz +=
x;
355 if (!nonzero_uncorr[i] && expected_uncorr[i]) se +=
x;
357 if (snz.length()) snz.pop_back();
358 if (se.length()) se.pop_back();
359 std::string w{
"systUncorrVariationIndex() at " + dom.str() +
360 " indicates different NP(s) than those found in the scan, "
362 Warning(
MSGSOURCE, w.c_str(), se.c_str(), snz.c_str());
364 for (
const auto& s : cfg.systematics) {
365 const NP np{std::get<NP>(s)};
367 np.uncorr? nonzero_uncorr.test(np.index)
368 : nonzero_corr.test(np.index)};
369 if (impact) affected_bins[np].emplace_back(d);
378 using namespace asg::msgUserCode;
379 for (
const auto& s : cfg.systematics) {
380 const NP np{std::get<NP>(s)};
381 const std::string name(std::get<CP::SystematicSet>(s).begin()->
basename());
383 bool valid{
false}, holes{
false}, abs_eta{
false};
384 auto itr = affected_bins.find(np);
385 if (itr != affected_bins.end()) {
389 Warning(
MSGSOURCE,
"%s seems to not affect any bin", name.c_str());
392 std::string txt(name +
" --> ");
393 if (holes) txt +=
"subdomain of ";
394 txt += bounds.
str(abs_eta) +
'.';
407 using namespace asg::msgUserCode;
409 std::vector<std::pair<std::string, int>> summary;
410 NP prev{-888,
false};
411 for (
const auto& kv : affected_bins) {
412 const auto&
bins{kv.second};
413 if (
bins.empty())
continue;
414 const NP np{kv.first};
415 const bool next{prev.
uncorr==np.uncorr && np.index==prev.
index+1};
417 if (!summary.empty() && next) {
418 std::get<int>(summary.back()) = np.index;
422 std::get<CP::SystematicSet>(
424 cfg.systematics.cbegin(), cfg.systematics.cend(),
425 [=](
auto&
x){ return std::get<NP>(x) == np; }))};
426 summary.emplace_back(sys.begin()->basename(), -1);
428 for (
const auto&
x: summary) {
429 std::string s(
" ++ " + std::get<std::string>(
x));
430 const int i{std::get<int>(
x)};
431 if (i >= 0) s +=
" to " + std::to_string(i);
439 const map_t::mapped_type& affected_bins,
444 if (affected_bins.empty())
return false;
445 constexpr float inf{std::numeric_limits<float>::max()};
446 constexpr float inf_{std::numeric_limits<float>::lowest()};
448 auto update = [&](
const int side,
const auto& dom,
449 const float etamin,
const float etamax) {
451 b.etamin = std::min(b.etamin, etamin);
452 b.etamax = std::max(b.etamax, etamax);
453 b.ptmin = std::min(b.ptmin, dom.ptmin);
454 b.ptmax = std::max(b.ptmax, dom.ptmax);
457 for (
const int bin : affected_bins) {
464 const int ac{2*(bAC[1].
ptmin!=
inf) + (bAC[0].ptmin!=
inf)};
467 (std::fabs(bAC[0].etamax + bAC[1].etamin) < 1e-4f) &&
468 (std::fabs(bAC[0].etamin + bAC[1].etamax) < 1e-4f);
475 bounds.
ptmin = std::min(bAC[0].ptmin, bAC[1].ptmin);
478 }
else if (ac) bounds = bAC[ac - 1];
483 const std::size_t
imax{cfg.domains.size()};
484 auto f = [=](
const float x) {
return abs_eta? std::fabs(
x) :
x; };
485 for (std::size_t i{0}; i<
imax && !holes; ++i) {
486 if (std::count(affected_bins.cbegin(), affected_bins.cend(), i))
continue;
487 const auto& dom{cfg.domains[i]};
488 holes = (dom.ptmax > bounds.
ptmin) &&
489 (dom.ptmin < bounds.
ptmax) &&
490 (f(dom.etamax) > bounds.
etamin) &&
491 (f(dom.etamin) < bounds.
etamax);
501 const char*
eta{abs_eta?
"|eta|" :
"eta"};
504 s << 1e-3f *
ptmin <<
" < pt < "
505 << 1e-3f *
ptmax <<
" GeV";
507 s <<
"pt > " << 1e-3f *
ptmin <<
" GeV";
521 std::vector<int8_t>& flags,
522 const std::vector<float>& edges)
524 const bool accept_aliases{&edges == &
eta_edges};
525 if (flags.size() != edges.size() - 1)
return false;
527 if (s ==
"nocrack") alias = 1;
528 else if (s ==
"barrel") alias = 2;
529 else if (s ==
"endcap") alias = 3;
530 else if (s ==
"sym") alias = 4;
531 if (!accept_aliases && alias>0)
return false;
532 if (alias>=1 && alias<=3) {
533 for (std::size_t i{0}; i<edges.size()-1; ++i) {
534 const float eta{std::fabs(edges[i])};
535 if (alias==1 &&
eta>=1.37f &&
eta<1.52f) flags[i] = -1;
536 if (alias==2 &&
eta<1.37f) flags[i] = 1;
537 if (alias==3 &&
eta>1.52f) flags[i] = 1;
540 }
else if (alias == 4) {
541 for (std::size_t i=0;i<edges.size();++i) {
542 if (edges[i] < 0) flags[i] = 2;
546 auto pos = s.find(
"..");
547 if (pos == std::string::npos)
return false;
548 std::stringstream
ss{s.replace(pos, 2, 1,
' ')};
551 if (
ss.fail() || !(
ss >> std::ws).eof())
return false;
552 for (std::size_t i{0}; i<edges.size()-1; ++i) {
553 if (
xmin<edges[i+1] &&
xmax>edges[i] && flags[i]>=0) {
561template<
typename...
Args>
564 std::replace(val.begin(), val.end(),
',',
' ');
565 std::stringstream
ss{val};
567 std::conditional_t<(
sizeof...(Args)<2),
float, std::string>
x;
569 if (
ss.fail())
break;
578 using namespace asg::msgUserCode;
579 constexpr int random_runs[] = {280423, 302737, 332720, 354826};
581 case 2015:
case 2016:
case 2017:
case 2018:
582 return random_runs[year - 2015];
585 "Invalid year specified, it should be between 2015 and 2018.");
Scalar eta() const
pseudorapidity method
StatusCode getElectrons(const std::vector< std::pair< double, double > > &pt_eta, int runNumber, xAOD::TStore &store)
static const std::vector< std::string > bins
static void enableFailure() noexcept
Class to wrap a set of SystematicVariations.
Tool for accessing xAOD files outside of Athena.
@ kClassAccess
Access auxiliary data using the aux containers.
A relatively simple transient store for objects created in analysis.
const std::size_t subdiv_pt
bool displayFindings(const Config &config, const map_t &affected_bins)
bool scanPhaseSpace(Config &config, map_t &affected_bins)
bool parse_csv_token(const float x, std::vector< float > &bins)
int get_run_number(const int year)
std::vector< float > pt_edges
std::vector< float > eta_edges
bool find_boundaries(const Config &cfg, const map_t::mapped_type &affected_bins, Domain &bounds, bool &abs_eta, bool &holes)
std::map< NP, std::vector< std::size_t > > map_t
bool displayFindings_analysis(const Config &cfg, const map_t &affected_bins)
const std::size_t subdiv_eta
bool parse_csv_list(std::string val, Args &... args)
std::vector< std::string > files
file names and file pointers
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
StatusCode Init(const char *appname)
Function initialising ROOT/PyROOT for using the ATLAS EDM.
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
Electron_v1 Electron
Definition of the current "egamma version".
std::vector< std::tuple< CP::SystematicSet, NP > > systematics
bool initialize(int argc, char *argv[])
std::vector< Domain > domains
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > tool
std::string str(const bool abs_eta=false) const
bool operator<(const NP &rhs) const
bool operator==(const NP &rhs) const
std::string basename(std::string name)