8 #include "../interface/HybridNew.h"
14 #include <TGraphErrors.h>
15 #include <TStopwatch.h>
16 #include "RooRealVar.h"
17 #include "RooArgSet.h"
18 #include "RooAbsPdf.h"
19 #include "RooFitResult.h"
20 #include "RooRandom.h"
21 #include "RooAddPdf.h"
22 #include "RooConstVar.h"
23 #include "RooMsgService.h"
24 #include <RooStats/ModelConfig.h>
25 #include <RooStats/FrequentistCalculator.h>
26 #include <RooStats/HybridCalculator.h>
27 #include <RooStats/SimpleLikelihoodRatioTestStat.h>
28 #include <RooStats/RatioOfProfiledLikelihoodsTestStat.h>
29 #include <RooStats/ProfileLikelihoodTestStat.h>
30 #include <RooStats/ToyMCSampler.h>
31 #include <RooStats/HypoTestPlot.h>
32 #include "../interface/Combine.h"
33 #include "../interface/CloseCoutSentry.h"
34 #include "../interface/RooFitGlobalKillSentry.h"
35 #include "../interface/SimplerLikelihoodRatioTestStat.h"
36 #include "../interface/ProfiledLikelihoodRatioTestStat.h"
37 #include "../interface/SimplerLikelihoodRatioTestStatExt.h"
38 #include "../interface/ProfiledLikelihoodRatioTestStatExt.h"
39 #include "../interface/BestFitSigmaTestStat.h"
40 #include "../interface/ToyMCSamplerOpt.h"
41 #include "../interface/utils.h"
42 #include "../interface/ProfileLikelihood.h"
43 #include "../interface/ProfilingTools.h"
45 using namespace RooStats;
92 (
"rule", boost::program_options::value<std::string>(&
rule_)->default_value(
rule_),
"Rule to use: CLs, CLsplusb")
93 (
"testStat",boost::program_options::value<std::string>(&
testStat_)->default_value(
testStat_),
"Test statistics: LEP, TEV, LHC (previously known as Atlas), Profile.")
94 (
"singlePoint", boost::program_options::value<std::string>(&
rValue_)->default_value(
rValue_),
"Just compute CLs for the given value of the parameter of interest. In case of multiple parameters, use a syntax 'name=value,name2=value2,...'")
95 (
"onlyTestStat",
"Just compute test statistics, not actual p-values (works only with --singlePoint)")
96 (
"generateNuisances", boost::program_options::value<bool>(&
genNuisances_)->default_value(
genNuisances_),
"Generate nuisance parameters for each toy")
97 (
"generateExternalMeasurements", boost::program_options::value<bool>(&
genGlobalObs_)->default_value(
genGlobalObs_),
"Generate external measurements for each toy, taken from the GlobalObservables of the ModelConfig")
98 (
"fitNuisances", boost::program_options::value<bool>(&
fitNuisances_)->default_value(
fitNuisances_),
"Fit the nuisances, when not generating them.")
99 (
"searchAlgo", boost::program_options::value<std::string>(&
algo_)->default_value(
algo_),
"Algorithm to use to search for the limit (bisection, logSecant)")
100 (
"toysH,T", boost::program_options::value<unsigned int>(&
nToys_)->default_value(
nToys_),
"Number of Toy MC extractions to compute CLs+b, CLb and CLs")
101 (
"clsAcc", boost::program_options::value<double>(&
clsAccuracy_ )->default_value(
clsAccuracy_),
"Absolute accuracy on CLs to reach to terminate the scan")
102 (
"rAbsAcc", boost::program_options::value<double>(&
rAbsAccuracy_)->default_value(
rAbsAccuracy_),
"Absolute accuracy on r to reach to terminate the scan")
103 (
"rRelAcc", boost::program_options::value<double>(&
rRelAccuracy_)->default_value(
rRelAccuracy_),
"Relative accuracy on r to reach to terminate the scan")
104 (
"interpAcc", boost::program_options::value<double>(&
interpAccuracy_)->default_value(
interpAccuracy_),
"Minimum uncertainty from interpolation delta(x)/(max(x)-min(x))")
105 (
"iterations,i", boost::program_options::value<unsigned int>(&
iterations_)->default_value(
iterations_),
"Number of times to throw 'toysH' toys to compute the p-values (for --singlePoint if clsAcc is set to zero disabling adaptive generation)")
106 (
"fork", boost::program_options::value<unsigned int>(&
fork_)->default_value(
fork_),
"Fork to N processes before running the toys (set to 0 for debugging)")
107 (
"nCPU", boost::program_options::value<unsigned int>(&
nCpu_)->default_value(
nCpu_),
"Use N CPUs with PROOF Lite (experimental!)")
108 (
"saveHybridResult",
"Save result in the output file")
109 (
"readHybridResults",
"Read and merge results from file (requires 'toysFile' or 'grid')")
110 (
"grid", boost::program_options::value<std::string>(&
gridFile_),
"Use the specified file containing a grid of SamplingDistributions for the limit (implies readHybridResults).\n For --singlePoint or --signif use --toysFile=x.root --readHybridResult instead of this.")
111 (
"expectedFromGrid", boost::program_options::value<float>(&
quantileForExpectedFromGrid_)->default_value(0.5),
"Use the grid to compute the expected limit for this quantile")
112 (
"signalForSignificance", boost::program_options::value<std::string>()->default_value(
"1"),
"Use this value of the parameter of interest when generating signal toys for expected significance (same syntax as --singlePoint)")
113 (
"clsQuantiles", boost::program_options::value<bool>(&
clsQuantiles_)->default_value(
clsQuantiles_),
"Compute correct quantiles of CLs or CLsplusb instead of assuming they're the same as CLb ones")
119 "Use optimized test statistics if the likelihood is not extended (works for LEP and TEV test statistics).")
121 "Optimize the code factorizing pdfs")
122 (
"minimizerAlgo", boost::program_options::value<std::string>(&
minimizerAlgo_)->default_value(
minimizerAlgo_),
"Choice of minimizer used for profiling (Minuit vs Minuit2)")
124 (
"plot", boost::program_options::value<std::string>(&
plot_),
"Save a plot of the result (test statistics distributions or limit scan)")
125 (
"frequentist",
"Shortcut to switch to Frequentist mode (--generateNuisances=0 --generateExternalMeasurements=1 --fitNuisances=1)")
126 (
"newToyMCSampler", boost::program_options::value<bool>(&
newToyMCSampler_)->default_value(
newToyMCSampler_),
"Use new ToyMC sampler with support for mixed binned-unbinned generation. On by default, you can turn it off if it doesn't work for your workspace.")
127 (
"fullGrid",
"Evaluate p-values at all grid points, without optimitations")
128 (
"saveGrid",
"Save CLs or (or FC p-value) at all grid points in the output tree. The value of 'r' is saved in the 'limit' branch, while the CLs or p-value in the 'quantileExpected' branch and the uncertainty on 'limitErr' (since there's no quantileExpectedErr)")
129 (
"noUpdateGrid",
"Do not update test statistics at grid points")
130 (
"fullBToys",
"Run as many B toys as S ones (default is to run 1/4 of b-only toys)")
131 (
"pvalue",
"Report p-value instead of significance (when running with --significance)")
137 if (vm.count(
"expectedFromGrid") && !vm[
"expectedFromGrid"].defaulted()) {
139 if (quantileForExpectedFromGrid_ <= 0 || quantileForExpectedFromGrid_ >= 1.0)
throw std::invalid_argument(
"HybridNew: the quantile for the expected limit must be between 0 and 1");
143 if (vm.count(
"frequentist")) {
145 if (vm[
"testStat"].defaulted())
testStat_ =
"LHC";
146 if (vm[
"toys"].as<int>() > 0 and vm.count(
"toysFrequentist")) {
148 std::cout <<
"When tossing frequenst toys outside the HybridNew, the nuisances will not be refitted for each toy by default. This can be changed by specifying explicitly the fitNuisances option" << std::endl;
154 std::cerr <<
"ALERT: generating both global observables and nuisance parameters at the same time is not validated." << std::endl;
156 if (!vm[
"singlePoint"].defaulted()) {
157 if (
doSignificance_)
throw std::invalid_argument(
"HybridNew: Can't use --significance and --singlePoint at the same time");
159 }
else if (vm.count(
"onlyTestStat")) {
161 else throw std::invalid_argument(
"HybridNew: --onlyTestStat works only with --singlePoint or --significance");
164 rValue_ = vm[
"signalForSignificance"].as<std::string>();
170 if (
readHybridResults_ && !(vm.count(
"toysFile") || vm.count(
"grid")))
throw std::invalid_argument(
"HybridNew: must have 'toysFile' or 'grid' option to have 'readHybridResults'\n");
171 mass_ = vm[
"mass"].as<
float>();
187 if (
rule_ ==
"CLs") {
189 }
else if (
rule_ ==
"CLsplusb") {
191 }
else if (
rule_ ==
"FC") {
194 throw std::invalid_argument(
"HybridNew: Rule must be either 'CLs' or 'CLsplusb'");
201 if (
testStat_ ==
"Atlas") {
testStat_ =
"LHC";
std::cout <<
"Note: the Atlas test statistics is now known as LHC test statistics.\n" << std::endl; }
203 throw std::invalid_argument(
"HybridNew: Test statistics should be one of 'LEP' or 'TEV' or 'LHC' (previously known as 'Atlas') or 'Profile'");
206 if (
testStat_ ==
"LEP")
std::cout <<
">>> using the Simple Likelihood Ratio test statistics (Q_LEP)" << std::endl;
207 if (
testStat_ ==
"TEV")
std::cout <<
">>> using the Ratio of Profiled Likelihoods test statistics (Q_TEV)" << std::endl;
208 if (
testStat_ ==
"LHC")
std::cout <<
">>> using the Profile Likelihood test statistics modified for upper limits (Q_LHC)" << std::endl;
209 if (
testStat_ ==
"LHCFC")
std::cout <<
">>> using the Profile Likelihood test statistics modified for upper limits and Feldman-Cousins (Q_LHCFC)" << std::endl;
210 if (
testStat_ ==
"Profile")
std::cout <<
">>> using the Profile Likelihood test statistics not modified for upper limits (Q_Profile)" << std::endl;
211 if (
testStat_ ==
"MLZ")
std::cout <<
">>> using the Maximum likelihood estimator of the signal strength as test statistics" << std::endl;
221 RooArgSet POI(*mc_s->GetParametersOfInterest());
222 if (
rValue_.find(
"=") == std::string::npos) {
223 if (POI.getSize() != 1)
throw std::invalid_argument(
"Error: the argument to --singlePoint or --signalForSignificance is a single value, but there are multiple POIs");
227 if (errno != 0) std::invalid_argument(
"Error: the argument to --singlePoint or --signalForSignificance is not a valid number.");
231 eqidx =
rValue_.find(
"=", colidx);
232 colidx2 =
rValue_.find(
",", colidx+1);
233 if (eqidx == std::string::npos || (colidx2 != std::string::npos && colidx2 < eqidx)) {
234 throw std::invalid_argument(
"Error: the argument to --singlePoint or --signalForSignificance is not in the forms 'value' or 'name1=value1,name2=value2,...'\n");
236 std::string poiName =
rValue_.substr(colidx, eqidx);
237 std::string poiVal =
rValue_.substr(eqidx+1, (colidx2 == std::string::npos ? std::string::npos : colidx2 - eqidx - 1));
238 RooAbsArg *poi = POI.find(poiName.c_str());
239 if (poi == 0)
throw std::invalid_argument(
"Error: unknown parameter '"+poiName+
"' passed to --singlePoint or --signalForSignificance.");
242 rValues_.setRealValue(poi->GetName(), strtod(poiVal.c_str(),
NULL));
243 if (errno != 0)
throw std::invalid_argument(
"Error: invalid value '"+poiVal+
"' for parameter '"+poiName+
"' passed to --singlePoint or --signalForSignificance.");
244 }
while (colidx2 != std::string::npos);
245 if (
rValues_.getSize() != POI.getSize()) {
246 throw std::invalid_argument(
"Error: not all parameters of interest specified in --singlePoint or --signalForSignificance");
251 bool HybridNew::run(RooWorkspace *
w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &
data,
double &
limit,
double &limitErr,
const double *hint) {
264 assert(
"Shouldn't get here" == 0);
269 std::auto_ptr<RooStats::HybridCalculator> hc(
create(w, mc_s, mc_b, data,
rValues_, setup));
270 std::auto_ptr<HypoTestResult> hcResult;
276 std::auto_ptr<HypoTestResult> more(
evalGeneric(*hc));
277 hcResult->Append(more.get());
278 if (
verbose)
std::cout <<
"\t1 - CLb = " << hcResult->CLb() <<
" +/- " << hcResult->CLbError() << std::endl;
281 if (hcResult.get() == 0) {
282 std::cerr <<
"Hypotest failed" << std::endl;
286 TString
name = TString::Format(
"HypoTestResult_mh%g",
mass_);
287 RooLinkedListIter it =
rValues_.iterator();
288 for (RooRealVar *rIn = (RooRealVar*) it.Next(); rIn != 0; rIn = (RooRealVar*) it.Next()) {
289 name += Form(
"_%s%g", rIn->GetName(), rIn->getVal());
292 writeToysHere->WriteTObject(
new HypoTestResult(*hcResult), name);
296 std::cout <<
"Observed test statistics in data: " << hcResult->GetTestStatisticData() << std::endl;
297 std::cout <<
"Background-only toys sampled: " << hcResult->GetNullDistribution()->GetSize() << std::endl;
301 hcResult->SetTestStatisticData(hcResult->GetTestStatisticData()+
EPS);
302 double sig = hcResult->Significance();
303 double sigHi = RooStats::PValueToSignificance( (hcResult->CLb() - hcResult->CLbError()) ) - sig;
304 double sigLo = RooStats::PValueToSignificance( (hcResult->CLb() + hcResult->CLbError()) ) - sig;
306 limit = hcResult->NullPValue();
307 limitErr = hcResult->NullPValueError();
313 std::cout <<
"Significance: " << sig <<
" " << sigLo <<
"/+" << sigHi <<
"\n";
314 std::cout <<
"Null p-value: " << hcResult->NullPValue() <<
" +/- " << hcResult->NullPValueError() <<
"\n";
315 return isfinite(limit);
318 bool HybridNew::runLimit(RooWorkspace *
w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &
data,
double &
limit,
double &limitErr,
const double *hint) {
319 if (mc_s->GetParametersOfInterest()->getSize() != 1)
throw std::logic_error(
"Cannot run limits in more than one dimension, for the moment.");
320 RooRealVar *
r =
dynamic_cast<RooRealVar *
>(mc_s->GetParametersOfInterest()->first()); r->setConstant(
true);
321 w->loadSnapshot(
"clean");
323 if ((hint != 0) && (*hint > r->getMin())) {
324 r->setMax(std::min<double>(3.0 * (*hint), r->getMax()));
325 r->setMin(std::max<double>(0.3 * (*hint), r->getMin()));
328 typedef std::pair<double,double> CLs_t;
330 double clsTarget = 1 -
cl;
331 CLs_t clsMin(1,0), clsMax(0,0), clsMid(0,0);
332 double rMin = r->getMin(), rMax = r->getMax();
333 limit = 0.5*(rMax + rMin);
334 limitErr = 0.5*(rMax - rMin);
337 TF1 expoFit(
"expoFit",
"[0]*exp([1]*(x-[2]))", rMin, rMax);
340 if (
verbose > 0)
std::cout <<
"Search for upper limit using pre-computed grid of p-values" << std::endl;
344 std::auto_ptr<TFile> gridFile(TFile::Open(
gridFile_.c_str()));
345 if (gridFile.get() == 0)
throw std::runtime_error((
"Can't open grid file "+
gridFile_).c_str());
346 TDirectory *toyDir = gridFile->GetDirectory(
"toys");
347 if (!toyDir)
throw std::logic_error(
"Cannot use readHypoTestResult: empty toy dir in input file empty");
350 if (
grid_.size() <= 1)
throw std::logic_error(
"The grid must contain at least 2 points.");
353 std::cout <<
"Will have to re-run points for which the test statistics was set to zero" << std::endl;
356 std::cout <<
"Will use the test statistics that had already been computed" << std::endl;
361 }
else throw std::logic_error(
"When setting a limit reading results from file, a grid file must be specified with option --grid");
362 if (
grid_.size() <= 1)
throw std::logic_error(
"The grid must contain at least 2 points.");
372 if (
verbose > 0) printf(
" r %.2f: %s = %6.4f +/- %6.4f\n", x,
CLs_ ?
"CLs" :
"CLsplusb",
y, ey);
374 if (
y-3*
max(ey,0.01) >= clsTarget) { rMin =
x; clsMin = CLs_t(
y,ey); }
375 if (fabs(
y-clsTarget) < minDist) { nearest =
x; minDist = fabs(
y-clsTarget); }
376 rMax =
x; clsMax = CLs_t(
y,ey);
380 if (
verbose > 0)
std::cout <<
" after scan x ~ " << limit <<
", bounds [ " << rMin <<
", " << rMax <<
"]" << std::endl;
381 limitErr =
std::max(limit-rMin, rMax-limit);
382 expoFit.SetRange(rMin,rMax);
391 if (
verbose > 0)
std::cout <<
"Search for upper limit to the limit" << std::endl;
392 for (
int tries = 0; tries < 6; ++tries) {
393 clsMax =
eval(w, mc_s, mc_b, data, rMax);
395 if (clsMax.first == 0 || clsMax.first + 3 * fabs(clsMax.second) < clsTarget )
break;
398 std::cerr <<
"Cannot set higher limit: at " << r->GetName() <<
" = " << rMax <<
" still get " << (
CLs_ ?
"CLs" :
"CLsplusb") <<
" = " << clsMax.first << std::endl;
402 if (
verbose > 0)
std::cout <<
"Search for lower limit to the limit" << std::endl;
403 clsMin = (
CLs_ && rMin == 0 ? CLs_t(1,0) :
eval(w, mc_s, mc_b, data, rMin));
404 if (!
lowerLimit_ && clsMin.first != 1 && clsMin.first - 3 * fabs(clsMin.second) < clsTarget) {
410 for (
int tries = 0; tries < 6; ++tries) {
411 clsMin =
eval(w, mc_s, mc_b, data, rMin);
412 if (clsMin.first == 1 || clsMin.first - 3 * fabs(clsMin.second) > clsTarget)
break;
415 std::cerr <<
"Cannot set lower limit: at " << r->GetName() <<
" = " << rMin <<
" still get " << (
CLs_ ?
"CLs" :
"CLsplusb") <<
" = " << clsMin.first << std::endl;
422 if (
verbose > 0)
std::cout <<
"Now doing proper bracketing & bisection" << std::endl;
425 limit = 0.5*(rMin+rMax); limitErr = 0.5*(rMax-rMin);
426 if (
algo_ ==
"logSecant" && clsMax.first != 0 && clsMin.first != 0) {
427 double logMin =
log(clsMin.first), logMax =
log(clsMax.first), logTarget =
log(clsTarget);
428 limit = rMin + (rMax-rMin) * (logTarget - logMin)/(logMax - logMin);
429 if (clsMax.second != 0 && clsMin.second != 0) {
430 limitErr = hypot((logTarget-logMax) * (clsMin.second/clsMin.first), (logTarget-logMin) * (clsMax.second/clsMax.first));
431 limitErr *= (rMax-rMin)/((logMax-logMin)*(logMax-logMin));
436 r->setError(limitErr);
445 clsMid =
eval(w, mc_s, mc_b, data, limit,
true, clsTarget);
446 if (clsMid.second == -1) {
447 std::cerr <<
"Hypotest failed" << std::endl;
452 if (fabs(clsMid.first-clsTarget) >= 2*clsMid.second) {
453 if ((clsMid.first>clsTarget) == (clsMax.first>clsTarget)) {
454 rMax =
limit; clsMax = clsMid;
456 rMin =
limit; clsMin = clsMid;
459 if (
verbose > 0)
std::cout <<
"Trying to move the interval edges closer" << std::endl;
460 double rMinBound = rMin, rMaxBound = rMax;
463 rMin = 0.5*(rMin+
limit);
464 clsMin =
eval(w, mc_s, mc_b, data, rMin,
true, clsTarget);
465 if (fabs(clsMin.first-clsTarget) <= 2*clsMin.second)
break;
469 rMax = 0.5*(rMax+
limit);
470 clsMax =
eval(w, mc_s, mc_b, data, rMax,
true, clsTarget);
471 if (fabs(clsMax.first-clsTarget) <= 2*clsMax.second)
break;
474 expoFit.SetRange(rMinBound,rMaxBound);
482 double rMinBound, rMaxBound; expoFit.GetRange(rMinBound, rMaxBound);
484 std::cout <<
"\n -- HybridNew, before fit -- \n";
485 std::cout <<
"Limit: " << r->GetName() <<
" < " << limit <<
" +/- " << limitErr <<
" [" << rMinBound <<
", " << rMaxBound <<
"]\n";
488 expoFit.FixParameter(0,clsTarget);
489 double clsmaxfirst = clsMax.first;
490 if ( clsmaxfirst == 0.0 ) clsmaxfirst = 0.005;
491 double par1guess =
log(clsmaxfirst/clsMin.first)/(rMax-rMin);
492 expoFit.SetParameter(1,par1guess);
493 expoFit.SetParameter(2,limit);
494 limitErr =
std::max(fabs(rMinBound-limit), fabs(rMaxBound-limit));
503 std::cout <<
"Fit to " << npoints <<
" points: " << expoFit.GetParameter(2) <<
" +/- " << expoFit.GetParError(2) << std::endl;
505 if ((rMinBound < expoFit.GetParameter(2)) && (expoFit.GetParameter(2) < rMaxBound) && (expoFit.GetParError(2) < 0.5*(rMaxBound-rMinBound))) {
507 limit = expoFit.GetParameter(2);
508 limitErr = expoFit.GetParError(2);
512 double rTry = RooRandom::uniform()*(rMaxBound-rMinBound)+rMinBound;
513 if (
i != imax)
eval(w, mc_s, mc_b, data, rTry,
true, clsTarget);
518 TCanvas *
c1 =
new TCanvas(
"c1",
"c1");
521 double xmin = r->getMin(), xmax = r->getMax();
527 limitPlot_->GetXaxis()->SetRangeUser(xmin,xmax);
528 limitPlot_->GetYaxis()->SetRangeUser(0.5*clsTarget, 1.5*clsTarget);
530 expoFit.Draw(
"SAME");
532 line.SetLineColor(kRed);
line.SetLineWidth(2);
line.Draw();
534 line.SetLineWidth(1);
line.SetLineStyle(2);
535 line.DrawLine(limit-limitErr, 0, limit-limitErr,
limitPlot_->GetY()[0]);
536 line.DrawLine(limit+limitErr, 0, limit+limitErr,
limitPlot_->GetY()[0]);
537 c1->Print(
plot_.c_str());
541 std::cout <<
"Limit: " << r->GetName() <<
" < " << limit <<
" +/- " << limitErr <<
" @ " <<
cl * 100 <<
"% CL\n";
549 std::cout << (
CLs_ ?
"CLs = " :
"CLsplusb = ") << result.first <<
" +/- " << result.second << std::endl;
551 limit = result.first;
552 limitErr = result.second;
561 limit = -2 * result->GetTestStatisticData();
564 std::auto_ptr<RooStats::HybridCalculator> hc(
create(w, mc_s, mc_b, data,
rValues_, setup));
570 limit = -2 * setup.
qvar->Evaluate(data, nullPOI);
572 if (isProfile) limit = -
limit;
578 std::pair<double, double>
HybridNew::eval(RooWorkspace *
w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &
data,
double rVal,
bool adaptive,
double clsTarget) {
580 mc_s->GetParametersOfInterest()->snapshot(rValues);
581 RooRealVar *
r =
dynamic_cast<RooRealVar*
>(rValues.first());
582 if (rVal > r->getMax()) r->setMax(2*rVal);
584 return eval(w,mc_s,mc_b,data,rValues,adaptive,clsTarget);
587 std::pair<double, double>
HybridNew::eval(RooWorkspace *
w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &
data,
const RooAbsCollection & rVals,
bool adaptive,
double clsTarget) {
591 std::pair<double, double>
ret(-1,-1);
592 assert(result.get() != 0 &&
"Null result in HybridNew::eval(Workspace,...) after readToysFromFile");
595 result->SetTestStatisticData(result->GetTestStatisticData() + (isProfile ? -
EPS :
EPS));
598 std::auto_ptr<RooStats::HybridCalculator> hc =
create(w, mc_s, mc_b, data, rVals, setup);
600 if (isProfile) nullPOI.assignValueOnly(rVals);
601 double testStat = setup.
qvar->Evaluate(data, nullPOI);
602 result->SetTestStatisticData(testStat + (isProfile ? -
EPS :
EPS));
604 ret =
eval(*result, rVals);
609 RooLinkedListIter it = rVals.iterator();
610 for (RooRealVar *rIn = (RooRealVar*) it.Next(); rIn != 0; rIn = (RooRealVar*) it.Next()) {
611 RooRealVar *
r =
dynamic_cast<RooRealVar *
>(mc_s->GetParametersOfInterest()->find(rIn->GetName()));
612 r->setVal(rIn->getVal());
613 if (
verbose)
std::cout <<
" " << r->GetName() <<
" = " << rIn->getVal() <<
" +/- " << r->getError() << std::endl;
615 std::auto_ptr<RooStats::HybridCalculator> hc(
create(w, mc_s, mc_b, data, rVals, setup));
616 std::pair<double, double>
ret =
eval(*hc, rVals, adaptive, clsTarget);
632 mc_s->GetParametersOfInterest()->snapshot(rValues);
633 RooRealVar *
r =
dynamic_cast<RooRealVar*
>(rValues.first());
634 if (rVal > r->getMax()) r->setMax(2*rVal);
636 return create(w,mc_s,mc_b,data,rValues,setup);
640 using namespace RooStats;
642 w->loadSnapshot(
"clean");
645 RooArgSet poi(*mc_s->GetParametersOfInterest()), params(poi);
646 RooRealVar *
r =
dynamic_cast<RooRealVar *
>(poi.first());
648 if (poi.getSize() == 1) {
649 double rVal = ((RooAbsReal*)rVals.first())->getVal();
653 r->setConstant(
false);
r->setMin(0);
659 r->setConstant(
true);
664 poi.assignValueOnly(rVals);
670 RooArgList gobsParams;
673 RooArgList allnuis(*mc_s->GetNuisanceParameters());
674 RooArgList allgobs(*mc_s->GetGlobalObservables());
675 for (
int i=0;
i<allnuis.getSize(); ++
i) {
676 RooRealVar *nuis = (RooRealVar*)allnuis.at(
i);
677 if (nuis->getAttribute(
"globalConstrained")) {
678 RooRealVar *glob = (RooRealVar*)allgobs.find(TString::Format(
"%s_In",nuis->GetName()));
680 nuis->setVal(glob->getVal());
682 gobsParams.add(*nuis);
689 std::auto_ptr<RooFitResult> fitMu, fitZero;
692 bool isExt = mc_s->GetPdf()->canBeExtended();
695 RooAbsPdf *pdfB = mc_b->GetPdf();
696 if (poi.getSize() == 1) {
697 r->setVal(0); pdfB = mc_s->GetPdf();
702 fitZero.reset(pdfB->fitTo(data, RooFit::Save(1), RooFit::Minimizer(
"Minuit2",
"minimize"), RooFit::Strategy(1), RooFit::Hesse(0), RooFit::Extended(isExt), RooFit::Constrain(*mc_s->GetNuisanceParameters())));
704 if (
verbose > 1) {
std::cout <<
"Zero signal fit" << std::endl; fitZero->Print(
"V"); }
705 if (
verbose > 1) {
std::cout <<
"Fitting of the background hypothesis done in " << timer.RealTime() <<
" s" << std::endl; }
706 poi.assignValueOnly(rVals);
710 fitMu.reset(mc_s->GetPdf()->fitTo(data, RooFit::Save(1), RooFit::Minimizer(
"Minuit2",
"minimize"), RooFit::Strategy(1), RooFit::Hesse(0), RooFit::Extended(isExt), RooFit::Constrain(*mc_s->GetNuisanceParameters())));
712 if (
verbose > 1) {
std::cout <<
"Reference signal fit" << std::endl; fitMu->Print(
"V"); }
713 if (
verbose > 1) {
std::cout <<
"Fitting of the signal-plus-background hypothesis done in " << timer.RealTime() <<
" s" << std::endl; }
717 setup.
modelConfig = ModelConfig(
"HybridNew_mc_s", w);
719 setup.
modelConfig.SetObservables(*mc_s->GetObservables());
720 setup.
modelConfig.SetParametersOfInterest(*mc_s->GetParametersOfInterest());
722 if (
genNuisances_ && mc_s->GetNuisanceParameters()) setup.
modelConfig.SetNuisanceParameters(*mc_s->GetNuisanceParameters());
723 if (
genGlobalObs_ && mc_s->GetGlobalObservables()) setup.
modelConfig.SetGlobalObservables(*mc_s->GetGlobalObservables());
730 setup.
modelConfig_bonly.SetParametersOfInterest(*mc_b->GetParametersOfInterest());
740 if (w->var(
"__HybridNew_fake_nuis__") == 0) {
741 w->factory(
"__HybridNew_fake_nuis__[0.5,0,1]");
742 w->factory(
"Uniform::__HybridNew_fake_nuisPdf__(__HybridNew_fake_nuis__)");
744 setup.
modelConfig.SetNuisanceParameters(RooArgSet(*w->var(
"__HybridNew_fake_nuis__")));
745 setup.
modelConfig_bonly.SetNuisanceParameters(RooArgSet(*w->var(
"__HybridNew_fake_nuis__")));
750 RooArgSet paramsZero;
751 if (poi.getSize() == 1) {
752 paramsZero.addClone(*rVals.first());
753 paramsZero.setRealValue(rVals.first()->GetName(), 0);
756 if (
fitNuisances_) paramsZero.addClone(fitZero->floatParsFinal());
759 TString paramsSnapName = TString::Format(
"%s_%s_snapshot", setup.
modelConfig.GetName(), params.GetName());
760 TString paramsZSnapName = TString::Format(
"%s__snapshot", setup.
modelConfig_bonly.GetName());
763 w->defineSet(paramsSnapName, params ,
true);
764 w->defineSet(paramsZSnapName, paramsZero ,
true);
774 if (factorizedPdf_s != mc_s->GetPdf()) setup.
cleanupList.addOwned(*factorizedPdf_s);
775 if (factorizedPdf_b != mc_b->GetPdf()) setup.
cleanupList.addOwned(*factorizedPdf_b);
784 params.add(*mc_s->GetNuisanceParameters(),
true);
785 paramsZero.addClone(*mc_b->GetNuisanceParameters(),
true);
787 std::cerr <<
"ALERT: using LEP test statistics with --fitNuisances is not validated and most likely broken" << std::endl;
788 params.assignValueOnly(*mc_s->GetNuisanceParameters());
789 paramsZero.assignValueOnly(*mc_s->GetNuisanceParameters());
792 RooAbsPdf *pdfB = factorizedPdf_b;
793 if (poi.getSize() == 1) pdfB = factorizedPdf_s;
795 if (!mc_s->GetPdf()->canBeExtended()) {
801 std::cerr <<
"ALERT: LEP test statistics without optimization not validated." << std::endl;
802 RooArgSet paramsSnap; params.snapshot(paramsSnap);
803 setup.
qvar.reset(
new SimpleLikelihoodRatioTestStat(*pdfB,*factorizedPdf_s));
804 ((SimpleLikelihoodRatioTestStat&)*setup.
qvar).SetNullParameters(paramsZero);
805 ((SimpleLikelihoodRatioTestStat&)*setup.
qvar).SetAltParameters(paramsSnap);
808 std::cerr <<
"ALERT: Tevatron test statistics not yet validated." << std::endl;
809 RooAbsPdf *pdfB = factorizedPdf_b;
810 if (poi.getSize() == 1) pdfB = factorizedPdf_s;
815 setup.
qvar.reset(
new RatioOfProfiledLikelihoodsTestStat(*mc_s->GetPdf(), *pdfB, setup.
modelConfig.GetSnapshot()));
816 ((RatioOfProfiledLikelihoodsTestStat&)*setup.
qvar).SetSubtractMLE(
false);
819 if (poi.getSize() != 1 &&
testStat_ !=
"Profile") {
820 throw std::logic_error(
"ERROR: modified profile likelihood definitions (LHC, LHCFC) do not make sense in more than one dimension");
829 std::cerr <<
"ALERT: LHC test statistics without optimization not validated." << std::endl;
830 setup.
qvar.reset(
new ProfileLikelihoodTestStat(*mc_s->GetPdf()));
832 ((ProfileLikelihoodTestStat&)*setup.
qvar).SetOneSided(
true);
834 throw std::invalid_argument(
"Test statistics LHCFC is not supported without optimization");
842 RooAbsPdf *nuisancePdf = 0;
845 if (nuisancePdf) setup.
cleanupList.addOwned(*nuisancePdf);
850 std::cerr <<
"ALERT: running with newToyMC=0 not validated." << std::endl;
854 if (!mc_b->GetPdf()->canBeExtended()) setup.
toymcsampler->SetNEventsPerToy(1);
857 std::cerr <<
"ALERT: running with proof not validated." << std::endl;
859 setup.
pc.reset(
new ProofConfig(*w,
nCpu_,
"", kFALSE));
868 (
static_cast<HybridCalculator&
>(*hc)).ForcePriorNuisanceNull(*nuisancePdf);
869 (
static_cast<HybridCalculator&
>(*hc)).ForcePriorNuisanceAlt(*nuisancePdf);
873 hc->ForcePriorNuisanceNull(*w->pdf(
"__HybridNew_fake_nuisPdf__"));
874 hc->ForcePriorNuisanceAlt(*w->pdf(
"__HybridNew_fake_nuisPdf__"));
900 static const char * istr =
"__HybridNew__importanceSamplingDensity";
902 std::cerr <<
"ALERT: running with importance sampling not validated (and probably not working)." << std::endl;
903 if(
verbose > 1)
std::cout <<
">>> Enabling importance sampling for null hyp." << std::endl;
905 throw std::invalid_argument(
"Importance sampling is not available without systematics");
907 RooArgSet importanceSnapshot;
908 importanceSnapshot.addClone(poi);
909 importanceSnapshot.addClone(*mc_s->GetNuisanceParameters());
910 if (
verbose > 2) importanceSnapshot.Print(
"V");
911 hc->SetNullImportanceDensity(mc_b->GetPdf(), &importanceSnapshot);
914 std::cerr <<
"ALERT: running with importance sampling not validated (and probably not working)." << std::endl;
915 if(
verbose > 1)
std::cout <<
">>> Enabling importance sampling for alt. hyp." << std::endl;
917 throw std::invalid_argument(
"Importance sampling is not available without systematics");
919 if (w->pdf(istr) == 0) {
920 w->factory(
"__oneHalf__[0.5]");
921 RooAddPdf *sum =
new RooAddPdf(istr,
"fifty-fifty", *mc_s->GetPdf(), *mc_b->GetPdf(), *w->var(
"__oneHalf__"));
924 RooArgSet importanceSnapshot;
925 importanceSnapshot.addClone(poi);
926 importanceSnapshot.addClone(*mc_s->GetNuisanceParameters());
927 if (
verbose > 2) importanceSnapshot.Print(
"V");
928 hc->SetAltImportanceDensity(w->pdf(istr), &importanceSnapshot);
934 std::pair<double,double>
935 HybridNew::eval(RooStats::HybridCalculator &hc,
const RooAbsCollection & rVals,
bool adaptive,
double clsTarget) {
936 std::auto_ptr<HypoTestResult> hcResult(
evalGeneric(hc));
938 if (hcResult.get() == 0) {
939 std::cerr <<
"Hypotest failed" << std::endl;
940 return std::pair<double, double>(-1,-1);
944 hcResult->SetTestStatisticData(hcResult->GetTestStatisticData()-
EPS);
946 hcResult->SetTestStatisticData(hcResult->GetTestStatisticData()+
EPS);
947 hcResult->SetPValueIsRightTail(!hcResult->GetPValueIsRightTail());
949 std::pair<double,double> cls =
eval(*hcResult, rVals);
950 if (
verbose)
std::cout << (
CLs_ ?
"\tCLs = " :
"\tCLsplusb = ") << cls.first <<
" +/- " << cls.second << std::endl;
962 while (cls.second >=
clsAccuracy_ && (clsTarget == -1 || fabs(cls.first-clsTarget) < 3*cls.second) ) {
963 std::auto_ptr<HypoTestResult> more(
evalGeneric(hc));
964 more->SetBackgroundAsAlt(
false);
965 if (
testStat_ ==
"LHC" ||
testStat_ ==
"LHCFC" ||
testStat_ ==
"Profile") more->SetPValueIsRightTail(!more->GetPValueIsRightTail());
966 hcResult->Append(more.get());
968 cls =
eval(*hcResult, rVals);
969 if (
verbose)
std::cout << (
CLs_ ?
"\tCLs = " :
"\tCLsplusb = ") << cls.first <<
" +/- " << cls.second << std::endl;
973 std::auto_ptr<HypoTestResult> more(
evalGeneric(hc));
974 more->SetBackgroundAsAlt(
false);
975 if (
testStat_ ==
"LHC" ||
testStat_ ==
"LHCFC" ||
testStat_ ==
"Profile") more->SetPValueIsRightTail(!more->GetPValueIsRightTail());
976 hcResult->Append(more.get());
978 cls =
eval(*hcResult, rVals);
979 if (
verbose)
std::cout << (
CLs_ ?
"\tCLs = " :
"\tCLsplusb = ") << cls.first <<
" +/- " << cls.second << std::endl;
985 "\tCLs = " << hcResult->CLs() <<
" +/- " << hcResult->CLsError() <<
"\n" <<
986 "\tCLb = " << hcResult->CLb() <<
" +/- " << hcResult->CLbError() <<
"\n" <<
987 "\tCLsplusb = " << hcResult->CLsplusb() <<
" +/- " << hcResult->CLsplusbError() <<
"\n" <<
991 perf_totalToysRun_ += (hcResult->GetAltDistribution()->GetSize() + hcResult->GetNullDistribution()->GetSize());
994 HypoTestPlot
plot(*hcResult, 30);
995 TCanvas *
c1 =
new TCanvas(
"c1",
"c1");
997 c1->Print(
plot_.c_str());
1001 TString
name = TString::Format(
"HypoTestResult_mh%g",
mass_);
1002 RooLinkedListIter it = rVals.iterator();
1003 for (RooRealVar *rIn = (RooRealVar*) it.Next(); rIn != 0; rIn = (RooRealVar*) it.Next()) {
1004 name += Form(
"_%s%g", rIn->GetName(), rIn->getVal());
1007 writeToysHere->WriteTObject(
new HypoTestResult(*hcResult), name);
1014 std::pair<double,double>
HybridNew::eval(
const RooStats::HypoTestResult &hcres,
const RooAbsCollection & rVals)
1016 double rVal = ((RooAbsReal*)rVals.first())->getVal();
1017 return eval(hcres,rVal);
1020 std::pair<double,double>
HybridNew::eval(
const RooStats::HypoTestResult &hcres,
double rVal)
1023 RooStats::SamplingDistribution * bDistribution = hcres.GetNullDistribution(), * sDistribution = hcres.GetAltDistribution();
1024 const std::vector<Double_t> & bdist = bDistribution->GetSamplingDistribution();
1025 const std::vector<Double_t> & bweight = bDistribution->GetSampleWeights();
1026 const std::vector<Double_t> & sdist = sDistribution->GetSamplingDistribution();
1027 const std::vector<Double_t> & sweight = sDistribution->GetSampleWeights();
1028 Double_t
data = hcres.GetTestStatisticData();
1029 std::vector<Double_t> absbdist(bdist.size()), abssdist(sdist.size());
1030 std::vector<Double_t> absbweight(bweight), abssweight(sweight);
1032 if (
rule_ ==
"FC") {
1033 for (
int i = 0,
n = absbdist.size();
i <
n; ++
i) absbdist[
i] = fabs(bdist[
i]);
1034 for (
int i = 0, n = abssdist.size(); i <
n; ++
i) abssdist[i] = fabs(sdist[i]);
1037 for (
int i = 0,
n = absbdist.size();
i <
n; ++
i) absbdist[
i] =
max(0., bdist[
i]);
1038 for (
int i = 0, n = abssdist.size(); i <
n; ++
i) abssdist[i] =
max(0., sdist[i]);
1039 absdata =
max(0., data) -
EPS;
1042 abssdist.reserve(absbdist.size() + abssdist.size());
1043 abssdist.insert(abssdist.end(), absbdist.begin(), absbdist.end());
1044 abssweight.reserve(absbweight.size() + abssweight.size());
1045 abssweight.insert(abssweight.end(), absbweight.begin(), absbweight.end());
1047 RooStats::HypoTestResult
result;
1048 RooStats::SamplingDistribution *abssDist =
new RooStats::SamplingDistribution(
"s",
"s",abssdist,abssweight);
1049 RooStats::SamplingDistribution *absbDist =
new RooStats::SamplingDistribution(
"b",
"b",absbdist,absbweight);
1050 result.SetNullDistribution(absbDist);
1051 result.SetAltDistribution(abssDist);
1052 result.SetTestStatisticData(absdata);
1053 result.SetPValueIsRightTail(!result.GetPValueIsRightTail());
1055 return std::pair<double,double>(result.CLs(), result.CLsError());
1057 return std::pair<double,double>(result.CLsplusb(), result.CLsplusbError());
1061 return std::pair<double,double>(hcres.CLs(), hcres.CLsError());
1063 return std::pair<double,double>(hcres.CLsplusb(), hcres.CLsplusbError());
1075 std::vector<Double_t> btoys = hcres.GetNullDistribution()->GetSamplingDistribution();
1079 hcres.SetTestStatisticData(testStat);
1085 RooStats::SamplingDistribution * bDistribution = hcres.GetNullDistribution(), * sDistribution = hcres.GetAltDistribution();
1086 const std::vector<Double_t> & bdist = bDistribution->GetSamplingDistribution();
1087 const std::vector<Double_t> & bweight = bDistribution->GetSampleWeights();
1088 const std::vector<Double_t> & sdist = sDistribution->GetSamplingDistribution();
1089 const std::vector<Double_t> & sweight = sDistribution->GetSampleWeights();
1094 std::vector<std::pair<double,double> > bcumul; bcumul.reserve(bdist.size());
1095 std::vector<std::pair<double,double> > scumul; scumul.reserve(sdist.size());
1096 double btot = 0, stot = 0;
1097 for (std::vector<Double_t>::const_iterator it = bdist.begin(), ed = bdist.end(), itw = bweight.begin(); it != ed; ++it, ++itw) {
1098 bcumul.push_back(std::pair<double,double>(*it, *itw));
1101 for (std::vector<Double_t>::const_iterator it = sdist.begin(), ed = sdist.end(), itw = sweight.begin(); it != ed; ++it, ++itw) {
1102 scumul.push_back(std::pair<double,double>(*it, *itw));
1105 double sinv = 1.0/stot, binv = 1.0/btot, runningSum;
1107 std::sort(scumul.begin(), scumul.end());
1109 for (std::vector<std::pair<double,double> >::reverse_iterator it = scumul.rbegin(), ed = scumul.rend(); it != ed; ++it) {
1110 runningSum += it->second;
1111 it->second = runningSum * sinv;
1113 std::sort(bcumul.begin(), bcumul.end());
1114 std::vector<std::pair<double,std::pair<double,double> > > xcumul; xcumul.reserve(bdist.size());
1116 std::vector<std::pair<double,double> >::const_iterator sbegin = scumul.begin(), send = scumul.end();
1118 for (std::vector<std::pair<double,double> >::const_reverse_iterator it = bcumul.rbegin(), ed = bcumul.rend(); it != ed; ++it) {
1119 runningSum += it->second;
1120 std::vector<std::pair<double,double> >::const_iterator
match = std::upper_bound(sbegin, send, std::pair<double,double>(it->first, 0));
1121 if (match == send) {
1123 double clsb = (scumul.back().second > 0.5 ? 1.0 : 0.0), clb = runningSum*binv, cls = clsb / clb;
1124 xcumul.push_back(std::make_pair(
CLs_ ? cls : clsb, *it));
1126 double clsb = match->second, clb = runningSum*binv, cls = clsb / clb;
1128 xcumul.push_back(std::make_pair(
CLs_ ? cls : clsb, *it));
1132 std::sort(xcumul.begin(), xcumul.end());
1135 for (std::vector<std::pair<
double,std::pair<double,double> > >::const_iterator it = xcumul.begin(), ed = xcumul.end(); it != ed; ++it) {
1136 runningSum += it->second.second;
1137 if (runningSum >= cut) {
1138 hcres.SetTestStatisticData(it->second.first);
1148 std::vector<std::pair<double, double> >
values(bdist.size());
1149 for (
int i = 0,
n = bdist.size();
i <
n; ++
i) {
1150 hcres.SetTestStatisticData( bdist[
i] );
1151 values[
i] = std::pair<double, double>(
CLs_ ? hcres.CLs() : hcres.CLsplusb(), bdist[
i]);
1157 std::cout <<
"CLs quantile = " << (
CLs_ ? hcres.CLs() : hcres.CLsplusb()) <<
" for test stat = " <<
values[index].second << std::endl;
1158 std::cout <<
"Computed quantiles in " << timer.RealTime() <<
" s" << std::endl;
1163 std::vector<Double_t> stoys = hcres.GetAltDistribution()->GetSamplingDistribution();
1167 hcres.SetTestStatisticData(testStat);
1173 TStopwatch timer; timer.Start();
1174 RooStats::HypoTestResult *
ret = hc.GetHypoTest();
1175 if (
runtimedef::get(
"HybridNew_Timing"))
std::cout <<
"Evaluated toys in " << timer.RealTime() <<
" s " << std::endl;
1182 std::auto_ptr<RooStats::HypoTestResult>
result(0);
1184 unsigned int ich = 0;
1185 std::vector<UInt_t> newSeeds(
fork_);
1186 for (ich = 0; ich <
fork_; ++ich) {
1193 do { ret = waitpid(-1, &cstatus, 0); }
while (ret == -1 && errno == EINTR);
1194 }
while (ret != -1);
1195 if (ret == -1 && errno != ECHILD)
throw std::runtime_error(
"Didn't wait for child");
1196 for (ich = 0; ich <
fork_; ++ich) {
1197 TFile *
f = TFile::Open(TString::Format(
"%s.%d.root", tmpfile, ich));
1198 if (f == 0)
throw std::runtime_error(TString::Format(
"Child didn't leave output file %s.%d.root", tmpfile, ich).
Data());
1199 RooStats::HypoTestResult *res =
dynamic_cast<RooStats::HypoTestResult *
>(f->Get(
"result"));
1200 if (res == 0)
throw std::runtime_error(TString::Format(
"Child output file %s.%d.root is corrupted", tmpfile, ich).
Data());
1201 if (result.get()) result->Append(res);
else result.reset(dynamic_cast<RooStats::HypoTestResult *>(res->Clone()));
1203 unlink(TString::Format(
"%s.%d.root", tmpfile, ich).
Data());
1204 unlink(TString::Format(
"%s.%d.out.txt", tmpfile, ich).
Data());
1205 unlink(TString::Format(
"%s.%d.err.txt", tmpfile, ich).
Data());
1208 RooRandom::randomGenerator()->SetSeed(newSeeds[ich]);
1209 freopen(TString::Format(
"%s.%d.out.txt", tmpfile, ich).
Data(),
"w", stdout);
1210 freopen(TString::Format(
"%s.%d.err.txt", tmpfile, ich).
Data(),
"w", stderr);
1211 std::cout <<
" I'm child " << ich <<
", seed " << newSeeds[ich] << std::endl;
1212 RooStats::HypoTestResult *hcResult =
evalGeneric(hc,
true);
1213 TFile *
f = TFile::Open(TString::Format(
"%s.%d.root", tmpfile, ich),
"RECREATE");
1214 f->WriteTObject(hcResult,
"result");
1217 fflush(stdout); fflush(stderr);
1218 std::cout <<
"And I'm done" << std::endl;
1219 throw std::runtime_error(
"done");
1224 if (
verbose > 1) {
std::cout <<
" Evaluation of p-values done in " << timer.RealTime() <<
" s" << std::endl; }
1225 return result.release();
1232 RooStats::HypoTestResult * HybridNew::evalFrequentist(RooStats::HybridCalculator &hc) {
1235 RooArgSet obs(*hc.GetAlternateModel()->GetObservables());
1236 RooArgSet nuis(*hc.GetAlternateModel()->GetNuisanceParameters());
1237 RooArgSet gobs(*hc.GetAlternateModel()->GetGlobalObservables());
1238 RooArgSet nullPoi(*hc.GetNullModel()->GetSnapshot());
1239 std::auto_ptr<RooAbsCollection> parS(hc.GetAlternateModel()->GetPdf()->getParameters(obs));
1240 std::auto_ptr<RooAbsCollection> parB(hc.GetNullModel()->GetPdf()->getParameters(obs));
1241 RooArgList constraintsS, constraintsB;
1242 RooAbsPdf *factorS = hc.GetAlternateModel()->GetPdf();
1243 RooAbsPdf *factorB = hc.GetNullModel()->GetPdf();
1246 std::auto_ptr<RooAbsPdf> nuisPdf(
utils::makeNuisancePdf(const_cast<RooStats::ModelConfig&>(*hc.GetAlternateModel())));
1247 std::vector<Double_t> distSB, distB;
1248 *parS = *snapGlobalObs_;
1249 Double_t tsData = hc.GetTestStatSampler()->GetTestStatistic()->Evaluate(*realData_, nullPoi);
1250 if (
verbose > 2)
std::cout <<
"Test statistics on data: " << tsData << std::endl;
1251 for (
int i = 0;
i < toysSB; ++
i) {
1253 *parS = *hc.GetAlternateModel()->GetSnapshot();
1255 if (
verbose > 2) {
std::cout <<
"Generating global obs starting from " << std::endl; parS->Print(
"V"); }
1256 std::auto_ptr<RooDataSet> gdata(nuisPdf->generate(gobs, 1));
1257 *parS = *gdata->get(0);
1260 if (
verbose > 2) {
std::cout <<
"Generating obs starting from " << std::endl; parS->Print(
"V"); }
1261 std::auto_ptr<RooDataSet>
data(factorS->generate(obs, RooFit::Extended()));
1264 distSB.push_back(hc.GetTestStatSampler()->GetTestStatistic()->Evaluate(*
data, nullPoi));
1267 for (
int i = 0;
i < toysB; ++
i) {
1269 *parB = *hc.GetNullModel()->GetSnapshot();
1272 if (
verbose > 2) {
std::cout <<
"Generating global obs starting from " << std::endl; parB->Print(
"V"); }
1273 std::auto_ptr<RooDataSet> gdata(nuisPdf->generate(gobs, 1));
1274 *parB = *gdata->get(0);
1277 if (
verbose > 2) {
std::cout <<
"Generating obs starting from " << std::endl; parB->Print(
"V"); }
1278 std::auto_ptr<RooDataSet>
data(factorB->generate(obs, RooFit::Extended()));
1281 distB.push_back(hc.GetTestStatSampler()->GetTestStatistic()->Evaluate(*
data, nullPoi));
1285 RooStats::HypoTestResult *
ret =
new RooStats::HypoTestResult();
1286 ret->SetTestStatisticData(tsData);
1287 ret->SetAltDistribution(
new RooStats::SamplingDistribution(
"sb",
"sb",distSB));
1288 ret->SetNullDistribution(
new RooStats::SamplingDistribution(
"b",
"b",distB));
1294 if (!
readToysFromHere)
throw std::logic_error(
"Cannot use readHypoTestResult: option toysFile not specified, or input file empty");
1296 if (!toyDir)
throw std::logic_error(
"Cannot use readHypoTestResult: empty toy dir in input file empty");
1298 TString prefix1 = TString::Format(
"HypoTestResult_mh%g",
mass_);
1299 TString prefix2 = TString::Format(
"HypoTestResult");
1300 RooLinkedListIter it = rVals.iterator();
1301 for (RooRealVar *rIn = (RooRealVar*) it.Next(); rIn != 0; rIn = (RooRealVar*) it.Next()) {
1303 prefix1 += Form(
"_%s%g", rIn->GetName(), rIn->getVal());
1304 prefix2 += Form(
"_%s%g", rIn->GetName(), rIn->getVal());
1307 std::auto_ptr<RooStats::HypoTestResult>
ret;
1308 TIter
next(toyDir->GetListOfKeys()); TKey *
k;
1309 while ((k = (TKey *)
next()) != 0) {
1310 if (TString(k->GetName()).Index(prefix1) != 0 && TString(k->GetName()).Index(prefix2) != 0)
continue;
1311 RooStats::HypoTestResult *toy =
dynamic_cast<RooStats::HypoTestResult *
>(toyDir->Get(k->GetName()));
1312 if (toy == 0)
continue;
1314 if (ret.get() == 0) {
1315 ret.reset(
new RooStats::HypoTestResult(*toy));
1321 if (ret.get() == 0) {
1322 std::cout <<
"ERROR: parameter point not found in input root file.\n";
1324 if (
verbose > 0) toyDir->ls();
1325 std::cout <<
"ERROR: parameter point not found in input root file" << std::endl;
1326 throw std::invalid_argument(
"Missing input");
1330 "\tCLs = " << ret->CLs() <<
" +/- " << ret->CLsError() <<
"\n" <<
1331 "\tCLb = " << ret->CLb() <<
" +/- " << ret->CLbError() <<
"\n" <<
1332 "\tCLsplusb = " << ret->CLsplusb() <<
" +/- " << ret->CLsplusbError() <<
"\n" <<
1335 HypoTestPlot
plot(*ret, 30);
1336 TCanvas *
c1 =
new TCanvas(
"c1",
"c1");
1338 c1->Print(
plot_.c_str());
1342 return ret.release();
1346 if (
rValues_.getSize() != 1)
throw std::runtime_error(
"Running limits with grid only works in one dimension for the moment");
1349 TIter
next(toyDir->GetListOfKeys()); TKey *
k;
const char *poiName =
rValues_.first()->GetName();
1350 while ((k = (TKey *)
next()) != 0) {
1351 TString
name(k->GetName());
1352 if (
name.Index(
"HypoTestResult_mh") == 0) {
1353 if (
name.Index(TString::Format(
"HypoTestResult_mh%g_%s",
mass_,poiName)) != 0 ||
name.Index(
"_",
name.Index(
"_")+1) == -1)
continue;
1354 name.ReplaceAll(TString::Format(
"HypoTestResult_mh%g_%s",
mass_,poiName),
"");
1355 if (
name.Index(
"_") == -1)
continue;
1357 }
else if (
name.Index(
"HypoTestResult_") == 0) {
1359 std::cout <<
"HybridNew::readGrid: HypoTestResult with non-conformant name " <<
name <<
" will be skipped" << std::endl;
1362 double rVal = atof(
name.Data());
1363 if (rVal < rMin || rVal > rMax)
continue;
1364 if (
verbose > 2)
std::cout <<
" Do " << k->GetName() <<
" -> " <<
name <<
" --> " << rVal << std::endl;
1365 RooStats::HypoTestResult *toy =
dynamic_cast<RooStats::HypoTestResult *
>(toyDir->Get(k->GetName()));
1366 RooStats::HypoTestResult *&
merge =
grid_[rVal];
1367 if (merge == 0) merge =
new RooStats::HypoTestResult(*toy);
1368 else merge->Append(toy);
1372 std::cout <<
"GRID, as is." << std::endl;
1373 typedef std::map<double, RooStats::HypoTestResult *>::iterator
point;
1374 for (point it =
grid_.begin(), ed =
grid_.end(); it != ed; ++it) {
1375 std::cout <<
" - " << it->first <<
" (CLs = " << it->second->CLs() <<
" +/- " << it->second->CLsError() <<
")" << std::endl;
1380 typedef std::map<double, RooStats::HypoTestResult *>::iterator
point;
1382 for (point it =
grid_.begin(), ed =
grid_.end(); it != ed; ++it) {
1383 it->second->ResetBit(1);
1387 typedef std::pair<double,double> CLs_t;
1388 std::vector<point> points; points.reserve(
grid_.size());
1389 std::vector<CLs_t>
values; values.reserve(
grid_.size());
1390 for (point it =
grid_.begin(), ed =
grid_.end(); it != ed; ++it) { points.push_back(it); values.push_back(CLs_t(-99, -99)); }
1391 int iMin = 0, iMax = points.size()-1;
1392 while (iMax-iMin > 3) {
1393 if (
verbose > 1)
std::cout <<
"Bisecting range [" << iMin <<
", " << iMax <<
"]" << std::endl;
1394 int iMid = (iMin+iMax)/2;
1395 CLs_t clsMid = values[iMid] =
updateGridPoint(w, mc_s, mc_b, data, points[iMid]);
1396 if (
verbose > 1)
std::cout <<
" Midpoint " << iMid <<
" value " << clsMid.first <<
" +/- " << clsMid.second << std::endl;
1397 if (clsMid.first - 3*
max(clsMid.second,0.01) > clsTarget_) {
1399 iMin = iMid;
continue;
1400 }
else if (clsMid.first + 3*
max(clsMid.second,0.01) < clsTarget_) {
1402 iMax = iMid;
continue;
1405 while (iMin < iMid-1) {
1406 int iLo = (iMin+iMid)/2;
1407 CLs_t clsLo = values[iLo] =
updateGridPoint(w, mc_s, mc_b, data, points[iLo]);
1408 if (
verbose > 1)
std::cout <<
" Lowpoint " << iLo <<
" value " << clsLo.first <<
" +/- " << clsLo.second << std::endl;
1409 if (clsLo.first - 3*
max(clsLo.second,0.01) > clsTarget_) iMin = iLo;
1412 while (iMax > iMid+1) {
1413 int iHi = (iMax+iMid)/2;
1414 CLs_t clsHi = values[iHi] =
updateGridPoint(w, mc_s, mc_b, data, points[iHi]);
1415 if (
verbose > 1)
std::cout <<
" Highpoint " << iHi <<
" value " << clsHi.first <<
" +/- " << clsHi.second << std::endl;
1416 if (clsHi.first + 3*
max(clsHi.second,0.01) < clsTarget_) iMax = iHi;
1422 if (
verbose > 1)
std::cout <<
"Final range [" << iMin <<
", " << iMax <<
"]" << std::endl;
1423 for (
int i = 0;
i < iMin; ++
i) {
1424 points[
i]->second->SetBit(1);
1425 if (
verbose > 1)
std::cout <<
" Will not use point " <<
i <<
" (r " << points[
i]->first <<
")" << std::endl;
1427 for (
int i = iMin;
i <= iMax; ++
i) {
1428 points[
i]->second->ResetBit(1);
1429 if (values[
i].
first < -2) {
1430 if (
verbose > 1)
std::cout <<
" Updaing point " <<
i <<
" (r " << points[
i]->first <<
")" << std::endl;
1433 else if (
verbose > 1)
std::cout <<
" Point " <<
i <<
" (r " << points[
i]->first <<
") was already updated during search." << std::endl;
1435 for (
int i = iMax+1,
n = points.size();
i <
n; ++
i) {
1436 points[
i]->second->SetBit(1);
1437 if (
verbose > 1)
std::cout <<
" Will not use point " <<
i <<
" (r " << points[
i]->first <<
")" << std::endl;
1442 typedef std::map<double, RooStats::HypoTestResult *>::iterator
point;
1443 std::vector<Double_t> rToUpdate; std::vector<point> pointToUpdate;
1444 for (point it =
grid_.begin(), ed =
grid_.end(); it != ed; ++it) {
1445 it->second->ResetBit(1);
1446 if (it->first == 0 || fabs(it->second->GetTestStatisticData()) <= 2*
minimizerTolerance_) {
1447 rToUpdate.push_back(it->first);
1448 pointToUpdate.push_back(it);
1451 if (
verbose > 0)
std::cout <<
"A total of " << rToUpdate.size() <<
" points will be updated." << std::endl;
1453 std::auto_ptr<RooStats::HybridCalculator> hc =
create(w, mc_s, mc_b, data, rToUpdate.back(),
setup);
1456 for (
int i = 0,
n = rToUpdate.size();
i <
n; ++
i) {
1457 pointToUpdate[
i]->second->SetTestStatisticData(qVals[
i] -
EPS);
1459 if (
verbose > 0)
std::cout <<
"All points have been updated." << std::endl;
1462 std::pair<double,double>
HybridNew::updateGridPoint(RooWorkspace *
w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &
data, std::map<double, RooStats::HypoTestResult *>::iterator
point) {
1463 typedef std::pair<double,double> CLs_t;
1465 if (point->first == 0 &&
CLs_)
return std::pair<double,double>(1,0);
1466 RooArgSet poi(*mc_s->GetParametersOfInterest());
1467 RooRealVar *
r =
dynamic_cast<RooRealVar *
>(poi.first());
1470 point->second->SetTestStatisticData(point->second->GetTestStatisticData() + (isProfile ?
EPS :
EPS));
1473 std::auto_ptr<RooStats::HybridCalculator> hc =
create(w, mc_s, mc_b, data, point->first, setup);
1475 if (isProfile) nullPOI.setRealValue(r->GetName(), point->first);
1476 double testStat = setup.
qvar->Evaluate(data, nullPOI);
1477 point->second->SetTestStatisticData(testStat + (isProfile ?
EPS :
EPS));
1480 std::cout <<
"At " << r->GetName() <<
" = " << point->first <<
":\n" <<
1481 "\tCLs = " << point->second->CLs() <<
" +/- " << point->second->CLsError() <<
"\n" <<
1482 "\tCLb = " << point->second->CLb() <<
" +/- " << point->second->CLbError() <<
"\n" <<
1483 "\tCLsplusb = " << point->second->CLsplusb() <<
" +/- " << point->second->CLsplusbError() <<
"\n" <<
1487 return eval(*point->second, point->first);
1490 typedef std::pair<double,double> CLs_t;
1493 for (std::map<double, RooStats::HypoTestResult *>::iterator itg =
grid_.begin(), edg =
grid_.end(); itg != edg; ++itg, ++
i) {
1494 if (itg->second->TestBit(1))
continue;
1497 if (itg->first > 0) val =
eval(*itg->second, itg->first);
1499 val =
eval(*itg->second, itg->first);
1501 if (val.first == -1)
continue;
1502 if (val.second == 0 && (val.first != 1 && val.first != 0))
continue;
1510 for (std::map<double, RooStats::HypoTestResult *>::iterator it =
grid_.begin(), ed =
grid_.end(); it != ed; ++it) {
TDirectory * readToysFromHere
std::auto_ptr< RooStats::ProofConfig > pc
static unsigned int iterations_
static bool importanceSamplingNull_
static unsigned int fork_
std::auto_ptr< RooStats::ToyMCSampler > toymcsampler
bool setAllConstant(const RooAbsCollection &coll, bool constant=true)
set all RooRealVars to constants. return true if at least one changed status
RooStats::ModelConfig modelConfig
static PFTauRenderPlugin instance
RooStats::HypoTestResult * evalGeneric(RooStats::HybridCalculator &hc, bool forceNoFork=false)
virtual bool runSignificance(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
int get(const char *name)
void updateGridDataFC(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, bool smart, double clsTarget)
virtual bool runLimit(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
static std::string rValue_
RooAbsPdf * makeNuisancePdf(RooStats::ModelConfig &model, const char *name="nuisancePdf")
static float minimizerTolerance_
static double interpAccuracy_
static std::string minimizerAlgo_
static WorkingMode workingMode_
TDirectory * writeToysHere
void applySignalQuantile(RooStats::HypoTestResult &hcres)
static bool saveHybridResult_
virtual const std::string & name() const
U second(std::pair< T, U > const &p)
static double rAbsAccuracy_
static void commitPoint(bool expected, float quantile)
Save a point into the output tree. Usually if expected = false, quantile should be set to -1 (except ...
static float quantileForExpectedFromGrid_
void updateGridData(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, bool smart, double clsTarget)
virtual void applyOptions(const boost::program_options::variables_map &vm)
void applyExpectedQuantile(RooStats::HypoTestResult &hcres)
const T & max(const T &a, const T &b)
std::auto_ptr< RooStats::TestStatistic > qvar
RooAbsPdf * factorizePdf(const RooArgSet &observables, RooAbsPdf &pdf, RooArgList &constraints)
virtual bool run(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
Float_t g_quantileExpected_
std::pair< double, double > eval(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, const RooAbsCollection &rVals, bool adaptive=false, double clsTarget=-1)
generic version
std::map< double, RooStats::HypoTestResult * > grid_
static unsigned int nCpu_
virtual bool runTestStatistics(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
static unsigned int nToys_
static bool genGlobalObs_
static std::string testStat_
static bool optimizeProductPdf_
static bool noUpdateGrid_
void setupPOI(RooStats::ModelConfig *mc_s)
RooStats::HypoTestResult * readToysFromFile(const RooAbsCollection &rVals)
Setup Minimizer configuration on creation, reset the previous one on destruction. ...
static std::string gridFile_
unsigned int perf_totalToysRun_
std::auto_ptr< TGraphErrors > limitPlot_
void printRAD(const RooAbsData *d)
char data[epos_bytes_allocation]
static bool optimizeTestStatistics_
std::pair< double, double > updateGridPoint(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, std::map< double, RooStats::HypoTestResult * >::iterator point)
static bool genNuisances_
static double rRelAccuracy_
RooStats::ModelConfig modelConfig_bonly
perl if(1 lt scalar(@::datatypes))
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
static bool expectedFromGrid_
static bool newToyMCSampler_
void applyClsQuantile(RooStats::HypoTestResult &hcres)
boost::program_options::options_description options_
void readGrid(TDirectory *directory, double rMin, double rMax)
virtual void applyDefaultOptions()
static bool clsQuantiles_
virtual bool runSinglePoint(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
static bool importanceSamplingAlt_
RooStats::HypoTestResult * evalWithFork(RooStats::HybridCalculator &hc)
void setup(std::vector< TH2F > &depth, std::string name, std::string units="")
static bool fitNuisances_
*vegas h *****************************************************used in the default bin number in original ***version of VEGAS is ***a higher bin number might help to derive a more precise ***grade subtle point
static bool readHybridResults_
static RooArgSet rValues_
static double clsAccuracy_
std::auto_ptr< RooStats::HybridCalculator > create(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, const RooAbsCollection &rVals, Setup &setup)
generic version