ROOT logo
// @(#)root/roostats:$Id: HypoTestInverterResult.cxx 31798 2009-12-10 14:57:15Z moneta $
// Author: Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke
/*************************************************************************
 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/


/**
   HypoTestInverterResult class: holds the array of hypothesis test results and compute a confidence interval.
   Based on the RatioFinder code available in the RooStatsCms package developed by Gregory Schott and Danilo Piparo
   Ported and adapted to RooStats by Gregory Schott
   Some contributions to this class have been written by Matthias Wolf (error estimation)
**/


// include header file of this class 
#include "RooStats/HypoTestInverterResult.h"

#include "RooStats/HypoTestInverterPlot.h"
#include "RooStats/HybridResult.h"

#include "TF1.h"
#include "TGraphErrors.h"

ClassImp(RooStats::HypoTestInverterResult)

using namespace RooStats;


HypoTestInverterResult::HypoTestInverterResult(const char * name ) :
   SimpleInterval(name),
   fUseCLs(false),
   fInterpolateLowerLimit(true),
   fInterpolateUpperLimit(true)
{
  // default constructor
}


HypoTestInverterResult::HypoTestInverterResult( const char* name,
						const RooRealVar& scannedVariable,
						double cl ) :
   SimpleInterval(name,scannedVariable,-999,999,cl), 
   fUseCLs(false),
   fInterpolateLowerLimit(true),
   fInterpolateUpperLimit(true)
{
  // constructor 
   fYObjects.SetOwner();
}


HypoTestInverterResult::~HypoTestInverterResult()
{
   // destructor
   // no need to delete explictly the objects in the TList since the TList owns the objects
}


bool HypoTestInverterResult::Add( HypoTestInverterResult /* otherResult */  )
{
  /// Merge this HypoTestInverterResult with another
  /// HypoTestInverterResult passed as argument

  std::cout << "Sorry, this function is not yet implemented\n";

  return true;
}

 
double HypoTestInverterResult::GetXValue( int index ) const
{
  if ( index >= ArraySize() || index<0 ) {
    std::cout << "Problem: You are asking for an impossible array index value\n";
    return -999;
  }

  return fXValues[index];
}

double HypoTestInverterResult::GetYValue( int index ) const
{
  if ( index >= ArraySize() || index<0 ) {
    std::cout << "Problem: You are asking for an impossible array index value\n";
    return -999;
  }

  if (fUseCLs) 
    return ((HybridResult*)fYObjects.At(index))->CLs();
  else 
    return ((HybridResult*)fYObjects.At(index))->AlternatePValue();  // CLs+b
}

double HypoTestInverterResult::GetYError( int index ) const
{
  if ( index >= ArraySize() || index<0 ) {
    std::cout << "Problem: You are asking for an impossible array index value\n";
    return -999;
  }

  if (fUseCLs) 
    return ((HybridResult*)fYObjects.At(index))->CLsError();
  else 
    return ((HybridResult*)fYObjects.At(index))->CLsplusbError();
}

HypoTestResult* HypoTestInverterResult::GetResult( int index ) const
{
  if ( index >= ArraySize() || index<0 ) {
    std::cout << "Problem: You are asking for an impossible array index value\n";
    return 0;
  }

  return ((HypoTestResult*) fYObjects.At(index));
}

double HypoTestInverterResult::FindInterpolatedLimit(double target)
{
  std::cout << "Interpolate the upper limit between the 2 results closest to the target confidence level" << endl;

  if (ArraySize()<2) {
    std::cout << "Error: not enough points to get the inverted interval\n";
    if (target<0.5) return ((RooRealVar*)fParameters.first())->getMax();
    else return ((RooRealVar*)fParameters.first())->getMin();
  }

  double v1 = fabs(GetYValue(0)-target);
  int i1 = 0;
  double v2 = fabs(GetYValue(1)-target);
  int i2 = 1;

  if (ArraySize()>2)
    for (int i=2; i<ArraySize(); i++) {
      double vt = fabs(GetYValue(i)-target);
      if ( vt<v1 || vt<v2 ) {
	if ( v1<v2 ) {
	  v2 = vt;
	  i2 = i;
	} else {
	  v1 = vt;
	  i1 = i;
	}
      }
    }

  return GetXValue(i1)+(target-GetYValue(i1))*(GetXValue(i2)-GetXValue(i1))/(GetYValue(i2)-GetYValue(i1));
}

int HypoTestInverterResult::FindClosestPointIndex(double target)
{
  // find the object with the smallest error that is < 1 sigma from the target
  double bestValue = fabs(GetYValue(0)-target);
  int bestIndex = 0;
  for (int i=1; i<ArraySize(); i++) {
    if ( fabs(GetYValue(i)-target)<GetYError(i) ) { // less than 1 sigma from target CL
      double value = fabs(GetYValue(i)-target);
      if ( value<bestValue ) {
	bestValue = value;
	bestIndex = i;
      }
    }
  }

  return bestIndex;
}

Double_t HypoTestInverterResult::LowerLimit()
{
   //std::cout << "finding point with cl = " << 1-(1-ConfidenceLevel())/2 << endl;
  if ( fInterpolateLowerLimit ){
    fLowerLimit = FindInterpolatedLimit(1-(1-ConfidenceLevel())/2);
  } else {
    fLowerLimit = GetXValue( FindClosestPointIndex(1-(1-ConfidenceLevel())/2) );
  }
  return fLowerLimit;
}

Double_t HypoTestInverterResult::UpperLimit()
{
   //std::cout << "finding point with cl = " << (1-ConfidenceLevel())/2 << endl;
  if ( fInterpolateUpperLimit ) {
     fUpperLimit = FindInterpolatedLimit((1-ConfidenceLevel())/2);
  } else {
     fUpperLimit = GetXValue( FindClosestPointIndex((1-ConfidenceLevel())/2) );
  }
  return fUpperLimit;
}

Double_t HypoTestInverterResult::CalculateEstimatedError(double target)
{
  // Return an error estimate on the upper limit.  This is the error on
  // either CLs or CLsplusb divided by an estimate of the slope at this
  // point.

  if (ArraySize()<2) {
    std::cout << "not enough points to get the inverted interval\n";
  }
 
  // The graph contains the points sorted by their x-value
  HypoTestInverterPlot plot("plot", "", this);
  TGraphErrors* graph = plot.MakePlot();
  double* xs = graph->GetX();
  const double minX = xs[0];
  const double maxX = xs[ArraySize()-1];

  TF1 fct("fct", "exp([0] * x + [1] * x**2)", minX, maxX);
  graph->Fit(&fct,"Q");

  int index = FindClosestPointIndex(target);
  double m = fct.Derivative( GetXValue(index) );
  double theError = fabs( GetYError(index) / m);

  delete graph;

  return theError;
}


Double_t HypoTestInverterResult::LowerLimitEstimatedError()
{
   //std::cout << "The HypoTestInverterResult::LowerLimitEstimatedError() function evaluates only a rought error on the upper limit. Be careful when using this estimation\n";
  if (fInterpolateLowerLimit) std::cout << "The lower limit was an interpolated results... in this case the error is even less reliable (the Y-error bars are currently not used in the interpolation)\n";

  return CalculateEstimatedError(ConfidenceLevel()/2);
}


Double_t HypoTestInverterResult::UpperLimitEstimatedError()
{
   //std::cout << "The HypoTestInverterResult::UpperLimitEstimatedError() function evaluates only a rought error on the upper limit. Be careful when using this estimation\n";
  if (fInterpolateUpperLimit) std::cout << "The upper limit was an interpolated results... in this case the error is even less reliable (the Y-error bars are currently not used in the interpolation)\n";

  return CalculateEstimatedError(1-ConfidenceLevel()/2);
}
 HypoTestInverterResult.cxx:1
 HypoTestInverterResult.cxx:2
 HypoTestInverterResult.cxx:3
 HypoTestInverterResult.cxx:4
 HypoTestInverterResult.cxx:5
 HypoTestInverterResult.cxx:6
 HypoTestInverterResult.cxx:7
 HypoTestInverterResult.cxx:8
 HypoTestInverterResult.cxx:9
 HypoTestInverterResult.cxx:10
 HypoTestInverterResult.cxx:11
 HypoTestInverterResult.cxx:12
 HypoTestInverterResult.cxx:13
 HypoTestInverterResult.cxx:14
 HypoTestInverterResult.cxx:15
 HypoTestInverterResult.cxx:16
 HypoTestInverterResult.cxx:17
 HypoTestInverterResult.cxx:18
 HypoTestInverterResult.cxx:19
 HypoTestInverterResult.cxx:20
 HypoTestInverterResult.cxx:21
 HypoTestInverterResult.cxx:22
 HypoTestInverterResult.cxx:23
 HypoTestInverterResult.cxx:24
 HypoTestInverterResult.cxx:25
 HypoTestInverterResult.cxx:26
 HypoTestInverterResult.cxx:27
 HypoTestInverterResult.cxx:28
 HypoTestInverterResult.cxx:29
 HypoTestInverterResult.cxx:30
 HypoTestInverterResult.cxx:31
 HypoTestInverterResult.cxx:32
 HypoTestInverterResult.cxx:33
 HypoTestInverterResult.cxx:34
 HypoTestInverterResult.cxx:35
 HypoTestInverterResult.cxx:36
 HypoTestInverterResult.cxx:37
 HypoTestInverterResult.cxx:38
 HypoTestInverterResult.cxx:39
 HypoTestInverterResult.cxx:40
 HypoTestInverterResult.cxx:41
 HypoTestInverterResult.cxx:42
 HypoTestInverterResult.cxx:43
 HypoTestInverterResult.cxx:44
 HypoTestInverterResult.cxx:45
 HypoTestInverterResult.cxx:46
 HypoTestInverterResult.cxx:47
 HypoTestInverterResult.cxx:48
 HypoTestInverterResult.cxx:49
 HypoTestInverterResult.cxx:50
 HypoTestInverterResult.cxx:51
 HypoTestInverterResult.cxx:52
 HypoTestInverterResult.cxx:53
 HypoTestInverterResult.cxx:54
 HypoTestInverterResult.cxx:55
 HypoTestInverterResult.cxx:56
 HypoTestInverterResult.cxx:57
 HypoTestInverterResult.cxx:58
 HypoTestInverterResult.cxx:59
 HypoTestInverterResult.cxx:60
 HypoTestInverterResult.cxx:61
 HypoTestInverterResult.cxx:62
 HypoTestInverterResult.cxx:63
 HypoTestInverterResult.cxx:64
 HypoTestInverterResult.cxx:65
 HypoTestInverterResult.cxx:66
 HypoTestInverterResult.cxx:67
 HypoTestInverterResult.cxx:68
 HypoTestInverterResult.cxx:69
 HypoTestInverterResult.cxx:70
 HypoTestInverterResult.cxx:71
 HypoTestInverterResult.cxx:72
 HypoTestInverterResult.cxx:73
 HypoTestInverterResult.cxx:74
 HypoTestInverterResult.cxx:75
 HypoTestInverterResult.cxx:76
 HypoTestInverterResult.cxx:77
 HypoTestInverterResult.cxx:78
 HypoTestInverterResult.cxx:79
 HypoTestInverterResult.cxx:80
 HypoTestInverterResult.cxx:81
 HypoTestInverterResult.cxx:82
 HypoTestInverterResult.cxx:83
 HypoTestInverterResult.cxx:84
 HypoTestInverterResult.cxx:85
 HypoTestInverterResult.cxx:86
 HypoTestInverterResult.cxx:87
 HypoTestInverterResult.cxx:88
 HypoTestInverterResult.cxx:89
 HypoTestInverterResult.cxx:90
 HypoTestInverterResult.cxx:91
 HypoTestInverterResult.cxx:92
 HypoTestInverterResult.cxx:93
 HypoTestInverterResult.cxx:94
 HypoTestInverterResult.cxx:95
 HypoTestInverterResult.cxx:96
 HypoTestInverterResult.cxx:97
 HypoTestInverterResult.cxx:98
 HypoTestInverterResult.cxx:99
 HypoTestInverterResult.cxx:100
 HypoTestInverterResult.cxx:101
 HypoTestInverterResult.cxx:102
 HypoTestInverterResult.cxx:103
 HypoTestInverterResult.cxx:104
 HypoTestInverterResult.cxx:105
 HypoTestInverterResult.cxx:106
 HypoTestInverterResult.cxx:107
 HypoTestInverterResult.cxx:108
 HypoTestInverterResult.cxx:109
 HypoTestInverterResult.cxx:110
 HypoTestInverterResult.cxx:111
 HypoTestInverterResult.cxx:112
 HypoTestInverterResult.cxx:113
 HypoTestInverterResult.cxx:114
 HypoTestInverterResult.cxx:115
 HypoTestInverterResult.cxx:116
 HypoTestInverterResult.cxx:117
 HypoTestInverterResult.cxx:118
 HypoTestInverterResult.cxx:119
 HypoTestInverterResult.cxx:120
 HypoTestInverterResult.cxx:121
 HypoTestInverterResult.cxx:122
 HypoTestInverterResult.cxx:123
 HypoTestInverterResult.cxx:124
 HypoTestInverterResult.cxx:125
 HypoTestInverterResult.cxx:126
 HypoTestInverterResult.cxx:127
 HypoTestInverterResult.cxx:128
 HypoTestInverterResult.cxx:129
 HypoTestInverterResult.cxx:130
 HypoTestInverterResult.cxx:131
 HypoTestInverterResult.cxx:132
 HypoTestInverterResult.cxx:133
 HypoTestInverterResult.cxx:134
 HypoTestInverterResult.cxx:135
 HypoTestInverterResult.cxx:136
 HypoTestInverterResult.cxx:137
 HypoTestInverterResult.cxx:138
 HypoTestInverterResult.cxx:139
 HypoTestInverterResult.cxx:140
 HypoTestInverterResult.cxx:141
 HypoTestInverterResult.cxx:142
 HypoTestInverterResult.cxx:143
 HypoTestInverterResult.cxx:144
 HypoTestInverterResult.cxx:145
 HypoTestInverterResult.cxx:146
 HypoTestInverterResult.cxx:147
 HypoTestInverterResult.cxx:148
 HypoTestInverterResult.cxx:149
 HypoTestInverterResult.cxx:150
 HypoTestInverterResult.cxx:151
 HypoTestInverterResult.cxx:152
 HypoTestInverterResult.cxx:153
 HypoTestInverterResult.cxx:154
 HypoTestInverterResult.cxx:155
 HypoTestInverterResult.cxx:156
 HypoTestInverterResult.cxx:157
 HypoTestInverterResult.cxx:158
 HypoTestInverterResult.cxx:159
 HypoTestInverterResult.cxx:160
 HypoTestInverterResult.cxx:161
 HypoTestInverterResult.cxx:162
 HypoTestInverterResult.cxx:163
 HypoTestInverterResult.cxx:164
 HypoTestInverterResult.cxx:165
 HypoTestInverterResult.cxx:166
 HypoTestInverterResult.cxx:167
 HypoTestInverterResult.cxx:168
 HypoTestInverterResult.cxx:169
 HypoTestInverterResult.cxx:170
 HypoTestInverterResult.cxx:171
 HypoTestInverterResult.cxx:172
 HypoTestInverterResult.cxx:173
 HypoTestInverterResult.cxx:174
 HypoTestInverterResult.cxx:175
 HypoTestInverterResult.cxx:176
 HypoTestInverterResult.cxx:177
 HypoTestInverterResult.cxx:178
 HypoTestInverterResult.cxx:179
 HypoTestInverterResult.cxx:180
 HypoTestInverterResult.cxx:181
 HypoTestInverterResult.cxx:182
 HypoTestInverterResult.cxx:183
 HypoTestInverterResult.cxx:184
 HypoTestInverterResult.cxx:185
 HypoTestInverterResult.cxx:186
 HypoTestInverterResult.cxx:187
 HypoTestInverterResult.cxx:188
 HypoTestInverterResult.cxx:189
 HypoTestInverterResult.cxx:190
 HypoTestInverterResult.cxx:191
 HypoTestInverterResult.cxx:192
 HypoTestInverterResult.cxx:193
 HypoTestInverterResult.cxx:194
 HypoTestInverterResult.cxx:195
 HypoTestInverterResult.cxx:196
 HypoTestInverterResult.cxx:197
 HypoTestInverterResult.cxx:198
 HypoTestInverterResult.cxx:199
 HypoTestInverterResult.cxx:200
 HypoTestInverterResult.cxx:201
 HypoTestInverterResult.cxx:202
 HypoTestInverterResult.cxx:203
 HypoTestInverterResult.cxx:204
 HypoTestInverterResult.cxx:205
 HypoTestInverterResult.cxx:206
 HypoTestInverterResult.cxx:207
 HypoTestInverterResult.cxx:208
 HypoTestInverterResult.cxx:209
 HypoTestInverterResult.cxx:210
 HypoTestInverterResult.cxx:211
 HypoTestInverterResult.cxx:212
 HypoTestInverterResult.cxx:213
 HypoTestInverterResult.cxx:214
 HypoTestInverterResult.cxx:215
 HypoTestInverterResult.cxx:216
 HypoTestInverterResult.cxx:217
 HypoTestInverterResult.cxx:218
 HypoTestInverterResult.cxx:219
 HypoTestInverterResult.cxx:220
 HypoTestInverterResult.cxx:221
 HypoTestInverterResult.cxx:222
 HypoTestInverterResult.cxx:223
 HypoTestInverterResult.cxx:224
 HypoTestInverterResult.cxx:225
 HypoTestInverterResult.cxx:226
 HypoTestInverterResult.cxx:227
 HypoTestInverterResult.cxx:228
 HypoTestInverterResult.cxx:229
 HypoTestInverterResult.cxx:230
 HypoTestInverterResult.cxx:231
 HypoTestInverterResult.cxx:232
 HypoTestInverterResult.cxx:233
 HypoTestInverterResult.cxx:234
 HypoTestInverterResult.cxx:235
 HypoTestInverterResult.cxx:236
 HypoTestInverterResult.cxx:237
 HypoTestInverterResult.cxx:238