6 #include "boost/lexical_cast.hpp"
7 #include "boost/format.hpp"
8 #include "boost/multi_array.hpp"
10 #include "TGraphErrors.h"
11 #include "RooFitResult.h"
12 #include "RooRealVar.h"
13 #include "RooDataHist.h"
14 #include "RooProduct.h"
15 #include "RooConstVar.h"
29 for (
auto const& bin : cb.
bin_set()) {
32 std::cout <<
">> Processing " << bin <<
"," << proc <<
"\n";
34 if (process_vs_norm_postfix_map.find(proc) == process_vs_norm_postfix_map.end())
36 norm_postfix_ =
"norm";
40 norm_postfix_ = process_vs_norm_postfix_map[proc];
42 RunSingleProc(cb, ws, bin, proc);
44 TH1F data_hist = cb.
cp().
bin({bin}).GetObservedShape();
45 if (rebin_) data_hist =
RebinHist(data_hist);
48 RooRealVar *xvar = ws.var(TString::Format(
"CMS_x_%s", bin.c_str()));
49 RooDataHist rdh_dat(TString::Format(
"%s_data_obs", bin.c_str()),
"",
50 RooArgList(*xvar), &data_hist);
65 void CMSHistFuncFactory::RunSingleProc(
CombineHarvester& cb, RooWorkspace& ws,
66 std::string bin, std::string
process) {
70 using boost::lexical_cast;
71 using boost::multi_array;
74 TString key = bin +
"_" +
process;
80 unsigned m = m_str_vec.size();
82 if (m_str_vec.size() == 1) {
84 std::sort(m_str_vec.begin(), m_str_vec.end(),
85 [](
string const& s1,
string const& s2) {
86 return lexical_cast<double>(s1) < lexical_cast<double>(s2);
88 for (
auto const& s : m_str_vec) {
89 if (v_) std::cout <<
">>>> Mass point: " << s <<
"\n";
90 m_vec.push_back(lexical_cast<double>(s));
96 vector<string> ss_vec =
99 for (
auto const& s : m_str_vec) {
102 throw std::runtime_error(
FNERROR(
103 "Some mass points do not have the full set of shape systematics, "
104 "this is currently unsupported"));
107 unsigned ss = ss_vec.size();
109 vector<string> ls_vec =
111 unsigned ls = ls_vec.size();
114 multi_array<ch::Process *, 1> pr_arr(extents[m]);
117 multi_array<ch::Systematic *, 2> ss_arr(extents[ss][m]);
123 multi_array<double, 1> ss_scale_arr(extents[ss]);
126 multi_array<bool, 1> ss_must_scale_arr(extents[ss]);
130 multi_array<ch::Systematic *, 2> ls_arr(extents[ls][m]);
134 multi_array<std::shared_ptr<RooRealVar>, 1> ss_scale_var_arr(extents[ss]);
137 multi_array<std::shared_ptr<RooConstVar>, 1> ss_scale_fac_arr(extents[ss]);
141 multi_array<std::shared_ptr<RooProduct>, 1> ss_scale_prod_arr(extents[ss]);
144 for (
unsigned mi = 0; mi < m; ++mi) {
149 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
151 cbp.
cp().
mass({m_str_vec[mi]}).syst_name({ss_vec[ssi]})
156 for (
unsigned lsi = 0; lsi < ls; ++lsi) {
158 cbp.
cp().
mass({m_str_vec[mi]}).syst_name({ls_vec[lsi]})
170 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
174 ss_scale_var_arr[ssi] =
175 std::make_shared<RooRealVar>(ss_vec[ssi].c_str(),
"", 0);
182 for (
unsigned mi = 0; mi < m; ++mi) {
183 scales.insert(ss_arr[ssi][mi]->scale());
185 if (scales.size() > 1) {
188 "Shape morphing parameters that vary with mass are not allowed"));
191 ss_scale_arr[ssi] = *(scales.begin());
193 if (std::fabs(ss_scale_arr[ssi] - 1.0) > 1E-6) {
194 ss_must_scale_arr[ssi] =
true;
196 ss_scale_fac_arr[ssi] = std::make_shared<RooConstVar>(
197 TString::Format(
"%g", ss_scale_arr[ssi]),
"",
201 ss_scale_prod_arr[ssi] = std::make_shared<RooProduct>(
202 ss_vec[ssi] +
"_scaled_" + key,
"",
203 RooArgList(*(ss_scale_var_arr[ssi]), *(ss_scale_fac_arr[ssi])));
205 ss_list.add(*(ss_scale_prod_arr[ssi]));
209 ss_list.add(*(ss_scale_var_arr[ssi]));
216 std::cout <<
">> Shape systematics: " << ss <<
"\n";
217 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
218 std::cout << boost::format(
"%-50s %-5i %-8.3g\n")
219 % ss_vec[ssi] % ss_must_scale_arr[ssi] % ss_scale_arr[ssi];
232 vector<string> lms_vec;
235 vector<unsigned > lms_vec_idx;
236 for (
unsigned lsi = 0; lsi < ls; ++lsi) {
244 for (
unsigned mi = 0; mi < m; ++mi) {
245 Systematic *n = ls_arr[lsi][mi];
246 k_hi.insert(n->value_u());
248 k_lo.insert(n->value_d());
252 if (k_hi.size() > 1 || k_lo.size() > 1) {
253 lms_vec.push_back(ls_vec[lsi]);
254 lms_set.insert(ls_vec[lsi]);
255 lms_vec_idx.push_back(lsi);
258 unsigned lms = lms_vec.size();
260 multi_array<ch::Systematic *, 2> lms_arr(extents[lms][m]);
261 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
262 for (
unsigned mi = 0; mi < m; ++mi) {
263 lms_arr[lmsi][mi] = ls_arr[lms_vec_idx[lmsi]][mi];
268 multi_array<std::shared_ptr<RooRealVar>, 1> lms_var_arr(extents[lms]);
269 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
271 std::make_shared<RooRealVar>(lms_vec[lmsi].c_str(),
"", 0);
276 std::cout <<
">> lnN morphing systematics: " << lms <<
"\n";
277 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
278 std::cout <<
">>>> " << lms_vec[lmsi] <<
"\n";
284 multi_array<std::shared_ptr<TH1F>, 2> hist_arr(extents[m][1+ss*2]);
287 multi_array<double, 1> rate_arr(extents[m]);
290 multi_array<double, 1> rate_unc_arr(extents[m]);
292 multi_array<std::shared_ptr<TList>, 1> list_arr(extents[m]);
297 multi_array<double, 2> ss_k_hi_arr(extents[ss][m]);
298 multi_array<double, 2> ss_k_lo_arr(extents[ss][m]);
301 multi_array<std::shared_ptr<RooAbsReal>, 1> ss_spl_hi_arr(extents[ss]);
302 multi_array<std::shared_ptr<RooAbsReal>, 1> ss_spl_lo_arr(extents[ss]);
305 multi_array<std::shared_ptr<AsymPow>, 1> ss_asy_arr(extents[ss]);
308 multi_array<double, 2> lms_k_hi_arr(extents[lms][m]);
309 multi_array<double, 2> lms_k_lo_arr(extents[lms][m]);
310 multi_array<std::shared_ptr<RooSpline1D>, 1> lms_spl_hi_arr(extents[lms]);
311 multi_array<std::shared_ptr<RooSpline1D>, 1> lms_spl_lo_arr(extents[lms]);
312 multi_array<std::shared_ptr<AsymPow>, 1> lms_asy_arr(extents[lms]);
314 for (
unsigned mi = 0; mi < m; ++mi) {
320 std::make_shared<TH1F>(AsTH1F(pr_arr[mi]->ClonedScaledShape().get()));
321 if (rebin_) *hist_arr[mi][0] =
RebinHist(*hist_arr[mi][0]);
323 for (
int b = 1; b < hist_arr[mi][0]->GetNbinsX() + 1; ++b) {
324 hist_arr[mi][0]->SetBinError(b, 0.);
337 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
338 hist_arr[mi][1 + 2 * ssi] =
339 std::make_shared<TH1F>(AsTH1F(ss_arr[ssi][mi]->shape_u()));
340 hist_arr[mi][2 + 2 * ssi] =
341 std::make_shared<TH1F>(AsTH1F(ss_arr[ssi][mi]->shape_d()));
342 if (rebin_) *hist_arr[mi][1 + 2 * ssi] =
RebinHist(*hist_arr[mi][1 + 2 * ssi]);
343 if (rebin_) *hist_arr[mi][2 + 2 * ssi] =
RebinHist(*hist_arr[mi][2 + 2 * ssi]);
344 TH1F* h_hi = hist_arr[mi][1 + 2 * ssi].get();
345 TH1F* h_lo = hist_arr[mi][2 + 2 * ssi].get();
346 if (h_hi->Integral() > 0.) {
347 h_hi->Scale(hist_arr[mi][0]->Integral() / h_hi->Integral());
349 if (h_lo->Integral() > 0.) {
350 h_lo->Scale(hist_arr[mi][0]->Integral() / h_lo->Integral());
362 ss_k_hi_arr[ssi][mi] = ss_arr[ssi][mi]->value_u();
363 ss_k_lo_arr[ssi][mi] = ss_arr[ssi][mi]->value_d();
366 if (std::fabs(ss_scale_arr[ssi] - 1.0) > 1E-6) {
367 ss_k_hi_arr[ssi][mi] = std::pow(ss_arr[ssi][mi]->value_u(), ss_scale_arr[ssi]);
368 ss_k_lo_arr[ssi][mi] = std::pow(ss_arr[ssi][mi]->value_d(), ss_scale_arr[ssi]);
373 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
374 lms_k_hi_arr[lmsi][mi] = lms_arr[lmsi][mi]->value_u();
375 if (lms_arr[lmsi][mi]->asymm()) {
376 lms_k_lo_arr[lmsi][mi] = lms_arr[lmsi][mi]->value_d();
378 lms_k_lo_arr[lmsi][mi] = 1. / lms_arr[lmsi][mi]->value_u();
397 for (
unsigned mi = 0; mi < m; ++mi) {
398 std::cout << boost::format(
"%-10s") % m_str_vec[mi];
401 for (
unsigned mi = 0; mi < m; ++mi) {
402 std::cout << boost::format(
"%-10.5g") % rate_arr[mi];
405 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
406 std::cout << ss_vec[ssi] <<
" Up" << std::endl;
407 for (
unsigned mi = 0; mi < m; ++mi) {
408 std::cout << boost::format(
"%-10.5g") % ss_k_hi_arr[ssi][mi];
411 std::cout << ss_vec[ssi] <<
" Down" << std::endl;
412 for (
unsigned mi = 0; mi < m; ++mi) {
413 std::cout << boost::format(
"%-10.5g") % ss_k_lo_arr[ssi][mi];
417 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
418 std::cout << lms_vec[lmsi] <<
" Up" << std::endl;
419 for (
unsigned mi = 0; mi < m; ++mi) {
420 std::cout << boost::format(
"%-10.5g") % lms_k_hi_arr[lmsi][mi];
423 std::cout << lms_vec[lmsi] <<
" Down" << std::endl;
424 for (
unsigned mi = 0; mi < m; ++mi) {
425 std::cout << boost::format(
"%-10.5g") % lms_k_lo_arr[lmsi][mi];
433 TString interp =
"LINEAR";
439 vector<double> new_m_vec(m_vec);
443 new_m_vec.insert(new_m_vec.begin(),m_vec[0]-1E-6);
444 new_m_vec.push_back(m_vec[m-1]+1E-6);
447 multi_array<double, 1> new_rate_arr(extents[m+2]);
448 new_rate_arr[0] = 0.0;
452 for(
unsigned i = 0; i < m; ++i) new_rate_arr[i+1] = 1.0;
453 new_rate_arr[m+1] = 0.0;
455 bool force_template_limit =
false;
470 std::shared_ptr<RooSpline1D> rate_spline;
471 if (m > 1) rate_spline = std::make_shared<RooSpline1D>(
"interp_rate_"+key,
"", *mass_var[process],
472 force_template_limit ? m+2 : m,
473 force_template_limit ? new_m_vec.data() : m_vec.data(),
474 force_template_limit ? new_rate_arr.data() : rate_arr.data(),
482 RooArgList rate_prod;
484 rate_prod.add(*rate_spline);
487 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
489 ss_spl_hi_arr[ssi] = std::make_shared<RooSpline1D>(
"spline_hi_" +
490 key +
"_" + ss_vec[ssi],
"", *mass_var[process], m, m_vec.data(),
491 ss_k_hi_arr[ssi].origin(), interp);
492 ss_spl_lo_arr[ssi] = std::make_shared<RooSpline1D>(
"spline_lo_" +
493 key +
"_" + ss_vec[ssi],
"", *mass_var[process], m, m_vec.data(),
494 ss_k_lo_arr[ssi].origin(), interp);
496 ss_spl_hi_arr[ssi] = std::make_shared<RooConstVar>(TString::Format(
"%g", ss_k_hi_arr[ssi][0]),
"", ss_k_hi_arr[ssi][0]);
497 ss_spl_lo_arr[ssi] = std::make_shared<RooConstVar>(TString::Format(
"%g", ss_k_lo_arr[ssi][0]),
"", ss_k_lo_arr[ssi][0]);
499 ss_asy_arr[ssi] = std::make_shared<AsymPow>(
"systeff_" +
500 key +
"_" + ss_vec[ssi],
"",
501 *(ss_spl_lo_arr[ssi]), *(ss_spl_hi_arr[ssi]),
502 *(ss_scale_var_arr[ssi]));
511 rate_prod.add(*(ss_asy_arr[ssi]));
515 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
516 lms_spl_hi_arr[lmsi] = std::make_shared<RooSpline1D>(
"spline_hi_" +
517 key +
"_" + lms_vec[lmsi],
"", *mass_var[process], m, m_vec.data(),
518 lms_k_hi_arr[lmsi].origin(), interp);
519 lms_spl_lo_arr[lmsi] = std::make_shared<RooSpline1D>(
"spline_lo_" +
520 key +
"_" + lms_vec[lmsi],
"", *mass_var[process], m, m_vec.data(),
521 lms_k_lo_arr[lmsi].origin(), interp);
522 lms_asy_arr[lmsi] = std::make_shared<AsymPow>(
"systeff_" +
523 key +
"_" + lms_vec[lmsi],
"", *(lms_spl_lo_arr[lmsi]),
524 *(lms_spl_hi_arr[lmsi]), *(lms_var_arr[lmsi]));
525 rate_prod.add(*(lms_asy_arr[lmsi]));
541 TString xvar_name = TString::Format(
"CMS_x_%s", bin.c_str());
542 RooRealVar xvar = VarFromHist(xvar_name, xvar_name, data_hist);
563 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
564 if (ss_scale_arr[ssi] < qrange) qrange = ss_scale_arr[ssi];
568 TString morph_name = key +
"_morph";
578 CMSHistFunc morph_func(morph_name,
"", xvar, *hist_arr[0][0]);
579 morph_func.setVerticalSmoothRegion(qrange);
580 morph_func.setHorizontalType(CMSHistFunc::HorizontalType::Integral);
581 morph_func.setVerticalMorphs(ss_list);
583 morph_func.addHorizontalMorph(*mass_var[process], TVectorD(m, m_vec.data()));
585 morph_func.prepareStorage();
587 for (
unsigned mi = 0; mi < m; ++mi) {
588 morph_func.setShape(0, mi, 0, 0, *hist_arr[mi][0]);
589 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
590 morph_func.setShape(0, mi, ssi + 1, 0, *hist_arr[mi][2 + 2 * ssi]);
591 morph_func.setShape(0, mi, ssi + 1, 1, *hist_arr[mi][1 + 2 * ssi]);
600 RooProduct morph_rate(morph_name +
"_" + TString(norm_postfix_),
"",
608 ws.import(morph_func, RooFit::RecycleConflictNodes());
609 if (rate_prod.getSize() > 0) {
610 ws.import(morph_rate, RooFit::RecycleConflictNodes());
612 std::cout <<
"No normalisation term to import!\n";
621 std::string mass_min = m_str_vec.at(0);
625 return p->
bin() == bin && p->
process() == process && p->
mass() != mass_min;
632 return (n->
bin() == bin && n->
process() == process) &&
633 ((n->
mass() != mass_min) || (n->
type() ==
"shape" || n->
type() ==
"shapeU") ||
634 (lms_set.count(n->
name())));
640 if (p->
bin() == bin && p->
process() == process) {
651 if (n->
bin() == bin && n->
process() == process) {
void Run(CombineHarvester &cb, RooWorkspace &ws, std::map< std::string, std::string > process_vs_norm_postfix_map)
CombineHarvester & mass(std::vector< std::string > const &vec, bool cond=true)
void ForEachSyst(Function func)
void ForEachProc(Function func)
std::set< std::string > process_set()
std::set< R > SetFromProcs(T func)
Fill an std::set using only the Process entries.
CombineHarvester & bin(std::vector< std::string > const &vec, bool cond=true)
std::set< std::string > bin_set()
CombineHarvester & FilterSysts(Function func)
CombineHarvester & FilterProcs(Function func)
std::set< std::string > syst_name_set()
CombineHarvester cp()
Creates and returns a shallow copy of the CombineHarvester instance.
CombineHarvester & syst_type(std::vector< std::string > const &vec, bool cond=true)
virtual std::string const & process() const
virtual std::string const & bin() const
virtual std::string const & mass() const
void set_rate(double const &rate)
void set_shape(std::unique_ptr< TH1 > shape, bool set_rate)
void set_rate(double const &rate)
void set_shape(std::unique_ptr< TH1 > shape, bool set_rate)
std::string const & type() const
std::string const & name() const
TH1F RebinHist(TH1F const &hist)
std::vector< T > Set2Vec(std::set< T > const &in)