105using FFTComplex = std::complex<double>;
110void fftRadix2(std::vector<FFTComplex> &
a,
int sign)
112 const std::size_t
n =
a.size();
117 for (std::size_t i = 1, j = 0; i <
n; ++i) {
118 std::size_t bit =
n >> 1;
119 for (; j & bit; bit >>= 1) {
124 std::swap(
a[i],
a[j]);
133 std::vector<FFTComplex> tw(
n >> 1);
134 const double angle = sign * 2.0 *
TMath::Pi() /
static_cast<double>(
n);
135 for (std::size_t k = 0; k < tw.size(); ++k) {
136 tw[k] = std::polar(1.0,
angle *
static_cast<double>(k));
140 for (std::size_t
len = 2;
len <=
n;
len <<= 1) {
141 const std::size_t half =
len >> 1;
142 const std::size_t stride =
n /
len;
143 for (std::size_t i = 0; i <
n; i +=
len) {
144 for (std::size_t k = 0; k < half; ++k) {
145 const FFTComplex u =
a[i + k];
146 const FFTComplex
v =
a[i + k + half] * tw[k * stride];
148 a[i + k + half] = u -
v;
166void doFFT(
int n,
double const *input1,
double const *input2,
double *output)
170 const std::size_t
N =
static_cast<std::size_t
>(
n);
173 if ((
N & (
N - 1)) != 0) {
175 while (
m < 2 *
N - 1) {
180 std::vector<FFTComplex> z(
m, FFTComplex(0.0, 0.0));
181 bool nonNegativeInputs =
true;
182 for (std::size_t k = 0; k <
N; ++k) {
183 nonNegativeInputs &= input1[k] >= 0.0 && input2[k] >= 0.0;
184 z[k] = FFTComplex(input1[k], input2[k]);
193 for (std::size_t k = 0; k <=
m / 2; ++k) {
194 const std::size_t j = (
m - k) & (
m - 1);
195 const FFTComplex zk = z[k];
196 const FFTComplex zjc = std::conj(z[j]);
197 const FFTComplex ak = 0.5 * (zk + zjc);
198 const FFTComplex bk = FFTComplex(0.0, -0.5) * (zk - zjc);
199 const FFTComplex pk = ak * bk;
201 z[j] = std::conj(pk);
208 const double scale =
static_cast<double>(
N) /
static_cast<double>(
m);
209 for (std::size_t k = 0; k <
N; ++k) {
210 double val = z[k].real();
212 val += z[k +
N].real();
218 if (nonNegativeInputs && val < 0.0) {
227using std::endl, std::string, std::ostream;
244 _x(
"!x",
"Convolution Variable", this, convVar),
245 _xprime(
"!xprime",
"External Convolution Variable", this, false),
246 _pdf1(
"!pdf1",
"pdf1", this, pdf1, false),
247 _pdf2(
"!pdf2",
"pdf2", this, pdf2, false),
248 _params(
"!params",
"effective parameters", this),
252 _shift2((convVar.getMax(
"cache") + convVar.getMin(
"cache")) / 2),
253 _cacheObs(
"!cacheObs",
"Cached observables", this, false, false)
270 _x(
"!x",
"Convolution Variable", this, convVar, false, false),
271 _xprime(
"!xprime",
"External Convolution Variable", this, pdfConvVar),
272 _pdf1(
"!pdf1",
"pdf1", this, pdf1, false),
273 _pdf2(
"!pdf2",
"pdf2", this, pdf2, false),
274 _params(
"!params",
"effective parameters", this),
278 _shift2((convVar.getMax(
"cache") + convVar.getMin(
"cache")) / 2),
279 _cacheObs(
"!cacheObs",
"Cached observables", this, false, false)
293 _x(
"!x",this,other._x),
294 _xprime(
"!xprime",this,other._xprime),
295 _pdf1(
"!pdf1",this,other._pdf1),
296 _pdf2(
"!pdf2",this,other._pdf2),
297 _params(
"!params",this,other._params),
298 _bufFrac(other._bufFrac),
299 _bufStrat(other._bufStrat),
300 _shift1(other._shift1),
301 _shift2(other._shift2),
302 _cacheObs(
"!cacheObs",this,other._cacheObs)
328 coutI(Caching) <<
"Changing internal binning of variable '" << convVar.
GetName()
329 <<
"' in FFT '" <<
fName <<
"'"
330 <<
" from " << varBinning.
numBins()
331 <<
" to " << optimal <<
" to improve the precision of the numerical FFT."
332 <<
" This can be done manually by setting an additional binning named 'cache'." << std::endl;
335 coutE(Caching) <<
"The internal binning of variable " << convVar.
GetName()
336 <<
" is not uniform. The numerical FFT will likely yield wrong results." << std::endl;
350 name.Append(
"_CONV_") ;
384 string refName =
Form(
"refrange_fft_%s",self.
GetName()) ;
397 pdf1Clone->addOwnedComponents(*shiftObs1) ;
398 pdf1Clone->addOwnedComponents(*clonePdf1) ;
412 pdf1Clone->addOwnedComponents(*shiftObs2) ;
413 pdf1Clone->addOwnedComponents(*clonePdf2) ;
439 pdf1Clone->recursiveRedirectServers(fftParams) ;
440 pdf2Clone->recursiveRedirectServers(fftParams) ;
441 pdf1Clone->fixAddCoefRange(refName.c_str(),
true) ;
442 pdf2Clone->fixAddCoefRange(refName.c_str(),
true) ;
446 pdf1Clone->fixAddCoefNormalization(convSet,
true);
447 pdf2Clone->fixAddCoefNormalization(convSet,
true);
454 oocoutW(&self, Eval) <<
"The FFT convolution '" << self.
GetName() <<
"' will run with " <<
N
455 <<
" bins. A decent accuracy for difficult convolutions is typically only reached with n >= 1000. Suggest to increase the number"
456 " of bins of the observable '" << convObs->
GetName() <<
"'." << std::endl;
489 ret.
add(*pdf1Clone) ;
490 ret.
add(*pdf2Clone) ;
491 if (pdf1Clone->ownedComponents()) {
492 ret.
add(*pdf1Clone->ownedComponents()) ;
494 if (pdf2Clone->ownedComponents()) {
495 ret.
add(*pdf2Clone->ownedComponents()) ;
519 otherObs.
remove(*histArg,
true,
true) ;
525 if (otherObs.
empty()) {
535 std::vector<int> binCur(
n+1);
536 std::vector<int> binMax(
n+1);
539 std::vector<RooAbsLValue*> obsLV(
n);
541 for (
auto* lvarg : dynamic_range_cast<RooAbsLValue*>(otherObs)) {
560 while(binCur[curObs]==binMax[curObs]) {
613 std::vector<double> output(N2);
614 doFFT(N2, input1.data(), input2.data(), output.data());
616 Int_t totalShift = binShift1 + (N2-
N)/2 ;
620 std::unique_ptr<TIterator> iter{
const_cast<RooDataHist&
>(cacheHist).sliceIterator(
const_cast<RooAbsReal&
>(
_x.
arg()),slicePos)};
621 for (
Int_t i =0 ; i<
N ; i++) {
624 Int_t j = i + totalShift ;
626 while (j>=N2) j-= N2 ;
629 const std::size_t binIdx = cacheHist.
getIndex(*cacheHist.
get(),
true);
630 cacheHist.
set(binIdx, output[j], -1.);
655 std::vector<double> array(N2);
664 }
else if (histX->
getMin()>0) {
674 zeroBin += binShift ;
675 while(zeroBin>=N2) zeroBin-= N2 ;
676 while(zeroBin<0) zeroBin+= N2 ;
679 auto getPdfVal = [&]() {
680 double rawVal = pdf.
getVal();
685 std::vector<double> tmp(N2);
691 for (k=0 ; k<N2 ; k++) {
693 tmp[k] = getPdfVal();
702 double val = getPdfVal();
703 for (k=0 ; k<Nbuf ; k++) {
706 for (k=0 ; k<
N ; k++) {
708 tmp[k+Nbuf] = getPdfVal();
712 for (k=0 ; k<Nbuf ; k++) {
713 tmp[
N+Nbuf+k] = val ;
721 for (k=0 ; k<
N ; k++) {
723 tmp[k+Nbuf] = getPdfVal();
725 for (k=1 ; k<=Nbuf ; k++) {
727 tmp[Nbuf-k] = getPdfVal();
729 tmp[Nbuf+
N+k-1] = getPdfVal();
735 for (
Int_t i=0 ; i<N2 ; i++) {
737 Int_t j = i - (zeroBin) ;
768 obs1->add(obs2,
true) ;
775 for(
auto const& arg : *obs1) {
780 obs1->remove(killList) ;
783 obs1->add(
_x.
arg(),
true) ;
792 for(
auto const& arg : *obs1) {
797 obs1->remove(killList) ;
802 obs1->add(
_x.
arg(),
true) ;
835 return histObservable ;
848 const RooArgSet* auxProto,
bool verbose)
const
862 <<
" has internal generator that is safe to use in current context" << std::endl ;
866 <<
" has internal generator that is safe to use in current context" << std::endl ;
869 cxcoutI(Generation) <<
"RooFFTConvPdf::genContext() generation requested for observables other than the convolution observable " <<
_x.
arg().
GetName() << std::endl ;
873 if (numAddDep>0 || !pdfCanDir || !resCanDir) {
876 cxcoutI(Generation) <<
"RooFFTConvPdf::genContext() selecting accept/reject generator context because one or both of the input "
877 <<
"p.d.f.s cannot use internal generator and/or "
878 <<
"observables other than the convolution variable are requested for generation" << std::endl ;
879 return new RooGenContext(*
this,vars,prototype,auxProto,verbose) ;
883 cxcoutI(Generation) <<
"RooFFTConvPdf::genContext() selecting specialized convolution generator context as both input "
884 <<
"p.d.fs are safe for internal generator and only "
885 <<
"the convolution observables is requested for generation" << std::endl ;
898 coutE(InputArguments) <<
"RooFFTConvPdf::setBufferFraction(" <<
GetName() <<
") fraction should be greater than or equal to zero" << std::endl ;
int Int_t
Signed integer 4 bytes (int)
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint angle
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Common abstract base class for objects that represent a value and a "shape" in RooFit.
void setOperMode(OperMode mode, bool recurseADirty=true)
Set the operation mode of this node.
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
RooFit::OwningPtr< RooArgSet > getObservables(const RooArgSet &set, bool valueOnly=true) const
Given a set of possible observables, return the observables that this PDF depends on.
RooFit::OwningPtr< RooArgSet > getVariables(bool stripDisconnected=true) const
Return RooArgSet with all variables (tree leaf nodes of expression tree)
virtual RooAbsArg * cloneTree(const char *newname=nullptr) const
Clone tree expression of objects.
void attachDataSet(const RooAbsData &set)
Replace server nodes with names matching the dataset variable names with those data set variables,...
Abstract base class for RooRealVar binning definitions.
int binNumber(double x) const
Returns the bin number corresponding to the value x.
Int_t numBins() const
Return number of bins.
virtual bool isUniform() const
virtual double highBound() const =0
virtual double lowBound() const =0
virtual RooAbsBinning * clone(const char *name=nullptr) const =0
Abstract base class for p.d.f.s that need or want to cache their evaluate() output in a RooHistPdf de...
virtual const char * binningName() const
RooObjCacheManager _cacheMgr
! The cache manager
bool contains(const char *name) const
Check if collection contains an argument with a specific name.
virtual bool remove(const RooAbsArg &var, bool silent=false, bool matchByNameOnly=false)
Remove the specified argument from our list.
virtual bool add(const RooAbsArg &var, bool silent=false)
Add the specified argument to list.
Storage_t::size_type size() const
RooAbsArg * find(const char *name) const
Find object with given name in list.
void setDirtyProp(bool flag)
Control propagation of dirty flags from observables in dataset.
Abstract base class for generator contexts of RooAbsPdf objects.
Abstract interface for all probability density functions.
Int_t numBins(const char *rangeName=nullptr) const override
virtual double getMax(const char *name=nullptr) const
Get maximum of currently defined range.
void setBin(Int_t ibin, const char *rangeName=nullptr) override
Set value to center of bin 'ibin' of binning 'rangeName' (or of default binning if no range is specif...
virtual double getMin(const char *name=nullptr) const
Get minimum of currently defined range.
Abstract base class for objects that represent a real value and implements functionality common to al...
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
RooArgList is a container object that can hold multiple RooAbsArg objects.
RooAbsArg * absArg() const
Return pointer to contained argument.
RooArgSet is a container object that can hold multiple RooAbsArg objects.
RooArgSet * snapshot(bool deepCopy=true) const
Use RooAbsCollection::snapshot(), but return as RooArgSet.
void removeAll() override
Remove all argument inset using remove(const RooAbsArg&).
bool add(const RooAbsArg &var, bool valueServer, bool shapeServer, bool silent)
Overloaded RooCollection_t::add() method insert object into set and registers object as server to own...
RooCustomizer is a factory class to produce clones of a prototype composite PDF object with the same ...
void replaceArg(const RooAbsArg &orig, const RooAbsArg &subst)
Replace any occurrence of arg 'orig' with arg 'subst'.
RooAbsArg * build(const char *masterCatState, bool verbose=false)
Build a clone of the prototype executing all registered 'replace' rules and 'split' rules for the mas...
Container class to hold N-dimensional binned data.
Int_t getIndex(const RooAbsCollection &coord, bool fast=false) const
Calculate bin number of the given coordinates.
void set(std::size_t binNumber, double weight, double wgtErr)
Set bin content of bin that was last loaded with get(std::size_t).
const RooArgSet * get() const override
Get bin centre of current bin.
Container class to hold unbinned data.
RooArgList containedArgs(Action) override
Returns all RooAbsArg objects contained in the cache element.
std::unique_ptr< RooAbsPdf > pdf2Clone
FFTCacheElem(const RooFFTConvPdf &self, const RooArgSet *nset)
Clone input pdf and attach to dataset.
std::unique_ptr< RooAbsBinning > histBinning
std::unique_ptr< RooAbsBinning > scanBinning
std::unique_ptr< RooAbsPdf > pdf1Clone
PDF for the numerical (FFT) convolution of two PDFs.
friend class RooConvGenContext
RooSetProxy _params
Effective parameters of this p.d.f.
void calcParams()
(Re)calculate effective parameters of this p.d.f.
void setBufferFraction(double frac)
Change the size of the buffer on either side of the observable range to frac times the size of the ra...
double bufferFraction() const
Return value of buffer fraction applied in FFT calculation array beyond either end of the observable ...
TString histNameSuffix() const override
Suffix for cache histogram (added in addition to suffix for cache name)
void prepareFFTBinning(RooRealVar &convVar) const
Try to improve the binning and inform user if possible.
void fillCacheSlice(FFTCacheElem &cache, const RooArgSet &slicePosition) const
Fill a slice of cachePdf with the output of the FFT convolution calculation.
RooRealProxy _xprime
Input function representing value of convolution observable.
RooRealProxy _pdf1
First input p.d.f.
RooRealProxy _x
Convolution observable.
const char * inputBaseName() const override
Return base name component for cache components in this case 'PDF1_CONV_PDF2'.
RooAbsArg & pdfObservable(RooAbsArg &histObservable) const override
Return p.d.f.
std::vector< double > scanPdf(RooRealVar &obs, RooAbsPdf &pdf, double normVal, const RooDataHist &hist, const RooArgSet &slicePos, Int_t &N, Int_t &N2, Int_t &zeroBin, double shift) const
Scan the values of 'pdf' in observable 'obs' using the bin values stored in 'hist' at slice position ...
~RooFFTConvPdf() override
Destructor.
RooFit::OwningPtr< RooArgSet > actualParameters(const RooArgSet &nset) const override
Return the parameters on which the cache depends given normalization set nset.
RooRealProxy _pdf2
Second input p.d.f.
void printMetaArgs(std::ostream &os) const override
Customized printing of arguments of a RooNumConvPdf to more intuitively reflect the contents of the p...
void setBufferStrategy(BufStrat bs)
Change strategy to fill the overflow buffer on either side of the convolution observable range.
PdfCacheElem * createCache(const RooArgSet *nset) const override
Return specialized cache subclass for FFT calculations.
RooAbsGenContext * genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose=false) const override
Create appropriate generator context for this convolution.
RooFit::OwningPtr< RooArgSet > actualObservables(const RooArgSet &nset) const override
Return the observables to be cached given the normalization set nset.
void fillCacheObject(PdfCacheElem &cache) const override
Fill the contents of the cache the FFT convolution output.
friend class FFTCacheElem
RooSetProxy _cacheObs
Non-convolution observables that are also cached.
Implements a universal generator context for all RooAbsPdf classes that do not have or need a special...
RooLinearVar is the most general form of a derived real-valued object that can be used by RooRealInte...
void sterilize() override
Clear the cache payload but retain slot mapping w.r.t to normalization and integration sets.
Variable that can be changed from the outside.
bool hasBinning(const char *name) const override
Returns true if variable has a binning named 'name'.
void setRange(const char *name, double min, double max, bool shared=true)
Set a fit or plotting range.
void setBinning(const RooAbsBinning &binning, const char *name=nullptr, bool shared=true)
Add given binning under name 'name' with this variable.
const RooAbsBinning & getBinning(const char *name=nullptr, bool verbose=true, bool createOnTheFly=false, bool shared=true) const override
Return binning definition with name.
const T & arg() const
Return reference to object held in proxy.
const char * GetName() const override
Returns name of object.
RooConstVar & RooConst(double val)
double normalizeWithNaNPacking(RooAbsPdf const &pdf, double rawVal, double normVal)
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.