SensitivityCalculator.cc
1 #include "SensitivityCalculator.h"
2 #include "TGraphErrors.h"
3 #include "TAxis.h"
4 #include "TH1.h"
5 
6 #ifdef USE_ROOSTATS
7 #include "RooWorkspace.h"
8 #include "RooStats/FeldmanCousins.h"
9 #include "RooStats/HypoTestResult.h"
10 #include "RooStats/ProfileLikelihoodCalculator.h"
11 #endif
12 
13 
14 SensitivityCalculator::~SensitivityCalculator()
15 {
16 #ifdef USE_ROOSTATS
17 
18  delete w;
19 #endif
20 }
21 
22 
23 
24 SensitivityCalculator::SensitivityCalculator(double CL, bool FC)
25 {
26  cl = CL;
27  use_fc = FC;
28 
29 #ifndef USE_ROOSTATS
30 
31  fprintf(stderr,"Need to build with USE_ROOSTATS to use Sensitivity Calculator\n");
32 
33 
34 #else
35  w = new RooWorkspace("w");
36 
37 
38  /* We observe from a poisson distribution, with a mean of e * s + banthro + bthermal */
39  w->factory("Poisson::obsModel(nobs[0,0,20], sum(prod(s[1,0,50], eff[0.7,0,1]),banthro[1,0,30],bthermal[0.3,0,30]))");
40 
41  /*We estimate bthermal from the counts in a sideband that's tauthermal size the signal region, so nthermal (what we observe) is poisson distributed with a mean of tauthermal * bthermal */
42  w->factory("Poisson::thermalModel(nthermal[1,0,30], prod::taubthermal(bthermal, tauthermal[3,0,10]))");
43 
44  /*We estimate banthro from the counts in a sideband that's tauanthro size the signal region, so nanthro (what we observe) is poisson distributed with a mean of tauanthro * banthro */
45  w->factory("Poisson::anthroModel(nanthro[1,0,30], prod::taubanthro(banthro, tauanthro[1,0,10]))");
46 
47  /*Errors on tau anthro */
48  w->factory("Gaussian::anthroTauErrorModel(mean_tauanthro[1,0,10],tauanthro, sigma_tau_anthro[0.1,0,1])");
49 
50  /* We assign a systematic error (gaussian) to our analysis efficiency */
51  w->factory("Gaussian::effModel(mean_eff[0.7,0,1], eff, sigma_eff[0.05,0,0.2])");
52 
53  /* The likelihood model is the product of all of the distributions */
54  w->factory("PROD::model(obsModel,thermalModel,anthroModel,effModel, anthroTauErrorModel)");
55 
56 // w->factory("SUM:total_bg(banthro,bthermal)");
57 
58 
59 
60 
61  /* Set all auxilliary observables to constants */
62  w->var("tauthermal")->setConstant();
63  w->var("mean_tauanthro")->setConstant();
64  w->var("sigma_tau_anthro")->setConstant();
65  w->var("nthermal")->setConstant();
66  w->var("nanthro")->setConstant();
67  w->var("mean_eff")->setConstant();
68  w->var("sigma_eff")->setConstant();
69 
70  w->defineSet("poi","s"); //parameter of interest
71  w->defineSet("nuis","bthermal,banthro,eff,tauanthro"); //nuisance parameters
72  w->defineSet("gobs","nthermal,nanthro,tauthermal,mean_tauanthro,sigma_tau_anthro,mean_eff,sigma_eff"); //"global observed parameters"
73  w->defineSet("obs","nobs"); //"main observed parameters"
74  w->defineSet("sens","bthermal,banthro,eff,nobs,tauanthro");
75  w->defineSet("bkg_anthro","banthro,tauanthro");
76  w->defineSet("bkg_thermal","bthermal");
77  w->defineSet("bkg_total","banthro,tauanthro,bthermal");
78 
79  setEfficiency(0.7,0.05);
80  setThermalBackground(1,3);
81  setAnthroBackground(1,1,0.1);
82 #endif
83 
84 }
85 
86 void SensitivityCalculator::SensitivityCalculator::setThermalBackground(int nobs, double tau)
87 {
88 #ifdef USE_ROOSTATS
89  w->var("tauthermal")->setVal(tau);
90  w->var("nthermal")->setVal(nobs);
91 #endif
92 }
93 
94 
95 void SensitivityCalculator::SensitivityCalculator::setAnthroBackground(int nobs, double tau, double sigma_tau)
96 {
97 #ifdef USE_ROOSTATS
98  w->var("mean_tauanthro")->setVal(tau);
99  w->var("sigma_tau_anthro")->setVal(sigma_tau);
100  w->var("nanthro")->setVal(nobs);
101 #endif
102 
103 }
104 
105 void SensitivityCalculator::SensitivityCalculator::setEfficiency(double mean, double sigma)
106 {
107 #ifdef USE_ROOSTATS
108  if (sigma == 0)
109  {
110  w->var("eff")->setVal(mean);
111  w->var("eff")->setConstant(true);
112 
113  }
114  else
115  {
116  w->var("eff")->setConstant(false);
117  w->var("mean_eff")->setVal(mean);
118  w->var("sigma_eff")->setVal(sigma);
119  }
120 #endif
121 }
122 
123 
124 
125 double SensitivityCalculator::getLimit(int nobs, double * lower, double * upper)
126 {
127 #ifdef USE_ROOSTATS
128  w->var("s")->setConstant(false);
129  w->var("nobs")->setVal(nobs);
130  RooDataSet data("data","",*w->var("nobs"));
131  data.add(*w->var("nobs"));
132 
133  //generate model with what we've observed
134  RooStats::ModelConfig m("mod");
135  m.SetWorkspace(*w);
136  m.SetPdf(*w->pdf("model"));
137  m.SetObservables(*w->var("nobs"));
138  m.SetGlobalObservables(*w->set("gobs"));
139  m.SetParametersOfInterest(*w->set("poi"));
140  m.SetNuisanceParameters(*w->set("nuis"));
141 
142  if (use_fc)
143  {
144  RooStats::FeldmanCousins fc(data,m);
145  fc.SetConfidenceLevel(cl);
146  fc.FluctuateNumDataEntries(false); // number counting experiment!
147  fc.UseAdaptiveSampling(true); //no idea what this does but it's supposed to make it faster
148  fc.SetNBins(501);
149  RooStats::PointSetInterval * ci = fc.GetInterval();
150 
151  if (upper) *upper=ci->UpperLimit(*w->var("s"));
152  if (lower) *lower=ci->LowerLimit(*w->var("s"));
153  return 0;
154  }
155  else
156  {
157  //use profile likelihood
158  RooStats::ProfileLikelihoodCalculator pl(data, m);
159  pl.SetConfidenceLevel(cl);
160  pl.SetNullParameters(*w->set("poi"));
161  RooStats::LikelihoodInterval * ci = pl.GetInterval();
162  pl.GetHypoTest()->Print();
163  if (upper) *upper=ci->UpperLimit(*w->var("s"));
164  if (lower) *lower=ci->LowerLimit(*w->var("s"));
165  return 0;
166  }
167 #endif
168 
169 
170 }
171 
172 
173 TGraphErrors * SensitivityCalculator::confidenceBands(int start, int stop)
174 {
175  TGraphErrors * g = new TGraphErrors(stop-start+1);
176  g->SetMarkerStyle(0);
177  g->SetTitle(TString::Format("%g%% bands", cl * 100));
178  g->GetXaxis()->SetTitle("Nobserved");
179  g->GetYaxis()->SetTitle("Signal");
180 
181  int ii = 0;
182  for (int i = start; i <= stop; i++)
183  {
184  double l,u;
185  getLimit(i,&l,&u);
186 
187  g->SetPoint(ii, i, (l+u)/2);
188  g->SetPointError(ii, 0, (u-l)/2);
189  ii++;
190  }
191 
192  return g;
193 
194 }
195 
196 
197 TH1 * SensitivityCalculator::histBAnthro()
198 {
199 #ifdef USE_ROOSTATS
200  RooDataSet * data = w->pdf("model")->generate(*w->set("bkg_anthro"),10000);
201  TH1 * hist = data->createHistogram("B_{anthro}", *w->var("banthro"));
202  hist->Scale(1./10000);
203  delete data;
204  return hist;
205 #else
206  return 0;
207 #endif
208 }
209 
210 TH1 * SensitivityCalculator::histBThermal()
211 {
212 #ifdef USE_ROOSTATS
213  RooDataSet * data = w->pdf("model")->generate(*w->set("bkg_thermal"),10000);
214  TH1 * hist = data->createHistogram("B_{thermal}", *w->var("bthermal"));
215  hist->Scale(1./10000);
216  delete data;
217  return hist;
218 #else
219  return 0;
220 #endif
221 }
222 
223 TH1 * SensitivityCalculator::histBTotal()
224 {
225  TH1 * banthro = histBAnthro();
226  TH1 * bthermal = histBThermal();
227  TH1 * btotal = new TH1D("total", "Total", 100,0,20);
228 
229  for (int i = 0; i < 10000; i++)
230  {
231  btotal->Fill(banthro->GetRandom() + bthermal->GetRandom());
232  }
233  btotal->Scale(1./btotal->Integral());
234  delete banthro;
235  delete bthermal;
236  return btotal;
237 }
238 
239 
240 
241 
242 TH1 * SensitivityCalculator::histNObserved(double S)
243 {
244 #ifdef USE_ROOSTATS
245 
246  w->var("s")->setVal(S);
247  w->var("s")->setConstant(true);
248  RooDataSet * data = w->pdf("model")->generate(*w->set("sens"),10000);
249 // data->Print();
250  TString str;
251  str.Form("observed_s_%g",S);
252  TH1 * hist = data->createHistogram(str.Data(), *w->var("nobs"),RooFit::Binning(20,0,20));
253  hist->Scale(1./10000);
254  delete data;
255  w->var("s")->setConstant(false);
256  return hist;
257 #else
258  return 0;
259 #endif
260 }
261 
262 
263 
264