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

# User Rev Content
1 algomez 1.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     }