#include "TROOT.h"
#include "TF3.h"
#include "TMath.h"
#include "TH3.h"
#include "TVirtualPad.h"
#include "TRandom.h"
#include "TVectorD.h"
#include "Riostream.h"
#include "TColor.h"
#include "TVirtualFitter.h"
#include "TVirtualHistPainter.h"
#include "TClass.h"
ClassImp(TF3)
TF3::TF3(): TF2()
{
fNpz = 0;
fZmin = 0;
fZmax = 1;
}
TF3::TF3(const char *name,const char *formula, Double_t xmin, Double_t xmax,
Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax)
:TF2(name,formula,xmin,xmax,ymax,ymin)
{
fZmin = zmin;
fZmax = zmax;
fNpz = 30;
if (fNdim != 3 && xmin < xmax) {
Error("TF3","function: %s/%s has %d parameters instead of 3",name,formula,fNdim);
MakeZombie();
}
}
TF3::TF3(const char *name,Double_t (*fcn)(Double_t *, Double_t *),
Double_t xmin, Double_t xmax,
Double_t ymin, Double_t ymax,
Double_t zmin, Double_t zmax, Int_t npar)
:TF2(name,fcn,xmin,xmax,ymin,ymax,npar)
{
fZmin = zmin;
fZmax = zmax;
fNpz = 30;
fNdim = 3;
}
TF3::TF3(const char *name,Double_t (*fcn)(const Double_t *, const Double_t *),
Double_t xmin, Double_t xmax,
Double_t ymin, Double_t ymax,
Double_t zmin, Double_t zmax, Int_t npar)
: TF2(name,fcn,xmin,xmax,ymin,ymax,npar),
fZmin(zmin),
fZmax(zmax),
fNpz(30)
{
fNdim = 3;
}
TF3::TF3(const char *name, ROOT::Math::ParamFunctor f,
Double_t xmin, Double_t xmax,
Double_t ymin, Double_t ymax,
Double_t zmin, Double_t zmax, Int_t npar)
: TF2(name, f, xmin, xmax, ymin, ymax, npar),
fZmin(zmin),
fZmax(zmax),
fNpz(30)
{
fNdim = 3;
}
TF3& TF3::operator=(const TF3 &rhs)
{
if (this != &rhs) {
rhs.Copy(*this);
}
return *this;
}
TF3::~TF3()
{
}
TF3::TF3(const TF3 &f3) : TF2()
{
((TF3&)f3).Copy(*this);
}
void TF3::Copy(TObject &obj) const
{
TF2::Copy(obj);
((TF3&)obj).fZmin = fZmin;
((TF3&)obj).fZmax = fZmax;
((TF3&)obj).fNpz = fNpz;
}
Int_t TF3::DistancetoPrimitive(Int_t px, Int_t py)
{
return TF1::DistancetoPrimitive(px, py);
}
void TF3::Draw(Option_t *option)
{
TString opt = option;
opt.ToLower();
if (gPad && !opt.Contains("same")) gPad->Clear();
AppendPad(option);
}
void TF3::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
TF1::ExecuteEvent(event, px, py);
}
Double_t TF3::FindMinMax(Double_t *x, Bool_t findmax) const
{
Double_t xx[3];
Double_t rsign = (findmax) ? -1. : 1.;
TF3 & function = const_cast<TF3&>(*this);
Double_t xxmin = 0, yymin = 0, zzmin = 0, ttmin = 0;
if (x == NULL || ( (x!= NULL) && ( !TMath::Finite(x[0]) || !TMath::Finite(x[1]) || !TMath::Finite(x[2]) ) ) ){
Double_t dx = (fXmax - fXmin)/fNpx;
Double_t dy = (fYmax - fYmin)/fNpy;
Double_t dz = (fZmax - fZmin)/fNpz;
xxmin = fXmin;
yymin = fYmin;
zzmin = fZmin;
ttmin = 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;
for (Int_t k=0; k<fNpz; k++){
xx[2] = fZmin+(k+0.5)*dz;
Double_t tt = function(xx);
if (rsign*tt < rsign*ttmin) {xxmin = xx[0], yymin = xx[1]; zzmin = xx[2]; ttmin=tt;}
}
}
}
xxmin = TMath::Min(fXmax, xxmin);
yymin = TMath::Min(fYmax, yymin);
zzmin = TMath::Min(fZmax, zzmin);
}
else {
xxmin = x[0];
yymin = x[1];
zzmin = x[2];
zzmin = function(xx);
}
xx[0] = xxmin;
xx[1] = yymin;
xx[2] = zzmin;
double fmin = GetMinMaxNDim(xx,findmax);
if (rsign*fmin < rsign*zzmin) {
if (x) {x[0] = xx[0]; x[1] = xx[1]; x[2] = xx[2];}
return fmin;
}
if (x) { x[0] = xxmin; x[1] = yymin; x[2] = zzmin; }
return ttmin;
}
Double_t TF3::GetMinimumXYZ(Double_t &x, Double_t &y, Double_t &z)
{
double xx[3] = { 0,0,0 };
xx[0] = TMath::QuietNaN();
double fmin = FindMinMax(xx, false);
x = xx[0]; y = xx[1]; z = xx[2];
return fmin;
}
Double_t TF3::GetMaximumXYZ(Double_t &x, Double_t &y, Double_t &z)
{
double xx[3] = { 0,0,0 };
xx[0] = TMath::QuietNaN();
double fmax = FindMinMax(xx, true);
x = xx[0]; y = xx[1]; z = xx[2];
return fmax;
}
void TF3::GetRandom3(Double_t &xrandom, Double_t &yrandom, Double_t &zrandom)
{
Int_t i,j,k,cell;
Double_t dx = (fXmax-fXmin)/fNpx;
Double_t dy = (fYmax-fYmin)/fNpy;
Double_t dz = (fZmax-fZmin)/fNpz;
Int_t ncells = fNpx*fNpy*fNpz;
Double_t xx[3];
InitArgs(xx,fParams);
if (fIntegral == 0) {
fIntegral = new Double_t[ncells+1];
fIntegral[0] = 0;
Double_t integ;
Int_t intNegative = 0;
cell = 0;
for (k=0;k<fNpz;k++) {
xx[2] = fZmin+(k+0.5)*dz;
for (j=0;j<fNpy;j++) {
xx[1] = fYmin+(j+0.5)*dy;
for (i=0;i<fNpx;i++) {
xx[0] = fXmin+(i+0.5)*dx;
integ = EvalPar(xx,fParams);
if (integ < 0) {intNegative++; integ = -integ;}
fIntegral[cell+1] = fIntegral[cell] + integ;
cell++;
}
}
}
if (intNegative > 0) {
Warning("GetRandom3","function:%s has %d negative values: abs assumed",GetName(),intNegative);
}
if (fIntegral[ncells] == 0) {
Error("GetRandom3","Integral of function is zero");
return;
}
for (i=1;i<=ncells;i++) {
fIntegral[i] /= fIntegral[ncells];
}
}
Double_t r;
r = gRandom->Rndm();
cell = TMath::BinarySearch(ncells,fIntegral,r);
k = cell/(fNpx*fNpy);
j = (cell -k*fNpx*fNpy)/fNpx;
i = cell -fNpx*(j +fNpy*k);
xrandom = fXmin +dx*i +dx*gRandom->Rndm();
yrandom = fYmin +dy*j +dy*gRandom->Rndm();
zrandom = fZmin +dz*k +dz*gRandom->Rndm();
}
void TF3::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 = fZmin;
zmax = fZmax;
}
Double_t TF3::GetSave(const Double_t *xx)
{
if (fNsave <= 0) return 0;
if (fSave == 0) return 0;
Int_t np = fNsave - 9;
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]);
Double_t zmin = Double_t(fSave[np+4]);
Double_t zmax = Double_t(fSave[np+5]);
Int_t npx = Int_t(fSave[np+6]);
Int_t npy = Int_t(fSave[np+7]);
Int_t npz = Int_t(fSave[np+8]);
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;
Double_t z = Double_t(xx[2]);
Double_t dz = (zmax-zmin)/npz;
if (z < zmin || z > zmax) return 0;
if (dz <= 0) return 0;
Int_t ibin = Int_t((x-xmin)/dx);
Int_t jbin = Int_t((y-ymin)/dy);
Int_t kbin = Int_t((z-zmin)/dz);
Double_t xlow = xmin + ibin*dx;
Double_t ylow = ymin + jbin*dy;
Double_t zlow = zmin + kbin*dz;
Double_t t = (x-xlow)/dx;
Double_t u = (y-ylow)/dy;
Double_t v = (z-zlow)/dz;
Int_t k1 = (ibin ) + (npx+1)*((jbin ) + (npy+1)*(kbin ));
Int_t k2 = (ibin+1) + (npx+1)*((jbin ) + (npy+1)*(kbin ));
Int_t k3 = (ibin+1) + (npx+1)*((jbin+1) + (npy+1)*(kbin ));
Int_t k4 = (ibin ) + (npx+1)*((jbin+1) + (npy+1)*(kbin ));
Int_t k5 = (ibin ) + (npx+1)*((jbin ) + (npy+1)*(kbin+1));
Int_t k6 = (ibin+1) + (npx+1)*((jbin ) + (npy+1)*(kbin+1));
Int_t k7 = (ibin+1) + (npx+1)*((jbin+1) + (npy+1)*(kbin+1));
Int_t k8 = (ibin ) + (npx+1)*((jbin+1) + (npy+1)*(kbin+1));
Double_t r = (1-t)*(1-u)*(1-v)*fSave[k1] + t*(1-u)*(1-v)*fSave[k2] + t*u*(1-v)*fSave[k3] + (1-t)*u*(1-v)*fSave[k4] +
(1-t)*(1-u)*v*fSave[k5] + t*(1-u)*v*fSave[k6] + t*u*v*fSave[k7] + (1-t)*u*v*fSave[k8];
return r;
}
Double_t TF3::Integral(Double_t ax, Double_t bx, Double_t ay, Double_t by, Double_t az, Double_t bz, Double_t epsrel)
{
Double_t a[3], b[3];
a[0] = ax;
b[0] = bx;
a[1] = ay;
b[1] = by;
a[2] = az;
b[2] = bz;
Double_t relerr = 0;
Int_t n = 3;
Int_t maxpts = TMath::Min(100000, 20*fNpx*fNpy*fNpz);
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 TF3::IsInside(const Double_t *x) const
{
if (x[0] < fXmin || x[0] > fXmax) return kFALSE;
if (x[1] < fYmin || x[1] > fYmax) return kFALSE;
if (x[2] < fZmin || x[2] > fZmax) return kFALSE;
return kTRUE;
}
TH1* TF3::CreateHistogram()
{
TH1* h = new TH3F("R__TF3",(char*)GetTitle(),fNpx,fXmin,fXmax
,fNpy,fYmin,fYmax
,fNpz,fZmin,fZmax);
h->SetDirectory(0);
return h;
}
void TF3::Paint(Option_t *option)
{
TString opt = option;
opt.ToLower();
if (!fHistogram) {
fHistogram = new TH3F("R__TF3",(char*)GetTitle(),fNpx,fXmin,fXmax
,fNpy,fYmin,fYmax
,fNpz,fZmin,fZmax);
fHistogram->SetDirectory(0);
}
fHistogram->GetPainter(option)->ProcessMessage("SetF3",this);
if (opt.Length() == 0 ) {
fHistogram->Paint("tf3");
} else {
opt += "tf3";
fHistogram->Paint(opt.Data());
}
}
void TF3::SetClippingBoxOff()
{
if (!fHistogram) {
fHistogram = new TH3F("R__TF3",(char*)GetTitle(),fNpx,fXmin,fXmax
,fNpy,fYmin,fYmax
,fNpz,fZmin,fZmax);
fHistogram->SetDirectory(0);
}
fHistogram->GetPainter()->ProcessMessage("SetF3ClippingBoxOff",0);
}
void TF3::Save(Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax)
{
if (fSave != 0) {delete [] fSave; fSave = 0;}
Int_t nsave = (fNpx+1)*(fNpy+1)*(fNpz+1);
fNsave = nsave+9;
if (fNsave <= 9) {fNsave=0; return;}
fSave = new Double_t[fNsave];
Int_t i,j,k,l=0;
Double_t dx = (xmax-xmin)/fNpx;
Double_t dy = (ymax-ymin)/fNpy;
Double_t dz = (zmax-zmin)/fNpz;
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;
}
if (dz <= 0) {
dz = (fZmax-fZmin)/fNpz;
zmin = fZmin +0.5*dz;
zmax = fZmax -0.5*dz;
}
Double_t xv[3];
InitArgs(xv,fParams);
for (k=0;k<=fNpz;k++) {
xv[2] = zmin + dz*k;
for (j=0;j<=fNpy;j++) {
xv[1] = ymin + dy*j;
for (i=0;i<=fNpx;i++) {
xv[0] = xmin + dx*i;
fSave[l] = EvalPar(xv,fParams);
l++;
}
}
}
fSave[nsave+0] = xmin;
fSave[nsave+1] = xmax;
fSave[nsave+2] = ymin;
fSave[nsave+3] = ymax;
fSave[nsave+4] = zmin;
fSave[nsave+5] = zmax;
fSave[nsave+6] = fNpx;
fSave[nsave+7] = fNpy;
fSave[nsave+8] = fNpz;
}
void TF3::SavePrimitive(std::ostream &out, Option_t *option )
{
char quote = '"';
out<<" "<<std::endl;
if (gROOT->ClassSaved(TF3::Class())) {
out<<" ";
} else {
out<<" TF3 *";
}
if (!fMethodCall) {
out<<GetName()<<" = new TF3("<<quote<<GetName()<<quote<<","<<quote<<GetTitle()<<quote<<","<<fXmin<<","<<fXmax<<","<<fYmin<<","<<fYmax<<","<<fZmin<<","<<fZmax<<");"<<std::endl;
} else {
out<<GetName()<<" = new TF3("<<quote<<GetName()<<quote<<","<<GetTitle()<<","<<fXmin<<","<<fXmax<<","<<fYmin<<","<<fYmax<<","<<fZmin<<","<<fZmax<<","<<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 (GetLineColor() != 1) {
if (GetLineColor() > 228) {
TColor::SaveColor(out, GetLineColor());
out<<" "<<GetName()<<"->SetLineColor(ci);" << std::endl;
} else
out<<" "<<GetName()<<"->SetLineColor("<<GetLineColor()<<");"<<std::endl;
}
if (GetNpz() != 100) {
out<<" "<<GetName()<<"->SetNpz("<<GetNpz()<<");"<<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 TF3::SetClippingBoxOn(Double_t xclip, Double_t yclip, Double_t zclip)
{
if (!fHistogram) {
fHistogram = new TH3F("R__TF3",(char*)GetTitle(),fNpx,fXmin,fXmax
,fNpy,fYmin,fYmax
,fNpz,fZmin,fZmax);
fHistogram->SetDirectory(0);
}
TVectorD v(3);
v(0) = xclip;
v(1) = yclip;
v(2) = zclip;
fHistogram->GetPainter()->ProcessMessage("SetF3ClippingBoxOn",&v);
}
void TF3::SetNpz(Int_t npz)
{
if (npz < 4) {
Warning("SetNpz","Number of points must be >=4 && <= 10000, fNpz set to 4");
fNpz = 4;
} else if(npz > 10000) {
Warning("SetNpz","Number of points must be >=4 && <= 10000, fNpz set to 10000");
fNpz = 10000;
} else {
fNpz = npz;
}
Update();
}
void TF3::SetRange(Double_t xmin, Double_t ymin, Double_t zmin,
Double_t xmax, Double_t ymax, Double_t zmax)
{
fXmin = xmin;
fXmax = xmax;
fYmin = ymin;
fYmax = ymax;
fZmin = zmin;
fZmax = zmax;
Update();
}
void TF3::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 > 0) {
R__b.ReadClassBuffer(TF3::Class(), this, R__v, R__s, R__c);
return;
}
} else {
Int_t saved = 0;
if (fType > 0 && fNsave <= 0) { saved = 1; Save(fXmin,fXmax,fYmin,fYmax,fZmin,fZmax);}
R__b.WriteClassBuffer(TF3::Class(),this);
if (saved) {delete [] fSave; fSave = 0; fNsave = 0;}
}
}
Double_t TF3::Moment3(Double_t nx, Double_t ax, Double_t bx,
Double_t ny, Double_t ay, Double_t by,
Double_t nz, Double_t az, Double_t bz, Double_t epsilon)
{
Double_t norm = Integral(ax,bx,ay,by,az,bz,epsilon);
if (norm == 0) {
Error("Moment3", "Integral zero over range");
return 0;
}
TF3 fnc("TF3_ExpValHelper",Form("%s*pow(x,%f)*pow(y,%f)*pow(z,%f)",GetName(),nx,ny,nz));
return fnc.Integral(ax,bx,ay,by,az,bz,epsilon)/norm;
}
Double_t TF3::CentralMoment3(Double_t nx, Double_t ax, Double_t bx,
Double_t ny, Double_t ay, Double_t by,
Double_t nz, Double_t az, Double_t bz, Double_t epsilon)
{
Double_t norm = Integral(ax,bx,ay,by,az,bz,epsilon);
if (norm == 0) {
Error("CentralMoment3", "Integral zero over range");
return 0;
}
Double_t xbar = 0;
Double_t ybar = 0;
Double_t zbar = 0;
if (nx!=0) {
TF3 fncx("TF3_ExpValHelperx",Form("%s*x",GetName()));
xbar = fncx.Integral(ax,bx,ay,by,az,bz,epsilon)/norm;
}
if (ny!=0) {
TF3 fncy("TF3_ExpValHelpery",Form("%s*y",GetName()));
ybar = fncy.Integral(ax,bx,ay,by,az,bz,epsilon)/norm;
}
if (nz!=0) {
TF3 fncz("TF3_ExpValHelperz",Form("%s*z",GetName()));
zbar = fncz.Integral(ax,bx,ay,by,az,bz,epsilon)/norm;
}
TF3 fnc("TF3_ExpValHelper",Form("%s*pow(x-%f,%f)*pow(y-%f,%f)*pow(z-%f,%f)",GetName(),xbar,nx,ybar,ny,zbar,nz));
return fnc.Integral(ax,bx,ay,by,az,bz,epsilon)/norm;
}