6 #include "boost/lexical_cast.hpp"
7 #include "boost/format.hpp"
8 #include "boost/multi_array.hpp"
9 #include "TGraphErrors.h"
10 #include "RooFitResult.h"
11 #include "RooRealVar.h"
12 #include "RooDataHist.h"
13 #include "RooProduct.h"
14 #include "RooConstVar.h"
21 std::string
const& bin, std::string
const&
process,
22 RooAbsReal& mass_var, std::string norm_postfix,
23 bool allow_morph,
bool verbose,
bool force_template_limit, TFile * file) {
29 using boost::lexical_cast;
30 using boost::multi_array;
35 RooFit::MsgLevel backup_msg_level =
36 RooMsgService::instance().globalKillBelow();
37 if (!verbose) RooMsgService::instance().setGlobalKillBelow(RooFit::WARNING);
44 std::cout <<
">> Bin: " << bin <<
" Process: " <<
process <<
"\n";
46 TString key = bin +
"_" +
process;
61 std::sort(m_str_vec.begin(), m_str_vec.end(),
62 [](
string const& s1,
string const& s2) {
63 return lexical_cast<double>(s1) < lexical_cast<double>(s2);
68 for (
auto const& s : m_str_vec) {
69 if (verbose) std::cout <<
">>>> Mass point: " << s <<
"\n";
70 m_vec.push_back(lexical_cast<double>(s));
73 unsigned m = m_vec.size();
78 vector<string> ss_vec =
81 for (
auto const& s : m_str_vec) {
84 throw std::runtime_error(
FNERROR(
85 "Some mass points do not have the full set of shape systematics, "
86 "this is currently unsupported"));
90 unsigned ss = ss_vec.size();
95 vector<string> ls_vec =
97 unsigned ls = ls_vec.size();
105 multi_array<ch::Process *, 1> pr_arr(extents[m]);
108 multi_array<ch::Systematic *, 2> ss_arr(extents[ss][m]);
114 multi_array<double, 1> ss_scale_arr(extents[ss]);
117 multi_array<bool, 1> ss_must_scale_arr(extents[ss]);
121 multi_array<ch::Systematic *, 2> ls_arr(extents[ls][m]);
125 multi_array<std::shared_ptr<RooRealVar>, 1> ss_scale_var_arr(extents[ss]);
128 multi_array<std::shared_ptr<RooConstVar>, 1> ss_scale_fac_arr(extents[ss]);
132 multi_array<std::shared_ptr<RooProduct>, 1> ss_scale_prod_arr(extents[ss]);
136 for (
unsigned mi = 0; mi < m; ++mi) {
141 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
143 cb_bp.
cp().
mass({m_str_vec[mi]}).syst_name({ss_vec[ssi]})
148 for (
unsigned lsi = 0; lsi < ls; ++lsi) {
150 cb_bp.
cp().
mass({m_str_vec[mi]}).syst_name({ls_vec[lsi]})
162 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
166 ss_scale_var_arr[ssi] =
167 std::make_shared<RooRealVar>(ss_vec[ssi].c_str(),
"", 0);
174 for (
unsigned mi = 0; mi < m; ++mi) {
175 scales.insert(ss_arr[ssi][mi]->scale());
177 if (scales.size() > 1) {
180 "Shape morphing parameters that vary with mass are not allowed"));
183 ss_scale_arr[ssi] = *(scales.begin());
185 if (std::fabs(ss_scale_arr[ssi] - 1.0) > 1E-6) {
186 ss_must_scale_arr[ssi] =
true;
188 ss_scale_fac_arr[ssi] = std::make_shared<RooConstVar>(
189 TString::Format(
"%g", ss_scale_arr[ssi]),
"",
193 ss_scale_prod_arr[ssi] = std::make_shared<RooProduct>(
194 ss_vec[ssi] +
"_scaled_" + key,
"",
195 RooArgList(*(ss_scale_var_arr[ssi]), *(ss_scale_fac_arr[ssi])));
197 ss_list.add(*(ss_scale_prod_arr[ssi]));
201 ss_list.add(*(ss_scale_var_arr[ssi]));
209 std::cout <<
">> Shape systematics: " << ss <<
"\n";
210 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
211 std::cout << boost::format(
"%-50s %-5i %-8.3g\n")
212 % ss_vec[ssi] % ss_must_scale_arr[ssi] % ss_scale_arr[ssi];
226 vector<string> lms_vec;
229 vector<unsigned > lms_vec_idx;
230 for (
unsigned lsi = 0; lsi < ls; ++lsi) {
238 for (
unsigned mi = 0; mi < m; ++mi) {
246 if (k_hi.size() > 1 || k_lo.size() > 1) {
247 lms_vec.push_back(ls_vec[lsi]);
248 lms_set.insert(ls_vec[lsi]);
249 lms_vec_idx.push_back(lsi);
252 unsigned lms = lms_vec.size();
254 multi_array<ch::Systematic *, 2> lms_arr(extents[lms][m]);
255 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
256 for (
unsigned mi = 0; mi < m; ++mi) {
257 lms_arr[lmsi][mi] = ls_arr[lms_vec_idx[lmsi]][mi];
262 multi_array<std::shared_ptr<RooRealVar>, 1> lms_var_arr(extents[lms]);
263 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
265 std::make_shared<RooRealVar>(lms_vec[lmsi].c_str(),
"", 0);
270 std::cout <<
">> lnN morphing systematics: " << lms <<
"\n";
271 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
272 std::cout <<
">>>> " << lms_vec[lmsi] <<
"\n";
280 multi_array<std::shared_ptr<TH1F>, 2> hist_arr(extents[m][1+ss*2]);
283 multi_array<double, 1> rate_arr(extents[m]);
286 multi_array<double, 1> rate_unc_arr(extents[m]);
288 multi_array<std::shared_ptr<TList>, 1> list_arr(extents[m]);
293 multi_array<double, 2> ss_k_hi_arr(extents[ss][m]);
294 multi_array<double, 2> ss_k_lo_arr(extents[ss][m]);
297 multi_array<std::shared_ptr<RooSpline1D>, 1> ss_spl_hi_arr(extents[ss]);
298 multi_array<std::shared_ptr<RooSpline1D>, 1> ss_spl_lo_arr(extents[ss]);
301 multi_array<std::shared_ptr<AsymPow>, 1> ss_asy_arr(extents[ss]);
304 multi_array<double, 2> lms_k_hi_arr(extents[lms][m]);
305 multi_array<double, 2> lms_k_lo_arr(extents[lms][m]);
306 multi_array<std::shared_ptr<RooSpline1D>, 1> lms_spl_hi_arr(extents[lms]);
307 multi_array<std::shared_ptr<RooSpline1D>, 1> lms_spl_lo_arr(extents[lms]);
308 multi_array<std::shared_ptr<AsymPow>, 1> lms_asy_arr(extents[lms]);
312 for (
unsigned mi = 0; mi < m; ++mi) {
322 file->WriteTObject(pr_arr[mi]->shape(), key +
"_" + m_str_vec[mi]);
325 rate_arr[mi] = pr_arr[mi]->rate();
326 auto proc_hist = pr_arr[mi]->ClonedScaledShape();
327 proc_hist->IntegralAndError(1, proc_hist->GetNbinsX(), rate_unc_arr[mi]);
329 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
330 hist_arr[mi][1 + 2 * ssi] =
332 hist_arr[mi][2 + 2 * ssi] =
335 file->WriteTObject(ss_arr[ssi][mi]->shape_u(),
336 key +
"_" + m_str_vec[mi] +
"_" + ss_vec[ssi] +
"Up");
337 file->WriteTObject(ss_arr[ssi][mi]->shape_d(),
338 key +
"_" + m_str_vec[mi] +
"_" + ss_vec[ssi] +
"Down");
341 ss_k_hi_arr[ssi][mi] = ss_arr[ssi][mi]->value_u();
342 ss_k_lo_arr[ssi][mi] = ss_arr[ssi][mi]->value_d();
345 if (std::fabs(ss_scale_arr[ssi] - 1.0) > 1E-6) {
346 ss_k_hi_arr[ssi][mi] = std::pow(ss_arr[ssi][mi]->value_u(), ss_scale_arr[ssi]);
347 ss_k_lo_arr[ssi][mi] = std::pow(ss_arr[ssi][mi]->value_d(), ss_scale_arr[ssi]);
352 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
353 lms_k_hi_arr[lmsi][mi] = lms_arr[lmsi][mi]->value_u();
354 if (lms_arr[lmsi][mi]->asymm()) {
355 lms_k_lo_arr[lmsi][mi] = lms_arr[lmsi][mi]->value_d();
357 lms_k_lo_arr[lmsi][mi] = 1. / lms_arr[lmsi][mi]->value_u();
364 for (
unsigned mi = 0; mi < m; ++mi) {
365 list_arr[mi] = std::make_shared<TList>();
366 for (
unsigned xi = 0; xi < (1 + ss * 2); ++xi) {
367 list_arr[mi]->Add(hist_arr[mi][xi].get());
374 for (
unsigned mi = 0; mi < m; ++mi) {
375 std::cout << boost::format(
"%-10s") % m_str_vec[mi];
378 for (
unsigned mi = 0; mi < m; ++mi) {
379 std::cout << boost::format(
"%-10.5g") % rate_arr[mi];
382 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
383 std::cout << ss_vec[ssi] <<
" Up" << std::endl;
384 for (
unsigned mi = 0; mi < m; ++mi) {
385 std::cout << boost::format(
"%-10.5g") % ss_k_hi_arr[ssi][mi];
388 std::cout << ss_vec[ssi] <<
" Down" << std::endl;
389 for (
unsigned mi = 0; mi < m; ++mi) {
390 std::cout << boost::format(
"%-10.5g") % ss_k_lo_arr[ssi][mi];
394 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
395 std::cout << lms_vec[lmsi] <<
" Up" << std::endl;
396 for (
unsigned mi = 0; mi < m; ++mi) {
397 std::cout << boost::format(
"%-10.5g") % lms_k_hi_arr[lmsi][mi];
400 std::cout << lms_vec[lmsi] <<
" Down" << std::endl;
401 for (
unsigned mi = 0; mi < m; ++mi) {
402 std::cout << boost::format(
"%-10.5g") % lms_k_lo_arr[lmsi][mi];
410 TString interp =
"LINEAR";
416 vector<double> new_m_vec(m_vec);
419 new_m_vec.insert(new_m_vec.begin(),m_vec[0]-1E-6);
420 new_m_vec.push_back(m_vec[m-1]+1E-6);
422 multi_array<double, 1> new_rate_arr(extents[m+2]);
423 new_rate_arr[0] = 0.0;
424 for(
unsigned i = 0; i < m; ++i) new_rate_arr[i+1] = rate_arr[i] ;
425 new_rate_arr[m+1] = 0.0;
427 if (verbose && force_template_limit) {
428 std::cout <<
">>>> Forcing rate to 0 outside of template range:" <<
"\n";
429 for(
unsigned mi = 0; mi < m+2; ++mi) {
430 std::cout << boost::format(
"%-10.5g") % new_m_vec[mi];
433 for(
unsigned mi = 0; mi < m+2; ++mi) {
434 std::cout << boost::format(
"%-10.5g") % new_rate_arr[mi];
440 RooSpline1D rate_spline(
"interp_rate_"+key,
"", mass_var,
441 force_template_limit ? m+2 : m,
442 force_template_limit ? new_m_vec.data() : m_vec.data(),
443 force_template_limit ? new_rate_arr.data() : rate_arr.data(),
448 TGraphErrors tmp(m, m_vec.data(), rate_arr.data(),
nullptr, rate_unc_arr.data());
449 file->WriteTObject(&tmp,
"interp_rate_"+key);
453 RooArgList rate_prod(rate_spline);
455 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
456 ss_spl_hi_arr[ssi] = std::make_shared<RooSpline1D>(
"spline_hi_" +
457 key +
"_" + ss_vec[ssi],
"", mass_var, m, m_vec.data(),
458 ss_k_hi_arr[ssi].origin(), interp);
459 ss_spl_lo_arr[ssi] = std::make_shared<RooSpline1D>(
"spline_lo_" +
460 key +
"_" + ss_vec[ssi],
"", mass_var, m, m_vec.data(),
461 ss_k_lo_arr[ssi].origin(), interp);
463 TGraph tmp_hi(m, m_vec.data(), ss_k_hi_arr[ssi].origin());
464 file->WriteTObject(&tmp_hi,
"spline_hi_" + key +
"_" + ss_vec[ssi]);
465 TGraph tmp_lo(m, m_vec.data(), ss_k_lo_arr[ssi].origin());
466 file->WriteTObject(&tmp_lo,
"spline_lo_" + key +
"_" + ss_vec[ssi]);
470 ss_asy_arr[ssi] = std::make_shared<AsymPow>(
"systeff_" +
471 key +
"_" + ss_vec[ssi],
"",
472 *(ss_spl_lo_arr[ssi]), *(ss_spl_hi_arr[ssi]),
473 *(ss_scale_var_arr[ssi]));
474 rate_prod.add(*(ss_asy_arr[ssi]));
478 for (
unsigned lmsi = 0; lmsi < lms; ++lmsi) {
479 lms_spl_hi_arr[lmsi] = std::make_shared<RooSpline1D>(
"spline_hi_" +
480 key +
"_" + lms_vec[lmsi],
"", mass_var, m, m_vec.data(),
481 lms_k_hi_arr[lmsi].origin(), interp);
482 lms_spl_lo_arr[lmsi] = std::make_shared<RooSpline1D>(
"spline_lo_" +
483 key +
"_" + lms_vec[lmsi],
"", mass_var, m, m_vec.data(),
484 lms_k_lo_arr[lmsi].origin(), interp);
485 lms_asy_arr[lmsi] = std::make_shared<AsymPow>(
"systeff_" +
486 key +
"_" + lms_vec[lmsi],
"", *(lms_spl_lo_arr[lmsi]),
487 *(lms_spl_hi_arr[lmsi]), *(lms_var_arr[lmsi]));
488 rate_prod.add(*(lms_asy_arr[lmsi]));
503 RooRealVar xvar(
"CMS_th1x",
"CMS_th1x", 0,
504 static_cast<float>(data_hist.GetNbinsX()));
505 xvar.setBins(data_hist.GetNbinsX());
509 RooRealVar morph_xvar((
"CMS_th1x_"+bin).c_str(),
"", 0,
510 static_cast<float>(proc_hist.GetNbinsX()));
513 morph_xvar.setConstant();
514 morph_xvar.setBins(proc_hist.GetNbinsX());
522 multi_array<std::shared_ptr<FastVerticalInterpHistPdf2>, 1> vpdf_arr(
524 RooArgList vpdf_list;
526 TString vert_name = key +
"_";
531 for (
unsigned ssi = 0; ssi < ss; ++ssi) {
532 if (ss_scale_arr[ssi] < qrange) qrange = ss_scale_arr[ssi];
535 for (
unsigned mi = 0; mi < m; ++mi) {
538 vpdf_arr[mi] = std::make_shared<FastVerticalInterpHistPdf2>(
539 vert_name + m_str_vec[mi] +
"_vmorph",
"", morph_xvar, *(list_arr[mi]),
542 vpdf_list.add(*(vpdf_arr[mi]));
544 TString morph_name = key +
"_morph";
554 RooMorphingPdf morph_pdf(morph_name,
"", xvar, mass_var, vpdf_list,
555 m_vec, allow_morph, *(data_hist.GetXaxis()),
556 *(proc_hist.GetXaxis()));
564 RooProduct morph_rate(morph_name +
"_" + TString(norm_postfix),
"",
572 ws.import(morph_pdf, RooFit::RecycleConflictNodes());
573 ws.import(morph_rate, RooFit::RecycleConflictNodes());
575 if (!verbose) RooMsgService::instance().setGlobalKillBelow(backup_msg_level);
581 std::string mass_min = m_str_vec.at(0);
593 ((n->
mass() != mass_min) || (n->
type() ==
"shape") ||
594 (lms_set.count(n->
name())));
602 p->set_shape(nullptr, false);
624 return std::string(morph_name);
628 std::vector<double>
const& masses, TFile* f, TH1 *ref_bins) {
629 RooRealVar *rrv =
dynamic_cast<RooRealVar*
>(mass);
632 f->mkdir(pdf->GetName());
633 gDirectory->cd(pdf->GetName());
634 for (
unsigned i = 0; i < masses.size(); ++i) {
635 rrv->setVal(masses[i]);
636 TH1 * h = pdf->createHistogram(
"CMS_th1x");
637 h->AddDirectory(
false);
640 h2 = (TH1*)ref_bins->Clone();
642 for (
int x = 1; x <= h2->GetNbinsX(); ++x) {
643 h2->SetBinContent(x, h->GetBinContent(x));
649 h2->AddDirectory(
false);
650 h2->SetName(TString::Format(
"actual_point_%g", masses[i]));
651 gDirectory->WriteTObject(h2);
655 double m = masses.front();
657 if (((masses.back() - masses.front()) / step) > 100.) step = step * 10.;
658 if (((masses.back() - masses.front()) / step) > 100.) step = step * 10.;
659 if (((masses.back() - masses.front()) / step) < 10.) step = step/10.;
660 while (m <= masses.back()) {
662 TH1* hm = pdf->createHistogram(
"CMS_th1x");
663 hm->AddDirectory(
false);
666 hm2 = (TH1*)ref_bins->Clone();
668 for (
int x = 1; x <= hm2->GetNbinsX(); ++x) {
669 hm2->SetBinContent(x, hm->GetBinContent(x));
675 hm2->AddDirectory(
false);
676 hm2->SetName(TString::Format(
"morph_point_%g", m));
678 if(fabs(m) < 1E-5) hm2->SetName(TString::Format(
"morph_point_0"));
679 gDirectory->WriteTObject(hm2);
CombineHarvester & mass(std::vector< std::string > const &vec, bool cond=true)
void ForEachSyst(Function func)
void ForEachProc(Function func)
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)
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
std::string const & type() const
std::string const & name() const
std::string BuildRooMorphing(RooWorkspace &ws, CombineHarvester &cb, std::string const &bin, std::string const &process, RooAbsReal &mass_var, std::string norm_postfix, bool allow_morph, bool verbose, bool force_template_limit=false, TFile *file=nullptr)
[part1]
void MakeMorphDebugPlots(RooMorphingPdf *pdf, RooAbsReal *mass, std::vector< double > const &masses, TFile *f, TH1 *ref_bins=nullptr)
TH1F RebinHist(TH1F const &hist)
std::vector< T > Set2Vec(std::set< T > const &in)
TH1F AsTH1F(TH1 const *hist)