This C++ version of BAT is still being maintained, but addition of new features is unlikely. Check out our new incarnation, BAT.jl, the Bayesian analysis toolkit in Julia. In addition to Metropolis-Hastings sampling, BAT.jl supports Hamiltonian Monte Carlo (HMC) with automatic differentiation, automatic prior-based parameter space transformations, and much more. See the BAT.jl documentation.
Signal search in the presence of background - tutorial for BAT 0.9
Physics motivation
The search for a weak signal in the presence of background is a common situation in particle physics. In particular, searches for neutrino-less double-beta-decay are limited by the background level reached by experiments. In this case, the signal process - if present - would cause a sharp line with known shape and position in the energy spectrum measured in the experiments. The expected number of signal and background events can reach a level of the order of 10 in the region of interest resulting in count-rates of less than one event per bin. Approximations valid for large statistics do not apply in this case.
Tutorial
This tutorial shows how to judge the validity of models and
how to compare those models. Different goodness-of-fit tests
are compared. The base line for the analysis presented is
the following: the data is assumed to be composed of events
from different contributions, e.g., various background
sources and a signal process. The shapes of the resulting
distributions are assumed to be known and stacked on top of
each other. A binned Likelihood fit, assuming independent
Poissonian fluctuations in each bin, is performed by scaling
the distributions, or
The tutorial is split into six steps:
- Step 1 - Getting started
- Step 2 - Fitting a background-only model
- Step 3 - Introduction to the goodness-of-fit tests
- Step 4 - Goodness-of-fit tests for signal and background models
- Step 5 - Comparing signal and background models
- Step 6 - Testing more complex models
Step 1 - Getting started
Create the HypothesisTest
project. Compile and run the code. You can clean up the
runHypothesisTest.cxx
file from the automatically generated code that are not needed.
Modify the file runHypothesisTest.cxx
such that the histogram containing the data,
hist_data
, is read in from the file
histograms.root
and plot it. The ROOT file can
be found here.
In file runHypothesisTest.cxx
#include <TFile.h> #include <TH1D.h> #include <TCanvas.h> #include <HypothesisTest.h> int main() { // ---------------------------------------------------- // open file with data and templates // ---------------------------------------------------- TFile * file = new TFile("histograms.root", "READ"); TH1D hist_data = *((TH1D*) file->Get("hist_data")); // close file file->Close(); // ---------------------------------------------------- // print // ---------------------------------------------------- // print data TCanvas c1("c1"); c1.cd(); hist_data.Draw(); c1.Print("data.ps"); return 0; }
The plot of the data can be found here.
| Source code |
Step 2 - Fitting a background-only model
The first model we test considers only background. The shape of the distribution is assumed to be flat in the region of interest.
-
Create a new instance of
BCTemplateFitter
. -
Read in the background template (histogram)
hist_bkg1
from the ROOT file. - Add the histogram to the
BCTemplateFitter
usingAddTemplate (TH1D hist, const char *name, double Nmin=0, double Nmax=0)
whereNmin
andNmax
are the minimum and maximum values of the normalization. The normalization is the integral of all contributions over the whole range. - Run the Markov chains and estimate the global mode.
-
Print the stack plot using the method
BCTemplateFitter::PrintStack(const char * filename)
.
In file runHypothesisTest.cxx
#include <BAT/BCLog.h> #include <BAT/BCAux.h> #include <TFile.h> #include <TH1D.h> #include <TCanvas.h> #include <HypothesisTest.h> #include <BAT/BCTemplateFitter.h> int main() { // ---------------------------------------------------- // open file with data and templates // ---------------------------------------------------- TFile * file = new TFile("histograms.root", "READ"); TH1D hist_bkg1 = *((TH1D*) file->Get("hist_bkg1")); TH1D hist_data = *((TH1D*) file->Get("hist_data")); // close file file->Close(); // ---------------------------------------------------- // configure BAT // ---------------------------------------------------- // set nice style for drawing than the ROOT default BCAux::SetStyle(); // open log file BCLog::OpenLog("log.txt"); BCLog::SetLogLevel(BCLog::detail); // ---------------------------------------------------- // model: 1 bkg 0 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg0sgn = new BCTemplateFitter("model 1 bkg 0 sgn"); // set data histogram m_1bkg0sgn->SetData(hist_data); // add template histograms m_1bkg0sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.); // set prior m_1bkg0sgn->SetPriorConstant("bkg 1"); // ---------------------------------------------------- // perform analyses // ---------------------------------------------------- // initialize models m_1bkg0sgn->Initialize(); // perform marginalization and find global mode m_1bkg0sgn->MarginalizeAll(); m_1bkg0sgn->FindMode(); // ---------------------------------------------------- // print // ---------------------------------------------------- // print data TCanvas c1("c1"); c1.cd(); hist_data.Draw(); c1.Print("data.ps"); // print stack plots and results m_1bkg0sgn->PrintStack("1bkg0sgn_stack.ps"); // ---------------------------------------------------- // clean-up and end // ---------------------------------------------------- // close log file BCLog::CloseLog(); // delete models delete m_1bkg0sgn; return 0; }
The plot of the data can he found here.
| Source code |
Step 3 - Introduction to the goodness-of-fit tests
Does the model describe the data? Perform the following three tests for the goodness of fit and compare the results with an inspection by eye:
- χ2-test using the methods
double BCTemplateFitter::CalculateChi2(std::vector<double> parameters)
,int BCTemplateFitter::GetNDF()
, anddouble BCTemplateFitter::GetChi2Prob(std::vector<double> parameters)
; - Kolmogorov-Smirnov test using the method
double BCTemplateFitter::CalculateKSProb()
; - p-value test using the method
double BCTemplateFitter::CalculatePValue()
.
In file runHypothesisTest.cxx
#include <BAT/BCLog.h> #include <BAT/BCAux.h> #include <TFile.h> #include <TH1D.h> #include <TCanvas.h> #include <BAT/BCTemplateFitter.h> #include <HypothesisTest.h> int main() { // ---------------------------------------------------- // open file with data and templates // ---------------------------------------------------- TFile * file = new TFile("histograms.root", "READ"); TH1D hist_bkg1 = *((TH1D*) file->Get("hist_bkg1")); TH1D hist_data = *((TH1D*) file->Get("hist_data")); // close file file->Close(); // ---------------------------------------------------- // configure BAT // ---------------------------------------------------- // set nice style for drawing than the ROOT default BCAux::SetStyle(); // open log file BCLog::OpenLog("log.txt"); BCLog::SetLogLevel(BCLog::detail); // ---------------------------------------------------- // model: 1 bkg 0 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg0sgn = new BCTemplateFitter("model 1 bkg 0 sgn"); // set data histogram m_1bkg0sgn->SetData(hist_data); // add template histograms m_1bkg0sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.); // set prior m_1bkg0sgn->SetPriorConstant("bkg 1"); // ---------------------------------------------------- // perform analyses // ---------------------------------------------------- // initialize models m_1bkg0sgn->Initialize(); // perform marginalization and find global mode m_1bkg0sgn->MarginalizeAll(); m_1bkg0sgn->FindMode(); // calculate gof-variables double chi2_1bkg0sgn = m_1bkg0sgn->CalculateChi2(m_1bkg0sgn->GetBestFitParameters()); int ndf_1bkg0sgn = m_1bkg0sgn->GetNDF(); double chi2prob_1bkg0sgn = m_1bkg0sgn->CalculateChi2Prob(m_1bkg0sgn->GetBestFitParameters()); double pvalue_1bkg0sgn = m_1bkg0sgn->CalculatePValue(); double KSprob_1bkg0sgn = m_1bkg0sgn->CalculateKSProb(); // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: " << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg0sgn << " / " << ndf_1bkg0sgn << " (" << chi2prob_1bkg0sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg0sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg0sgn << std::endl << std::endl; // ---------------------------------------------------- // print // ---------------------------------------------------- // print data TCanvas c1("c1"); c1.cd(); hist_data.Draw(); c1.Print("data.ps"); // print stack plots and results m_1bkg0sgn->PrintStack("1bkg0sgn_stack.ps"); // ---------------------------------------------------- // clean-up and end // ---------------------------------------------------- // close log file BCLog::CloseLog(); // delete models delete m_1bkg0sgn; return 0; }
The results of the tests for the background model are χ2/ndf (χ2-prob.) = 50.0192 / 39 (0.111167) , Kolmogorov-Smirnov probability = 0.525956 , p-value = 0.27674 . The agreement between the model and the data is not too bad. From the inspection by eye one could argue that there are features in the data which are not described by the model.
| Source code !
Step 4 - Goodness-of-fit tests for signal and background models
After the goodness-fit-test for the background-only model, a second model is introduced which contains a signal contribution. The shape of the signal is a Gaussian centered around 2,040 keV with a width of σ = 2.5 keV.
-
Create a second
BCTemplateFitter
and read in the signal template,hist_sgn
, from the ROOT file. - Estimate the signal contribution (95% limit) and print out the marginalized distribution.
- Perform the goodness-of-fit tests introduced in the previous step for the signal model. Does the signal model describe the data?
In file runHypothesisTest.cxx
#include <BAT/BCLog.h> #include <BAT/BCAux.h> #include <BAT/BCH1D.h> #include <TFile.h> #include <TH1D.h> #include <TCanvas.h> #include <BAT/BCTemplateFitter.h> #include <HypothesisTest.h> int main() { // ---------------------------------------------------- // open file with data and templates // ---------------------------------------------------- TFile * file = new TFile("histograms.root", "READ"); TH1D hist_bkg1 = *((TH1D*) file->Get("hist_bkg1")); TH1D hist_sgn = *((TH1D*) file->Get("hist_sgn")); TH1D hist_data = *((TH1D*) file->Get("hist_data")); // close file file->Close(); // ---------------------------------------------------- // configure BAT // ---------------------------------------------------- // set nice style for drawing than the ROOT default BCAux::SetStyle(); // open log file BCLog::OpenLog("log.txt"); BCLog::SetLogLevel(BCLog::detail); // ---------------------------------------------------- // model: 1 bkg 0 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg0sgn = new BCTemplateFitter("model 1 bkg 0 sgn"); // set data histogram m_1bkg0sgn->SetData(hist_data); // add template histograms m_1bkg0sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.); // set prior m_1bkg0sgn->SetPriorConstant("bkg 1"); // ---------------------------------------------------- // model: 1 bkg 1 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg1sgn = new BCTemplateFitter("model 1 bkg 1 sgn"); // set data histogram m_1bkg1sgn->SetData(hist_data); // add template histograms m_1bkg1sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.0); m_1bkg1sgn->AddTemplate(hist_sgn, "sgn", 0., 50.); // set priors m_1bkg1sgn->SetPriorConstant("bkg 1"); m_1bkg1sgn->SetPriorConstant("sgn"); // ---------------------------------------------------- // perform analyses // ---------------------------------------------------- // initialize models m_1bkg0sgn->Initialize(); m_1bkg1sgn->Initialize(); // run MCMC and find global mode m_1bkg0sgn->MarginalizeAll(); m_1bkg0sgn->FindMode(); m_1bkg1sgn->MarginalizeAll(); m_1bkg1sgn->FindMode(); // calculate gof-variables double chi2_1bkg0sgn = m_1bkg0sgn->CalculateChi2(m_1bkg0sgn->GetBestFitParameters()); int ndf_1bkg0sgn = m_1bkg0sgn->GetNDF(); double chi2prob_1bkg0sgn = m_1bkg0sgn->CalculateChi2Prob(m_1bkg0sgn->GetBestFitParameters()); double pvalue_1bkg0sgn = m_1bkg0sgn->CalculatePValue(); double KSprob_1bkg0sgn = m_1bkg0sgn->CalculateKSProb(); double chi2_1bkg1sgn = m_1bkg1sgn->CalculateChi2(m_1bkg1sgn->GetBestFitParameters()); int ndf_1bkg1sgn = m_1bkg1sgn->GetNDF(); double chi2prob_1bkg1sgn = m_1bkg1sgn->CalculateChi2Prob(m_1bkg1sgn->GetBestFitParameters()); double pvalue_1bkg1sgn = m_1bkg1sgn->CalculatePValue(); double KSprob_1bkg1sgn = m_1bkg1sgn->CalculateKSProb(); // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 1bkg 0 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg0sgn << " / " << ndf_1bkg0sgn << " (" << chi2prob_1bkg0sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg0sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg0sgn << std::endl << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 1bkg 1 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg1sgn << " / " << ndf_1bkg1sgn << " (" << chi2prob_1bkg1sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg1sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg1sgn << std::endl << std::endl; // ---------------------------------------------------- // print // ---------------------------------------------------- // print data TCanvas c1("c1"); c1.cd(); hist_data.Draw(); c1.Print("data.ps"); // print marginalized distribution for signal c1.cd(); m_1bkg1sgn->GetMarginalized("sgn")->Draw(0, -95); c1.Print("1bkg1sgn_sgn.ps"); // print stack plots and results m_1bkg0sgn->PrintStack("1bkg0sgn_stack.eps"); m_1bkg1sgn->PrintStack("1bkg1sgn_stack.eps"); // ---------------------------------------------------- // clean-up and end // ---------------------------------------------------- // close log file BCLog::CloseLog(); delete m_1bkg0sgn; delete m_1bkg1sgn; return 0; }
The results of the tests for the signal model are χ2/ndf (χ2-prob.) = 49.2102 / 37 (0.0863675) , Kolmogorov-Smirnov probability = 0.483098 , p-value = 0.29038 . The agreement between both models and the data is not too bad. From the inspection by eye one could argue that there are features in the data which are not described by any of the two models.
| Source code |
Step 5 - Comparing signal and background models
Both models describe the data. Compare the models directly
by using the BCModelManager
.
- Create an instance of the
BCModelManager
. - Add the two models.
- Calculate the Bayes Factor for the two models using the method
BCModelManager::BayesFactor(modelindex1,modelindex2)
. The method can also perform a calculation of other useful quantities like p-values, posterior probabilities.
In file runHypothesisTest.cxx
#include <BAT/BCLog.h> #include <BAT/BCAux.h> #include <BAT/BCH1D.h> #include <TFile.h> #include <TH1D.h> #include <TCanvas.h> #include <BAT/BCTemplateFitter.h> #include <BAT/BCModelManager.h> #include <HypothesisTest.h> int main() { // ---------------------------------------------------- // open file with data and templates // ---------------------------------------------------- TFile * file = new TFile("histograms.root", "READ"); TH1D hist_bkg1 = *((TH1D*) file->Get("hist_bkg1")); TH1D hist_sgn = *((TH1D*) file->Get("hist_sgn")); TH1D hist_data = *((TH1D*) file->Get("hist_data")); // close file file->Close(); // ---------------------------------------------------- // configure BAT // ---------------------------------------------------- // set nice style for drawing than the ROOT default BCAux::SetStyle(); // open log file BCLog::OpenLog("log.txt"); BCLog::SetLogLevel(BCLog::detail); // ---------------------------------------------------- // model: 1 bkg 0 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg0sgn = new BCTemplateFitter("model 1 bkg 0 sgn"); // set data histogram m_1bkg0sgn->SetData(hist_data); // add template histograms m_1bkg0sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.); // set prior m_1bkg0sgn->SetPriorConstant("bkg 1"); // ---------------------------------------------------- // model: 1 bkg 1 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg1sgn = new BCTemplateFitter("model 1 bkg 1 sgn"); // set data histogram m_1bkg1sgn->SetData(hist_data); // add template histograms m_1bkg1sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.0); m_1bkg1sgn->AddTemplate(hist_sgn, "sgn", 0., 50.); // set priors m_1bkg1sgn->SetPriorConstant("bkg 1"); m_1bkg1sgn->SetPriorConstant("sgn"); // ---------------------------------------------------- // perform analyses // ---------------------------------------------------- // initialize models m_1bkg0sgn->Initialize(); m_1bkg1sgn->Initialize(); // run MCMC and find global mode m_1bkg0sgn->MarginalizeAll(); m_1bkg0sgn->FindMode(); m_1bkg1sgn->MarginalizeAll(); m_1bkg1sgn->FindMode(); // calculate gof-variables double chi2_1bkg0sgn = m_1bkg0sgn->CalculateChi2(m_1bkg0sgn->GetBestFitParameters()); int ndf_1bkg0sgn = m_1bkg0sgn->GetNDF(); double chi2prob_1bkg0sgn = m_1bkg0sgn->CalculateChi2Prob(m_1bkg0sgn->GetBestFitParameters()); double pvalue_1bkg0sgn = m_1bkg0sgn->CalculatePValue(); double KSprob_1bkg0sgn = m_1bkg0sgn->CalculateKSProb(); double chi2_1bkg1sgn = m_1bkg1sgn->CalculateChi2(m_1bkg1sgn->GetBestFitParameters()); int ndf_1bkg1sgn = m_1bkg1sgn->GetNDF(); double chi2prob_1bkg1sgn = m_1bkg1sgn->CalculateChi2Prob(m_1bkg1sgn->GetBestFitParameters()); double pvalue_1bkg1sgn = m_1bkg1sgn->CalculatePValue(); double KSprob_1bkg1sgn = m_1bkg1sgn->CalculateKSProb(); // ---------------------------------------------------- // set up model manager // ---------------------------------------------------- // create new BCTemplateFitterManager BCModelManager * smm = new BCModelManager(); smm->AddModel(m_1bkg0sgn); smm->AddModel(m_1bkg1sgn); // Calculates the normalization of the likelihood for each model smm->Normalize(); // compare models double bayesFact01 = smm->BayesFactor(0,1); std::cout << std::endl << "Bayes Factor 1bkg0sig/1bkg1sig = " << bayesFact01 << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 1bkg 0 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg0sgn << " / " << ndf_1bkg0sgn << " (" << chi2prob_1bkg0sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg0sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg0sgn << std::endl << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 1bkg 1 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg1sgn << " / " << ndf_1bkg1sgn << " (" << chi2prob_1bkg1sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg1sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg1sgn << std::endl << std::endl; // ---------------------------------------------------- // print // ---------------------------------------------------- // print data TCanvas c1("c1"); c1.cd(); hist_data.Draw(); c1.Print("data.ps"); // print marginalized distribution for signal c1.cd(); m_1bkg1sgn->GetMarginalized("sgn")->Draw(0, -95); c1.Print("1bkg1sgn_sgn.ps"); // print stack plots and results m_1bkg0sgn->PrintStack("1bkg0sgn_stack.eps"); m_1bkg1sgn->PrintStack("1bkg1sgn_stack.eps"); // ---------------------------------------------------- // clean-up and end // ---------------------------------------------------- // close log file BCLog::CloseLog(); delete m_1bkg0sgn; delete m_1bkg1sgn; // delete model manager delete smm; return 0; }
The results is
Bayes Factor 1bkg0sig/1bkg1sig = 3.30999.
The 95% upper limit on the signal contribution is 15.77.
The marginalized distribution can be found here.
The plot of the best fit can be found here.
| Source code |
Step 6 - Testing more complex models
A better model for the background could be a composition of two distributions: a flat one and an expotentially decaying one.
- Create two new
BCTemplateFitter
and read in the second background template, hist_bkg2, from the ROOT file. - Perform the same tests as in the previous step and compare the results. Which of the four models describes the data best? Which model is preferred over which?
- Compare the two signal models (with one and two sources of background, respectively) and calculate the limit on the signal contribution. How does the background model change the limits?
In file runHypothesisTest.cxx
#include <BAT/BCLog.h> #include <BAT/BCAux.h> #include <BAT/BCH1D.h> #include <TFile.h> #include <TH1D.h> #include <TCanvas.h> #include <BAT/BCTemplateFitter.h> #include <BAT/BCModelManager.h> #include <HypothesisTest.h> int main() { // ---------------------------------------------------- // open file with data and templates // ---------------------------------------------------- TFile * file = new TFile("histograms.root", "READ"); TH1D hist_bkg1 = *((TH1D*) file->Get("hist_bkg1")); TH1D hist_bkg2 = *((TH1D*) file->Get("hist_bkg2")); TH1D hist_sgn = *((TH1D*) file->Get("hist_sgn")); TH1D hist_data = *((TH1D*) file->Get("hist_data")); // close file file->Close(); // ---------------------------------------------------- // configure BAT // ---------------------------------------------------- // set nice style for drawing than the ROOT default BCAux::SetStyle(); // open log file BCLog::OpenLog("log.txt"); BCLog::SetLogLevel(BCLog::detail); // ---------------------------------------------------- // model: 1 bkg 0 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg0sgn = new BCTemplateFitter("model 1 bkg 0 sgn"); // set data histogram m_1bkg0sgn->SetData(hist_data); // add template histograms m_1bkg0sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.); // set prior m_1bkg0sgn->SetPriorConstant("bkg 1"); // ---------------------------------------------------- // model: 1 bkg 1 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_1bkg1sgn = new BCTemplateFitter("model 1 bkg 1 sgn"); // set data histogram m_1bkg1sgn->SetData(hist_data); // add template histograms m_1bkg1sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.0); m_1bkg1sgn->AddTemplate(hist_sgn, "sgn", 0., 50.); // set priors m_1bkg1sgn->SetPriorConstant("bkg 1"); m_1bkg1sgn->SetPriorConstant("sgn"); // ---------------------------------------------------- // model: 2 bkg 0 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_2bkg0sgn = new BCTemplateFitter("model 2 bkg 0 sgn"); // set data histogram m_2bkg0sgn->SetData(hist_data); // add template histograms m_2bkg0sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.0); m_2bkg0sgn->AddTemplate(hist_bkg2, "bkg 2", 40., 160.0); // set priors m_2bkg0sgn->SetPriorConstant("bkg 1"); m_2bkg0sgn->SetPriorConstant("bkg 2"); // ---------------------------------------------------- // model: 2 bkg 1 sgn // ---------------------------------------------------- // create new BCTemplateFitter object BCTemplateFitter * m_2bkg1sgn = new BCTemplateFitter("model 2 bkg 1 sgn"); m_2bkg1sgn->MCMCSetNLag(10); // set data histogram m_2bkg1sgn->SetData(hist_data); // add template histograms m_2bkg1sgn->AddTemplate(hist_bkg1, "bkg 1", 40., 160.); m_2bkg1sgn->AddTemplate(hist_bkg2, "bkg 2", 40., 160.); m_2bkg1sgn->AddTemplate(hist_sgn, "sgn", 0., 50.); // set priors m_2bkg1sgn->SetPriorConstant("bkg 1"); m_2bkg1sgn->SetPriorConstant("bkg 2"); m_2bkg1sgn->SetPriorConstant("sgn"); // ---------------------------------------------------- // perform analyses // ---------------------------------------------------- // initialize models m_1bkg0sgn->Initialize(); m_1bkg1sgn->Initialize(); m_2bkg0sgn->Initialize(); m_2bkg1sgn->Initialize(); // run MCMC and find global mode m_1bkg0sgn->MarginalizeAll(); m_1bkg0sgn->FindMode(); m_1bkg1sgn->MarginalizeAll(); m_1bkg1sgn->FindMode(); m_2bkg0sgn->MarginalizeAll(); m_2bkg0sgn->FindMode(); m_2bkg1sgn->MarginalizeAll(); m_2bkg1sgn->FindMode(); // calculate gof-variables double chi2_1bkg0sgn = m_1bkg0sgn->CalculateChi2(m_1bkg0sgn->GetBestFitParameters()); int ndf_1bkg0sgn = m_1bkg0sgn->GetNDF(); double chi2prob_1bkg0sgn = m_1bkg0sgn->CalculateChi2Prob(m_1bkg0sgn->GetBestFitParameters()); double pvalue_1bkg0sgn = m_1bkg0sgn->CalculatePValue(); double KSprob_1bkg0sgn = m_1bkg0sgn->CalculateKSProb(); double chi2_1bkg1sgn = m_1bkg1sgn->CalculateChi2(m_1bkg1sgn->GetBestFitParameters()); int ndf_1bkg1sgn = m_1bkg1sgn->GetNDF(); double chi2prob_1bkg1sgn = m_1bkg1sgn->CalculateChi2Prob(m_1bkg1sgn->GetBestFitParameters()); double pvalue_1bkg1sgn = m_1bkg1sgn->CalculatePValue(); double KSprob_1bkg1sgn = m_1bkg1sgn->CalculateKSProb(); double chi2_2bkg0sgn = m_2bkg0sgn->CalculateChi2(m_2bkg0sgn->GetBestFitParameters()); int ndf_2bkg0sgn = m_2bkg0sgn->GetNDF(); double chi2prob_2bkg0sgn = m_2bkg0sgn->CalculateChi2Prob(m_2bkg0sgn->GetBestFitParameters()); double pvalue_2bkg0sgn = m_2bkg0sgn->CalculatePValue(); double KSprob_2bkg0sgn = m_2bkg0sgn->CalculateKSProb(); double chi2_2bkg1sgn = m_2bkg1sgn->CalculateChi2(m_2bkg1sgn->GetBestFitParameters()); int ndf_2bkg1sgn = m_2bkg1sgn->GetNDF(); double chi2prob_2bkg1sgn = m_2bkg1sgn->CalculateChi2Prob(m_2bkg1sgn->GetBestFitParameters()); double pvalue_2bkg1sgn = m_2bkg1sgn->CalculatePValue(); double KSprob_2bkg1sgn = m_2bkg1sgn->CalculateKSProb(); // ---------------------------------------------------- // set up model manager // ---------------------------------------------------- // create new BCTemplateFitterManager BCModelManager * smm = new BCModelManager(); smm->AddModel(m_1bkg0sgn); smm->AddModel(m_1bkg1sgn); smm->AddModel(m_2bkg0sgn); smm->AddModel(m_2bkg1sgn); // Calculates the normalization of the likelihood for each model smm->Normalize(); // compare models double bayesFact01 = smm->BayesFactor(0,1); std::cout << std::endl << "Bayes Factor 1bkg0sig/1bkg1sig = " << bayesFact01 << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 1bkg 0 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg0sgn << " / " << ndf_1bkg0sgn << " (" << chi2prob_1bkg0sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg0sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg0sgn << std::endl << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 1bkg 1 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_1bkg1sgn << " / " << ndf_1bkg1sgn << " (" << chi2prob_1bkg1sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_1bkg1sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_1bkg1sgn << std::endl << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 2bkg 0 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_2bkg0sgn << " / " << ndf_2bkg0sgn << " (" << chi2prob_2bkg0sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_2bkg0sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_2bkg0sgn << std::endl << std::endl; // print gof-variables std::cout << std::endl << "Goodness-of-fit tests: 2bkg 1 sgn" << std::endl; std::cout << " chi2 / dof (chi2 prob.) = " << chi2_2bkg1sgn << " / " << ndf_2bkg1sgn << " (" << chi2prob_2bkg1sgn << ")" << std::endl; std::cout << " p-value = " << pvalue_2bkg1sgn << std::endl; std::cout << " Kolmogorov-Smirnov prob. = " << KSprob_2bkg1sgn << std::endl << std::endl; // ---------------------------------------------------- // print // ---------------------------------------------------- // print data TCanvas c1("c1"); c1.cd(); hist_data.Draw(); c1.Print("data.ps"); // print marginalized distribution for signal c1.cd(); m_1bkg1sgn->GetMarginalized("sgn")->Draw(0, -95); c1.Print("1bkg1sgn_sgn.ps"); // print marginalized distribution for signal c1.cd(); m_2bkg1sgn->GetMarginalized("sgn")->Draw(0, -95); c1.Print("2bkg1sgn_sgn.ps"); // print stack plots and results m_1bkg0sgn->PrintStack("1bkg0sgn_stack.eps"); m_1bkg1sgn->PrintStack("1bkg1sgn_stack.eps"); m_2bkg0sgn->PrintStack("2bkg0sgn_stack.eps"); m_2bkg1sgn->PrintStack("2bkg1sgn_stack.eps"); // ---------------------------------------------------- // clean-up and end // ---------------------------------------------------- // close log file BCLog::CloseLog(); delete m_1bkg0sgn; delete m_1bkg1sgn; delete m_2bkg0sgn; delete m_2bkg1sgn; // delete model manager delete smm; return 0; }
The results is
The 95% upper limit on the signal contribution is 17.95.
The marginalized distribution can be found here.
The plot of the best fit can be found here.
| Source code |
Further material and documentation
A sensitivity study for the GERDA experiment can be found here:
- A. Caldwell, K. Kröninger
Signal discovery in sparse spectra: A Bayesian analysis,
Phys. Rev. D74 (2006) 092003 [physics/0608249].
- An introduction to this tutorial can be found here.
Kevin Kröninger Last modified: Fri Feb 25 14:17:23 CET 2011