Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
rs401d_FeldmanCousins.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_roostats
3 /// \notebook
4 /// Neutrino Oscillation Example from Feldman & Cousins
5 ///
6 /// This tutorial shows a more complex example using the FeldmanCousins utility
7 /// to create a confidence interval for a toy neutrino oscillation experiment.
8 /// The example attempts to faithfully reproduce the toy example described in Feldman & Cousins'
9 /// original paper, Phys.Rev.D57:3873-3889,1998.
10 ///
11 /// \macro_image
12 /// \macro_output
13 /// \macro_code
14 ///
15 /// \author Kyle Cranmer
16 
17 #include "RooGlobalFunc.h"
18 #include "RooStats/ConfInterval.h"
25 #include "RooStats/MCMCInterval.h"
26 
27 #include "RooDataSet.h"
28 #include "RooDataHist.h"
29 #include "RooRealVar.h"
30 #include "RooConstVar.h"
31 #include "RooAddition.h"
32 #include "RooProduct.h"
33 #include "RooProdPdf.h"
34 #include "RooAddPdf.h"
35 
36 #include "TROOT.h"
37 #include "RooPolynomial.h"
38 #include "RooRandom.h"
39 
40 #include "RooNLLVar.h"
41 #include "RooProfileLL.h"
42 
43 #include "RooPlot.h"
44 
45 #include "TCanvas.h"
46 #include "TH1F.h"
47 #include "TH2F.h"
48 #include "TTree.h"
49 #include "TMarker.h"
50 #include "TStopwatch.h"
51 
52 #include <iostream>
53 
54 // PDF class created for this macro
55 #if !defined(__CINT__) || defined(__MAKECINT__)
56 #include "../tutorials/roostats/NuMuToNuE_Oscillation.h"
57 #include "../tutorials/roostats/NuMuToNuE_Oscillation.cxx" // so that it can be executed directly
58 #else
59 #include "../tutorials/roostats/NuMuToNuE_Oscillation.cxx+" // so that it can be executed directly
60 #endif
61 
62 // use this order for safety on library loading
63 using namespace RooFit;
64 using namespace RooStats;
65 
66 void rs401d_FeldmanCousins(bool doFeldmanCousins = false, bool doMCMC = true)
67 {
68 
69  // to time the macro
70  TStopwatch t;
71  t.Start();
72 
73  // Taken from Feldman & Cousins paper, Phys.Rev.D57:3873-3889,1998.
74  // e-Print: physics/9711021 (see page 13.)
75  //
76  // Quantum mechanics dictates that the probability of such a transformation is given by the formula
77  // $P (\nu\mu \rightarrow \nu e ) = sin^2 (2\theta) sin^2 (1.27 \Delta m^2 L /E )$
78  // where P is the probability for a $\nu\mu$ to transform into a $\nu e$ , L is the distance in km between
79  // the creation of the neutrino from meson decay and its interaction in the detector, E is the
80  // neutrino energy in GeV, and $\Delta m^2 = |m^2 - m^2 |$ in $(eV/c^2 )^2$ .
81  //
82  // To demonstrate how this works in practice, and how it compares to alternative approaches
83  // that have been used, we consider a toy model of a typical neutrino oscillation experiment.
84  // The toy model is defined by the following parameters: Mesons are assumed to decay to
85  // neutrinos uniformly in a region 600 m to 1000 m from the detector. The expected background
86  // from conventional $\nu e$ interactions and misidentified $\nu\mu$ interactions is assumed to be 100
87  // events in each of 5 energy bins which span the region from 10 to 60 GeV. We assume that
88  // the $\nu\mu$ flux is such that if $P (\nu\mu \rightarrow \nu e ) = 0.01$ averaged over any bin, then that bin
89  // would
90  // have an expected additional contribution of 100 events due to $\nu\mu \rightarrow \nu e$ oscillations.
91 
92  // Make signal model model
93  RooRealVar E("E", "", 15, 10, 60, "GeV");
94  RooRealVar L("L", "", .800, .600, 1.0, "km"); // need these units in formula
95  RooRealVar deltaMSq("deltaMSq", "#Delta m^{2}", 40, 1, 300, "eV/c^{2}");
96  RooRealVar sinSq2theta("sinSq2theta", "sin^{2}(2#theta)", .006, .0, .02);
97  // RooRealVar deltaMSq("deltaMSq","#Delta m^{2}",40,20,70,"eV/c^{2}");
98  // RooRealVar sinSq2theta("sinSq2theta","sin^{2}(2#theta)", .006,.001,.01);
99  // PDF for oscillation only describes deltaMSq dependence, sinSq2theta goes into sigNorm
100  // 1) The code for this PDF was created by issuing these commands
101  // root [0] RooClassFactory x
102  // root [1] x.makePdf("NuMuToNuE_Oscillation","L,E,deltaMSq","","pow(sin(1.27*deltaMSq*L/E),2)")
103  NuMuToNuE_Oscillation PnmuTone("PnmuTone", "P(#nu_{#mu} #rightarrow #nu_{e}", L, E, deltaMSq);
104 
105  // only E is observable, so create the signal model by integrating out L
106  RooAbsPdf *sigModel = PnmuTone.createProjection(L);
107 
108  // create $ \int dE' dL' P(E',L' | \Delta m^2)$.
109  // Given RooFit will renormalize the PDF in the range of the observables,
110  // the average probability to oscillate in the experiment's acceptance
111  // needs to be incorporated into the extended term in the likelihood.
112  // Do this by creating a RooAbsReal representing the integral and divide by
113  // the area in the E-L plane.
114  // The integral should be over "primed" observables, so we need
115  // an independent copy of PnmuTone not to interfere with the original.
116 
117  // Independent copy for Integral
118  RooRealVar EPrime("EPrime", "", 15, 10, 60, "GeV");
119  RooRealVar LPrime("LPrime", "", .800, .600, 1.0, "km"); // need these units in formula
120  NuMuToNuE_Oscillation PnmuTonePrime("PnmuTonePrime", "P(#nu_{#mu} #rightarrow #nu_{e}", LPrime, EPrime, deltaMSq);
121  RooAbsReal *intProbToOscInExp = PnmuTonePrime.createIntegral(RooArgSet(EPrime, LPrime));
122 
123  // Getting the flux is a bit tricky. It is more clear to include a cross section term that is not
124  // explicitly referred to in the text, eg.
125  // number events in bin = flux * cross-section for nu_e interaction in E bin * average prob nu_mu osc. to nu_e in bin
126  // let maxEventsInBin = flux * cross-section for nu_e interaction in E bin
127  // maxEventsInBin * 1% chance per bin = 100 events / bin
128  // therefore maxEventsInBin = 10,000.
129  // for 5 bins, this means maxEventsTot = 50,000
130  RooConstVar maxEventsTot("maxEventsTot", "maximum number of sinal events", 50000);
131  RooConstVar inverseArea("inverseArea", "1/(#Delta E #Delta L)",
132  1. / (EPrime.getMax() - EPrime.getMin()) / (LPrime.getMax() - LPrime.getMin()));
133 
134  // $sigNorm = maxEventsTot \cdot \int dE dL \frac{P_{oscillate\ in\ experiment}}{Area} \cdot {sin}^2(2\theta)$
135  RooProduct sigNorm("sigNorm", "", RooArgSet(maxEventsTot, *intProbToOscInExp, inverseArea, sinSq2theta));
136  // bkg = 5 bins * 100 events / bin
137  RooConstVar bkgNorm("bkgNorm", "normalization for background", 500);
138 
139  // flat background (0th order polynomial, so no arguments for coefficients)
140  RooPolynomial bkgEShape("bkgEShape", "flat bkg shape", E);
141 
142  // total model
143  RooAddPdf model("model", "", RooArgList(*sigModel, bkgEShape), RooArgList(sigNorm, bkgNorm));
144 
145  // for debugging, check model tree
146  // model.printCompactTree();
147  // model.graphVizTree("model.dot");
148 
149  // turn off some messages
150  RooMsgService::instance().setStreamStatus(0, kFALSE);
151  RooMsgService::instance().setStreamStatus(1, kFALSE);
152  RooMsgService::instance().setStreamStatus(2, kFALSE);
153 
154  // --------------------------------------
155  // n events in data to data, simply sum of sig+bkg
156  Int_t nEventsData = bkgNorm.getVal() + sigNorm.getVal();
157  cout << "generate toy data with nEvents = " << nEventsData << endl;
158  // adjust random seed to get a toy dataset similar to one in paper.
159  // Found by trial and error (3 trials, so not very "fine tuned")
160  RooRandom::randomGenerator()->SetSeed(3);
161  // create a toy dataset
162  RooDataSet *data = model.generate(RooArgSet(E), nEventsData);
163 
164  // --------------------------------------
165  // make some plots
166  TCanvas *dataCanvas = new TCanvas("dataCanvas");
167  dataCanvas->Divide(2, 2);
168 
169  // plot the PDF
170  dataCanvas->cd(1);
171  TH1 *hh = PnmuTone.createHistogram("hh", E, Binning(40), YVar(L, Binning(40)), Scaling(kFALSE));
172  hh->SetLineColor(kBlue);
173  hh->SetTitle("True Signal Model");
174  hh->Draw("surf");
175 
176  // plot the data with the best fit
177  dataCanvas->cd(2);
178  RooPlot *Eframe = E.frame();
179  data->plotOn(Eframe);
180  model.fitTo(*data, Extended());
181  model.plotOn(Eframe);
182  model.plotOn(Eframe, Components(*sigModel), LineColor(kRed));
183  model.plotOn(Eframe, Components(bkgEShape), LineColor(kGreen));
184  model.plotOn(Eframe);
185  Eframe->SetTitle("toy data with best fit model (and sig+bkg components)");
186  Eframe->Draw();
187 
188  // plot the likelihood function
189  dataCanvas->cd(3);
190  RooNLLVar nll("nll", "nll", model, *data, Extended());
191  RooProfileLL pll("pll", "", nll, RooArgSet(deltaMSq, sinSq2theta));
192  // TH1* hhh = nll.createHistogram("hhh",sinSq2theta,Binning(40),YVar(deltaMSq,Binning(40))) ;
193  TH1 *hhh = pll.createHistogram("hhh", sinSq2theta, Binning(40), YVar(deltaMSq, Binning(40)), Scaling(kFALSE));
194  hhh->SetLineColor(kBlue);
195  hhh->SetTitle("Likelihood Function");
196  hhh->Draw("surf");
197 
198  dataCanvas->Update();
199 
200  // --------------------------------------------------------------
201  // show use of Feldman-Cousins utility in RooStats
202  // set the distribution creator, which encodes the test statistic
203  RooArgSet parameters(deltaMSq, sinSq2theta);
204  RooWorkspace *w = new RooWorkspace();
205 
206  ModelConfig modelConfig;
207  modelConfig.SetWorkspace(*w);
208  modelConfig.SetPdf(model);
209  modelConfig.SetParametersOfInterest(parameters);
210 
211  RooStats::FeldmanCousins fc(*data, modelConfig);
212  fc.SetTestSize(.1); // set size of test
213  fc.UseAdaptiveSampling(true);
214  fc.SetNBins(10); // number of points to test per parameter
215 
216  // use the Feldman-Cousins tool
217  ConfInterval *interval = 0;
218  if (doFeldmanCousins)
219  interval = fc.GetInterval();
220 
221  // ---------------------------------------------------------
222  // show use of ProfileLikeihoodCalculator utility in RooStats
223  RooStats::ProfileLikelihoodCalculator plc(*data, modelConfig);
224  plc.SetTestSize(.1);
225 
226  ConfInterval *plcInterval = plc.GetInterval();
227 
228  // --------------------------------------------
229  // show use of MCMCCalculator utility in RooStats
230  MCMCInterval *mcInt = NULL;
231 
232  if (doMCMC) {
233  // turn some messages back on
234  RooMsgService::instance().setStreamStatus(0, kTRUE);
235  RooMsgService::instance().setStreamStatus(1, kTRUE);
236 
237  TStopwatch mcmcWatch;
238  mcmcWatch.Start();
239 
240  RooArgList axisList(deltaMSq, sinSq2theta);
241  MCMCCalculator mc(*data, modelConfig);
242  mc.SetNumIters(5000);
243  mc.SetNumBurnInSteps(100);
244  mc.SetUseKeys(true);
245  mc.SetTestSize(.1);
246  mc.SetAxes(axisList); // set which is x and y axis in posterior histogram
247  // mc.SetNumBins(50);
248  mcInt = (MCMCInterval *)mc.GetInterval();
249 
250  mcmcWatch.Stop();
251  mcmcWatch.Print();
252  }
253  // -------------------------------
254  // make plot of resulting interval
255 
256  dataCanvas->cd(4);
257 
258  // first plot a small dot for every point tested
259  if (doFeldmanCousins) {
260  RooDataHist *parameterScan = (RooDataHist *)fc.GetPointsToScan();
261  TH2F *hist = (TH2F *)parameterScan->createHistogram("sinSq2theta:deltaMSq", 30, 30);
262  // hist->Draw();
263  TH2F *forContour = (TH2F *)hist->Clone();
264 
265  // now loop through the points and put a marker if it's in the interval
266  RooArgSet *tmpPoint;
267  // loop over points to test
268  for (Int_t i = 0; i < parameterScan->numEntries(); ++i) {
269  // get a parameter point from the list of points to test.
270  tmpPoint = (RooArgSet *)parameterScan->get(i)->clone("temp");
271 
272  if (interval) {
273  if (interval->IsInInterval(*tmpPoint)) {
274  forContour->SetBinContent(
275  hist->FindBin(tmpPoint->getRealValue("sinSq2theta"), tmpPoint->getRealValue("deltaMSq")), 1);
276  } else {
277  forContour->SetBinContent(
278  hist->FindBin(tmpPoint->getRealValue("sinSq2theta"), tmpPoint->getRealValue("deltaMSq")), 0);
279  }
280  }
281 
282  delete tmpPoint;
283  }
284 
285  if (interval) {
286  Double_t level = 0.5;
287  forContour->SetContour(1, &level);
288  forContour->SetLineWidth(2);
289  forContour->SetLineColor(kRed);
290  forContour->Draw("cont2,same");
291  }
292  }
293 
294  MCMCIntervalPlot *mcPlot = NULL;
295  if (mcInt) {
296  cout << "MCMC actual confidence level: " << mcInt->GetActualConfidenceLevel() << endl;
297  mcPlot = new MCMCIntervalPlot(*mcInt);
298  mcPlot->SetLineColor(kMagenta);
299  mcPlot->Draw();
300  }
301  dataCanvas->Update();
302 
303  LikelihoodIntervalPlot plotInt((LikelihoodInterval *)plcInterval);
304  plotInt.SetTitle("90% Confidence Intervals");
305  if (mcInt)
306  plotInt.Draw("same");
307  else
308  plotInt.Draw();
309  dataCanvas->Update();
310 
311  /// print timing info
312  t.Stop();
313  t.Print();
314 }