ROOT logo

 /***************************************************************************** 
  * 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)             * 
  *****************************************************************************/ 

//////////////////////////////////////////////////////////////////////////////
//
 // 
 // This class implement a generic one-dimensional numeric convolution of two p.d.f.
 // and can convolve any two RooAbsPdfs. The class exploits the convolution theorem
 //
 //       f(x) (*) g(x) --F--> f(k_i) * g(k_i)
 //
 // and calculate the convolution by calculate a Real->Complex FFT of both input p.d.fs
 // multiplying the complex coefficients and performing the reverse Complex->Real FFT
 // to get the result in the input space. This class using the ROOT FFT Interface to
 // the (free) FFTW3 package (www.fftw.org) and requires that your ROOT installation is
 // compiled with the --enable-fftw3 option (instructions for Linux follow)
 //
 // Note that the performance in terms of speed and stability of RooFFTConvPdf is 
 // vastly superior to that of RooNumConvPdf 
 //
 // An important feature of FFT convolutions is that the observable is treated in a
 // cyclical way. This is correct & desirable behavior for cyclical observables such as angles,
 // but it may not be for other observables. The effect that is observed is that if
 // p.d.f is zero at xMin and non-zero at xMax some spillover occurs and
 // a rising tail may appear at xMin. This effect can be reduced or eliminated by
 // introducing a buffer zone in the FFT calculation. If this feature is activated
 // input the sampling array for the FFT calculation is extended in both directions
 // and filled with repetitions of the lowest bin value and highest bin value
 // respectively. The buffer bins are stripped again when the FFT output values
 // are transferred to the p.d.f cache. The default buffer size is 10% of the
 // observable domain size and can be changed with setBufferFraction() member function.
 // 
 // This class is a caching p.d.f inheriting from RooAbsCachedPdf. If this p.d.f 
 // is evaluated for a particular value of x, the FFT calculate the values for the
 // p.d.f at all points in observables space for the given choice of parameters,
 // which are stored in the cache. Subsequent evaluations of RooFFTConvPdf with
 // identical parameters will retrieve results from the cache. If one or more
 // of the parameters change, the cache will be updated.
 // 
 // The sampling density of the cache is controlled by the binning of the 
 // the convolution observable, which can be changed from RooRealVar::setBins(N)
 // For good results N should be large (>1000). Additional interpolation of
 // cache values may improve the result if courser binning are chosen. These can be 
 // set in the constructor or through the setInterpolationOrder() member function. 
 // For N>1000 interpolation will not substantially improve the performance.
 //
 // Additionial information on caching activities can be displayed by monitoring
 // the message stream with topic "Caching" at the INFO level, i.e. 
 // do RooMsgService::instance().addStream(RooMsgService::INFO,Topic("Caching")) 
 // to see these message on stdout
 //
 // Multi-dimensional convolutions are not supported yet, but will be in the future
 // as FFTW can calculate them
 //
 // ---
 // 
 // Installing a copy of FFTW on Linux and compiling ROOT to use it
 // 
 // 1) Go to www.fftw.org and download the latest stable version (a .tar.gz file)
 //
 // If you have root access to your machine and want to make a system installation of FFTW
 //
 //   2) Untar fftw-XXX.tar.gz in /tmp, cd into the untarred directory 
 //       and type './configure' followed by 'make install'. 
 //       This will install fftw in /usr/local/bin,lib etc...
 //
 //   3) Start from a source installation of ROOT. If you now have a binary distribution,
 //      first download a source tar ball from root.cern.ch for your ROOT version and untar it.
 //      Run 'configure', following the instruction from 'configure --help' but be sure run 'configure' 
 //      with additional flags '--enable-fftw3' and '--enable-roofit', then run 'make'
 //         
 // 
 // If you do not have root access and want to make a private installation of FFTW
 //
 //   2) Make a private install area for FFTW, e.g. /home/myself/fftw
 //
 //   3) Untar fftw-XXX.tar.gz in /tmp, cd into the untarred directory
 //       and type './configure --prefix=/home/myself/fftw' followed by 'make install'. 
 //       Substitute /home/myself/fftw with a directory of your choice. This
 //       procedure will install FFTW in the location designated by you
 // 
 //   4) Start from a source installation of ROOT. If you now have a binary distribution,
 //      first download a source tar ball from root.cern.ch for your ROOT version and untar it.
 //      Run 'configure', following the instruction from 'configure --help' but be sure run 'configure' 
 //      with additional flags
 //       '--enable-fftw3', 
 //       '--with-fftw3-incdir=/home/myself/fftw/include', 
 //       '--width-fftw3-libdir=/home/myself/fftw/lib' and 
 //       '--enable-roofit' 
 //      Then run 'make'
//


#include "Riostream.h" 

#include "RooFit.h"
#include "RooFFTConvPdf.h" 
#include "RooAbsReal.h" 
#include "RooMsgService.h"
#include "RooDataHist.h"
#include "RooHistPdf.h"
#include "RooRealVar.h"
#include "TComplex.h"
#include "TVirtualFFT.h"
#include "RooGenContext.h"
#include "RooConvGenContext.h"
#include "RooBinning.h"
#include "RooLinearVar.h"
#include "RooCustomizer.h"
#include "RooGlobalFunc.h"
#include "RooLinearVar.h"
#include "RooConstVar.h"
#include "TClass.h"
#include "TSystem.h"

using namespace std ;

ClassImp(RooFFTConvPdf) 



//_____________________________________________________________________________
RooFFTConvPdf::RooFFTConvPdf(const char *name, const char *title, RooRealVar& convVar, RooAbsPdf& pdf1, RooAbsPdf& pdf2, Int_t ipOrder) :
  RooAbsCachedPdf(name,title,ipOrder),
  _x("!x","Convolution Variable",this,convVar),
  _xprime("!xprime","External Convolution Variable",this,0),
  _pdf1("!pdf1","pdf1",this,pdf1,kFALSE),
  _pdf2("!pdf2","pdf2",this,pdf2,kFALSE),
  _params("!params","effective parameters",this),
  _bufFrac(0.1),
  _bufStrat(Extend),
  _shift1(0),
  _shift2(0),
  _cacheObs("!cacheObs","Cached observables",this,kFALSE,kFALSE)
 { 
   // Constructor for convolution of pdf1 (x) pdf2 in observable convVar. The binning used for the FFT sampling is controlled
   // by the binning named "cache" in the convolution observable. The resulting FFT convolved histogram is interpolated at
   // order 'ipOrder' A minimum binning of 1000 bins is recommended.

   if (!convVar.hasBinning("cache")) {
     convVar.setBinning(convVar.getBinning(),"cache") ;
   }
   
   _shift2 = (convVar.getMax()+convVar.getMin())/2 ;

   calcParams() ;

 } 



//_____________________________________________________________________________
RooFFTConvPdf::RooFFTConvPdf(const char *name, const char *title, RooAbsReal& pdfConvVar, RooRealVar& convVar, RooAbsPdf& pdf1, RooAbsPdf& pdf2, Int_t ipOrder) :
  RooAbsCachedPdf(name,title,ipOrder),
  _x("!x","Convolution Variable",this,convVar,kFALSE,kFALSE),
  _xprime("!xprime","External Convolution Variable",this,pdfConvVar),
  _pdf1("!pdf1","pdf1",this,pdf1,kFALSE),
  _pdf2("!pdf2","pdf2",this,pdf2,kFALSE),
  _params("!params","effective parameters",this),
  _bufFrac(0.1),
  _bufStrat(Extend),
  _shift1(0),
  _shift2(0),
  _cacheObs("!cacheObs","Cached observables",this,kFALSE,kFALSE)
 { 
   // Constructor for convolution of pdf1 (x) pdf2 in observable convVar. The binning used for the FFT sampling is controlled
   // by the binning named "cache" in the convolution observable. The resulting FFT convolved histogram is interpolated at
   // order 'ipOrder' A minimum binning of 1000 bins is recommended.

   if (!convVar.hasBinning("cache")) {
     convVar.setBinning(convVar.getBinning(),"cache") ;
   }
   
   _shift2 = (convVar.getMax()+convVar.getMin())/2 ;

   calcParams() ;
 } 



//_____________________________________________________________________________
RooFFTConvPdf::RooFFTConvPdf(const RooFFTConvPdf& other, const char* name) :  
  RooAbsCachedPdf(other,name),
  _x("!x",this,other._x),
  _xprime("!xprime",this,other._xprime),
  _pdf1("!pdf1",this,other._pdf1),
  _pdf2("!pdf2",this,other._pdf2),
  _params("!params",this,other._params),
  _bufFrac(other._bufFrac),
  _bufStrat(other._bufStrat),
  _shift1(other._shift1),
  _shift2(other._shift2),
  _cacheObs("!cacheObs",this,other._cacheObs)
 { 
   // Copy constructor
 } 



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



//_____________________________________________________________________________
const char* RooFFTConvPdf::inputBaseName() const 
{
  // Return base name component for cache components in this case 'PDF1_CONV_PDF2'

  static TString name ;
  name = _pdf1.arg().GetName() ;
  name.Append("_CONV_") ;
  name.Append(_pdf2.arg().GetName()) ;
  return name.Data() ;
}




//_____________________________________________________________________________
RooFFTConvPdf::PdfCacheElem* RooFFTConvPdf::createCache(const RooArgSet* nset) const 
{
  // Return specialized cache subclass for FFT calculations
  return new FFTCacheElem(*this,nset) ;
}




//_____________________________________________________________________________
RooFFTConvPdf::FFTCacheElem::FFTCacheElem(const RooFFTConvPdf& self, const RooArgSet* nsetIn) : 
  PdfCacheElem(self,nsetIn),
  fftr2c1(0),fftr2c2(0),fftc2r(0) 
{

  // Clone input pdf and attach to dataset
  RooAbsPdf* clonePdf1 = (RooAbsPdf*) self._pdf1.arg().cloneTree() ;
  RooAbsPdf* clonePdf2 = (RooAbsPdf*) self._pdf2.arg().cloneTree() ;
  clonePdf1->attachDataSet(*hist()) ;
  clonePdf2->attachDataSet(*hist()) ;
   
   // Shift observable
   RooRealVar* convObs = (RooRealVar*) hist()->get()->find(self._x.arg().GetName()) ;

   // Install FFT reference range 
   string refName = Form("refrange_fft_%s",self.GetName()) ;
   convObs->setRange(refName.c_str(),convObs->getMin(),convObs->getMax()) ;   
  
   if (self._shift1!=0) {
     RooLinearVar* shiftObs1 = new RooLinearVar(Form("%s_shifted_FFTBuffer1",convObs->GetName()),"shiftObs1",
					       *convObs,RooFit::RooConst(1),RooFit::RooConst(-1*self._shift1)) ;

    RooArgSet clonedBranches1 ;
    RooCustomizer cust(*clonePdf1,"fft") ;
    cust.replaceArg(*convObs,*shiftObs1) ;  

    pdf1Clone = (RooAbsPdf*) cust.build() ;

    pdf1Clone->addOwnedComponents(*shiftObs1) ;
    pdf1Clone->addOwnedComponents(*clonePdf1) ;

  } else {
    pdf1Clone = clonePdf1 ;
  }

  if (self._shift2!=0) {
    RooLinearVar* shiftObs2 = new RooLinearVar(Form("%s_shifted_FFTBuffer2",convObs->GetName()),"shiftObs2",
					       *convObs,RooFit::RooConst(1),RooFit::RooConst(-1*self._shift2)) ;

    RooArgSet clonedBranches2 ;
    RooCustomizer cust(*clonePdf2,"fft") ;
    cust.replaceArg(*convObs,*shiftObs2) ;  

    pdf1Clone->addOwnedComponents(*shiftObs2) ;
    pdf1Clone->addOwnedComponents(*clonePdf2) ;

    pdf2Clone = (RooAbsPdf*) cust.build() ;

  } else {
    pdf2Clone = clonePdf2 ;
  }


  // Attach cloned pdf to all original parameters of self
  RooArgSet* fftParams = self.getParameters(*convObs) ;

  // Remove all cache histogram from fftParams as these
  // observable need to remain attached to the histogram
  fftParams->remove(*hist()->get(),kTRUE,kTRUE) ;

  pdf1Clone->recursiveRedirectServers(*fftParams) ;
  pdf2Clone->recursiveRedirectServers(*fftParams) ;
  pdf1Clone->fixAddCoefRange(refName.c_str()) ;
  pdf2Clone->fixAddCoefRange(refName.c_str()) ;

  delete fftParams ;

  // Save copy of original histX binning and make alternate binning
  // for extended range scanning

  Int_t N = convObs->numBins() ;
  Int_t Nbuf = static_cast<Int_t>((N*self.bufferFraction())/2 + 0.5) ;
  Double_t obw = (convObs->getMax() - convObs->getMin())/N ;
  Int_t N2 = N+2*Nbuf ;

  scanBinning = new RooUniformBinning (convObs->getMin()-Nbuf*obw,convObs->getMax()+Nbuf*obw,N2) ;
  histBinning = convObs->getBinning().clone() ;

  // Deactivate dirty state propagation on datahist observables
  // and set all nodes on both pdfs to operMode AlwaysDirty
  hist()->setDirtyProp(kFALSE) ;  
  convObs->setOperMode(ADirty,kTRUE) ;
} 


//_____________________________________________________________________________
TString RooFFTConvPdf::histNameSuffix() const
{
  // Suffix for cache histogram (added in addition to suffix for cache name)
  return TString(Form("_BufFrac%3.1f_BufStrat%d",_bufFrac,_bufStrat)) ;
}



//_____________________________________________________________________________
RooArgList RooFFTConvPdf::FFTCacheElem::containedArgs(Action a) 
{
  // Returns all RooAbsArg objects contained in the cache element
  RooArgList ret(PdfCacheElem::containedArgs(a)) ;

  ret.add(*pdf1Clone) ;
  ret.add(*pdf2Clone) ;
  if (pdf1Clone->ownedComponents()) {
    ret.add(*pdf1Clone->ownedComponents()) ;
  }
  if (pdf2Clone->ownedComponents()) {
    ret.add(*pdf2Clone->ownedComponents()) ;
  }

  return ret ;
}


//_____________________________________________________________________________
RooFFTConvPdf::FFTCacheElem::~FFTCacheElem() 
{ 
  delete fftr2c1 ; 
  delete fftr2c2 ; 
  delete fftc2r ; 

  delete pdf1Clone ;
  delete pdf2Clone ;

  delete histBinning ;
  delete scanBinning ;

}




//_____________________________________________________________________________
void RooFFTConvPdf::fillCacheObject(RooAbsCachedPdf::PdfCacheElem& cache) const 
{
  // Fill the contents of the cache the FFT convolution output
  RooDataHist& cacheHist = *cache.hist() ;
  
  ((FFTCacheElem&)cache).pdf1Clone->setOperMode(ADirty,kTRUE) ;
  ((FFTCacheElem&)cache).pdf2Clone->setOperMode(ADirty,kTRUE) ;

  // Determine if there other observables than the convolution observable in the cache
  RooArgSet otherObs ;
  RooArgSet(*cacheHist.get()).snapshot(otherObs) ;

  RooAbsArg* histArg = otherObs.find(_x.arg().GetName()) ;
  if (histArg) {
    otherObs.remove(*histArg,kTRUE,kTRUE) ;
    delete histArg ;
  } 

  // Handle trivial scenario -- no other observables
  if (otherObs.getSize()==0) {
    fillCacheSlice((FFTCacheElem&)cache,RooArgSet()) ;
    return ;
  }

  // Handle cases where there are other cache slices
  // Iterator over available slice positions and fill each

  // Determine number of bins for each slice position observable
  Int_t n = otherObs.getSize() ;
  Int_t* binCur = new Int_t[n+1] ;
  Int_t* binMax = new Int_t[n+1] ;
  Int_t curObs = 0 ;

  RooAbsLValue** obsLV = new RooAbsLValue*[n] ;
  TIterator* iter = otherObs.createIterator() ;
  RooAbsArg* arg ;
  Int_t i(0) ;
  while((arg=(RooAbsArg*)iter->Next())) {
    RooAbsLValue* lvarg = dynamic_cast<RooAbsLValue*>(arg) ;
    obsLV[i] = lvarg ;
    binCur[i] = 0 ;
    binMax[i] = lvarg->numBins(binningName())-1 ;    
    i++ ;
  }
  delete iter ;

  Bool_t loop(kTRUE) ;
  while(loop) {
    // Set current slice position
    for (Int_t j=0 ; j<n ; j++) { obsLV[j]->setBin(binCur[j],binningName()) ; }

//     cout << "filling slice: bin of obsLV[0] = " << obsLV[0]->getBin() << endl ;

    // Fill current slice
    fillCacheSlice((FFTCacheElem&)cache,otherObs) ;

    // Determine which iterator to increment
    while(binCur[curObs]==binMax[curObs]) {
      
      // Reset current iterator and consider next iterator ;
      binCur[curObs]=0 ;      
      curObs++ ;

      // master termination condition
      if (curObs==n) {
	loop=kFALSE ;
	break ;
      }
    }

    // Increment current iterator
    binCur[curObs]++ ;
    curObs=0 ;      

  }
  
  
}


//_____________________________________________________________________________
void RooFFTConvPdf::fillCacheSlice(FFTCacheElem& aux, const RooArgSet& slicePos) const 
{
  // Fill a slice of cachePdf with the output of the FFT convolution calculation

  // Extract histogram that is the basis of the RooHistPdf
  RooDataHist& cacheHist = *aux.hist() ;

  // Sample array of input points from both pdfs 
  // Note that returned arrays have optional buffers zones below and above range ends
  // to reduce cyclical effects and have been cyclically rotated so that bin containing
  // zero value is at position zero. Example:
  // 
  //     original:                -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5
  //     add buffer zones:    U U -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5 O O
  //     rotate:              0 +1 +2 +3 +4 +5 O O U U -5 -4 -3 -2 -1
  //
  // 

  Int_t N,N2,binShift1,binShift2 ;
  
  RooRealVar* histX = (RooRealVar*) cacheHist.get()->find(_x.arg().GetName()) ;
  if (_bufStrat==Extend) histX->setBinning(*aux.scanBinning) ;
  Double_t* input1 = scanPdf((RooRealVar&)_x.arg(),*aux.pdf1Clone,cacheHist,slicePos,N,N2,binShift1,_shift1) ;
  Double_t* input2 = scanPdf((RooRealVar&)_x.arg(),*aux.pdf2Clone,cacheHist,slicePos,N,N2,binShift2,_shift2) ;
  if (_bufStrat==Extend) histX->setBinning(*aux.histBinning) ;

  // Retrieve previously defined FFT transformation plans
  if (!aux.fftr2c1) {
    aux.fftr2c1 = TVirtualFFT::FFT(1, &N2, "R2CK");
    aux.fftr2c2 = TVirtualFFT::FFT(1, &N2, "R2CK");
    aux.fftc2r  = TVirtualFFT::FFT(1, &N2, "C2RK");
  }
  
  // Real->Complex FFT Transform on p.d.f. 1 sampling
  aux.fftr2c1->SetPoints(input1);
  aux.fftr2c1->Transform();

  // Real->Complex FFT Transform on p.d.f 2 sampling
  aux.fftr2c2->SetPoints(input2);
  aux.fftr2c2->Transform();

  // Loop over first half +1 of complex output results, multiply 
  // and set as input of reverse transform
  for (Int_t i=0 ; i<N2/2+1 ; i++) {
    Double_t re1,re2,im1,im2 ;
    aux.fftr2c1->GetPointComplex(i,re1,im1) ;
    aux.fftr2c2->GetPointComplex(i,re2,im2) ;
    Double_t re = re1*re2 - im1*im2 ;
    Double_t im = re1*im2 + re2*im1 ;
    TComplex t(re,im) ;
    aux.fftc2r->SetPointComplex(i,t) ;
  }

  // Reverse Complex->Real FFT transform product
  aux.fftc2r->Transform() ;

  Int_t totalShift = binShift1 + (N2-N)/2 ;

  // Store FFT result in cache
  TIterator* iter = const_cast<RooDataHist&>(cacheHist).sliceIterator(const_cast<RooAbsReal&>(_x.arg()),slicePos) ;
  for (Int_t i =0 ; i<N ; i++) {

    // Cyclically shift array back so that bin containing zero is back in zeroBin
    Int_t j = i + totalShift ;
    while (j<0) j+= N2 ;
    while (j>=N2) j-= N2 ;

    iter->Next() ;
    cacheHist.set(aux.fftc2r->GetPointReal(j)) ;    
  }
  delete iter ;

  // cacheHist.dump2() ;

  // Delete input arrays
  delete[] input1 ;
  delete[] input2 ;

}


//_____________________________________________________________________________
Double_t*  RooFFTConvPdf::scanPdf(RooRealVar& obs, RooAbsPdf& pdf, const RooDataHist& hist, const RooArgSet& slicePos, 
				  Int_t& N, Int_t& N2, Int_t& zeroBin, Double_t shift) const
{
  // Scan the values of 'pdf' in observable 'obs' using the bin values stored in 'hist' at slice position 'slicePos'
  // N is filled with the number of bins defined in hist, N2 is filled with N plus the number of buffer bins
  // The return value is an array of doubles of length N2 with the sampled values. The caller takes ownership
  // of the array


  RooRealVar* histX = (RooRealVar*) hist.get()->find(obs.GetName()) ;

  // Calculate number of buffer bins on each size to avoid cyclical flow
  N = histX->numBins(binningName()) ;
  Int_t Nbuf = static_cast<Int_t>((N*bufferFraction())/2 + 0.5) ;
  N2 = N+2*Nbuf ;

  
  // Allocate array of sampling size plus optional buffer zones
  Double_t* array = new Double_t[N2] ;
  
  // Set position of non-convolution observable to that of the cache slice that were are processing now
  hist.get(slicePos) ;

  // Find bin ID that contains zero value
  zeroBin = 0 ;
  if (histX->getMax()>=0 && histX->getMin()<=0) {
    zeroBin = histX->getBinning().binNumber(0) ;
  } else if (histX->getMin()>0) {
    Double_t bw = (histX->getMax() - histX->getMin())/N2 ;
    zeroBin = Int_t(-histX->getMin()/bw) ;
  } else {
    Double_t bw = (histX->getMax() - histX->getMin())/N2 ;
    zeroBin = Int_t(-1*histX->getMax()/bw) ;
  }

  Int_t binShift = Int_t((N2* shift) / (histX->getMax()-histX->getMin())) ;

  zeroBin += binShift ;
  while(zeroBin>=N2) zeroBin-= N2 ;
  while(zeroBin<0) zeroBin+= N2 ;

  // First scan hist into temp array 
  Double_t *tmp = new Double_t[N2] ;
  Int_t k(0) ;
  switch(_bufStrat) {

  case Extend:
    // Sample entire extended range (N2 samples)
    for (k=0 ; k<N2 ; k++) {
      histX->setBin(k) ;
      tmp[k] = pdf.getVal(hist.get()) ;    
    }  
    break ;

  case Flat:    
    // Sample original range (N samples) and fill lower and upper buffer
    // bins with p.d.f. value at respective boundary
    {
      histX->setBin(0) ;
      Double_t val = pdf.getVal(hist.get()) ;  
      for (k=0 ; k<Nbuf ; k++) {
	tmp[k] = val ;
      }
      for (k=0 ; k<N ; k++) {
	histX->setBin(k) ;
	tmp[k+Nbuf] = pdf.getVal(hist.get()) ;    
      }  
      histX->setBin(N-1) ;
      val = pdf.getVal(hist.get()) ;  
      for (k=0 ; k<Nbuf ; k++) {
	tmp[N+Nbuf+k] = val ;
      }  
    }
    break ;

  case Mirror:
    // Sample original range (N samples) and fill lower and upper buffer
    // bins with mirror image of sampled range
    for (k=0 ; k<N ; k++) {
      histX->setBin(k) ;
      tmp[k+Nbuf] = pdf.getVal(hist.get()) ;    
    }  
    for (k=1 ; k<=Nbuf ; k++) {
      histX->setBin(k) ;
      tmp[Nbuf-k] = pdf.getVal(hist.get()) ;    
      histX->setBin(N-k) ;
      tmp[Nbuf+N+k-1] = pdf.getVal(hist.get()) ;    
    }  
    break ;
  }

  // Scan function and store values in array
  for (Int_t i=0 ; i<N2 ; i++) {
    // Cyclically shift writing location by zero bin position    
    Int_t j = i - (zeroBin) ;
    if (j<0) j+= N2 ;
    if (j>=N2) j-= N2 ;
    array[i] = tmp[j] ;
  }  

  // Cleanup 
  delete[] tmp ;
  return array ;
}



//_____________________________________________________________________________
RooArgSet* RooFFTConvPdf::actualObservables(const RooArgSet& nset) const 
{
  // Return the observables to be cached given the normalization set nset
  //
  // If the cache observables is in nset then this is 
  //    - the convolution observable plus 
  //    - any member of nset that is either a RooCategory, 
  //    - or was previously specified through setCacheObservables().
  //
  // In case the cache observable is _not_ in nset, then it is
  //    - the convolution observable plus 
  //    - all member of nset are observables of this p.d.f.
  // 

  // Get complete list of observables 
  RooArgSet* obs1 = _pdf1.arg().getObservables(nset) ;
  RooArgSet* obs2 = _pdf2.arg().getObservables(nset) ;
  obs1->add(*obs2,kTRUE) ;

  // Check if convolution observable is in nset
  if (nset.contains(_x.arg())) {

    // Now strip out all non-category observables
    TIterator* iter = obs1->createIterator() ;
    RooAbsArg* arg ;
    RooArgSet killList ;
    while((arg=(RooAbsArg*)iter->Next())) {
      if (arg->IsA()->InheritsFrom(RooAbsReal::Class()) && !_cacheObs.find(arg->GetName())) {
	killList.add(*arg) ;
      }
    }
    delete iter ;
    obs1->remove(killList) ;
    
    // And add back the convolution observables
    obs1->add(_x.arg(),kTRUE) ; 
    delete obs2 ;
    
  } else {

    // If cacheObs was filled, cache only observables in there
    if (_cacheObs.getSize()>0) {
      TIterator* iter = obs1->createIterator() ;
      RooAbsArg* arg ;
      RooArgSet killList ;
      while((arg=(RooAbsArg*)iter->Next())) {
	if (arg->IsA()->InheritsFrom(RooAbsReal::Class()) && !_cacheObs.find(arg->GetName())) {
	  killList.add(*arg) ;
	}
      }
      delete iter ;
      obs1->remove(killList) ;
    }


    // Make sure convolution observable is always in there
    obs1->add(_x.arg(),kTRUE) ; 
    delete obs2 ;
    
  }
  
  return obs1 ;  
}



//_____________________________________________________________________________
RooArgSet* RooFFTConvPdf::actualParameters(const RooArgSet& nset) const 
{  
  // Return the parameters on which the cache depends given normalization
  // set nset. For this p.d.f these are the parameters of the input p.d.f.
  // but never the convolution variable, it case it is not part of nset

  RooArgSet* vars = getVariables() ;
  RooArgSet* obs = actualObservables(nset) ;
  vars->remove(*obs) ;
  delete obs ;

  return vars ;
}



//_____________________________________________________________________________
RooAbsArg& RooFFTConvPdf::pdfObservable(RooAbsArg& histObservable) const 
{
  // Return p.d.f. observable (which can be a function) to substitute given
  // p.d.f. observable. Substitute x by xprime if xprime is set

  if (_xprime.absArg() && string(histObservable.GetName())==_x.absArg()->GetName()) {
    return (*_xprime.absArg()) ;
  }
  return histObservable ;
}



//_____________________________________________________________________________
RooAbsGenContext* RooFFTConvPdf::genContext(const RooArgSet &vars, const RooDataSet *prototype, 
					    const RooArgSet* auxProto, Bool_t verbose) const 
{
  // Create appropriate generator context for this convolution. If both input p.d.f.s support
  // internal generation, if it is safe to use them and if no observables other than the convolution
  // observable are requested for generation, use the specialized convolution generator context
  // which implements a smearing strategy in the convolution observable. If not return the
  // regular accept/reject generator context

  RooArgSet vars2(vars) ;
  vars2.remove(_x.arg(),kTRUE,kTRUE) ;
  Int_t numAddDep = vars2.getSize() ;

  RooArgSet dummy ;
  Bool_t pdfCanDir = (((RooAbsPdf&)_pdf1.arg()).getGenerator(_x.arg(),dummy) != 0 && \
		      ((RooAbsPdf&)_pdf1.arg()).isDirectGenSafe(_x.arg())) ;
  Bool_t resCanDir = (((RooAbsPdf&)_pdf2.arg()).getGenerator(_x.arg(),dummy) !=0  && 
		      ((RooAbsPdf&)_pdf2.arg()).isDirectGenSafe(_x.arg())) ;

  if (pdfCanDir) {
    cxcoutI(Generation) << "RooFFTConvPdf::genContext() input p.d.f " << _pdf1.arg().GetName() 
			<< " has internal generator that is safe to use in current context" << endl ;
  }
  if (resCanDir) {
    cxcoutI(Generation) << "RooFFTConvPdf::genContext() input p.d.f. " << _pdf2.arg().GetName() 
			<< " has internal generator that is safe to use in current context" << endl ;
  }
  if (numAddDep>0) {
    cxcoutI(Generation) << "RooFFTConvPdf::genContext() generation requested for observables other than the convolution observable " << _x.arg().GetName() << endl ;
  }  

  
  if (numAddDep>0 || !pdfCanDir || !resCanDir) {
    // Any resolution model with more dependents than the convolution variable
    // or pdf or resmodel do not support direct generation
    cxcoutI(Generation) << "RooFFTConvPdf::genContext() selecting accept/reject generator context because one or both of the input "
			<< "p.d.f.s cannot use internal generator and/or " 
			<< "observables other than the convolution variable are requested for generation" << endl ;
    return new RooGenContext(*this,vars,prototype,auxProto,verbose) ;
  } 
  
  // Any other resolution model: use specialized generator context
  cxcoutI(Generation) << "RooFFTConvPdf::genContext() selecting specialized convolution generator context as both input "
		      << "p.d.fs are safe for internal generator and only "
		      << "the convolution observables is requested for generation" << endl ;
  return new RooConvGenContext(*this,vars,prototype,auxProto,verbose) ;
}



//_____________________________________________________________________________
void RooFFTConvPdf::setBufferFraction(Double_t frac) 
{
  // Change the size of the buffer on either side of the observable range to frac times the
  // size of the range of the convolution observable

  if (frac<0) {
    coutE(InputArguments) << "RooFFTConvPdf::setBufferFraction(" << GetName() << ") fraction should be greater than or equal to zero" << endl ;
    return ;
  }
  _bufFrac = frac ;

  // Sterilize the cache as certain partial results depend on buffer fraction
  _cacheMgr.sterilize() ;
}


//_____________________________________________________________________________
void RooFFTConvPdf::setBufferStrategy(BufStrat bs) 
{
  // Change strategy to fill the overflow buffer on either side of the convolution observable range.
  //
  // 'Extend' means is that the input p.d.f convolution observable range is widened to include the buffer range
  // 'Flat' means that the buffer is filled with the p.d.f. value at the boundary of the observable range
  // 'Mirror' means that the buffer is filled with a ,irror image of the p.d.f. around the convolution observable boundary 
  //
  // The default strategy is extend. If one of the input p.d.f.s is a RooAddPdf, it is configured so that the interpretation
  // range of the fraction coefficients is kept at the nominal convolutions observable range (instead of interpreting coefficients
  // in the widened range including the buffer)

  _bufStrat = bs ;
}



//_____________________________________________________________________________
void RooFFTConvPdf::printMetaArgs(ostream& os) const 
{
  // Customized printing of arguments of a RooNumConvPdf to more intuitively reflect the contents of the
  // product operator construction

  os << _pdf1.arg().GetName() << "(" << _x.arg().GetName() << ") (*) " << _pdf2.arg().GetName() << "(" << _x.arg().GetName() << ") " ;
}



//_____________________________________________________________________________
void RooFFTConvPdf::calcParams() 
{
  // (Re)calculate effective parameters of this p.d.f.

  RooArgSet* params1 = _pdf1.arg().getParameters(_x.arg()) ;
  RooArgSet* params2 = _pdf2.arg().getParameters(_x.arg()) ;
  _params.removeAll() ;
  _params.add(*params1) ;
  _params.add(*params2,kTRUE) ;
  delete params1 ;
  delete params2 ;
}



//_____________________________________________________________________________
Bool_t RooFFTConvPdf::redirectServersHook(const RooAbsCollection& /*newServerList*/, Bool_t /*mustReplaceAll*/, Bool_t /*nameChange*/, Bool_t /*isRecursive*/) 
{
  //calcParams() ;
  return kFALSE ;
}
 RooFFTConvPdf.cxx:1
 RooFFTConvPdf.cxx:2
 RooFFTConvPdf.cxx:3
 RooFFTConvPdf.cxx:4
 RooFFTConvPdf.cxx:5
 RooFFTConvPdf.cxx:6
 RooFFTConvPdf.cxx:7
 RooFFTConvPdf.cxx:8
 RooFFTConvPdf.cxx:9
 RooFFTConvPdf.cxx:10
 RooFFTConvPdf.cxx:11
 RooFFTConvPdf.cxx:12
 RooFFTConvPdf.cxx:13
 RooFFTConvPdf.cxx:14
 RooFFTConvPdf.cxx:15
 RooFFTConvPdf.cxx:16
 RooFFTConvPdf.cxx:17
 RooFFTConvPdf.cxx:18
 RooFFTConvPdf.cxx:19
 RooFFTConvPdf.cxx:20
 RooFFTConvPdf.cxx:21
 RooFFTConvPdf.cxx:22
 RooFFTConvPdf.cxx:23
 RooFFTConvPdf.cxx:24
 RooFFTConvPdf.cxx:25
 RooFFTConvPdf.cxx:26
 RooFFTConvPdf.cxx:27
 RooFFTConvPdf.cxx:28
 RooFFTConvPdf.cxx:29
 RooFFTConvPdf.cxx:30
 RooFFTConvPdf.cxx:31
 RooFFTConvPdf.cxx:32
 RooFFTConvPdf.cxx:33
 RooFFTConvPdf.cxx:34
 RooFFTConvPdf.cxx:35
 RooFFTConvPdf.cxx:36
 RooFFTConvPdf.cxx:37
 RooFFTConvPdf.cxx:38
 RooFFTConvPdf.cxx:39
 RooFFTConvPdf.cxx:40
 RooFFTConvPdf.cxx:41
 RooFFTConvPdf.cxx:42
 RooFFTConvPdf.cxx:43
 RooFFTConvPdf.cxx:44
 RooFFTConvPdf.cxx:45
 RooFFTConvPdf.cxx:46
 RooFFTConvPdf.cxx:47
 RooFFTConvPdf.cxx:48
 RooFFTConvPdf.cxx:49
 RooFFTConvPdf.cxx:50
 RooFFTConvPdf.cxx:51
 RooFFTConvPdf.cxx:52
 RooFFTConvPdf.cxx:53
 RooFFTConvPdf.cxx:54
 RooFFTConvPdf.cxx:55
 RooFFTConvPdf.cxx:56
 RooFFTConvPdf.cxx:57
 RooFFTConvPdf.cxx:58
 RooFFTConvPdf.cxx:59
 RooFFTConvPdf.cxx:60
 RooFFTConvPdf.cxx:61
 RooFFTConvPdf.cxx:62
 RooFFTConvPdf.cxx:63
 RooFFTConvPdf.cxx:64
 RooFFTConvPdf.cxx:65
 RooFFTConvPdf.cxx:66
 RooFFTConvPdf.cxx:67
 RooFFTConvPdf.cxx:68
 RooFFTConvPdf.cxx:69
 RooFFTConvPdf.cxx:70
 RooFFTConvPdf.cxx:71
 RooFFTConvPdf.cxx:72
 RooFFTConvPdf.cxx:73
 RooFFTConvPdf.cxx:74
 RooFFTConvPdf.cxx:75
 RooFFTConvPdf.cxx:76
 RooFFTConvPdf.cxx:77
 RooFFTConvPdf.cxx:78
 RooFFTConvPdf.cxx:79
 RooFFTConvPdf.cxx:80
 RooFFTConvPdf.cxx:81
 RooFFTConvPdf.cxx:82
 RooFFTConvPdf.cxx:83
 RooFFTConvPdf.cxx:84
 RooFFTConvPdf.cxx:85
 RooFFTConvPdf.cxx:86
 RooFFTConvPdf.cxx:87
 RooFFTConvPdf.cxx:88
 RooFFTConvPdf.cxx:89
 RooFFTConvPdf.cxx:90
 RooFFTConvPdf.cxx:91
 RooFFTConvPdf.cxx:92
 RooFFTConvPdf.cxx:93
 RooFFTConvPdf.cxx:94
 RooFFTConvPdf.cxx:95
 RooFFTConvPdf.cxx:96
 RooFFTConvPdf.cxx:97
 RooFFTConvPdf.cxx:98
 RooFFTConvPdf.cxx:99
 RooFFTConvPdf.cxx:100
 RooFFTConvPdf.cxx:101
 RooFFTConvPdf.cxx:102
 RooFFTConvPdf.cxx:103
 RooFFTConvPdf.cxx:104
 RooFFTConvPdf.cxx:105
 RooFFTConvPdf.cxx:106
 RooFFTConvPdf.cxx:107
 RooFFTConvPdf.cxx:108
 RooFFTConvPdf.cxx:109
 RooFFTConvPdf.cxx:110
 RooFFTConvPdf.cxx:111
 RooFFTConvPdf.cxx:112
 RooFFTConvPdf.cxx:113
 RooFFTConvPdf.cxx:114
 RooFFTConvPdf.cxx:115
 RooFFTConvPdf.cxx:116
 RooFFTConvPdf.cxx:117
 RooFFTConvPdf.cxx:118
 RooFFTConvPdf.cxx:119
 RooFFTConvPdf.cxx:120
 RooFFTConvPdf.cxx:121
 RooFFTConvPdf.cxx:122
 RooFFTConvPdf.cxx:123
 RooFFTConvPdf.cxx:124
 RooFFTConvPdf.cxx:125
 RooFFTConvPdf.cxx:126
 RooFFTConvPdf.cxx:127
 RooFFTConvPdf.cxx:128
 RooFFTConvPdf.cxx:129
 RooFFTConvPdf.cxx:130
 RooFFTConvPdf.cxx:131
 RooFFTConvPdf.cxx:132
 RooFFTConvPdf.cxx:133
 RooFFTConvPdf.cxx:134
 RooFFTConvPdf.cxx:135
 RooFFTConvPdf.cxx:136
 RooFFTConvPdf.cxx:137
 RooFFTConvPdf.cxx:138
 RooFFTConvPdf.cxx:139
 RooFFTConvPdf.cxx:140
 RooFFTConvPdf.cxx:141
 RooFFTConvPdf.cxx:142
 RooFFTConvPdf.cxx:143
 RooFFTConvPdf.cxx:144
 RooFFTConvPdf.cxx:145
 RooFFTConvPdf.cxx:146
 RooFFTConvPdf.cxx:147
 RooFFTConvPdf.cxx:148
 RooFFTConvPdf.cxx:149
 RooFFTConvPdf.cxx:150
 RooFFTConvPdf.cxx:151
 RooFFTConvPdf.cxx:152
 RooFFTConvPdf.cxx:153
 RooFFTConvPdf.cxx:154
 RooFFTConvPdf.cxx:155
 RooFFTConvPdf.cxx:156
 RooFFTConvPdf.cxx:157
 RooFFTConvPdf.cxx:158
 RooFFTConvPdf.cxx:159
 RooFFTConvPdf.cxx:160
 RooFFTConvPdf.cxx:161
 RooFFTConvPdf.cxx:162
 RooFFTConvPdf.cxx:163
 RooFFTConvPdf.cxx:164
 RooFFTConvPdf.cxx:165
 RooFFTConvPdf.cxx:166
 RooFFTConvPdf.cxx:167
 RooFFTConvPdf.cxx:168
 RooFFTConvPdf.cxx:169
 RooFFTConvPdf.cxx:170
 RooFFTConvPdf.cxx:171
 RooFFTConvPdf.cxx:172
 RooFFTConvPdf.cxx:173
 RooFFTConvPdf.cxx:174
 RooFFTConvPdf.cxx:175
 RooFFTConvPdf.cxx:176
 RooFFTConvPdf.cxx:177
 RooFFTConvPdf.cxx:178
 RooFFTConvPdf.cxx:179
 RooFFTConvPdf.cxx:180
 RooFFTConvPdf.cxx:181
 RooFFTConvPdf.cxx:182
 RooFFTConvPdf.cxx:183
 RooFFTConvPdf.cxx:184
 RooFFTConvPdf.cxx:185
 RooFFTConvPdf.cxx:186
 RooFFTConvPdf.cxx:187
 RooFFTConvPdf.cxx:188
 RooFFTConvPdf.cxx:189
 RooFFTConvPdf.cxx:190
 RooFFTConvPdf.cxx:191
 RooFFTConvPdf.cxx:192
 RooFFTConvPdf.cxx:193
 RooFFTConvPdf.cxx:194
 RooFFTConvPdf.cxx:195
 RooFFTConvPdf.cxx:196
 RooFFTConvPdf.cxx:197
 RooFFTConvPdf.cxx:198
 RooFFTConvPdf.cxx:199
 RooFFTConvPdf.cxx:200
 RooFFTConvPdf.cxx:201
 RooFFTConvPdf.cxx:202
 RooFFTConvPdf.cxx:203
 RooFFTConvPdf.cxx:204
 RooFFTConvPdf.cxx:205
 RooFFTConvPdf.cxx:206
 RooFFTConvPdf.cxx:207
 RooFFTConvPdf.cxx:208
 RooFFTConvPdf.cxx:209
 RooFFTConvPdf.cxx:210
 RooFFTConvPdf.cxx:211
 RooFFTConvPdf.cxx:212
 RooFFTConvPdf.cxx:213
 RooFFTConvPdf.cxx:214
 RooFFTConvPdf.cxx:215
 RooFFTConvPdf.cxx:216
 RooFFTConvPdf.cxx:217
 RooFFTConvPdf.cxx:218
 RooFFTConvPdf.cxx:219
 RooFFTConvPdf.cxx:220
 RooFFTConvPdf.cxx:221
 RooFFTConvPdf.cxx:222
 RooFFTConvPdf.cxx:223
 RooFFTConvPdf.cxx:224
 RooFFTConvPdf.cxx:225
 RooFFTConvPdf.cxx:226
 RooFFTConvPdf.cxx:227
 RooFFTConvPdf.cxx:228
 RooFFTConvPdf.cxx:229
 RooFFTConvPdf.cxx:230
 RooFFTConvPdf.cxx:231
 RooFFTConvPdf.cxx:232
 RooFFTConvPdf.cxx:233
 RooFFTConvPdf.cxx:234
 RooFFTConvPdf.cxx:235
 RooFFTConvPdf.cxx:236
 RooFFTConvPdf.cxx:237
 RooFFTConvPdf.cxx:238
 RooFFTConvPdf.cxx:239
 RooFFTConvPdf.cxx:240
 RooFFTConvPdf.cxx:241
 RooFFTConvPdf.cxx:242
 RooFFTConvPdf.cxx:243
 RooFFTConvPdf.cxx:244
 RooFFTConvPdf.cxx:245
 RooFFTConvPdf.cxx:246
 RooFFTConvPdf.cxx:247
 RooFFTConvPdf.cxx:248
 RooFFTConvPdf.cxx:249
 RooFFTConvPdf.cxx:250
 RooFFTConvPdf.cxx:251
 RooFFTConvPdf.cxx:252
 RooFFTConvPdf.cxx:253
 RooFFTConvPdf.cxx:254
 RooFFTConvPdf.cxx:255
 RooFFTConvPdf.cxx:256
 RooFFTConvPdf.cxx:257
 RooFFTConvPdf.cxx:258
 RooFFTConvPdf.cxx:259
 RooFFTConvPdf.cxx:260
 RooFFTConvPdf.cxx:261
 RooFFTConvPdf.cxx:262
 RooFFTConvPdf.cxx:263
 RooFFTConvPdf.cxx:264
 RooFFTConvPdf.cxx:265
 RooFFTConvPdf.cxx:266
 RooFFTConvPdf.cxx:267
 RooFFTConvPdf.cxx:268
 RooFFTConvPdf.cxx:269
 RooFFTConvPdf.cxx:270
 RooFFTConvPdf.cxx:271
 RooFFTConvPdf.cxx:272
 RooFFTConvPdf.cxx:273
 RooFFTConvPdf.cxx:274
 RooFFTConvPdf.cxx:275
 RooFFTConvPdf.cxx:276
 RooFFTConvPdf.cxx:277
 RooFFTConvPdf.cxx:278
 RooFFTConvPdf.cxx:279
 RooFFTConvPdf.cxx:280
 RooFFTConvPdf.cxx:281
 RooFFTConvPdf.cxx:282
 RooFFTConvPdf.cxx:283
 RooFFTConvPdf.cxx:284
 RooFFTConvPdf.cxx:285
 RooFFTConvPdf.cxx:286
 RooFFTConvPdf.cxx:287
 RooFFTConvPdf.cxx:288
 RooFFTConvPdf.cxx:289
 RooFFTConvPdf.cxx:290
 RooFFTConvPdf.cxx:291
 RooFFTConvPdf.cxx:292
 RooFFTConvPdf.cxx:293
 RooFFTConvPdf.cxx:294
 RooFFTConvPdf.cxx:295
 RooFFTConvPdf.cxx:296
 RooFFTConvPdf.cxx:297
 RooFFTConvPdf.cxx:298
 RooFFTConvPdf.cxx:299
 RooFFTConvPdf.cxx:300
 RooFFTConvPdf.cxx:301
 RooFFTConvPdf.cxx:302
 RooFFTConvPdf.cxx:303
 RooFFTConvPdf.cxx:304
 RooFFTConvPdf.cxx:305
 RooFFTConvPdf.cxx:306
 RooFFTConvPdf.cxx:307
 RooFFTConvPdf.cxx:308
 RooFFTConvPdf.cxx:309
 RooFFTConvPdf.cxx:310
 RooFFTConvPdf.cxx:311
 RooFFTConvPdf.cxx:312
 RooFFTConvPdf.cxx:313
 RooFFTConvPdf.cxx:314
 RooFFTConvPdf.cxx:315
 RooFFTConvPdf.cxx:316
 RooFFTConvPdf.cxx:317
 RooFFTConvPdf.cxx:318
 RooFFTConvPdf.cxx:319
 RooFFTConvPdf.cxx:320
 RooFFTConvPdf.cxx:321
 RooFFTConvPdf.cxx:322
 RooFFTConvPdf.cxx:323
 RooFFTConvPdf.cxx:324
 RooFFTConvPdf.cxx:325
 RooFFTConvPdf.cxx:326
 RooFFTConvPdf.cxx:327
 RooFFTConvPdf.cxx:328
 RooFFTConvPdf.cxx:329
 RooFFTConvPdf.cxx:330
 RooFFTConvPdf.cxx:331
 RooFFTConvPdf.cxx:332
 RooFFTConvPdf.cxx:333
 RooFFTConvPdf.cxx:334
 RooFFTConvPdf.cxx:335
 RooFFTConvPdf.cxx:336
 RooFFTConvPdf.cxx:337
 RooFFTConvPdf.cxx:338
 RooFFTConvPdf.cxx:339
 RooFFTConvPdf.cxx:340
 RooFFTConvPdf.cxx:341
 RooFFTConvPdf.cxx:342
 RooFFTConvPdf.cxx:343
 RooFFTConvPdf.cxx:344
 RooFFTConvPdf.cxx:345
 RooFFTConvPdf.cxx:346
 RooFFTConvPdf.cxx:347
 RooFFTConvPdf.cxx:348
 RooFFTConvPdf.cxx:349
 RooFFTConvPdf.cxx:350
 RooFFTConvPdf.cxx:351
 RooFFTConvPdf.cxx:352
 RooFFTConvPdf.cxx:353
 RooFFTConvPdf.cxx:354
 RooFFTConvPdf.cxx:355
 RooFFTConvPdf.cxx:356
 RooFFTConvPdf.cxx:357
 RooFFTConvPdf.cxx:358
 RooFFTConvPdf.cxx:359
 RooFFTConvPdf.cxx:360
 RooFFTConvPdf.cxx:361
 RooFFTConvPdf.cxx:362
 RooFFTConvPdf.cxx:363
 RooFFTConvPdf.cxx:364
 RooFFTConvPdf.cxx:365
 RooFFTConvPdf.cxx:366
 RooFFTConvPdf.cxx:367
 RooFFTConvPdf.cxx:368
 RooFFTConvPdf.cxx:369
 RooFFTConvPdf.cxx:370
 RooFFTConvPdf.cxx:371
 RooFFTConvPdf.cxx:372
 RooFFTConvPdf.cxx:373
 RooFFTConvPdf.cxx:374
 RooFFTConvPdf.cxx:375
 RooFFTConvPdf.cxx:376
 RooFFTConvPdf.cxx:377
 RooFFTConvPdf.cxx:378
 RooFFTConvPdf.cxx:379
 RooFFTConvPdf.cxx:380
 RooFFTConvPdf.cxx:381
 RooFFTConvPdf.cxx:382
 RooFFTConvPdf.cxx:383
 RooFFTConvPdf.cxx:384
 RooFFTConvPdf.cxx:385
 RooFFTConvPdf.cxx:386
 RooFFTConvPdf.cxx:387
 RooFFTConvPdf.cxx:388
 RooFFTConvPdf.cxx:389
 RooFFTConvPdf.cxx:390
 RooFFTConvPdf.cxx:391
 RooFFTConvPdf.cxx:392
 RooFFTConvPdf.cxx:393
 RooFFTConvPdf.cxx:394
 RooFFTConvPdf.cxx:395
 RooFFTConvPdf.cxx:396
 RooFFTConvPdf.cxx:397
 RooFFTConvPdf.cxx:398
 RooFFTConvPdf.cxx:399
 RooFFTConvPdf.cxx:400
 RooFFTConvPdf.cxx:401
 RooFFTConvPdf.cxx:402
 RooFFTConvPdf.cxx:403
 RooFFTConvPdf.cxx:404
 RooFFTConvPdf.cxx:405
 RooFFTConvPdf.cxx:406
 RooFFTConvPdf.cxx:407
 RooFFTConvPdf.cxx:408
 RooFFTConvPdf.cxx:409
 RooFFTConvPdf.cxx:410
 RooFFTConvPdf.cxx:411
 RooFFTConvPdf.cxx:412
 RooFFTConvPdf.cxx:413
 RooFFTConvPdf.cxx:414
 RooFFTConvPdf.cxx:415
 RooFFTConvPdf.cxx:416
 RooFFTConvPdf.cxx:417
 RooFFTConvPdf.cxx:418
 RooFFTConvPdf.cxx:419
 RooFFTConvPdf.cxx:420
 RooFFTConvPdf.cxx:421
 RooFFTConvPdf.cxx:422
 RooFFTConvPdf.cxx:423
 RooFFTConvPdf.cxx:424
 RooFFTConvPdf.cxx:425
 RooFFTConvPdf.cxx:426
 RooFFTConvPdf.cxx:427
 RooFFTConvPdf.cxx:428
 RooFFTConvPdf.cxx:429
 RooFFTConvPdf.cxx:430
 RooFFTConvPdf.cxx:431
 RooFFTConvPdf.cxx:432
 RooFFTConvPdf.cxx:433
 RooFFTConvPdf.cxx:434
 RooFFTConvPdf.cxx:435
 RooFFTConvPdf.cxx:436
 RooFFTConvPdf.cxx:437
 RooFFTConvPdf.cxx:438
 RooFFTConvPdf.cxx:439
 RooFFTConvPdf.cxx:440
 RooFFTConvPdf.cxx:441
 RooFFTConvPdf.cxx:442
 RooFFTConvPdf.cxx:443
 RooFFTConvPdf.cxx:444
 RooFFTConvPdf.cxx:445
 RooFFTConvPdf.cxx:446
 RooFFTConvPdf.cxx:447
 RooFFTConvPdf.cxx:448
 RooFFTConvPdf.cxx:449
 RooFFTConvPdf.cxx:450
 RooFFTConvPdf.cxx:451
 RooFFTConvPdf.cxx:452
 RooFFTConvPdf.cxx:453
 RooFFTConvPdf.cxx:454
 RooFFTConvPdf.cxx:455
 RooFFTConvPdf.cxx:456
 RooFFTConvPdf.cxx:457
 RooFFTConvPdf.cxx:458
 RooFFTConvPdf.cxx:459
 RooFFTConvPdf.cxx:460
 RooFFTConvPdf.cxx:461
 RooFFTConvPdf.cxx:462
 RooFFTConvPdf.cxx:463
 RooFFTConvPdf.cxx:464
 RooFFTConvPdf.cxx:465
 RooFFTConvPdf.cxx:466
 RooFFTConvPdf.cxx:467
 RooFFTConvPdf.cxx:468
 RooFFTConvPdf.cxx:469
 RooFFTConvPdf.cxx:470
 RooFFTConvPdf.cxx:471
 RooFFTConvPdf.cxx:472
 RooFFTConvPdf.cxx:473
 RooFFTConvPdf.cxx:474
 RooFFTConvPdf.cxx:475
 RooFFTConvPdf.cxx:476
 RooFFTConvPdf.cxx:477
 RooFFTConvPdf.cxx:478
 RooFFTConvPdf.cxx:479
 RooFFTConvPdf.cxx:480
 RooFFTConvPdf.cxx:481
 RooFFTConvPdf.cxx:482
 RooFFTConvPdf.cxx:483
 RooFFTConvPdf.cxx:484
 RooFFTConvPdf.cxx:485
 RooFFTConvPdf.cxx:486
 RooFFTConvPdf.cxx:487
 RooFFTConvPdf.cxx:488
 RooFFTConvPdf.cxx:489
 RooFFTConvPdf.cxx:490
 RooFFTConvPdf.cxx:491
 RooFFTConvPdf.cxx:492
 RooFFTConvPdf.cxx:493
 RooFFTConvPdf.cxx:494
 RooFFTConvPdf.cxx:495
 RooFFTConvPdf.cxx:496
 RooFFTConvPdf.cxx:497
 RooFFTConvPdf.cxx:498
 RooFFTConvPdf.cxx:499
 RooFFTConvPdf.cxx:500
 RooFFTConvPdf.cxx:501
 RooFFTConvPdf.cxx:502
 RooFFTConvPdf.cxx:503
 RooFFTConvPdf.cxx:504
 RooFFTConvPdf.cxx:505
 RooFFTConvPdf.cxx:506
 RooFFTConvPdf.cxx:507
 RooFFTConvPdf.cxx:508
 RooFFTConvPdf.cxx:509
 RooFFTConvPdf.cxx:510
 RooFFTConvPdf.cxx:511
 RooFFTConvPdf.cxx:512
 RooFFTConvPdf.cxx:513
 RooFFTConvPdf.cxx:514
 RooFFTConvPdf.cxx:515
 RooFFTConvPdf.cxx:516
 RooFFTConvPdf.cxx:517
 RooFFTConvPdf.cxx:518
 RooFFTConvPdf.cxx:519
 RooFFTConvPdf.cxx:520
 RooFFTConvPdf.cxx:521
 RooFFTConvPdf.cxx:522
 RooFFTConvPdf.cxx:523
 RooFFTConvPdf.cxx:524
 RooFFTConvPdf.cxx:525
 RooFFTConvPdf.cxx:526
 RooFFTConvPdf.cxx:527
 RooFFTConvPdf.cxx:528
 RooFFTConvPdf.cxx:529
 RooFFTConvPdf.cxx:530
 RooFFTConvPdf.cxx:531
 RooFFTConvPdf.cxx:532
 RooFFTConvPdf.cxx:533
 RooFFTConvPdf.cxx:534
 RooFFTConvPdf.cxx:535
 RooFFTConvPdf.cxx:536
 RooFFTConvPdf.cxx:537
 RooFFTConvPdf.cxx:538
 RooFFTConvPdf.cxx:539
 RooFFTConvPdf.cxx:540
 RooFFTConvPdf.cxx:541
 RooFFTConvPdf.cxx:542
 RooFFTConvPdf.cxx:543
 RooFFTConvPdf.cxx:544
 RooFFTConvPdf.cxx:545
 RooFFTConvPdf.cxx:546
 RooFFTConvPdf.cxx:547
 RooFFTConvPdf.cxx:548
 RooFFTConvPdf.cxx:549
 RooFFTConvPdf.cxx:550
 RooFFTConvPdf.cxx:551
 RooFFTConvPdf.cxx:552
 RooFFTConvPdf.cxx:553
 RooFFTConvPdf.cxx:554
 RooFFTConvPdf.cxx:555
 RooFFTConvPdf.cxx:556
 RooFFTConvPdf.cxx:557
 RooFFTConvPdf.cxx:558
 RooFFTConvPdf.cxx:559
 RooFFTConvPdf.cxx:560
 RooFFTConvPdf.cxx:561
 RooFFTConvPdf.cxx:562
 RooFFTConvPdf.cxx:563
 RooFFTConvPdf.cxx:564
 RooFFTConvPdf.cxx:565
 RooFFTConvPdf.cxx:566
 RooFFTConvPdf.cxx:567
 RooFFTConvPdf.cxx:568
 RooFFTConvPdf.cxx:569
 RooFFTConvPdf.cxx:570
 RooFFTConvPdf.cxx:571
 RooFFTConvPdf.cxx:572
 RooFFTConvPdf.cxx:573
 RooFFTConvPdf.cxx:574
 RooFFTConvPdf.cxx:575
 RooFFTConvPdf.cxx:576
 RooFFTConvPdf.cxx:577
 RooFFTConvPdf.cxx:578
 RooFFTConvPdf.cxx:579
 RooFFTConvPdf.cxx:580
 RooFFTConvPdf.cxx:581
 RooFFTConvPdf.cxx:582
 RooFFTConvPdf.cxx:583
 RooFFTConvPdf.cxx:584
 RooFFTConvPdf.cxx:585
 RooFFTConvPdf.cxx:586
 RooFFTConvPdf.cxx:587
 RooFFTConvPdf.cxx:588
 RooFFTConvPdf.cxx:589
 RooFFTConvPdf.cxx:590
 RooFFTConvPdf.cxx:591
 RooFFTConvPdf.cxx:592
 RooFFTConvPdf.cxx:593
 RooFFTConvPdf.cxx:594
 RooFFTConvPdf.cxx:595
 RooFFTConvPdf.cxx:596
 RooFFTConvPdf.cxx:597
 RooFFTConvPdf.cxx:598
 RooFFTConvPdf.cxx:599
 RooFFTConvPdf.cxx:600
 RooFFTConvPdf.cxx:601
 RooFFTConvPdf.cxx:602
 RooFFTConvPdf.cxx:603
 RooFFTConvPdf.cxx:604
 RooFFTConvPdf.cxx:605
 RooFFTConvPdf.cxx:606
 RooFFTConvPdf.cxx:607
 RooFFTConvPdf.cxx:608
 RooFFTConvPdf.cxx:609
 RooFFTConvPdf.cxx:610
 RooFFTConvPdf.cxx:611
 RooFFTConvPdf.cxx:612
 RooFFTConvPdf.cxx:613
 RooFFTConvPdf.cxx:614
 RooFFTConvPdf.cxx:615
 RooFFTConvPdf.cxx:616
 RooFFTConvPdf.cxx:617
 RooFFTConvPdf.cxx:618
 RooFFTConvPdf.cxx:619
 RooFFTConvPdf.cxx:620
 RooFFTConvPdf.cxx:621
 RooFFTConvPdf.cxx:622
 RooFFTConvPdf.cxx:623
 RooFFTConvPdf.cxx:624
 RooFFTConvPdf.cxx:625
 RooFFTConvPdf.cxx:626
 RooFFTConvPdf.cxx:627
 RooFFTConvPdf.cxx:628
 RooFFTConvPdf.cxx:629
 RooFFTConvPdf.cxx:630
 RooFFTConvPdf.cxx:631
 RooFFTConvPdf.cxx:632
 RooFFTConvPdf.cxx:633
 RooFFTConvPdf.cxx:634
 RooFFTConvPdf.cxx:635
 RooFFTConvPdf.cxx:636
 RooFFTConvPdf.cxx:637
 RooFFTConvPdf.cxx:638
 RooFFTConvPdf.cxx:639
 RooFFTConvPdf.cxx:640
 RooFFTConvPdf.cxx:641
 RooFFTConvPdf.cxx:642
 RooFFTConvPdf.cxx:643
 RooFFTConvPdf.cxx:644
 RooFFTConvPdf.cxx:645
 RooFFTConvPdf.cxx:646
 RooFFTConvPdf.cxx:647
 RooFFTConvPdf.cxx:648
 RooFFTConvPdf.cxx:649
 RooFFTConvPdf.cxx:650
 RooFFTConvPdf.cxx:651
 RooFFTConvPdf.cxx:652
 RooFFTConvPdf.cxx:653
 RooFFTConvPdf.cxx:654
 RooFFTConvPdf.cxx:655
 RooFFTConvPdf.cxx:656
 RooFFTConvPdf.cxx:657
 RooFFTConvPdf.cxx:658
 RooFFTConvPdf.cxx:659
 RooFFTConvPdf.cxx:660
 RooFFTConvPdf.cxx:661
 RooFFTConvPdf.cxx:662
 RooFFTConvPdf.cxx:663
 RooFFTConvPdf.cxx:664
 RooFFTConvPdf.cxx:665
 RooFFTConvPdf.cxx:666
 RooFFTConvPdf.cxx:667
 RooFFTConvPdf.cxx:668
 RooFFTConvPdf.cxx:669
 RooFFTConvPdf.cxx:670
 RooFFTConvPdf.cxx:671
 RooFFTConvPdf.cxx:672
 RooFFTConvPdf.cxx:673
 RooFFTConvPdf.cxx:674
 RooFFTConvPdf.cxx:675
 RooFFTConvPdf.cxx:676
 RooFFTConvPdf.cxx:677
 RooFFTConvPdf.cxx:678
 RooFFTConvPdf.cxx:679
 RooFFTConvPdf.cxx:680
 RooFFTConvPdf.cxx:681
 RooFFTConvPdf.cxx:682
 RooFFTConvPdf.cxx:683
 RooFFTConvPdf.cxx:684
 RooFFTConvPdf.cxx:685
 RooFFTConvPdf.cxx:686
 RooFFTConvPdf.cxx:687
 RooFFTConvPdf.cxx:688
 RooFFTConvPdf.cxx:689
 RooFFTConvPdf.cxx:690
 RooFFTConvPdf.cxx:691
 RooFFTConvPdf.cxx:692
 RooFFTConvPdf.cxx:693
 RooFFTConvPdf.cxx:694
 RooFFTConvPdf.cxx:695
 RooFFTConvPdf.cxx:696
 RooFFTConvPdf.cxx:697
 RooFFTConvPdf.cxx:698
 RooFFTConvPdf.cxx:699
 RooFFTConvPdf.cxx:700
 RooFFTConvPdf.cxx:701
 RooFFTConvPdf.cxx:702
 RooFFTConvPdf.cxx:703
 RooFFTConvPdf.cxx:704
 RooFFTConvPdf.cxx:705
 RooFFTConvPdf.cxx:706
 RooFFTConvPdf.cxx:707
 RooFFTConvPdf.cxx:708
 RooFFTConvPdf.cxx:709
 RooFFTConvPdf.cxx:710
 RooFFTConvPdf.cxx:711
 RooFFTConvPdf.cxx:712
 RooFFTConvPdf.cxx:713
 RooFFTConvPdf.cxx:714
 RooFFTConvPdf.cxx:715
 RooFFTConvPdf.cxx:716
 RooFFTConvPdf.cxx:717
 RooFFTConvPdf.cxx:718
 RooFFTConvPdf.cxx:719
 RooFFTConvPdf.cxx:720
 RooFFTConvPdf.cxx:721
 RooFFTConvPdf.cxx:722
 RooFFTConvPdf.cxx:723
 RooFFTConvPdf.cxx:724
 RooFFTConvPdf.cxx:725
 RooFFTConvPdf.cxx:726
 RooFFTConvPdf.cxx:727
 RooFFTConvPdf.cxx:728
 RooFFTConvPdf.cxx:729
 RooFFTConvPdf.cxx:730
 RooFFTConvPdf.cxx:731
 RooFFTConvPdf.cxx:732
 RooFFTConvPdf.cxx:733
 RooFFTConvPdf.cxx:734
 RooFFTConvPdf.cxx:735
 RooFFTConvPdf.cxx:736
 RooFFTConvPdf.cxx:737
 RooFFTConvPdf.cxx:738
 RooFFTConvPdf.cxx:739
 RooFFTConvPdf.cxx:740
 RooFFTConvPdf.cxx:741
 RooFFTConvPdf.cxx:742
 RooFFTConvPdf.cxx:743
 RooFFTConvPdf.cxx:744
 RooFFTConvPdf.cxx:745
 RooFFTConvPdf.cxx:746
 RooFFTConvPdf.cxx:747
 RooFFTConvPdf.cxx:748
 RooFFTConvPdf.cxx:749
 RooFFTConvPdf.cxx:750
 RooFFTConvPdf.cxx:751
 RooFFTConvPdf.cxx:752
 RooFFTConvPdf.cxx:753
 RooFFTConvPdf.cxx:754
 RooFFTConvPdf.cxx:755
 RooFFTConvPdf.cxx:756
 RooFFTConvPdf.cxx:757
 RooFFTConvPdf.cxx:758
 RooFFTConvPdf.cxx:759
 RooFFTConvPdf.cxx:760
 RooFFTConvPdf.cxx:761
 RooFFTConvPdf.cxx:762
 RooFFTConvPdf.cxx:763
 RooFFTConvPdf.cxx:764
 RooFFTConvPdf.cxx:765
 RooFFTConvPdf.cxx:766
 RooFFTConvPdf.cxx:767
 RooFFTConvPdf.cxx:768
 RooFFTConvPdf.cxx:769
 RooFFTConvPdf.cxx:770
 RooFFTConvPdf.cxx:771
 RooFFTConvPdf.cxx:772
 RooFFTConvPdf.cxx:773
 RooFFTConvPdf.cxx:774
 RooFFTConvPdf.cxx:775
 RooFFTConvPdf.cxx:776
 RooFFTConvPdf.cxx:777
 RooFFTConvPdf.cxx:778
 RooFFTConvPdf.cxx:779
 RooFFTConvPdf.cxx:780
 RooFFTConvPdf.cxx:781
 RooFFTConvPdf.cxx:782
 RooFFTConvPdf.cxx:783
 RooFFTConvPdf.cxx:784
 RooFFTConvPdf.cxx:785
 RooFFTConvPdf.cxx:786
 RooFFTConvPdf.cxx:787
 RooFFTConvPdf.cxx:788
 RooFFTConvPdf.cxx:789
 RooFFTConvPdf.cxx:790
 RooFFTConvPdf.cxx:791
 RooFFTConvPdf.cxx:792
 RooFFTConvPdf.cxx:793
 RooFFTConvPdf.cxx:794
 RooFFTConvPdf.cxx:795
 RooFFTConvPdf.cxx:796
 RooFFTConvPdf.cxx:797
 RooFFTConvPdf.cxx:798
 RooFFTConvPdf.cxx:799
 RooFFTConvPdf.cxx:800
 RooFFTConvPdf.cxx:801
 RooFFTConvPdf.cxx:802
 RooFFTConvPdf.cxx:803
 RooFFTConvPdf.cxx:804
 RooFFTConvPdf.cxx:805
 RooFFTConvPdf.cxx:806
 RooFFTConvPdf.cxx:807
 RooFFTConvPdf.cxx:808
 RooFFTConvPdf.cxx:809
 RooFFTConvPdf.cxx:810
 RooFFTConvPdf.cxx:811
 RooFFTConvPdf.cxx:812
 RooFFTConvPdf.cxx:813
 RooFFTConvPdf.cxx:814
 RooFFTConvPdf.cxx:815
 RooFFTConvPdf.cxx:816
 RooFFTConvPdf.cxx:817
 RooFFTConvPdf.cxx:818
 RooFFTConvPdf.cxx:819
 RooFFTConvPdf.cxx:820
 RooFFTConvPdf.cxx:821
 RooFFTConvPdf.cxx:822
 RooFFTConvPdf.cxx:823
 RooFFTConvPdf.cxx:824
 RooFFTConvPdf.cxx:825
 RooFFTConvPdf.cxx:826
 RooFFTConvPdf.cxx:827
 RooFFTConvPdf.cxx:828
 RooFFTConvPdf.cxx:829
 RooFFTConvPdf.cxx:830
 RooFFTConvPdf.cxx:831
 RooFFTConvPdf.cxx:832
 RooFFTConvPdf.cxx:833
 RooFFTConvPdf.cxx:834
 RooFFTConvPdf.cxx:835
 RooFFTConvPdf.cxx:836
 RooFFTConvPdf.cxx:837
 RooFFTConvPdf.cxx:838
 RooFFTConvPdf.cxx:839
 RooFFTConvPdf.cxx:840
 RooFFTConvPdf.cxx:841
 RooFFTConvPdf.cxx:842
 RooFFTConvPdf.cxx:843
 RooFFTConvPdf.cxx:844
 RooFFTConvPdf.cxx:845
 RooFFTConvPdf.cxx:846
 RooFFTConvPdf.cxx:847
 RooFFTConvPdf.cxx:848
 RooFFTConvPdf.cxx:849
 RooFFTConvPdf.cxx:850
 RooFFTConvPdf.cxx:851
 RooFFTConvPdf.cxx:852
 RooFFTConvPdf.cxx:853
 RooFFTConvPdf.cxx:854
 RooFFTConvPdf.cxx:855
 RooFFTConvPdf.cxx:856
 RooFFTConvPdf.cxx:857
 RooFFTConvPdf.cxx:858
 RooFFTConvPdf.cxx:859
 RooFFTConvPdf.cxx:860
 RooFFTConvPdf.cxx:861