36 bool w2 =
true,
double total_events = 0)
39 total{total_events} {}
42 void fill (
double val,
double weight = 1.0);
49 const Hist&
fetch_unc (
const std::string& key,
const std::string& direction)
const;
59 void scale (
const double lumi,
const double xs);
70 TH1D*
roothist (
bool allunc =
true)
const;
87 double min_w_unc (
const bool includezeros =
true)
const;
103 double get_unc (
unsigned bin,
bool allunc =
true)
const;
104 void doscale (
const double scale);
105 void doscale (
const double lumi,
const double xs);
109 template<
typename F>
void doall (
const F& func);
111 using Envelope = std::tuple<Hist, Hist, std::list<Hist>>;
120 std::list<TH1D> histstore;
125 unsigned bin {std::min(
nbins + 1, static_cast<unsigned>(std::ceil(((val -
min) *
nbins/(
max -
min)))))};
127 std::cerr << bin <<
" " << val <<
" " <<
nbins <<
" " <<
min <<
" " <<
max << std::endl;
128 throw std::runtime_error{
"bin too big"};
132 sumw2[bin] += std::pow(weight, 2);
143 auto& mysys = std::get<2>(
envs[sys]);
145 return mysys.front();
156 std::cerr <<
"Num bins other: " << other.
nbins <<
" me: " <<
nbins << std::endl;
157 throw std::runtime_error{
"Hists don't have same number of bins"};
161 for (
unsigned ibin = 0; ibin <
contents.size(); ++ibin) {
168 for (
auto& unc :
uncs)
169 unc.second.add(other.
uncs.at(unc.first));
176 throw std::logic_error{
"Trying to add one histogram with envelope set to another one without"};
178 std::get<0>(
env.second).
add(std::get<0>(other.
envs.at(
env.first)));
179 std::get<1>(
env.second).
add(std::get<1>(other.
envs.at(
env.first)));
183 const auto& otherenv = std::get<2>(other.
envs.at(
env.first));
184 auto& meenv = std::get<2>(
env.second);
185 if (otherenv.size() != meenv.size()) {
186 std::cerr <<
"Num envs other: " << otherenv.size() <<
" me: " << meenv.size() << std::endl;
187 throw std::runtime_error{
"Hists don't have same number of envelope histograms"};
190 auto iother = otherenv.cbegin();
191 for (
auto& me : meenv) {
203 for (
unsigned ibin = 0; ibin <
contents.size(); ++ibin) {
206 sumw2[ibin] *= std::pow(scale, 2);
219 for (
auto& unc :
uncs)
224 for (
auto& hist : std::get<2>(
env.second))
227 func(std::get<0>(
env.second));
228 func(std::get<1>(
env.second));
235 doall([scale] (
auto& hist) { hist.doscale(scale); });
240 doall([lumi, xs] (
auto& hist) { hist.doscale(lumi, xs); });
245 static unsigned plot = 0;
246 auto title = std::string(
";") +
label +
";Events";
248 histstore.emplace_back(std::to_string(plot++).data(),
title.data(),
static_cast<int>(
nbins),
min,
max);
249 auto& hist = histstore.back();
250 for (
unsigned ibin = 0; ibin <
contents.size(); ++ibin) {
251 hist.SetBinContent(ibin,
contents[ibin]);
252 hist.SetBinError(ibin,
get_unc(ibin, allunc));
254 Debug::Debug(__PRETTY_FUNCTION__,
"hist with", hist.Integral());
262 for (
unsigned ibin = 1; ibin <=
nbins; ++ibin) {
268 return std::make_pair(maxbin, std::max(
nbins, 1u));
274 for (
unsigned ibin = 1; ibin <=
nbins; ++ibin)
281 double output = std::numeric_limits<double>::max();
282 for (
unsigned ibin = 1; ibin <=
nbins; ++ibin) {
286 return std::max(output, 0.0);
294 auto change = [&other] (
Hist& tochange) {
295 for (
unsigned ibin = 0; ibin < other.
contents.size(); ++ibin) {
296 auto bincontent = other.
contents.at(ibin);
298 tochange.contents[ibin] /= other.
contents.at(ibin);
299 if (tochange.sumw2.size())
300 tochange.sumw2[ibin] /= std::pow(other.
contents.at(ibin), 2);
303 tochange.contents[ibin] = 1.0;
304 if (tochange.sumw2.size())
305 tochange.sumw2[ibin] = 0;
310 output.doall(change);
312 Debug::Debug(__PRETTY_FUNCTION__,
"output", output.nbins, output.min, output.max);
319 throw std::logic_error{
"Attempted to set total value for histogram twice. Probably a bug."};
328 for (
auto& unc :
uncs)
329 w2 += std::pow(
contents.at(bin) - unc.second.contents.at(bin), 2)/2;
339 return std::sqrt(w2);
354 auto& hmax = std::get<1>(
env.second) = hmin;
356 auto& envs_list = std::get<2>(
env.second);
357 for (
auto& part : envs_list) {
358 for (
unsigned ibin = 0; ibin !=
contents.size(); ++ibin) {
359 hmin.contents[ibin] = std::min(hmin.contents[ibin], part.contents[ibin]);
360 hmax.contents[ibin] = std::max(hmax.contents[ibin], part.contents[ibin]);
369 if (direction !=
"Up" and direction !=
"Down")
370 throw std::logic_error{
"Direction must be 'Up' or 'Down'."};
374 if (direction ==
"Up")
375 return std::get<1>(
envs.at(key));
376 return std::get<0>(
envs.at(key));
379 return uncs.at(key + direction);
385 for (
auto& unc :
uncs)
386 output.insert({unc.first, unc.second.roothist(
false)});
389 for (
const std::string&
dir : {
"Up",
"Down"})
390 output.insert({env.first + dir, fetch_unc(env.first, dir).roothist(false)});