1 |
/* -*- mode: c++ -*- */
|
2 |
// Standard tutorial macro for performing an inverted hypothesis test
|
3 |
//
|
4 |
// This macro will perform a scan of tehe p-values for computing the limit
|
5 |
//
|
6 |
|
7 |
#include <iostream>
|
8 |
|
9 |
#include "StandardHypoTestInvDemo.h"
|
10 |
|
11 |
#include "TFile.h"
|
12 |
#include "RooWorkspace.h"
|
13 |
#include "RooAbsPdf.h"
|
14 |
#include "RooRealVar.h"
|
15 |
#include "RooDataSet.h"
|
16 |
#include "RooStats/ModelConfig.h"
|
17 |
#include "TGraphErrors.h"
|
18 |
#include "TGraphAsymmErrors.h"
|
19 |
#include "TCanvas.h"
|
20 |
#include "TLine.h"
|
21 |
#include "TROOT.h"
|
22 |
|
23 |
#include "RooStats/AsymptoticCalculator.h"
|
24 |
#include "RooStats/HybridCalculator.h"
|
25 |
#include "RooStats/FrequentistCalculator.h"
|
26 |
#include "RooStats/ToyMCSampler.h"
|
27 |
#include "RooStats/HypoTestPlot.h"
|
28 |
|
29 |
#include "RooStats/NumEventsTestStat.h"
|
30 |
#include "RooStats/ProfileLikelihoodTestStat.h"
|
31 |
#include "RooStats/SimpleLikelihoodRatioTestStat.h"
|
32 |
#include "RooStats/RatioOfProfiledLikelihoodsTestStat.h"
|
33 |
#include "RooStats/MaxLikelihoodEstimateTestStat.h"
|
34 |
|
35 |
#include "RooStats/HypoTestInverter.h"
|
36 |
#include "RooStats/HypoTestInverterResult.h"
|
37 |
#include "RooStats/HypoTestInverterPlot.h"
|
38 |
|
39 |
using namespace RooFit;
|
40 |
using namespace RooStats;
|
41 |
|
42 |
|
43 |
bool plotHypoTestResult = true; // plot test statistic result at each point
|
44 |
bool writeResult = true; // write HypoTestInverterResult in a file
|
45 |
bool optimize = true; // optmize evaluation of test statistic
|
46 |
bool useVectorStore = true; // convert data to use new roofit data store
|
47 |
bool generateBinned = false; // generate binned data sets
|
48 |
bool noSystematics = false; // force all systematics to be off (i.e. set all nuisance parameters as constat
|
49 |
// to their nominal values)
|
50 |
double nToysRatio = 2; // ratio Ntoys S+b/ntoysB
|
51 |
double maxPOI = -1; // max value used of POI (in case of auto scan)
|
52 |
bool useProof = false; // use Proof Light when using toys (for freq or hybrid)
|
53 |
int nworkers = 4; // number of worker for Proof
|
54 |
bool rebuild = false; // re-do extra toys for computing expected limits and rebuild test stat
|
55 |
// distributions (N.B this requires much more CPU (factor is equivalent to nToyToRebuild)
|
56 |
int nToyToRebuild = 100; // number of toys used to rebuild
|
57 |
|
58 |
std::string massValue = ""; // extra string to tag output file of result
|
59 |
std::string minimizerType = ""; // minimizer type (default is what is in ROOT::Math::MinimizerOptions::DefaultMinimizerType()
|
60 |
int printLevel = 0; // print level for debugging PL test statistics and calculators
|
61 |
|
62 |
|
63 |
|
64 |
// internal class to run the inverter and more
|
65 |
|
66 |
|
67 |
RooStats::HypoTestInvTool::HypoTestInvTool() : mPlotHypoTestResult(true),
|
68 |
mWriteResult(false),
|
69 |
mOptimize(true),
|
70 |
mUseVectorStore(true),
|
71 |
mGenerateBinned(false),
|
72 |
mUseProof(false),
|
73 |
mRebuild(false),
|
74 |
mNWorkers(4),
|
75 |
mNToyToRebuild(100),
|
76 |
mPrintLevel(0),
|
77 |
mNToysRatio(2),
|
78 |
mMaxPoi(-1),
|
79 |
mMassValue(""),
|
80 |
mMinimizerType(""){
|
81 |
}
|
82 |
|
83 |
|
84 |
|
85 |
void
|
86 |
RooStats::HypoTestInvTool::SetParameter(const char * name, bool value){
|
87 |
//
|
88 |
// set boolean parameters
|
89 |
//
|
90 |
|
91 |
std::string s_name(name);
|
92 |
|
93 |
if (s_name.find("PlotHypoTestResult") != std::string::npos) mPlotHypoTestResult = value;
|
94 |
if (s_name.find("WriteResult") != std::string::npos) mWriteResult = value;
|
95 |
if (s_name.find("Optimize") != std::string::npos) mOptimize = value;
|
96 |
if (s_name.find("UseVectorStore") != std::string::npos) mUseVectorStore = value;
|
97 |
if (s_name.find("GenerateBinned") != std::string::npos) mGenerateBinned = value;
|
98 |
if (s_name.find("UseProof") != std::string::npos) mUseProof = value;
|
99 |
if (s_name.find("Rebuild") != std::string::npos) mRebuild = value;
|
100 |
|
101 |
return;
|
102 |
}
|
103 |
|
104 |
|
105 |
|
106 |
void
|
107 |
RooStats::HypoTestInvTool::SetParameter(const char * name, int value){
|
108 |
//
|
109 |
// set integer parameters
|
110 |
//
|
111 |
|
112 |
std::string s_name(name);
|
113 |
|
114 |
if (s_name.find("NWorkers") != std::string::npos) mNWorkers = value;
|
115 |
if (s_name.find("NToyToRebuild") != std::string::npos) mNToyToRebuild = value;
|
116 |
if (s_name.find("PrintLevel") != std::string::npos) mPrintLevel = value;
|
117 |
|
118 |
return;
|
119 |
}
|
120 |
|
121 |
|
122 |
|
123 |
void
|
124 |
RooStats::HypoTestInvTool::SetParameter(const char * name, double value){
|
125 |
//
|
126 |
// set double precision parameters
|
127 |
//
|
128 |
|
129 |
std::string s_name(name);
|
130 |
|
131 |
if (s_name.find("NToysRatio") != std::string::npos) mNToysRatio = value;
|
132 |
if (s_name.find("MaxPoi") != std::string::npos) mMaxPoi = value;
|
133 |
|
134 |
return;
|
135 |
}
|
136 |
|
137 |
|
138 |
|
139 |
void
|
140 |
RooStats::HypoTestInvTool::SetParameter(const char * name, const char * value){
|
141 |
//
|
142 |
// set string parameters
|
143 |
//
|
144 |
|
145 |
std::string s_name(name);
|
146 |
|
147 |
if (s_name.find("MassValue") != std::string::npos) mMassValue.assign(value);
|
148 |
if (s_name.find("MinimizerType") != std::string::npos) mMinimizerType.assign(value);
|
149 |
|
150 |
return;
|
151 |
}
|
152 |
|
153 |
|
154 |
|
155 |
void
|
156 |
StandardHypoTestInvDemo(const char * infile = 0,
|
157 |
const char * wsName = "combined",
|
158 |
const char * modelSBName = "ModelConfig",
|
159 |
const char * modelBName = "",
|
160 |
const char * dataName = "obsData",
|
161 |
int calculatorType = 0,
|
162 |
int testStatType = 0,
|
163 |
bool useCLs = true ,
|
164 |
int npoints = 6,
|
165 |
double poimin = 0,
|
166 |
double poimax = 5,
|
167 |
int ntoys=1000,
|
168 |
bool useNumberCounting = false,
|
169 |
const char * nuisPriorName = 0){
|
170 |
/*
|
171 |
|
172 |
Other Parameter to pass in tutorial
|
173 |
apart from standard for filename, ws, modelconfig and data
|
174 |
|
175 |
type = 0 Freq calculator
|
176 |
type = 1 Hybrid calculator
|
177 |
type = 2 Asymptotic calculator
|
178 |
|
179 |
testStatType = 0 LEP
|
180 |
= 1 Tevatron
|
181 |
= 2 Profile Likelihood
|
182 |
= 3 Profile Likelihood one sided (i.e. = 0 if mu < mu_hat)
|
183 |
|
184 |
useCLs scan for CLs (otherwise for CLs+b)
|
185 |
|
186 |
npoints: number of points to scan , for autoscan set npoints = -1
|
187 |
|
188 |
poimin,poimax: min/max value to scan in case of fixed scans
|
189 |
(if min >= max, try to find automatically)
|
190 |
|
191 |
ntoys: number of toys to use
|
192 |
|
193 |
useNumberCounting: set to true when using number counting events
|
194 |
|
195 |
nuisPriorName: name of prior for the nnuisance. This is often expressed as constraint term in the global model
|
196 |
It is needed only when using the HybridCalculator (type=1)
|
197 |
If not given by default the prior pdf from ModelConfig is used.
|
198 |
|
199 |
extra options are available as global paramwters of the macro. They major ones are:
|
200 |
|
201 |
plotHypoTestResult plot result of tests at each point (TS distributions) (defauly is true)
|
202 |
useProof use Proof (default is true)
|
203 |
writeResult write result of scan (default is true)
|
204 |
rebuild rebuild scan for expected limits (require extra toys) (default is false)
|
205 |
generateBinned generate binned data sets for toys (default is false) - be careful not to activate with
|
206 |
a too large (>=3) number of observables
|
207 |
nToyRatio ratio of S+B/B toys (default is 2)
|
208 |
|
209 |
|
210 |
*/
|
211 |
|
212 |
|
213 |
|
214 |
TString fileName(infile);
|
215 |
if (fileName.IsNull()) {
|
216 |
fileName = "results/example_combined_GaussExample_model.root";
|
217 |
std::cout << "Use standard file generated with HistFactory : " << fileName << std::endl;
|
218 |
}
|
219 |
|
220 |
// open file and check if input file exists
|
221 |
TFile * file = TFile::Open(fileName);
|
222 |
|
223 |
// if input file was specified but not found, quit
|
224 |
if(!file && !TString(infile).IsNull()){
|
225 |
std::cout <<"file " << fileName << " not found" << std::endl;
|
226 |
return;
|
227 |
}
|
228 |
|
229 |
// if default file not found, try to create it
|
230 |
if(!file ){
|
231 |
// Normally this would be run on the command line
|
232 |
std::cout <<"will run standard hist2workspace example"<<std::endl;
|
233 |
gROOT->ProcessLine(".! prepareHistFactory .");
|
234 |
gROOT->ProcessLine(".! hist2workspace config/example.xml");
|
235 |
std::cout <<"\n\n---------------------"<<std::endl;
|
236 |
std::cout <<"Done creating example input"<<std::endl;
|
237 |
std::cout <<"---------------------\n\n"<<std::endl;
|
238 |
|
239 |
// now try to access the file again
|
240 |
file = TFile::Open(fileName);
|
241 |
|
242 |
}
|
243 |
|
244 |
if(!file){
|
245 |
// if it is still not there, then we can't continue
|
246 |
std::cout << "Not able to run hist2workspace to create example input" <<std::endl;
|
247 |
return;
|
248 |
}
|
249 |
|
250 |
|
251 |
|
252 |
HypoTestInvTool calc;
|
253 |
|
254 |
// set parameters
|
255 |
calc.SetParameter("PlotHypoTestResult", plotHypoTestResult);
|
256 |
calc.SetParameter("WriteResult", writeResult);
|
257 |
calc.SetParameter("Optimize", optimize);
|
258 |
calc.SetParameter("UseVectorStore", useVectorStore);
|
259 |
calc.SetParameter("GenerateBinned", generateBinned);
|
260 |
calc.SetParameter("NToysRatio", nToysRatio);
|
261 |
calc.SetParameter("MaxPOI", maxPOI);
|
262 |
calc.SetParameter("UseProof", useProof);
|
263 |
calc.SetParameter("Nworkers", nworkers);
|
264 |
calc.SetParameter("Rebuild", rebuild);
|
265 |
calc.SetParameter("NToyToRebuild", nToyToRebuild);
|
266 |
calc.SetParameter("MassValue", massValue.c_str());
|
267 |
calc.SetParameter("MinimizerType", minimizerType.c_str());
|
268 |
calc.SetParameter("PrintLevel", printLevel);
|
269 |
|
270 |
|
271 |
RooWorkspace * w = dynamic_cast<RooWorkspace*>( file->Get(wsName) );
|
272 |
HypoTestInverterResult * r = 0;
|
273 |
std::cout << w << "\t" << fileName << std::endl;
|
274 |
if (w != NULL) {
|
275 |
r = calc.RunInverter(w, modelSBName, modelBName,
|
276 |
dataName, calculatorType, testStatType, useCLs,
|
277 |
npoints, poimin, poimax,
|
278 |
ntoys, useNumberCounting, nuisPriorName );
|
279 |
if (!r) {
|
280 |
std::cerr << "Error running the HypoTestInverter - Exit " << std::endl;
|
281 |
return;
|
282 |
}
|
283 |
}
|
284 |
else {
|
285 |
// case workspace is not present look for the inverter result
|
286 |
std::cout << "Reading an HypoTestInverterResult with name " << wsName << " from file " << fileName << std::endl;
|
287 |
r = dynamic_cast<HypoTestInverterResult*>( file->Get(wsName) ); //
|
288 |
if (!r) {
|
289 |
std::cerr << "File " << fileName << " does not contain a workspace or an HypoTestInverterResult - Exit "
|
290 |
<< std::endl;
|
291 |
file->ls();
|
292 |
return;
|
293 |
}
|
294 |
}
|
295 |
|
296 |
calc.AnalyzeResult( r, calculatorType, testStatType, useCLs, npoints, infile );
|
297 |
|
298 |
return;
|
299 |
}
|
300 |
|
301 |
|
302 |
|
303 |
void
|
304 |
RooStats::HypoTestInvTool::AnalyzeResult( HypoTestInverterResult * r,
|
305 |
int calculatorType,
|
306 |
int testStatType,
|
307 |
bool useCLs,
|
308 |
int npoints,
|
309 |
const char * fileNameBase ){
|
310 |
|
311 |
// analyize result produced by the inverter, optionally save it in a file
|
312 |
|
313 |
double upperLimit = r->UpperLimit();
|
314 |
double ulError = r->UpperLimitEstimatedError();
|
315 |
|
316 |
std::cout << "The computed upper limit is: " << upperLimit << " +/- " << ulError << std::endl;
|
317 |
|
318 |
// compute expected limit
|
319 |
std::cout << " expected limit (median) " << r->GetExpectedUpperLimit(0) << std::endl;
|
320 |
std::cout << " expected limit (-1 sig) " << r->GetExpectedUpperLimit(-1) << std::endl;
|
321 |
std::cout << " expected limit (+1 sig) " << r->GetExpectedUpperLimit(1) << std::endl;
|
322 |
std::cout << " expected limit (-2 sig) " << r->GetExpectedUpperLimit(-2) << std::endl;
|
323 |
std::cout << " expected limit (+2 sig) " << r->GetExpectedUpperLimit(2) << std::endl;
|
324 |
|
325 |
|
326 |
// write result in a file
|
327 |
if (r != NULL && mWriteResult) {
|
328 |
|
329 |
// write to a file the results
|
330 |
const char * calcType = (calculatorType == 0) ? "Freq" : (calculatorType == 1) ? "Hybr" : "Asym";
|
331 |
const char * limitType = (useCLs) ? "CLs" : "Cls+b";
|
332 |
const char * scanType = (npoints < 0) ? "auto" : "grid";
|
333 |
TString resultFileName = TString::Format("%s_%s_%s_ts%d_",calcType,limitType,scanType,testStatType);
|
334 |
//strip the / from the filename
|
335 |
if (mMassValue.size()>0) {
|
336 |
resultFileName += mMassValue.c_str();
|
337 |
resultFileName += "_";
|
338 |
}
|
339 |
|
340 |
TString name = fileNameBase;
|
341 |
name.Replace(0, name.Last('/')+1, "");
|
342 |
resultFileName += name;
|
343 |
|
344 |
TFile * fileOut = new TFile(resultFileName,"RECREATE");
|
345 |
r->Write();
|
346 |
fileOut->Close();
|
347 |
}
|
348 |
|
349 |
|
350 |
// plot the result ( p values vs scan points)
|
351 |
std::string typeName = "";
|
352 |
if (calculatorType == 0 )
|
353 |
typeName = "Frequentist";
|
354 |
if (calculatorType == 1 )
|
355 |
typeName = "Hybrid";
|
356 |
else if (calculatorType == 2 ) {
|
357 |
typeName = "Asymptotic";
|
358 |
mPlotHypoTestResult = false;
|
359 |
}
|
360 |
|
361 |
const char * resultName = r->GetName();
|
362 |
TString plotTitle = TString::Format("%s CL Scan for workspace %s",typeName.c_str(),resultName);
|
363 |
HypoTestInverterPlot *plot = new HypoTestInverterPlot("HTI_Result_Plot",plotTitle,r);
|
364 |
plot->Draw("CLb 2CL"); // plot all and Clb
|
365 |
|
366 |
const int nEntries = r->ArraySize();
|
367 |
|
368 |
// plot test statistics distributions for the two hypothesis
|
369 |
if (mPlotHypoTestResult) {
|
370 |
TCanvas * c2 = new TCanvas();
|
371 |
if (nEntries > 1) {
|
372 |
int ny = TMath::CeilNint( sqrt(nEntries) );
|
373 |
int nx = TMath::CeilNint(double(nEntries)/ny);
|
374 |
c2->Divide( nx,ny);
|
375 |
}
|
376 |
for (int i=0; i<nEntries; i++) {
|
377 |
if (nEntries > 1) c2->cd(i+1);
|
378 |
SamplingDistPlot * pl = plot->MakeTestStatPlot(i);
|
379 |
pl->SetLogYaxis(true);
|
380 |
pl->Draw();
|
381 |
}
|
382 |
}
|
383 |
}
|
384 |
|
385 |
|
386 |
|
387 |
// internal routine to run the inverter
|
388 |
HypoTestInverterResult *
|
389 |
RooStats::HypoTestInvTool::RunInverter(RooWorkspace * w,
|
390 |
const char * modelSBName, const char * modelBName,
|
391 |
const char * dataName, int type, int testStatType,
|
392 |
bool useCLs, int npoints, double poimin, double poimax,
|
393 |
int ntoys,
|
394 |
bool useNumberCounting,
|
395 |
const char * nuisPriorName ){
|
396 |
|
397 |
std::cout << "Running HypoTestInverter on the workspace " << w->GetName() << std::endl;
|
398 |
|
399 |
w->Print();
|
400 |
|
401 |
|
402 |
RooAbsData * data = w->data(dataName);
|
403 |
if (!data) {
|
404 |
Error("StandardHypoTestDemo","Not existing data %s",dataName);
|
405 |
return 0;
|
406 |
}
|
407 |
else
|
408 |
std::cout << "Using data set " << dataName << std::endl;
|
409 |
|
410 |
if (mUseVectorStore) {
|
411 |
RooAbsData::defaultStorageType = RooAbsData::Vector;
|
412 |
data->convertToVectorStore() ;
|
413 |
}
|
414 |
|
415 |
|
416 |
// get models from WS
|
417 |
// get the modelConfig out of the file
|
418 |
ModelConfig* bModel = (ModelConfig*) w->obj(modelBName);
|
419 |
ModelConfig* sbModel = (ModelConfig*) w->obj(modelSBName);
|
420 |
|
421 |
if (!sbModel) {
|
422 |
Error("StandardHypoTestDemo","Not existing ModelConfig %s",modelSBName);
|
423 |
return 0;
|
424 |
}
|
425 |
// check the model
|
426 |
if (!sbModel->GetPdf()) {
|
427 |
Error("StandardHypoTestDemo","Model %s has no pdf ",modelSBName);
|
428 |
return 0;
|
429 |
}
|
430 |
if (!sbModel->GetParametersOfInterest()) {
|
431 |
Error("StandardHypoTestDemo","Model %s has no poi ",modelSBName);
|
432 |
return 0;
|
433 |
}
|
434 |
if (!sbModel->GetObservables()) {
|
435 |
Error("StandardHypoTestInvDemo","Model %s has no observables ",modelSBName);
|
436 |
return 0;
|
437 |
}
|
438 |
if (!sbModel->GetSnapshot() ) {
|
439 |
Info("StandardHypoTestInvDemo","Model %s has no snapshot - make one using model poi",modelSBName);
|
440 |
sbModel->SetSnapshot( *sbModel->GetParametersOfInterest() );
|
441 |
}
|
442 |
|
443 |
// case of no systematics
|
444 |
// remove nuisance parameters from model
|
445 |
if (noSystematics) {
|
446 |
const RooArgSet * nuisPar = sbModel->GetNuisanceParameters();
|
447 |
if (nuisPar && nuisPar->getSize() > 0) {
|
448 |
std::cout << "StandardHypoTestInvDemo" << " - Switch off all systematics by setting them constant to their initial values" << std::endl;
|
449 |
RooStats::SetAllConstant(*nuisPar);
|
450 |
}
|
451 |
if (bModel) {
|
452 |
const RooArgSet * bnuisPar = bModel->GetNuisanceParameters();
|
453 |
if (bnuisPar)
|
454 |
RooStats::SetAllConstant(*bnuisPar);
|
455 |
}
|
456 |
}
|
457 |
|
458 |
if (!bModel || bModel == sbModel) {
|
459 |
Info("StandardHypoTestInvDemo","The background model %s does not exist",modelBName);
|
460 |
Info("StandardHypoTestInvDemo","Copy it from ModelConfig %s and set POI to zero",modelSBName);
|
461 |
bModel = (ModelConfig*) sbModel->Clone();
|
462 |
bModel->SetName(TString(modelSBName)+TString("_with_poi_0"));
|
463 |
RooRealVar * var = dynamic_cast<RooRealVar*>(bModel->GetParametersOfInterest()->first());
|
464 |
if (!var) return 0;
|
465 |
double oldval = var->getVal();
|
466 |
var->setVal(0);
|
467 |
bModel->SetSnapshot( RooArgSet(*var) );
|
468 |
var->setVal(oldval);
|
469 |
}
|
470 |
else {
|
471 |
if (!bModel->GetSnapshot() ) {
|
472 |
Info("StandardHypoTestInvDemo","Model %s has no snapshot - make one using model poi and 0 values ",modelBName);
|
473 |
RooRealVar * var = dynamic_cast<RooRealVar*>(bModel->GetParametersOfInterest()->first());
|
474 |
if (var) {
|
475 |
double oldval = var->getVal();
|
476 |
var->setVal(0);
|
477 |
bModel->SetSnapshot( RooArgSet(*var) );
|
478 |
var->setVal(oldval);
|
479 |
}
|
480 |
else {
|
481 |
Error("StandardHypoTestInvDemo","Model %s has no valid poi",modelBName);
|
482 |
return 0;
|
483 |
}
|
484 |
}
|
485 |
}
|
486 |
|
487 |
// run first a data fit
|
488 |
|
489 |
const RooArgSet * poiSet = sbModel->GetParametersOfInterest();
|
490 |
RooRealVar *poi = (RooRealVar*)poiSet->first();
|
491 |
|
492 |
std::cout << "StandardHypoTestInvDemo : POI initial value: " << poi->GetName() << " = " << poi->getVal() << std::endl;
|
493 |
|
494 |
// fit the data first (need to use constraint )
|
495 |
Info( "StandardHypoTestInvDemo"," Doing a first fit to the observed data ");
|
496 |
if (minimizerType.size()==0) minimizerType = ROOT::Math::MinimizerOptions::DefaultMinimizerType();
|
497 |
else
|
498 |
ROOT::Math::MinimizerOptions::SetDefaultMinimizer(minimizerType.c_str());
|
499 |
Info("StandardHypoTestInvDemo","Using %s as minimizer for computing the test statistic",
|
500 |
ROOT::Math::MinimizerOptions::DefaultMinimizerType().c_str() );
|
501 |
RooArgSet constrainParams;
|
502 |
if (sbModel->GetNuisanceParameters() ) constrainParams.add(*sbModel->GetNuisanceParameters());
|
503 |
RooStats::RemoveConstantParameters(&constrainParams);
|
504 |
TStopwatch tw;
|
505 |
tw.Start();
|
506 |
RooFitResult * fitres = sbModel->GetPdf()->fitTo(*data,InitialHesse(false), Hesse(false),
|
507 |
Minimizer(minimizerType.c_str(),"Migrad"), Strategy(0), PrintLevel(mPrintLevel+1), Constrain(constrainParams), Save(true) );
|
508 |
if (fitres->status() != 0) {
|
509 |
Warning("StandardHypoTestInvDemo","Fit to the model failed - try with strategy 1 and perform first an Hesse computation");
|
510 |
fitres = sbModel->GetPdf()->fitTo(*data,InitialHesse(true), Hesse(false),Minimizer(minimizerType.c_str(),"Migrad"), Strategy(1), PrintLevel(mPrintLevel+1), Constrain(constrainParams), Save(true) );
|
511 |
}
|
512 |
if (fitres->status() != 0)
|
513 |
Warning("StandardHypoTestInvDemo"," Fit still failed - continue anyway.....");
|
514 |
|
515 |
|
516 |
double poihat = poi->getVal();
|
517 |
std::cout << "StandardHypoTestInvDemo - Best Fit value : " << poi->GetName() << " = "
|
518 |
<< poihat << " +/- " << poi->getError() << std::endl;
|
519 |
std::cout << "Time for fitting : "; tw.Print();
|
520 |
|
521 |
//save best fit value in the poi snapshot
|
522 |
sbModel->SetSnapshot(*sbModel->GetParametersOfInterest());
|
523 |
std::cout << "StandardHypoTestInvo: snapshot of S+B Model " << sbModel->GetName()
|
524 |
<< " is set to the best fit value" << std::endl;
|
525 |
|
526 |
// build test statistics and hypotest calculators for running the inverter
|
527 |
|
528 |
SimpleLikelihoodRatioTestStat slrts(*sbModel->GetPdf(),*bModel->GetPdf());
|
529 |
|
530 |
if (sbModel->GetSnapshot()) slrts.SetNullParameters(*sbModel->GetSnapshot());
|
531 |
if (bModel->GetSnapshot()) slrts.SetAltParameters(*bModel->GetSnapshot());
|
532 |
|
533 |
// ratio of profile likelihood - need to pass snapshot for the alt
|
534 |
RatioOfProfiledLikelihoodsTestStat
|
535 |
ropl(*sbModel->GetPdf(), *bModel->GetPdf(), bModel->GetSnapshot());
|
536 |
ropl.SetSubtractMLE(false);
|
537 |
ropl.SetPrintLevel(mPrintLevel);
|
538 |
ropl.SetMinimizer(minimizerType.c_str());
|
539 |
|
540 |
ProfileLikelihoodTestStat profll(*sbModel->GetPdf());
|
541 |
if (testStatType == 3) profll.SetOneSided(1);
|
542 |
profll.SetMinimizer(minimizerType.c_str());
|
543 |
profll.SetPrintLevel(mPrintLevel);
|
544 |
|
545 |
profll.SetReuseNLL(mOptimize);
|
546 |
slrts.SetReuseNLL(mOptimize);
|
547 |
ropl.SetReuseNLL(mOptimize);
|
548 |
|
549 |
if (mOptimize) {
|
550 |
profll.SetStrategy(0);
|
551 |
ropl.SetStrategy(0);
|
552 |
}
|
553 |
|
554 |
if (mMaxPoi > 0) poi->setMax(mMaxPoi); // increase limit
|
555 |
|
556 |
MaxLikelihoodEstimateTestStat maxll(*sbModel->GetPdf(),*poi);
|
557 |
|
558 |
// create the HypoTest calculator class
|
559 |
HypoTestCalculatorGeneric * hc = 0;
|
560 |
if (type == 0) hc = new FrequentistCalculator(*data, *bModel, *sbModel);
|
561 |
else if (type == 1) hc = new HybridCalculator(*data, *bModel, *sbModel);
|
562 |
else if (type == 2) hc = new AsymptoticCalculator(*data, *bModel, *sbModel);
|
563 |
else {
|
564 |
Error("StandardHypoTestInvDemo","Invalid - calculator type = %d supported values are only :\n\t\t\t 0 (Frequentist) , 1 (Hybrid) , 2 (Asymptotic) ",type);
|
565 |
return 0;
|
566 |
}
|
567 |
|
568 |
// set the test statistic
|
569 |
TestStatistic * testStat = 0;
|
570 |
if (testStatType == 0) testStat = &slrts;
|
571 |
if (testStatType == 1) testStat = &ropl;
|
572 |
if (testStatType == 2 || testStatType == 3) testStat = &profll;
|
573 |
if (testStatType == 4) testStat = &maxll;
|
574 |
if (testStat == 0) {
|
575 |
Error("StandardHypoTestInvDemo","Invalid - test statistic type = %d supported values are only :\n\t\t\t 0 (SLR) , 1 (Tevatron) , 2 (PLR), 3 (PLR1), 4(MLE)",testStatType);
|
576 |
return 0;
|
577 |
}
|
578 |
|
579 |
|
580 |
ToyMCSampler *toymcs = (ToyMCSampler*)hc->GetTestStatSampler();
|
581 |
if (toymcs) {
|
582 |
if (useNumberCounting) toymcs->SetNEventsPerToy(1);
|
583 |
toymcs->SetTestStatistic(testStat);
|
584 |
|
585 |
if (data->isWeighted() && !mGenerateBinned) {
|
586 |
Info("StandardHypoTestInvDemo","Data set is weighted, nentries = %d and sum of weights = %8.1f but toy generation is unbinned - it would be faster to set mGenerateBinned to true\n",data->numEntries(), data->sumEntries());
|
587 |
}
|
588 |
toymcs->SetGenerateBinned(mGenerateBinned);
|
589 |
|
590 |
toymcs->SetUseMultiGen(mOptimize);
|
591 |
|
592 |
if (mGenerateBinned && sbModel->GetObservables()->getSize() > 2) {
|
593 |
Warning("StandardHypoTestInvDemo","generate binned is activated but the number of ovservable is %d. Too much memory could be needed for allocating all the bins",sbModel->GetObservables()->getSize() );
|
594 |
}
|
595 |
|
596 |
}
|
597 |
|
598 |
|
599 |
if (type == 1) {
|
600 |
HybridCalculator *hhc = dynamic_cast<HybridCalculator*> (hc);
|
601 |
assert(hhc);
|
602 |
|
603 |
hhc->SetToys(ntoys,ntoys/mNToysRatio); // can use less ntoys for b hypothesis
|
604 |
|
605 |
// remove global observables from ModelConfig (this is probably not needed anymore in 5.32)
|
606 |
bModel->SetGlobalObservables(RooArgSet() );
|
607 |
sbModel->SetGlobalObservables(RooArgSet() );
|
608 |
|
609 |
|
610 |
// check for nuisance prior pdf in case of nuisance parameters
|
611 |
if (bModel->GetNuisanceParameters() || sbModel->GetNuisanceParameters() ) {
|
612 |
RooAbsPdf * nuisPdf = 0;
|
613 |
if (nuisPriorName) nuisPdf = w->pdf(nuisPriorName);
|
614 |
// use prior defined first in bModel (then in SbModel)
|
615 |
if (!nuisPdf) {
|
616 |
Info("StandardHypoTestInvDemo","No nuisance pdf given for the HybridCalculator - try to deduce pdf from the model");
|
617 |
if (bModel->GetPdf() && bModel->GetObservables() )
|
618 |
nuisPdf = RooStats::MakeNuisancePdf(*bModel,"nuisancePdf_bmodel");
|
619 |
else
|
620 |
nuisPdf = RooStats::MakeNuisancePdf(*sbModel,"nuisancePdf_sbmodel");
|
621 |
}
|
622 |
if (!nuisPdf ) {
|
623 |
if (bModel->GetPriorPdf()) {
|
624 |
nuisPdf = bModel->GetPriorPdf();
|
625 |
Info("StandardHypoTestInvDemo","No nuisance pdf given - try to use %s that is defined as a prior pdf in the B model",nuisPdf->GetName());
|
626 |
}
|
627 |
else {
|
628 |
Error("StandardHypoTestInvDemo","Cannnot run Hybrid calculator because no prior on the nuisance parameter is specified or can be derived");
|
629 |
return 0;
|
630 |
}
|
631 |
}
|
632 |
assert(nuisPdf);
|
633 |
Info("StandardHypoTestInvDemo","Using as nuisance Pdf ... " );
|
634 |
nuisPdf->Print();
|
635 |
|
636 |
const RooArgSet * nuisParams = (bModel->GetNuisanceParameters() ) ? bModel->GetNuisanceParameters() : sbModel->GetNuisanceParameters();
|
637 |
RooArgSet * np = nuisPdf->getObservables(*nuisParams);
|
638 |
if (np->getSize() == 0) {
|
639 |
Warning("StandardHypoTestInvDemo","Prior nuisance does not depend on nuisance parameters. They will be smeared in their full range");
|
640 |
}
|
641 |
delete np;
|
642 |
|
643 |
hhc->ForcePriorNuisanceAlt(*nuisPdf);
|
644 |
hhc->ForcePriorNuisanceNull(*nuisPdf);
|
645 |
|
646 |
|
647 |
}
|
648 |
}
|
649 |
else if (type == 2) {
|
650 |
((AsymptoticCalculator*) hc)->SetOneSided(true);
|
651 |
// ((AsymptoticCalculator*) hc)->SetQTilde(true); // not needed should be done automatically now
|
652 |
((AsymptoticCalculator*) hc)->SetPrintLevel(mPrintLevel+1);
|
653 |
}
|
654 |
else if (type != 2)
|
655 |
((FrequentistCalculator*) hc)->SetToys(ntoys,ntoys/mNToysRatio);
|
656 |
|
657 |
// Get the result
|
658 |
RooMsgService::instance().getStream(1).removeTopic(RooFit::NumIntegration);
|
659 |
|
660 |
|
661 |
|
662 |
HypoTestInverter calc(*hc);
|
663 |
calc.SetConfidenceLevel(0.95);
|
664 |
|
665 |
|
666 |
calc.UseCLs(useCLs);
|
667 |
calc.SetVerbose(true);
|
668 |
|
669 |
// can speed up using proof-lite
|
670 |
if (mUseProof && mNWorkers > 1) {
|
671 |
ProofConfig pc(*w, mNWorkers, "", kFALSE);
|
672 |
toymcs->SetProofConfig(&pc); // enable proof
|
673 |
}
|
674 |
|
675 |
|
676 |
if (npoints > 0) {
|
677 |
if (poimin > poimax) {
|
678 |
// if no min/max given scan between MLE and +4 sigma
|
679 |
poimin = int(poihat);
|
680 |
poimax = int(poihat + 4 * poi->getError());
|
681 |
}
|
682 |
std::cout << "Doing a fixed scan in interval : " << poimin << " , " << poimax << std::endl;
|
683 |
calc.SetFixedScan(npoints,poimin,poimax);
|
684 |
}
|
685 |
else {
|
686 |
//poi->setMax(10*int( (poihat+ 10 *poi->getError() )/10 ) );
|
687 |
std::cout << "Doing an automatic scan in interval : " << poi->getMin() << " , " << poi->getMax() << std::endl;
|
688 |
}
|
689 |
|
690 |
tw.Start();
|
691 |
HypoTestInverterResult * r = calc.GetInterval();
|
692 |
std::cout << "Time to perform limit scan \n";
|
693 |
tw.Print();
|
694 |
|
695 |
if (mRebuild) {
|
696 |
calc.SetCloseProof(1);
|
697 |
tw.Start();
|
698 |
SamplingDistribution * limDist = calc.GetUpperLimitDistribution(true,mNToyToRebuild);
|
699 |
std::cout << "Time to rebuild distributions " << std::endl;
|
700 |
tw.Print();
|
701 |
|
702 |
if (limDist) {
|
703 |
std::cout << "expected up limit " << limDist->InverseCDF(0.5) << " +/- "
|
704 |
<< limDist->InverseCDF(0.16) << " "
|
705 |
<< limDist->InverseCDF(0.84) << "\n";
|
706 |
|
707 |
//update r to a new updated result object containing the rebuilt expected p-values distributions
|
708 |
// (it will not recompute the expected limit)
|
709 |
if (r) delete r; // need to delete previous object since GetInterval will return a cloned copy
|
710 |
r = calc.GetInterval();
|
711 |
|
712 |
}
|
713 |
else
|
714 |
std::cout << "ERROR : failed to re-build distributions " << std::endl;
|
715 |
}
|
716 |
|
717 |
return r;
|
718 |
}
|
719 |
|
720 |
|
721 |
|
722 |
void ReadResult(const char * fileName, const char * resultName="", bool useCLs=true) {
|
723 |
// read a previous stored result from a file given the result name
|
724 |
|
725 |
StandardHypoTestInvDemo(fileName, resultName,"","","",0,0,useCLs);
|
726 |
}
|
727 |
|
728 |
|
729 |
#ifdef USE_AS_MAIN
|
730 |
int main() {
|
731 |
StandardHypoTestInvDemo();
|
732 |
}
|
733 |
#endif
|
734 |
|
735 |
|
736 |
|
737 |
|