#include "TROOT.h"
#include "TF2.h"
#include "TMath.h"
#include "TRandom.h"
#include "TH2.h"
#include "TVirtualPad.h"
#include "TStyle.h"
#include "Riostream.h"
#include "TColor.h"
#include "TVirtualFitter.h"
#include "TClass.h"
ClassImp(TF2)
/*
<img src="gif/function2.gif">
*/
//End_Html
TF2::TF2(): TF1(),fYmin(0),fYmax(0),fNpy(100)
{
}
TF2::TF2(const char *name,const char *formula, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax)
:TF1(name,formula,xmax,xmin)
{
if (ymin < ymax) {
fYmin = ymin;
fYmax = ymax;
} else {
fYmin = ymax;
fYmax = ymin;
}
fNpx = 30;
fNpy = 30;
fContour.Set(0);
if (fNdim != 2 && xmin < xmax && ymin < ymax) {
Error("TF2","function: %s/%s has %d parameters instead of 2",name,formula,fNdim);
MakeZombie();
}
}
TF2::TF2(const char *name, Double_t (*fcn)(Double_t *, Double_t *), Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar)
: TF1(name, fcn, xmin, xmax, npar)
{
fYmin = ymin;
fYmax = ymax;
fNpx = 30;
fNpy = 30;
fNdim = 2;
fContour.Set(0);
}
TF2::TF2(const char *name, Double_t (*fcn)(const Double_t *, const Double_t *), Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar)
: TF1(name, fcn, xmin, xmax, npar)
{
fYmin = ymin;
fYmax = ymax;
fNpx = 30;
fNpy = 30;
fNdim = 2;
fContour.Set(0);
}
TF2::TF2(const char *name, ROOT::Math::ParamFunctor f, Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Int_t npar)
: TF1(name, f, xmin, xmax, npar)
{
fYmin = ymin;
fYmax = ymax;
fNpx = 30;
fNpy = 30;
fNdim = 2;
fContour.Set(0);
}
TF2& TF2::operator=(const TF2 &rhs)
{
if (this != &rhs) {
rhs.Copy(*this);
}
return *this;
}
TF2::~TF2()
{
}
TF2::TF2(const TF2 &f2) : TF1()
{
((TF2&)f2).Copy(*this);
}
void TF2::Copy(TObject &obj) const
{
TF1::Copy(obj);
((TF2&)obj).fYmin = fYmin;
((TF2&)obj).fYmax = fYmax;
((TF2&)obj).fNpy = fNpy;
fContour.Copy(((TF2&)obj).fContour);
}
Int_t TF2::DistancetoPrimitive(Int_t px, Int_t py)
{
if (!fHistogram) return 9999;
Int_t distance = fHistogram->DistancetoPrimitive(px,py);
if (distance <= 1) return distance;
Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
const char *drawOption = GetDrawOption();
Double_t uxmin,uxmax;
Double_t uymin,uymax;
if (gPad->GetView() || strncmp(drawOption,"cont",4) == 0
|| strncmp(drawOption,"CONT",4) == 0) {
uxmin=gPad->GetUxmin();
uxmax=gPad->GetUxmax();
x = fXmin +(fXmax-fXmin)*(x-uxmin)/(uxmax-uxmin);
uymin=gPad->GetUymin();
uymax=gPad->GetUymax();
y = fYmin +(fYmax-fYmin)*(y-uymin)/(uymax-uymin);
}
if (x < fXmin || x > fXmax) return distance;
if (y < fYmin || y > fYmax) return distance;
return 0;
}
void TF2::Draw(Option_t *option)
{
TString opt = option;
opt.ToLower();
if (gPad && !opt.Contains("same")) gPad->Clear();
AppendPad(option);
}
TF1 *TF2::DrawCopy(Option_t *option) const
{
TF2 *newf2 = new TF2();
Copy(*newf2);
newf2->AppendPad(option);
newf2->SetBit(kCanDelete);
return newf2;
}
void TF2::DrawF2(const char *formula, Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax, Option_t *option)
{
if (Compile((char*)formula)) return;
SetRange(xmin, ymin, xmax, ymax);
Draw(option);
}
void TF2::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
TF1::ExecuteEvent(event, px, py);
}
Int_t TF2::GetContour(Double_t *levels)
{
Int_t nlevels = fContour.fN;
if (levels) {
for (Int_t level=0; level<nlevels; level++) levels[level] = GetContourLevel(level);
}
return nlevels;
}
Double_t TF2::GetContourLevel(Int_t level) const
{
if (level <0 || level >= fContour.fN) return 0;
if (fContour.fArray[0] != -9999) return fContour.fArray[level];
if (fHistogram == 0) return 0;
return fHistogram->GetContourLevel(level);
}
Double_t TF2::FindMinMax(Double_t *x, Bool_t findmax) const
{
Double_t xx[2];
Double_t rsign = (findmax) ? -1. : 1.;
TF2 & function = const_cast<TF2&>(*this);
Double_t xxmin = 0, yymin = 0, zzmin = 0;
if (x == NULL || ( (x!= NULL) && ( !TMath::Finite(x[0]) || !TMath::Finite(x[1]) ) ) ){
Double_t dx = (fXmax - fXmin)/fNpx;
Double_t dy = (fYmax - fYmin)/fNpy;
xxmin = fXmin;
yymin = fYmin;
zzmin = rsign * TMath::Infinity();
for (Int_t i=0; i<fNpx; i++){
xx[0]=fXmin + (i+0.5)*dx;
for (Int_t j=0; j<fNpy; j++){
xx[1]=fYmin+(j+0.5)*dy;
Double_t zz = function(xx);
if (rsign*zz < rsign*zzmin) {xxmin = xx[0], yymin = xx[1]; zzmin = zz;}
}
}
xxmin = TMath::Min(fXmax, xxmin);
yymin = TMath::Min(fYmax, yymin);
}
else {
xxmin = x[0];
yymin = x[1];
zzmin = function(xx);
}
xx[0] = xxmin;
xx[1] = yymin;
double fmin = GetMinMaxNDim(xx,findmax);
if (rsign*fmin < rsign*zzmin) {
if (x) {x[0] = xx[0]; x[1] = xx[1]; }
return fmin;
}
if (x) { x[0] = xxmin; x[1] = yymin; }
return zzmin;
}
Double_t TF2::GetMinimumXY(Double_t &x, Double_t &y) const
{
double xx[2] = { 0,0 };
xx[0] = TMath::QuietNaN();
double fmin = FindMinMax(xx, false);
x = xx[0]; y = xx[1];
return fmin;
}
Double_t TF2::GetMaximumXY(Double_t &x, Double_t &y) const
{
double xx[2] = { 0,0 };
xx[0] = TMath::QuietNaN();
double fmax = FindMinMax(xx, true);
x = xx[0]; y = xx[1];
return fmax;
}
Double_t TF2::GetMinimum(Double_t *x) const
{
return FindMinMax(x, false);
}
Double_t TF2::GetMaximum(Double_t *x) const
{
return FindMinMax(x, true);
}
char *TF2::GetObjectInfo(Int_t px, Int_t py) const
{
const char *snull = "";
if (!gPad) return (char*)snull;
static char info[64];
Double_t x = gPad->PadtoX(gPad->AbsPixeltoX(px));
Double_t y = gPad->PadtoY(gPad->AbsPixeltoY(py));
const char *drawOption = GetDrawOption();
Double_t uxmin,uxmax;
Double_t uymin,uymax;
if (gPad->GetView() || strncmp(drawOption,"cont",4) == 0
|| strncmp(drawOption,"CONT",4) == 0) {
uxmin=gPad->GetUxmin();
uxmax=gPad->GetUxmax();
x = fXmin +(fXmax-fXmin)*(x-uxmin)/(uxmax-uxmin);
uymin=gPad->GetUymin();
uymax=gPad->GetUymax();
y = fYmin +(fYmax-fYmin)*(y-uymin)/(uymax-uymin);
}
snprintf(info,64,"(x=%g, y=%g, f=%.18g)",x,y,((TF2*)this)->Eval(x,y));
return info;
}
Double_t TF2::GetRandom()
{
Error("GetRandom","cannot be called for TF2/3, use GetRandom2/3 instead");
return 0;
}
Double_t TF2::GetRandom(Double_t, Double_t)
{
Error("GetRandom","cannot be called for TF2/3, use GetRandom2/3 instead");
return 0;
}
void TF2::GetRandom2(Double_t &xrandom, Double_t &yrandom)
{
Int_t i,j,cell;
Double_t dx = (fXmax-fXmin)/fNpx;
Double_t dy = (fYmax-fYmin)/fNpy;
Int_t ncells = fNpx*fNpy;
if (fIntegral == 0) {
fIntegral = new Double_t[ncells+1];
fIntegral[0] = 0;
Double_t integ;
Int_t intNegative = 0;
cell = 0;
for (j=0;j<fNpy;j++) {
for (i=0;i<fNpx;i++) {
integ = Integral(fXmin+i*dx,fXmin+i*dx+dx,fYmin+j*dy,fYmin+j*dy+dy);
if (integ < 0) {intNegative++; integ = -integ;}
fIntegral[cell+1] = fIntegral[cell] + integ;
cell++;
}
}
if (intNegative > 0) {
Warning("GetRandom2","function:%s has %d negative values: abs assumed",GetName(),intNegative);
}
if (fIntegral[ncells] == 0) {
Error("GetRandom2","Integral of function is zero");
return;
}
for (i=1;i<=ncells;i++) {
fIntegral[i] /= fIntegral[ncells];
}
}
Double_t r,ddx,ddy,dxint;
r = gRandom->Rndm();
cell = TMath::BinarySearch(ncells,fIntegral,r);
dxint = fIntegral[cell+1] - fIntegral[cell];
if (dxint > 0) ddx = dx*(r - fIntegral[cell])/dxint;
else ddx = 0;
ddy = dy*gRandom->Rndm();
j = cell/fNpx;
i = cell%fNpx;
xrandom = fXmin +dx*i +ddx;
yrandom = fYmin +dy*j +ddy;
}
void TF2::GetRange(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) const
{
xmin = fXmin;
xmax = fXmax;
ymin = fYmin;
ymax = fYmax;
}
void TF2::GetRange(Double_t &xmin, Double_t &ymin, Double_t &zmin, Double_t &xmax, Double_t &ymax, Double_t &zmax) const
{
xmin = fXmin;
xmax = fXmax;
ymin = fYmin;
ymax = fYmax;
zmin = 0;
zmax = 0;
}
Double_t TF2::GetSave(const Double_t *xx)
{
if (fNsave <= 0) return 0;
if (fSave == 0) return 0;
Int_t np = fNsave - 6;
Double_t xmin = Double_t(fSave[np+0]);
Double_t xmax = Double_t(fSave[np+1]);
Double_t ymin = Double_t(fSave[np+2]);
Double_t ymax = Double_t(fSave[np+3]);
Int_t npx = Int_t(fSave[np+4]);
Int_t npy = Int_t(fSave[np+5]);
Double_t x = Double_t(xx[0]);
Double_t dx = (xmax-xmin)/npx;
if (x < xmin || x > xmax) return 0;
if (dx <= 0) return 0;
Double_t y = Double_t(xx[1]);
Double_t dy = (ymax-ymin)/npy;
if (y < ymin || y > ymax) return 0;
if (dy <= 0) return 0;
Int_t ibin = Int_t((x-xmin)/dx);
Int_t jbin = Int_t((y-ymin)/dy);
Double_t xlow = xmin + ibin*dx;
Double_t ylow = ymin + jbin*dy;
Double_t t = (x-xlow)/dx;
Double_t u = (y-ylow)/dy;
Int_t k1 = jbin*(npx+1) + ibin;
Int_t k2 = jbin*(npx+1) + ibin +1;
Int_t k3 = (jbin+1)*(npx+1) + ibin +1;
Int_t k4 = (jbin+1)*(npx+1) + ibin;
Double_t z = (1-t)*(1-u)*fSave[k1] +t*(1-u)*fSave[k2] +t*u*fSave[k3] + (1-t)*u*fSave[k4];
return z;
}
Double_t TF2::Integral(Double_t ax, Double_t bx, Double_t ay, Double_t by, Double_t epsrel)
{
Double_t a[2], b[2];
a[0] = ax;
b[0] = bx;
a[1] = ay;
b[1] = by;
Double_t relerr = 0;
Int_t n = 2;
Int_t maxpts = 20*fNpx*fNpy;
Int_t nfnevl,ifail;
Double_t result = IntegralMultiple(n,a,b,maxpts,epsrel,epsrel,relerr,nfnevl,ifail);
if (ifail > 0) {
Warning("Integral","failed code=%d, maxpts=%d, epsrel=%g, nfnevl=%d, relerr=%g ",ifail,maxpts,epsrel,nfnevl,relerr);
}
return result;
}
Bool_t TF2::IsInside(const Double_t *x) const
{
if (x[0] < fXmin || x[0] > fXmax) return kFALSE;
if (x[1] < fYmin || x[1] > fYmax) return kFALSE;
return kTRUE;
}
TH1* TF2::CreateHistogram()
{
Int_t i,j,bin;
Double_t dx, dy;
Double_t xv[2];
TH2F* h = new TH2F("Func",(char*)GetTitle(),fNpx,fXmin,fXmax,fNpy,fYmin,fYmax);
h->SetDirectory(0);
InitArgs(xv,fParams);
dx = (fXmax - fXmin)/Double_t(fNpx);
dy = (fYmax - fYmin)/Double_t(fNpy);
for (i=1;i<=fNpx;i++) {
xv[0] = fXmin + (Double_t(i) - 0.5)*dx;
for (j=1;j<=fNpy;j++) {
xv[1] = fYmin + (Double_t(j) - 0.5)*dy;
bin = j*(fNpx + 2) + i;
h->SetBinContent(bin,EvalPar(xv,fParams));
}
}
h->Fill(fXmin-1,fYmin-1,0);
Double_t *levels = fContour.GetArray();
if (levels && levels[0] == -9999) levels = 0;
h->SetMinimum(fMinimum);
h->SetMaximum(fMaximum);
h->SetContour(fContour.fN, levels);
h->SetLineColor(GetLineColor());
h->SetLineStyle(GetLineStyle());
h->SetLineWidth(GetLineWidth());
h->SetFillColor(GetFillColor());
h->SetFillStyle(GetFillStyle());
h->SetMarkerColor(GetMarkerColor());
h->SetMarkerStyle(GetMarkerStyle());
h->SetMarkerSize(GetMarkerSize());
h->SetStats(0);
return h;
}
void TF2::Paint(Option_t *option)
{
Int_t i,j,bin;
Double_t dx, dy;
Double_t xv[2];
TString opt = option;
opt.ToLower();
if (!fHistogram) {
fHistogram = new TH2F("Func",(char*)GetTitle(),fNpx,fXmin,fXmax,fNpy,fYmin,fYmax);
if (!fHistogram) return;
fHistogram->SetDirectory(0);
}
InitArgs(xv,fParams);
dx = (fXmax - fXmin)/Double_t(fNpx);
dy = (fYmax - fYmin)/Double_t(fNpy);
for (i=1;i<=fNpx;i++) {
xv[0] = fXmin + (Double_t(i) - 0.5)*dx;
for (j=1;j<=fNpy;j++) {
xv[1] = fYmin + (Double_t(j) - 0.5)*dy;
bin = j*(fNpx + 2) + i;
fHistogram->SetBinContent(bin,EvalPar(xv,fParams));
}
}
((TH2F*)fHistogram)->Fill(fXmin-1,fYmin-1,0);
Double_t *levels = fContour.GetArray();
if (levels && levels[0] == -9999) levels = 0;
fHistogram->SetMinimum(fMinimum);
fHistogram->SetMaximum(fMaximum);
fHistogram->SetContour(fContour.fN, levels);
fHistogram->SetLineColor(GetLineColor());
fHistogram->SetLineStyle(GetLineStyle());
fHistogram->SetLineWidth(GetLineWidth());
fHistogram->SetFillColor(GetFillColor());
fHistogram->SetFillStyle(GetFillStyle());
fHistogram->SetMarkerColor(GetMarkerColor());
fHistogram->SetMarkerStyle(GetMarkerStyle());
fHistogram->SetMarkerSize(GetMarkerSize());
fHistogram->SetStats(0);
if (!gPad) return;
if (opt.Length() == 0) fHistogram->Paint("cont3");
else if (opt == "same") fHistogram->Paint("cont2same");
else fHistogram->Paint(option);
}
void TF2::Save(Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t, Double_t)
{
if (fSave != 0) {delete [] fSave; fSave = 0;}
Int_t nsave = (fNpx+1)*(fNpy+1);
fNsave = nsave+6;
if (fNsave <= 6) {fNsave=0; return;}
fSave = new Double_t[fNsave];
Int_t i,j,k=0;
Double_t dx = (xmax-xmin)/fNpx;
Double_t dy = (ymax-ymin)/fNpy;
if (dx <= 0) {
dx = (fXmax-fXmin)/fNpx;
xmin = fXmin +0.5*dx;
xmax = fXmax -0.5*dx;
}
if (dy <= 0) {
dy = (fYmax-fYmin)/fNpy;
ymin = fYmin +0.5*dy;
ymax = fYmax -0.5*dy;
}
Double_t xv[2];
InitArgs(xv,fParams);
for (j=0;j<=fNpy;j++) {
xv[1] = ymin + dy*j;
for (i=0;i<=fNpx;i++) {
xv[0] = xmin + dx*i;
fSave[k] = EvalPar(xv,fParams);
k++;
}
}
fSave[nsave+0] = xmin;
fSave[nsave+1] = xmax;
fSave[nsave+2] = ymin;
fSave[nsave+3] = ymax;
fSave[nsave+4] = fNpx;
fSave[nsave+5] = fNpy;
}
void TF2::SavePrimitive(std::ostream &out, Option_t *option )
{
char quote = '"';
out<<" "<<std::endl;
if (gROOT->ClassSaved(TF2::Class())) {
out<<" ";
} else {
out<<" TF2 *";
}
if (!fMethodCall) {
out<<GetName()<<" = new TF2("<<quote<<GetName()<<quote<<","<<quote<<GetTitle()<<quote<<","<<fXmin<<","<<fXmax<<","<<fYmin<<","<<fYmax<<");"<<std::endl;
} else {
out<<GetName()<<" = new TF2("<<quote<<GetName()<<quote<<","<<GetTitle()<<","<<fXmin<<","<<fXmax<<","<<fYmin<<","<<fYmax<<","<<GetNpar()<<");"<<std::endl;
}
if (GetFillColor() != 0) {
if (GetFillColor() > 228) {
TColor::SaveColor(out, GetFillColor());
out<<" "<<GetName()<<"->SetFillColor(ci);" << std::endl;
} else
out<<" "<<GetName()<<"->SetFillColor("<<GetFillColor()<<");"<<std::endl;
}
if (GetFillStyle() != 1001) {
out<<" "<<GetName()<<"->SetFillStyle("<<GetFillStyle()<<");"<<std::endl;
}
if (GetMarkerColor() != 1) {
if (GetMarkerColor() > 228) {
TColor::SaveColor(out, GetMarkerColor());
out<<" "<<GetName()<<"->SetMarkerColor(ci);" << std::endl;
} else
out<<" "<<GetName()<<"->SetMarkerColor("<<GetMarkerColor()<<");"<<std::endl;
}
if (GetMarkerStyle() != 1) {
out<<" "<<GetName()<<"->SetMarkerStyle("<<GetMarkerStyle()<<");"<<std::endl;
}
if (GetMarkerSize() != 1) {
out<<" "<<GetName()<<"->SetMarkerSize("<<GetMarkerSize()<<");"<<std::endl;
}
if (GetLineColor() != 1) {
if (GetLineColor() > 228) {
TColor::SaveColor(out, GetLineColor());
out<<" "<<GetName()<<"->SetLineColor(ci);" << std::endl;
} else
out<<" "<<GetName()<<"->SetLineColor("<<GetLineColor()<<");"<<std::endl;
}
if (GetLineWidth() != 4) {
out<<" "<<GetName()<<"->SetLineWidth("<<GetLineWidth()<<");"<<std::endl;
}
if (GetLineStyle() != 1) {
out<<" "<<GetName()<<"->SetLineStyle("<<GetLineStyle()<<");"<<std::endl;
}
if (GetNpx() != 100) {
out<<" "<<GetName()<<"->SetNpx("<<GetNpx()<<");"<<std::endl;
}
if (GetChisquare() != 0) {
out<<" "<<GetName()<<"->SetChisquare("<<GetChisquare()<<");"<<std::endl;
}
Double_t parmin, parmax;
for (Int_t i=0;i<fNpar;i++) {
out<<" "<<GetName()<<"->SetParameter("<<i<<","<<GetParameter(i)<<");"<<std::endl;
out<<" "<<GetName()<<"->SetParError("<<i<<","<<GetParError(i)<<");"<<std::endl;
GetParLimits(i,parmin,parmax);
out<<" "<<GetName()<<"->SetParLimits("<<i<<","<<parmin<<","<<parmax<<");"<<std::endl;
}
out<<" "<<GetName()<<"->Draw("
<<quote<<option<<quote<<");"<<std::endl;
}
void TF2::SetContour(Int_t nlevels, const Double_t *levels)
{
Int_t level;
if (nlevels <=0 ) {
fContour.Set(0);
return;
}
fContour.Set(nlevels);
if (levels) {
for (level=0; level<nlevels; level++) fContour.fArray[level] = levels[level];
} else {
fContour.fArray[0] = -9999;
}
}
void TF2::SetContourLevel(Int_t level, Double_t value)
{
if (level <0 || level >= fContour.fN) return;
fContour.fArray[level] = value;
}
void TF2::SetNpy(Int_t npy)
{
if (npy < 4) {
Warning("SetNpy","Number of points must be >=4 && <= 10000, fNpy set to 4");
fNpy = 4;
} else if(npy > 10000) {
Warning("SetNpy","Number of points must be >=4 && <= 10000, fNpy set to 10000");
fNpy = 10000;
} else {
fNpy = npy;
}
Update();
}
void TF2::SetRange(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax)
{
fXmin = xmin;
fXmax = xmax;
fYmin = ymin;
fYmax = ymax;
Update();
}
void TF2::Streamer(TBuffer &R__b)
{
if (R__b.IsReading()) {
UInt_t R__s, R__c;
Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
if (R__v > 3) {
R__b.ReadClassBuffer(TF2::Class(), this, R__v, R__s, R__c);
return;
}
Int_t nlevels;
TF1::Streamer(R__b);
if (R__v < 3) {
Float_t ymin,ymax;
R__b >> ymin; fYmin = ymin;
R__b >> ymax; fYmax = ymax;
} else {
R__b >> fYmin;
R__b >> fYmax;
}
R__b >> fNpy;
R__b >> nlevels;
if (R__v < 3) {
Float_t *contour = 0;
Int_t n = R__b.ReadArray(contour);
fContour.Set(n);
for (Int_t i=0;i<n;i++) fContour.fArray[i] = contour[i];
delete [] contour;
} else {
fContour.Streamer(R__b);
}
R__b.CheckByteCount(R__s, R__c, TF2::IsA());
} else {
Int_t saved = 0;
if (fType > 0 && fNsave <= 0) { saved = 1; Save(fXmin,fXmax,fYmin,fYmax,0,0);}
R__b.WriteClassBuffer(TF2::Class(),this);
if (saved) {delete [] fSave; fSave = 0; fNsave = 0;}
}
}
Double_t TF2::Moment2(Double_t nx, Double_t ax, Double_t bx, Double_t ny, Double_t ay, Double_t by, Double_t epsilon)
{
Double_t norm = Integral(ax,bx,ay,by,epsilon);
if (norm == 0) {
Error("Moment2", "Integral zero over range");
return 0;
}
TF2 fnc("TF2_ExpValHelper",Form("%s*pow(x,%f)*pow(y,%f)",GetName(),nx,ny));
return fnc.Integral(ax,bx,ay,by,epsilon)/norm;
}
Double_t TF2::CentralMoment2(Double_t nx, Double_t ax, Double_t bx, Double_t ny, Double_t ay, Double_t by, Double_t epsilon)
{
Double_t norm = Integral(ax,bx,ay,by,epsilon);
if (norm == 0) {
Error("CentralMoment2", "Integral zero over range");
return 0;
}
Double_t xbar = 0;
Double_t ybar = 0;
if (nx!=0) {
TF2 fncx("TF2_ExpValHelperx",Form("%s*x",GetName()));
xbar = fncx.Integral(ax,bx,ay,by,epsilon)/norm;
}
if (ny!=0) {
TF2 fncx("TF2_ExpValHelpery",Form("%s*y",GetName()));
ybar = fncx.Integral(ax,bx,ay,by,epsilon)/norm;
}
TF2 fnc("TF2_ExpValHelper",Form("%s*pow(x-%f,%f)*pow(y-%f,%f)",GetName(),xbar,nx,ybar,ny));
return fnc.Integral(ax,bx,ay,by,epsilon)/norm;
}