21 #include <TGraphAsymmErrors.h> 23 #include "../../BAT/BCMath.h" 24 #include "../../BAT/BCLog.h" 26 #include "BCMTFChannel.h" 27 #include "BCMTFProcess.h" 28 #include "BCMTFTemplate.h" 29 #include "BCMTFSystematic.h" 30 #include "BCMTFSystematicVariation.h" 40 , fFlagEfficiencyConstraint(false)
47 for (
int i = 0; i < fNChannels; ++i)
48 delete fChannelContainer.at(i);
55 for (
int i = 0; i < fNChannels; ++i)
57 if (fChannelContainer[i]->
GetName().compare(name) == 0)
68 for (
int i = 0; i < fNProcesses; ++i)
70 if (fProcessContainer[i]->
GetName().compare(name) == 0)
81 for (
int i = 0; i < fNSystematics; ++i) {
83 if (fSystematicContainer[i]->
GetName().compare(name) == 0)
92 void BCMTF::SetTemplate(
const std::string& channelname,
const std::string& processname, TH1D hist,
double efficiency,
double norm)
98 if (channelindex < 0) {
99 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
106 if (processindex < 0) {
107 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
117 hist.SetStats(kFALSE);
121 color = 2 + processindex;
130 hist.SetFillColor(color);
131 hist.SetFillStyle(fillstyle);
132 hist.SetLineStyle(linestyle);
145 void BCMTF::SetTemplate(
const std::string& channelname,
const std::string& processname, std::vector<TF1*>* funccont,
int nbins,
double efficiency)
151 if (channelindex < 0) {
152 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
159 if (processindex < 0) {
160 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
177 void BCMTF::SetData(
const std::string& channelname, TH1D hist,
double minimum,
double maximum)
182 if (channelindex < 0) {
183 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
193 hist.SetStats(kFALSE);
196 hist.SetMarkerStyle(20);
197 hist.SetMarkerSize(1.1);
200 hist.SetNdivisions(509);
212 maximum = ceil(hist.GetMaximum() + 5.*sqrt(hist.GetMaximum()));
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);
222 TH2D* hist_uncbandexp, *hist_uncbandpoisson;
226 hist_copy =
new TH1D(hist);
228 hist_uncbandexp =
new TH2D(Form(
"UncertaintyBandExpectation_%s_%d",
GetSafeName().data(), channelindex),
"", hist.GetNbinsX(), &a[0], 1000, minimum, maximum);
229 hist_uncbandexp->SetStats(kFALSE);
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);
248 for (
int i = 0; i < fNChannels; ++i) {
251 throw std::runtime_error(
"BCMultitemplateFitter::AddChannel() : Channel with this name exists already.");
265 for (
int i = 0; i < fNProcesses; ++i) {
277 for (
int i = 0; i < fNSystematics; ++i)
282 fChannelContainer.push_back(channel);
289 void BCMTF::AddProcess(
const std::string& name,
double nmin,
double nmax,
int color,
int fillstyle,
int linestyle)
292 for (
int i = 0; i < fNProcesses; ++i) {
295 throw std::runtime_error(
"BCMultitemplateFitter::AddProcess() : Process with this name exists already.");
306 fProcessContainer.push_back(process);
309 for (
int i = 0; i < fNChannels; ++i) {
320 for (
int j = 0; j < fNSystematics; ++j) {
339 fExpectationFunctionContainer.push_back(0);
346 for (
int i = 0; i < fNSystematics; ++i) {
349 throw std::runtime_error(
"BCMultitemplateFitter::AddSystematic() : Systematic with this name exists already.");
357 fSystematicContainer.push_back(systematic);
360 for (
int i = 0; i < fNChannels; ++i) {
382 fExpectationFunctionContainer.push_back(0);
386 void BCMTF::SetSystematicVariation(
const std::string& channelname,
const std::string& processname,
const std::string& systematicname,
double variation_up,
double variation_down)
393 if (channelindex < 0) {
394 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
401 if (processindex < 0) {
402 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
409 if (systematicindex < 0) {
410 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Systematic does not exist.");
420 TH1D hist_up = TH1D(*hist_template);
421 TH1D hist_down = TH1D(*hist_template);
423 int nbins = hist_up.GetNbinsX();
426 for (
int ibin = 1; ibin <= nbins; ++ibin) {
427 hist_up.SetBinContent(ibin, variation_up);
428 hist_down.SetBinContent(ibin, variation_down);
435 variation->
SetHistograms(processindex,
new TH1D(hist_up),
new TH1D(hist_down));
439 void BCMTF::SetSystematicVariation(
const std::string& channelname,
const std::string& processname,
const std::string& systematicname, TH1D hist_up, TH1D hist_down)
445 if (channelindex < 0) {
446 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
453 if (processindex < 0) {
454 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
461 if (systematicindex < 0) {
462 throw std::runtime_error(
"BCMultitemplateFitter::SetTemplate() : Systematic does not exist.");
472 variation->
SetHistograms(processindex,
new TH1D(hist_up),
new TH1D(hist_down));
476 void BCMTF::SetSystematicVariation(
const std::string& channelname,
const std::string& processname,
const std::string& systematicname, TH1D hist, TH1D hist_up, TH1D hist_down)
479 int nbins = hist.GetNbinsX();
481 TH1D* hist_up_rel =
new TH1D(hist);
482 TH1D* hist_down_rel =
new TH1D(hist);
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));
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(
"");
504 BCLog::OutSummary(
" Channels :");
506 BCLog::OutSummary(Form(
" %d : \"%s\"", i, fChannelContainer[i]->
GetName().data()));
507 BCLog::OutSummary(
"");
509 BCLog::OutSummary(
" Processes :");
511 BCLog::OutSummary(Form(
" %d : \"%s\" (par index %d)", i, fProcessContainer[i]->
GetName().data(),
GetParIndexProcess(i)));
512 BCLog::OutSummary(
"");
514 BCLog::OutSummary(
" Systematics :");
518 BCLog::OutSummary(
" - none - ");
519 BCLog::OutSummary(
"");
521 BCLog::OutSummary(
" Goodness-of-fit: ");
524 BCLog::OutSummary(
"");
530 double expectation = 0.;
533 for (
int i = 0; i < fNProcesses; ++i) {
535 double efficiency =
Efficiency(channelindex, i, binindex, parameters);
538 double probability =
Probability(channelindex, i, binindex, parameters);
541 int parindex = fProcessParIndexContainer[i];
560 std::vector<TF1*>* funccont = fChannelContainer[channelindex]->GetTemplate(processindex)->GetFunctionContainer();
562 if (funccont->size() > 0)
565 else if (!fExpectationFunctionContainer[parindex])
566 return parameters[parindex];
569 TF1* func = fExpectationFunctionContainer[parindex];
570 return func->Eval(parameters[parindex]);
575 double BCMTF::Efficiency(
int channelindex,
int processindex,
int binindex,
const std::vector<double>& parameters)
578 BCMTFChannel* channel = fChannelContainer[channelindex];
582 double defficiency = 1.;
585 for (
int i = 0; i < fNSystematics; ++i) {
586 if (!(fSystematicContainer[i]->GetFlagSystematicActive()))
590 int parindex = fSystematicParIndexContainer[i];
595 if (parameters[parindex] > 0)
605 defficiency += parameters[parindex] * hist->GetBinContent(binindex);
609 efficiency *= defficiency;
612 if (fFlagEfficiencyConstraint) {
623 double BCMTF::Probability(
int channelindex,
int processindex,
int binindex,
const std::vector<double>& parameters)
626 TH1D* hist = fChannelContainer[channelindex]->GetTemplate(processindex)->GetHistogram();
629 std::vector<TF1*>* funccont = fChannelContainer[channelindex]->GetTemplate(processindex)->GetFunctionContainer();
632 if (!hist && !(funccont->size() > 0))
636 return hist->GetBinContent(binindex);
638 int parindex = fProcessParIndexContainer[processindex];
639 return funccont->at(binindex - 1)->Eval(parameters[parindex]);
644 void BCMTF::PrintStack(
int channelindex,
const std::vector<double>& parameters,
const std::string& filename,
const std::string& options)
647 if (parameters.empty())
651 bool flag_logx =
false;
652 bool flag_logy =
false;
653 bool flag_bw =
false;
655 bool flag_sum =
false;
656 bool flag_stack =
false;
658 bool flag_e0 =
false;
659 bool flag_e1 =
false;
661 bool flag_b0 =
false;
662 bool flag_b1 =
false;
664 if (options.find(
"logx") < options.size())
667 if (options.find(
"logy") < options.size())
670 if (options.find(
"bw") < options.size())
673 if (options.find(
"sum") < options.size())
676 if (options.find(
"stack") < options.size())
679 if (options.find(
"e0") < options.size())
682 if (options.find(
"e1") < options.size())
685 if (options.find(
"b0") < options.size())
688 if (options.find(
"b1") < options.size())
698 BCLog::OutWarning(
"BCMTF::PrintStack : Did not run MCMC. Error bands are not available.");
705 TCanvas* c1 =
new TCanvas();
719 int nbins = hist_data->GetNbinsX();
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);
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);
735 TGraphAsymmErrors* graph_error_exp =
new TGraphAsymmErrors(nbins);
737 graph_error_exp->SetMarkerStyle(0);
738 graph_error_exp->SetFillColor(kBlack);
739 graph_error_exp->SetFillStyle(3005);
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());
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]));
762 THStack* stack =
new THStack(
"",
"");
765 std::vector<TH1D*> histcontainer;
771 for (
unsigned int i = 0; i < ntemplates; ++i) {
783 hist =
new TH1D( *(temphist) );
801 hist->SetFillColor(color);
802 hist->SetFillStyle(fillstyle);
803 hist->SetLineStyle(linestyle);
806 hist->SetFillColor(0);
810 for (
int ibin = 1; ibin <= nbins; ++ibin) {
813 double efficiency =
Efficiency(channelindex, i, ibin, parameters);
816 double probability =
Probability(channelindex, i, ibin, parameters);
822 double expectation = parameters[parindex] * efficiency * probability;
825 hist->SetBinContent(ibin, expectation);
828 hist_sum->SetBinContent(ibin, hist_sum->GetBinContent(ibin) + expectation);
832 histcontainer.push_back(hist);
839 hist_data->Draw(
"P0");
845 ymax = hist_data->GetMaximum() + sqrt(hist_data->GetMaximum());
847 ymax = hist_data->GetMaximum();
854 stack->Draw(
"SAMEHIST");
855 if (stack->GetMaximum() > ymax)
856 ymax = stack->GetMaximum();
863 hist_temp->Draw(
"SAMEE2");
868 int ymaxbin = hist_temp->GetMaximumBin();
870 if (hist_temp->GetBinContent(ymaxbin) + hist_temp->GetBinError(ymaxbin) > ymax)
871 ymax = hist_temp->GetBinContent(ymaxbin) + hist_temp->GetBinError(ymaxbin);
876 hist_error_band->Draw(
"SAMEE2");
880 hist_sum->Draw(
"SAME");
884 hist_data->Draw(
"SAMEP0");
887 hist_data->Draw(
"SAMEP0E");
889 hist_data->GetYaxis()->SetRangeUser(0., 1.1 * ymax);
895 c1->Print(filename.data());
898 for (
unsigned int i = 0; i < histcontainer.size(); ++i) {
899 TH1D* hist = histcontainer.at(i);
904 delete graph_error_exp;
905 delete hist_error_band;
912 if (parameters.empty())
929 int nbins = hist->GetNbinsX();
932 for (
int ibin = 1; ibin <= nbins; ++ibin) {
934 double expectation =
Expectation(channelindex, ibin, parameters);
937 double observation = hist->GetBinContent(ibin);
940 chi2 += (expectation - observation) * (expectation - observation) / expectation;
951 if (parameters.empty())
960 for (
int i = 0; i < nchannels; ++i) {
971 if (parameters.empty())
988 int nbins = hist->GetNbinsX();
991 for (
int ibin = 1; ibin <= nbins; ++ibin) {
993 double expectation =
Expectation(channelindex, ibin, parameters);
996 double observation = hist->GetBinContent(ibin);
999 cash += 2. * (expectation - observation);
1002 if (observation > 0)
1003 cash += 2. * observation * log (observation / expectation);
1015 if (parameters.empty())
1024 for (
int i = 0; i < nchannels; ++i) {
1047 int nbins = hist->GetNbinsX();
1050 std::vector<unsigned> observation(nbins);
1051 std::vector<double> expectation(nbins);
1054 for (
int ibin = 0; ibin < nbins; ++ibin) {
1056 expectation[ibin] =
Expectation(channelindex, ibin + 1, parameters);
1059 observation[ibin] = unsigned(hist->GetBinContent(ibin + 1));
1063 static const unsigned nIterations = unsigned (1e5);
1072 std::vector<unsigned> observation;
1073 std::vector<double> expectation;
1076 for (
int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1094 int nbins = hist->GetNbinsX();
1097 for (
int ibin = 0; ibin < nbins; ++ibin) {
1099 expectation.push_back(
Expectation(ichannel, ibin + 1, parameters));
1102 observation.push_back(
unsigned(hist->GetBinContent(ibin + 1)));
1107 static const unsigned nIterations = unsigned(1e5);
1116 double logprob = 0.;
1119 for (
int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1142 for (
int ibin = 1; ibin <= nbins; ++ibin) {
1145 double expectation =
Expectation(ichannel, ibin, parameters);
1148 double observation = hist->GetBinContent(ibin);
1162 for (
int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1185 if (!hist_uncbandexp)
1189 int nbins = hist_data->GetNbinsX();
1192 for (
int ibin = 1; ibin <= nbins; ++ibin) {
1198 hist_uncbandexp->Fill(hist_data->GetBinCenter(ibin), expectation);
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.
BCIntegrate::BCMarginalizationMethod GetMarginalizationMethod() const
int GetHistogramLineStyle() const
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.
int GetHistogramColor() const
double CalculatePValue(int channelindex, const std::vector< double > ¶meters)
Calculates and returns the fast p-value for the total likelihood as test statistic.
void AddTemplate(BCMTFTemplate *bctemplate)
Add a template.
bool GetFlagChannelActive()
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...
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.
int GetNProcesses() const
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...
A guard object to prevent ROOT from taking over ownership of TNamed objects.
double ExpectationFunction(int parindex, int channelindex, int processindex, const std::vector< double > ¶meters)
Return the function value of the expectation function for a parameter, channel and process...
The base class for all user-defined models.
void SetHistogram(TH1D *hist, double norm=1)
Set the histogram.
~BCMTF()
The default destructor.
int GetHistogramFillStyle() const
void AddSystematicVariation(BCMTFSystematicVariation *variation)
Add a systematic variation.
BCMTFTemplate * GetTemplate(int index)
Return a template.
int GetParIndexProcess(int index) const
void MCMCUserIterationInterface()
Method executed for every iteration of the MCMC.
BCMTFSystematicVariation * GetSystematicVariation(int index)
Return a systematic variation.
double Expectation(int channelindex, int binindex, const std::vector< double > ¶meters)
Return the expected number of events for a channel and bin.
double Efficiency(int channelindex, int processindex, int binindex, const std::vector< double > ¶meters)
Return the efficiency for a process in a channel and for a particular bin.
A class describing a process.
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.
void SetRangeY(double min, double max)
Set the y-ranges for printing.
double Probability(int channelindex, int processindex, int binindex, const std::vector< double > ¶meters)
Return the probability for a process in a channel and for a particular bin.
const std::string & GetName() const
double CalculateCash(int channelindex, const std::vector< double > ¶meters)
Calculate the Cash statistic for a single channel.
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.
const std::string & GetName() const
TH1D * GetHistogramUp(int index)
Returns the histogram correponding to the up-scale variation of the systematic.
void PrintStack(int channelindex, const std::vector< double > ¶meters, const std::string &filename="stack.pdf", const std::string &options="e1b0stack")
Print the stack of templates together with the data in a particular channel.
int GetNSystematics() const
int GetParIndexSystematic(int index) const
int GetChannelIndex(const std::string &name) const
A class describing a physics channel.
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
int GetProcessIndex(const std::string &name) const
void CalculateHistUncertaintyBandPoisson()
Calculate histogram for uncertainty band calculation.
const std::string & GetSafeName() const
void SetData(const std::string &channelname, TH1D hist, double minimum=-1, double maximum=-1)
Set the data histogram in a particular channel.
TRandom3 fRandom
Random number generator.
BCMTFTemplate * GetData()
TH1D * GetHistogramDown(int index)
Returns the histogram correponding to the down-scale variation of the systematic. ...
void SetHistogramColor(int color)
Set the histogram color.
double LogPoisson(double x, double lambda)
Calculate the natural logarithm of a poisson distribution.
void PrintFitSummary()
Print a summary of the fit to the log.
BCMTFChannel * GetChannel(int index)
BCMTF(const std::string &name="multi_template_fitter")
A constructor.
void SetData(BCMTFTemplate *bctemplate)
Set the data set.
const std::string & GetName() const
BCMTFProcess * GetProcess(int index)
int GetSystematicIndex(const std::string &name) const
void AddChannel(const std::string &name)
Add a channel.
void SetHistogramLineStyle(int style)
Set the histogram line style.
std::vector< TF1 * > * GetFunctionContainer()
double CalculateChi2(int channelindex, const std::vector< double > ¶meters)
Calculate a chi2 for a single channel given a set of parameters.
void AddSystematic(const std::string &name, double min=-5., double max=5.)
Add a source of systematic uncertainty and the associated BAT (nuisance) parameter.
void SetHistUncertaintyBandPoisson(TH2D *hist)
Set a histogram used for the calculation of the Poisson fluctuations.
TH1D * CalculateUncertaintyBandPoisson(double minimum, double maximum, int color)
Calculate histogram for uncertainty band calculation and return a TH1D.
unsigned GetNParameters() const
double LogLikelihood(const std::vector< double > ¶meters)
Calculate natural logarithm of the likelihood.
void SetHistogramFillStyle(int style)
Set the histogram fill style.
virtual const std::vector< double > & GetBestFitParameters() const
A class desribing a systematic uncertainty.
A class describing a systematic variation.