RooMath.cxx

Go to the documentation of this file.
00001 /*****************************************************************************
00002  * Project: RooFit                                                           *
00003  * Package: RooFitCore                                                       *
00004  * @(#)root/roofitcore:$Id: RooMath.cxx 36230 2010-10-09 20:21:02Z wouter $
00005  * Authors:                                                                  *
00006  *   WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu       *
00007  *   DK, David Kirkby,    UC Irvine,         dkirkby@uci.edu                 *
00008  *                                                                           *
00009  * Copyright (c) 2000-2005, Regents of the University of California          *
00010  *                          and Stanford University. All rights reserved.    *
00011  *                                                                           *
00012  * Redistribution and use in source and binary forms,                        *
00013  * with or without modification, are permitted according to the terms        *
00014  * listed in LICENSE (http://roofit.sourceforge.net/license.txt)             *
00015  *****************************************************************************/
00016 
00017 // -- CLASS DESCRIPTION [MISC] --
00018 // RooMath is a singleton class implementing various mathematical
00019 // functions not found in TMath, mostly involving complex algebra
00020 //
00021 //
00022 
00023 #include "RooFit.h"
00024 
00025 #include "RooMath.h"
00026 #include "RooMath.h"
00027 #include "TMath.h"
00028 #include <math.h>
00029 #include "Riostream.h"
00030 #include "RooMsgService.h"
00031 #include "RooSentinel.h"
00032 #include "TSystem.h"
00033 
00034 ClassImp(RooMath)
00035 ;
00036 
00037 
00038 RooComplex RooMath::FastComplexErrFunc(const RooComplex& z)
00039 {
00040   return ITPComplexErrFunc(z,z.im()>0?3:4) ;
00041 }
00042   
00043 Double_t RooMath::FastComplexErrFuncRe(const RooComplex& z) 
00044 {
00045   return ITPComplexErrFuncRe(z,z.im()>0?3:4) ;
00046 }
00047 
00048 Double_t RooMath::FastComplexErrFuncIm(const RooComplex& z) 
00049 {
00050   return ITPComplexErrFuncIm(z,z.im()>0?3:4) ;
00051 }
00052 
00053 void RooMath::cacheCERF(Bool_t flag) 
00054 { 
00055   _cacheTable = flag ; 
00056 }
00057 
00058 
00059 RooComplex RooMath::ComplexErrFunc(Double_t re, Double_t im) {
00060   // Return CERNlib complex error function for Z(re,im)
00061   return ComplexErrFunc(RooComplex(re,im));
00062 }
00063 
00064 RooComplex RooMath::ComplexErrFunc(const RooComplex& Z) {
00065   // Return CERNlib complex error function
00066   //
00067   // This code is translated from the fortran version in the CERN mathlib.
00068   // (see ftp://asisftp.cern.ch/cernlib/share/pro/src/mathlib/gen/c/cwerf64.F)
00069 
00070   RooComplex ZH,S,T,V;
00071   static RooComplex R[38];
00072 
00073   static const Double_t Z1= 1, HF= Z1/2, Z10= 10;
00074   static const Double_t C1= 74/Z10, C2= 83/Z10, C3= Z10/32, C4 = 16/Z10;
00075   static const Double_t C = 1.12837916709551257, P = pow(2*C4,33);
00076   static const RooComplex zero(0);
00077 
00078   Double_t X(Z.re()),Y(Z.im()), XA(fabs(X)), YA(fabs(Y));
00079   int N;
00080   if((YA < C1) && (XA < C2)) {
00081     ZH= RooComplex(YA+C4,XA);
00082     R[37]=zero;
00083     N= 36;
00084     while(N > 0) {
00085       T=ZH+R[N+1].conj()*N;
00086       R[N--]=(T*HF)/T.abs2();
00087     }
00088     Double_t XL=P;
00089     S=zero;
00090     N= 33;
00091     while(N > 0) {
00092       XL=C3*XL;
00093       S=R[N--]*(S+XL);
00094     }
00095     V=S*C;
00096   }
00097   else {
00098     ZH=RooComplex(YA,XA);
00099     R[1]=zero;
00100     N= 9;
00101     while(N > 0) {
00102       T=ZH+R[1].conj()*N;
00103       R[1]=(T*HF)/T.abs2();
00104       N--;
00105     }
00106     V=R[1]*C;
00107   }
00108   if(YA==0) V=RooComplex(exp(-(XA*XA)),V.im());
00109 
00110   if(Y < 0) {
00111     RooComplex tmp(XA,YA);
00112     tmp= -tmp*tmp;
00113     V=tmp.exp()*2-V;
00114     if(X > 0) V= V.conj();
00115   }
00116   else {
00117     if(X < 0) V= V.conj();
00118   }
00119   return V;
00120 }
00121 
00122 
00123 
00124 void RooMath::initFastCERF(Int_t reBins, Double_t reMin, Double_t reMax, Int_t imBins, Double_t imMin, Double_t imMax) 
00125 {
00126   // Allocate and initialize lookup table for interpolated complex error function
00127   // for given grid parameters
00128 
00129   // Store grid dimensions and related parameters
00130   _reBins = reBins ;
00131   _imBins = imBins ;
00132   _reMin = reMin ;
00133   _reMax = reMax ;
00134   _reRange = _reMax-_reMin ;
00135   _reStep  = _reRange/_reBins ;
00136 
00137   _imMin = imMin ;
00138   _imMax = imMax ;
00139   _imRange = _imMax-_imMin ;
00140   _imStep = _imRange/_imBins ;
00141 
00142   oocxcoutD((TObject*)0,Eval) << endl
00143                               << "RooMath::initFastCERF: Allocating Complex Error Function lookup table" << endl
00144                               << "                       Re: " << _reBins << " bins in range (" << _reMin << "," << _reMax << ")" << endl
00145                               << "                       Im: " << _imBins << " bins in range (" << _imMin << "," << _imMax << ")" << endl
00146                               << "                       Allocation size : " << _reBins*_imBins * 2 * sizeof(Double_t) / 1024 << " kB" << endl ;
00147 
00148 
00149   // Allocate storage matrix for Im(cerf) and Re(cerf) and fill it using ComplexErrFunc()
00150   RooSentinel::activate() ;
00151   Int_t imIdx,reIdx ;
00152   _reCerfArray = new pDouble_t[_imBins] ;
00153   _imCerfArray = new pDouble_t[_imBins] ;
00154   for (imIdx=0 ; imIdx<_imBins ; imIdx++) {
00155     _reCerfArray[imIdx] = new Double_t[_reBins] ;
00156     _imCerfArray[imIdx] = new Double_t[_reBins] ;
00157   }
00158   
00159   Bool_t cacheLoaded(kFALSE) ;
00160   if (!_cacheTable || !(cacheLoaded=loadCache())) {
00161     
00162     oocxcoutD((TObject*)0,Eval) << endl
00163                                 << "                       Filling table: |..................................................|\r" 
00164                                 << "                       Filling table: |" ;
00165     
00166     // Allocate storage matrix for Im(cerf) and Re(cerf) and fill it using ComplexErrFunc()
00167     for (imIdx=0 ; imIdx<_imBins ; imIdx++) {
00168       if (imIdx % (_imBins/50) ==0) {
00169         ooccxcoutD((TObject*)0,Eval) << ">" ; cout.flush() ;
00170       }
00171       for (reIdx=0 ; reIdx<_reBins ; reIdx++) {
00172         RooComplex val=ComplexErrFunc(_reMin+reIdx*_reStep,_imMin+imIdx*_imStep) ;
00173         _reCerfArray[imIdx][reIdx] = val.re();
00174         _imCerfArray[imIdx][reIdx] = val.im() ;
00175       }
00176     }
00177     ooccoutI((TObject*)0,Eval) << endl ;
00178   } 
00179 
00180   if (_cacheTable && !cacheLoaded) storeCache() ;
00181 }
00182 
00183 
00184 void RooMath::cleanup()
00185 {
00186   if (_reCerfArray) {
00187     for (Int_t imIdx=0 ; imIdx<_imBins ; imIdx++) {
00188       delete[] _reCerfArray[imIdx] ;
00189       delete[] _imCerfArray[imIdx] ;
00190     }
00191     delete[] _reCerfArray ;
00192     delete[] _imCerfArray ;
00193     _reCerfArray = 0 ;
00194     _imCerfArray = 0 ;
00195   }
00196   
00197 }
00198 
00199 
00200 RooComplex RooMath::ITPComplexErrFunc(const RooComplex& z, Int_t nOrder)
00201 {
00202   // Return complex error function interpolated from lookup tabel created
00203   // by initFastCERF(). Interpolation is performed in Im and Re plane
00204   // to specified order.
00205 
00206   // Initialize grid
00207   if (!_reCerfArray) initFastCERF() ;
00208 
00209   // Located nearest grid point
00210   Double_t imPrime = (z.im()-_imMin) / _imStep ;
00211   Double_t rePrime = (z.re()-_reMin) / _reStep ;
00212 
00213   // Calculate corners of nOrder X nOrder grid box
00214   Int_t imIdxLo = Int_t(imPrime - 1.0*nOrder/2 + 0.5) ;
00215   Int_t imIdxHi = imIdxLo+nOrder-1 ;
00216   Int_t reIdxLo = Int_t(rePrime - 1.0*nOrder/2 + 0.5) ;
00217   Int_t reIdxHi = reIdxLo+nOrder-1 ;
00218 
00219   // Check if the box is fully contained in the grid
00220   if (imIdxLo<0 || imIdxHi>_imBins-1 || reIdxLo<0 || reIdxHi>_reBins-1) {
00221     return ComplexErrFunc(z) ;
00222   }
00223 
00224   // Allocate temporary array space for interpolation
00225   Int_t imIdx /*, reIdx*/ ;
00226   Double_t imYR[10] ;
00227   Double_t imYI[10] ;
00228 
00229   // Loop over imaginary grid points
00230   for (imIdx=imIdxLo ; imIdx<=imIdxHi ; imIdx++) {
00231     // Interpolate real array and store as array point for imaginary interpolation
00232     imYR[imIdx-imIdxLo] = interpolate(&_reCerfArray[imIdx][reIdxLo],nOrder,rePrime-reIdxLo) ;
00233     imYI[imIdx-imIdxLo] = interpolate(&_imCerfArray[imIdx][reIdxLo],nOrder,rePrime-reIdxLo) ;
00234   }
00235   // Interpolate imaginary arrays and construct complex return value
00236   Double_t re = interpolate(imYR,nOrder,imPrime-imIdxLo) ;
00237   Double_t im = interpolate(imYI,nOrder,imPrime-imIdxLo) ;
00238   return RooComplex(re,im) ;
00239 }
00240 
00241 
00242 
00243 
00244 
00245 Double_t RooMath::ITPComplexErrFuncRe(const RooComplex& z, Int_t nOrder)
00246 {
00247   // Return real component of complex error function interpolated from 
00248   // lookup table created by initFastCERF(). Interpolation is performed in 
00249   // Im and Re plane to specified order. This functions is noticably faster
00250   // than ITPComplexErrrFunc().re() because only the real lookup table
00251   // is interpolated
00252 
00253   // Initialize grid
00254   if (!_reCerfArray) initFastCERF() ;
00255 
00256   // Located nearest grid point
00257   Double_t imPrime = (z.im()-_imMin) / _imStep ;
00258   Double_t rePrime = (z.re()-_reMin) / _reStep ;
00259 
00260   // Calculate corners of nOrder X nOrder grid box
00261   Int_t imIdxLo = Int_t(imPrime - 1.0*nOrder/2 + 0.5) ;
00262   Int_t imIdxHi = imIdxLo+nOrder-1 ;
00263   Int_t reIdxLo = Int_t(rePrime - 1.0*nOrder/2 + 0.5) ;
00264   Int_t reIdxHi = reIdxLo+nOrder-1 ;
00265   
00266   // Check if the box is fully contained in the grid
00267   if (imIdxLo<0 || imIdxHi>_imBins-1 || reIdxLo<0 || reIdxHi>_reBins-1) {
00268     //cout << "RooMath::ITPComplexErrFuncRe: (" << z.re() << "," << z.im() << ") outside interpolation grid" << endl ;
00269     return ComplexErrFunc(z).re() ;
00270   }
00271 
00272   if (nOrder==1) return _reCerfArray[imIdxLo][reIdxLo] ;
00273 
00274   Int_t imIdx ;
00275   Double_t imYR[10] ;
00276 
00277   // Allocate temporary array space for interpolation
00278   for (imIdx=imIdxLo ; imIdx<=imIdxHi ; imIdx++) {
00279     // Interpolate real array and store as array point for imaginary interpolation
00280     imYR[imIdx-imIdxLo] = interpolate(&_reCerfArray[imIdx][reIdxLo],nOrder,rePrime-reIdxLo) ;
00281   }
00282   // Interpolate imaginary arrays and construct complex return value
00283   return interpolate(imYR,nOrder,imPrime-imIdxLo) ;
00284 }
00285 
00286 
00287 
00288 Double_t RooMath::ITPComplexErrFuncIm(const RooComplex& z, Int_t nOrder)
00289 {
00290   // Return real component of complex error function interpolated from 
00291   // lookup table created by initFastCERF(). Interpolation is performed in 
00292   // Im and Re plane to specified order. This functions is noticably faster
00293   // than ITPComplexErrrFunc().im() because only the imaginary lookup table
00294   // is interpolated
00295 
00296   // Initialize grid
00297   if (!_reCerfArray) initFastCERF() ;
00298 
00299   // Located nearest grid point
00300   Double_t imPrime = (z.im()-_imMin) / _imStep ;
00301   Double_t rePrime = (z.re()-_reMin) / _reStep ;
00302 
00303   // Calculate corners of nOrder X nOrder grid box
00304   Int_t imIdxLo = Int_t(imPrime - 1.0*nOrder/2 + 0.5) ;
00305   Int_t imIdxHi = imIdxLo+nOrder-1 ;
00306   Int_t reIdxLo = Int_t(rePrime - 1.0*nOrder/2 + 0.5) ;
00307   Int_t reIdxHi = reIdxLo+nOrder-1 ;
00308 
00309   // Check if the box is fully contained in the grid
00310   if (imIdxLo<0 || imIdxHi>_imBins-1 || reIdxLo<0 || reIdxHi>_reBins-1) {
00311     return ComplexErrFunc(z).im() ;
00312   }
00313 
00314   // Allocate temporary array space for interpolation
00315   Int_t imIdx ;
00316   Double_t imYI[10] ;
00317 
00318   // Loop over imaginary grid points
00319   for (imIdx=imIdxLo ; imIdx<=imIdxHi ; imIdx++) {
00320     // Interpolate real array and store as array point for imaginary interpolation
00321     imYI[imIdx-imIdxLo] = interpolate(&_imCerfArray[imIdx][reIdxLo],nOrder,rePrime-reIdxLo) ;
00322   }
00323   // Interpolate imaginary arrays and construct complex return value
00324   return interpolate(imYI,nOrder,imPrime-imIdxLo) ;
00325 }
00326 
00327 
00328 
00329 
00330 
00331 
00332 Double_t RooMath::interpolate(Double_t ya[], Int_t n, Double_t x) 
00333 {
00334   // Interpolate array 'ya' with 'n' elements for 'x' (between 0 and 'n'-1)
00335 
00336   // Int to Double conversion is faster via array lookup than type conversion!
00337   static Double_t itod[20] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,
00338                               10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0} ;
00339   int i,m,ns=1 ;
00340   Double_t den,dif,dift/*,ho,hp,w*/,y,dy ;
00341   Double_t c[20], d[20] ;
00342 
00343   dif = fabs(x) ;
00344   for(i=1 ; i<=n ; i++) {
00345     if ((dift=fabs(x-itod[i-1]))<dif) {
00346       ns=i ;
00347       dif=dift ;
00348     }
00349     c[i] = ya[i-1] ;
00350     d[i] = ya[i-1] ;
00351   }
00352   
00353   y=ya[--ns] ;
00354   for(m=1 ; m<n; m++) {       
00355     for(i=1 ; i<=n-m ; i++) { 
00356       den=(c[i+1] - d[i])/itod[m] ;
00357       d[i]=(x-itod[i+m-1])*den ;
00358       c[i]=(x-itod[i-1])*den ;
00359     }
00360     dy = (2*ns)<(n-m) ? c[ns+1] : d[ns--] ;
00361     y += dy ;
00362   }
00363   return y ;
00364 }
00365 
00366 
00367 
00368 Double_t RooMath::interpolate(Double_t xa[], Double_t ya[], Int_t n, Double_t x) 
00369 {
00370   // Interpolate array 'ya' with 'n' elements for 'xa' 
00371 
00372   // Int to Double conversion is faster via array lookup than type conversion!
00373 //   static Double_t itod[20] = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0,
00374 //                            10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0} ;
00375   int i,m,ns=1 ;
00376   Double_t den,dif,dift,ho,hp,w,y,dy ;
00377   Double_t c[20], d[20] ;
00378 
00379   dif = fabs(x-xa[0]) ;
00380   for(i=1 ; i<=n ; i++) {
00381     if ((dift=fabs(x-xa[i-1]))<dif) {
00382       ns=i ;
00383       dif=dift ;
00384     }
00385     c[i] = ya[i-1] ;
00386     d[i] = ya[i-1] ;
00387   }
00388   
00389   y=ya[--ns] ;
00390   for(m=1 ; m<n; m++) {       
00391     for(i=1 ; i<=n-m ; i++) { 
00392       ho=xa[i-1]-x ;
00393       hp=xa[i-1+m]-x ;
00394       w=c[i+1]-d[i] ;
00395       den=ho-hp ;
00396       if (den==0.) {
00397         oocoutE((TObject*)0,Eval) << "RooMath::interpolate ERROR: zero distance between points not allowed" << endl ;
00398         return 0 ;
00399       }
00400       den = w/den ;
00401       d[i]=hp*den ;
00402       c[i]=ho*den;
00403     }
00404     dy = (2*ns)<(n-m) ? c[ns+1] : d[ns--] ;
00405     y += dy ;
00406   }
00407   return y ;
00408 }
00409 
00410 
00411 
00412 Bool_t RooMath::loadCache() 
00413 {
00414   // Load the complex error function lookup table from the cache file
00415 
00416   const char* fName = cacheFileName() ;
00417   // Open cache file
00418   ifstream ifs(fName) ;
00419 
00420   // Return immediately if file doesn't exist
00421   if (ifs.fail()) return kFALSE ;
00422 
00423   oocxcoutD((TObject*)0,Eval) << endl << "                       Filling table from cache file " << fName << endl ;
00424 
00425   // Load data in memory arrays
00426   Bool_t ok(kTRUE) ;
00427   Int_t i ;
00428   for (i=0 ; i<_imBins ; i++) {
00429     ifs.read((char*)_imCerfArray[i],_reBins*sizeof(Double_t)) ;
00430     if (ifs.fail()) ok=kFALSE ;
00431     ifs.read((char*)_reCerfArray[i],_reBins*sizeof(Double_t)) ;
00432     if (ifs.fail()) ok=kFALSE ;
00433   }  
00434 
00435   // Issue error message on partial read failure
00436   if (!ok) {
00437     oocoutE((TObject*)0,Eval) << "RooMath::loadCERFCache: error reading file " << cacheFileName() << endl ;
00438   }
00439   return ok ;
00440 }
00441 
00442 
00443 void RooMath::storeCache()
00444 {
00445   // Store the complex error function lookup table in the cache file
00446 
00447   ofstream ofs(cacheFileName()) ;
00448   
00449   oocxcoutI((TObject*)0,Eval) << endl << "                       Writing table to cache file " << cacheFileName() << endl ;
00450   Int_t i ;
00451   for (i=0 ; i<_imBins ; i++) {
00452     ofs.write((char*)_imCerfArray[i],_reBins*sizeof(Double_t)) ;
00453     ofs.write((char*)_reCerfArray[i],_reBins*sizeof(Double_t)) ;
00454   }
00455 }
00456 
00457 
00458 
00459 const char* RooMath::cacheFileName() 
00460 {
00461   // Construct and return the name of the complex error function cache file
00462   static char fileName[1024] ;  
00463   snprintf(fileName,1024,"/tmp/RooMath_CERFcache_R%04d_I%04d_%d.dat",_reBins,_imBins,gSystem->GetUid()) ;
00464   return fileName ;
00465 }
00466 
00467 
00468 Double_t RooMath::erf(Double_t x) 
00469 {
00470   return TMath::Erf(x) ;
00471 }
00472 
00473 Double_t RooMath::erfc(Double_t x)
00474 {
00475   return TMath::Erfc(x) ;
00476 }
00477 
00478 
00479 
00480 // Instantiation of static members
00481 Int_t RooMath::_reBins(0) ;
00482 Int_t RooMath::_imBins(0) ;
00483 Double_t RooMath::_reMin(0) ;
00484 Double_t RooMath::_reMax(0) ;
00485 Double_t RooMath::_reRange(0) ;
00486 Double_t RooMath::_reStep(0) ;
00487 Double_t RooMath::_imMin(0) ;
00488 Double_t RooMath::_imMax(0) ;
00489 Double_t RooMath::_imRange(0) ;
00490 Double_t RooMath::_imStep(0) ;
00491 pDouble_t* RooMath::_reCerfArray = 0;
00492 pDouble_t* RooMath::_imCerfArray = 0;
00493 Bool_t RooMath::_cacheTable(kTRUE) ;
00494 

Generated on Tue Jul 5 15:06:48 2011 for ROOT_528-00b_version by  doxygen 1.5.1