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"
36 :
BCModel(
"Multi-template Fitter")
40 , fFlagEfficiencyConstraint(false)
49 , fFlagEfficiencyConstraint(false)
56 for (
int i = 0; i < fNChannels; ++i)
57 delete fChannelContainer.at(i);
64 for (
int i = 0; i < fNChannels; ++i) {
69 if (!channel->
GetName().compare(name))
81 for (
int i = 0; i < fNProcesses; ++i) {
86 if (!process->
GetName().compare(name))
98 for (
int i = 0; i < fNSystematics; ++i) {
103 if (!systematic->
GetName().compare(name))
112 int BCMTF::SetTemplate(
const char * channelname,
const char * processname, TH1D hist,
double efficiency,
double norm)
118 if (channelindex < 0) {
119 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
127 if (processindex < 0) {
128 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
139 hist.SetStats(kFALSE);
143 color = 2 + processindex;
152 hist.SetFillColor(color);
153 hist.SetFillStyle(fillstyle);
154 hist.SetLineStyle(linestyle);
157 TH1D * temphist =
new TH1D(hist);
170 int BCMTF::SetTemplate(
const char * channelname,
const char * processname, std::vector<TF1 *> * funccont,
int nbins,
double efficiency)
176 if (channelindex < 0) {
177 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
185 if (processindex < 0) {
186 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
207 int BCMTF::SetData(
const char * channelname, TH1D hist,
double minimum,
double maximum)
212 if (channelindex < 0) {
213 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
224 hist.SetStats(kFALSE);
227 hist.SetMarkerStyle(20);
228 hist.SetMarkerSize(1.1);
231 hist.SetNdivisions(509);
254 maximum = ceil(hist.GetMaximum() + 5.*sqrt(hist.GetMaximum()));
256 std::vector<double> a(hist.GetNbinsX()+1);
257 for (
int i = 0; i < hist.GetNbinsX()+1; ++i) {
258 a[i] = hist.GetXaxis()->GetBinLowEdge(i+1);
261 TH2D* hist_uncbandexp =
new TH2D(TString::Format(
"UncertaintyBandExpectation_%i",
BCLog::GetHIndex()),
"",
262 hist.GetNbinsX(), &a[0], 1000, minimum, maximum);
263 hist_uncbandexp->SetStats(kFALSE);
265 TH2D* hist_uncbandpoisson =
new TH2D(TString::Format(
"UncertaintyBandPoisson_%i",
BCLog::GetHIndex()),
"",
266 hist.GetNbinsX(), &a[0], int(maximum-minimum), minimum, maximum);
267 hist_uncbandpoisson->SetStats(kFALSE);
285 for (
int i = 0; i < fNChannels; ++i) {
288 BCLog::OutWarning(
"BCMultitemplateFitter::AddChannel() : Channel with this name exists already.");
303 for (
int i = 0; i < fNProcesses; ++i) {
315 for (
int i = 0; i < fNSystematics; ++i) {
327 fChannelContainer.push_back(channel);
337 int BCMTF::AddProcess(
const char * name,
double nmin,
double nmax,
int color,
int fillstyle,
int linestyle)
340 for (
int i = 0; i < fNProcesses; ++i) {
343 BCLog::OutWarning(
"BCMultitemplateFitter::AddProcess() : Process with this name exists already.");
355 fProcessContainer.push_back(process);
358 for (
int i = 0; i < fNChannels; ++i) {
369 for (
int j = 0; j < fNSystematics; ++j) {
382 fProcessParIndexContainer.push_back(GetNParameters());
388 fExpectationFunctionContainer.push_back(0);
398 for (
int i = 0; i < fNSystematics; ++i) {
401 BCLog::OutWarning(
"BCMultitemplateFitter::AddSystematic() : Systematic with this name exists already.");
410 fSystematicContainer.push_back(systematic);
413 for (
int i = 0; i < fNChannels; ++i) {
429 fSystematicParIndexContainer.push_back(GetNParameters());
435 fExpectationFunctionContainer.push_back(0);
442 int BCMTF::SetSystematicVariation(
const char * channelname,
const char * processname,
const char * systematicname,
double variation_up,
double variation_down)
449 if (channelindex < 0) {
450 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
458 if (processindex < 0) {
459 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
467 if (systematicindex < 0) {
468 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Systematic does not exist.");
479 TH1D hist_up = TH1D(*hist_template);
480 TH1D hist_down = TH1D(*hist_template);
482 int nbins = hist_up.GetNbinsX();
485 for (
int ibin = 1; ibin <= nbins; ++ibin) {
486 hist_up.SetBinContent(ibin, variation_up);
487 hist_down.SetBinContent(ibin, variation_down);
494 variation->
SetHistograms(processindex,
new TH1D(hist_up),
new TH1D(hist_down));
507 if (channelindex < 0) {
508 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Channel does not exist.");
516 if (processindex < 0) {
517 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Process does not exist.");
525 if (systematicindex < 0) {
526 BCLog::OutWarning(
"BCMultitemplateFitter::SetTemplate() : Systematic does not exist.");
537 variation->
SetHistograms(processindex,
new TH1D(hist_up),
new TH1D(hist_down));
547 int nbins = hist.GetNbinsX();
549 TH1D * hist_up_rel =
new TH1D(hist);
550 TH1D * hist_down_rel =
new TH1D(hist);
553 for (
int ibin = 1; ibin <= nbins; ++ibin) {
554 hist_up_rel->SetBinContent(ibin, (hist_up.GetBinContent(ibin) - hist.GetBinContent(ibin)) / hist.GetBinContent(ibin));
555 hist_down_rel->SetBinContent(ibin, (hist.GetBinContent(ibin) - hist_down.GetBinContent(ibin)) / hist.GetBinContent(ibin));
566 std::ofstream ofi(filename);
571 BCLog::OutWarning(Form(
"BCMultitemplateFitter::PrintSummary() : Could not open file %s", filename));
576 <<
" Multi template fitter summary " << std::endl
577 <<
" ----------------------------- " << std::endl
579 <<
" Number of channels : " << fNChannels << std::endl
580 <<
" Number of processes : " << fNProcesses << std::endl
581 <<
" Number of systematics : " << fNSystematics << std::endl
585 <<
" Channels :" << std::endl;
596 <<
" Processes :" << std::endl;
608 <<
" Systematics :" << std::endl;
620 <<
" - none - " << std::endl;
623 <<
" Goodness-of-fit: " << std::endl;
644 double expectation = 0.;
647 for (
int i = 0; i < fNProcesses; ++i) {
649 double efficiency =
Efficiency(channelindex, i, binindex, parameters);
652 double probability =
Probability(channelindex, i, binindex, parameters);
655 int parindex = fProcessParIndexContainer[i];
674 std::vector<TF1 *> * funccont = fChannelContainer[channelindex]->GetTemplate(processindex)->GetFunctionContainer();
676 if (funccont->size()>0)
679 else if (!fExpectationFunctionContainer[parindex])
680 return parameters[parindex];
683 TF1 * func = fExpectationFunctionContainer[parindex];
684 return func->Eval(parameters[parindex]);
689 double BCMTF::Efficiency(
int channelindex,
int processindex,
int binindex,
const std::vector<double> & parameters)
692 BCMTFChannel * channel = fChannelContainer[channelindex];
696 double defficiency = 1.;
699 for (
int i = 0; i < fNSystematics; ++i) {
700 if (!(fSystematicContainer[i]->GetFlagSystematicActive()))
704 int parindex = fSystematicParIndexContainer[i];
709 if (parameters[parindex] > 0)
719 defficiency += parameters[parindex] * hist->GetBinContent(binindex);
723 efficiency *= defficiency;
726 if (fFlagEfficiencyConstraint) {
737 double BCMTF::Probability(
int channelindex,
int processindex,
int binindex,
const std::vector<double> & parameters)
740 TH1D * hist = fChannelContainer[channelindex]->GetTemplate(processindex)->GetHistogram();
743 std::vector<TF1 *> * funccont = fChannelContainer[channelindex]->GetTemplate(processindex)->GetFunctionContainer();
746 if (!hist && !(funccont->size()>0))
750 return hist->GetBinContent(binindex);
752 int parindex = fProcessParIndexContainer[processindex];
753 return funccont->at(binindex-1)->Eval(parameters[parindex]);
758 int BCMTF::PrintStack(
const char * channelname,
const std::vector<double> & parameters,
const char * filename,
const char * options)
762 return PrintStack(index, parameters, filename, options);
766 int BCMTF::PrintStack(
int channelindex,
const std::vector<double> & parameters,
const char * filename,
const char * options)
773 if (!parameters.size())
777 bool flag_logx =
false;
778 bool flag_logy =
false;
779 bool flag_bw =
false;
781 bool flag_sum =
false;
782 bool flag_stack =
false;
784 bool flag_e0 =
false;
785 bool flag_e1 =
false;
787 bool flag_b0 =
false;
788 bool flag_b1 =
false;
790 if (std::string(options).find(
"logx") < std::string(options).size())
793 if (std::string(options).find(
"logy") < std::string(options).size())
796 if (std::string(options).find(
"bw") < std::string(options).size())
799 if (std::string(options).find(
"sum") < std::string(options).size())
802 if (std::string(options).find(
"stack") < std::string(options).size())
805 if (std::string(options).find(
"e0") < std::string(options).size())
808 if (std::string(options).find(
"e1") < std::string(options).size())
811 if (std::string(options).find(
"b0") < std::string(options).size())
814 if (std::string(options).find(
"b1") < std::string(options).size())
821 if (!(GetMarginalizationMethod() == BCIntegrate::kMargMetropolis)) {
824 BCLog::OutWarning(
"BCMTF::PrintStack : Did not run MCMC. Error bands are not available.");
831 TCanvas * c1 =
new TCanvas();
845 int nbins = hist_data->GetNbinsX();
848 TH1D* hist_sum =
new TH1D(*hist_data);
849 hist_sum->SetLineColor(kBlack);
850 for (
int i = 1; i <= nbins; ++i)
851 hist_sum->SetBinContent(i, 0);
854 TH1D* hist_error_band =
new TH1D(*hist_data);
855 hist_error_band->SetFillColor(kBlack);
856 hist_error_band->SetFillStyle(3005);
857 hist_error_band->SetLineWidth(1);
858 hist_error_band->SetStats(kFALSE);
859 hist_error_band->SetMarkerSize(0);
861 TGraphAsymmErrors * graph_error_exp =
new TGraphAsymmErrors(nbins);
863 graph_error_exp->SetMarkerStyle(0);
864 graph_error_exp->SetFillColor(kBlack);
865 graph_error_exp->SetFillStyle(3005);
872 for (
int i = 1; i <= nbins; ++i) {
873 TH1D * proj = hist_uncbandexp->ProjectionY(
"_py", i, i);
874 if (proj->Integral() > 0)
875 proj->Scale(1.0 / proj->Integral());
877 double sums[3] = {0.16, 0.5, 0.84};
878 proj->GetQuantiles(3, quantiles, sums);
879 graph_error_exp->SetPoint(i-1, hist_data->GetBinCenter(i), quantiles[1]);
880 graph_error_exp->SetPointError(i-1, 0.0, 0.0, quantiles[1] - quantiles[0], quantiles[2]-quantiles[1]);
881 hist_error_band->SetBinContent(i, 0.5*(quantiles[2]+quantiles[0]));
882 hist_error_band->SetBinError(i, 0, 0.5*(quantiles[2]-quantiles[0]));
888 THStack * stack =
new THStack(
"",
"");
891 std::vector<TH1D *> histcontainer;
897 for (
unsigned int i = 0; i < ntemplates; ++i) {
909 hist =
new TH1D( *(temphist) );
927 hist->SetFillColor(color);
928 hist->SetFillStyle(fillstyle);
929 hist->SetLineStyle(linestyle);
932 hist->SetFillColor(0);
936 for (
int ibin = 1; ibin <= nbins; ++ibin) {
939 double efficiency =
Efficiency(channelindex, i, ibin, parameters);
942 double probability =
Probability(channelindex, i, ibin, parameters);
948 double expectation = parameters[parindex] * efficiency * probability;
951 hist->SetBinContent(ibin, expectation);
954 hist_sum->SetBinContent(ibin, hist_sum->GetBinContent(ibin) + expectation);
958 histcontainer.push_back(hist);
965 hist_data->Draw(
"P0");
971 ymax = hist_data->GetMaximum() + sqrt(hist_data->GetMaximum());
973 ymax = hist_data->GetMaximum();
980 stack->Draw(
"SAMEHIST");
981 if (stack->GetMaximum() > ymax)
982 ymax = stack->GetMaximum();
989 hist_temp->Draw(
"SAMEE2");
994 int ymaxbin = hist_temp->GetMaximumBin();
996 if (hist_temp->GetBinContent(ymaxbin)+hist_temp->GetBinError(ymaxbin)> ymax)
997 ymax = hist_temp->GetBinContent(ymaxbin)+hist_temp->GetBinError(ymaxbin);
1002 hist_error_band->Draw(
"SAMEE2");
1006 hist_sum->Draw(
"SAME");
1010 hist_data->Draw(
"SAMEP0");
1013 hist_data->Draw(
"SAMEP0E");
1015 hist_data->GetYaxis()->SetRangeUser(0., 1.1* ymax);
1021 c1->Print(filename);
1024 for (
unsigned int i = 0; i < histcontainer.size(); ++i) {
1025 TH1D * hist = histcontainer.at(i);
1030 delete graph_error_exp;
1031 delete hist_error_band;
1041 if (parameters.size() == 0)
1058 int nbins = hist->GetNbinsX();
1061 for (
int ibin = 1; ibin <= nbins; ++ibin) {
1063 double expectation =
Expectation(channelindex, ibin, parameters);
1066 double observation = hist->GetBinContent(ibin);
1069 chi2 += (expectation - observation) * (expectation - observation) / expectation;
1080 if (parameters.size() == 0)
1089 for (
int i = 0; i < nchannels; ++i) {
1100 if (parameters.size() == 0)
1117 int nbins = hist->GetNbinsX();
1120 for (
int ibin = 1; ibin <= nbins; ++ibin) {
1122 double expectation =
Expectation(channelindex, ibin, parameters);
1125 double observation = hist->GetBinContent(ibin);
1128 cash += 2. * (expectation - observation);
1131 if (observation > 0)
1132 cash += 2. * observation * log (observation/expectation);
1144 if (parameters.size() == 0)
1153 for (
int i = 0; i < nchannels; ++i) {
1176 int nbins = hist->GetNbinsX();
1179 std::vector<unsigned> observation(nbins);
1180 std::vector<double> expectation(nbins);
1183 for (
int ibin = 0; ibin < nbins; ++ibin) {
1185 expectation[ibin] =
Expectation(channelindex, ibin + 1, parameters);
1188 observation[ibin]= unsigned(hist->GetBinContent(ibin + 1));
1192 static const unsigned nIterations = unsigned (1e5);
1193 return BCMath::FastPValue(observation, expectation, nIterations, fRandom->GetSeed());
1201 std::vector<unsigned> observation;
1202 std::vector<double> expectation;
1205 for (
int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1223 int nbins = hist->GetNbinsX();
1226 for (
int ibin = 0; ibin < nbins; ++ibin) {
1228 expectation.push_back(
Expectation(ichannel, ibin + 1, parameters));
1231 observation.push_back(
unsigned(hist->GetBinContent(ibin + 1)));
1236 static const unsigned nIterations = unsigned(1e5);
1246 double logprob = 0.;
1249 for (
int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1272 for (
int ibin = 1; ibin <= nbins; ++ibin) {
1275 double expectation =
Expectation(ichannel, ibin, parameters);
1278 double observation = hist->GetBinContent(ibin);
1292 for (
int ichannel = 0; ichannel < fNChannels; ++ichannel) {
1315 if (!hist_uncbandexp)
1319 int nbins = hist_data->GetNbinsX();
1322 for (
int ibin = 1; ibin <= nbins; ++ibin) {
1325 double expectation =
Expectation(ichannel, ibin, fMCMCx);
1328 hist_uncbandexp->Fill(hist_data->GetBinCenter(ibin), expectation);
int SetSystematicVariation(const char *channelname, const char *processname, const char *systematicname, double variation_up, double variation_down)
int GetHistogramLineStyle()
int AddChannel(const char *name)
void SetFunctionContainer(std::vector< TF1 * > *funccont, int nbins)
int SetData(const char *channelname, TH1D hist, double minimum=-1, double maximum=-1)
TH1D * CalculateUncertaintyBandPoisson(double minimum, double maximumm, int color)
A class describing a template.
double CalculatePValue(int channelindex, const std::vector< double > ¶meters)
void AddTemplate(BCMTFTemplate *bctemplate)
bool GetFlagChannelActive()
void SetHistUncertaintyBandExpectation(TH2D *hist)
double FastPValue(const std::vector< unsigned > &observed, const std::vector< double > &expected, unsigned nIterations, unsigned seed)
int SetTemplate(const char *channelname, const char *processname, TH1D hist, double efficiency=1., double norm=1.)
int GetProcessIndex(const char *name)
double ExpectationFunction(int parindex, int channelindex, int processindex, const std::vector< double > ¶meters)
The base class for all user-defined models.
int AddSystematic(const char *name, double min=-5., double max=5.)
void SetHistogram(TH1D *hist, double norm=1)
void AddSystematicVariation(BCMTFSystematicVariation *variation)
int GetChannelIndex(const char *name)
BCMTFTemplate * GetTemplate(int index)
void MCMCUserIterationInterface()
double CorrectPValue(const double &pvalue, const unsigned &npar, const unsigned &nobservations)
BCMTFSystematicVariation * GetSystematicVariation(int index)
double Expectation(int channelindex, int binindex, const std::vector< double > ¶meters)
int GetSystematicIndex(const char *name)
double Efficiency(int channelindex, int processindex, int binindex, const std::vector< double > ¶meters)
A class describing a process.
void SetEfficiency(double eff)
void AddHistograms(TH1D *hist_up, TH1D *hist_down)
TH2D * GetHistUncertaintyBandExpectation()
void SetRangeY(double min, double max)
double Probability(int channelindex, int processindex, int binindex, const std::vector< double > ¶meters)
int PrintStack(int channelindex, const std::vector< double > ¶meters, const char *filename="stack.pdf", const char *options="e1b0stack")
TH2D * GetHistUncertaintyBandPoisson()
double CalculateCash(int channelindex, const std::vector< double > ¶meters)
virtual int AddParameter(BCParameter *parameter)
TH1D * GetHistogramUp(int index)
std::vector< TF1 * > * GetFunctionContainer()
A class describing a physics channel.
void SetHistograms(int index, TH1D *hist_up, TH1D *hist_down)
int AddProcess(const char *name, double nmin=0., double nmax=1., int color=-1, int fillstyle=-1, int linestyle=-1)
int GetParIndexSystematic(int index)
void CalculateHistUncertaintyBandPoisson()
BCMTFTemplate * GetData()
TH1D * GetHistogramDown(int index)
void SetHistogramColor(int color)
BCMTFSystematic * GetSystematic(int index)
int GetParIndexProcess(int index)
BCMTFChannel * GetChannel(int index)
void SetData(BCMTFTemplate *bctemplate)
BCMTFProcess * GetProcess(int index)
double LogPoisson(double x, double par)
void SetHistogramLineStyle(int style)
int GetHistogramFillStyle()
double CalculateChi2(int channelindex, const std::vector< double > ¶meters)
void SetHistUncertaintyBandPoisson(TH2D *hist)
double LogLikelihood(const std::vector< double > ¶meters)
void SetHistogramFillStyle(int style)
A class desribing a systematic uncertainty.
A class describing a systematic variation.