44 ClassImp(RooStats::HypoTestInverterResult);
46 using namespace RooStats;
47 using namespace RooFit;
52 double HypoTestInverterResult::fgAsymptoticMaxSigma = 5;
53 int HypoTestInverterResult::fgAsymptoticNumPoints = 11;
58 HypoTestInverterResult::HypoTestInverterResult(
const char * name ) :
62 fInterpolateLowerLimit(true),
63 fInterpolateUpperLimit(true),
64 fFittedLowerLimit(false),
65 fFittedUpperLimit(false),
66 fInterpolOption(kLinear),
69 fCLsCleanupThreshold(0.005)
71 fLowerLimit = TMath::QuietNaN();
72 fUpperLimit = TMath::QuietNaN();
75 fExpPValues.SetOwner();
81 HypoTestInverterResult::HypoTestInverterResult(
const HypoTestInverterResult& other,
const char * name ) :
82 SimpleInterval(other,name),
83 fUseCLs(other.fUseCLs),
84 fIsTwoSided(other.fIsTwoSided),
85 fInterpolateLowerLimit(other.fInterpolateLowerLimit),
86 fInterpolateUpperLimit(other.fInterpolateUpperLimit),
87 fFittedLowerLimit(other.fFittedLowerLimit),
88 fFittedUpperLimit(other.fFittedUpperLimit),
89 fInterpolOption(other.fInterpolOption),
90 fLowerLimitError(other.fLowerLimitError),
91 fUpperLimitError(other.fUpperLimitError),
92 fCLsCleanupThreshold(other.fCLsCleanupThreshold)
94 fLowerLimit = TMath::QuietNaN();
95 fUpperLimit = TMath::QuietNaN();
96 int nOther = other.ArraySize();
98 fXValues = other.fXValues;
99 for (
int i = 0; i < nOther; ++i)
100 fYObjects.Add( other.fYObjects.At(i)->Clone() );
101 for (
int i = 0; i < fExpPValues.GetSize() ; ++i)
102 fExpPValues.Add( other.fExpPValues.At(i)->Clone() );
104 fYObjects.SetOwner();
105 fExpPValues.SetOwner();
110 HypoTestInverterResult&
111 HypoTestInverterResult::operator=(
const HypoTestInverterResult& other)
117 SimpleInterval::operator = (other);
118 fLowerLimit = other.fLowerLimit;
119 fUpperLimit = other.fUpperLimit;
120 fUseCLs = other.fUseCLs;
121 fIsTwoSided = other.fIsTwoSided;
122 fInterpolateLowerLimit = other.fInterpolateLowerLimit;
123 fInterpolateUpperLimit = other.fInterpolateUpperLimit;
124 fFittedLowerLimit = other.fFittedLowerLimit;
125 fFittedUpperLimit = other.fFittedUpperLimit;
126 fInterpolOption = other.fInterpolOption;
127 fLowerLimitError = other.fLowerLimitError;
128 fUpperLimitError = other.fUpperLimitError;
129 fCLsCleanupThreshold = other.fCLsCleanupThreshold;
131 int nOther = other.ArraySize();
132 fXValues = other.fXValues;
134 fYObjects.RemoveAll();
135 for (
int i=0; i < nOther; ++i) {
136 fYObjects.Add( other.fYObjects.At(i)->Clone() );
138 fExpPValues.RemoveAll();
139 for (
int i=0; i < fExpPValues.GetSize() ; ++i) {
140 fExpPValues.Add( other.fExpPValues.At(i)->Clone() );
143 fYObjects.SetOwner();
144 fExpPValues.SetOwner();
152 HypoTestInverterResult::HypoTestInverterResult(
const char* name,
153 const RooRealVar& scannedVariable,
155 SimpleInterval(name,scannedVariable,TMath::QuietNaN(),TMath::QuietNaN(),cl),
158 fInterpolateLowerLimit(true),
159 fInterpolateUpperLimit(true),
160 fFittedLowerLimit(false),
161 fFittedUpperLimit(false),
162 fInterpolOption(kLinear),
163 fLowerLimitError(-1),
164 fUpperLimitError(-1),
165 fCLsCleanupThreshold(0.005)
167 fYObjects.SetOwner();
168 fExpPValues.SetOwner();
173 fParameters.removeAll();
174 fParameters.takeOwnership();
175 fParameters.addOwned(*((RooRealVar *) scannedVariable.clone(scannedVariable.GetName()) ));
181 HypoTestInverterResult::~HypoTestInverterResult()
184 fYObjects.RemoveAll();
185 fExpPValues.RemoveAll();
188 fExpPValues.Delete();
193 int HypoTestInverterResult::ExclusionCleanup()
195 const int nEntries = ArraySize();
202 std::vector<double> qv;
205 p[0] = ROOT::Math::normal_cdf(-nsig2);
206 p[1] = ROOT::Math::normal_cdf(-nsig1);
208 p[3] = ROOT::Math::normal_cdf(nsig1);
209 p[4] = ROOT::Math::normal_cdf(nsig2);
211 bool resultIsAsymptotic(
false);
213 HypoTestResult* r =
dynamic_cast<HypoTestResult *
> ( GetResult(0) );
215 if ( !r->GetNullDistribution() && !r->GetAltDistribution() ) {
216 resultIsAsymptotic =
true;
220 int nPointsRemoved(0);
222 double CLsobsprev(1.0);
223 std::vector<double>::iterator itr = fXValues.begin();
225 for (; itr!=fXValues.end();) {
228 int i = FindIndex(x);
231 SamplingDistribution * s = GetExpectedPValueDist(i);
236 const std::vector<double> & values = s->GetSamplingDistribution();
237 if ((
int) values.size() != fgAsymptoticNumPoints) {
238 oocoutE(
this,Eval) <<
"HypoTestInverterResult::ExclusionCleanup - invalid size of sampling distribution" << std::endl;
245 if (resultIsAsymptotic) {
246 double maxSigma = fgAsymptoticMaxSigma;
247 double dsig = 2.*maxSigma / (values.size() -1) ;
248 int i0 = (int) TMath::Floor ( ( -nsig2 + maxSigma )/dsig + 0.5 );
249 int i1 = (int) TMath::Floor ( ( -nsig1 + maxSigma )/dsig + 0.5 );
250 int i2 = (int) TMath::Floor ( ( maxSigma )/dsig + 0.5 );
251 int i3 = (int) TMath::Floor ( ( nsig1 + maxSigma )/dsig + 0.5 );
252 int i4 = (int) TMath::Floor ( ( nsig2 + maxSigma )/dsig + 0.5 );
260 double * z =
const_cast<double *
>( &values[0] );
261 TMath::Quantiles(values.size(), 5, z, q, p,
false);
268 for (
int j=0; j<5; ++j) { qv[j]=q[j]; }
270 qv[6] = CLsError(i) ;
272 qv[8] = CLbError(i) ;
273 qv[9] = CLsplusb(i) ;
274 qv[10] = CLsplusbError(i) ;
275 double CLsobs = qv[5];
279 bool removeThisPoint(
false);
282 if (!removeThisPoint && resultIsAsymptotic && i>=1 && CLsobs>CLsobsprev) {
284 removeThisPoint =
true;
285 }
else { CLsobsprev = CLsobs; }
288 if (!removeThisPoint && i>=1 && CLsobs>=0.9999) {
290 removeThisPoint =
true;
293 if (!removeThisPoint && i>=1 && qv[4]<fCLsCleanupThreshold) { removeThisPoint =
true; }
296 if (removeThisPoint) {
297 itr = fXValues.erase(itr);
298 fYObjects.RemoveAt(i);
299 fExpPValues.RemoveAt(i);
309 fFittedUpperLimit =
false;
310 fFittedLowerLimit =
false;
311 FindInterpolatedLimit(1-ConfidenceLevel(),
true);
313 return nPointsRemoved;
327 bool HypoTestInverterResult::Add(
const HypoTestInverterResult& otherResult )
329 int nThis = ArraySize();
330 int nOther = otherResult.ArraySize();
331 if (nOther == 0)
return true;
332 if (nOther != otherResult.fYObjects.GetSize() )
return false;
333 if (nThis != fYObjects.GetSize() )
return false;
336 if (fExpPValues.GetSize() > 0 && fExpPValues.GetSize() != nThis )
return false;
337 if (otherResult.fExpPValues.GetSize() > 0 && otherResult.fExpPValues.GetSize() != nOther )
return false;
339 oocoutI(
this,Eval) <<
"HypoTestInverterResult::Add - merging result from " << otherResult.GetName()
340 <<
" in " << GetName() << std::endl;
342 bool addExpPValues = (fExpPValues.GetSize() == 0 && otherResult.fExpPValues.GetSize() > 0);
343 bool mergeExpPValues = (fExpPValues.GetSize() > 0 && otherResult.fExpPValues.GetSize() > 0);
345 if (addExpPValues || mergeExpPValues)
346 oocoutI(
this,Eval) <<
"HypoTestInverterResult::Add - merging also the expected p-values from pseudo-data" << std::endl;
352 fXValues = otherResult.fXValues;
353 for (
int i = 0; i < nOther; ++i)
354 fYObjects.Add( otherResult.fYObjects.At(i)->Clone() );
355 for (
int i = 0; i < fExpPValues.GetSize() ; ++i)
356 fExpPValues.Add( otherResult.fExpPValues.At(i)->Clone() );
360 for (
int i = 0; i < nOther; ++i) {
361 double otherVal = otherResult.fXValues[i];
362 HypoTestResult * otherHTR = (HypoTestResult*) otherResult.fYObjects.At(i);
363 if (otherHTR == 0)
continue;
364 bool sameXFound =
false;
365 for (
int j = 0; j < nThis; ++j) {
366 double thisVal = fXValues[j];
369 if ( (std::abs(otherVal) < 1 && TMath::AreEqualAbs(otherVal, thisVal,1.E-12) ) ||
370 (std::abs(otherVal) >= 1 && TMath::AreEqualRel(otherVal, thisVal,1.E-12) ) ) {
371 HypoTestResult * thisHTR = (HypoTestResult*) fYObjects.At(j);
372 thisHTR->Append(otherHTR);
374 if (mergeExpPValues) {
375 ((SamplingDistribution*) fExpPValues.At(j))->Add( (SamplingDistribution*)otherResult.fExpPValues.At(i) );
377 int thisNToys = (thisHTR->GetNullDistribution() ) ? thisHTR->GetNullDistribution()->GetSize() : 0;
378 int otherNToys = (otherHTR->GetNullDistribution() ) ? otherHTR->GetNullDistribution()->GetSize() : 0;
379 if (thisNToys != otherNToys )
380 oocoutW(
this,Eval) <<
"HypoTestInverterResult::Add expected p values have been generated with different toys " << thisNToys <<
" , " << otherNToys << std::endl;
387 fYObjects.Add(otherHTR->Clone() );
388 fXValues.push_back( otherVal);
392 fExpPValues.Add( otherResult.fExpPValues.At(i)->Clone() );
398 if (ArraySize() > nThis)
399 oocoutI(
this,Eval) <<
"HypoTestInverterResult::Add - new number of points is " << fXValues.size()
402 oocoutI(
this,Eval) <<
"HypoTestInverterResult::Add - new toys/point is "
403 << ((HypoTestResult*) fYObjects.At(0))->GetNullDistribution()->GetSize()
407 fLowerLimit = TMath::QuietNaN();
408 fUpperLimit = TMath::QuietNaN();
416 bool HypoTestInverterResult::Add (Double_t x,
const HypoTestResult & res)
420 fXValues.push_back(x);
421 fYObjects.Add(res.Clone());
423 HypoTestResult* r= GetResult(i);
424 if (!r)
return false;
429 fLowerLimit = TMath::QuietNaN();
430 fUpperLimit = TMath::QuietNaN();
438 double HypoTestInverterResult::GetXValue(
int index )
const
440 if ( index >= ArraySize() || index<0 ) {
441 oocoutE(
this,InputArguments) <<
"Problem: You are asking for an impossible array index value\n";
445 return fXValues[index];
451 double HypoTestInverterResult::GetYValue(
int index )
const
453 auto result = GetResult(index);
459 return result->CLs();
461 return result->CLsplusb();
468 double HypoTestInverterResult::GetYError(
int index )
const
470 auto result = GetResult(index);
476 return result->CLsError();
478 return result->CLsplusbError();
485 double HypoTestInverterResult::CLb(
int index )
const
487 auto result = GetResult(index);
491 return result->CLb();
497 double HypoTestInverterResult::CLsplusb(
int index )
const
499 auto result = GetResult(index);
503 return result->CLsplusb();
509 double HypoTestInverterResult::CLs(
int index )
const
511 auto result = GetResult(index);
515 return result->CLs();
521 double HypoTestInverterResult::CLbError(
int index )
const
523 auto result = GetResult(index);
527 return result->CLbError();
533 double HypoTestInverterResult::CLsplusbError(
int index )
const
535 auto result = GetResult(index);
539 return result->CLsplusbError();
545 double HypoTestInverterResult::CLsError(
int index )
const
547 auto result = GetResult(index);
551 return result->CLsError();
557 HypoTestResult* HypoTestInverterResult::GetResult(
int index )
const
559 if ( index >= ArraySize() || index<0 ) {
560 oocoutE(
this,InputArguments) <<
"Problem: You are asking for an impossible array index value\n";
564 return ((HypoTestResult*) fYObjects.At(index));
572 int HypoTestInverterResult::FindIndex(
double xvalue)
const
574 const double tol = 1.E-12;
575 for (
int i=0; i<ArraySize(); i++) {
576 double xpoint = fXValues[i];
577 if ( (std::abs(xvalue) > 1 && TMath::AreEqualRel( xvalue, xpoint, tol) ) ||
578 (std::abs(xvalue) < 1 && TMath::AreEqualAbs( xvalue, xpoint, tol) ) )
589 double HypoTestInverterResult::GetGraphX(
const TGraph & graph,
double y0,
bool lowSearch,
double &axmin,
double &axmax)
const {
593 std::cout <<
"using graph for search " << lowSearch <<
" min " << axmin <<
" max " << axmax << std::endl;
598 const double * y = graph.GetY();
599 int n = graph.GetN();
601 ooccoutE(
this,Eval) <<
"HypoTestInverterResult::GetGraphX - need at least 2 points for interpolation (n=" << n <<
")\n";
602 return (n>0) ? y[0] : 0;
605 double varmin = - TMath::Infinity();
606 double varmax = TMath::Infinity();
607 const RooRealVar* var =
dynamic_cast<RooRealVar*
>( fParameters.first() );
609 varmin = var->getMin();
610 varmax = var->getMax();
615 double ymin = TMath::MinElement(n,y);
616 double ymax = TMath::MaxElement(n,y);
619 return (lowSearch) ? varmax : varmin;
622 return (lowSearch) ? varmin : varmax;
629 if (axmin >= axmax ) {
632 std::cout <<
"No rage given - check if extrapolation is needed " << std::endl;
635 xmin = graph.GetX()[0];
636 xmax = graph.GetX()[n-1];
638 double yfirst = graph.GetY()[0];
639 double ylast = graph.GetY()[n-1];
645 if ( (ymax < y0 && !lowSearch) || ( yfirst > y0 && lowSearch) ) {
649 if ( (ymax < y0 && lowSearch) || ( ylast > y0 && !lowSearch) ) {
654 auto func = [&](
double x) {
655 return (fInterpolOption == kSpline) ? graph.Eval(x,
nullptr,
"S") - y0 : graph.Eval(x) - y0;
657 ROOT::Math::Functor1D f1d(func);
659 ROOT::Math::BrentRootFinder brf;
660 brf.SetFunction(f1d,xmin,xmax);
661 brf.SetNpx(TMath::Max(graph.GetN()*2,100) );
663 std::cout <<
"findind root for " << xmin <<
" , "<< xmax <<
"f(x) : " << graph.Eval(xmin) <<
" , " << graph.Eval(0.5*(xmax+xmin))
664 <<
" , " << graph.Eval(xmax) <<
" target " << y0 << std::endl;
667 bool ret = brf.Solve(100, 1.E-16, 1.E-6);
669 ooccoutE(
this,Eval) <<
"HypoTestInverterResult - interpolation failed for interval [" << xmin <<
"," << xmax
670 <<
" ] g(xmin,xmax) =" << graph.Eval(xmin) <<
"," << graph.Eval(xmax)
671 <<
" target=" << y0 <<
" return inf" << std::endl;
672 return TMath::Infinity();
674 double limit = brf.Root();
683 if (lowSearch) std::cout <<
"lower limit search : ";
684 else std::cout <<
"Upper limit search : ";
685 std::cout <<
"interpolation done between " << xmin <<
" and " << xmax
686 <<
"\n Found limit using RootFinder is " << limit << std::endl;
688 TString fname =
"graph_upper.root";
689 if (lowSearch) fname =
"graph_lower.root";
690 auto file = TFile::Open(fname,
"RECREATE");
691 graph.Write(
"graph");
697 if (axmin >= axmax) {
698 int index = TMath::BinarySearch(n, graph.GetX(), limit);
700 std::cout <<
"do new interpolation dividing from " << index <<
" and " << y[index] << std::endl;
703 if (lowSearch && index >= 1 && (y[0] - y0) * ( y[index]- y0) < 0) {
705 limit = GetGraphX(graph, y0, lowSearch, graph.GetX()[0], graph.GetX()[index] );
707 else if (!lowSearch && index < n-2 && (y[n-1] - y0) * ( y[index+1]- y0) < 0) {
709 limit = GetGraphX(graph, y0, lowSearch, graph.GetX()[index+1], graph.GetX()[n-1] );
723 double HypoTestInverterResult::FindInterpolatedLimit(
double target,
bool lowSearch,
double xmin,
double xmax )
727 double varmin = - TMath::Infinity();
728 double varmax = TMath::Infinity();
729 const RooRealVar* var =
dynamic_cast<RooRealVar*
>( fParameters.first() );
731 varmin = var->getMin();
732 varmax = var->getMax();
736 double val = (lowSearch) ? xmin : xmax;
737 oocoutW(
this,Eval) <<
"HypoTestInverterResult::FindInterpolatedLimit"
738 <<
" - not enough points to get the inverted interval - return "
740 fLowerLimit = varmin;
741 fUpperLimit = varmax;
742 return (lowSearch) ? fLowerLimit : fUpperLimit;
747 std::vector<unsigned int> index(n );
748 TMath::SortItr(fXValues.begin(), fXValues.end(), index.begin(),
false);
751 for (
int i = 0; i < n; ++i)
752 graph.SetPoint(i, GetXValue(index[i]), GetYValue(index[i] ) );
763 double * itrmax = std::max_element(graph.GetY() , graph.GetY() +n);
764 double ymax = *itrmax;
765 int iymax = itrmax - graph.GetY();
766 double xwithymax = graph.GetX()[iymax];
769 std::cout <<
" max of y " << iymax <<
" " << xwithymax <<
" " << ymax <<
" target is " << target << std::endl;
776 xmin = ( graph.GetY()[0] <= target ) ? graph.GetX()[0] : varmin;
781 fLowerLimit = varmin;
789 xmax = ( graph.GetY()[n-1] <= target ) ? graph.GetX()[n-1] : varmax;
793 fUpperLimit = varmax;
801 if (iymax <= (n-1)/2 ) {
803 fLowerLimit = varmin;
807 fUpperLimit = varmax;
812 std::cout <<
" found xmin, xmax = " << xmin <<
" " << xmax <<
" for search " << lowSearch << std::endl;
819 if (lowSearch && fUpperLimit < varmax) {
820 xmin = fXValues[ index.front() ];
822 int upI = FindClosestPointIndex(target, 2, fUpperLimit);
823 if (upI < 1)
return xmin;
824 xmax = GetXValue(upI);
826 else if (!lowSearch && fLowerLimit > varmin ) {
828 int lowI = FindClosestPointIndex(target, 3, fLowerLimit);
829 if (lowI >= n-1)
return xmax;
830 xmin = GetXValue(lowI);
831 xmax = fXValues[ index.back() ];
837 std::cout <<
"finding " << lowSearch <<
" limit between " << xmin <<
" " << xmax << endl;
841 double limit = GetGraphX(graph, target, lowSearch, xmin, xmax);
842 if (lowSearch) fLowerLimit = limit;
843 else fUpperLimit = limit;
845 double error = CalculateEstimatedError( target, lowSearch, xmin, xmax);
847 TString limitType = (lowSearch) ?
"lower" :
"upper";
848 ooccoutD(
this,Eval) <<
"HypoTestInverterResult::FindInterpolateLimit "
849 <<
"the computed " << limitType <<
" limit is " << limit <<
" +/- " << error << std::endl;
852 std::cout <<
"Found limit is " << limit <<
" +/- " << error << std::endl;
856 if (lowSearch)
return fLowerLimit;
896 int HypoTestInverterResult::FindClosestPointIndex(
double target,
int mode,
double xtarget)
900 int closestIndex = -1;
902 double smallestError = 2;
903 double bestValue = 2;
904 for (
int i=0; i<ArraySize(); i++) {
905 double dist = fabs(GetYValue(i)-target);
906 if ( dist <3 *GetYError(i) ) {
907 if (GetYError(i) < smallestError ) {
908 smallestError = GetYError(i);
912 if ( dist < bestValue) {
917 if (bestIndex >=0)
return bestIndex;
924 int n = fXValues.size();
925 std::vector<unsigned int> indx(n);
926 TMath::SortItr(fXValues.begin(), fXValues.end(), indx.begin(),
false);
927 std::vector<double> xsorted( n);
928 for (
int i = 0; i < n; ++i) xsorted[i] = fXValues[indx[i] ];
929 int index1 = TMath::BinarySearch( n, &xsorted[0], xtarget);
932 std::cout <<
"finding closest point to " << xtarget <<
" is " << index1 <<
" " << indx[index1] << std::endl;
936 if (index1 < 0)
return indx[0];
937 if (index1 >= n-1)
return indx[n-1];
938 int index2 = index1 +1;
940 if (mode == 2)
return (GetXValue(indx[index1]) < GetXValue(indx[index2])) ? indx[index1] : indx[index2];
941 if (mode == 3)
return (GetXValue(indx[index1]) > GetXValue(indx[index2])) ? indx[index1] : indx[index2];
943 if (fabs(GetYValue(indx[index1])-target) <= fabs(GetYValue(indx[index2])-target) )
951 Double_t HypoTestInverterResult::LowerLimit()
953 if (fFittedLowerLimit)
return fLowerLimit;
955 if ( fInterpolateLowerLimit ) {
957 if (TMath::IsNaN(fLowerLimit) ) FindInterpolatedLimit(1-ConfidenceLevel(),
true);
960 fLowerLimit = GetXValue( FindClosestPointIndex((1-ConfidenceLevel())) );
967 Double_t HypoTestInverterResult::UpperLimit()
970 if (fFittedUpperLimit)
return fUpperLimit;
971 if ( fInterpolateUpperLimit ) {
972 if (TMath::IsNaN(fUpperLimit) ) FindInterpolatedLimit(1-ConfidenceLevel(),
false);
975 fUpperLimit = GetXValue( FindClosestPointIndex((1-ConfidenceLevel())) );
985 Double_t HypoTestInverterResult::CalculateEstimatedError(
double target,
bool lower,
double xmin,
double xmax)
988 if (ArraySize()==0) {
989 oocoutW(
this,Eval) <<
"HypoTestInverterResult::CalculateEstimateError"
990 <<
"Empty result \n";
995 oocoutW(
this,Eval) <<
"HypoTestInverterResult::CalculateEstimateError"
996 <<
" only points - return its error\n";
1001 if (!GetNullTestStatDist(0) )
return 0;
1003 TString type = (!lower) ?
"upper" :
"lower";
1006 std::cout <<
"calculate estimate error " << type <<
" between " << xmin <<
" and " << xmax << std::endl;
1007 std::cout <<
"computed limit is " << ( (lower) ? fLowerLimit : fUpperLimit ) << std::endl;
1011 std::vector<unsigned int> indx(fXValues.size());
1012 TMath::SortItr(fXValues.begin(), fXValues.end(), indx.begin(),
false);
1016 for (
int i = 0; i < ArraySize(); ++i) {
1017 if ( (xmin < xmax) && ( GetXValue(indx[i]) >= xmin && GetXValue(indx[i]) <= xmax) ) {
1020 if (GetYError(indx[i] ) > 1.E-6) {
1021 graph.SetPoint(ip, GetXValue(indx[i]), GetYValue(indx[i] ) );
1022 graph.SetPointError(ip, 0., GetYError(indx[i]) );
1027 if (graph.GetN() < 2) {
1028 if (np >= 2) oocoutW(
this,Eval) <<
"HypoTestInverterResult::CalculateEstimatedError - no valid points - cannot estimate the " << type <<
" limit error " << std::endl;
1035 minX = fXValues[ indx.front() ];
1036 maxX = fXValues[ indx.back() ];
1039 TF1 fct(
"fct",
"exp([0] * (x - [2] ) + [1] * (x-[2])**2)", minX, maxX);
1040 double scale = maxX-minX;
1042 fct.SetParameters( 2./scale, 0.1/scale, graph.GetX()[0] );
1043 fct.SetParLimits(0,0,100./scale);
1044 fct.SetParLimits(1,0, 10./scale); }
1046 fct.SetParameters( -2./scale, -0.1/scale );
1047 fct.SetParLimits(0,-100./scale, 0);
1048 fct.SetParLimits(1,-100./scale, 0); }
1050 if (graph.GetN() < 3) fct.FixParameter(1,0.);
1053 double limit = (!lower) ? fUpperLimit : fLowerLimit;
1054 if (TMath::IsNaN(limit))
return 0;
1058 TCanvas * c1 =
new TCanvas();
1059 std::cout <<
"fitting for limit " << type <<
"between " << minX <<
" , " << maxX <<
" points considered " << graph.GetN() << std::endl;
1060 int fitstat = graph.Fit(&fct,
" EX0");
1061 graph.SetMarkerStyle(20);
1064 c1->SaveAs(TString::Format(
"graphFit_%s.pdf",type.Data()) );
1067 int fitstat = graph.Fit(&fct,
"Q EX0");
1070 int index = FindClosestPointIndex(target, 1, limit);
1071 double theError = 0;
1073 double errY = GetYError(index);
1075 double m = fct.Derivative( GetXValue(index) );
1076 theError = std::min(fabs( GetYError(index) / m), maxX-minX);
1080 oocoutW(
this,Eval) <<
"HypoTestInverterResult::CalculateEstimatedError - cannot estimate the " << type <<
" limit error " << std::endl;
1084 fLowerLimitError = theError;
1086 fUpperLimitError = theError;
1089 std::cout <<
"closes point to the limit is " << index <<
" " << GetXValue(index) <<
" and has error " << GetYError(index) << std::endl;
1098 Double_t HypoTestInverterResult::LowerLimitEstimatedError()
1100 if (TMath::IsNaN(fLowerLimit) ) LowerLimit();
1101 if (fLowerLimitError >= 0)
return fLowerLimitError;
1103 return CalculateEstimatedError(1-ConfidenceLevel(),
true);
1108 Double_t HypoTestInverterResult::UpperLimitEstimatedError()
1110 if (TMath::IsNaN(fUpperLimit) ) UpperLimit();
1111 if (fUpperLimitError >= 0)
return fUpperLimitError;
1113 return CalculateEstimatedError(1-ConfidenceLevel(),
false);
1119 SamplingDistribution * HypoTestInverterResult::GetBackgroundTestStatDist(
int index )
const {
1121 HypoTestResult * firstResult = (HypoTestResult*) fYObjects.At(index);
1122 if (!firstResult)
return 0;
1123 return firstResult->GetBackGroundIsAlt() ? firstResult->GetAltDistribution() : firstResult->GetNullDistribution();
1129 SamplingDistribution * HypoTestInverterResult::GetSignalAndBackgroundTestStatDist(
int index)
const {
1130 HypoTestResult * result = (HypoTestResult*) fYObjects.At(index);
1131 if (!result)
return 0;
1132 return !result->GetBackGroundIsAlt() ? result->GetAltDistribution() : result->GetNullDistribution();
1138 SamplingDistribution * HypoTestInverterResult::GetExpectedPValueDist(
int index)
const {
1140 if (index < 0 || index >= ArraySize() )
return 0;
1142 if (fExpPValues.GetSize() == ArraySize() ) {
1143 return (SamplingDistribution*) fExpPValues.At(index)->Clone();
1146 static bool useFirstB =
false;
1148 int bIndex = (useFirstB) ? 0 : index;
1150 SamplingDistribution * bDistribution = GetBackgroundTestStatDist(bIndex);
1151 SamplingDistribution * sbDistribution = GetSignalAndBackgroundTestStatDist(index);
1153 HypoTestResult * result = (HypoTestResult*) fYObjects.At(index);
1155 if (bDistribution && sbDistribution) {
1158 HypoTestResult tempResult;
1159 tempResult.SetPValueIsRightTail( result->GetPValueIsRightTail() );
1160 tempResult.SetBackgroundAsAlt(
true);
1162 tempResult.SetNullDistribution(
new SamplingDistribution(*sbDistribution) );
1163 tempResult.SetAltDistribution(
new SamplingDistribution(*bDistribution ) );
1165 std::vector<double> values(bDistribution->GetSize());
1166 for (
int i = 0; i < bDistribution->GetSize(); ++i) {
1167 tempResult.SetTestStatisticData( bDistribution->GetSamplingDistribution()[i] );
1168 values[i] = (fUseCLs) ? tempResult.CLs() : tempResult.CLsplusb();
1170 return new SamplingDistribution(
"expected values",
"expected values",values);
1174 fgAsymptoticMaxSigma = 5;
1175 fgAsymptoticNumPoints = 2*fgAsymptoticMaxSigma+1;
1176 const double smax = fgAsymptoticMaxSigma;
1177 const int npoints = fgAsymptoticNumPoints;
1178 const double dsig = 2* smax/ (npoints-1) ;
1179 std::vector<double> values(npoints);
1180 for (
int i = 0; i < npoints; ++i) {
1181 double nsig = -smax + dsig*i;
1182 double pval = AsymptoticCalculator::GetExpectedPValues( result->NullPValue(), result->AlternatePValue(), nsig, fUseCLs, !fIsTwoSided);
1183 if (pval < 0) {
return 0;}
1186 return new SamplingDistribution(
"Asymptotic expected values",
"Asymptotic expected values",values);
1194 SamplingDistribution * HypoTestInverterResult::GetLimitDistribution(
bool lower )
const {
1195 if (ArraySize()<2) {
1196 oocoutE(
this,Eval) <<
"HypoTestInverterResult::GetLimitDistribution"
1197 <<
" not enough points - return 0 " << std::endl;
1201 ooccoutD(
this,Eval) <<
"HypoTestInverterResult - computing limit distribution...." << std::endl;
1205 int npoints = ArraySize();
1206 std::vector<SamplingDistribution*> distVec( npoints );
1208 for (
unsigned int i = 0; i < distVec.size(); ++i) {
1209 distVec[i] = GetExpectedPValueDist(i);
1213 distVec[i]->InverseCDF(0);
1214 sum += distVec[i]->GetSize();
1217 int size = int( sum/ npoints);
1220 ooccoutW(
this,InputArguments) <<
"HypoTestInverterResult - set a minimum size of 10 for limit distribution" << std::endl;
1225 double target = 1-fConfidenceLevel;
1228 std::vector< std::vector<double> > quantVec(npoints );
1229 for (
int i = 0; i < npoints; ++i) {
1231 if (!distVec[i])
continue;
1234 std::vector<double> pvalues = distVec[i]->GetSamplingDistribution();
1235 delete distVec[i]; distVec[i] = 0;
1236 std::sort(pvalues.begin(), pvalues.end());
1241 quantVec[i] = std::vector<double>(size);
1242 for (
int ibin = 0; ibin < size; ++ibin) {
1244 p[0] = std::min( (ibin+1) * 1./
double(size), 1.0);
1246 TMath::Quantiles(pvalues.size(), 1, &pvalues[0], q, p,
true, 0, 1 );
1247 (quantVec[i])[ibin] = q[0];
1253 std::vector<unsigned int> index( npoints );
1254 TMath::SortItr(fXValues.begin(), fXValues.end(), index.begin(),
false);
1260 std::vector<double> limits(size);
1262 for (
int j = 0; j < size; ++j ) {
1265 for (
int k = 0; k < npoints ; ++k) {
1266 if (quantVec[index[k]].size() > 0 )
1267 g.SetPoint(g.GetN(), GetXValue(index[k]), (quantVec[index[k]])[j] );
1270 limits[j] = GetGraphX(g, target, lower);
1276 return new SamplingDistribution(
"Expected lower Limit",
"Expected lower limits",limits);
1278 return new SamplingDistribution(
"Expected upper Limit",
"Expected upper limits",limits);
1294 double HypoTestInverterResult::GetExpectedLowerLimit(
double nsig,
const char * opt )
const {
1296 return GetExpectedLimit(nsig,
true, opt);
1312 double HypoTestInverterResult::GetExpectedUpperLimit(
double nsig,
const char * opt )
const {
1314 return GetExpectedLimit(nsig,
false, opt);
1325 double HypoTestInverterResult::GetExpectedLimit(
double nsig,
bool lower,
const char * opt )
const {
1327 const int nEntries = ArraySize();
1328 if (nEntries <= 0)
return (lower) ? 1 : 0;
1330 HypoTestResult * r =
dynamic_cast<HypoTestResult *
> (fYObjects.First() );
1332 if (!r->GetNullDistribution() && !r->GetAltDistribution() ) {
1335 SamplingDistribution * limitDist = GetLimitDistribution(lower);
1336 if (!limitDist)
return 0;
1337 const std::vector<double> & values = limitDist->GetSamplingDistribution();
1338 if (values.size() <= 1)
return 0;
1339 double dsig = 2* fgAsymptoticMaxSigma/ (values.size() -1) ;
1340 int i = (int) TMath::Floor ( (nsig + fgAsymptoticMaxSigma)/dsig + 0.5);
1346 p[0] = ROOT::Math::normal_cdf(nsig,1);
1353 TString option(opt);
1355 if (option.Contains(
"P")) {
1360 std::vector<unsigned int> index(nEntries);
1361 TMath::SortItr(fXValues.begin(), fXValues.end(), index.begin(),
false);
1363 for (
int j=0; j<nEntries; ++j) {
1365 SamplingDistribution * s = GetExpectedPValueDist(i);
1367 ooccoutI(
this,Eval) <<
"HypoTestInverterResult - cannot compute expected p value distribution for point, x = "
1368 << GetXValue(i) <<
" skip it " << std::endl;
1371 const std::vector<double> & values = s->GetSamplingDistribution();
1372 double * x =
const_cast<double *
>(&values[0]);
1373 TMath::Quantiles(values.size(), 1, x,q,p,
false);
1374 g.SetPoint(g.GetN(), fXValues[i], q[0] );
1378 ooccoutE(
this,Eval) <<
"HypoTestInverterResult - cannot compute limits , not enough points, n = " << g.GetN() << std::endl;
1383 double target = 1-fConfidenceLevel;
1384 return GetGraphX(g, target, lower);
1388 SamplingDistribution * limitDist = GetLimitDistribution(lower);
1389 if (!limitDist)
return 0;
1390 const std::vector<double> & values = limitDist->GetSamplingDistribution();
1391 double * x =
const_cast<double *
>(&values[0]);
1392 TMath::Quantiles(values.size(), 1, x,q,p,
false);