/*****************************************************************************
 * Project: RooFit                                                           *
 * Package: RooFitCore                                                       *
 * @(#)root/roofitcore:$Id$
 * Authors:                                                                  *
 *   WV, Wouter Verkerke, NIKHEF
 *   GR, Gerhard Raven, NIKHEF/VU                                            *
 *                                                                           *
 * 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
// The class RooEffProd implements the product of a PDF with an efficiency function.
// The normalization integral of the product is calculated numerically, but the
// event generation is handled by a specialized generator context that implements
// the event generation in a more efficient for cases where the PDF has an internal
// generator that is smarter than accept reject. 
// END_HTML
//

#include "RooFit.h"
#include "RooEffProd.h"
#include "RooEffGenContext.h"
#include "RooNameReg.h"
#include "RooRealVar.h"

using namespace std;

ClassImp(RooEffProd)
  ;



//_____________________________________________________________________________
RooEffProd::RooEffProd(const char *name, const char *title, 
                             RooAbsPdf& inPdf, RooAbsReal& inEff) :
  RooAbsPdf(name,title),
  _cacheMgr(this,10),
  _pdf("pdf","pre-efficiency pdf", this,inPdf),
  _eff("eff","efficiency function",this,inEff),
  _nset(0),
  _fixedNset(0)
{  
  // Constructor of a a production of p.d.f inPdf with efficiency
  // function inEff.
}




//_____________________________________________________________________________
RooEffProd::RooEffProd(const RooEffProd& other, const char* name) : 
  RooAbsPdf(other, name),
  _cacheMgr(other._cacheMgr,this),
  _pdf("pdf",this,other._pdf),
  _eff("acc",this,other._eff),
  _nset(0),
  _fixedNset(0) 
{
  // Copy constructor
}




//_____________________________________________________________________________
RooEffProd::~RooEffProd() 
{
  // Destructor
}



//_____________________________________________________________________________
Double_t RooEffProd::getValV(const RooArgSet* set) const 
{  
  // Return p.d.f. value normalized over given set of observables

  _nset = _fixedNset ? _fixedNset : set ;
  return RooAbsPdf::getValV(set) ;
}




//_____________________________________________________________________________
Double_t RooEffProd::evaluate() const
{
  // Calculate and return 'raw' unnormalized value of p.d.f

  return eff()->getVal() * pdf()->getVal(_nset);
}



//_____________________________________________________________________________
RooAbsGenContext* RooEffProd::genContext(const RooArgSet &vars, const RooDataSet *prototype,
                                            const RooArgSet* auxProto, Bool_t verbose) const
{
  // Return specialized generator context for RooEffProds that implements generation
  // in a more efficient way than can be done for generic correlated products
  
  assert(pdf()!=0);
  assert(eff()!=0);
  return new RooEffGenContext(*this,*pdf(),*eff(),vars,prototype,auxProto,verbose) ;
}





//_____________________________________________________________________________
Int_t RooEffProd::getAnalyticalIntegralWN(RooArgSet& allVars, RooArgSet& analVars, 
					  const RooArgSet* normSet, const char* rangeName) const 
{
  // Return internal integration capabilities of the p.d.f. Given a set 'allVars' for which
  // integration is requested, returned the largest subset for which internal (analytical)
  // integration is implemented (in argument analVars). The return value is a unique integer
  // code that identifies the integration configuration (integrated observables and range name).
  //
  // This implementation in RooEffProd catches all integrals without normalization and reroutes them
  // through a custom integration routine that properly accounts for the use of normalized p.d.f.
  // in the evaluate() expression, which breaks the default RooAbsPdf normalization handling

  
  // No special handling required if a normalization set is given
  if (normSet && normSet->getSize()>0) {    
    return 0 ;
  }
  // No special handling required if running with a fixed normalization set
  if (_fixedNset) {
    return 0 ;
  }

  // Special handling of integrals w/o normalization set. We need to pass _a_ normalization set
  // to pdf().getVal(nset) in evaluate() because for certain p.d.fs the shape depends on the
  // chosen normalization set. This functions correctly automatically for plain getVal() calls,
  // however when the (numeric) normalization is calculated, getVal() is called without any normalization
  // set causing the normalization to be calculated for a possibly different shape. To fix that
  // integrals over a RooEffProd without normalization setup are explicitly handled here. These integrals
  // are calculated using a clone of the RooEffProd that has a fixed normalization set passed to the
  // underlying p.d.f regardless of the normalization set passed to getVal(). Here the set of observables
  // over which is integrated is passed.

  // Declare that we can analytically integrate all requested observables
  analVars.add(allVars) ;

  // Check if cache was previously created
  Int_t sterileIndex(-1) ;
  CacheElem* cache = (CacheElem*) _cacheMgr.getObj(&allVars,&allVars,&sterileIndex,RooNameReg::ptr(rangeName)) ;
  if (cache) {
    return _cacheMgr.lastIndex()+1;
  }

  // Construct cache with clone of p.d.f that has fixed normalization set that is passed to input pdf
  cache = new CacheElem ;
  cache->_intObs.addClone(allVars) ;
  cache->_clone = (RooEffProd*) clone(Form("%s_clone",GetName())) ;
  cache->_clone->_fixedNset = &cache->_intObs ;
  cache->_int = cache->_clone->createIntegral(cache->_intObs,rangeName) ;

  // Store cache and return index as code
  Int_t code = _cacheMgr.setObj(&allVars,&allVars,(RooAbsCacheElement*)cache,RooNameReg::ptr(rangeName)) ; 

  return code+1 ;
}





//_____________________________________________________________________________
Double_t RooEffProd::analyticalIntegralWN(Int_t code, const RooArgSet* normSet, const char* /*rangeName*/) const 
{
  // Return value of integral identified by code, which should be a return value of getAnalyticalIntegralWN,
  // Code zero is always handled and signifies no integration (return value is normalized p.d.f. value)

  // Return analytical integral defined by given scenario code

  // No integration scenario
  if (code==0) {
    return getVal(normSet) ;
  }

  // Partial integration scenarios
  CacheElem* cache = (CacheElem*) _cacheMgr.getObjByIndex(code-1) ;

  return cache->_int->getVal() ;
}




//_____________________________________________________________________________
RooArgList RooEffProd::CacheElem::containedArgs(Action) 
{
  // Report all RooAbsArg derived objects contained in Cache Element (used in function optimization and
  // and server redirect management of the cache)

  RooArgList ret(_intObs) ;
  ret.add(*_int) ;
  ret.add(*_clone) ;
  return ret ;
}
 RooEffProd.cxx:1
 RooEffProd.cxx:2
 RooEffProd.cxx:3
 RooEffProd.cxx:4
 RooEffProd.cxx:5
 RooEffProd.cxx:6
 RooEffProd.cxx:7
 RooEffProd.cxx:8
 RooEffProd.cxx:9
 RooEffProd.cxx:10
 RooEffProd.cxx:11
 RooEffProd.cxx:12
 RooEffProd.cxx:13
 RooEffProd.cxx:14
 RooEffProd.cxx:15
 RooEffProd.cxx:16
 RooEffProd.cxx:17
 RooEffProd.cxx:18
 RooEffProd.cxx:19
 RooEffProd.cxx:20
 RooEffProd.cxx:21
 RooEffProd.cxx:22
 RooEffProd.cxx:23
 RooEffProd.cxx:24
 RooEffProd.cxx:25
 RooEffProd.cxx:26
 RooEffProd.cxx:27
 RooEffProd.cxx:28
 RooEffProd.cxx:29
 RooEffProd.cxx:30
 RooEffProd.cxx:31
 RooEffProd.cxx:32
 RooEffProd.cxx:33
 RooEffProd.cxx:34
 RooEffProd.cxx:35
 RooEffProd.cxx:36
 RooEffProd.cxx:37
 RooEffProd.cxx:38
 RooEffProd.cxx:39
 RooEffProd.cxx:40
 RooEffProd.cxx:41
 RooEffProd.cxx:42
 RooEffProd.cxx:43
 RooEffProd.cxx:44
 RooEffProd.cxx:45
 RooEffProd.cxx:46
 RooEffProd.cxx:47
 RooEffProd.cxx:48
 RooEffProd.cxx:49
 RooEffProd.cxx:50
 RooEffProd.cxx:51
 RooEffProd.cxx:52
 RooEffProd.cxx:53
 RooEffProd.cxx:54
 RooEffProd.cxx:55
 RooEffProd.cxx:56
 RooEffProd.cxx:57
 RooEffProd.cxx:58
 RooEffProd.cxx:59
 RooEffProd.cxx:60
 RooEffProd.cxx:61
 RooEffProd.cxx:62
 RooEffProd.cxx:63
 RooEffProd.cxx:64
 RooEffProd.cxx:65
 RooEffProd.cxx:66
 RooEffProd.cxx:67
 RooEffProd.cxx:68
 RooEffProd.cxx:69
 RooEffProd.cxx:70
 RooEffProd.cxx:71
 RooEffProd.cxx:72
 RooEffProd.cxx:73
 RooEffProd.cxx:74
 RooEffProd.cxx:75
 RooEffProd.cxx:76
 RooEffProd.cxx:77
 RooEffProd.cxx:78
 RooEffProd.cxx:79
 RooEffProd.cxx:80
 RooEffProd.cxx:81
 RooEffProd.cxx:82
 RooEffProd.cxx:83
 RooEffProd.cxx:84
 RooEffProd.cxx:85
 RooEffProd.cxx:86
 RooEffProd.cxx:87
 RooEffProd.cxx:88
 RooEffProd.cxx:89
 RooEffProd.cxx:90
 RooEffProd.cxx:91
 RooEffProd.cxx:92
 RooEffProd.cxx:93
 RooEffProd.cxx:94
 RooEffProd.cxx:95
 RooEffProd.cxx:96
 RooEffProd.cxx:97
 RooEffProd.cxx:98
 RooEffProd.cxx:99
 RooEffProd.cxx:100
 RooEffProd.cxx:101
 RooEffProd.cxx:102
 RooEffProd.cxx:103
 RooEffProd.cxx:104
 RooEffProd.cxx:105
 RooEffProd.cxx:106
 RooEffProd.cxx:107
 RooEffProd.cxx:108
 RooEffProd.cxx:109
 RooEffProd.cxx:110
 RooEffProd.cxx:111
 RooEffProd.cxx:112
 RooEffProd.cxx:113
 RooEffProd.cxx:114
 RooEffProd.cxx:115
 RooEffProd.cxx:116
 RooEffProd.cxx:117
 RooEffProd.cxx:118
 RooEffProd.cxx:119
 RooEffProd.cxx:120
 RooEffProd.cxx:121
 RooEffProd.cxx:122
 RooEffProd.cxx:123
 RooEffProd.cxx:124
 RooEffProd.cxx:125
 RooEffProd.cxx:126
 RooEffProd.cxx:127
 RooEffProd.cxx:128
 RooEffProd.cxx:129
 RooEffProd.cxx:130
 RooEffProd.cxx:131
 RooEffProd.cxx:132
 RooEffProd.cxx:133
 RooEffProd.cxx:134
 RooEffProd.cxx:135
 RooEffProd.cxx:136
 RooEffProd.cxx:137
 RooEffProd.cxx:138
 RooEffProd.cxx:139
 RooEffProd.cxx:140
 RooEffProd.cxx:141
 RooEffProd.cxx:142
 RooEffProd.cxx:143
 RooEffProd.cxx:144
 RooEffProd.cxx:145
 RooEffProd.cxx:146
 RooEffProd.cxx:147
 RooEffProd.cxx:148
 RooEffProd.cxx:149
 RooEffProd.cxx:150
 RooEffProd.cxx:151
 RooEffProd.cxx:152
 RooEffProd.cxx:153
 RooEffProd.cxx:154
 RooEffProd.cxx:155
 RooEffProd.cxx:156
 RooEffProd.cxx:157
 RooEffProd.cxx:158
 RooEffProd.cxx:159
 RooEffProd.cxx:160
 RooEffProd.cxx:161
 RooEffProd.cxx:162
 RooEffProd.cxx:163
 RooEffProd.cxx:164
 RooEffProd.cxx:165
 RooEffProd.cxx:166
 RooEffProd.cxx:167
 RooEffProd.cxx:168
 RooEffProd.cxx:169
 RooEffProd.cxx:170
 RooEffProd.cxx:171
 RooEffProd.cxx:172
 RooEffProd.cxx:173
 RooEffProd.cxx:174
 RooEffProd.cxx:175
 RooEffProd.cxx:176
 RooEffProd.cxx:177
 RooEffProd.cxx:178
 RooEffProd.cxx:179
 RooEffProd.cxx:180
 RooEffProd.cxx:181
 RooEffProd.cxx:182
 RooEffProd.cxx:183
 RooEffProd.cxx:184
 RooEffProd.cxx:185
 RooEffProd.cxx:186
 RooEffProd.cxx:187
 RooEffProd.cxx:188
 RooEffProd.cxx:189
 RooEffProd.cxx:190
 RooEffProd.cxx:191
 RooEffProd.cxx:192
 RooEffProd.cxx:193
 RooEffProd.cxx:194
 RooEffProd.cxx:195
 RooEffProd.cxx:196
 RooEffProd.cxx:197
 RooEffProd.cxx:198
 RooEffProd.cxx:199
 RooEffProd.cxx:200
 RooEffProd.cxx:201
 RooEffProd.cxx:202
 RooEffProd.cxx:203
 RooEffProd.cxx:204
 RooEffProd.cxx:205
 RooEffProd.cxx:206
 RooEffProd.cxx:207
 RooEffProd.cxx:208