/*****************************************************************************
* Project: RooFit *
* *
* Copyright (c) 2000-2005, Regents of the University of California *
* and Stanford University. All rights reserved. *
* *
* Redistribution and use in source and binary forms, *
* with or without modification, are permitted according to the terms *
* listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
*****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// Class RooNumRunningInt is an implementation of RooAbsCachedReal that represents a running integral
//
// RI(f(x)) = Int[x_lo,x] f(x') dx'
//
// that is calculated internally with a numeric technique: The input function
// is first sampled into a histogram, which is then numerically integrated.
// The output function is an interpolated version of the integrated histogram.
// The sampling density is controlled by the binning named "cache" in the observable x.
// The shape of the p.d.f is always calculated for the entire domain in x and
// cached in a histogram. The cache histogram is automatically recalculated
// when any of the parameters of the input p.d.f. has changed.
// END_HTML
//
#include "Riostream.h"
#include "RooAbsPdf.h"
#include "RooNumRunningInt.h"
#include "RooAbsReal.h"
#include "RooMsgService.h"
#include "RooDataHist.h"
#include "RooHistPdf.h"
#include "RooRealVar.h"
using namespace std;
ClassImp(RooNumRunningInt)
;
//_____________________________________________________________________________
RooNumRunningInt::RooNumRunningInt(const char *name, const char *title, RooAbsReal& _func, RooRealVar& _x, const char* bname) :
RooAbsCachedReal(name,title),
func("func","func",this,_func),
x("x","x",this,_x),
_binningName(bname?bname:"cache")
{
// Construct running integral of function '_func' over x_print from
// the lower bound on _x to the present value of _x using a numeric
// sampling technique. The sampling frequency is controlled by the
// binning named 'bname' and a default second order interpolation
// is applied to smooth the histogram-based c.d.f.
setInterpolationOrder(2) ;
}
//_____________________________________________________________________________
RooNumRunningInt::RooNumRunningInt(const RooNumRunningInt& other, const char* name) :
RooAbsCachedReal(other,name),
func("func",this,other.func),
x("x",this,other.x),
_binningName(other._binningName)
{
// Copy constructor
}
//_____________________________________________________________________________
RooNumRunningInt::~RooNumRunningInt()
{
// Destructor
}
//_____________________________________________________________________________
const char* RooNumRunningInt::inputBaseName() const
{
// Return unique name for RooAbsCachedPdf cache components
// constructed from input function name
static string ret ;
ret = func.arg().GetName() ;
ret += "_NUMRUNINT" ;
return ret.c_str() ;
} ;
//_____________________________________________________________________________
RooNumRunningInt::RICacheElem::RICacheElem(const RooNumRunningInt& self, const RooArgSet* nset) :
FuncCacheElem(self,nset), _self(&const_cast(self))
{
// Construct RunningIntegral CacheElement
// Instantiate temp arrays
_ax = new Double_t[hist()->numEntries()] ;
_ay = new Double_t[hist()->numEntries()] ;
// Copy X values from histo
_xx = (RooRealVar*) hist()->get()->find(self.x.arg().GetName()) ;
for (int i=0 ; inumEntries() ; i++) {
hist()->get(i) ;
_ax[i] = _xx->getVal() ;
_ay[i] = -1 ;
}
}
//_____________________________________________________________________________
RooNumRunningInt::RICacheElem::~RICacheElem()
{
// Destructor
// Delete temp arrays
delete[] _ax ;
delete[] _ay ;
}
//_____________________________________________________________________________
RooArgList RooNumRunningInt::RICacheElem::containedArgs(Action action)
{
// Return all RooAbsArg components contained in cache element
RooArgList ret ;
ret.add(FuncCacheElem::containedArgs(action)) ;
ret.add(*_self) ;
ret.add(*_xx) ;
return ret ;
}
//_____________________________________________________________________________
void RooNumRunningInt::RICacheElem::calculate(Bool_t cdfmode)
{
// Calculate the numeric running integral and store
// the result in the cache histogram provided
// by RooAbsCachedPdf
// Update contents of histogram
Int_t nbins = hist()->numEntries() ;
Double_t xsave = _self->x ;
Int_t lastHi=0 ;
Int_t nInitRange=32 ;
for (int i=1 ; i<=nInitRange ; i++) {
Int_t hi = (i*nbins)/nInitRange -1 ;
Int_t lo = lastHi ;
addRange(lo,hi,nbins) ;
lastHi=hi ;
}
// Perform numeric integration
for (int i=1 ; ix.max()-_self->x.min())/nbins ;
for (int i=0 ; iget(i) ;
if (cdfmode) {
hist()->set(_ay[i]/_ay[nbins-1]) ;
} else {
hist()->set(_ay[i]*binv) ;
}
}
if (cdfmode) {
func()->setCdfBoundaries(kTRUE) ;
}
_self->x = xsave ;
}
//_____________________________________________________________________________
void RooNumRunningInt::RICacheElem::addRange(Int_t ixlo, Int_t ixhi, Int_t nbins)
{
// Fill all empty histogram bins in the range [ixlo,ixhi] where nbins is the
// total number of histogram bins. This method samples the mid-point of the
// range and if the mid-point value is within small tolerance of the interpolated
// mid-point value fills all remaining elements through linear interpolation.
// If the tolerance is exceeded, the algorithm is recursed on the two subranges
// [xlo,xmid] and [xmid,xhi]
// Add first and last point, if not there already
if (_ay[ixlo]<0) {
addPoint(ixlo) ;
}
if (_ay[ixhi]<0) {
addPoint(ixhi) ;
}
// Terminate here if there is no gap
if (ixhi-ixlo==1) {
return ;
}
// If gap size is one, simply fill gap and return
if (ixhi-ixlo==2) {
addPoint(ixlo+1) ;
return ;
}
// Add mid-point
Int_t ixmid = (ixlo+ixhi)/2 ;
addPoint(ixmid) ;
// Calculate difference of mid-point w.r.t interpolated value
Double_t yInt = _ay[ixlo] + (_ay[ixhi]-_ay[ixlo])*(ixmid-ixlo)/(ixhi-ixlo) ;
// If relative deviation is greater than tolerance divide and iterate
if (fabs(yInt-_ay[ixmid])*(_ax[nbins-1]-_ax[0])>1e-6) {
addRange(ixlo,ixmid,nbins) ;
addRange(ixmid,ixhi,nbins) ;
} else {
for (Int_t j=ixlo+1 ; jget(ix) ;
_self->x = _xx->getVal() ;
_ay[ix] = _self->func.arg().getVal(*_xx) ;
}
//_____________________________________________________________________________
void RooNumRunningInt::fillCacheObject(RooAbsCachedReal::FuncCacheElem& cache) const
{
// Fill the cache object by calling its calculate() method
RICacheElem& riCache = static_cast(cache) ;
riCache.calculate(kFALSE) ;
}
//_____________________________________________________________________________
RooArgSet* RooNumRunningInt::actualObservables(const RooArgSet& /*nset*/) const
{
// Return observable in nset to be cached by RooAbsCachedPdf
// this is always the x observable that is integrated
RooArgSet* ret = new RooArgSet ;
ret->add(x.arg()) ;
return ret ;
}
//_____________________________________________________________________________
RooArgSet* RooNumRunningInt::actualParameters(const RooArgSet& /*nset*/) const
{
// Return the parameters of the cache created by RooAbsCachedPdf.
// These are always the input functions parameter, but never the
// integrated variable x.
RooArgSet* ret = func.arg().getParameters(RooArgSet()) ;
ret->remove(x.arg(),kTRUE,kTRUE) ;
return ret ;
}
//_____________________________________________________________________________
RooAbsCachedReal::FuncCacheElem* RooNumRunningInt::createCache(const RooArgSet* nset) const
{
// Create custom cache element for running integral calculations
return new RICacheElem(*const_cast(this),nset) ;
}
//_____________________________________________________________________________
Double_t RooNumRunningInt::evaluate() const
{
// Dummy function that is never called
cout << "RooNumRunningInt::evaluate(" << GetName() << ")" << endl ;
return 0 ;
}