ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/algomez/Stops/BATLimits/fit.cc
Revision: 1.1
Committed: Thu Sep 5 03:58:16 2013 UTC (11 years, 8 months ago) by algomez
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Log Message:
First version

File Contents

# Content
1 #include <cassert>
2 #include <sstream>
3 #include <cmath>
4 #include <limits>
5
6 #include <TF1.h>
7 #include <TMath.h>
8 #include <TH1D.h>
9 #include <TGraph.h>
10
11 #include "fit.hh"
12 #include "binneddata.hh"
13 #include "statistics.hh"
14
15 Fitter* Fitter::theFitter_;
16
17 // ---------------------------------------------------------
18 Fitter::Fitter()
19 {
20 data_=0;
21 functionIntegral_=0;
22 printlevel_=3;
23 strategy_=2;
24 minuit_.SetErrorDef(0.5); // likelihood
25 rand_=new TRandom3(31415);
26 parameters_=0;
27 poiIndex_=-1;
28 callLimitReached_=false;
29 poiBestFit_ = 0;
30 poiUserError_ = 0;
31 parRangeSet_=false;
32 }
33
34 // ---------------------------------------------------------
35 Fitter::Fitter(TH1D* data, integral_ptr_t functionIntegral, int maxpar) :
36 minuit_(maxpar)
37 {
38 data_=data;
39 functionIntegral_=functionIntegral;
40 printlevel_=3;
41 strategy_=2;
42 minuit_.SetErrorDef(0.5); // likelihood
43 rand_=new TRandom3(31415);
44 parameters_=0;
45 poiIndex_=-1;
46 callLimitReached_=false;
47 poiBestFit_ = 0;
48 poiUserError_ = 0;
49 parRangeSet_=false;
50 }
51
52 // ---------------------------------------------------------
53 Fitter::~Fitter()
54 {
55 if(parameters_) delete[] parameters_;
56
57 delete rand_;
58
59 // remove nuisance parameter priors
60 for(std::map<int, RandomPrior*>::const_iterator it=priors_.begin(); it!=priors_.end(); ++it) delete it->second;
61 }
62
63 // ---------------------------------------------------------
64 void Fitter::doFit(void)
65 {
66 // setup the fitter so the information can be retrieved by nll
67 Fitter::theFitter_=this;
68
69 // setup TMinuit
70 minuit_.SetPrintLevel(printlevel_); // printlevel = -1 quiet (also suppresse all warnings), = 0 normal, = 1 verbose
71
72 // set the strategy
73 std::ostringstream command;
74 command << "SET STR " << strategy_;
75 minuit_.Command(command.str().c_str());
76
77 // do the fit
78 minuit_.SetFCN(nll);
79 Double_t arglist[1] = {20000.0};
80 Int_t err = 0;
81 minuit_.mnexcm("MIGRAD",arglist,1,err); /// MIGRAD: Causes minimization of the function by the method of Migrad, the most efficient and complete single method, recommended for general functions (see also MINImize). The minimization produces as a by-product the error matrix of the parameters, which is usually reliable unless warning messages are produced. The optional argument [maxcalls] specifies the (approximate) maximum number of function calls after which the calculation will be stopped even if it has not yet converged. The optional argument [tolerance] specifies required tolerance on the function value at the minimum. The default tolerance is 0.1, and the minimization will stop when the estimated vertical distance to the minimum (EDM) is less than 0.001*[tolerance]*UP (see SET ERR).
82
83 return;
84 }
85
86 // ---------------------------------------------------------
87 void Fitter::doFit(double* emat, int ndim)
88 {
89 // setup the fitter so the information can be retrieved by nll
90 Fitter::theFitter_=this;
91
92 // setup TMinuit
93 minuit_.SetPrintLevel(printlevel_);
94
95 // set the strategy
96 std::ostringstream command;
97 command << "SET STR " << strategy_;
98 minuit_.Command(command.str().c_str());
99
100 // do the fit
101 minuit_.SetFCN(nll);
102 Double_t arglist[1] = {20000.0};
103 Int_t err = 0;
104 minuit_.mnexcm("MIGRAD",arglist,1,err);
105 minuit_.mnemat(emat, ndim);
106
107 return;
108 }
109
110 // ---------------------------------------------------------
111 TH1D* Fitter::calcPull(const char* name)
112 {
113 const double alpha = 1 - 0.6827;
114
115 TH1D* hPull=dynamic_cast<TH1D*>(data_->Clone(name));
116 hPull->SetTitle("Pull Distribution");
117
118 hPull->SetBinContent(0, 0.);
119 hPull->SetBinContent(hPull->GetNbinsX()+1, 0.);
120 hPull->SetBinError(0, 0.);
121 hPull->SetBinError(hPull->GetNbinsX()+1, 0.);
122 for(int bin=1; bin<=data_->GetNbinsX(); bin++) {
123 double binwidth=data_->GetBinWidth(bin);
124 double N=data_->GetBinContent(bin)*binwidth;
125 double l = 0.5*TMath::ChisquareQuantile(alpha/2,2*N);
126 double h = 0.5*TMath::ChisquareQuantile(1-alpha/2,2*(N+1));
127 double el = N-l;
128 double eh = h-N;
129
130 double x0=data_->GetBinLowEdge(bin);
131 double xf=data_->GetBinLowEdge(bin+1);
132 double mu=functionIntegral_(&x0, &xf, getParameters());
133
134 double err = (el + eh)/2.;
135 if(N>=mu) err = el;
136 if(N<mu) err = eh;
137
138 double pull=(N-mu)/err;
139 hPull->SetBinContent(bin, pull);
140 hPull->SetBinError(bin, 1.0);
141 }
142 return hPull;
143 }
144
145 // ---------------------------------------------------------
146 TH1D* Fitter::calcDiff(const char* name)
147 {
148 TH1D* hDiff=dynamic_cast<TH1D*>(data_->Clone(name));
149 hDiff->SetTitle("Difference Distribution");
150
151 hDiff->SetBinContent(0, 0.);
152 hDiff->SetBinContent(hDiff->GetNbinsX()+1, 0.);
153 hDiff->SetBinError(0, 0.);
154 hDiff->SetBinError(hDiff->GetNbinsX()+1, 0.);
155 for(int bin=1; bin<=data_->GetNbinsX(); bin++) {
156 double binwidth=data_->GetBinWidth(bin);
157 double N=data_->GetBinContent(bin)*binwidth;
158 double err=Fitter::histError(N);
159
160 double x0=data_->GetBinLowEdge(bin);
161 double xf=data_->GetBinLowEdge(bin+1);
162 double mu=functionIntegral_(&x0, &xf, getParameters());
163
164 double diff=(N-mu)/mu;
165 hDiff->SetBinContent(bin, diff);
166 hDiff->SetBinError(bin, err/mu);
167 }
168 return hDiff;
169 }
170
171 // ---------------------------------------------------------
172 int Fitter::setParameter(int parno, double value)
173 {
174 int err;
175 double tmp[2];
176 tmp[0]=parno+1;
177 tmp[1]=value;
178
179 minuit_.mnexcm("SET PAR", tmp, 2, err);
180 return err;
181 }
182
183 // ---------------------------------------------------------
184 int Fitter::setParLimits(int parno, double loLimit, double hiLimit)
185 {
186 int err;
187 double tmp[3];
188 tmp[0]=parno+1;
189 tmp[1]=loLimit;
190 tmp[2]=hiLimit;
191
192 minuit_.mnexcm("SET LIM", tmp, 3, err);
193 return err;
194 }
195
196 // ---------------------------------------------------------
197 double Fitter::getParameter(int parno) const
198 {
199 double val, err;
200 getParameter(parno, val, err);
201 return val;
202 }
203
204 // ---------------------------------------------------------
205 double Fitter::getParError(int parno) const
206 {
207 double val, err;
208 getParameter(parno, val, err);
209 return err;
210 }
211
212 // ---------------------------------------------------------
213 void Fitter::getParLimits(int parno, double &loLimit, double &hiLimit) const
214 {
215 TString _name;
216 double _val, _err;
217 int _iuint;
218 minuit_.mnpout(parno, _name, _val, _err, loLimit, hiLimit, _iuint);
219 return;
220 }
221
222 // ---------------------------------------------------------
223 double* Fitter::getParameters(void)
224 {
225 // remove what is there
226 if(parameters_) delete[] parameters_;
227
228 int nPars=minuit_.GetNumPars();
229 parameters_ = new double[nPars];
230 for(int i=0; i<nPars; i++) {
231 double value, err;
232 getParameter(i, value, err);
233 parameters_[i]=value;
234 }
235
236 return parameters_;
237 }
238
239 // ---------------------------------------------------------
240 int Fitter::defineParameter(int parno, const char *name, double value, double error, double lo, double hi, int isNuisance)
241 {
242 parameterIsNuisance_[parno]=isNuisance;
243 if(poiIndex_>=0 && parno==poiIndex_)
244 if(poiUserError_==0.) poiUserError_=error;
245 return minuit_.DefineParameter(parno, name, value, error, lo, hi);
246 }
247
248 // ---------------------------------------------------------
249 TGraph* Fitter::calculatePosterior(int nSamples)
250 {
251 // we need a parameter of index defined
252 assert(poiIndex_>=0);
253
254 // set the number of samples for subsequent functions
255 nSamples_=nSamples;
256 nCalls_=0;
257
258 // fit for the best value of the POI
259 int nPars=getNumPars();
260 double loLimit, hiLimit;
261 getParLimits(poiIndex_, loLimit, hiLimit);
262 for(int i=0; i<nPars; i++) if(i==poiIndex_) floatParameter(i); else fixParameter(i);
263 setParameter(poiIndex_, 0.1*(loLimit+hiLimit));
264 doFit();
265 fixParameter(poiIndex_);
266 poiBestFit_=getParameter(poiIndex_);
267
268 // setup Fitter
269 Fitter::theFitter_=this;
270
271 // now float all parameters
272 for(int i=0; i<nPars; i++) if(i!=poiIndex_) floatParameter(i);
273
274 // evalulate NLL at the POI fit value for future normalizations
275 double nllNormalization=evalNLL();
276
277 // recursively evaluate the posterior
278 std::map<double, double> fcnEvaluations;
279 evaluateForPosterior(loLimit, poiBestFit_, hiLimit, nllNormalization, fcnEvaluations);
280
281 // dump the info into a graph
282 int cntr=0;
283 double maximumVal=-9999.;
284 TGraph* graph=new TGraph(fcnEvaluations.size());
285 for(std::map<double, double>::const_iterator it=fcnEvaluations.begin(); it!=fcnEvaluations.end(); ++it) {
286 graph->SetPoint(cntr++, it->first, it->second);
287 if(it->second>maximumVal) maximumVal=it->second;
288 }
289
290 // identify trivially small points on the left
291 std::vector<int> pointsToRemove;
292 // for(int i=0; i<graph->GetN()-1; i++) {
293 // double x, y, nextx, nexty;
294 // graph->GetPoint(i, x, y);
295 // graph->GetPoint(i+1, nextx, nexty);
296 //
297 // if(y/maximumVal<1.E-3 && nexty/maximumVal<1.E-3) pointsToRemove.push_back(i);
298 // else break;
299 // }
300
301 // identify trivially small points on the right
302 for(int i=graph->GetN()-1; i>=1; i--) {
303 double x, y, nextx, nexty;
304 graph->GetPoint(i, x, y);
305 graph->GetPoint(i-1, nextx, nexty);
306
307 if(y/maximumVal<1.E-3 && nexty/maximumVal<1.E-3) pointsToRemove.push_back(i);
308 else break;
309 }
310
311 // sort the points to remove from first to last
312 std::sort(pointsToRemove.begin(), pointsToRemove.end());
313
314 // remove the points
315 for(int i=pointsToRemove.size()-1; i>=0; i--)
316 graph->RemovePoint(pointsToRemove[i]);
317
318 return graph;
319 }
320
321 // ---------------------------------------------------------
322 double Fitter::evalNLL(void)
323 {
324 Fitter::theFitter_=this;
325 int a;
326 double f;
327 nll(a, 0, f, getParameters(), 0);
328 return f;
329 }
330
331 // ---------------------------------------------------------
332 double Fitter::histError(double val)
333 {
334 const double alpha = 1 - 0.6827;
335
336 if(val<25. && val>0.) return (0.5*TMath::ChisquareQuantile(1-alpha/2,2*(val+1))-0.5*TMath::ChisquareQuantile(alpha/2,2*val))/2.0; // this is not exactly correct since it symmetrizes what are otherwise asymmetric error bars
337 else if(val==0.) return 0.5*TMath::ChisquareQuantile(1-alpha/2,2*(val+1)); // special case of 0 events with one-sided error bar
338 else return sqrt(val); // for val>25 error bars with correct coverage are essentially symmetric
339 }
340
341 // ---------------------------------------------------------
342 void Fitter::nll(int &, double *, double &f, double *par, int)
343 {
344 assert(Fitter::theFitter_);
345 TH1D* data=Fitter::theFitter_->data_;
346 integral_ptr_t functionIntegral=Fitter::theFitter_->functionIntegral_;
347
348 f=0.0;
349 for(int bin=1; bin<=data->GetNbinsX(); bin++) {
350 double binwidth=data->GetBinWidth(bin);
351 double N=data->GetBinContent(bin)*binwidth;
352
353 double x0=data->GetBinLowEdge(bin);
354 double xf=data->GetBinLowEdge(bin+1);
355 double mu=functionIntegral(&x0, &xf, par);
356
357 if(N==0.0) f += mu;
358 else f -= (N*TMath::Log(mu) - TMath::LnGamma(N+1) - mu);
359 }
360 return;
361 }
362
363 // ---------------------------------------------------------
364 TH1D* Fitter::makePseudoData(const char* name, double* parameters)
365 {
366 if(!parameters) parameters=getParameters();
367
368 // start with a copy of the original dataset
369 TH1D* hData=dynamic_cast<TH1D*>(data_->Clone(name));
370
371 for(int bin=1; bin<=hData->GetNbinsX(); ++bin) {
372 double lobin=hData->GetBinLowEdge(bin);
373 double hibin=hData->GetBinLowEdge(bin+1);
374 double integral=functionIntegral_(&lobin, &hibin, parameters);
375 double val=rand_->Poisson(integral);
376 double binWidth=hData->GetBinWidth(bin);
377 hData->SetBinContent(bin, val/binWidth);
378 hData->SetBinError(bin, histError(val)/binWidth);
379 }
380 return hData;
381 }
382
383 // ---------------------------------------------------------
384 void Fitter::evaluateForPosterior(double lo, double mid, double hi, double nllNormalization, std::map<double, double>& fcnEval_)
385 {
386 if((nCalls_++)>1000) {
387 callLimitReached_=true;
388 return;
389 }
390
391 // get the low value
392 std::map<double, double>::iterator findit;
393 findit = fcnEval_.find(lo);
394 double loVal;
395 if(findit==fcnEval_.end()) {
396 loVal=computeLikelihoodWithSystematics(lo, nllNormalization);
397 fcnEval_[lo]=loVal;
398 } else {
399 loVal=fcnEval_[lo];
400 }
401
402 // get the middle value
403 findit = fcnEval_.find(mid);
404 double midVal;
405 if(findit==fcnEval_.end()) {
406 midVal=computeLikelihoodWithSystematics(mid, nllNormalization);
407 fcnEval_[mid]=midVal;
408 } else {
409 midVal=fcnEval_[mid];
410 }
411
412 // get the high value
413 findit = fcnEval_.find(hi);
414 double hiVal;
415 if(findit==fcnEval_.end()) {
416 hiVal=computeLikelihoodWithSystematics(hi, nllNormalization);
417 fcnEval_[hi]=hiVal;
418 } else {
419 hiVal=fcnEval_[hi];
420 }
421
422 //double maximumValX = 0.;
423 double maximumVal = -999.;
424 for(std::map<double, double>::const_iterator it=fcnEval_.begin(); it!=fcnEval_.end(); ++it)
425 if(maximumVal<it->second)
426 {
427 //maximumValX=it->first;
428 maximumVal=it->second;
429 }
430
431 // for debugging
432 //std::cout << "nCalls: " << nCalls_ << std::endl
433 // << "nllNormalization: " << nllNormalization << std::endl
434 // << "lo, mid, high: " << lo << ", " << mid << ", " << hi << std::endl
435 // << "loval, midval, hival: " << loVal << ", " << midVal << ", " << hiVal << std::endl
436 // << "maximumValX, maximumVal: " << maximumValX << ", " << maximumVal << std::endl << std::endl;
437
438 if(fabs(loVal-midVal)>0.04*maximumVal || fabs(hiVal-midVal)>0.04*maximumVal) {
439 if(fabs(hi-mid)/fabs(hi)>0.01 && fabs(hi-mid)/fabs(poiBestFit_)>0.01 && fabs(hi-mid)>poiUserError_) evaluateForPosterior(mid, 0.5*(mid+hi), hi, nllNormalization, fcnEval_); // important to go to the mid-high range first to get a nicely falling posterior tail in case the number of calls limit is reached
440 if(fabs(lo-mid)/fabs(mid)>0.01 && fabs(lo-mid)/fabs(poiBestFit_)>0.01 && fabs(lo-mid)>poiUserError_) evaluateForPosterior(lo, 0.5*(lo+mid), mid, nllNormalization, fcnEval_);
441 }
442
443 return;
444 }
445
446 // ---------------------------------------------------------
447 double Fitter::computeLikelihoodWithSystematics(double poiVal, double nllNormalization)
448 {
449 // setup parameters
450 int a;
451 double f;
452 double *pars=getParameters();
453 pars[poiIndex_]=poiVal;
454
455 // no systematics
456 if(nSamples_==0) {
457 nll(a, 0, f, pars, 0);
458 return TMath::Exp(-f+nllNormalization);
459 }
460
461 // setup nuisance parameter priors
462 if( priors_.size()==0 && parameterIsNuisance_.size()>0 )
463 {
464 for(std::map<int, int>::const_iterator it=parameterIsNuisance_.begin(); it!=parameterIsNuisance_.end(); ++it)
465 {
466 if(it->second>0) {
467 assert(it->first!=poiIndex_);
468 double parval, parerr;
469 double lolim, uplim;
470 // find the optimal integration range for nuisance parameters with uniform priors
471 if(it->second>=4 && !parRangeSet_)
472 {
473 getParameter(it->first, parval, parerr);
474 getParLimits(it->first, lolim, uplim);
475 double tempval=parval, tempuplim=parval, templolim=parval;
476 bool uplimFound=false, lolimFound=false;
477 pars[poiIndex_]=poiBestFit_; // here we need to use the best-fit value in order to probe the posterior likelihood close to its maximum
478
479 while(tempval<=uplim)
480 {
481 pars[it->first]=tempval;
482 nll(a,0,f,pars,0);
483 if(TMath::Exp(-f+nllNormalization)<1.E-3)
484 {
485 tempuplim=tempval+1.0*(tempval-parval);
486 uplimFound=true;
487 break;
488 }
489 tempval=tempval+parerr;
490 }
491 tempval=parval;
492 while(tempval>=lolim)
493 {
494 pars[it->first]=tempval;
495 nll(a,0,f,pars,0);
496 if(TMath::Exp(-f+nllNormalization)<1.E-3)
497 {
498 templolim=tempval-1.0*(parval-tempval);
499 lolimFound=true;
500 break;
501 }
502 tempval=tempval-parerr;
503 }
504
505 if((!uplimFound || tempuplim>uplim) || (!lolimFound || templolim<lolim))
506 {
507 std::cout << "WARNING! The integration range for parameter " << (it->first+1) << " [" << lolim << ", " << uplim << "] is likely too narrow. Please extend the range." << std::endl;
508 priors_[it->first]=new RandomPrior(it->second, parval, parerr, lolim, uplim);
509 }
510 else
511 {
512 double maxdiff = std::max(tempuplim-parval,parval-templolim);
513 templolim = parval - maxdiff;
514 tempuplim = parval + maxdiff;
515 std::cout << "The integration range for parameter " << (it->first+1) << " set to [" << templolim << ", " << tempuplim << "]" << std::endl;
516 setParLimits(it->first, templolim, tempuplim);
517 priors_[it->first]=new RandomPrior(it->second, parval, parerr, templolim, tempuplim);
518 }
519
520 // return the parameters to their original values
521 pars[it->first]=parval;
522 pars[poiIndex_]=poiVal;
523 }
524 else
525 {
526 getParameter(it->first, parval, parerr);
527 getParLimits(it->first, lolim, uplim);
528 priors_[it->first]=new RandomPrior(it->second, parval, parerr, lolim, uplim);
529 }
530 }
531 }
532 }
533 if(!parRangeSet_) parRangeSet_=true;
534
535 // calculate average likelihood value over nuisance parameters
536 double total=0.0;
537 for(int sample=0; sample<=nSamples_; sample++) {
538 for(std::map<int, RandomPrior*>::const_iterator it=priors_.begin(); it!=priors_.end(); ++it)
539 pars[it->first]=it->second->getRandom();
540 nll(a,0,f,pars,0);
541 double like=TMath::Exp(-f+nllNormalization);
542
543 total+=like;
544 }
545
546 return total/nSamples_;
547 }
548
549 // ---------------------------------------------------------
550 double Fitter::calculateUpperBoundWithCLs(int nSamples, double alpha)
551 {
552 // we need a parameter of index defined
553 assert(poiIndex_>=0);
554
555 // set the number of samples for subsequent functions
556 nSamples_=nSamples;
557
558 // fit for the best value of the POI
559 int nPars=getNumPars();
560 double loLimit, hiLimit;
561 getParLimits(poiIndex_, loLimit, hiLimit);
562 for(int i=0; i<nPars; i++) if(i==poiIndex_) floatParameter(i); else fixParameter(i);
563 setParameter(poiIndex_, 0.1*(loLimit+hiLimit));
564 doFit();
565 double poiBestFit=getParameter(poiIndex_);
566 double poiBestFitErr=getParError(poiIndex_);
567 fixParameter(poiIndex_);
568
569 // now float all parameters
570 for(int i=0; i<nPars; i++) if(i!=poiIndex_) floatParameter(i);
571
572 // scan the CLs in steps of error, first
573 double poiVal;
574 double prevPoiVal=0.0;
575 double prevCLsVal=nSamples;
576 double CLsVal=0.0;
577 for(poiVal=poiBestFit; poiVal<hiLimit; poiVal+=poiBestFitErr) {
578
579 // calculate CLs
580 std::vector<double> CLb, CLsb;
581 std::pair<int, int> numden=calculateCLs_(poiVal, CLb, CLsb);
582 double A=static_cast<double>(numden.first)/nSamples;
583 double B=static_cast<double>(numden.second)/nSamples;
584 double Aerr=sqrt(A*(1-A)/nSamples);
585 double Berr=sqrt(B*(1-B)/nSamples);
586 CLsVal = B==0 ? nSamples*2 : A/B;
587 double CLsErr = Aerr==0 || Berr==0 ? 0. : CLsVal*sqrt(Aerr*Aerr/A/A+Berr*Berr/B/B);
588 double diff=fabs(CLsVal-alpha);
589
590 std::cout << "Scan: CLsVal=" << CLsVal << "; poiVal=" << poiVal << std::endl;
591
592 if(diff<CLsErr) return poiVal;
593
594 if((prevCLsVal>=alpha && CLsVal<=alpha) || (prevCLsVal<=alpha && CLsVal>=alpha)) break;
595
596 prevPoiVal=poiVal;
597 prevCLsVal=CLsVal;
598 }
599 if(poiVal>=hiLimit) return -999.;
600
601 // now, try to converge on best CLs point
602 double poiValLo=prevPoiVal;
603 double poiValHi=poiVal;
604 double CLsValLo=prevCLsVal;
605 double CLsValHi=CLsVal;
606 int cntr=0;
607 do {
608 poiVal=(alpha-CLsValLo)*(poiValHi-poiValLo)/(CLsValHi-CLsValLo)+poiValLo;
609 std::vector<double> CLb, CLsb;
610 std::pair<int, int> numden=calculateCLs_(poiVal, CLb, CLsb);
611 double A=static_cast<double>(numden.first)/nSamples;
612 double B=static_cast<double>(numden.second)/nSamples;
613 double Aerr=sqrt(A*(1-A)/nSamples);
614 double Berr=sqrt(B*(1-B)/nSamples);
615 double CLsVal = B==0 ? nSamples*2 : A/B;
616 double CLsErr = Aerr==0 || Berr==0 ? 0. : CLsVal*sqrt(Aerr*Aerr/A/A+Berr*Berr/B/B);
617 double diff=fabs(CLsVal-alpha);
618
619 std::cout << "poiVal=" << poiVal << "; poiValLo=" << poiValLo << "; poiValHi=" << poiValHi
620 << "; CLsVal=" << CLsVal << "; CLsErr=" << CLsErr << "; CLSValLo=" << CLsValLo << "; CLsValHi=" << CLsValHi << std::endl;
621 std::cout << "A=" << A << "; Aerr=" << Aerr
622 <<"; B=" << B << "; Berr=" << Berr << std::endl;
623
624 if(diff>CLsErr) {
625 if(alpha>CLsVal) {
626 poiValHi=poiVal;
627 CLsValHi=CLsVal;
628 } else {
629 poiValLo=poiVal;
630 CLsValLo=CLsVal;
631 }
632 } else {
633 break;
634 }
635
636 }while(cntr<100);
637
638 return poiVal;
639 }
640
641 // ---------------------------------------------------------
642 std::pair<int, int> Fitter::calculateCLs_(double poiVal, std::vector<double>& CLb, std::vector<double>& CLsb)
643 {
644 // setup parameters
645 int a;
646 double f;
647 double *pars=getParameters();
648
649 // setup nuisance parameter priors
650 if( priors_.size()==0 && parameterIsNuisance_.size()>0 )
651 {
652 for(std::map<int, int>::const_iterator it=parameterIsNuisance_.begin(); it!=parameterIsNuisance_.end(); ++it)
653 {
654 if(it->second>0) {
655 assert(it->first!=poiIndex_);
656 double parval, parerr;
657 double lolim, uplim;
658 getParameter(it->first, parval, parerr);
659 getParLimits(it->first, lolim, uplim);
660 priors_[it->first]=new RandomPrior(it->second, parval, parerr, lolim, uplim);
661 }
662 }
663 }
664
665 TH1D* theData=data_;
666
667 for(int i=0; i<nSamples_; i++) {
668
669 // create the pseudodata
670 TH1D* CLSB_pdata;
671 TH1D* CLB_pdata;
672 if(i>0) {
673 for(std::map<int, RandomPrior*>::const_iterator it=priors_.begin(); it!=priors_.end(); ++it)
674 pars[it->first]=it->second->getRandom();
675
676 pars[poiIndex_]=poiVal;
677 data_=theData;
678 CLSB_pdata=makePseudoData("CLSB_pdata", pars);
679 pars[poiIndex_]=0.0;
680 CLB_pdata=makePseudoData("CLB_pdata", pars);
681 } else {
682 CLSB_pdata=theData;
683 CLB_pdata=theData;
684 }
685
686 // CL_{s+b}
687 data_=CLSB_pdata;
688 pars[poiIndex_]=poiVal;
689 nll(a, 0, f, pars, 0);
690 double llnum=f;
691 pars[poiIndex_]=0.0;
692 nll(a, 0, f, pars, 0);
693 double llden=f;
694 CLsb.push_back(2*llnum-2*llden);
695
696 // CL_{b}
697 data_=CLB_pdata;
698 pars[poiIndex_]=poiVal;
699 nll(a, 0, f, pars, 0);
700 llnum=f;
701 pars[poiIndex_]=0.0;
702 nll(a, 0, f, pars, 0);
703 llden=f;
704 CLb.push_back(2*llnum-2*llden);
705
706 // remove the pseudodata
707 if(i>0) {
708 delete CLSB_pdata;
709 delete CLB_pdata;
710 }
711 }
712
713 // set the data back
714 data_=theData;
715
716 // calculate the CLs
717 int nNum=0, nDen=0;
718 for(unsigned int i=1; i<CLb.size(); i++) {
719
720 bool numPass=(CLsb[i]>=CLsb[0]);
721 bool denPass=(CLb[i]>CLb[0]);
722
723 nNum+=numPass;
724 nDen+=denPass;
725 }
726 return std::pair<int, int>(nNum, nDen);
727 }