RooIntegralMorph.cxx

Go to the documentation of this file.
00001  /***************************************************************************** 
00002   * Project: RooFit                                                           * 
00003   *                                                                           * 
00004   * Copyright (c) 2000-2005, Regents of the University of California          * 
00005   *                          and Stanford University. All rights reserved.    * 
00006   *                                                                           * 
00007   * Redistribution and use in source and binary forms,                        * 
00008   * with or without modification, are permitted according to the terms        * 
00009   * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             * 
00010   *****************************************************************************/ 
00011 
00012 //////////////////////////////////////////////////////////////////////////////
00013 //
00014 // Class RooIntegralMorph is an implementation of the histogram interpolation
00015 // technique described by Alex Read in 'NIM A 425 (1999) 357-369 'Linear interpolation of histograms'
00016 // for continuous functions rather than histograms. The interpolation method, in short,
00017 // works as follows. 
00018 //
00019 //   - Given a p.d.f f1(x) with c.d.f F1(x) and p.d.f f2(x) with c.d.f F2(x)
00020 // 
00021 //   - One finds takes a value 'y' of both c.d.fs and determines the corresponding x
00022 //     values x(1,2) at which F(1,2)(x)==y. 
00023 //
00024 //   - The value of the interpolated p.d.f fbar(x) is then calculated as 
00025 //     fbar(alpha*x1+(1-alpha)*x2) = f1(x1)*f2(x2) / ( alpha*f2(x2) + (1-alpha)*f1(x1) ) ;
00026 // 
00027 // From a technical point of view class RooIntegralMorph is a p.d.f that takes
00028 // two input p.d.fs f1(x,p) an f2(x,q) and an interpolation parameter to
00029 // make a p.d.f fbar(x,p,q,alpha). The shapes f1 and f2 are always taken
00030 // to be end the end-points of the parameter alpha, regardless of what
00031 // the those numeric values are. 
00032 //
00033 // Since the value of fbar(x) cannot be easily calculated for a given value
00034 // of x, class RooIntegralMorph is an implementation of RooAbsCachedPdf and
00035 // calculates the shape of the interpolated p.d.f. fbar(x) for all values
00036 // of x for a given value of alpha,p,q and caches these values in a histogram
00037 // (as implemented by RooAbsCachedPdf). The binning granularity of the cache
00038 // can be controlled by the binning named "cache" on the RooRealVar representing
00039 // the observable x. The fbar sampling algorithm is based on a recursive division
00040 // mechanism with a built-in precision cutoff: First an initial sampling in
00041 // 64 equally spaced bins is made. Then the value of fbar is calculated in
00042 // the center of each gap. If the calculated value deviates too much from
00043 // the value obtained by linear interpolation from the edge bins, gap
00044 // is recursively divided. This strategy makes it possible to define a very
00045 // fine cache sampling (e.g. 1000 or 10000) bins without incurring a
00046 // corresponding CPU penalty.
00047 //
00048 // Note on numeric stability of the algorithm. Since the algorithm relies
00049 // on a numeric inversion of cumulative distributions functions, some precision
00050 // may be lost at the 'edges' of the same (i.e. at regions in x where the
00051 // c.d.f. value is close to zero or one). The general sampling strategy is
00052 // to start with 64 equally spaces samples in the range y=(0.01-0.99).
00053 // Then the y ranges are pushed outward by reducing y (or the distance of y to 1.0)
00054 // by a factor of sqrt(10) iteratively up to the point where the corresponding
00055 // x value no longer changes significantly. For p.d.f.s with very flat tails
00056 // such as Gaussians some part of the tail may be lost due to limitations
00057 // in numeric precision in the CDF inversion step. 
00058 //
00059 // An effect related to the above limitation in numeric precision should
00060 // be anticipated when floating the alpha parameter in a fit. If a p.d.f
00061 // with such flat tails is fitted, it is likely that the dataset contains
00062 // events in the flat tail region. If the alpha parameter is varied, the
00063 // likelihood contribution from such events may exhibit discontinuities
00064 // in alpha, causing discontinuities in the summed likelihood as well
00065 // that will cause convergence problems in MINUIT. To mitigate this effect
00066 // one can use the setCacheAlpha() method to instruct RooIntegralMorph
00067 // to construct a two-dimensional cache for its output values in both
00068 // x and alpha. If linear interpolation is requested on the resulting
00069 // output histogram, the resulting interpolation of the p.d.f in the
00070 // alpha dimension will smooth out the discontinities in the tail regions
00071 // result in a continuous likelihood distribution that can be fitted.
00072 // An added advantage of the cacheAlpha option is that if parameters
00073 // p,q of f1,f2 are fixed, the cached values in RooIntegralMorph are
00074 // valid for the entire fit session and do not need to be recalculated
00075 // for each change in alpha, which may result an considerable increase
00076 // in calculation speed.
00077 // 
00078 //
00079 
00080 #include "Riostream.h" 
00081 
00082 #include "RooIntegralMorph.h" 
00083 #include "RooAbsReal.h" 
00084 #include "RooAbsCategory.h" 
00085 #include "RooBrentRootFinder.h"
00086 #include "RooAbsFunc.h"
00087 #include "RooRealVar.h"
00088 #include "RooDataHist.h"
00089 #include "TH1.h"
00090 
00091 ClassImp(RooIntegralMorph) 
00092 
00093 
00094 //_____________________________________________________________________________
00095 RooIntegralMorph::RooIntegralMorph(const char *name, const char *title, 
00096                                RooAbsReal& _pdf1,
00097                                RooAbsReal& _pdf2,
00098                                RooAbsReal& _x,
00099                                RooAbsReal& _alpha,
00100                                Bool_t doCacheAlpha) :
00101   RooAbsCachedPdf(name,title,2), 
00102   pdf1("pdf1","pdf1",this,_pdf1),
00103   pdf2("pdf2","pdf2",this,_pdf2),
00104   x("x","x",this,_x),
00105   alpha("alpha","alpha",this,_alpha),
00106   _cacheAlpha(doCacheAlpha),
00107   _cache(0)
00108 { 
00109   // Constructor with observables x, pdf shapes pdf1 and pdf2 which represent
00110   // the shapes at the end points of the interpolation parameter alpha
00111   // If doCacheAlpha is true, a two-dimensional cache is constructed in
00112   // both alpha and x
00113 } 
00114 
00115 
00116 
00117 //_____________________________________________________________________________
00118 RooIntegralMorph::RooIntegralMorph(const RooIntegralMorph& other, const char* name) :  
00119   RooAbsCachedPdf(other,name), 
00120   pdf1("pdf1",this,other.pdf1),
00121   pdf2("pdf2",this,other.pdf2),
00122   x("x",this,other.x),
00123   alpha("alpha",this,other.alpha),
00124   _cacheAlpha(other._cacheAlpha),
00125   _cache(0)
00126 { 
00127   // Copy constructor
00128 } 
00129 
00130 
00131 
00132 //_____________________________________________________________________________
00133 RooArgSet* RooIntegralMorph::actualObservables(const RooArgSet& /*nset*/) const 
00134 {
00135   // Observable to be cached for given choice of normalization.
00136   // Returns the 'x' observable unless doCacheAlpha is set in which
00137   // case a set with both x and alpha
00138 
00139   RooArgSet* obs = new RooArgSet ;
00140   if (_cacheAlpha) {
00141     obs->add(alpha.arg()) ;
00142   }
00143   obs->add(x.arg()) ;
00144   return obs ;
00145 }
00146 
00147 
00148 
00149 //_____________________________________________________________________________
00150 RooArgSet* RooIntegralMorph::actualParameters(const RooArgSet& /*nset*/) const 
00151 {  
00152   // Parameters of the cache. Returns parameters of both pdf1 and pdf2
00153   // and parameter cache, in case doCacheAlpha is not set.
00154 
00155   RooArgSet* par1 = pdf1.arg().getParameters(RooArgSet()) ;
00156   RooArgSet* par2 = pdf2.arg().getParameters(RooArgSet()) ;
00157   par1->add(*par2,kTRUE) ;
00158   par1->remove(x.arg(),kTRUE,kTRUE) ;
00159   if (!_cacheAlpha) {
00160     par1->add(alpha.arg()) ;
00161   }
00162   delete par2 ;
00163   return par1 ;
00164 }
00165 
00166 
00167 
00168 //_____________________________________________________________________________
00169 const char* RooIntegralMorph::inputBaseName() const 
00170 {
00171   // Return base name component for cache components in this case
00172   // a string encoding the names of both end point p.d.f.s
00173 
00174   static TString name ;
00175 
00176   name = pdf1.arg().GetName() ;
00177   name.Append("_MORPH_") ;
00178   name.Append(pdf2.arg().GetName()) ;
00179   return name.Data() ;
00180 }
00181 
00182   
00183 
00184 //_____________________________________________________________________________
00185 void RooIntegralMorph::fillCacheObject(PdfCacheElem& cache) const 
00186 {
00187   // Fill the cache with the interpolated shape. 
00188 
00189   MorphCacheElem& mcache = static_cast<MorphCacheElem&>(cache) ;
00190   
00191   // If cacheAlpha is true employ slice iterator here to fill all slices
00192 
00193   if (!_cacheAlpha) {
00194 
00195     TIterator* dIter = cache.hist()->sliceIterator((RooAbsArg&)x.arg(),RooArgSet()) ;
00196     mcache.calculate(dIter) ; 
00197     delete dIter ;
00198 
00199   } else {
00200     TIterator* slIter = cache.hist()->sliceIterator((RooAbsArg&)alpha.arg(),RooArgSet()) ;
00201 
00202     Double_t alphaSave = alpha ;
00203     RooArgSet alphaSet(alpha.arg()) ;
00204     coutP(Eval) << "RooIntegralMorph::fillCacheObject(" << GetName() << ") filling multi-dimensional cache" ;
00205     while(slIter->Next()) {
00206       alphaSet = (*cache.hist()->get()) ;
00207       TIterator* dIter = cache.hist()->sliceIterator((RooAbsArg&)x.arg(),RooArgSet(alpha.arg())) ;
00208       mcache.calculate(dIter) ;     
00209       ccoutP(Eval) << "." << flush;
00210       delete dIter ;
00211     }
00212     ccoutP(Eval) << endl ;
00213 
00214     delete slIter ;
00215     const_cast<RooIntegralMorph*>(this)->alpha = alphaSave ;
00216   }
00217 }
00218 
00219 
00220 
00221 //_____________________________________________________________________________
00222 RooAbsCachedPdf::PdfCacheElem* RooIntegralMorph::createCache(const RooArgSet* nset) const 
00223 {
00224   // Create and return a derived MorphCacheElem.
00225 
00226   return new MorphCacheElem(const_cast<RooIntegralMorph&>(*this),nset) ;
00227 }
00228 
00229 
00230 
00231 //_____________________________________________________________________________
00232 RooArgList RooIntegralMorph::MorphCacheElem::containedArgs(Action action) 
00233 {
00234   // Return all RooAbsArg components contained in this cache
00235 
00236   RooArgList ret ;
00237   ret.add(PdfCacheElem::containedArgs(action)) ;
00238   ret.add(*_self) ;
00239   ret.add(*_pdf1) ;
00240   ret.add(*_pdf2) ;
00241   ret.add(*_x  ) ; 
00242   ret.add(*_alpha) ;
00243   ret.add(*_c1) ; 
00244   ret.add(*_c2) ; 
00245 
00246   return ret ;
00247 }
00248 
00249 
00250 
00251 //_____________________________________________________________________________
00252 RooIntegralMorph::MorphCacheElem::MorphCacheElem(RooIntegralMorph& self, const RooArgSet* nsetIn) : PdfCacheElem(self,nsetIn)
00253 {
00254   // Construct of cache element, copy relevant input from RooIntegralMorph,
00255   // create the cdfs from the input p.d.fs and instantiate the root finders
00256   // on the cdfs to perform the inversion.
00257 
00258   // Mark in base class that normalization of cached pdf is invariant under pdf parameters
00259   _x = (RooRealVar*)self.x.absArg() ;
00260   _nset = new RooArgSet(*_x) ;
00261 
00262   _alpha = (RooAbsReal*)self.alpha.absArg() ;
00263   _pdf1 = (RooAbsPdf*)(self.pdf1.absArg()) ;
00264   _pdf2 = (RooAbsPdf*)(self.pdf2.absArg()) ;
00265   _c1 = _pdf1->createCdf(*_x);
00266   _c2 = _pdf2->createCdf(*_x) ;  
00267   _cb1 = _c1->bindVars(*_x,_nset) ;
00268   _cb2 = _c2->bindVars(*_x,_nset) ;  
00269   _self = &self ;
00270 
00271   _rf1 = new RooBrentRootFinder(*_cb1) ;
00272   _rf2 = new RooBrentRootFinder(*_cb2) ;
00273   _ccounter = 0 ;
00274 
00275   _rf1->setTol(1e-12) ;
00276   _rf2->setTol(1e-12) ;
00277   _ycutoff = 1e-7 ;
00278   
00279   _yatX = 0 ;
00280   _calcX = 0 ;
00281 
00282   // Must do this here too: fillCache() may not be called if cache contents is retrieved from EOcache
00283   pdf()->setUnitNorm(kTRUE) ;
00284 
00285   _yatXmax = 0 ;
00286   _yatXmin = 0 ;
00287 }
00288 
00289 
00290 //_____________________________________________________________________________
00291 RooIntegralMorph::MorphCacheElem::~MorphCacheElem() 
00292 {
00293   // Destructor
00294 
00295   delete _rf1 ;
00296   delete _rf2 ;
00297   delete[] _yatX ;
00298   delete[] _calcX ;
00299 }
00300 
00301 
00302 
00303 //_____________________________________________________________________________
00304 Double_t RooIntegralMorph::MorphCacheElem::calcX(Double_t y, Bool_t& ok)
00305 {
00306   // Calculate the x value of the output p.d.f at the given cdf value y.
00307   // The ok boolean is filled with the success status of the operation.
00308 
00309   if (y<0 || y>1) {
00310     oocoutW(_self,Eval) << "RooIntegralMorph::MorphCacheElem::calcX() WARNING: requested root finding for unphysical CDF value " << y << endl ; 
00311   }
00312   Double_t x1,x2 ;    
00313 
00314   Double_t xmax = _x->getMax("cache") ;
00315   Double_t xmin = _x->getMin("cache") ;
00316 
00317   ok=kTRUE ;
00318   ok &= _rf1->findRoot(x1,xmin,xmax,y) ;
00319   ok &= _rf2->findRoot(x2,xmin,xmax,y) ;
00320   if (!ok) return 0 ;
00321   _ccounter++ ;
00322 
00323   return _alpha->getVal()*x1 + (1-_alpha->getVal())*x2 ;  
00324 }
00325 
00326 
00327 //_____________________________________________________________________________
00328 Int_t RooIntegralMorph::MorphCacheElem::binX(Double_t X) 
00329 {
00330   // Return the bin number enclosing the given x value
00331 
00332   Double_t xmax = _x->getMax("cache") ;
00333   Double_t xmin = _x->getMin("cache") ;
00334   return (Int_t)(_x->numBins("cache")*(X-xmin)/(xmax-xmin)) ;
00335 }
00336 
00337 
00338 
00339 //_____________________________________________________________________________
00340 void RooIntegralMorph::MorphCacheElem::calculate(TIterator* dIter)
00341 {
00342   // Calculate shape of p.d.f for x,alpha values 
00343   // defined by dIter iterator over cache histogram
00344 
00345   Double_t xsave = _self->x ;
00346 
00347   if (!_yatX) {
00348     _yatX = new Double_t[_x->numBins("cache")+1] ;
00349     _calcX = new Double_t[_x->numBins("cache")+1] ;
00350   }
00351 
00352   RooArgSet nsetTmp(*_x) ;
00353   _ccounter = 0 ;
00354   
00355   // Get number of bins from PdfCacheElem histogram
00356   Int_t nbins = _x->numBins("cache") ;
00357 
00358   // Initialize yatX array to 'uncalculated values (-1)'
00359   for (int i=0 ; i<nbins ; i++) {
00360     _yatX[i] = -1 ;
00361     _calcX[i] = 0 ;
00362   }
00363 
00364   // Find low and high point
00365   findRange() ;
00366 
00367   // Perform initial scan of 100 points
00368   for (int i=0 ; i<10 ; i++) {    
00369 
00370     // Take a point in y
00371     Double_t offset = _yatX[_yatXmin] ;
00372     Double_t delta = (_yatX[_yatXmax] - _yatX[_yatXmin])/10 ;
00373     Double_t y = offset + i*delta ;
00374 
00375     // Calculate corresponding X
00376     Bool_t ok ;
00377     Double_t X = calcX(y,ok) ;
00378     if (ok) {
00379       Int_t iX = binX(X) ;
00380       _yatX[iX] = y ;           
00381       _calcX[iX] =  X ;
00382     }
00383   }
00384 
00385   // Now take an iteration filling the 'gaps'
00386   Int_t igapLow = _yatXmin+1 ;
00387   while(true) {
00388     // Find next gap
00389     Int_t igapHigh = igapLow+1 ;
00390     while(_yatX[igapHigh]<0 && igapHigh<(_yatXmax)) igapHigh++ ;
00391 
00392     // Fill the gap (iteratively and/or using interpolation)
00393     fillGap(igapLow-1,igapHigh) ;
00394     
00395     // Terminate after processing of last gap
00396     if (igapHigh>=_yatXmax-1) break ;
00397     igapLow = igapHigh+1 ;
00398   }
00399 
00400   // Make one more iteration to recalculate Y value at bin centers  
00401   Double_t xmax = _x->getMax("cache") ;
00402   Double_t xmin = _x->getMin("cache") ;
00403   Double_t binw = (xmax-xmin)/_x->numBins("cache") ;
00404   for (int i=_yatXmin+1 ; i<_yatXmax-1 ; i++) {
00405 
00406     // Calculate additional offset to apply if bin ixlo does not have X value calculated at bin center
00407     Double_t xBinC = xmin + (i+0.5)*binw ;
00408     Double_t xOffset = xBinC-_calcX[i] ;
00409     if (fabs(xOffset/binw)>1e-3) {
00410       Double_t slope = (_yatX[i+1]-_yatX[i-1])/(_calcX[i+1]-_calcX[i-1]) ;
00411       Double_t newY = _yatX[i] + slope*xOffset ;
00412       //cout << "bin " << i << " needs to be recentered " << xOffset/binw << " slope = " << slope << " origY = " << _yatX[i] << " newY = " << newY << endl ;      
00413       _yatX[i] = newY ;
00414     } 
00415   }
00416 
00417   // Zero output histogram below lowest calculable X value
00418   for (int i=0; i<_yatXmin ; i++) {
00419     dIter->Next() ;
00420     //_hist->get(i) ; 
00421     hist()->set(0) ;
00422   }
00423   // Transfer calculated values to histogram
00424   for (int i=_yatXmin ; i<_yatXmax ; i++) {
00425     
00426     Double_t y = _yatX[i] ;
00427     
00428     Double_t x1,x2 ;    
00429 
00430     Double_t xMin = _x->getMin("cache") ;
00431     Double_t xMax = _x->getMax("cache") ;
00432     _rf1->findRoot(x1,xMin,xMax,y) ;
00433     _rf2->findRoot(x2,xMin,xMax,y) ;
00434     
00435     _x->setVal(x1) ; Double_t f1x1 = _pdf1->getVal(&nsetTmp) ;
00436     _x->setVal(x2) ; Double_t f2x2 = _pdf2->getVal(&nsetTmp) ;
00437     Double_t fbarX = f1x1*f2x2 / ( _alpha->getVal()*f2x2 + (1-_alpha->getVal())*f1x1 ) ;
00438 
00439     dIter->Next() ;
00440     //_hist->get(i) ; 
00441     hist()->set(fbarX) ;
00442   }
00443   // Zero output histogram above highest calculable X value
00444   for (int i=_yatXmax+1 ; i<nbins ; i++) {
00445     dIter->Next() ;
00446     //_hist->get(i) ; 
00447     hist()->set(0) ;
00448   }
00449 
00450   pdf()->setUnitNorm(kTRUE) ;
00451   _self->x = xsave ;
00452 
00453   oocxcoutD(_self,Eval) << "RooIntegralMorph::MorphCacheElem::calculate(" << _self->GetName() << ") calculation required " << _ccounter << " samplings of cdfs" << endl ;
00454 }
00455 
00456 
00457 //_____________________________________________________________________________
00458 void RooIntegralMorph::MorphCacheElem::fillGap(Int_t ixlo, Int_t ixhi, Double_t splitPoint) 
00459 {
00460   // Fill all empty histogram bins between bins ixlo and ixhi. The value of 'splitPoint'
00461   // defines the split point for the recursive division strategy to fill the gaps
00462   // If the midpoint value of y is very close to the midpoint in x, use interpolation
00463   // to fill the gaps, otherwise the intervals again.
00464 
00465   // CONVENTION: _yatX[ixlo] is filled, _yatX[ixhi] is filled, elements in between are empty
00466   //   cout << "fillGap: gap from _yatX[" << ixlo << "]=" << _yatX[ixlo] << " to _yatX[" << ixhi << "]=" << _yatX[ixhi] << ", size = " << ixhi-ixlo << endl ;
00467   
00468   if (_yatX[ixlo]<0) {
00469     oocoutE(_self,Eval) << "RooIntegralMorph::MorphCacheElme::fillGap(" << _self->GetName() << "): ERROR in fillgap " << ixlo << " = " << ixhi 
00470                         << " splitPoint= " << splitPoint << " _yatX[ixlo] = " << _yatX[ixlo] << endl ;
00471   }
00472   if (_yatX[ixhi]<0) {
00473     oocoutE(_self,Eval) << "RooIntegralMorph::MorphCacheElme::fillGap(" << _self->GetName() << "): ERROR in fillgap " << ixlo << " = " << ixhi 
00474                         << " splitPoint " << splitPoint << " _yatX[ixhi] = " << _yatX[ixhi] << endl ;
00475   }
00476 
00477   // Determine where half-way Y value lands
00478   Double_t ymid = _yatX[ixlo]*splitPoint + _yatX[ixhi]*(1-splitPoint) ;
00479   Bool_t ok ;
00480   Double_t Xmid = calcX(ymid,ok) ;
00481   if (!ok) {
00482     oocoutW(_self,Eval) << "RooIntegralMorph::MorphCacheElem::fillGap(" << _self->GetName() << ") unable to calculate midpoint in gap [" 
00483                         << ixlo << "," << ixhi << "], resorting to interpolation" << endl ;
00484     interpolateGap(ixlo,ixhi) ;
00485   }
00486 
00487   Int_t iX = binX(Xmid) ;  
00488   Double_t cq = (Xmid-_calcX[ixlo])/(_calcX[ixhi]-_calcX[ixlo])-0.5 ;
00489 
00490   // Store midway point
00491   _yatX[iX] = ymid ;
00492   _calcX[iX] = Xmid ;
00493 
00494 
00495   // Policy: If centration quality is better than 1% OR better than 1/10 of a bin, fill interval with linear interpolation
00496   if (fabs(cq)<0.01 || fabs(cq*(ixhi-ixlo))<0.1 || ymid<_ycutoff ) {
00497         
00498     // Fill remaining gaps on either side with linear interpolation
00499     if (iX-ixlo>1) {      
00500       interpolateGap(ixlo,iX) ;
00501     }
00502     if (ixhi-iX>1) {
00503       interpolateGap(iX,ixhi) ;
00504     }
00505         
00506   } else {
00507 
00508     if (iX==ixlo) {
00509 
00510       if (splitPoint<0.95) {
00511         // Midway value lands on lowest bin, retry split with higher split point
00512         Double_t newSplit = splitPoint + 0.5*(1-splitPoint) ;
00513         fillGap(ixlo,ixhi,newSplit) ;
00514       } else {
00515         // Give up and resort to interpolation
00516         interpolateGap(ixlo,ixhi) ;
00517       }
00518 
00519     } else if (iX==ixhi) {
00520 
00521       // Midway value lands on highest bin, retry split with lower split point      
00522       if (splitPoint>0.05) {
00523         Double_t newSplit = splitPoint/2 ;
00524         fillGap(ixlo,ixhi,newSplit) ;
00525       } else {
00526         // Give up and resort to interpolation
00527         interpolateGap(ixlo,ixhi) ;
00528       }
00529 
00530     } else {
00531 
00532       // Midway point reasonable, iterate on interval on both sides
00533       if (iX-ixlo>1) {
00534         fillGap(ixlo,iX) ;
00535       }
00536       if (ixhi-iX>1) {
00537         fillGap(iX,ixhi) ;
00538       }    
00539     }
00540   }  
00541 }
00542 
00543 
00544 //_____________________________________________________________________________
00545 void RooIntegralMorph::MorphCacheElem::interpolateGap(Int_t ixlo, Int_t ixhi)
00546 {
00547   // Fill empty histogram bins between ixlo and ixhi with values obtained
00548   // from linear interpolation of ixlo,ixhi elements. 
00549 
00550   //cout << "filling gap with linear interpolation ixlo=" << ixlo << " ixhi=" << ixhi << endl ;
00551 
00552   Double_t xmax = _x->getMax("cache") ;
00553   Double_t xmin = _x->getMin("cache") ;
00554   Double_t binw = (xmax-xmin)/_x->numBins("cache") ;
00555 
00556   // Calculate deltaY in terms of actuall X difference calculate, not based on nominal bin width
00557   Double_t deltaY = (_yatX[ixhi]-_yatX[ixlo])/((_calcX[ixhi]-_calcX[ixlo])/binw) ;
00558 
00559   // Calculate additional offset to apply if bin ixlo does not have X value calculated at bin center
00560   Double_t xBinC = xmin + (ixlo+0.5)*binw ;
00561   Double_t xOffset = xBinC-_calcX[ixlo] ;
00562   
00563   for (int j=ixlo+1 ; j<ixhi ; j++) {
00564     _yatX[j] = _yatX[ixlo]+(xOffset+(j-ixlo))*deltaY ;
00565     _calcX[j] = xmin + (j+0.5)*binw ;
00566   } 
00567 
00568 }
00569 
00570 
00571 
00572 //_____________________________________________________________________________
00573 void RooIntegralMorph::MorphCacheElem::findRange()
00574 {
00575   // Determine which range of y values can be mapped to x values
00576   // from the numeric inversion of the input c.d.fs.
00577   // Start with a y rannge of [0.1-0.9] and push boundaries
00578   // outward with a factor of 1/sqrt(10). Stop iteration if
00579   // inverted x values no longer change
00580   
00581   Double_t xmin = _x->getMin("cache") ;
00582   Double_t xmax = _x->getMax("cache") ;
00583   Int_t nbins = _x->numBins("cache") ;
00584 
00585   Double_t x1,x2 ;      
00586   Bool_t ok = kTRUE ;
00587   Double_t ymin=0.1,yminSave(-1) ;
00588   Double_t Xsave(-1),Xlast=xmax ;
00589 
00590   // Find lowest Y value that can be measured
00591   // Start at 0.1 and iteratively lower limit by sqrt(10)
00592   while(true) {
00593     ok &= _rf1->findRoot(x1,xmin,xmax,ymin) ;
00594     ok &= _rf2->findRoot(x2,xmin,xmax,ymin) ;
00595     oocxcoutD(_self,Eval) << "RooIntegralMorph::MorphCacheElem::findRange(" << _self->GetName() << ") findMin: x1 = " << x1 << " x2 = " << x2 << " ok = " << (ok?"T":"F") << endl ;
00596 
00597     // Terminate in case of non-convergence
00598     if (!ok) break ;
00599 
00600     // Terminate if value of X no longer moves by >0.1 bin size
00601     Double_t X = _alpha->getVal()*x1 + (1-_alpha->getVal())*x2 ;
00602     if (fabs(X-Xlast)/(xmax-xmin)<0.0001) {
00603       break ;
00604     } 
00605     Xlast=X ;
00606 
00607     // Store new Y value
00608     _yatXmin = (Int_t)(nbins*(X-xmin)/(xmax-xmin)) ;
00609     _yatX[_yatXmin] = ymin ;
00610     _calcX[_yatXmin] = X ;
00611     yminSave = ymin ;
00612     Xsave=X ;
00613 
00614     // Reduce ymin by half an order of magnitude
00615     ymin /=sqrt(10.) ;
00616 
00617     // Emergency break
00618     if (ymin<_ycutoff) break ;
00619   }
00620   _yatX[_yatXmin] = yminSave ;
00621   _calcX[_yatXmin] = Xsave ;
00622 
00623   // Find highst Y value that can be measured
00624   // Start at 1 - 0.1 and iteratively lower delta by sqrt(10)
00625   ok = kTRUE ;
00626   Double_t deltaymax=0.1, deltaymaxSave(-1) ;
00627   Xlast=xmin ;
00628   while(true) {
00629     ok &= _rf1->findRoot(x1,xmin,xmax,1-deltaymax) ;
00630     ok &= _rf2->findRoot(x2,xmin,xmax,1-deltaymax) ;
00631 
00632     oocxcoutD(_self,Eval) << "RooIntegralMorph::MorphCacheElem::findRange(" << _self->GetName() << ") findMax: x1 = " << x1 << " x2 = " << x2 << " ok = " << (ok?"T":"F") << endl ;
00633 
00634     // Terminate in case of non-convergence
00635     if (!ok) break ;
00636 
00637     // Terminate if value of X no longer moves by >0.1 bin size
00638     Double_t X = _alpha->getVal()*x1 + (1-_alpha->getVal())*x2 ;
00639     if (fabs(X-Xlast)/(xmax-xmin)<0.0001) {
00640       break ;
00641     } 
00642     Xlast=X ;
00643 
00644     // Store new Y value
00645     _yatXmax = (Int_t)(nbins*(X-xmin)/(xmax-xmin)) ;    
00646     _yatX[_yatXmax] = 1-deltaymax ;
00647     _calcX[_yatXmax] = X ;
00648     deltaymaxSave = deltaymax ;
00649     Xsave=X ;
00650 
00651     // Reduce ymin by half an order of magnitude
00652     deltaymax /=sqrt(10.) ;
00653 
00654     // Emergency break
00655     if (deltaymax<_ycutoff) break ;
00656   }
00657 
00658   _yatX[_yatXmax] = 1-deltaymaxSave ;
00659   _calcX[_yatXmax] = Xsave ;
00660 
00661    
00662   // Initialize values out of range to 'out-of-range' (-2)
00663   for (int i=0 ; i<_yatXmin ; i++)  _yatX[i] = -2 ;
00664   for (int i=_yatXmax+1 ; i<nbins; i++) _yatX[i] = -2 ;
00665   oocxcoutD(_self,Eval) << "RooIntegralMorph::findRange(" << _self->GetName() << "): ymin = " << _yatX[_yatXmin] << " ymax = " << _yatX[_yatXmax] << endl; 
00666   oocxcoutD(_self,Eval) << "RooIntegralMorph::findRange(" << _self->GetName() << "): xmin = " << _calcX[_yatXmin] << " xmax = " << _calcX[_yatXmax] << endl; 
00667 }
00668 
00669 
00670 
00671 //_____________________________________________________________________________
00672 Double_t RooIntegralMorph::evaluate() const 
00673 { 
00674   // Dummy
00675   return 0 ;
00676 } 
00677 
00678 
00679 
00680 //_____________________________________________________________________________
00681 void RooIntegralMorph::preferredObservableScanOrder(const RooArgSet& obs, RooArgSet& orderedObs) const
00682 {
00683   // Indicate to the RooAbsCachedPdf base class that for the filling of the
00684   // cache the traversal of the x should be in the innermost loop, to minimize
00685   // recalculation of the one-dimensional internal cache for a fixed value of alpha
00686 
00687   // Put x last to minimize cache faulting
00688   orderedObs.removeAll() ;
00689 
00690   orderedObs.add(obs) ;
00691   RooAbsArg* obsX = obs.find(x.arg().GetName()) ;
00692   if (obsX) {
00693     orderedObs.remove(*obsX) ;
00694     orderedObs.add(*obsX) ;
00695   }  
00696 }
00697 
00698 
00699 

Generated on Tue Jul 5 14:55:14 2011 for ROOT_528-00b_version by  doxygen 1.5.1