8 #include "boost/format.hpp"
9 #include "RooFitResult.h"
10 #include "RooRealVar.h"
11 #include "RooDataHist.h"
12 #include "RooAbsReal.h"
13 #include "RooAbsData.h"
20 std::cout<<
"Systematic "<<syst->
name()<<
" for process "<<syst->
process()<<
" in region "<<syst->
bin()<<
" :";
24 std::cout<<
"Process "<<proc->
process()<<
" in region "<<proc->
bin()<<
" :";
32 jsobj[
"uncertVarySameDirect"][sys->name()][sys->bin()][sys->process()]={{
"value_u",sys->value_u()},{
"value_d",sys->value_d()}};
41 std::cout<<
" Up/Down normalisations go in the same direction: up variation: "<<sys->value_u()<<
", down variation: "<<sys->value_d()<<std::endl;
51 hist_u = sys->shape_u();
52 hist_d = sys->shape_d();
54 for(int i=1;i<=hist_u->GetNbinsX();i++){
55 if(fabs(hist_u->GetBinContent(i))+fabs(hist_d->GetBinContent(i))>0){
56 if(2*double(fabs(hist_u->GetBinContent(i)-hist_d->GetBinContent(i)))/(fabs(hist_u->GetBinContent(i))+fabs(hist_d->GetBinContent(i)))>0.001) is_same = 0;
60 jsobj[
"uncertTemplSame"][sys->name()][sys->bin()][sys->process()]={{
"value_u",sys->value_u()},{
"value_d",sys->value_d()}};
71 hist_u = sys->shape_u();
72 hist_d = sys->shape_d();
74 for(int i=1;i<=hist_u->GetNbinsX();i++){
75 if(fabs(hist_u->GetBinContent(i))+fabs(hist_d->GetBinContent(i))>0){
76 if(2*double(fabs(hist_u->GetBinContent(i)-hist_d->GetBinContent(i)))/(fabs(hist_u->GetBinContent(i))+fabs(hist_d->GetBinContent(i)))>0.001) is_same = 0;
81 std::cout<<
"Up/Down templates are identical: up variation: "<<sys->value_u()<<
", down variation: "<<sys->value_d()<<std::endl;
90 std::vector<ch::Process*> empty_procs;
94 empty_procs.push_back(proc);
95 if (jsobj[
"emptyProcessShape"][proc->bin()] !=NULL){
96 jsobj[
"emptyProcessShape"][proc->bin()].push_back(proc->process());
98 jsobj[
"emptyProcessShape"][proc->bin()] = {proc->process()};
104 for(
unsigned int i=0; i< empty_procs.size(); i++){
109 jsobj[
"emptySystematicShape"][sys->name()][sys->bin()][sys->process()]={{
"value_u",sys->value_u()},{
"value_d",sys->value_d()}};
116 std::vector<ch::Process*> empty_procs;
118 if(proc->
rate()==0.){
119 empty_procs.push_back(proc);
121 std::cout<<
" has 0 yield"<<std::endl;
126 for(
unsigned int i=0; i< empty_procs.size(); i++){
131 PrintSystematic(sys);
132 std::cout<<
" At least one empty histogram: up variation: "<<sys->value_u()<<
" Down variation: "<<sys->value_d()<<std::endl;
139 std::vector<ch::Process*> empty_procs;
141 if(proc->
rate()==0.){
142 empty_procs.push_back(proc);
147 for(
unsigned int i=0; i< empty_procs.size(); i++){
150 if(!no_check && ((sys->
type()==
"shape" && (sys->
value_u()-1 > maxNormEff || sys->
value_u()-1 < -maxNormEff || sys->
value_d()-1>maxNormEff || sys->
value_d()-1< -maxNormEff)) || (sys->
type()==
"lnN" && (sys->
value_u()-1 > maxNormEff || sys->
value_u()-1 < - maxNormEff) ))){
151 PrintSystematic(sys);
152 std::cout<<
"Uncertainty has a large normalisation effect: up variation: "<<sys->value_u()<<
" Down variation: "<<sys->value_d()<<std::endl;
158 std::vector<ch::Process*> empty_procs;
160 if(proc->
rate()==0.){
161 empty_procs.push_back(proc);
166 for(
unsigned int i=0; i< empty_procs.size(); i++){
169 if(!no_check && ((sys->
type()==
"shape" && (std::abs(sys->
value_u()-1) > maxNormEff || std::abs(sys->
value_d()-1)>maxNormEff)) || (sys->
type()==
"lnN" && (std::abs(sys->
value_u()-1) > maxNormEff) ))){
170 jsobj[
"largeNormEff"][sys->name()][sys->bin()][sys->process()]={{
"value_u",sys->value_u()},{
"value_d",sys->value_d()}};
179 auto cb_bin_backgrounds = cb.
cp().
bin({b}).backgrounds();
180 tothist = cb_bin_backgrounds.
GetShape();
181 for(
int i=1;i<=tothist.GetNbinsX();i++){
182 if(tothist.GetBinContent(i)<=0){
183 std::cout<<
"Channel "<<b<<
" bin "<<i<<
" of the templates is empty in background"<<std::endl;
193 auto cb_bin_backgrounds = cb.
cp().
bin({b}).backgrounds();
194 tothist = cb_bin_backgrounds.
GetShape();
195 for(
int i=1;i<=tothist.GetNbinsX();i++){
196 if(tothist.GetBinContent(i)<=0){
197 if (jsobj[
"emptyBkgBin"][b] !=NULL){
198 jsobj[
"emptyBkgBin"][b].push_back(i);
200 jsobj[
"emptyBkgBin"][b] = {i};
209 double diff_lim=0.001;
214 if(sys->
type()==
"shape"){
215 hist_u = sys->shape_u();
216 hist_d = sys->shape_d();
217 hist_nom=cb.cp().bin({sys->bin()}).process({sys->
process()}).GetShape();
218 hist_nom.Scale(1./hist_nom.Integral());
221 for(
int i=1;i<=hist_u->GetNbinsX();i++){
222 if(fabs(hist_u->GetBinContent(i))+fabs(hist_nom.GetBinContent(i))>0){
223 up_diff+=2*double(fabs(hist_u->GetBinContent(i)-hist_nom.GetBinContent(i)))/(fabs(hist_u->GetBinContent(i))+fabs(hist_nom.GetBinContent(i)));
225 if(fabs(hist_d->GetBinContent(i))+fabs(hist_nom.GetBinContent(i))>0){
226 down_diff+=2*double(fabs(hist_d->GetBinContent(i)-hist_nom.GetBinContent(i)))/(fabs(hist_d->GetBinContent(i))+fabs(hist_nom.GetBinContent(i)));
229 if(up_diff<diff_lim && down_diff<diff_lim){
231 std::cout<<
"Uncertainty probably has no genuine shape effect. Summed relative difference per bin between normalised nominal and up shape: "<<up_diff<<
" between normalised nominal and down shape: "<<down_diff<<std::endl;
239 double diff_lim=0.001;
244 if(sys->
type()==
"shape"){
245 hist_u = sys->shape_u();
246 hist_d = sys->shape_d();
247 hist_nom=cb.cp().bin({sys->bin()}).process({sys->
process()}).GetShape();
248 hist_nom.Scale(1./hist_nom.Integral());
251 for(
int i=1;i<=hist_u->GetNbinsX();i++){
252 if(fabs(hist_u->GetBinContent(i))+fabs(hist_nom.GetBinContent(i))>0){
253 up_diff+=2*double(fabs(hist_u->GetBinContent(i)-hist_nom.GetBinContent(i)))/(fabs(hist_u->GetBinContent(i))+fabs(hist_nom.GetBinContent(i)));
255 if(fabs(hist_d->GetBinContent(i))+fabs(hist_nom.GetBinContent(i))>0){
256 down_diff+=2*double(fabs(hist_d->GetBinContent(i)-hist_nom.GetBinContent(i)))/(fabs(hist_d->GetBinContent(i))+fabs(hist_nom.GetBinContent(i)));
259 if(up_diff<diff_lim && down_diff<diff_lim) jsobj[
"smallShapeEff"][sys->
name()][sys->
bin()][sys->
process()]={{
"diff_u",up_diff},{
"diff_d",down_diff}};
267 auto cb_bin_signals = cb.
cp().
bin({b}).signals();
268 auto cb_bin_backgrounds = cb.
cp().
bin({b}).backgrounds();
269 auto cb_bin = cb.
cp().
bin({b});
270 double sigrate = cb_bin_signals.
GetRate();
271 for(
auto p : cb_bin_signals.process_set()){
272 if(cb_bin_signals.cp().process({p}).GetRate() < minSigFrac*sigrate){
273 std::cout<<
"Very small signal process. In bin "<<b<<
" signal process "<<p<<
" has yield "<<cb_bin_signals.cp().process({p}).GetRate()<<
". Total signal rate in this bin is "<<sigrate<<std::endl;
283 auto cb_bin_signals = cb.
cp().
bin({b}).signals();
284 auto cb_bin_backgrounds = cb.
cp().
bin({b}).backgrounds();
285 auto cb_bin = cb.
cp().
bin({b});
286 double sigrate = cb_bin_signals.
GetRate();
287 for(
auto p : cb_bin_signals.process_set()){
288 if(cb_bin_signals.cp().process({p}).GetRate() < minSigFrac*sigrate){
289 jsobj[
"smallSignalProc"][b][p]={{
"sigrate_tot",sigrate},{
"procrate",cb_bin_signals.cp().process({p}).GetRate()}};
298 bool is_shape_card=1;
310 std::cout<<
"Not a shape-based datacard / shape-based datacard using RooDataHist. Skipping checks on systematic shapes."<<std::endl;
315 std::ofstream outfile(filename);
316 outfile <<std::setw(4)<<output_js<<std::endl;
void ForEachSyst(Function func)
void ForEachProc(Function func)
CombineHarvester & bin(std::vector< std::string > const &vec, bool cond=true)
std::set< std::string > bin_set()
CombineHarvester cp()
Creates and returns a shallow copy of the CombineHarvester instance.
virtual std::string const & process() const
virtual std::string const & bin() const
RooAbsReal const * pdf() const
TH1 const * shape() const
std::string const & type() const
std::string const & name() const
void ValidateShapeTemplates(CombineHarvester &cb, json &jsobj)
void ValidateShapeUncertaintyDirection(CombineHarvester &cb, json &jsobj)
void CheckNormEff(CombineHarvester &cb, double maxNormEff, json &jsobj)
void PrintProc(ch::Process *proc)
void CheckSizeOfShapeEffect(CombineHarvester &cb, json &jsobj)
void ValidateCards(CombineHarvester &cb, std::string const &filename, double maxNormEff, double minSigFrac)
void CheckEmptyBins(CombineHarvester &cb, json &jsobj)
void CheckEmptyShapes(CombineHarvester &cb, json &jsobj)
bool MatchingProcess(T const &first, U const &second)
void CheckSmallSignals(CombineHarvester &cb, double minSigFrac, json &jsobj)
void PrintSystematic(ch::Systematic *syst)