diff --git a/hist/hist/inc/TF1.h b/hist/hist/inc/TF1.h index 964d731e2fe330f59f166eb1bb43559a9bae7a8e..bb7bde2385414c776720537472ef7c3bb31889d6 100644 --- a/hist/hist/inc/TF1.h +++ b/hist/hist/inc/TF1.h @@ -45,6 +45,12 @@ class TH1; class TAxis; class TMethodCall; +namespace ROOT { + namespace Fit { + class FitResult; + } +} + class TF1 : public TFormula, public TAttLine, public TAttFill, public TAttMarker { protected: @@ -255,6 +261,7 @@ public: virtual void Save(Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax); virtual void SavePrimitive(ostream &out, Option_t *option = ""); virtual void SetChisquare(Double_t chi2) {fChisquare = chi2;} + virtual void SetFitResult(const ROOT::Fit::FitResult & result, const Int_t * indpar = 0); template <class PtrObj, typename MemFn> void SetFunction( PtrObj& p, MemFn memFn ); template <typename Func> diff --git a/hist/hist/src/TF1.cxx b/hist/hist/src/TF1.cxx index c70a9f284133f4291df829a061cc0fb4c10633c7..4e17b8a1bde3d091b409624fbd114b05adff1a75 100644 --- a/hist/hist/src/TF1.cxx +++ b/hist/hist/src/TF1.cxx @@ -35,6 +35,7 @@ #include "Math/AdaptiveIntegratorMultiDim.h" #include "Math/RichardsonDerivator.h" #include "Math/Functor.h" +#include "Fit/FitResult.h" //#include <iostream> @@ -2536,11 +2537,21 @@ Double_t TF1::IntegralError(Double_t a, Double_t b, const Double_t * params, con { // Return Error on Integral of a parameteric function between a and b // due to the parameter uncertainties. - // A pointer to a vector of parameter values and to the elements of the covariance matrix (covmat) can be optionally passed. - // By default (i.e. when a zero pointer is passed) the current stored parameter values are used to estimate the integral error - // together with the covariance matrix from the last fit (retrieved from the global fitter instance) - // IMPORTANT NOTE: When no covariance matrix is passed and in the meantime a fit is done - // using another function, the routine will signal an error and return zero. + // A pointer to a vector of parameter values and to the elements of the covariance matrix (covmat) + // can be optionally passed. By default (i.e. when a zero pointer is passed) the current stored + // parameter values are used to estimate the integral error together with the covariance matrix + // from the last fit (retrieved from the global fitter instance) + // + // IMPORTANT NOTE1: When no covariance matrix is passed and in the meantime a fit is done + // using another function, the routine will signal an error and it will return zero only + // when the number of fit parameter is different than the values stored in TF1 (TF1::GetNpar() ). + // In the case that npar is the same, an incorrect result is returned. + // + // IMPORTANT NOTE2: The user must pass a pointer to the elements of the full covariance matrix + // dimensioned with the right size (npar*npar), where npar is the total number of parameters (TF1::GetNpar()), + // including also the fixed parameters. When there are fixed parameters, the pointer returned from + // TVirtualFitter::GetCovarianceMatrix() cannot be used. + // One should use the TFitResult class, as shown in the example below. // // To get the matrix and values from an old fit do for example: // TFitResultPtr r = histo->Fit(func, "S"); @@ -2563,10 +2574,23 @@ Double_t TF1::IntegralError(Int_t n, const Double_t * a, const Double_t * b, con // // A pointer to a vector of parameter values and to the elements of the covariance matrix (covmat) can be optionally passed. // By default (i.e. when a zero pointer is passed) the current stored parameter values are used to estimate the integral error - // together with the covariance matrix from the last fit (retrieved from the global fitter instance) - // IMPORTANT NOTE: When no covariance matrix is passed and in the meantime a fit is done - // using another function, the routine will signal an error and return zero. - // + // together with the covariance matrix from the last fit (retrieved from the global fitter instance). + // + // IMPORTANT NOTE1: When no covariance matrix is passed and in the meantime a fit is done + // using another function, the routine will signal an error and it will return zero only + // when the number of fit parameter is different than the values stored in TF1 (TF1::GetNpar() ). + // In the case that npar is the same, an incorrect result is returned. + // + // IMPORTANT NOTE2: The user must pass a pointer to the elements of the full covariance matrix + // dimensioned with the right size (npar*npar), where npar is the total number of parameters (TF1::GetNpar()), + // including also the fixed parameters. When there are fixed parameters, the pointer returned from + // TVirtualFitter::GetCovarianceMatrix() cannot be used. + // One should use the TFitResult class, as shown in the example below. + // + // To get the matrix and values from an old fit do for example: + // TFitResultPtr r = histo->Fit(func, "S"); + // ..... after performing other fits on the same function do + // func->IntegralError(x1,x2,r->GetParams(), r->GetCovarianceMatrix()->GetMatrixArray() ); return ROOT::TF1Helper::IntegralError(this,n,a,b,params,covmat,epsilon); } @@ -3022,6 +3046,45 @@ void TF1::SetCurrent(TF1 *f1) fgCurrent = f1; } +//______________________________________________________________________________ +void TF1::SetFitResult(const ROOT::Fit::FitResult & result, const Int_t* indpar ) +{ + // Set the result from the fit + // parameter values, errors, chi2, etc... + // Optionally a pointer to a vector (with size fNpar) of the parameter indices in the FitResult can be passed + // This is useful in the case of a combined fit with different functions, and the FitResult contains the global result + // By default it is assume that indpar = {0,1,2,....,fNpar-1}. + + if (result.IsEmpty()) { + Warning("SetFitResult","Empty Fit result - nathing is set in TF1"); + return; + } + if (indpar == 0 && fNpar != (int) result.NPar() ) { + Error("SetFitResult","Invalid Fit result passed - number of parameter is %d , different than TF1::GetNpar() = %d",fNpar,result.NPar()); + return; + } + if (result.Chi2() > 0) + SetChisquare(result.Chi2() ); + else + SetChisquare(result.MinFcnValue() ); + + SetNDF(result.Ndf() ); + SetNumberFitPoints(result.Ndf() + result.NFreeParameters() ); + + + for (Int_t i = 0; i < fNpar; ++i) { + Int_t ipar = (indpar != 0) ? indpar[i] : i; + if (ipar < 0) continue; + fParams[i] = result.Parameter(ipar); + // in case errors are not present do not set them + if (ipar < (int) result.Errors().size() ) + fParErrors[i] = result.Error(ipar); + } + //invalidate cached integral since parameters have changed + Update(); + +} + //______________________________________________________________________________ void TF1::SetMaximum(Double_t maximum) diff --git a/hist/hist/src/TF1Helper.cxx b/hist/hist/src/TF1Helper.cxx index eb4d3f4a9f5b62ff451f3b3d0f1a3ef8c3ed43b5..1f16613f37dc202b3e1fcf33d75de33cb33bb960 100644 --- a/hist/hist/src/TF1Helper.cxx +++ b/hist/hist/src/TF1Helper.cxx @@ -95,7 +95,7 @@ double IntegralError(TF1 * func, Int_t ndim, const double * a, const double * b, TVectorD ig(npar); for (int i=0; i < npar; ++i) { - // check that parameter error is not zero - otehrwise skip + // check that parameter error is not zero - otherwise skip it // should check the limits double integral = 0; if (covMatrix(i,i) > 0 ) {