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.
Cross-section combination - a BAT tutorial
Physics motivation
This tutorial shows how to combine two different measurements of the same physical quantity, or parameter. The shape of the posterior probabilities of the individual measurements are not constrained to a Gaussian. In addtion, the treatment of correlated and uncorrelated systematic uncertainties is explained using a nuisance parameter ansatz.
Tutorial
The physics case is that of a combination of two cross-section measurements. A process observed in a collider is supposed to be measured in two different channels, one with electrons in the final state, one with muons in the final state. A certain number of events is observed in each channel after an event selection. The corresponding efficiencies and the luminosity are treated as uncorrelated and correlated uncertainties, respectively.
The cross-section, σ, is connected to the number of observed events via the following equation:
N = L ⋅ ε ⋅ σ
where L. is the luminosity, ε is the efficiency for selecting events from the process under study and N is the number of observed events. Background is not considered in this tutorial.
Systematic uncertainties can be included in the model by added nuisance parameters. A quantity, e.g., the efficiency or luminosity, is known up to some precision. The nuisance parameter, δε, is linearly added to the parameter. The prior for the nuisance parameter is usually described by a Gaussian distribution with mean 0 and standard deviation 1. The nuisance parameter is multiplied with a scale factor, Δε, which describes the size of the effect, i.e.,
ε → ε + δε ⋅ Δε .
The tutorial is split into five steps:
- Step 1 - Calculating the cross-section
- Step 2 - A first combination
- Step 3 - Including uncorrelated uncertainties
- Step 4 - Including correlated uncertainties
- Step 5 - Large and small statistics *
Steps marked with * are advanced examples and independent of the limit of the rest of the tutorial. A proposal for additional studies is also given.
Step 1 - Calculating the cross-section
This step shows how to calculate the cross-section for a given number of observed events in one channel and how to present the results. The number of observed events in the muon channel is 38. The luminosity is 10 pb-1 and the efficiency for selecting muon events is 35%.
- Calculate the cross-section using the formula above.
- Create a new project (
XSecCombiModel
). Execute it to generate a BAT analysis skeleton. Look trough the code. - Set up a statistical model with the cross-section as the sole parameter and calculate the posterior probability for the cross-section. Choose a parameter range of (2., 210.) pb.
- Use a Gaussian uncertainty using (a) the observed number of events, and (b) the expected number of events as an uncertainty and compare the results with (c) the case when using a Poisson distribution. Consider only the latter ansatz in the following.
- Look at different possible values to describe the posterior for the cross-section, e.g., mean and variance, mode and smallest interval, or the median together with the 16% and 84% quantiles.
- σ = 10.857 pb
- -
- In file
XSecCombiModel.cxx
:
#include <XSecCombiModel.h> #include <BAT/BCMath.h> // --------------------------------------------------------- XSecCombiModel::XSecCombiModel() : BCModel() , fEfficiencyMu(0.35) , fLuminosity(10.) , fNobsMu(38) { // default constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::XSecCombiModel(const char * name) : BCModel(name) { // constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::~XSecCombiModel() { // default destructor }; // --------------------------------------------------------- void XSecCombiModel::DefineParameters() { // total cross-section in pb AddParameter("xsec", 2.0, 210.0); // index 0 } // --------------------------------------------------------- double XSecCombiModel::LogLikelihood(const std::vector <double> & parameters) { // This methods returns the logarithm of the conditional // probability p(data|parameters). This is where you have to // define your model. double logprob = 0.; // get parameters and calculate nuisance term double xsec = parameters[0]; // calculate efficiency as sum of estimated efficiency plus nuisance // term double effMu = fEfficiencyMu; // calculate luminosity as sum of estimated luminosity plus nuisance // term double luminosity = fLuminosity; // check if efficiencies and luminosity are positive if (effMu < 0 || luminosity < 0) return -1e99; // calculate expected number of muon and electron events double nexpectedMu = xsec * luminosity * effMu; // Poisson probability for observing a certain number of events // given some expectation (muon channel) if (fNobsMu >= 0) // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(fNobsMu)); // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(nexpectedMu)); logprob += BCMath::LogPoisson(fNobsMu, nexpectedMu); return logprob; } // --------------------------------------------------------- double XSecCombiModel::LogAPrioriProbability(const std::vector <double> & parameters) { // This method returns the logarithm of the prior probability for the // parameters p(parameters). double logprob = 0.; // get parameter range double dxsec = GetParameter(0)->GetRangeWidth(); // flat prior for cross-section logprob += log(1./dxsec); return logprob; } // ---------------------------------------------------------
In fileXSecCombiModel.h
add the necessary definitions:
protected: double fEfficiencyMu; double fLuminosity; double fNobsMu;
In filerunXSecCombiModel.cxx
uncomment the necessary functions to run the chains and record the results in desired formats, for example:
m->MarginalizeAll(); m->FindMode( m->GetBestFitParameters() ); m->PrintAllMarginalized("XSecCombiModel_plots.ps"); summary->PrintParameterPlot("XSecCombiModel_parameters.eps");
- Median (mode from Minuit) und central 68% interval for different Likelihoods:
- (a) σ = 10.89+1.90-2.06 (10.86 ± 1.76) pb
- (b) σ = 11.21+2.18-2.03 (10.86 ± 1.76) pb
- (c) σ = 11.11+2.05-2.03 (10.86 ± 1.76) pb
- Possible values to summarize the cross-section estimate:
- Mean ± RMS: (11.14 ± 1.78) pb (symmetric)
- Median and central 68% interval: (11.11 +2.05 -2.03) pb
- Mode and smallest interval 11.36 pb with (8.24, 14.48) pb
Step 2 - A first combination
Step 2 shows how to combine the results from two simultaneous measurements, e.g., in two different channels.
- Repeat the last study for the electron channel. The number of observed events in the electron channel is 21 for the same luminosity. The efficiency is 20%.
- Extend your model so that it combines the results from the muon and the electron channel.
- How does the combination improve the measurement of the cross-section?
- Calculate the central value and the uncertainties using Gaussian error propagation for the individual channels and the combination. Compare your results.
Hint: you can do the calculation on a piece of paper.
- Possible values to summarize the cross-section estimate in electron channel:
- Mean ± RMS: 10.99 ± 2.34 pb from MCMC, 10.50 ± 2.29 pb from Minuit (symmetric)
- Median and central 68% interval: (10.87 +2.67 -2.29) pb
- Mode and smallest interval 11.36 pb with (8.24, 16.56) pb
- Possible values to summarize the cross-section estimate for the combination:
- Mean ± RMS: (10.91 ± 1.41) pb from MCMC, 10.73 ± 1.40 pb from Minuit (symmetric)
- Median and central 68% interval: (10.93 +1.40 -1.82) pb
- Mode and smallest interval 11.36 pb with (8.24, 14.48) pb
#include <XSecCombiModel.h> #include <BAT/BCMath.h> // --------------------------------------------------------- XSecCombiModel::XSecCombiModel() : BCModel() , fEfficiencyMu(0.35) , fEfficiencyE(0.20) , fLuminosity(10.) , fNobsMu(38) , fNobsE(21) { // default constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::XSecCombiModel(const char * name) : BCModel(name) { // constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::~XSecCombiModel() { // default destructor }; // --------------------------------------------------------- void XSecCombiModel::DefineParameters() { // Add parameters to your model here. // You can then use them in the methods below by calling the // parameters.at(i) or parameters[i], where i is the index // of the parameter. The indices increase from 0 according to the // order of adding the parameters. // total cross-section in pb AddParameter("xsec", 2.0, 210.0); // index 0 } // --------------------------------------------------------- double XSecCombiModel::LogLikelihood(const std::vector <double> & parameters) { // This methods returns the logarithm of the conditional probability // p(data|parameters). This is where you have to define your model. double logprob = 0.; // get parameters and calculate nuisance term double xsec = parameters[0]; // calculate efficiency as sum of estimated efficiency plus nuisance // term double effMu = fEfficiencyMu; double effE = fEfficiencyE; // calculate luminosity as sum of estimated luminosity plus nuisance // term double luminosity = fLuminosity; // check if efficiencies and luminosity are positive if (effMu < 0 || effE < 0 || luminosity < 0) return -1e99; // calculate expected number of muon and electron events double nexpectedMu = xsec * luminosity * effMu; double nexpectedE = xsec * luminosity * effE; // Poisson probability for observing a certain number of events // given some expectation (muon channel) if (fNobsMu >= 0) // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(fNobsMu)); // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(nexpectedMu)); logprob += BCMath::LogPoisson(fNobsMu, nexpectedMu); // Poisson probability for observing a certain number of events // given some expectation (electron channel) if (fNobsE >= 0) // logprob += BCMath::LogGaus(fNobsE, nexpectedE, sqrt(fNobsE)); // logprob += BCMath::LogGaus(fNobsE, nexpectedE, sqrt(nexpectedE)); logprob += BCMath::LogPoisson(fNobsE, nexpectedE); return logprob; } // --------------------------------------------------------- double XSecCombiModel::LogAPrioriProbability(const std::vector <double> & parameters) { // This method returns the logarithm of the prior probability for the // parameters p(parameters). double logprob = 0.; // get parameter range double dxsec = GetParameter(0)->GetRangeWidth(); // flat prior for cross-section logprob += log(1./dxsec); return logprob; } // ---------------------------------------------------------
In fileXSecCombiModel.h
add the necessary definitions:
protected: double fEfficiencyMu; double fEfficiencyE; double fLuminosity; double fNobsMu; double fNobsE;
- The central value is slightly shifted and the uncertainty is reduced.
- Individual values and uncertainties:
Δσ = N-1/2 / L / ε
Muon channel: σμ = (10.86 ± 1.76) pb
Electron channel: σe = (10.50 ± 2.29) pb
Weighted average: σ = ( σe/Δσe2 + σe/Δσμ2) / (1/Δσe2 + 1/Δσμ2) = 10.72 pb
Uncertainty: Δσ = √ 1/(1/Δσe2 + 1/Δσμ2) = 1.40 pb
Main difference is the symmetric uncertainty in this calculation, the mode is the same for both calculations.
Step 3 - Including uncorrelated uncertainties
This step shows how to include systematic uncertainties into the analysis. The uncertainties are on the efficiencies for the two channels and are assumed to be uncorrelated.
- Extend your model to include the systematic uncertainties for the efficiencies for both channels separately. Assume the uncertainties are uncorrelated and amount to 0.01. How do the central value and the uncertainties change?
- Calculate the correlation factors between the three parameters.
- Compare your results to those obtained with a variation ansatz, in particular the central value.
- Compare your results to those obtained with Gaussian error propagation.
- Code
#include <XSecCombiModel.h> #include <BAT/BCMathh.h> // --------------------------------------------------------- XSecCombiModel::XSecCombiModel() : BCModel() , fEfficiencyMu(0.35) , fEfficiencyE(0.20) , fLuminosity(10.) , fErrorEfficiencyMu(0.01) , fErrorEfficiencyE(0.01) , fNobsMu(38) , fNobsE(21) { // default constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::XSecCombiModel(const char * name) : BCModel(name) { // constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::~XSecCombiModel() { // default destructor }; // --------------------------------------------------------- void XSecCombiModel::DefineParameters() { // Add parameters to your model here. // You can then use them in the methods below by calling the // parameters.at(i) or parameters[i], where i is the index // of the parameter. The indices increase from 0 according to the // order of adding the parameters. // total cross-section in pb AddParameter("xsec", 2.0, 210.0); // index 0 // nuisance parameter for efficiency for muon channel in "sigma" AddParameter("effMu", -5.0, 5.0); // index 1 // nuisance parameter for efficiency for electron channel in "sigma" AddParameter("effE", -5.0, 5.0); // index 2 } // --------------------------------------------------------- double XSecCombiModel::LogLikelihood(const std::vector <double> & parameters) { // This methods returns the logarithm of the conditional probability // p(data|parameters). This is where you have to define your model. double logprob = 0.; // get parameters and calculate nuisance term double xsec = parameters[0]; double deffMu = parameters[1] * fErrorEfficiencyMu; double deffE = parameters[2] * fErrorEfficiencyE; // calculate efficiency as sum of estimated efficiency plus nuisance // term double effMu = fEfficiencyMu + deffMu; double effE = fEfficiencyE + deffE; // calculate luminosity as sum of estimated luminosity plus nuisance // term double luminosity = fLuminosity; // check if efficiencies and luminosity are positive if (effMu < 0 || effE < 0 || luminosity < 0) return -1e99; // calculate expected number of muon and electron events double nexpectedMu = xsec * luminosity * effMu; double nexpectedE = xsec * luminosity * effE; // Poisson probability for observing a certain number of events // given some expectation (muon channel) if (fNobsMu >= 0) // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(fNobsMu)); // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(nexpectedMu)); logprob += BCMath::LogPoisson(fNobsMu, nexpectedMu); // Poisson probability for observing a certain number of events // given some expectation (electron channel) if (fNobsE >= 0) // logprob += BCMath::LogGaus(fNobsE, nexpectedE, sqrt(fNobsE)); // logprob += BCMath::LogGaus(fNobsE, nexpectedE, sqrt(nexpectedE)); logprob += BCMath::LogPoisson(fNobsE, nexpectedE); return logprob; } // --------------------------------------------------------- double XSecCombiModel::LogAPrioriProbability(const std::vector <double> & parameters) { // This method returns the logarithm of the prior probability for the // parameters p(parameters). double logprob = 0.; // get parameters double deffMu = parameters[1]; double deffE = parameters[2]; // get parameter range double dxsec = GetParameter(0)->GetRangeWidth(); // flat prior for cross-section logprob += log(1./dxsec); // Gaussian prior for efficiency if (fErrorEfficiencyMu > 0.) logprob += BCMath::LogGaus(deffMu, 0., 1.0); // Gaussian prior for efficiency if (fErrorEfficiencyE > 0.) logprob += BCMath::LogGaus(deffE, 0., 1.0); return logprob; } // ---------------------------------------------------------
In fileXSecCombiModel.h
add the necessary definitions:
protected: double fEfficiencyMu; double fEfficiencyE; double fLuminosity; double fNobsMu; double fNobsE;
Possible values to summarize the cross-section estimate for the nuisance parameter ansatz:- Mean ± RMS: 10.93 ± 1.44 pb from MCMC, 10.73 ± 1.42 pb from Minuit (symmetric)
- Median and central 68% interval: (10.95 +1.42 -1.83) pb
- Mode and smallest interval 11.36 pb with (8.24, 14.48) pb
- In file
runXSecCombiModel.cxx
usePrintCorrelationMatrix
function fromBCSummaryTool
to get the correlation factors:- cross-section vs. efficiency (electron) : -0.14
- cross-section vs. efficiency (muon) : -0.14
- efficiency (electron) vs. efficiency (muon): 0.02
- Possible values to summarize the cross-section estimate for
the variation ansatz:
- Mean ± RMS: (10.91 ± 1.41 +0.25-0.22) pb
- Median and central 68% interval: (10.93 +1.40 -1.82 +0.25-0.22) pb
- Mode and smallest interval 11.36 pb +0.25-0.22 with (8.24, 14.48) pb
- Individual values and uncertainties:
Δσ = N-1/2 / L / ε
Muon channel: σμ = (10.86 ± 1.79) pb
Electron channel: σe = (10.50 ± 2.35) pb
Weighted average: σ = (10.73 ± 1.42) pb
Step 4 - Including correlated uncertainties
One source of systematic uncertainty common to both channels is the luminosity. This steps shows how to include correlated uncertainties giving this example.
- Include a systematic uncertainty for the luminosity of 3%. How does the (marginalized) posterior for the cross-section change?
- Calculate the correlation factors between the four parameters.
- Compare your results to those obtained with Gaussian error propagation, in particular the central value. Mind the correlation in both channels.
- Code
#include <XSecCombiModel.h> #include <BAT/BCMath.h> // --------------------------------------------------------- XSecCombiModel::XSecCombiModel() : BCModel() , fEfficiencyMu(0.35) , fEfficiencyE(0.20) , fLuminosity(10.) , fErrorEfficiencyMu(0.01) , fErrorEfficiencyE(0.01) , fErrorLuminosity(0.03) , fNobsMu(38) , fNobsE(21) { // default constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::XSecCombiModel(const char * name) : BCModel(name) { // constructor DefineParameters(); }; // --------------------------------------------------------- XSecCombiModel::~XSecCombiModel() { // default destructor }; // --------------------------------------------------------- void XSecCombiModel::DefineParameters() { // Add parameters to your model here. // You can then use them in the methods below by calling the // parameters.at(i) or parameters[i], where i is the index // of the parameter. The indices increase from 0 according to the // order of adding the parameters. // total cross-section in pb AddParameter("xsec", 2.0, 210.0); // index 0 // nuisance parameter for efficiency for muon channel in "sigma" AddParameter("effMu", -5.0, 5.0); // index 1 // nuisance parameter for efficiency for electron channel in "sigma" AddParameter("effE", -5.0, 5.0); // index 2 // nuisance parameter for luminosity in "sigma" AddParameter("luminosity", -5.0, 5.0); // index 3 } // --------------------------------------------------------- double XSecCombiModel::LogLikelihood(const std::vector <double> & parameters) { // This methods returns the logarithm of the conditional probability // p(data|parameters). This is where you have to define your model. double logprob = 0.; // get parameters and calculate nuisance term double xsec = parameters[0]; double deffMu = parameters[1] * fErrorEfficiencyMu; double deffE = parameters[2] * fErrorEfficiencyE; double dlumi = parameters[3] * fErrorLuminosity; // calculate efficiency as sum of estimated efficiency plus nuisance // term double effMu = fEfficiencyMu + deffMu; double effE = fEfficiencyE + deffE; // calculate luminosity as sum of estimated luminosity plus nuisance // term double luminosity = fLuminosity + dlumi ; // check if efficiencies and luminosity are positive if (effMu < 0 || effE < 0 || luminosity < 0) return -1e99; // calculate expected number of muon and electron events double nexpectedMu = xsec * luminosity * effMu; double nexpectedE = xsec * luminosity * effE; // Poisson probability for observing a certain number of events // given some expectation (muon channel) if (fNobsMu >= 0) // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(fNobsMu)); // logprob += BCMath::LogGaus(fNobsMu, nexpectedMu, sqrt(nexpectedMu)); logprob += BCMath::LogPoisson(fNobsMu, nexpectedMu); // Poisson probability for observing a certain number of events // given some expectation (electron channel) if (fNobsE >= 0) // logprob += BCMath::LogGaus(fNobsE, nexpectedE, sqrt(fNobsE)); // logprob += BCMath::LogGaus(fNobsE, nexpectedE, sqrt(nexpectedE)); logprob += BCMath::LogPoisson(fNobsE, nexpectedE); return logprob; } // --------------------------------------------------------- double XSecCombiModel::LogAPrioriProbability(const std::vector <double> & parameters) { // This method returns the logarithm of the prior probability for the // parameters p(parameters). double logprob = 0.; // get parameters double deffMu = parameters[1]; double deffE = parameters[2]; double dlumi = parameters[3]; // get parameter range double dxsec = GetParameter(0)->GetRangeWidth(); // flat prior for cross-section logprob += log(1./dxsec); // Gaussian prior for efficiency if (fErrorEfficiencyMu > 0.) logprob += BCMath::LogGaus(deffMu, 0., 1.0); // Gaussian prior for efficiency if (fErrorEfficiencyE > 0.) logprob += BCMath::LogGaus(deffE, 0., 1.0); // Gaussian prior for luminosity if (fErrorLuminosity > 0.) logprob += BCMath::LogGaus(dlumi, 0., 1.0); return logprob; } // ---------------------------------------------------------
Possible values to summarize the cross-section estimate for the nuisance parameter ansatz:- Mean ± RMS: (10.93 ± 1.44) pb (symmetric)
- Median and central 68% interval: (10.95 +1.43 -1.84) pb
- Mode and smallest interval 11.38 pb with (9.11, 12.46) pb
- Correlation factors:
- cross-section vs. efficiency (electron) : -0.14
- cross-section vs. efficiency (muon) : -0.14
- cross-section vs. luminosity : -0.02
- efficiency (electron) vs. efficiency (muon): 0.02
- efficiency (electron) vs. luminosity: 0.006
- efficiency (muon) vs. luminosity: -0.0001
- Possible values to summarize the cross-section estimate for
the variation ansatz:
- Mean ± RMS: (10.91 ± 1.41 +0.25-0.22+0.12-0.16) pb
- Median and central 68% interval: (10.93 +1.40 -1.82 +0.25-0.22+0.12-0.16) pb
- Mode and smallest interval 11.38 pb with (9.11, 12.46) +0.25-0.22+0.12-0.16 pb
- Individual values and uncertainties:
Δσ = N-1/2 / L / ε
Muon channel: σμ = (11.16 ± 1.80) pb
Electron channel: σe = (11.05 ± 2.43) pb
Weighted average: σ = (10.92 ± 1.43) pb
Step 5 - Large and small statistics
The last step shows that the extreme case for large statistics yields the same results obtained with Gaussian error propagation.
- Repeat your study using a luminosity of 100 pb-1 and 361 and 212 events in the muon and electron channel, respectively. Compare the results obtained with a Gaussian ansatz using common error propagation.
- Repeat your study using a luminosity of 0.5 pb-1 and 0 observed events in both channels. Compare the results obtained with a Gaussian ansatz using common error propagation. Describe the transition from setting a limit to an actual measurement. How does the combination improve the limit?
- Repeat your study using a luminosity of 0.5 pb-1 and 1 observed events in both channels. Compare the results obtained with a Gaussian ansatz using common error propagation. Describe the transition from setting a limit to an actual measurement. How does the combination improve the limit?
- Possible values to summarize the cross-section estimate for
the nuisance parameter ansatz:
- Mean ± RMS: (10.44 ± 0.51) pb (symmetric)
- Median and central 68% interval: (10.63 +1.20 -1.58) pb
- Mode and smallest interval 11.36 pb with (8.24, 14.48) pb
Electron channel: σe = (10.60 ± 1.41) pb
Weighted average: σ = (10.41 ± 0.51) pb
-
95% probability limits on the cross-section:
Combined channel: 10.07 pb (with range (0, 50) pb)
Gaussian uncertainty propagation does not work. -
Possible values to summarize the cross-section estimate for
the nuisance parameter ansatz:
- Mean ± RMS: (10.15 ± 5.86) pb (symmetric)
- Median and central 68% interval: (9.04 +6.72 -4.42) pb
- Mode and smallest interval 8.25 pb with (3, 14) pb
Additional studies
- Use a flat prior for the systematic uncertainty of the luminosity. How does the (marginalized) posterior for the cross-section change?
- Increase the uncertainties to 0.05 for the efficiencies and 10% for the luminosity. How does the (marginalized) posterior for the cross-section change? Have a look at the correlation plots. What can you learn about the systematic uncertainties?
- Extend your model such that it is possible to include background processes which can, but do not necessarily have to, be correlated.
Further material and documentation
For a short introduction to this tutorial, see this PDF.
Kevin Kröninger Last modified: Mon Sep 28 14:33:38 CEST 2009