CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Asymptotic.cc
Go to the documentation of this file.
1 #include <stdexcept>
2 
3 #include "../interface/Asymptotic.h"
4 #include <RooRealVar.h>
5 #include <RooArgSet.h>
6 #include <RooAbsPdf.h>
7 #include <RooFitResult.h>
8 #include <RooRandom.h>
9 #include <RooStats/ModelConfig.h>
10 #include <Math/DistFuncMathCore.h>
11 #include "../interface/Combine.h"
12 #include "../interface/CloseCoutSentry.h"
13 #include "../interface/RooFitGlobalKillSentry.h"
14 #include "../interface/ProfiledLikelihoodRatioTestStatExt.h"
15 #include "../interface/ToyMCSamplerOpt.h"
16 #include "../interface/ProfileLikelihood.h"
17 #include "../interface/CascadeMinimizer.h"
18 #include "../interface/utils.h"
19 #include "../interface/AsimovUtils.h"
20 
21 using namespace RooStats;
22 
23 double Asymptotic::rAbsAccuracy_ = 0.0005;
24 double Asymptotic::rRelAccuracy_ = 0.005;
25 std::string Asymptotic::what_ = "both";
26 bool Asymptotic::qtilde_ = true;
27 bool Asymptotic::picky_ = false;
28 bool Asymptotic::noFitAsimov_ = false;
29 bool Asymptotic::newExpected_ = false;
30 std::string Asymptotic::minosAlgo_ = "stepping";
31 std::string Asymptotic::minimizerAlgo_ = "Minuit2";
34 double Asymptotic::rValue_ = 1.0;
35 
36 
38 LimitAlgo("Asymptotic specific options") {
39  options_.add_options()
40  ("rAbsAcc", boost::program_options::value<double>(&rAbsAccuracy_)->default_value(rAbsAccuracy_), "Absolute accuracy on r to reach to terminate the scan")
41  ("rRelAcc", boost::program_options::value<double>(&rRelAccuracy_)->default_value(rRelAccuracy_), "Relative accuracy on r to reach to terminate the scan")
42  ("run", boost::program_options::value<std::string>(&what_)->default_value(what_), "What to run: both (default), observed, expected, blind.")
43  ("singlePoint", boost::program_options::value<double>(&rValue_), "Just compute CLs for the given value of r")
44  ("minimizerAlgo", boost::program_options::value<std::string>(&minimizerAlgo_)->default_value(minimizerAlgo_), "Choice of minimizer used for profiling (Minuit vs Minuit2)")
45  ("minimizerTolerance", boost::program_options::value<float>(&minimizerTolerance_)->default_value(minimizerTolerance_), "Tolerance for minimizer used for profiling")
46  ("minimizerStrategy", boost::program_options::value<int>(&minimizerStrategy_)->default_value(minimizerStrategy_), "Stragegy for minimizer")
47  ("qtilde", boost::program_options::value<bool>(&qtilde_)->default_value(qtilde_), "Allow only non-negative signal strengths (default is true).")
48  ("picky", "Abort on fit failures")
49  ("noFitAsimov", "Use the pre-fit asimov dataset")
50  ("newExpected", "Use the new formula for expected limits")
51  ("minosAlgo", boost::program_options::value<std::string>(&minosAlgo_)->default_value(minosAlgo_), "Algorithm to use to get the median expected limit: 'minos' (fastest), 'bisection', 'stepping' (default, most robust)")
52  ;
53 }
54 
55 void Asymptotic::applyOptions(const boost::program_options::variables_map &vm) {
56  if (vm.count("singlePoint") && !vm["singlePoint"].defaulted()) {
57  if (!vm["run"].defaulted()) throw std::invalid_argument("Asymptotic: when using --singlePoint you can't use --run (at least for now)");
58  what_ = "singlePoint";
59  } else {
60  if (what_ != "observed" && what_ != "expected" && what_ != "both" && what_ != "blind")
61  throw std::invalid_argument("Asymptotic: option 'run' can only be 'observed', 'expected' or 'both' (the default) or 'blind' (a-priori expected)");
62  }
63  picky_ = vm.count("picky");
64  noFitAsimov_ = vm.count("noFitAsimov");
65  newExpected_ = vm.count("newExpected");
66  if (what_ == "blind") { what_ = "expected"; noFitAsimov_ = true; }
67  if (noFitAsimov_) std::cout << "Will use a-priori expected background instead of a-posteriori one." << std::endl;
68 }
69 
71  what_ = "observed"; noFitAsimov_ = true; // faster
72 }
73 
74 bool Asymptotic::run(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint) {
77  if (verbose > 0) std::cout << "Will compute " << what_ << " limit(s) using minimizer " << minimizerAlgo_
78  << " with strategy " << minimizerStrategy_ << " and tolerance " << minimizerTolerance_ << std::endl;
79 
80  bool ret = false;
81  std::vector<std::pair<float,float> > expected;
82  if (what_ == "both" || what_ == "expected") expected = runLimitExpected(w, mc_s, mc_b, data, limit, limitErr, hint);
83  if (what_ != "expected") ret = runLimit(w, mc_s, mc_b, data, limit, limitErr, hint);
84 
85  if (verbose >= 0) {
86  const char *rname = mc_s->GetParametersOfInterest()->first()->GetName();
87  std::cout << "\n -- Asymptotic -- " << "\n";
88  if (what_ == "singlePoint") {
89  printf("Observed CLs for %s = %.1f: %6.4f \n", rname, rValue_, limit);
90  } else if (ret && what_ != "expected") {
91  printf("Observed Limit: %s < %6.4f\n", rname, limit);
92  }
93  for (std::vector<std::pair<float,float> >::const_iterator it = expected.begin(), ed = expected.end(); it != ed; ++it) {
94  printf("Expected %4.1f%%: %s < %6.4f\n", it->first*100, rname, it->second);
95  }
96  std::cout << std::endl;
97  }
98 
99  // note that for expected we have to return FALSE even if we succeed because otherwise it goes into the observed limit as well
100  return ret;
101 }
102 
103 bool Asymptotic::runLimit(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint) {
104  RooRealVar *r = dynamic_cast<RooRealVar *>(mc_s->GetParametersOfInterest()->first());
105  w->loadSnapshot("clean");
106  RooAbsData &asimov = *asimovDataset(w, mc_s, mc_b, data);
107 
108  r->setConstant(false);
109  r->setVal(0.1*r->getMax());
110  r->setMin(qtilde_ ? 0 : -r->getMax());
111 
112  if (params_.get() == 0) params_.reset(mc_s->GetPdf()->getParameters(data));
113 
114  hasFloatParams_ = false;
115  std::auto_ptr<TIterator> itparam(params_->createIterator());
116  for (RooAbsArg *a = (RooAbsArg *) itparam->Next(); a != 0; a = (RooAbsArg *) itparam->Next()) {
117  RooRealVar *rrv = dynamic_cast<RooRealVar *>(a);
118  if ( rrv != 0 && rrv != r && rrv->isConstant() == false ) { hasFloatParams_ = true; break; }
119  }
120 
121 
122  RooArgSet constraints; if (withSystematics) constraints.add(*mc_s->GetNuisanceParameters());
123  nllD_.reset(mc_s->GetPdf()->createNLL(data, RooFit::Constrain(constraints)));
124  nllA_.reset(mc_s->GetPdf()->createNLL(asimov, RooFit::Constrain(constraints)));
125 
126  if (verbose > 0) std::cout << (qtilde_ ? "Restricting" : "Not restricting") << " " << r->GetName() << " to positive values." << std::endl;
127  if (verbose > 1) params_->Print("V");
128 
129  if (verbose > 0) std::cout << "\nMake global fit of real data" << std::endl;
130  {
131  CloseCoutSentry sentry(verbose < 3);
135  minim.minimize(verbose-2);
137  minNllD_ = nllD_->getVal();
138  }
139  if (verbose > 0) std::cout << "NLL at global minimum of data: " << minNllD_ << " (" << r->GetName() << " = " << r->getVal() << ")" << std::endl;
140  double rErr = std::max<double>(r->getError(), 0.02 * (r->getMax() - r->getMin()));
141 
142  r->setMin(0);
143 
144  if (verbose > 1) fitFreeD_.Print("V");
145  if (verbose > 0) std::cout << "\nMake global fit of asimov data" << std::endl;
146  {
147  CloseCoutSentry sentry(verbose < 3);
151  minim.minimize(verbose-2);
153  minNllA_ = nllA_->getVal();
154  }
155  if (verbose > 0) std::cout << "NLL at global minimum of asimov: " << minNllA_ << " (" << r->GetName() << " = " << r->getVal() << ")" << std::endl;
156  if (verbose > 1) fitFreeA_.Print("V");
157 
159  r->setConstant(true);
160 
161  if (what_ == "singlePoint") {
162  limit = getCLs(*r, rValue_, true, &limit, &limitErr);
163  return true;
164  }
165 
166  double clsTarget = 1-cl;
167  double rMin = std::max<double>(0, r->getVal()), rMax = rMin + 3 * rErr;
168  double clsMax = 1, clsMin = 0;
169  for (int tries = 0; tries < 5; ++tries) {
170  double cls = getCLs(*r, rMax);
171  if (cls == -999) { std::cerr << "Minimization failed in an unrecoverable way" << std::endl; break; }
172  if (cls < clsTarget) { clsMin = cls; break; }
173  rMax *= 2;
174  }
175 
176  do {
177  if (clsMax < 3*clsTarget && clsMin > 0.3*clsTarget) {
178  double rCross = rMin + (rMax-rMin)*log(clsMax/clsTarget)/log(clsMax/clsMin);
179  if ((rCross-rMin) < (rMax - rCross)) {
180  limit = 0.8*rCross + 0.2*rMax;
181  } else {
182  limit = 0.8*rCross + 0.2*rMin;
183  }
184  limitErr = 0.5*(rMax - rMin);
185  } else {
186  limit = 0.5*(rMin + rMax);
187  limitErr = 0.5*(rMax - rMin);
188  }
189  double cls = getCLs(*r, limit);
190  if (cls == -999) { std::cerr << "Minimization failed in an unrecoverable way" << std::endl; break; }
191  if (cls > clsTarget) {
192  clsMax = cls;
193  rMin = limit;
194  } else {
195  clsMin = cls;
196  rMax = limit;
197  }
198  } while (limitErr > std::max(rRelAccuracy_ * limit, rAbsAccuracy_));
199 
200  return true;
201 }
202 
203 double Asymptotic::getCLs(RooRealVar &r, double rVal, bool getAlsoExpected, double *limit, double *limitErr) {
204  r.setMax(1.1 * rVal);
205  r.setConstant(true);
206 
207  CloseCoutSentry sentry(verbose < 3);
208 
211 
212  (!fitFixD_.empty() ? fitFixD_ : fitFreeD_).writeTo(*params_);
214  r.setVal(rVal);
215  r.setConstant(true);
216  if (hasFloatParams_) {
217  if (!minimD.improve(verbose-2) && picky_) return -999;
219  if (verbose >= 2) fitFixD_.Print("V");
220  }
221  double qmu = 2*(nllD_->getVal() - minNllD_); if (qmu < 0) qmu = 0;
222 
225 
226  (!fitFixA_.empty() ? fitFixA_ : fitFreeA_).writeTo(*params_);
228  r.setVal(rVal);
229  r.setConstant(true);
230  if (hasFloatParams_) {
231  if (!minimA.improve(verbose-2) && picky_) return -999;
233  if (verbose >= 2) fitFixA_.Print("V");
234  }
235  double qA = 2*(nllA_->getVal() - minNllA_); if (qA < 0) qA = 0;
236 
237  double CLsb = ROOT::Math::normal_cdf_c(sqrt(qmu));
238  double CLb = ROOT::Math::normal_cdf(sqrt(qA)-sqrt(qmu));
239  if (qtilde_ && qmu > qA) {
240  // In this region, things are tricky
241  double mos = sqrt(qA); // mu/sigma
242  CLsb = ROOT::Math::normal_cdf_c( (qmu + qA)/(2*mos) );
243  CLb = ROOT::Math::normal_cdf_c( (qmu - qA)/(2*mos) );
244  }
245  double CLs = (CLb == 0 ? 0 : CLsb/CLb);
246  sentry.clear();
247  if (verbose > 0) printf("At %s = %f:\tq_mu = %.5f\tq_A = %.5f\tCLsb = %7.5f\tCLb = %7.5f\tCLs = %7.5f\n", r.GetName(), rVal, qmu, qA, CLsb, CLb, CLs);
248 
249  if (getAlsoExpected) {
250  const double quantiles[5] = { 0.025, 0.16, 0.50, 0.84, 0.975 };
251  for (int iq = 0; iq < 5; ++iq) {
252  double N = ROOT::Math::normal_quantile(quantiles[iq], 1.0);
253  double clb = quantiles[iq];
254  double clsplusb = ROOT::Math::normal_cdf_c( sqrt(qA) - N, 1.);
255  *limit = (clb != 0 ? clsplusb/clb : 0); *limitErr = 0;
256  Combine::commitPoint(true, quantiles[iq]);
257  if (verbose > 0) printf("Expected %4.1f%%: CLsb = %.5f CLb = %.5f CLs = %.5f\n", quantiles[iq]*100, clsplusb, clb, clsplusb/clb);
258  }
259  }
260  return CLs;
261 }
262 
263 std::vector<std::pair<float,float> > Asymptotic::runLimitExpected(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint) {
264  // See equation 35-38 of AN 2011/298 and references cited therein
265  //
266  // (35) sigma^2 = mu^2 / q_mu(Asimov)
267  // (38) mu_median = sigma * normal_quantile(1-0.5*(1-cl))
268  //
269  // --> q_mu(Asimov) = pow(normal_quantile(1-0.5*(1-cl)), 2)
270  // can be solved to find mu_median
271  //
272  // --> then (38) gives sigma, and the quantiles are given by (37)
273  // mu_N = sigma * (normal_quantile(1 - quantile*(1-cl), 1.0) + normal_quantile(quantile));
274  //
275  // 1) get parameter of interest
276  RooArgSet poi(*mc_s->GetParametersOfInterest());
277  RooRealVar *r = dynamic_cast<RooRealVar *>(poi.first());
278 
279  // 2) get asimov dataset
280  RooAbsData *asimov = asimovDataset(w, mc_s, mc_b, data);
281 
282  // 2b) load asimov global observables
283  if (params_.get() == 0) params_.reset(mc_s->GetPdf()->getParameters(data));
285 
286  // 3) solve for q_mu
287  r->setConstant(false);
288  //r->setMin(0);
289  r->setMin(qtilde_ ? 0 : -r->getMax()); // FIXME TEST
290  r->setVal(0.01*r->getMax());
291  r->setError(0.1*r->getMax());
292  //r->removeMax();
293 
294  std::auto_ptr<RooAbsReal> nll(mc_s->GetPdf()->createNLL(*asimov, RooFit::Constrain(*mc_s->GetNuisanceParameters())));
296  minim.setStrategy(minimizerStrategy_);
297  minim.setErrorLevel(0.5*pow(ROOT::Math::normal_quantile(1-0.5*(1-cl),1.0), 2)); // the 0.5 is because qmu is -2*NLL
298  // eventually if cl = 0.95 this is the usual 1.92!
299  CloseCoutSentry sentry(verbose < 3);
300  minim.minimize(verbose-2);
301  sentry.clear();
302  if (verbose > 1) {
303  std::cout << "Fit to asimov dataset:" << std::endl;
304  std::auto_ptr<RooFitResult> res(minim.save());
305  res->Print("V");
306  }
307  if (r->getVal()/r->getMax() > 1e-3) {
308  if (verbose) printf("WARNING: Best fit of asimov dataset is at %s = %f (%f times %sMax), while it should be at zero\n",
309  r->GetName(), r->getVal(), r->getVal()/r->getMax(), r->GetName());
310  }
311 
312 
313  // 3) get ingredients for equation 37
314  double nll0 = nll->getVal();
315  double median = findExpectedLimitFromCrossing(*nll, r, r->getMin(), r->getMax(), nll0, 0.5);
316  double sigma = median / ROOT::Math::normal_quantile(1-0.5*(1-cl),1.0);
317  double alpha = 1-cl;
318  if (verbose > 0) {
319  std::cout << "Median for expected limits: " << median << std::endl;
320  std::cout << "Sigma for expected limits: " << sigma << std::endl;
321  }
322 
323  std::vector<std::pair<float,float> > expected;
324  const double quantiles[5] = { 0.025, 0.16, 0.50, 0.84, 0.975 };
325  for (int iq = 0; iq < 5; ++iq) {
326  double N = ROOT::Math::normal_quantile(quantiles[iq], 1.0);
327  if (newExpected_ && iq != 2) { // the median is exactly the same in the two methods
328  std::string minosAlgoBackup = minosAlgo_;
329  if (minosAlgo_ == "stepping") minosAlgo_ = "bisection";
330  switch (iq) {
331  case 0: limit = findExpectedLimitFromCrossing(*nll, r, r->getMin(), median, nll0, quantiles[iq]); break;
332  case 1: limit = findExpectedLimitFromCrossing(*nll, r, expected.back().second, median, nll0, quantiles[iq]); break;
333  case 3: limit = findExpectedLimitFromCrossing(*nll, r, expected.back().second, median+2*sigma, nll0, quantiles[iq]); break;
334  case 4: limit = findExpectedLimitFromCrossing(*nll, r, expected.back().second, median+4*sigma, nll0, quantiles[iq]); break;
335  }
336  minosAlgo_ = minosAlgoBackup;
337  if (std::isnan(limit)) { expected.clear(); break; }
338  } else {
339  limit = sigma*(ROOT::Math::normal_quantile(1 - alpha * quantiles[iq], 1.0) + N);
340  }
341  limitErr = 0;
342  Combine::commitPoint(true, quantiles[iq]);
343  expected.push_back(std::pair<float,float>(quantiles[iq], limit));
344  }
345  return expected;
346 
347 }
348 
349 float Asymptotic::findExpectedLimitFromCrossing(RooAbsReal &nll, RooRealVar *r, double rMin, double rMax, double nll0, double clb) {
350  // EQ 37 of CMS NOTE 2011-005:
351  // mu_N = sigma * ( normal_quantile_c( (1-cl) * normal_cdf(N) ) + N )
352  // --> (mu_N/sigma) = N + normal_quantile_c( (1-cl) * clb )
353  // but qmu = (mu_N/sigma)^2
354  // --> qmu = [ N + normal_quantile_c( (1-cl)*CLb ) ]^2
355  // remember that qmu = 2*nll
356  double N = ROOT::Math::normal_quantile(clb, 1.0);
357  double errorlevel = 0.5 * pow(N+ROOT::Math::normal_quantile_c(clb*(1-cl),1.0), 2);
358  int minosStat = -1;
359  if (minosAlgo_ == "minos") {
360  double rMax0 = r->getMax();
361  // Have to repeat the fit, but I'm already at the minimum
364  minim.setErrorLevel(errorlevel);
365  CloseCoutSentry sentry(verbose < 3);
366  minim.minimize(verbose-2);
367  sentry.clear();
368  for (int tries = 0; tries < 3; ++tries) {
369  minosStat = minim.minimizer().minos(RooArgSet(*r));
370  if (minosStat != -1) {
371  while ((minosStat != -1) && (r->getVal()+r->getAsymErrorHi())/r->getMax() > 0.9) {
372  if (r->getMax() >= 100*rMax0) { minosStat = -1; break; }
373  r->setMax(2*r->getMax());
376  minim2.setErrorLevel(errorlevel);
377  minim2.minimize(verbose-2);
378  minosStat = minim2.minimizer().minos(RooArgSet(*r));
379  }
380  break;
381  }
382  minim.setStrategy(2);
383  if (tries == 1) {
384  if (minimizerAlgo_.find("Minuit2") != std::string::npos) {
385  minim.minimizer().minimize("Minuit","minimize");
386  } else {
387  minim.minimizer().minimize("Minuit2","minmize");
388  }
389  }
390  }
391  if (minosStat != -1) return r->getVal()+r->getAsymErrorHi();
392  } else {
393  double threshold = nll0 + errorlevel;
394  double rCross = 0.5*(rMin+rMax), rErr = 0.5*(rMax-rMin);
395  r->setVal(rCross); r->setConstant(true);
398  if (minosAlgo_ == "bisection") {
399  if (verbose > 1) printf("Will search for NLL crossing by bisection\n");
400  while (rErr > std::max(rRelAccuracy_*rCross, rAbsAccuracy_)) {
401  if (rCross >= r->getMax()) r->setMax(rCross*1.1);
402  r->setVal(rCross);
403  bool ok = true;
404  {
405  CloseCoutSentry sentry2(verbose < 3);
406  ok = minim2.improve(verbose-2);
407  }
408  if (!ok && picky_) break; else minosStat = 0;
409  double here = nll.getVal();
410  if (verbose > 1) printf("At %s = %f:\tdelta(nll) = %.5f\n", r->GetName(), rCross, here-nll0);
411  if (fabs(here - threshold) < 0.05*minimizerTolerance_) break;
412  if (here < threshold) rMin = rCross; else rMax = rCross;
413  rCross = 0.5*(rMin+rMax); rErr = 0.5*(rMax-rMin);
414  }
415  } else if (minosAlgo_ == "stepping") {
416  if (verbose > 1) printf("Will search for NLL crossing by stepping.\n");
417  rCross = 0.05 * rMax; rErr = rMax;
418  double stride = rCross; bool overstepped = false;
419  while (rErr > std::max(rRelAccuracy_*rCross, rAbsAccuracy_)) {
420  if (rCross >= r->getMax()) r->setMax(rCross*1.1);
421  double there = nll.getVal();
422  r->setVal(rCross);
423  bool ok = true;
424  {
425  CloseCoutSentry sentry2(verbose < 3);
426  ok = minim2.improve(verbose-2);
427  }
428  if (!ok && picky_) break; else minosStat = 0;
429  double here = nll.getVal();
430  if (verbose > 1) printf("At %s = %f:\tdelta(nll) = %.5f\n", r->GetName(), rCross, here-nll0);
431  if (fabs(here - threshold) < 0.05*minimizerTolerance_) break;
432  if (here < threshold) {
433  if ((threshold-here) < 0.5*fabs(threshold-there)) stride *= 0.5;
434  rCross += stride;
435  } else {
436  stride *= 0.5; overstepped = true;
437  rCross -= stride;
438  }
439  if (overstepped) rErr = stride;
440  }
441  } else if (minosAlgo_ == "new") {
442  if (verbose > 1) printf("Will search for NLL crossing with new algorithm.\n");
443  //
444  // Let X(x,y) = (x-a*y)^2 / s^2 + y^2 be the chi-square in case of correlations
445  // then yhat(x) = a*x / (a^2 + s^2)
446  // and X(x, yhat(x)) = x^2 / (a^2 + s^2)
447  // For an unprofiled step
448  // X(x+dx, yhat(x)) - X(x,yhat(x)) = dx^2 / s^2 + 2 * x * dx / (a^2 + s^2)
449  // For a profiled step
450  // X(x+dx, yhat(x+dx)) - X(x,yhat(x)) = dx^2 / (a^2 + s^2) + 2 * x * dx / (a^2 + s^2)
451  // So,
452  // dX_prof - dX_unprof = dx^2 * a^2 / (s^2 * (a^2 + s^2) )
453  // The idea is then to take this approximation
454  // X_approx(x) = X(x, y(x1)) - k * (x-x1)^2
455  // with k = [ X(x1, y1(x0)) - X(y1, y1(x1) ] / (x1-x0)^2
456  double r_0 = rMin;
457  r->setVal(rMin);
458  double nll_0 = nll.getVal();
459  double rMax0 = rMax*100;
460  double kappa = 0;
461  // part 1: try to bracket the crossing between two points that have profiled nll above & below threshold
462  double rStep = 0.05 * (rMax - r_0);
463  double r_1 = r_0, nll_1 = nll_0;
464  do {
465  r_1 += rStep;
466  if (r_1 >= r->getMax()) r->setMax(r_1*1.1);
467  r->setVal(r_1);
468  nll_1 = nll.getVal();
469  // we profile if the NLL changed by more than 0.5, or if we got above threshold
470  bool binNLLchange = (nll_1 < threshold && nll_1 - nll_0 > 0.5);
471  bool aboveThresh = (nll_1 > threshold + kappa*std::pow(r_1-r_0,2));
472  if (binNLLchange || aboveThresh) {
473  if (verbose > 1) printf("At %s = %f:\tdelta(nll unprof) = %.5f\t \tkappa=%.5f\n", r->GetName(), r_1, nll_1-nll0, kappa);
474  {
475  CloseCoutSentry sentry2(verbose < 3);
476  bool ok = minim2.improve(verbose-2);
477  if (!ok && picky_) return std::numeric_limits<float>::quiet_NaN();
478  }
479  double nll_1_prof = nll.getVal();
480  kappa = (nll_1 - nll_1_prof) / std::pow(r_1 - r_0,2);
481  if (verbose > 1) printf("At %s = %f:\tdelta(nll unprof) = %.5f\tdelta(nll prof) = %.5f\tkappa=%.5f\n", r->GetName(), r_1, nll_1-nll0, nll.getVal()-nll0, kappa);
482  if (nll_1_prof > threshold) {
483  nll_1 = nll_1_prof;
484  break;
485  } else {
486  r_0 = r_1;
487  nll_0 = nll_1_prof;
488  if (aboveThresh) rStep *= 2;
489  }
490  } else {
491  if (verbose > 1) printf("At %s = %f:\tdelta(nll unprof) = %.5f\t \tkappa=%.5f\n", r->GetName(), r_1, nll_1-nll0, kappa);
492  }
493  if (r_1 > rMax0) return std::numeric_limits<float>::quiet_NaN();
494  } while (true);
495  // now crossing is bracketed, do bisection
496  if (verbose > 1) printf("At %s = %f:\t \tdelta(nll prof) = %.5f\tkappa=%.5f\n", r->GetName(), r_0, nll_0-nll0, kappa);
497  if (verbose > 1) printf("At %s = %f:\t \tdelta(nll prof) = %.5f\tkappa=%.5f\n", r->GetName(), r_1, nll_1-nll0, kappa);
498  minosStat = 0;
499  do {
500  // LOOP PRECONDITIONS:
501  // - r_0 and r_1 have profiled nll values on the two sides of the threshold
502  // - nuisance parameters have been profiled at r_1
503  double rEps = 0.2*std::max(rRelAccuracy_*r_1, rAbsAccuracy_);
504  // bisection loop to find point with the right nll_approx
505  double r_lo = std::min(r_0,r_1), r_hi = std::max(r_1,r_0);
506  while (r_hi - r_lo > rEps) {
507  double r_2 = 0.5*(r_hi+r_lo);
508  r->setVal(r_2);
509  double y0 = nll.getVal(), y = y0 - kappa*std::pow(r_2-r_1,2);
510  if (verbose > 1) printf("At %s = %f:\tdelta(nll unprof) = %.5f\tdelta(nll appr) = %.5f\tkappa=%.5f\n", r->GetName(), r_2, y0-nll0, y-nll0, kappa);
511  if (y < threshold) { r_lo = r_2; } else { r_hi = r_2; }
512  }
513  // profile at that point
514  rCross = r->getVal();
515  double nll_unprof = nll.getVal();
516  bool ok = true;
517  {
518  CloseCoutSentry sentry2(verbose < 3);
519  ok = minim2.improve(verbose-2);
520  }
521  if (!ok && picky_) return std::numeric_limits<float>::quiet_NaN();
522  double nll_prof = nll.getVal();
523  if (verbose > 1) printf("At %s = %f:\tdelta(nll unprof) = %.5f\tdelta(nll prof) = %.5f\tdelta(nll appr) = %.5f\n", r->GetName(), rCross, nll_unprof-nll0, nll_prof-nll0, nll_unprof-nll0 - kappa*std::pow(rCross-r_1,2));
524  if (fabs(nll_prof - threshold) < 0.1*minimizerTolerance_) { break; }
525  // not yet bang on, so update r_0, kappa
526  kappa = (nll_unprof - nll_prof)/std::pow(rCross-r_1,2);
527  // (r0 or r1) --> r0, and rCross --> r1;
528  if ((nll_prof < threshold) == (nll_0 < threshold)) { // if rCross is on the same side of r_0
529  r_0 = r_1;
530  nll_0 = nll_1;
531  } else {
532  // stay with r_0 as is
533  }
534  r_1 = rCross; nll_1 = nll_prof;
535  } while (fabs(r_1-r_0) > std::max(rRelAccuracy_*rCross, rAbsAccuracy_));
536  }
537  if (minosStat != -1) return rCross;
538  }
539  return std::numeric_limits<float>::quiet_NaN();
540 }
541 
542 RooAbsData * Asymptotic::asimovDataset(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data) {
543  // Do this only once
544  if (w->data("_Asymptotic_asimovDataset_") != 0) {
545  return w->data("_Asymptotic_asimovDataset_");
546  }
547  // snapshot data global observables
548  RooArgSet gobs;
549  if (withSystematics && mc_s->GetGlobalObservables()) {
550  gobs.add(*mc_s->GetGlobalObservables());
551  snapGlobalObsData.removeAll();
552  utils::setAllConstant(gobs, true);
553  gobs.snapshot(snapGlobalObsData);
554  }
555  // get asimov dataset and global observables
556  RooAbsData *asimovData = (noFitAsimov_ ? asimovutils::asimovDatasetNominal(mc_s, 0.0, verbose) :
558  asimovData->SetName("_Asymptotic_asimovDataset_");
559  w->import(*asimovData); // I'm assuming the Workspace takes ownership. Might be false.
560  delete asimovData; // ^^^^^^^^----- now assuming that the workspace clones.
561  return w->data("_Asymptotic_asimovDataset_");
562 }
#define DEBUG
float alpha
Definition: AMPTWrapper.h:95
std::auto_ptr< RooArgSet > params_
Definition: Asymptotic.h:47
double minNllD_
Definition: Asymptotic.h:53
static std::string minimizerAlgo_
Definition: Asymptotic.h:40
static std::string minosAlgo_
Definition: Asymptotic.h:39
bool setAllConstant(const RooAbsCollection &coll, bool constant=true)
set all RooRealVars to constants. return true if at least one changed status
Definition: utils.cc:248
static bool newExpected_
Definition: Asymptotic.h:38
RooArgSet snapGlobalObsAsimov
Definition: Asymptotic.h:54
static int minimizerStrategy_
Definition: Asymptotic.h:42
float findExpectedLimitFromCrossing(RooAbsReal &nll, RooRealVar *r, double rMin, double rMax, double nll0, double quantile)
Definition: Asymptotic.cc:349
virtual bool run(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
Definition: Asymptotic.cc:74
bool minimize(int verbose=0, bool cascade=true)
static float minimizerTolerance_
Definition: Asymptotic.h:41
static const int WARNING
bool withSystematics
Definition: Combine.cc:68
void writeTo(const RooAbsCollection &) const
Definition: utils.cc:461
#define min(a, b)
Definition: mlp_lapack.h:161
bool improve(int verbose=0, bool cascade=true)
utils::CheapValueSnapshot fitFixD_
Definition: Asymptotic.h:51
virtual void applyOptions(const boost::program_options::variables_map &vm)
Definition: Asymptotic.cc:55
RooAbsData * asimovDatasetWithFit(RooStats::ModelConfig *mc, RooAbsData &realdata, RooAbsCollection &snapshot, double poiValue=0.0, int verbose=0)
Generate asimov dataset from best fit value of nuisance parameters, and fill in snapshot of correspon...
Definition: AsimovUtils.cc:26
utils::CheapValueSnapshot fitFixA_
Definition: Asymptotic.h:51
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 ...
Definition: Combine.cc:557
static bool noFitAsimov_
Definition: Asymptotic.h:37
std::auto_ptr< RooAbsReal > nllA_
Definition: Asymptotic.h:48
const T & max(const T &a, const T &b)
bool isnan(float x)
Definition: math.h:13
static double rRelAccuracy_
Definition: Asymptotic.h:33
T sqrt(T t)
Definition: SSEVec.h:46
static double rValue_
Definition: Asymptotic.h:44
RooAbsData * asimovDataset(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data)
Definition: Asymptotic.cc:542
static bool qtilde_
Definition: Asymptotic.h:35
static double rAbsAccuracy_
Definition: Asymptotic.h:33
virtual void applyDefaultOptions()
Definition: Asymptotic.cc:70
float cl
Definition: Combine.cc:71
static bool picky_
Definition: Asymptotic.h:36
void readFrom(const RooAbsCollection &)
Definition: utils.cc:448
#define N
Definition: blowfish.cc:9
static std::string what_
Definition: Asymptotic.h:34
utils::CheapValueSnapshot fitFreeA_
Definition: Asymptotic.h:51
Setup Minimizer configuration on creation, reset the previous one on destruction. ...
RooAbsData * asimovDatasetNominal(RooStats::ModelConfig *mc, double poiValue=0.0, int verbose=0)
Generate asimov dataset from nominal value of nuisance parameters.
Definition: AsimovUtils.cc:15
std::auto_ptr< RooAbsReal > nllD_
Definition: Asymptotic.h:48
RooMinimizerOpt & minimizer()
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
bool hasFloatParams_
Definition: Asymptotic.h:46
double a
Definition: hdecay.h:121
virtual bool runLimit(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
Definition: Asymptotic.cc:103
utils::CheapValueSnapshot fitFreeD_
Definition: Asymptotic.h:51
void Print(const char *fmt) const
Definition: utils.cc:478
tuple cout
Definition: gather_cfg.py:121
double minNllA_
Definition: Asymptotic.h:53
boost::program_options::options_description options_
Definition: LimitAlgo.h:31
void setErrorLevel(float errorLevel)
RooArgSet snapGlobalObsData
Definition: Asymptotic.h:54
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
void setStrategy(int strategy)
bool empty() const
Definition: utils.h:80
std::vector< std::pair< float, float > > runLimitExpected(RooWorkspace *w, RooStats::ModelConfig *mc_s, RooStats::ModelConfig *mc_b, RooAbsData &data, double &limit, double &limitErr, const double *hint)
Definition: Asymptotic.cc:263
T w() const
double getCLs(RooRealVar &r, double rVal, bool getAlsoExpected=false, double *limit=0, double *limitErr=0)
Definition: Asymptotic.cc:203