diff --git a/gui/fitpanel/CMakeLists.txt b/gui/fitpanel/CMakeLists.txt index 9cf73d01e18ad..9000277978071 100644 --- a/gui/fitpanel/CMakeLists.txt +++ b/gui/fitpanel/CMakeLists.txt @@ -30,3 +30,5 @@ ROOT_STANDARD_LIBRARY_PACKAGE(FitPanel Tree TreePlayer ) + +ROOT_ADD_TEST_SUBDIRECTORY(test) diff --git a/gui/fitpanel/test/CMakeLists.txt b/gui/fitpanel/test/CMakeLists.txt new file mode 100644 index 0000000000000..7b11b5dda0dc1 --- /dev/null +++ b/gui/fitpanel/test/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. +# All rights reserved. +# +# For the licensing terms see $ROOTSYS/LICENSE. +# For the list of contributors see $ROOTSYS/README/CREDITS. + +# @author Danilo Piparo CERN + +ROOT_EXECUTABLE(fitPanelUnitTesting UnitTesting.cxx LIBRARIES FitPanel Gui Tree Hist MathCore) +ROOT_ADD_TEST(test-fitpanel-UnitTesting COMMAND fitPanelUnitTesting) +set_tests_properties(test-fitpanel-UnitTesting PROPERTIES WILL_FAIL true) # Problems with batch mode https://github.com/root-project/root/issues/21881 +target_include_directories(fitPanelUnitTesting PRIVATE ../src/) diff --git a/gui/fitpanel/test/Makefile b/gui/fitpanel/test/Makefile deleted file mode 100644 index 602389c39cf02..0000000000000 --- a/gui/fitpanel/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# Makefile for the ROOT test programs. -# This Makefile shows nicely how to compile and link applications -# using the ROOT libraries on all supported platforms. -# -# Copyright (c) 2000 Rene Brun and Fons Rademakers -# -# Author: Fons Rademakers, 29/2/2000 - -ROOTSYS = ../../.. -include $(ROOTSYS)/etc/Makefile.arch - -#------------------------------------------------------------------------------ - -CXXFLAGS+= -I$(ROOTSYS)/gui/fitpanel/src - -LDFLAGS+=-lFitPanel -lGui - -UNITTESTOBJ = UnitTesting.$(ObjSuf) -UNITTESTSRC = UnitTesting.$(SrcSuf) -UNITTEST = UnitTesting$(ExeSuf) - - -OBJS = $(UNITTESTOBJ) - -PROGRAMS =$(UNITTEST) - -.SUFFIXES: .$(SrcSuf) .$(ObjSuf) $(ExeSuf) - - -all: $(PROGRAMS) - -$(UNITTEST): $(UNITTESTOBJ) - $(LD) $(LDFLAGS) $^ $(LIBS) $(OutPutOpt)$@ - @echo "$@ done" - -clean: - @rm -f $(OBJS) outputUnitTesting.txt - -distclean: clean - @rm -f $(PROGRAMS) - - -.SUFFIXES: .$(SrcSuf) - - -.$(SrcSuf).$(ObjSuf): - $(CXX) $(CXXFLAGS) -c $< diff --git a/gui/fitpanel/test/UnitTesting.cxx b/gui/fitpanel/test/UnitTesting.cxx index 19438198832b6..6baa73bdd8546 100644 --- a/gui/fitpanel/test/UnitTesting.cxx +++ b/gui/fitpanel/test/UnitTesting.cxx @@ -12,15 +12,27 @@ #include "TGComboBox.h" +#include "TF2.h" +#include "TMath.h" +#include "TRandom2.h" +#include "TTree.h" + #include #include #include #include +#include #include "CommonDefs.h" +#ifdef WIN32 +#include "io.h" +#else +#include "unistd.h" +#endif + // Function that compares to doubles up to an error limit -int equals(Double_t n1, Double_t n2, double ERRORLIMIT = 1.E-10) +int equals(Double_t n1, Double_t n2, double ERRORLIMIT = 1.E-5) { return fabs( n1 - n2 ) > ERRORLIMIT * fabs(n1); } @@ -34,6 +46,35 @@ int SelectEntry(TGComboBox* cb, const char* name) return findEntry->EntryId(); } +void createTree(int n = 100) +{ + TTree *tree = new TTree("tree","2 var gaus tree"); + double x, y, z, u, v, w; + tree->Branch("x", &x, "x/D"); + tree->Branch("y", &y, "y/D"); + tree->Branch("z", &z, "z/D"); + tree->Branch("u", &u, "u/D"); + tree->Branch("v", &v, "v/D"); + tree->Branch("w", &w, "w/D"); + TRandom2 rndm; + double origPars[13] = {1,2,3,0.5, 0.5, 0, 3, 0, 4, 0, 5, 1, 10 }; + TF2 f2("f2", "bigaus", -10, 10,-10, 10); + f2.FixParameter(0, 1. / (2. * TMath::Pi() * origPars[1] * origPars[3] * TMath::Sqrt(origPars[4]))); // constant (max-value), irrelevant + f2.FixParameter(1, origPars[0]); // mu_x + f2.FixParameter(2, origPars[1]); // sigma_x + f2.FixParameter(3, origPars[2]); // mu_y + f2.FixParameter(4, origPars[3]); // sigma_y + f2.FixParameter(5, origPars[4]); // rho + for (Int_t i = 0 ; i < n; i++) { + f2.GetRandom2(x, y, &rndm); + z = rndm.Gaus(origPars[5],origPars[6]); + u = rndm.Gaus(origPars[7],origPars[8]); + v = rndm.Gaus(origPars[9],origPars[10]); + w = rndm.Gaus(origPars[11],origPars[12]); + tree->Fill(); + } +} + // Class to make the Unit Testing. It is important than the test // methods are inside the class as this in particular is defined as a // friend of the TFitEditor. This way, we can access the private @@ -58,22 +99,37 @@ class FitEditorUnitTesting const char* _exp; public: InvalidPointer(const char* exp): _exp(exp) {}; - const char* what() { return _exp; }; + const char* what() const noexcept override { return _exp; }; }; // Constructor: Receives the instance of the TFitEditor FitEditorUnitTesting() { // Redirect the stdout to a file outputUnitTesting.txt + #ifdef WIN32 + old_stdout = _dup (_fileno (stdout)); + #else old_stdout = dup (fileno (stdout)); - (void) freopen ("outputUnitTesting.txt", "w", stdout); + #endif + auto res = freopen ("outputUnitTesting.txt", "w", stdout); + if (!res) { + throw InvalidPointer("In FitEditorUnitTesting constructor cannot freopen"); + } + #ifdef WIN32 + out = _fdopen (old_stdout, "w"); + #else out = fdopen (old_stdout, "w"); + #endif // Execute the initial script - gROOT->ProcessLine(".x $ROOTSYS/tutorials/fit/FittingDemo.C+"); + TString scriptLine = TString(".x ") + TROOT::GetTutorialDir() + "/math/fit/FittingDemo.C+"; + gROOT->ProcessLine(scriptLine.Data()); // Get an instance of the TFitEditor TCanvas* c1 = static_cast( gROOT->FindObject("c1") ); TH1* h = static_cast ( gROOT->FindObject("histo") ); + if (!c1 || !h) { + throw InvalidPointer("In c1 or h initialization"); + } f = TFitEditor::GetInstance(c1,h); @@ -176,7 +232,9 @@ class FitEditorUnitTesting for ( unsigned int i = 0; i < f->fFuncPars.size(); ++i ) { for ( unsigned int j = 0; j < 3; ++j) { int internalStatus = equals(pars[i][j], f->fFuncPars[i][j]); - //fprintf(out, "i: %d, j: %d, e: %d\n", i, j, internalStatus); + if (internalStatus != 0) { + fprintf(out, "i: %d, j: %d, e: %d, diff %g\n", i, j, internalStatus, TMath::Abs(pars[i][j] - f->fFuncPars[i][j])); + } status += internalStatus; } } @@ -186,7 +244,7 @@ class FitEditorUnitTesting // From here, the implementation of the different tests. The names // of the test should be enough to know what they are testing, as - // these tests are mean to be as simple as possible. + // these tests are meant to be as simple as possible. int TestHistogramFit() { f->fTypeFit->Select(kFP_UFUNC, kTRUE); @@ -222,7 +280,8 @@ class FitEditorUnitTesting } int TestUpdate() { - gROOT->ProcessLine(".x $ROOTSYS/tutorials/fit/ConfidenceIntervals.C+"); + TString scriptLine = TString(".x ") + TROOT::GetTutorialsDir() + "/math/fit/ConfidenceIntervals.C+"; + gROOT->ProcessLine(scriptLine.Data()); f->DoUpdate(); return 0; @@ -311,7 +370,7 @@ class FitEditorUnitTesting } int TestUpdateTree() { - gROOT->ProcessLine(".x ~/tmp/fitpanel/createTree.C++"); + createTree(); f->DoUpdate(); return 0; } @@ -326,11 +385,10 @@ class FitEditorUnitTesting f->ProcessTreeInput(objSelected, selected, "x", "y>1"); f->fTypeFit->Select(kFP_PRED1D, kTRUE); SelectEntry(f->fFuncList, "gausn"); - f->fFuncPars.resize(3); f->fFuncPars[0][0] = f->fFuncPars[0][1] = f->fFuncPars[0][2] = 1; - f->fFuncPars[1][0] = 0; - f->fFuncPars[2][0] = 1; + f->fFuncPars[1][0] = 0; f->fFuncPars[1][1] = f->fFuncPars[1][2] = 0; + f->fFuncPars[2][0] = 1; f->fFuncPars[2][1] = f->fFuncPars[2][2] = 0; f->DoFit(); diff --git a/hist/hist/src/TFormula.cxx b/hist/hist/src/TFormula.cxx index cb4998da3cf3e..d84092c775211 100644 --- a/hist/hist/src/TFormula.cxx +++ b/hist/hist/src/TFormula.cxx @@ -238,11 +238,15 @@ std::string vectorizedArgType() - `cheb0,1,2,...N` is a substitute for a Chebyshev polynomial of degree `N`: `ROOT::Math::Chebyshev10(x,[p0],[p1],[p2],...[pN])`. Note the maximum N allowed here is 10. 2. Two Dimensional functions: - - `xygaus` is a substitute for `[Constant]*exp(-0.5*pow(((x-[MeanX])/[SigmaX]),2 )- 0.5*pow(((y-[MeanY])/[SigmaY]),2))`, a 2d Gaussian without correlation. - - `bigaus` is a substitute for `[Constant]*ROOT::Math::bigaussian_pdf (x,y,[SigmaX],[SigmaY],[Rho],[MeanX],[MeanY])`, a 2d gaussian including a correlation parameter. + - `xygaus` is a substitute for `[Constant]*exp(-0.5*pow(((x-[MeanX])/[SigmaX]),2 )- + 0.5*pow(((y-[MeanY])/[SigmaY]),2))`, a 2d Gaussian without correlation. + - `bigaus` is a substitute for `[Constant]*ROOT::Math::bigaussian_pdf + (x,y,[SigmaX],[SigmaY],[Rho],[MeanX],[MeanY])`, a 2d gaussian including a correlation parameter. Note the different + order of parameters for bigaus: [Constant]=[0], [SigmaX]=[2], [SigmaY]=[4], [Rho]=[5], [MeanX]=[1], [MeanY]=[3] 3. Three Dimensional functions: - `xyzgaus` is for a 3d Gaussians without correlations: - `[Constant]*exp(-0.5*pow(((x-[MeanX])/[SigmaX]),2 )- 0.5*pow(((y-[MeanY])/[SigmaY]),2 )- 0.5*pow(((z-[MeanZ])/[SigmaZ]),2))` + `[Constant]*exp(-0.5*pow(((x-[MeanX])/[SigmaX]),2 )- 0.5*pow(((y-[MeanY])/[SigmaY]),2 )- + 0.5*pow(((z-[MeanZ])/[SigmaZ]),2))` ### An expanded note on variables and parameters