/*****************************************************************************
* 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 RooProjectedPdf is a RooAbsPdf implementation that represent a projection
// of a given input p.d.f and the object returned by RooAbsPdf::createProjection.
//
// The actual projection integral for it value and normalization are
// calculated on the fly in getVal() once the normalization observables are known.
// Class RooProjectedPdf can cache projected p.d.f.s for multiple normalization
// observables simultaneously.
//
// The createProjection() method of RooProjectedPdf is overloaded and will
// return a new RooProjectedPdf that performs the projection of itself
// and the requested additional projections in one integration step
// The performance of
f->createProjection(x)->createProjection(y)
// is therefore identical to that of f->createProjection(RooArgSet(x,y))
// END_HTML
//
#include "Riostream.h"
#include "RooFit.h"
#include "RooProjectedPdf.h"
#include "RooMsgService.h"
#include "RooAbsReal.h"
#include "RooRealVar.h"
#include "RooNameReg.h"
using namespace std;
ClassImp(RooProjectedPdf)
;
////////////////////////////////////////////////////////////////////////////////
/// Default constructor
RooProjectedPdf::RooProjectedPdf() : _curNormSet(0)
{
}
////////////////////////////////////////////////////////////////////////////////
/// Construct projection of input pdf '_intpdf' over observables 'intObs'
RooProjectedPdf::RooProjectedPdf(const char *name, const char *title, RooAbsReal& _intpdf, const RooArgSet& intObs) :
RooAbsPdf(name,title),
intpdf("!IntegratedPdf","intpdf",this,_intpdf,kFALSE,kFALSE),
intobs("!IntegrationObservables","intobs",this,kFALSE,kFALSE),
deps("!Dependents","deps",this,kTRUE,kTRUE),
_cacheMgr(this,10)
{
intobs.add(intObs) ;
// Add all other dependens of projected p.d.f. directly
RooArgSet* tmpdeps = _intpdf.getParameters(intObs) ;
deps.add(*tmpdeps) ;
delete tmpdeps ;
}
////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
RooProjectedPdf::RooProjectedPdf(const RooProjectedPdf& other, const char* name) :
RooAbsPdf(other,name),
intpdf("!IntegratedPdf",this,other.intpdf),
intobs("!IntegrationObservable",this,other.intobs),
deps("!Dependents",this,other.deps),
_cacheMgr(other._cacheMgr,this)
{
}
////////////////////////////////////////////////////////////////////////////////
/// Special version of getVal() overrides RooAbsReal::getValF() to save value of current normalization set
Double_t RooProjectedPdf::getValV(const RooArgSet* set) const
{
_curNormSet = (RooArgSet*)set ;
return RooAbsPdf::getValV(set) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Evaluate projected p.d.f
Double_t RooProjectedPdf::evaluate() const
{
// Calculate current unnormalized value of object
int code ;
const RooAbsReal* proj = getProjection(&intobs,_curNormSet,0,code) ;
return proj->getVal() ;
}
////////////////////////////////////////////////////////////////////////////////
/// Retrieve object representing projection integral of input p.d.f
/// over observables iset, while normalizing over observables
/// nset. The code argument returned by reference is the unique code
/// defining this particular projection configuration
const RooAbsReal* RooProjectedPdf::getProjection(const RooArgSet* iset, const RooArgSet* nset, const char* rangeName, int& code) const
{
// Check if this configuration was created before
Int_t sterileIdx(-1) ;
CacheElem* cache = (CacheElem*) _cacheMgr.getObj(iset,nset,&sterileIdx,RooNameReg::ptr(rangeName)) ;
if (cache) {
code = _cacheMgr.lastIndex() ;
return static_cast(cache->_projection);
}
RooArgSet* nset2 = intpdf.arg().getObservables(*nset) ;
if (iset) {
nset2->add(*iset) ;
}
RooAbsReal* proj = intpdf.arg().createIntegral(iset?*iset:RooArgSet(),nset2,0,rangeName) ;
delete nset2 ;
cache = new CacheElem ;
cache->_projection = proj ;
code = _cacheMgr.setObj(iset,nset,(RooAbsCacheElement*)cache,RooNameReg::ptr(rangeName)) ;
coutI(Integration) << "RooProjectedPdf::getProjection(" << GetName() << ") creating new projection " << proj->GetName() << " with code " << code << endl ;
return proj ;
}
////////////////////////////////////////////////////////////////////////////////
/// Special version of RooAbsReal::createProjection that deals with
/// projections of projections. Instead of integrating twice, a new
/// RooProjectedPdf is returned that is configured to perform the
/// complete integration in one step
RooAbsPdf* RooProjectedPdf::createProjection(const RooArgSet& iset)
{
RooArgSet combiset(iset) ;
combiset.add(intobs) ;
return static_cast( const_cast(intpdf.arg()) ).createProjection(combiset) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Force RooRealIntegral to relegate integration of all observables to internal logic
Bool_t RooProjectedPdf::forceAnalyticalInt(const RooAbsArg& /*dep*/) const
{
return kTRUE ;
}
////////////////////////////////////////////////////////////////////////////////
/// Mark all requested variables as internally integrated
Int_t RooProjectedPdf::getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars, const RooArgSet* normSet, const char* rangeName) const
{
analVars.add(allVars) ;
// Create the appropriate integral
int code ;
RooArgSet allVars2(allVars) ;
allVars2.add(intobs) ;
getProjection(&allVars2,normSet,rangeName,code) ;
return code+1 ;
}
////////////////////////////////////////////////////////////////////////////////
/// Return analytical integral represent by appropriate element of projection cache
Double_t RooProjectedPdf::analyticalIntegralWN(Int_t code, const RooArgSet* /*normSet*/, const char* rangeName) const
{
CacheElem *cache = (CacheElem*) _cacheMgr.getObjByIndex(code-1) ;
if (cache) {
Double_t ret= cache->_projection->getVal() ;
return ret ;
} else {
RooArgSet* vars = getParameters(RooArgSet()) ;
vars->add(intobs) ;
RooArgSet* iset = _cacheMgr.nameSet1ByIndex(code-1)->select(*vars) ;
RooArgSet* nset = _cacheMgr.nameSet2ByIndex(code-1)->select(*vars) ;
Int_t code2(-1) ;
const RooAbsReal* proj = getProjection(iset,nset,rangeName,code2) ;
delete vars ;
delete nset ;
delete iset ;
Double_t ret = proj->getVal() ;
return ret ;
}
}
////////////////////////////////////////////////////////////////////////////////
/// No internal generator is implemented
Int_t RooProjectedPdf::getGenerator(const RooArgSet& /*directVars*/, RooArgSet& /*generateVars*/, Bool_t /*staticInitOK*/) const
{
return 0 ;
}
////////////////////////////////////////////////////////////////////////////////
/// No internal generator is implemented
void RooProjectedPdf::generateEvent(Int_t /*code*/)
{
return;
}
////////////////////////////////////////////////////////////////////////////////
/// Intercept a server redirection all and update list of dependents if necessary
/// Specifically update the set proxy 'deps' which introduces the dependency
/// on server value dirty flags of ourselves
Bool_t RooProjectedPdf::redirectServersHook(const RooAbsCollection& newServerList, Bool_t /*mustReplaceAll*/,
Bool_t /*nameChange*/, Bool_t /*isRecursive*/)
{
// Redetermine explicit list of dependents if intPdf is being replaced
RooAbsArg* newPdf = newServerList.find(intpdf.arg().GetName()) ;
if (newPdf) {
// Determine if set of dependens of new p.d.f is different from old p.d.f.
RooArgSet olddeps(deps) ;
RooArgSet* newdeps = newPdf->getParameters(intobs) ;
RooArgSet* common = (RooArgSet*) newdeps->selectCommon(deps) ;
newdeps->remove(*common,kTRUE,kTRUE) ;
olddeps.remove(*common,kTRUE,kTRUE) ;
// If so, adjust composition of deps Listproxy
if (newdeps->getSize()>0) {
deps.add(*newdeps) ;
}
if (olddeps.getSize()>0) {
deps.remove(olddeps,kTRUE,kTRUE) ;
}
delete common ;
delete newdeps ;
}
return kFALSE ;
}
////////////////////////////////////////////////////////////////////////////////
/// Return RooAbsArg elements contained in projection cache element.
RooArgList RooProjectedPdf::CacheElem::containedArgs(Action)
{
RooArgList ret(*_projection) ;
return ret ;
}
////////////////////////////////////////////////////////////////////////////////
/// Customized printing of arguments of a RooRealIntegral to more intuitively reflect the contents of the
/// integration operation
void RooProjectedPdf::printMetaArgs(ostream& os) const
{
os << "Int " << intpdf.arg().GetName() ;
os << " d" ;
os << intobs ;
os << " " ;
}
////////////////////////////////////////////////////////////////////////////////
/// Print contents of cache when printing self as part of object tree
void RooProjectedPdf::CacheElem::printCompactTreeHook(ostream& os, const char* indent, Int_t curElem, Int_t maxElem)
{
if (curElem==0) {
os << indent << "RooProjectedPdf begin projection cache" << endl ;
}
TString indent2(indent) ;
indent2 += Form("[%d] ",curElem) ;
_projection->printCompactTree(os,indent2) ;
if(curElem==maxElem) {
os << indent << "RooProjectedPdf end projection cache" << endl ;
}
}