#include "RooFit.h"
#include "RooMsgService.h"
#include "Riostream.h"
#include "Riostream.h"
#include "RooAbsAnaConvPdf.h"
#include "RooResolutionModel.h"
#include "RooRealVar.h"
#include "RooFormulaVar.h"
#include "RooConvGenContext.h"
#include "RooGenContext.h"
#include "RooTruthModel.h"
#include "RooConvCoefVar.h"
#include "RooNameReg.h"
using namespace std;
ClassImp(RooAbsAnaConvPdf)
;
RooAbsAnaConvPdf::RooAbsAnaConvPdf() :
_isCopy(kFALSE),
_convNormSet(0),
_convSetIter(_convSet.createIterator())
{
}
RooAbsAnaConvPdf::RooAbsAnaConvPdf(const char *name, const char *title,
const RooResolutionModel& model, RooRealVar& cVar) :
RooAbsPdf(name,title), _isCopy(kFALSE),
_model("!model","Original resolution model",this,(RooResolutionModel&)model,kFALSE,kFALSE),
_convVar("!convVar","Convolution variable",this,cVar,kFALSE,kFALSE),
_convSet("!convSet","Set of resModel X basisFunc convolutions",this),
_convNormSet(0), _convSetIter(_convSet.createIterator()),
_coefNormMgr(this,10),
_codeReg(10)
{
_convNormSet = new RooArgSet(cVar,"convNormSet") ;
_model.absArg()->setAttribute("NOCacheAndTrack") ;
}
RooAbsAnaConvPdf::RooAbsAnaConvPdf(const RooAbsAnaConvPdf& other, const char* name) :
RooAbsPdf(other,name), _isCopy(kTRUE),
_model("!model",this,other._model),
_convVar("!convVar",this,other._convVar),
_convSet("!convSet",this,other._convSet),
_basisList(other._basisList),
_convNormSet(other._convNormSet? new RooArgSet(*other._convNormSet) : new RooArgSet() ),
_convSetIter(_convSet.createIterator()),
_coefNormMgr(other._coefNormMgr,this),
_codeReg(other._codeReg)
{
if (_model.absArg()) {
_model.absArg()->setAttribute("NOCacheAndTrack") ;
}
}
RooAbsAnaConvPdf::~RooAbsAnaConvPdf()
{
if (_convNormSet) {
delete _convNormSet ;
}
delete _convSetIter ;
if (!_isCopy) {
TIterator* iter = _convSet.createIterator() ;
RooAbsArg* arg ;
while (((arg = (RooAbsArg*)iter->Next()))) {
_convSet.remove(*arg) ;
delete arg ;
}
delete iter ;
}
}
Int_t RooAbsAnaConvPdf::declareBasis(const char* expression, const RooArgList& params)
{
if (_isCopy) {
coutE(InputArguments) << "RooAbsAnaConvPdf::declareBasis(" << GetName() << "): ERROR attempt to "
<< " declare basis functions in a copied RooAbsAnaConvPdf" << endl ;
return -1 ;
}
if (!((RooResolutionModel*)_model.absArg())->isBasisSupported(expression)) {
coutE(InputArguments) << "RooAbsAnaConvPdf::declareBasis(" << GetName() << "): resolution model "
<< _model.absArg()->GetName()
<< " doesn't support basis function " << expression << endl ;
return -1 ;
}
RooArgList basisArgs(_convVar.arg()) ;
basisArgs.add(params) ;
TString basisName(expression) ;
TIterator* iter = basisArgs.createIterator() ;
RooAbsArg* arg ;
while(((arg=(RooAbsArg*)iter->Next()))) {
basisName.Append("_") ;
basisName.Append(arg->GetName()) ;
}
delete iter ;
RooFormulaVar* basisFunc = new RooFormulaVar(basisName,expression,basisArgs) ;
basisFunc->setAttribute("RooWorkspace::Recycle") ;
basisFunc->setAttribute("NOCacheAndTrack") ;
basisFunc->setOperMode(operMode()) ;
_basisList.addOwned(*basisFunc) ;
RooAbsReal* conv = ((RooResolutionModel*)_model.absArg())->convolution(basisFunc,this) ;
if (!conv) {
coutE(InputArguments) << "RooAbsAnaConvPdf::declareBasis(" << GetName() << "): unable to construct convolution with basis function '"
<< expression << "'" << endl ;
return -1 ;
}
_convSet.add(*conv) ;
return _convSet.index(conv) ;
}
Bool_t RooAbsAnaConvPdf::changeModel(const RooResolutionModel& newModel)
{
TIterator* cIter = _convSet.createIterator() ;
RooResolutionModel* conv ;
RooArgList newConvSet ;
Bool_t allOK(kTRUE) ;
while(((conv=(RooResolutionModel*)cIter->Next()))) {
RooResolutionModel* newConv = newModel.convolution((RooFormulaVar*)&conv->basis(),this) ;
if (!newConvSet.add(*newConv)) {
allOK = kFALSE ;
break ;
}
}
delete cIter ;
if (!allOK) {
TIterator* iter = newConvSet.createIterator() ;
while(((conv=(RooResolutionModel*)iter->Next()))) delete conv ;
delete iter ;
return kTRUE ;
}
_convSet.removeAll() ;
_convSet.addOwned(newConvSet) ;
_model.setArg((RooResolutionModel&)newModel) ;
return kFALSE ;
}
RooAbsGenContext* RooAbsAnaConvPdf::genContext(const RooArgSet &vars, const RooDataSet *prototype,
const RooArgSet* auxProto, Bool_t verbose) const
{
RooResolutionModel* conv = dynamic_cast<RooResolutionModel*>(_model.absArg());
assert(conv);
RooArgSet* modelDep = _model.absArg()->getObservables(&vars) ;
modelDep->remove(*convVar(),kTRUE,kTRUE) ;
Int_t numAddDep = modelDep->getSize() ;
delete modelDep ;
RooArgSet dummy ;
Bool_t pdfCanDir = (getGenerator(*convVar(),dummy) != 0) ;
Bool_t resCanDir = conv && (conv->getGenerator(*convVar(),dummy)!=0) && conv->isDirectGenSafe(*convVar()) ;
if (numAddDep>0 || !pdfCanDir || !resCanDir) {
string reason ;
if (numAddDep>0) reason += "Resolution model has more onservables that the convolution variable. " ;
if (!pdfCanDir) reason += "PDF does not support internal generation of convolution observable. " ;
if (!resCanDir) reason += "Resolution model does not support internal generation of convolution observable. " ;
coutI(Generation) << "RooAbsAnaConvPdf::genContext(" << GetName() << ") Using regular accept/reject generator for convolution p.d.f because: " << reason.c_str() << endl ;
return new RooGenContext(*this,vars,prototype,auxProto,verbose) ;
}
RooAbsGenContext* context = conv->modelGenContext(*this, vars, prototype, auxProto, verbose);
if (context) return context;
return new RooConvGenContext(*this,vars,prototype,auxProto,verbose) ;
}
Bool_t RooAbsAnaConvPdf::isDirectGenSafe(const RooAbsArg& arg) const
{
if (!TString(_convVar.absArg()->GetName()).CompareTo(arg.GetName()) &&
dynamic_cast<RooTruthModel*>(_model.absArg())) {
return kTRUE ;
}
return RooAbsPdf::isDirectGenSafe(arg) ;
}
const RooRealVar* RooAbsAnaConvPdf::convVar() const
{
RooResolutionModel* conv = (RooResolutionModel*) _convSet.at(0) ;
if (!conv) return 0 ;
return &conv->convVar() ;
}
Double_t RooAbsAnaConvPdf::evaluate() const
{
Double_t result(0) ;
_convSetIter->Reset() ;
RooAbsPdf* conv ;
Int_t index(0) ;
while(((conv=(RooAbsPdf*)_convSetIter->Next()))) {
Double_t coef = coefficient(index++) ;
if (coef!=0.) {
Double_t c = conv->getVal(0) ;
Double_t r = coef ;
cxcoutD(Eval) << "RooAbsAnaConvPdf::evaluate(" << GetName() << ") val += coef*conv [" << index-1 << "/"
<< _convSet.getSize() << "] coef = " << r << " conv = " << c << endl ;
result += conv->getVal(0)*coef ;
} else {
cxcoutD(Eval) << "RooAbsAnaConvPdf::evaluate(" << GetName() << ") [" << index-1 << "/" << _convSet.getSize() << "] coef = 0" << endl ;
}
}
return result ;
}
Int_t RooAbsAnaConvPdf::getAnalyticalIntegralWN(RooArgSet& allVars,
RooArgSet& analVars, const RooArgSet* normSet2, const char* ) const
{
if (allVars.getSize()==0) return 0 ;
if (_forceNumInt) return 0 ;
RooArgSet* allDeps = getObservables(allVars) ;
RooArgSet* normSet = normSet2 ? getObservables(normSet2) : 0 ;
RooAbsArg *arg ;
RooResolutionModel *conv ;
RooArgSet* intSetAll = new RooArgSet(*allDeps,"intSetAll") ;
RooArgSet* intCoefSet = new RooArgSet("intCoefSet") ;
RooArgSet* intConvSet = new RooArgSet("intConvSet") ;
TIterator* varIter = intSetAll->createIterator() ;
TIterator* convIter = _convSet.createIterator() ;
while(((arg=(RooAbsArg*) varIter->Next()))) {
Bool_t ok(kTRUE) ;
convIter->Reset() ;
while(((conv=(RooResolutionModel*) convIter->Next()))) {
if (conv->dependsOn(*arg)) ok=kFALSE ;
}
if (ok) {
intCoefSet->add(*arg) ;
} else {
intConvSet->add(*arg) ;
}
}
delete varIter ;
RooArgSet* normCoefSet = new RooArgSet("normCoefSet") ;
RooArgSet* normConvSet = new RooArgSet("normConvSet") ;
RooArgSet* normSetAll = normSet ? (new RooArgSet(*normSet,"normSetAll")) : 0 ;
if (normSetAll) {
varIter = normSetAll->createIterator() ;
while(((arg=(RooAbsArg*) varIter->Next()))) {
Bool_t ok(kTRUE) ;
convIter->Reset() ;
while(((conv=(RooResolutionModel*) convIter->Next()))) {
if (conv->dependsOn(*arg)) ok=kFALSE ;
}
if (ok) {
normCoefSet->add(*arg) ;
} else {
normConvSet->add(*arg) ;
}
}
delete varIter ;
}
delete convIter ;
if (intCoefSet->getSize()==0) {
delete intCoefSet ; intCoefSet=0 ;
}
if (intConvSet->getSize()==0) {
delete intConvSet ; intConvSet=0 ;
}
if (normCoefSet->getSize()==0) {
delete normCoefSet ; normCoefSet=0 ;
}
if (normConvSet->getSize()==0) {
delete normConvSet ; normConvSet=0 ;
}
Int_t masterCode(0) ;
std::vector<Int_t> tmp(1, 0) ;
masterCode = _codeReg.store(tmp, intCoefSet, intConvSet, normCoefSet, normConvSet) + 1 ;
analVars.add(*allDeps) ;
delete allDeps ;
if (normSet) delete normSet ;
if (normSetAll) delete normSetAll ;
delete intSetAll ;
return masterCode ;
}
Double_t RooAbsAnaConvPdf::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* rangeName) const
{
if (code==0) return getVal(normSet) ;
RooArgSet *intCoefSet, *intConvSet, *normCoefSet, *normConvSet ;
_codeReg.retrieve(code-1,intCoefSet,intConvSet,normCoefSet,normConvSet) ;
RooResolutionModel* conv ;
Int_t index(0) ;
Double_t answer(0) ;
_convSetIter->Reset() ;
if (normCoefSet==0&&normConvSet==0) {
Double_t integral(0) ;
const TNamed *_rangeName = RooNameReg::ptr(rangeName);
while(((conv=(RooResolutionModel*)_convSetIter->Next()))) {
Double_t coef = getCoefNorm(index++,intCoefSet,_rangeName) ;
if (coef!=0) {
integral += coef*(_rangeName ? conv->getNormObj(0,intConvSet,_rangeName)->getVal() : conv->getNorm(intConvSet) ) ;
cxcoutD(Eval) << "RooAbsAnaConv::aiWN(" << GetName() << ") [" << index-1 << "] integral += " << conv->getNorm(intConvSet) << endl ;
}
}
answer = integral ;
} else {
Double_t integral(0) ;
Double_t norm(0) ;
const TNamed *_rangeName = RooNameReg::ptr(rangeName);
while(((conv=(RooResolutionModel*)_convSetIter->Next()))) {
Double_t coefInt = getCoefNorm(index,intCoefSet,_rangeName) ;
if (coefInt!=0) {
Double_t term = (_rangeName ? conv->getNormObj(0,intConvSet,_rangeName)->getVal() : conv->getNorm(intConvSet) ) ;
integral += coefInt*term ;
}
Double_t coefNorm = getCoefNorm(index,normCoefSet) ;
if (coefNorm!=0) {
Double_t term = conv->getNorm(normConvSet) ;
norm += coefNorm*term ;
}
index++ ;
}
answer = integral/norm ;
}
return answer ;
}
Int_t RooAbsAnaConvPdf::getCoefAnalyticalIntegral(Int_t , RooArgSet& , RooArgSet& , const char* ) const
{
return 0 ;
}
Double_t RooAbsAnaConvPdf::coefAnalyticalIntegral(Int_t coef, Int_t code, const char* ) const
{
if (code==0) return coefficient(coef) ;
coutE(InputArguments) << "RooAbsAnaConvPdf::coefAnalyticalIntegral(" << GetName() << ") ERROR: unrecognized integration code: " << code << endl ;
assert(0) ;
return 1 ;
}
Bool_t RooAbsAnaConvPdf::forceAnalyticalInt(const RooAbsArg& ) const
{
return kTRUE ;
}
Double_t RooAbsAnaConvPdf::getCoefNorm(Int_t coefIdx, const RooArgSet* nset, const TNamed* rangeName) const
{
if (nset==0) return coefficient(coefIdx) ;
CacheElem* cache = (CacheElem*) _coefNormMgr.getObj(nset,0,0,rangeName) ;
if (!cache) {
cache = new CacheElem ;
Int_t i ;
makeCoefVarList(cache->_coefVarList) ;
for (i=0 ; i<cache->_coefVarList.getSize() ; i++) {
RooAbsReal* coefInt = static_cast<RooAbsReal&>(*cache->_coefVarList.at(i)).createIntegral(*nset,RooNameReg::str(rangeName)) ;
cache->_normList.addOwned(*coefInt) ;
}
_coefNormMgr.setObj(nset,0,cache,rangeName) ;
}
return ((RooAbsReal*)cache->_normList.at(coefIdx))->getVal() ;
}
void RooAbsAnaConvPdf::makeCoefVarList(RooArgList& varList) const
{
for (Int_t i=0 ; i<_convSet.getSize() ; i++) {
RooArgSet* cvars = coefVars(i) ;
RooAbsReal* coefVar = new RooConvCoefVar(Form("%s_coefVar_%d",GetName(),i),"coefVar",*this,i,cvars) ;
varList.addOwned(*coefVar) ;
delete cvars ;
}
}
RooArgSet* RooAbsAnaConvPdf::coefVars(Int_t ) const
{
RooArgSet* cVars = getParameters((RooArgSet*)0) ;
TIterator* iter = cVars->createIterator() ;
RooAbsArg* arg ;
Int_t i ;
while(((arg=(RooAbsArg*)iter->Next()))) {
for (i=0 ; i<_convSet.getSize() ; i++) {
if (_convSet.at(i)->dependsOn(*arg)) {
cVars->remove(*arg,kTRUE) ;
}
}
}
delete iter ;
return cVars ;
}
void RooAbsAnaConvPdf::printMultiline(ostream& os, Int_t contents, Bool_t verbose, TString indent) const
{
RooAbsPdf::printMultiline(os,contents,verbose,indent);
os << indent << "--- RooAbsAnaConvPdf ---" << endl;
TIterator* iter = _convSet.createIterator() ;
RooResolutionModel* conv ;
while (((conv=(RooResolutionModel*)iter->Next()))) {
conv->printMultiline(os,contents,verbose,indent) ;
}
}