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

#ifndef ROOFFTCONVPDF
#define ROOFFTCONVPDF

#include "RooAbsCachedPdf.h"
#include "RooRealProxy.h"
#include "RooSetProxy.h"
#include "RooAbsReal.h"
#include "RooHistPdf.h"
#include "TVirtualFFT.h"
class RooRealVar ;

#include <map>
 
class RooFFTConvPdf : public RooAbsCachedPdf {
public:

  RooFFTConvPdf() {
    // coverity[UNINIT_CTOR]
  } ;
  RooFFTConvPdf(const char *name, const char *title, RooRealVar& convVar, RooAbsPdf& pdf1, RooAbsPdf& pdf2, Int_t ipOrder=2);
  RooFFTConvPdf(const char *name, const char *title, RooAbsReal& pdfConvVar, RooRealVar& convVar, RooAbsPdf& pdf1, RooAbsPdf& pdf2, Int_t ipOrder=2);
  RooFFTConvPdf(const RooFFTConvPdf& other, const char* name=0) ;
  virtual TObject* clone(const char* newname) const { return new RooFFTConvPdf(*this,newname); }
  virtual ~RooFFTConvPdf() ;

  void setShift(Double_t val1, Double_t val2) { _shift1 = val1 ; _shift2 = val2 ; }
  void setCacheObservables(const RooArgSet& obs) { _cacheObs.removeAll() ; _cacheObs.add(obs) ; }
  const RooArgSet& cacheObservables() const { return _cacheObs ; }
  
  Double_t bufferFraction() const { 
    // Return value of buffer fraction applied in FFT calculation array beyond either
    // end of the observable domain to reduce cyclical effects
    return _bufFrac ; 
  }

  enum BufStrat { Extend=0, Mirror=1, Flat=2 } ;
  BufStrat bufferStrategy() const {
    // Return the strategy currently used to fill the buffer: 
    // '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 mirror image of the p.d.f. around the convolution observable boundary 
    return _bufStrat ;
  }
  void setBufferStrategy(BufStrat bs) ;
  void setBufferFraction(Double_t frac) ;

  void printMetaArgs(std::ostream& os) const ;

  // Propagate maximum value estimate of pdf1 as convolution can only result in lower max values
  virtual Int_t getMaxVal(const RooArgSet& vars) const { return _pdf1.arg().getMaxVal(vars) ; }
  virtual Double_t maxVal(Int_t code) const { return _pdf1.arg().maxVal(code) ; }


protected:

  RooRealProxy _x ;       // Convolution observable
  RooRealProxy _xprime ;  // Input function representing value of convolution observable
  RooRealProxy _pdf1 ; // First input p.d.f
  RooRealProxy _pdf2 ; // Second input p.d.f
  RooSetProxy _params ; // Effective parameters of this p.d.f.

  void calcParams() ;
  Bool_t redirectServersHook(const RooAbsCollection& newServerList, Bool_t mustReplaceAll, Bool_t nameChange, Bool_t isRecursive) ;

  Double_t*  scanPdf(RooRealVar& obs, RooAbsPdf& pdf, const RooDataHist& hist, const RooArgSet& slicePos, Int_t& N, Int_t& N2, Int_t& zeroBin, Double_t shift) const ;

  class FFTCacheElem : public PdfCacheElem {
  public:
    FFTCacheElem(const RooFFTConvPdf& self, const RooArgSet* nset) ;
    ~FFTCacheElem() ;

    virtual RooArgList containedArgs(Action) ;

    TVirtualFFT* fftr2c1 ;
    TVirtualFFT* fftr2c2 ;
    TVirtualFFT* fftc2r ;

    RooAbsPdf* pdf1Clone ;
    RooAbsPdf* pdf2Clone ;

    RooAbsBinning* histBinning ;
    RooAbsBinning* scanBinning ;

  };

  friend class FFTCacheElem ;  

  virtual Double_t evaluate() const { RooArgSet dummy(_x.arg()) ; return getVal(&dummy) ; } ; // dummy
  virtual const char* inputBaseName() const ;
  virtual RooArgSet* actualObservables(const RooArgSet& nset) const ;
  virtual RooArgSet* actualParameters(const RooArgSet& nset) const ;
  virtual RooAbsArg& pdfObservable(RooAbsArg& histObservable) const ;
  virtual void fillCacheObject(PdfCacheElem& cache) const ;
  void fillCacheSlice(FFTCacheElem& cache, const RooArgSet& slicePosition) const ;

  virtual PdfCacheElem* createCache(const RooArgSet* nset) const ;
  virtual TString histNameSuffix() const ;

  // mutable std::map<const RooHistPdf*,CacheAuxInfo*> _cacheAuxInfo ; //! Auxilary Cache information (do not persist)
  Double_t _bufFrac ; // Sampling buffer size as fraction of domain size 
  BufStrat _bufStrat ; // Strategy to fill the buffer

  Double_t  _shift1 ; 
  Double_t  _shift2 ; 

  virtual RooAbsGenContext* genContext(const RooArgSet &vars, const RooDataSet *prototype=0, 
                                       const RooArgSet* auxProto=0, Bool_t verbose= kFALSE) const ;

  friend class RooConvGenContext ;
  RooSetProxy  _cacheObs ; // Non-convolution observables that are also cached

private:

  ClassDef(RooFFTConvPdf,1) // Convolution operator p.d.f based on numeric Fourier transforms
};
 
#endif
 RooFFTConvPdf.h:1
 RooFFTConvPdf.h:2
 RooFFTConvPdf.h:3
 RooFFTConvPdf.h:4
 RooFFTConvPdf.h:5
 RooFFTConvPdf.h:6
 RooFFTConvPdf.h:7
 RooFFTConvPdf.h:8
 RooFFTConvPdf.h:9
 RooFFTConvPdf.h:10
 RooFFTConvPdf.h:11
 RooFFTConvPdf.h:12
 RooFFTConvPdf.h:13
 RooFFTConvPdf.h:14
 RooFFTConvPdf.h:15
 RooFFTConvPdf.h:16
 RooFFTConvPdf.h:17
 RooFFTConvPdf.h:18
 RooFFTConvPdf.h:19
 RooFFTConvPdf.h:20
 RooFFTConvPdf.h:21
 RooFFTConvPdf.h:22
 RooFFTConvPdf.h:23
 RooFFTConvPdf.h:24
 RooFFTConvPdf.h:25
 RooFFTConvPdf.h:26
 RooFFTConvPdf.h:27
 RooFFTConvPdf.h:28
 RooFFTConvPdf.h:29
 RooFFTConvPdf.h:30
 RooFFTConvPdf.h:31
 RooFFTConvPdf.h:32
 RooFFTConvPdf.h:33
 RooFFTConvPdf.h:34
 RooFFTConvPdf.h:35
 RooFFTConvPdf.h:36
 RooFFTConvPdf.h:37
 RooFFTConvPdf.h:38
 RooFFTConvPdf.h:39
 RooFFTConvPdf.h:40
 RooFFTConvPdf.h:41
 RooFFTConvPdf.h:42
 RooFFTConvPdf.h:43
 RooFFTConvPdf.h:44
 RooFFTConvPdf.h:45
 RooFFTConvPdf.h:46
 RooFFTConvPdf.h:47
 RooFFTConvPdf.h:48
 RooFFTConvPdf.h:49
 RooFFTConvPdf.h:50
 RooFFTConvPdf.h:51
 RooFFTConvPdf.h:52
 RooFFTConvPdf.h:53
 RooFFTConvPdf.h:54
 RooFFTConvPdf.h:55
 RooFFTConvPdf.h:56
 RooFFTConvPdf.h:57
 RooFFTConvPdf.h:58
 RooFFTConvPdf.h:59
 RooFFTConvPdf.h:60
 RooFFTConvPdf.h:61
 RooFFTConvPdf.h:62
 RooFFTConvPdf.h:63
 RooFFTConvPdf.h:64
 RooFFTConvPdf.h:65
 RooFFTConvPdf.h:66
 RooFFTConvPdf.h:67
 RooFFTConvPdf.h:68
 RooFFTConvPdf.h:69
 RooFFTConvPdf.h:70
 RooFFTConvPdf.h:71
 RooFFTConvPdf.h:72
 RooFFTConvPdf.h:73
 RooFFTConvPdf.h:74
 RooFFTConvPdf.h:75
 RooFFTConvPdf.h:76
 RooFFTConvPdf.h:77
 RooFFTConvPdf.h:78
 RooFFTConvPdf.h:79
 RooFFTConvPdf.h:80
 RooFFTConvPdf.h:81
 RooFFTConvPdf.h:82
 RooFFTConvPdf.h:83
 RooFFTConvPdf.h:84
 RooFFTConvPdf.h:85
 RooFFTConvPdf.h:86
 RooFFTConvPdf.h:87
 RooFFTConvPdf.h:88
 RooFFTConvPdf.h:89
 RooFFTConvPdf.h:90
 RooFFTConvPdf.h:91
 RooFFTConvPdf.h:92
 RooFFTConvPdf.h:93
 RooFFTConvPdf.h:94
 RooFFTConvPdf.h:95
 RooFFTConvPdf.h:96
 RooFFTConvPdf.h:97
 RooFFTConvPdf.h:98
 RooFFTConvPdf.h:99
 RooFFTConvPdf.h:100
 RooFFTConvPdf.h:101
 RooFFTConvPdf.h:102
 RooFFTConvPdf.h:103
 RooFFTConvPdf.h:104
 RooFFTConvPdf.h:105
 RooFFTConvPdf.h:106
 RooFFTConvPdf.h:107
 RooFFTConvPdf.h:108
 RooFFTConvPdf.h:109
 RooFFTConvPdf.h:110
 RooFFTConvPdf.h:111
 RooFFTConvPdf.h:112
 RooFFTConvPdf.h:113
 RooFFTConvPdf.h:114
 RooFFTConvPdf.h:115
 RooFFTConvPdf.h:116
 RooFFTConvPdf.h:117
 RooFFTConvPdf.h:118
 RooFFTConvPdf.h:119
 RooFFTConvPdf.h:120
 RooFFTConvPdf.h:121
 RooFFTConvPdf.h:122
 RooFFTConvPdf.h:123
 RooFFTConvPdf.h:124
 RooFFTConvPdf.h:125
 RooFFTConvPdf.h:126
 RooFFTConvPdf.h:127
 RooFFTConvPdf.h:128