BCMTF.cxx
1 /*
2  * Copyright (C) 2007-2018, the BAT core developer team
3  * All rights reserved.
4  *
5  * For the licensing terms see doc/COPYING.
6  * For documentation see http://mpp.mpg.de/bat
7  */
8 
9 // ---------------------------------------------------------
10 
11 #include <iostream>
12 #include <fstream>
13 
14 #include <TCanvas.h>
15 #include <THStack.h>
16 #include <TH1D.h>
17 #include <TH2D.h>
18 #include <TAxis.h>
19 #include <TF1.h>
20 #include <TMath.h>
21 #include <TGraphAsymmErrors.h>
22 
23 #include "../../BAT/BCMath.h"
24 #include "../../BAT/BCLog.h"
25 
26 #include "BCMTFChannel.h"
27 #include "BCMTFProcess.h"
28 #include "BCMTFTemplate.h"
29 #include "BCMTFSystematic.h"
30 #include "BCMTFSystematicVariation.h"
31 
32 #include "BCMTF.h"
33 
34 // ---------------------------------------------------------
35 BCMTF::BCMTF(const std::string& name)
36  : BCModel(name)
37  , fNChannels(0)
38  , fNProcesses(0)
39  , fNSystematics(0)
40  , fFlagEfficiencyConstraint(false)
41 {}
42 
43 // ---------------------------------------------------------
45 // default destructor
46 {
47  for (int i = 0; i < fNChannels; ++i)
48  delete fChannelContainer.at(i);
49 }
50 
51 // ---------------------------------------------------------
52 int BCMTF::GetChannelIndex(const std::string& name) const
53 {
54  // loop over all channels and compare names
55  for (int i = 0; i < fNChannels; ++i)
56  // compare names;
57  if (fChannelContainer[i]->GetName().compare(name) == 0)
58  return i;
59 
60  // if channel does not exist, return -1
61  return -1;
62 }
63 
64 // ---------------------------------------------------------
65 int BCMTF::GetProcessIndex(const std::string& name) const
66 {
67  // loop over all processs and compare names
68  for (int i = 0; i < fNProcesses; ++i)
69  // compare names
70  if (fProcessContainer[i]->GetName().compare(name) == 0)
71  return i;
72 
73  // if process does not exist, return -1
74  return -1;
75 }
76 
77 // ---------------------------------------------------------
78 int BCMTF::GetSystematicIndex(const std::string& name) const
79 {
80  // loop over all systematics and compare names
81  for (int i = 0; i < fNSystematics; ++i) {
82  // compare names
83  if (fSystematicContainer[i]->GetName().compare(name) == 0)
84  return i;
85  }
86 
87  // if process does not exist, return -1
88  return -1;
89 }
90 
91 // ---------------------------------------------------------
92 void BCMTF::SetTemplate(const std::string& channelname, const std::string& processname, TH1D hist, double efficiency, double norm)
93 {
94  // get channel index
95  int channelindex = GetChannelIndex(channelname);
96 
97  // check if channel exists
98  if (channelindex < 0) {
99  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
100  }
101 
102  // get process index
103  int processindex = GetProcessIndex(processname);
104 
105  // check if process exists
106  if (processindex < 0) {
107  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Process does not exist.");
108  }
109 
110  // get channel
111  BCMTFChannel* channel = GetChannel(channelindex);
112 
113  // get template
114  BCMTFTemplate* bctemplate = channel->GetTemplate(processindex);
115 
116  // remove statistics box
117  hist.SetStats(kFALSE);
118 
119  int color = GetProcess(processindex)->GetHistogramColor();
120  if (color < 0)
121  color = 2 + processindex;
122  int fillstyle = GetProcess(processindex)->GetHistogramFillStyle();
123  if (fillstyle < 0)
124  fillstyle = 1001;
125  int linestyle = GetProcess(processindex)->GetHistogramLineStyle();
126  if (linestyle < 0)
127  linestyle = 1;
128 
129  // set color and fill style
130  hist.SetFillColor(color);
131  hist.SetFillStyle(fillstyle);
132  hist.SetLineStyle(linestyle);
133 
134  // create new histogram
135  TH1D* temphist = BCAux::OwnClone(&hist);
136 
137  // set histogram
138  bctemplate->SetHistogram(temphist, norm);
139 
140  // set efficiency
141  bctemplate->SetEfficiency(efficiency);
142 }
143 
144 // ---------------------------------------------------------
145 void BCMTF::SetTemplate(const std::string& channelname, const std::string& processname, std::vector<TF1*>* funccont, int nbins, double efficiency)
146 {
147  // get channel index
148  int channelindex = GetChannelIndex(channelname);
149 
150  // check if channel exists
151  if (channelindex < 0) {
152  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
153  }
154 
155  // get process index
156  int processindex = GetProcessIndex(processname);
157 
158  // check if process exists
159  if (processindex < 0) {
160  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Process does not exist.");
161  }
162 
163  // get channel
164  BCMTFChannel* channel = GetChannel(channelindex);
165 
166  // get template
167  BCMTFTemplate* bctemplate = channel->GetTemplate(processindex);
168 
169  // set histogram
170  bctemplate->SetFunctionContainer(funccont, nbins);
171 
172  // set efficiency
173  bctemplate->SetEfficiency(efficiency);
174 }
175 
176 // ---------------------------------------------------------
177 void BCMTF::SetData(const std::string& channelname, TH1D hist, double minimum, double maximum)
178 {
179  int channelindex = GetChannelIndex(channelname);
180 
181  // check if channel exists
182  if (channelindex < 0) {
183  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
184  }
185 
186  // get channel
187  BCMTFChannel* channel = GetChannel(channelindex);
188 
189  // get template
190  BCMTFTemplate* data = channel->GetData();
191 
192  // remove statistics box
193  hist.SetStats(kFALSE);
194 
195  // set marker
196  hist.SetMarkerStyle(20);
197  hist.SetMarkerSize(1.1);
198 
199  // set divisions
200  hist.SetNdivisions(509);
201 
202  // remove old data set if it exists
203  if (data->GetHistogram()) {
204  delete data->GetHistogram();
205  data->SetHistogram(0);
206  }
207 
208  // create new histograms for uncertainty bands
209  if (minimum == -1)
210  minimum = 0;
211  if (maximum == -1)
212  maximum = ceil(hist.GetMaximum() + 5.*sqrt(hist.GetMaximum()));
213 
214  std::vector<double> a(hist.GetNbinsX() + 1);
215  for (int i = 0; i < hist.GetNbinsX() + 1; ++i) {
216  a[i] = hist.GetXaxis()->GetBinLowEdge(i + 1);
217  }
218 
219  // histograms are deleted by us, prevent issues if a TFile happens to be around
220  // https://github.com/bat/bat/issues/166
221  TH1D* hist_copy;
222  TH2D* hist_uncbandexp, *hist_uncbandpoisson;
223  {
225 
226  hist_copy = new TH1D(hist);
227 
228  hist_uncbandexp = new TH2D(Form("UncertaintyBandExpectation_%s_%d", GetSafeName().data(), channelindex), "", hist.GetNbinsX(), &a[0], 1000, minimum, maximum);
229  hist_uncbandexp->SetStats(kFALSE);
230 
231  hist_uncbandpoisson = new TH2D(Form("UncertaintyBandPoisson_%s_%d", GetSafeName().data(), channelindex), "", hist.GetNbinsX(), &a[0], int(maximum - minimum), minimum, maximum);
232  hist_uncbandpoisson->SetStats(kFALSE);
233  }
234 
235  // set histograms
236  data->SetHistogram(hist_copy, hist.Integral());
237  channel->SetHistUncertaintyBandExpectation(hist_uncbandexp);
238  channel->SetHistUncertaintyBandPoisson(hist_uncbandpoisson);
239 
240  // set y-range for printing
241  channel->SetRangeY(minimum, maximum);
242 }
243 
244 // ---------------------------------------------------------
245 void BCMTF::AddChannel(const std::string& name)
246 {
247  // check if channel exists
248  for (int i = 0; i < fNChannels; ++i) {
249  // compare names
250  if (GetChannelIndex(name) >= 0) {
251  throw std::runtime_error("BCMultitemplateFitter::AddChannel() : Channel with this name exists already.");
252  }
253  }
254 
255  // create new channel
256  BCMTFChannel* channel = new BCMTFChannel(name);
257 
258  // create new data
259  BCMTFTemplate* bctemplate = new BCMTFTemplate(channel->GetName(), "data");
260 
261  // add data
262  channel->SetData(bctemplate);
263 
264  // add process templates
265  for (int i = 0; i < fNProcesses; ++i) {
266  // get process
267  BCMTFProcess* process = GetProcess(i);
268 
269  // create new template
270  BCMTFTemplate* bctemplate = new BCMTFTemplate(name, process->GetName());
271 
272  // add template
273  channel->AddTemplate(bctemplate);
274  }
275 
276  // loop over all systematics
277  for (int i = 0; i < fNSystematics; ++i)
278  // add systematic variation
279  channel->AddSystematicVariation(new BCMTFSystematicVariation(fNProcesses));
280 
281  // add channel
282  fChannelContainer.push_back(channel);
283 
284  // increase number of channels
285  fNChannels++;
286 }
287 
288 // ---------------------------------------------------------
289 void BCMTF::AddProcess(const std::string& name, double nmin, double nmax, int color, int fillstyle, int linestyle)
290 {
291  // check if process exists
292  for (int i = 0; i < fNProcesses; ++i) {
293  // compare names
294  if (GetProcessIndex(name) >= 0) {
295  throw std::runtime_error("BCMultitemplateFitter::AddProcess() : Process with this name exists already.");
296  }
297  }
298 
299  // create new process
300  BCMTFProcess* process = new BCMTFProcess(name);
301  process->SetHistogramColor(color);
302  process->SetHistogramFillStyle(fillstyle);
303  process->SetHistogramLineStyle(linestyle);
304 
305  // add process
306  fProcessContainer.push_back(process);
307 
308  // add process templates
309  for (int i = 0; i < fNChannels; ++i) {
310  // get channel
311  BCMTFChannel* channel = GetChannel(i);
312 
313  // create new template
314  BCMTFTemplate* bctemplate = new BCMTFTemplate(channel->GetName(), name);
315 
316  // add template
317  channel->AddTemplate(bctemplate);
318 
319  // loop over all systematic
320  for (int j = 0; j < fNSystematics; ++j) {
321  // get systematic variation
322  BCMTFSystematicVariation* variation = channel->GetSystematicVariation(j);
323 
324  // add histogram
325  variation->AddHistograms(0, 0);
326  }
327  }
328 
329  // increase number of processes
330  fNProcesses++;
331 
332  // add parameter index to container
333  fProcessParIndexContainer.push_back(GetNParameters());
334 
335  // add parameter
336  AddParameter(name, nmin, nmax);
337 
338  // add a functional form for the expectation
339  fExpectationFunctionContainer.push_back(0);
340 }
341 
342 // ---------------------------------------------------------
343 void BCMTF::AddSystematic(const std::string& name, double min, double max)
344 {
345  // check if systematic exists
346  for (int i = 0; i < fNSystematics; ++i) {
347  // compare names
348  if (GetSystematicIndex(name) >= 0) {
349  throw std::runtime_error("BCMultitemplateFitter::AddSystematic() : Systematic with this name exists already.");
350  }
351  }
352 
353  // create new systematic
354  BCMTFSystematic* systematic = new BCMTFSystematic(name);
355 
356  // add systematic
357  fSystematicContainer.push_back(systematic);
358 
359  // add systematic variations
360  for (int i = 0; i < fNChannels; ++i) {
361  // get channel
362  BCMTFChannel* channel = GetChannel(i);
363 
364  // create new systematic variation
365  BCMTFSystematicVariation* variation = new BCMTFSystematicVariation(fNProcesses);
366 
367  // add systematic variation
368  channel->AddSystematicVariation(variation);
369  }
370  // ...
371 
372  // increase number of systematices
373  fNSystematics++;
374 
375  // add parameter index to container
376  fSystematicParIndexContainer.push_back(GetNParameters());
377 
378  // add parameter
379  AddParameter(name, min, max);
380 
381  // add a functional form for the expectation
382  fExpectationFunctionContainer.push_back(0);
383 }
384 
385 // ---------------------------------------------------------
386 void BCMTF::SetSystematicVariation(const std::string& channelname, const std::string& processname, const std::string& systematicname, double variation_up, double variation_down)
387 {
388 
389  // get channel index
390  int channelindex = GetChannelIndex(channelname);
391 
392  // check if channel exists
393  if (channelindex < 0) {
394  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
395  }
396 
397  // get process index
398  int processindex = GetProcessIndex(processname);
399 
400  // check if process exists
401  if (processindex < 0) {
402  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Process does not exist.");
403  }
404 
405  // get systematic index
406  int systematicindex = GetSystematicIndex(systematicname);
407 
408  // check if systematic exists
409  if (systematicindex < 0) {
410  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Systematic does not exist.");
411  }
412 
413  // get channel
414  BCMTFChannel* channel = GetChannel(channelindex);
415 
416  BCMTFTemplate* bctemplate = channel->GetTemplate(processindex);
417 
418  TH1D* hist_template = bctemplate->GetHistogram();
419 
420  TH1D hist_up = TH1D(*hist_template);
421  TH1D hist_down = TH1D(*hist_template);
422 
423  int nbins = hist_up.GetNbinsX();
424 
425  // loop over all bins
426  for (int ibin = 1; ibin <= nbins; ++ibin) {
427  hist_up.SetBinContent(ibin, variation_up);
428  hist_down.SetBinContent(ibin, variation_down);
429  }
430 
431  // get systematic variation
432  BCMTFSystematicVariation* variation = channel->GetSystematicVariation(systematicindex);
433 
434  // set histogram
435  variation->SetHistograms(processindex, new TH1D(hist_up), new TH1D(hist_down));
436 }
437 
438 // ---------------------------------------------------------
439 void BCMTF::SetSystematicVariation(const std::string& channelname, const std::string& processname, const std::string& systematicname, TH1D hist_up, TH1D hist_down)
440 {
441  // get channel index
442  int channelindex = GetChannelIndex(channelname);
443 
444  // check if channel exists
445  if (channelindex < 0) {
446  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
447  }
448 
449  // get process index
450  int processindex = GetProcessIndex(processname);
451 
452  // check if process exists
453  if (processindex < 0) {
454  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Process does not exist.");
455  }
456 
457  // get systematic index
458  int systematicindex = GetSystematicIndex(systematicname);
459 
460  // check if systematic exists
461  if (systematicindex < 0) {
462  throw std::runtime_error("BCMultitemplateFitter::SetTemplate() : Systematic does not exist.");
463  }
464 
465  // get channel
466  BCMTFChannel* channel = GetChannel(channelindex);
467 
468  // get systematic variation
469  BCMTFSystematicVariation* variation = channel->GetSystematicVariation(systematicindex);
470 
471  // set histogram
472  variation->SetHistograms(processindex, new TH1D(hist_up), new TH1D(hist_down));
473 }
474 
475 // ---------------------------------------------------------
476 void BCMTF::SetSystematicVariation(const std::string& channelname, const std::string& processname, const std::string& systematicname, TH1D hist, TH1D hist_up, TH1D hist_down)
477 {
478  // get number of bins
479  int nbins = hist.GetNbinsX();
480 
481  TH1D* hist_up_rel = new TH1D(hist);
482  TH1D* hist_down_rel = new TH1D(hist);
483 
484  // loop over all bins
485  for (int ibin = 1; ibin <= nbins; ++ibin) {
486  hist_up_rel->SetBinContent(ibin, (hist_up.GetBinContent(ibin) - hist.GetBinContent(ibin)) / hist.GetBinContent(ibin));
487  hist_down_rel->SetBinContent(ibin, (hist.GetBinContent(ibin) - hist_down.GetBinContent(ibin)) / hist.GetBinContent(ibin));
488  }
489 
490  // set the systematic variation
491  return SetSystematicVariation(channelname, processname, systematicname, *hist_up_rel, *hist_down_rel);
492 }
493 
494 // ---------------------------------------------------------
496 {
497  BCLog::OutSummary(" Multi template fitter summary ");
498  BCLog::OutSummary(" ----------------------------- ");
499  BCLog::OutSummary(Form(" Number of channels : %u", fNChannels));
500  BCLog::OutSummary(Form(" Number of processes : %u", fNProcesses));
501  BCLog::OutSummary(Form(" Number of systematics : %u", fNSystematics));
502  BCLog::OutSummary("");
503 
504  BCLog::OutSummary(" Channels :");
505  for (int i = 0; i < GetNChannels(); ++i)
506  BCLog::OutSummary(Form(" %d : \"%s\"", i, fChannelContainer[i]->GetName().data()));
507  BCLog::OutSummary("");
508 
509  BCLog::OutSummary(" Processes :");
510  for (int i = 0; i < GetNProcesses(); ++i)
511  BCLog::OutSummary(Form(" %d : \"%s\" (par index %d)", i, fProcessContainer[i]->GetName().data(), GetParIndexProcess(i)));
512  BCLog::OutSummary("");
513 
514  BCLog::OutSummary(" Systematics :");
515  for (int i = 0; i < GetNSystematics(); ++i)
516  BCLog::OutSummary(Form(" %d : \"%s\" (par index %d)", i, fSystematicContainer[i]->GetName().data(), GetParIndexSystematic(i)));
517  if (GetNSystematics() == 0)
518  BCLog::OutSummary(" - none - ");
519  BCLog::OutSummary("");
520 
521  BCLog::OutSummary(" Goodness-of-fit: ");
522  for (int i = 0; i < GetNChannels(); ++i)
523  BCLog::OutSummary(Form(" %d : \"%s\" : chi2 = %f", i, fChannelContainer[i]->GetName().data(), CalculateChi2(i, GetBestFitParameters())));
524  BCLog::OutSummary("");
525 }
526 
527 // ---------------------------------------------------------
528 double BCMTF::Expectation(int channelindex, int binindex, const std::vector<double>& parameters)
529 {
530  double expectation = 0.;
531 
532  // loop over all processes
533  for (int i = 0; i < fNProcesses; ++i) {
534  // get efficiency
535  double efficiency = Efficiency(channelindex, i, binindex, parameters);
536 
537  // get probability
538  double probability = Probability(channelindex, i, binindex, parameters);
539 
540  // get parameter index
541  int parindex = fProcessParIndexContainer[i];
542 
543  // add to expectation
544  expectation += ExpectationFunction(parindex, channelindex, i, parameters)
545  * efficiency
546  * probability;
547  }
548 
549  // check if expectation is positive
550  if (expectation < 0)
551  expectation = 0.;
552 
553  return expectation;
554 }
555 
556 // ---------------------------------------------------------
557 double BCMTF::ExpectationFunction(int parindex, int channelindex, int processindex, const std::vector<double>& parameters)
558 {
559  // get function container
560  std::vector<TF1*>* funccont = fChannelContainer[channelindex]->GetTemplate(processindex)->GetFunctionContainer();
561 
562  if (funccont->size() > 0)
563  return 1.;
564 
565  else if (!fExpectationFunctionContainer[parindex])
566  return parameters[parindex];
567 
568  else {
569  TF1* func = fExpectationFunctionContainer[parindex];
570  return func->Eval(parameters[parindex]);
571  }
572 }
573 
574 // ---------------------------------------------------------
575 double BCMTF::Efficiency(int channelindex, int processindex, int binindex, const std::vector<double>& parameters)
576 {
577  // get channel
578  BCMTFChannel* channel = fChannelContainer[channelindex];
579 
580  double efficiency = channel->GetTemplate(processindex)->GetEfficiency();
581 
582  double defficiency = 1.;
583 
584  // loop over all systematics
585  for (int i = 0; i < fNSystematics; ++i) {
586  if (!(fSystematicContainer[i]->GetFlagSystematicActive()))
587  continue;
588 
589  // get parameter index
590  int parindex = fSystematicParIndexContainer[i];
591 
592  // get histogram
593  TH1D* hist = 0;
594 
595  if (parameters[parindex] > 0)
596  hist = channel->GetSystematicVariation(i)->GetHistogramUp(processindex);
597  else
598  hist = channel->GetSystematicVariation(i)->GetHistogramDown(processindex);
599 
600  // check if histogram exists
601  if (!hist)
602  continue;
603 
604  // multiply efficiency
605  defficiency += parameters[parindex] * hist->GetBinContent(binindex);
606  }
607 
608  // calculate efficiency
609  efficiency *= defficiency;
610 
611  // make sure efficiency is between 0 and 1
612  if (fFlagEfficiencyConstraint) {
613  if (efficiency < 0.)
614  efficiency = 0.;
615  if (efficiency > 1.)
616  efficiency = 1.;
617  }
618 
619  return efficiency;
620 }
621 
622 // ---------------------------------------------------------
623 double BCMTF::Probability(int channelindex, int processindex, int binindex, const std::vector<double>& parameters)
624 {
625  // get histogram
626  TH1D* hist = fChannelContainer[channelindex]->GetTemplate(processindex)->GetHistogram();
627 
628  // get function container
629  std::vector<TF1*>* funccont = fChannelContainer[channelindex]->GetTemplate(processindex)->GetFunctionContainer();
630 
631  // this needs to be fast
632  if (!hist && !(funccont->size() > 0))
633  return 0.;
634 
635  if (hist)
636  return hist->GetBinContent(binindex);
637  else {
638  int parindex = fProcessParIndexContainer[processindex];
639  return funccont->at(binindex - 1)->Eval(parameters[parindex]);
640  }
641 }
642 
643 // ---------------------------------------------------------
644 void BCMTF::PrintStack(int channelindex, const std::vector<double>& parameters, const std::string& filename, const std::string& options)
645 {
646  // check if parameters are filled
647  if (parameters.empty())
648  return;
649 
650  // check options
651  bool flag_logx = false; // plot x-axis in log-scale
652  bool flag_logy = false; // plot y-axis in log-scale
653  bool flag_bw = false; // plot in black and white
654 
655  bool flag_sum = false; // plot sum of all templates
656  bool flag_stack = false; // plot stack of templates
657 
658  bool flag_e0 = false; // do not draw error bars on data
659  bool flag_e1 = false; // draw sqrt(N) error bars on data
660 
661  bool flag_b0 = false; // draw an error band on the expectation
662  bool flag_b1 = false; // draw an error band on the number of events
663 
664  if (options.find("logx") < options.size())
665  flag_logx = true;
666 
667  if (options.find("logy") < options.size())
668  flag_logy = true;
669 
670  if (options.find("bw") < options.size())
671  flag_bw = true;
672 
673  if (options.find("sum") < options.size())
674  flag_sum = true;
675 
676  if (options.find("stack") < options.size())
677  flag_stack = true;
678 
679  if (options.find("e0") < options.size())
680  flag_e0 = true;
681 
682  if (options.find("e1") < options.size())
683  flag_e1 = true;
684 
685  if (options.find("b0") < options.size())
686  flag_b0 = true;
687 
688  if (options.find("b1") < options.size())
689  flag_b1 = true;
690 
691  if (!flag_e0)
692  flag_e1 = true;
693 
694  // check if MCMC ran
696  flag_b0 = false;
697  flag_b1 = false;
698  BCLog::OutWarning("BCMTF::PrintStack : Did not run MCMC. Error bands are not available.");
699  }
700 
701  // get channel
702  BCMTFChannel* channel = GetChannel(channelindex);
703 
704  // create canvas
705  TCanvas* c1 = new TCanvas();
706  c1->cd();
707 
708  // set log or linear scale
709  if (flag_logx)
710  c1->SetLogx();
711 
712  if (flag_logy)
713  c1->SetLogy();
714 
715  // get data histogram
716  TH1D* hist_data = channel->GetData()->GetHistogram();
717 
718  // get number of bins
719  int nbins = hist_data->GetNbinsX();
720 
721  // define sum of templates
722  TH1D* hist_sum = new TH1D(*hist_data);
723  hist_sum->SetLineColor(kBlack);
724  for (int i = 1; i <= nbins; ++i)
725  hist_sum->SetBinContent(i, 0);
726 
727  // define error band
728  TH1D* hist_error_band = new TH1D(*hist_data);
729  hist_error_band->SetFillColor(kBlack);
730  hist_error_band->SetFillStyle(3005);
731  hist_error_band->SetLineWidth(1);
732  hist_error_band->SetStats(kFALSE);
733  hist_error_band->SetMarkerSize(0);
734 
735  TGraphAsymmErrors* graph_error_exp = new TGraphAsymmErrors(nbins);
736  // graph_error_exp->SetLineWidth(2);
737  graph_error_exp->SetMarkerStyle(0);
738  graph_error_exp->SetFillColor(kBlack);
739  graph_error_exp->SetFillStyle(3005);
740 
741  // get histogram for uncertainty band
742  TH2D* hist_uncbandexp = channel->GetHistUncertaintyBandExpectation();
743 
744  // fill error band
745  if (flag_b0) {
746  for (int i = 1; i <= nbins; ++i) {
747  TH1D* proj = hist_uncbandexp->ProjectionY("_py", i, i);
748  if (proj->Integral() > 0)
749  proj->Scale(1.0 / proj->Integral());
750  double quantiles[3];
751  double sums[3] = {0.16, 0.5, 0.84};
752  proj->GetQuantiles(3, quantiles, sums);
753  graph_error_exp->SetPoint(i - 1, hist_data->GetBinCenter(i), quantiles[1]);
754  graph_error_exp->SetPointError(i - 1, 0.0, 0.0, quantiles[1] - quantiles[0], quantiles[2] - quantiles[1]);
755  hist_error_band->SetBinContent(i, 0.5 * (quantiles[2] + quantiles[0]));
756  hist_error_band->SetBinError(i, 0, 0.5 * (quantiles[2] - quantiles[0]));
757  delete proj;
758  }
759  }
760 
761  // create stack
762  THStack* stack = new THStack("", "");
763 
764  // create a container of temporary histograms
765  std::vector<TH1D*> histcontainer;
766 
767  // get number of templates
768  unsigned int ntemplates = GetNProcesses();
769 
770  // loop over all templates
771  for (unsigned int i = 0; i < ntemplates; ++i) {
772 
773  // get histogram
774  TH1D* temphist = channel->GetTemplate(i)->GetHistogram();
775 
776  // get function container
777  std::vector<TF1*>* funccont = channel->GetTemplate(i)->GetFunctionContainer();
778 
779  // create new histogram
780  TH1D* hist(0);
781 
782  if (temphist)
783  hist = new TH1D( *(temphist) );
784  else if (funccont)
785  hist = new TH1D( *(channel->GetData()->GetHistogram()));
786  else
787  continue;
788 
789  // set histogram style
790  int color = GetProcess(i)->GetHistogramColor();
791  if (color < 0)
792  color = 2 + i;
793  int fillstyle = GetProcess(i)->GetHistogramFillStyle();
794  if (fillstyle < 0)
795  fillstyle = 1001;
796  int linestyle = GetProcess(i)->GetHistogramLineStyle();
797  if (linestyle < 0)
798  linestyle = 1;
799 
800  // set color and fill style
801  hist->SetFillColor(color);
802  hist->SetFillStyle(fillstyle);
803  hist->SetLineStyle(linestyle);
804 
805  if (flag_bw) {
806  hist->SetFillColor(0);
807  }
808 
809  // scale histogram
810  for (int ibin = 1; ibin <= nbins; ++ibin) {
811 
812  // get efficiency
813  double efficiency = Efficiency(channelindex, i, ibin, parameters);
814 
815  // get probability
816  double probability = Probability(channelindex, i, ibin, parameters);
817 
818  // get parameter index
819  int parindex = GetParIndexProcess(i);
820 
821  // add to expectation
822  double expectation = parameters[parindex] * efficiency * probability;
823 
824  // set bin content
825  hist->SetBinContent(ibin, expectation);
826 
827  // add bin content
828  hist_sum->SetBinContent(ibin, hist_sum->GetBinContent(ibin) + expectation);
829  }
830 
831  // add histogram to container (for memory management)
832  histcontainer.push_back(hist);
833 
834  // add histogram to stack
835  stack->Add(hist);
836  }
837 
838  //draw data
839  hist_data->Draw("P0");
840 
841  // define variable for maximum in y-direction
842  double ymax = 0;;
843 
844  if (flag_e1)
845  ymax = hist_data->GetMaximum() + sqrt(hist_data->GetMaximum());
846  else
847  ymax = hist_data->GetMaximum();
848 
849  // set range user
850  hist_data->GetYaxis()->SetRangeUser(channel->GetRangeYMin(), channel->GetRangeYMax());
851 
852  // draw stack
853  if (flag_stack) {
854  stack->Draw("SAMEHIST");
855  if (stack->GetMaximum() > ymax)
856  ymax = stack->GetMaximum();
857  }
858 
859  // draw error band on number of observed events
860  if (flag_b1) {
862  TH1D* hist_temp = channel->CalculateUncertaintyBandPoisson(0.001, 0.999, kRed);
863  hist_temp->Draw("SAMEE2");
864  channel->CalculateUncertaintyBandPoisson(0.023, 0.977, kOrange)->Draw("SAMEE2");
865  channel->CalculateUncertaintyBandPoisson(0.159, 0.841, kGreen)->Draw("SAMEE2");
866 
867  // get bin with maximum
868  int ymaxbin = hist_temp->GetMaximumBin();
869 
870  if (hist_temp->GetBinContent(ymaxbin) + hist_temp->GetBinError(ymaxbin) > ymax)
871  ymax = hist_temp->GetBinContent(ymaxbin) + hist_temp->GetBinError(ymaxbin);
872  }
873 
874  // draw error band on expectation
875  if (flag_b0) {
876  hist_error_band->Draw("SAMEE2");
877  }
878 
879  if (flag_sum)
880  hist_sum->Draw("SAME");
881 
882  //draw data again
883  if (flag_e0)
884  hist_data->Draw("SAMEP0");
885 
886  if (flag_e1)
887  hist_data->Draw("SAMEP0E");
888 
889  hist_data->GetYaxis()->SetRangeUser(0., 1.1 * ymax);
890 
891  // redraw the axes
892  gPad->RedrawAxis();
893 
894  // print
895  c1->Print(filename.data());
896 
897  // free memory
898  for (unsigned int i = 0; i < histcontainer.size(); ++i) {
899  TH1D* hist = histcontainer.at(i);
900  delete hist;
901  }
902  delete stack;
903  delete c1;
904  delete graph_error_exp;
905  delete hist_error_band;
906  delete hist_sum;
907 }
908 
909 // ---------------------------------------------------------
910 double BCMTF::CalculateChi2(int channelindex, const std::vector<double>& parameters)
911 {
912  if (parameters.empty())
913  return -1;
914 
915  double chi2 = 0;
916 
917  // get channel
918  BCMTFChannel* channel = GetChannel(channelindex);
919 
920  // get data
921  BCMTFTemplate* data = channel->GetData();
922 
923  // get histogram
924  TH1D* hist = data->GetHistogram();
925 
926  // check if histogram exists
927  if (hist) {
928  // get number of bins in data
929  int nbins = hist->GetNbinsX();
930 
931  // loop over all bins
932  for (int ibin = 1; ibin <= nbins; ++ibin) {
933  // get expectation value
934  double expectation = Expectation(channelindex, ibin, parameters);
935 
936  // get observation
937  double observation = hist->GetBinContent(ibin);
938 
939  // add Poisson term
940  chi2 += (expectation - observation) * (expectation - observation) / expectation;
941  }
942  }
943 
944  // return chi2;
945  return chi2;
946 }
947 
948 // ---------------------------------------------------------
949 double BCMTF::CalculateChi2(const std::vector<double>& parameters)
950 {
951  if (parameters.empty())
952  return -1;
953 
954  double chi2 = 0;
955 
956  // get number of channels
957  int nchannels = GetNChannels();
958 
959  // loop over all channels
960  for (int i = 0; i < nchannels; ++i) {
961  chi2 += CalculateChi2(i, parameters);
962  }
963 
964  // return chi2
965  return chi2;
966 }
967 
968 // ---------------------------------------------------------
969 double BCMTF::CalculateCash(int channelindex, const std::vector<double>& parameters)
970 {
971  if (parameters.empty())
972  return -1;
973 
974  double cash = 0;
975 
976  // get channel
977  BCMTFChannel* channel = GetChannel(channelindex);
978 
979  // get data
980  BCMTFTemplate* data = channel->GetData();
981 
982  // get histogram
983  TH1D* hist = data->GetHistogram();
984 
985  // check if histogram exists
986  if (hist) {
987  // get number of bins in data
988  int nbins = hist->GetNbinsX();
989 
990  // loop over all bins
991  for (int ibin = 1; ibin <= nbins; ++ibin) {
992  // get expectation value
993  double expectation = Expectation(channelindex, ibin, parameters);
994 
995  // get observation
996  double observation = hist->GetBinContent(ibin);
997 
998  // calculate Cash statistic
999  cash += 2. * (expectation - observation);
1000 
1001  // check negative log
1002  if (observation > 0)
1003  cash += 2. * observation * log (observation / expectation);
1004  }
1005  }
1006 
1007  // return cash;
1008  return cash;
1009 
1010 }
1011 
1012 // ---------------------------------------------------------
1013 double BCMTF::CalculateCash(const std::vector<double>& parameters)
1014 {
1015  if (parameters.empty())
1016  return -1;
1017 
1018  double cash = 0;
1019 
1020  // get number of channels
1021  int nchannels = GetNChannels();
1022 
1023  // loop over all channels
1024  for (int i = 0; i < nchannels; ++i) {
1025  cash += CalculateCash(i, parameters);
1026  }
1027 
1028  // return cash
1029  return cash;
1030 }
1031 
1032 // ---------------------------------------------------------
1033 double BCMTF::CalculatePValue(int channelindex, const std::vector<double>& parameters)
1034 {
1035  // get channel
1036  BCMTFChannel* channel = GetChannel(channelindex);
1037 
1038  // get data histogram
1039  TH1D* hist = channel->GetData()->GetHistogram();
1040 
1041  // check if histogram exists
1042  if (!hist) {
1043  return -1;
1044  }
1045 
1046  // get number of bins in data
1047  int nbins = hist->GetNbinsX();
1048 
1049  // copy observed and expected values
1050  std::vector<unsigned> observation(nbins);
1051  std::vector<double> expectation(nbins);
1052 
1053  // loop over all bins
1054  for (int ibin = 0; ibin < nbins; ++ibin) {
1055  // get expectation value
1056  expectation[ibin] = Expectation(channelindex, ibin + 1, parameters);
1057 
1058  // get observation
1059  observation[ibin] = unsigned(hist->GetBinContent(ibin + 1));
1060  }
1061 
1062  // create pseudo experiments
1063  static const unsigned nIterations = unsigned (1e5);
1064  return BCMath::FastPValue(observation, expectation, nIterations, fRandom.GetSeed());
1065 }
1066 
1067 // ---------------------------------------------------------
1068 double BCMTF::CalculatePValue(const std::vector<double>& parameters)
1069 {
1070 
1071  // copy observed and expected values
1072  std::vector<unsigned> observation;
1073  std::vector<double> expectation;
1074 
1075  // loop over all channels
1076  for (int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1077 
1078  // get channel
1079  BCMTFChannel* channel = fChannelContainer[ichannel];
1080 
1081  // check if channel is active
1082  if (!(channel->GetFlagChannelActive()))
1083  continue;
1084 
1085  // get data histogram
1086  TH1D* hist = channel->GetData()->GetHistogram();
1087 
1088  // check if histogram exists
1089  if (!hist) {
1090  return -1;
1091  }
1092 
1093  // get number of bins in data
1094  int nbins = hist->GetNbinsX();
1095 
1096  // loop over all bins
1097  for (int ibin = 0; ibin < nbins; ++ibin) {
1098  // get expectation value
1099  expectation.push_back(Expectation(ichannel, ibin + 1, parameters));
1100 
1101  // get observation
1102  observation.push_back(unsigned(hist->GetBinContent(ibin + 1)));
1103  }
1104  }
1105 
1106  // create pseudo experiments
1107  static const unsigned nIterations = unsigned(1e5);
1108  fPValue = BCMath::FastPValue(observation, expectation, nIterations, fRandom.GetSeed());
1109 
1110  return fPValue;
1111 }
1112 
1113 // ---------------------------------------------------------
1114 double BCMTF::LogLikelihood(const std::vector<double>& parameters)
1115 {
1116  double logprob = 0.;
1117 
1118  // loop over all channels
1119  for (int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1120 
1121  // get channel
1122  BCMTFChannel* channel = fChannelContainer[ichannel];
1123 
1124  // check if channel is active
1125  if (!(channel->GetFlagChannelActive()))
1126  continue;
1127 
1128  // get data
1129  BCMTFTemplate* data = channel->GetData();
1130 
1131  // get histogram
1132  TH1D* hist = data->GetHistogram();
1133 
1134  // check if histogram exists
1135  if (!hist)
1136  continue;
1137 
1138  // get number of bins in data
1139  int nbins = data->GetNBins();
1140 
1141  // loop over all bins
1142  for (int ibin = 1; ibin <= nbins; ++ibin) {
1143 
1144  // get expectation value
1145  double expectation = Expectation(ichannel, ibin, parameters);
1146 
1147  // get observation
1148  double observation = hist->GetBinContent(ibin);
1149 
1150  // add Poisson term
1151  logprob += BCMath::LogPoisson(observation, expectation);
1152  }
1153  }
1154 
1155  return logprob;
1156 }
1157 
1158 // ---------------------------------------------------------
1160 {
1161  // loop over all channels
1162  for (int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1163 
1164  // get channel
1165  BCMTFChannel* channel = fChannelContainer[ichannel];
1166 
1167  // check if channel is active
1168  if (!(channel->GetFlagChannelActive()))
1169  continue;
1170 
1171  // get data
1172  BCMTFTemplate* data = channel->GetData();
1173 
1174  // get histogram
1175  TH1D* hist_data = data->GetHistogram();
1176 
1177  // check if histogram exists
1178  if (!hist_data)
1179  continue;
1180 
1181  // get histogram for uncertainty band
1182  TH2D* hist_uncbandexp = channel->GetHistUncertaintyBandExpectation();
1183 
1184  // check if histogram exists
1185  if (!hist_uncbandexp)
1186  continue;
1187 
1188  // get number of bins in data
1189  int nbins = hist_data->GetNbinsX();
1190 
1191  // loop over all bins
1192  for (int ibin = 1; ibin <= nbins; ++ibin) {
1193 
1194  // get expectation value
1195  double expectation = Expectation(ichannel, ibin, Getx(0));
1196 
1197  // fill uncertainty band on expectation
1198  hist_uncbandexp->Fill(hist_data->GetBinCenter(ibin), expectation);
1199  }
1200  }
1201 
1202 }
1203 
1204 // ---------------------------------------------------------
void SetTemplate(const std::string &channelname, const std::string &processname, TH1D hist, double efficiency=1., double norm=1.)
Set the template for a specific process in a particular channel.
Definition: BCMTF.cxx:92
BCIntegrate::BCMarginalizationMethod GetMarginalizationMethod() const
Definition: BCIntegrate.h:274
int GetHistogramLineStyle() const
Definition: BCMTFProcess.h:71
void SetFunctionContainer(std::vector< TF1 * > *funccont, int nbins)
Set a function container funccont The function container nbins The number of bins (and functions) ...
A class describing a template.
Definition: BCMTFTemplate.h:32
int GetHistogramColor() const
Definition: BCMTFProcess.h:61
double CalculatePValue(int channelindex, const std::vector< double > &parameters)
Calculates and returns the fast p-value for the total likelihood as test statistic.
Definition: BCMTF.cxx:1033
int GetNChannels() const
Definition: BCMTF.h:61
void AddTemplate(BCMTFTemplate *bctemplate)
Add a template.
Definition: BCMTFChannel.h:168
bool GetFlagChannelActive()
Definition: BCMTFChannel.h:88
void SetHistUncertaintyBandExpectation(TH2D *hist)
Set a histogram ued for the calculation of the error band of the expectation.
T * OwnClone(const T *o)
Create a clone of the input but avoid registering the object with ROOT so it cannot be deleted twice...
Definition: BCAux.h:189
virtual bool AddParameter(const std::string &name, double min, double max, const std::string &latexname="", const std::string &unitstring="")
double FastPValue(const std::vector< unsigned > &observed, const std::vector< double > &expected, unsigned nIterations=1e5, unsigned seed=0)
Calculate the p value using fast MCMC for a histogram and the likelihood as test statistic.
Definition: BCMath.cxx:310
int GetNProcesses() const
Definition: BCMTF.h:66
void SetSystematicVariation(const std::string &channelname, const std::string &processname, const std::string &systematicname, double variation_up, double variation_down)
Set the impact of a source of systematic uncertainty for a particular source of systematic uncertaint...
Definition: BCMTF.cxx:386
A guard object to prevent ROOT from taking over ownership of TNamed objects.
Definition: BCAux.h:171
double ExpectationFunction(int parindex, int channelindex, int processindex, const std::vector< double > &parameters)
Return the function value of the expectation function for a parameter, channel and process...
Definition: BCMTF.cxx:557
double GetEfficiency()
Definition: BCMTFTemplate.h:66
The base class for all user-defined models.
Definition: BCModel.h:39
void SetHistogram(TH1D *hist, double norm=1)
Set the histogram.
~BCMTF()
The default destructor.
Definition: BCMTF.cxx:44
int GetHistogramFillStyle() const
Definition: BCMTFProcess.h:66
double GetRangeYMin()
Definition: BCMTFChannel.h:106
void AddSystematicVariation(BCMTFSystematicVariation *variation)
Add a systematic variation.
Definition: BCMTFChannel.h:174
BCMTFTemplate * GetTemplate(int index)
Return a template.
Definition: BCMTFChannel.h:76
int GetParIndexProcess(int index) const
Definition: BCMTF.h:92
void MCMCUserIterationInterface()
Method executed for every iteration of the MCMC.
Definition: BCMTF.cxx:1159
BCMTFSystematicVariation * GetSystematicVariation(int index)
Return a systematic variation.
Definition: BCMTFChannel.h:83
double Expectation(int channelindex, int binindex, const std::vector< double > &parameters)
Return the expected number of events for a channel and bin.
Definition: BCMTF.cxx:528
double Efficiency(int channelindex, int processindex, int binindex, const std::vector< double > &parameters)
Return the efficiency for a process in a channel and for a particular bin.
Definition: BCMTF.cxx:575
A class describing a process.
Definition: BCMTFProcess.h:29
void SetEfficiency(double eff)
Set the efficiency.
void AddHistograms(TH1D *hist_up, TH1D *hist_down)
Add a histograms for up- and down-scale variations.
TH2D * GetHistUncertaintyBandExpectation()
Return a histogram ued for the calculation of the error band of the expectation.
Definition: BCMTFChannel.h:95
void SetRangeY(double min, double max)
Set the y-ranges for printing.
Definition: BCMTFChannel.h:154
double Probability(int channelindex, int processindex, int binindex, const std::vector< double > &parameters)
Return the probability for a process in a channel and for a particular bin.
Definition: BCMTF.cxx:623
const std::string & GetName() const
Definition: BCMTFProcess.h:51
TH1D * GetHistogram()
Definition: BCMTFTemplate.h:71
double CalculateCash(int channelindex, const std::vector< double > &parameters)
Calculate the Cash statistic for a single channel.
Definition: BCMTF.cxx:969
void AddProcess(const std::string &name, double nmin=0., double nmax=1., int color=-1, int fillstyle=-1, int linestyle=-1)
Add a process and the associated BAT parameter.
Definition: BCMTF.cxx:289
const std::string & GetName() const
Definition: BCEngineMCMC.h:269
TH1D * GetHistogramUp(int index)
Returns the histogram correponding to the up-scale variation of the systematic.
void PrintStack(int channelindex, const std::vector< double > &parameters, const std::string &filename="stack.pdf", const std::string &options="e1b0stack")
Print the stack of templates together with the data in a particular channel.
Definition: BCMTF.cxx:644
int GetNSystematics() const
Definition: BCMTF.h:71
int GetParIndexSystematic(int index) const
Definition: BCMTF.h:98
int GetChannelIndex(const std::string &name) const
Definition: BCMTF.cxx:52
A class describing a physics channel.
Definition: BCMTFChannel.h:36
void SetHistograms(int index, TH1D *hist_up, TH1D *hist_down)
Set the histograms correponding to the up- and down-scale variations of the systematic.
const std::vector< double > & Getx(unsigned c) const
Definition: BCEngineMCMC.h:370
double GetRangeYMax()
Definition: BCMTFChannel.h:111
int GetProcessIndex(const std::string &name) const
Definition: BCMTF.cxx:65
void CalculateHistUncertaintyBandPoisson()
Calculate histogram for uncertainty band calculation.
const std::string & GetSafeName() const
Definition: BCEngineMCMC.h:274
void SetData(const std::string &channelname, TH1D hist, double minimum=-1, double maximum=-1)
Set the data histogram in a particular channel.
Definition: BCMTF.cxx:177
TRandom3 fRandom
Random number generator.
BCMTFTemplate * GetData()
Definition: BCMTFChannel.h:69
TH1D * GetHistogramDown(int index)
Returns the histogram correponding to the down-scale variation of the systematic. ...
void SetHistogramColor(int color)
Set the histogram color.
Definition: BCMTFProcess.h:88
double LogPoisson(double x, double lambda)
Calculate the natural logarithm of a poisson distribution.
Definition: BCMath.cxx:53
void PrintFitSummary()
Print a summary of the fit to the log.
Definition: BCMTF.cxx:495
BCMTFChannel * GetChannel(int index)
Definition: BCMTF.h:104
BCMTF(const std::string &name="multi_template_fitter")
A constructor.
Definition: BCMTF.cxx:35
void SetData(BCMTFTemplate *bctemplate)
Set the data set.
Definition: BCMTFChannel.h:127
const std::string & GetName() const
Definition: BCMTFChannel.h:59
BCMTFProcess * GetProcess(int index)
Definition: BCMTF.h:113
int GetSystematicIndex(const std::string &name) const
Definition: BCMTF.cxx:78
void AddChannel(const std::string &name)
Add a channel.
Definition: BCMTF.cxx:245
void SetHistogramLineStyle(int style)
Set the histogram line style.
Definition: BCMTFProcess.h:100
std::vector< TF1 * > * GetFunctionContainer()
Definition: BCMTFTemplate.h:97
double CalculateChi2(int channelindex, const std::vector< double > &parameters)
Calculate a chi2 for a single channel given a set of parameters.
Definition: BCMTF.cxx:910
void AddSystematic(const std::string &name, double min=-5., double max=5.)
Add a source of systematic uncertainty and the associated BAT (nuisance) parameter.
Definition: BCMTF.cxx:343
Metropolis Hastings.
Definition: BCIntegrate.h:178
void SetHistUncertaintyBandPoisson(TH2D *hist)
Set a histogram used for the calculation of the Poisson fluctuations.
Definition: BCMTFChannel.h:139
TH1D * CalculateUncertaintyBandPoisson(double minimum, double maximum, int color)
Calculate histogram for uncertainty band calculation and return a TH1D.
unsigned GetNParameters() const
Definition: BCEngineMCMC.h:656
double LogLikelihood(const std::vector< double > &parameters)
Calculate natural logarithm of the likelihood.
Definition: BCMTF.cxx:1114
void SetHistogramFillStyle(int style)
Set the histogram fill style.
Definition: BCMTFProcess.h:94
virtual const std::vector< double > & GetBestFitParameters() const
A class desribing a systematic uncertainty.
A class describing a systematic variation.