51 namespace HFitInterface {
54 bool IsPointOutOfRange(
const TF1 * func,
const double * x) {
56 if (func ==0)
return false;
57 return !func->IsInside(x);
60 bool AdjustError(
const DataOptions & option,
double & error,
double value = 1) {
70 if (option.fUseEmpty || (option.fErrors1 && std::abs(value) > 0 ) )
74 }
else if (option.fErrors1)
79 void ExamineRange(
const TAxis * axis, std::pair<double,double> range,
int &hxfirst,
int &hxlast) {
82 double xlow = range.first;
83 double xhigh = range.second;
85 std::cout <<
"xlow " << xlow <<
" xhigh = " << xhigh << std::endl;
88 int ilow = axis->FindFixBin(xlow);
89 int ihigh = axis->FindFixBin(xhigh);
90 if (ilow > hxlast || ihigh < hxfirst) {
91 Warning(
"ROOT::Fit::FillData",
"fit range is outside histogram range, no fit data for %s",axis->GetName());
94 hxfirst = std::min( std::max( ilow, hxfirst), hxlast+1) ;
95 hxlast = std::max( std::min( ihigh, hxlast), hxfirst-1) ;
97 if (hxfirst < hxlast) {
98 if ( axis->GetBinCenter(hxfirst) < xlow) hxfirst++;
99 if ( axis->GetBinCenter(hxlast) > xhigh) hxlast--;
107 void FillData(BinData & dv,
const TH1 * hfit, TF1 * func)
117 const DataOptions & fitOpt = dv.Opt();
121 bool useBinEdges = fitOpt.fIntegral || fitOpt.fBinVolume;
127 int hxfirst = hfit->GetXaxis()->GetFirst();
128 int hxlast = hfit->GetXaxis()->GetLast();
130 int hyfirst = hfit->GetYaxis()->GetFirst();
131 int hylast = hfit->GetYaxis()->GetLast();
133 int hzfirst = hfit->GetZaxis()->GetFirst();
134 int hzlast = hfit->GetZaxis()->GetLast();
141 const DataRange & range = dv.Range();
142 if (range.Size(0) != 0) {
143 HFitInterface::ExamineRange( hfit->GetXaxis(), range(0), hxfirst, hxlast);
144 if (range.Size(0) > 1 ) {
145 Warning(
"ROOT::Fit::FillData",
"support only one range interval for X coordinate");
149 if (hfit->GetDimension() > 1 && range.Size(1) != 0) {
150 HFitInterface::ExamineRange( hfit->GetYaxis(), range(1), hyfirst, hylast);
151 if (range.Size(1) > 1 )
152 Warning(
"ROOT::Fit::FillData",
"support only one range interval for Y coordinate");
155 if (hfit->GetDimension() > 2 && range.Size(2) != 0) {
156 HFitInterface::ExamineRange( hfit->GetZaxis(), range(2), hzfirst, hzlast);
157 if (range.Size(2) > 1 )
158 Warning(
"ROOT::Fit::FillData",
"support only one range interval for Z coordinate");
162 int n = (hxlast-hxfirst+1)*(hylast-hyfirst+1)*(hzlast-hzfirst+1);
165 std::cout <<
"THFitInterface: ifirst = " << hxfirst <<
" ilast = " << hxlast
166 <<
" total bins " << n
173 int hdim = hfit->GetDimension();
176 if (func !=0 && func->GetNdim() == hdim-1) ndim = hdim-1;
181 dv.Initialize(n,ndim);
190 const TAxis *xaxis = hfit->GetXaxis();
191 const TAxis *yaxis = hfit->GetYaxis();
192 const TAxis *zaxis = hfit->GetZaxis();
194 for ( binx = hxfirst; binx <= hxlast; ++binx) {
196 x[0] = xaxis->GetBinLowEdge(binx);
197 s[0] = xaxis->GetBinUpEdge(binx);
200 x[0] = xaxis->GetBinCenter(binx);
203 for ( biny = hyfirst; biny <= hylast; ++biny) {
205 x[1] = yaxis->GetBinLowEdge(biny);
206 s[1] = yaxis->GetBinUpEdge(biny);
209 x[1] = yaxis->GetBinCenter(biny);
211 for ( binz = hzfirst; binz <= hzlast; ++binz) {
213 x[2] = zaxis->GetBinLowEdge(binz);
214 s[2] = zaxis->GetBinUpEdge(binz);
217 x[2] = zaxis->GetBinCenter(binz);
222 TF1::RejectPoint(
false);
224 if (TF1::RejectedPoint() )
continue;
228 double value = hfit->GetBinContent(binx, biny, binz);
229 double error = hfit->GetBinError(binx, biny, binz);
230 if (!HFitInterface::AdjustError(fitOpt,error,value) )
continue;
232 if (ndim == hdim -1) {
236 if (hdim == 2) dv.Add( x, x[1], yaxis->GetBinWidth(biny) / error );
237 if (hdim == 3) dv.Add( x, x[2], zaxis->GetBinWidth(binz) / error );
239 dv.Add( x, value, error );
241 dv.AddBinUpEdge( s );
247 std::cout <<
"bin " << binx <<
" add point " << x[0] <<
" " << hfit->GetBinContent(binx) << std::endl;
256 std::cout <<
"THFitInterface::FillData: Hist FitData size is " << dv.Size() << std::endl;
264 void InitExpo(
const ROOT::Fit::BinData & data, TF1 * f1)
266 unsigned int n = data.Size();
271 double xmin = *(data.GetPoint(0,valxmin));
273 double valxmax = valxmin;
275 for (
unsigned int i = 1; i < n; ++ i) {
277 double x = *(data.GetPoint(i,val) );
289 if (valxmin <= 0 && valxmax > 0 ) valxmin = valxmax;
290 else if (valxmax <=0 && valxmin > 0) valxmax = valxmin;
291 else if (valxmin <=0 && valxmax <= 0) { valxmin = 1; valxmax = 1; }
293 double slope = std::log( valxmax/valxmin) / (xmax - xmin);
294 double constant = std::log(valxmin) - slope * xmin;
295 f1->SetParameters(constant, slope);
303 void InitGaus(
const ROOT::Fit::BinData & data, TF1 * f1)
306 static const double sqrtpi = 2.506628;
309 unsigned int n = data.Size();
315 double rangex = data.Coords(n-1)[0] - data.Coords(0)[0];
318 if ( rangex > 0) binwidth = rangex;
320 for (
unsigned int i = 0; i < n; ++ i) {
322 double x = *(data.GetPoint(i,val) );
326 if (val > valmax) valmax = val;
329 if (dx < binwidth) binwidth = dx;
334 if (allcha <= 0)
return;
335 double mean = sumx/allcha;
336 double rms = sumx2/allcha - mean*mean;
340 rms = std::sqrt(rms);
355 double constant = 0.5*(valmax+ binwidth*allcha/(sqrtpi*rms));
369 f1->SetParameter(0,constant);
370 f1->SetParameter(1,mean);
371 f1->SetParameter(2,rms);
372 f1->SetParLimits(2,0,10*rms);
376 std::cout <<
"Gaussian initial par values" << constant <<
" " << mean <<
" " << rms << std::endl;
385 void Init2DGaus(
const ROOT::Fit::BinData & data, TF1 * f1)
388 static const double sqrtpi = 2.506628;
391 unsigned int n = data.Size();
393 double sumx = 0, sumy = 0;
394 double sumx2 = 0, sumy2 = 0;
397 double rangex = data.Coords(n-1)[0] - data.Coords(0)[0];
398 double rangey = data.Coords(n-1)[1] - data.Coords(0)[1];
400 double binwidthx = 1, binwidthy = 1;
401 if ( rangex > 0) binwidthx = rangex;
402 if ( rangey > 0) binwidthy = rangey;
403 double x0 = 0, y0 = 0;
404 for (
unsigned int i = 0; i < n; ++i) {
406 const double *coords = data.GetPoint(i,val);
407 double x = coords[0], y = coords[1];
413 if (val > valmax) valmax = val;
416 if (dx < binwidthx) binwidthx = dx;
418 if (dy < binwidthy) binwidthy = dy;
424 if (allcha <= 0)
return;
425 double meanx = sumx/allcha, meany = sumy/allcha;
426 double rmsx = sumx2/allcha - meanx*meanx;
427 double rmsy = sumy2/allcha - meany*meany;
431 rmsx = std::sqrt(rmsx);
433 rmsx = binwidthx*n/4;
436 rmsy = std::sqrt(rmsy);
438 rmsy = binwidthy*n/4;
448 double constant = 0.5 * (valmax+ binwidthx*allcha/(sqrtpi*rmsx))*
449 (valmax+ binwidthy*allcha/(sqrtpi*rmsy));
451 f1->SetParameter(0,constant);
452 f1->SetParameter(1,meanx);
453 f1->SetParameter(2,rmsx);
454 f1->SetParLimits(2,0,10*rmsx);
455 f1->SetParameter(3,meany);
456 f1->SetParameter(4,rmsy);
457 f1->SetParLimits(4,0,10*rmsy);
460 std::cout <<
"2D Gaussian initial par values"
473 BinData::ErrorType GetDataType(
const TGraph * gr, DataOptions & fitOpt) {
475 double *ex = gr->GetEX();
476 double *ey = gr->GetEY();
477 double * eyl = gr->GetEYlow();
478 double * eyh = gr->GetEYhigh();
482 BinData::ErrorType type = BinData::kValueError;
484 if (fitOpt.fErrors1 || ( ey == 0 && ( eyl == 0 || eyh == 0 ) ) ) {
485 type = BinData::kNoError;
489 else if ( ex != 0 && fitOpt.fCoordErrors) {
492 while (i < gr->GetN() && type != BinData::kCoordError) {
493 if (ex[i] > 0) type = BinData::kCoordError;
498 else if ( ( eyl != 0 && eyh != 0) && fitOpt.fAsymErrors) {
501 bool zeroErrorX =
true;
502 bool zeroErrorY =
true;
503 while (i < gr->GetN() && (zeroErrorX || zeroErrorY)) {
504 double e2X = ( gr->GetErrorXlow(i) + gr->GetErrorXhigh(i) );
505 double e2Y = eyl[i] + eyh[i];
506 zeroErrorX &= (e2X <= 0);
507 zeroErrorY &= (e2Y <= 0);
510 if (zeroErrorX && zeroErrorY)
511 type = BinData::kNoError;
512 else if (!zeroErrorX && zeroErrorY)
513 type = BinData::kCoordError;
514 else if (zeroErrorX && !zeroErrorY) {
515 type = BinData::kAsymError;
516 fitOpt.fCoordErrors =
false;
519 type = BinData::kAsymError;
524 if ( ey != 0 && type != BinData::kCoordError ) {
526 bool zeroError =
true;
527 while (i < gr->GetN() && zeroError) {
528 if (ey[i] > 0) zeroError =
false;;
531 if (zeroError) type = BinData::kNoError;
536 std::cout <<
"type is " << type <<
" graph type is " << gr->IsA()->GetName() << std::endl;
542 BinData::ErrorType GetDataType(
const TGraph2D * gr,
const DataOptions & fitOpt) {
544 double *ex = gr->GetEX();
545 double *ey = gr->GetEY();
546 double *ez = gr->GetEZ();
549 BinData::ErrorType type = BinData::kValueError;
551 if (fitOpt.fErrors1 || ez == 0 ) {
552 type = BinData::kNoError;
554 else if ( ex != 0 && ey!=0 && fitOpt.fCoordErrors) {
557 while (i < gr->GetN() && type != BinData::kCoordError) {
558 if (ex[i] > 0 || ey[i] > 0) type = BinData::kCoordError;
565 std::cout <<
"type is " << type <<
" graph2D type is " << gr->IsA()->GetName() << std::endl;
573 void DoFillData ( BinData & dv,
const TGraph * gr, BinData::ErrorType type, TF1 * func ) {
578 DataOptions & fitOpt = dv.Opt();
580 int nPoints = gr->GetN();
581 double *gx = gr->GetX();
582 double *gy = gr->GetY();
584 const DataRange & range = dv.Range();
585 bool useRange = ( range.Size(0) > 0);
588 range.GetRange(xmin,xmax);
590 dv.Initialize(nPoints,1, type);
593 std::cout <<
"DoFillData: graph npoints = " << nPoints <<
" type " << type << std::endl;
595 double a1,a2; func->GetRange(a1,a2); std::cout <<
"func range " << a1 <<
" " << a2 << std::endl;
600 for (
int i = 0; i < nPoints; ++i) {
605 if (useRange && ( x[0] < xmin || x[0] > xmax) )
continue;
610 TF1::RejectPoint(
false);
612 if (TF1::RejectedPoint() )
continue;
617 dv.Add( gx[i], gy[i] );
621 else if (type == BinData::kValueError) {
622 double errorY = gr->GetErrorY(i);
625 if (!HFitInterface::AdjustError(fitOpt,errorY) )
continue;
626 dv.Add( gx[i], gy[i], errorY );
629 std::cout <<
"Point " << i <<
" " << gx[i] <<
" " << gy[i] <<
" " << errorY << std::endl;
636 if (fitOpt.fCoordErrors)
640 errorX = std::max( 0.5 * ( gr->GetErrorXlow(i) + gr->GetErrorXhigh(i) ) , 0. ) ;
644 double errorY = std::max(gr->GetErrorY(i), 0.);
646 HFitInterface::AdjustError(fitOpt, errorY);
649 if ( errorX <=0 && errorY <= 0 )
continue;
652 if (type == BinData::kAsymError) {
654 dv.Add( gx[i], gy[i], errorX, gr->GetErrorYlow(i), gr->GetErrorYhigh(i) );
658 dv.Add( gx[i], gy[i], errorX, errorY );
665 std::cout <<
"TGraphFitInterface::FillData Graph FitData size is " << dv.Size() << std::endl;
670 void FillData(SparseData & dv,
const TH1 * h1, TF1 * )
672 const int dim = h1->GetDimension();
673 std::vector<double> min(dim);
674 std::vector<double> max(dim);
676 int ncells = h1->GetNcells();
677 for (
int i = 0; i < ncells; ++i ) {
682 if ( !( h1->IsBinOverflow(i) || h1->IsBinUnderflow(i) )
683 && h1->GetBinContent(i))
686 h1->GetBinXYZ(i, x, y, z);
697 min[0] = h1->GetXaxis()->GetBinLowEdge(x);
698 max[0] = h1->GetXaxis()->GetBinUpEdge(x);
701 min[1] = h1->GetYaxis()->GetBinLowEdge(y);
702 max[1] = h1->GetYaxis()->GetBinUpEdge(y);
705 min[2] = h1->GetZaxis()->GetBinLowEdge(z);
706 max[2] = h1->GetZaxis()->GetBinUpEdge(z);
709 dv.Add(min, max, h1->GetBinContent(i), h1->GetBinError(i));
714 void FillData(SparseData & dv,
const THnBase * h1, TF1 * )
716 const int dim = h1->GetNdimensions();
717 std::vector<double> min(dim);
718 std::vector<double> max(dim);
719 std::vector<Int_t> coord(dim);
721 ULong64_t nEntries = h1->GetNbins();
722 for ( ULong64_t i = 0; i < nEntries; i++ )
724 double value = h1->GetBinContent( i, &coord[0] );
725 if ( !value )
continue;
730 bool insertBox =
true;
731 for (
int j = 0; j < dim && insertBox; ++j )
733 TAxis* axis = h1->GetAxis(j);
734 if ( ( axis->GetBinLowEdge(coord[j]) < axis->GetXmin() ) ||
735 ( axis->GetBinUpEdge(coord[j]) > axis->GetXmax() ) ) {
738 min[j] = h1->GetAxis(j)->GetBinLowEdge(coord[j]);
739 max[j] = h1->GetAxis(j)->GetBinUpEdge(coord[j]);
753 dv.Add(min, max, value, h1->GetBinError(i));
757 void FillData(BinData & dv,
const THnBase * s1, TF1 * func)
760 unsigned int const ndim = s1->GetNdimensions();
761 std::vector<double> xmin(ndim);
762 std::vector<double> xmax(ndim);
763 for (
unsigned int i = 0; i < ndim; ++i ) {
764 TAxis* axis = s1->GetAxis(i);
765 xmin[i] = axis->GetXmin();
766 xmax[i] = axis->GetXmax();
771 ROOT::Fit::DataOptions& dopt = dv.Opt();
772 dopt.fUseEmpty =
true;
775 dopt.fBinVolume =
true;
776 dopt.fNormBinVolume =
true;
779 ROOT::Fit::SparseData d(ndim, &xmin[0], &xmax[0]);
780 ROOT::Fit::FillData(d, s1, func);
785 d.GetBinDataIntegral(dv);
789 void FillData ( BinData & dv,
const TGraph * gr, TF1 * func ) {
795 DataOptions & fitOpt = dv.Opt();
797 BinData::ErrorType type = GetDataType(gr,fitOpt);
799 fitOpt.fErrors1 = (type == BinData::kNoError);
804 fitOpt.fCoordErrors &= (type == BinData::kCoordError) || (type == BinData::kAsymError) ;
805 fitOpt.fAsymErrors &= (type == BinData::kAsymError);
809 if (dv.Size() > 0 && dv.NDim() == 1 ) {
811 if ( dv.GetErrorType() != type ) {
812 Error(
"FillData",
"Inconsistent TGraph with previous data set- skip all graph data");
817 DoFillData(dv, gr, type, func);
821 void FillData ( BinData & dv,
const TMultiGraph * mg, TF1 * func ) {
826 TList * grList = mg->GetListOfGraphs();
831 TIter itr(grList, kIterBackward);
833 std::cout <<
"multi-graph list of graps: " << std::endl;
834 while ((obj = itr())) {
835 std::cout << obj->IsA()->GetName() << std::endl;
841 DataOptions & fitOpt = dv.Opt();
846 BinData::ErrorType type = BinData::kNoError;
848 while ((gr = (TGraph*) next())) {
849 BinData::ErrorType t = GetDataType(gr,fitOpt);
850 if (t > type ) type = t;
853 fitOpt.fErrors1 = (type == BinData::kNoError);
854 fitOpt.fCoordErrors = (type == BinData::kCoordError);
855 fitOpt.fAsymErrors = (type == BinData::kAsymError);
859 std::cout <<
"Fitting MultiGraph of type " << type << std::endl;
864 while ((gr = (TGraph*) next())) {
865 DoFillData( dv, gr, type, func);
869 std::cout <<
"TGraphFitInterface::FillData MultiGraph FitData size is " << dv.Size() << std::endl;
874 void FillData ( BinData & dv,
const TGraph2D * gr, TF1 * func ) {
881 DataOptions & fitOpt = dv.Opt();
882 BinData::ErrorType type = GetDataType(gr,fitOpt);
884 fitOpt.fErrors1 = (type == BinData::kNoError);
885 fitOpt.fCoordErrors = (type == BinData::kCoordError);
886 fitOpt.fAsymErrors =
false;
888 int nPoints = gr->GetN();
889 double *gx = gr->GetX();
890 double *gy = gr->GetY();
891 double *gz = gr->GetZ();
894 if ( gr->GetEZ() == 0) fitOpt.fErrors1 =
true;
900 const DataRange & range = dv.Range();
901 bool useRangeX = ( range.Size(0) > 0);
902 bool useRangeY = ( range.Size(1) > 0);
907 range.GetRange(xmin,xmax,ymin,ymax);
909 dv.Initialize(nPoints,2, type);
911 for (
int i = 0; i < nPoints; ++i) {
917 if (useRangeX && ( x[0] < xmin || x[0] > xmax) )
continue;
918 if (useRangeY && ( x[1] < ymin || x[1] > ymax) )
continue;
923 TF1::RejectPoint(
false);
925 if (TF1::RejectedPoint() )
continue;
928 if (type == BinData::kNoError) {
933 double errorZ = gr->GetErrorZ(i);
934 if (!HFitInterface::AdjustError(fitOpt,errorZ) )
continue;
936 if (type == BinData::kValueError) {
937 dv.Add( x, gz[i], errorZ );
939 else if (type == BinData::kCoordError) {
940 ex[0] = std::max(gr->GetErrorX(i), 0.);
941 ex[1] = std::max(gr->GetErrorY(i), 0.);
942 dv.Add( x, gz[i], ex, errorZ );
948 std::cout <<
"Point " << i <<
" " << gx[i] <<
" " << gy[i] <<
" " << errorZ << std::endl;
954 std::cout <<
"THFitInterface::FillData Graph2D FitData size is " << dv.Size() << std::endl;
961 bool GetConfidenceIntervals(
const TH1 * h1,
const ROOT::Fit::FitResult & result, TGraphErrors * gr,
double cl ) {
962 if (h1->GetDimension() != 1) {
963 Error(
"GetConfidenceIntervals",
"Invalid object used for storing confidence intervals");
969 gr->Set(d.NPoints() );
970 double * ci = gr->GetEY();
971 result.GetConfidenceIntervals(d,ci,cl);
973 for (
unsigned int ipoint = 0; ipoint < d.NPoints(); ++ipoint) {
974 const double * x = d.Coords(ipoint);
975 const ROOT::Math::IParamMultiFunction * func = result.FittedFunction();
976 gr->SetPoint(ipoint, x[0], (*func)(x) );