Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion hist/hist/inc/TProfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ class TProfile : public TH1D {
Bool_t Add(const TH1 *h1, const TH1 *h2, Double_t c1=1, Double_t c2=1) override; // *MENU*
static void Approximate(Bool_t approx=kTRUE);
Int_t BufferEmpty(Int_t action=0) override;
void BuildOptions(Double_t ymin, Double_t ymax, Option_t *option);
void BuildOptions(Double_t ymin, Double_t ymax, Option_t *option);
Double_t Chi2Test(const TH1* h2, Option_t *option = "WW", Double_t *res = nullptr) const override;
void Copy(TObject &hnew) const override;
Bool_t Divide(TF1 *h1, Double_t c1=1) override;
Bool_t Divide(const TH1 *h1) override;
Expand Down
1 change: 1 addition & 0 deletions hist/hist/inc/TProfile2D.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class TProfile2D : public TH2D {
static void Approximate(Bool_t approx=kTRUE);
void BuildOptions(Double_t zmin, Double_t zmax, Option_t *option);
Int_t BufferEmpty(Int_t action=0) override;
Double_t Chi2Test(const TH1* h2, Option_t *option = "WW", Double_t *res = nullptr) const override;
void Copy(TObject &hnew) const override;
Bool_t Divide(TF1 *h1, Double_t c1=1) override;
Bool_t Divide(const TH1 *h1) override;
Expand Down
1 change: 1 addition & 0 deletions hist/hist/inc/TProfile3D.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class TProfile3D : public TH3D {
static void Approximate(Bool_t approx=kTRUE);
void BuildOptions(Double_t tmin, Double_t tmax, Option_t *option);
Int_t BufferEmpty(Int_t action=0) override;
Double_t Chi2Test(const TH1* h2, Option_t *option = "WW", Double_t *res = nullptr) const override;
void Copy(TObject &hnew) const override;
Bool_t Divide(TF1 *h1, Double_t c1=1) override;
Bool_t Divide(const TH1 *h1) override;
Expand Down
28 changes: 28 additions & 0 deletions hist/hist/src/TProfile.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,34 @@ Int_t TProfile::BufferFill(Double_t x, Double_t y, Double_t w)
return -2;
}

////////////////////////////////////////////////////////////////////////////////
/// Run a Chi2Test between a TProfileD and another histogram.
/// If the argument is also a TProfileD, this calls TH1::Chi2Test() with the option "WW".
/// \see TH1::Chi2Test()

Double_t TProfile::Chi2Test(const TH1 *h2, Option_t *option, Double_t *res) const
{
TString opt = option;
opt.ToUpper();

if (auto other = dynamic_cast<const TProfile *>(h2); other) {
if (fErrorMode != kERRORMEAN || other->fErrorMode != kERRORMEAN) {
Error("Chi2Test", "Chi2 tests need TProfiles in 'error of mean' mode.");
return 0;
}

opt += "WW";
opt.ReplaceAll("UU", "WW");
opt.ReplaceAll("UW", "WW");
} else if (!opt.Contains("WW")) {
Error("Chi2Test", "TProfiles need to be tested with the 'W' option. Either use option 'WW' or use "
"histogram.Chi2Test(<profile>, 'UW')");
return 0;
}

return TH1::Chi2Test(h2, opt, res);
}

////////////////////////////////////////////////////////////////////////////////
/// Copy a Profile histogram to a new profile histogram.

Expand Down
28 changes: 28 additions & 0 deletions hist/hist/src/TProfile2D.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,34 @@ Int_t TProfile2D::BufferFill(Double_t x, Double_t y, Double_t z, Double_t w)
return -2;
}

////////////////////////////////////////////////////////////////////////////////
/// Run a Chi2Test between a TProfile2D and another histogram.
/// If the argument is also a TProfile2D, this calls TH1::Chi2Test() with the option "WW".
/// \see TH1::Chi2Test()

Double_t TProfile2D::Chi2Test(const TH1 *h2, Option_t *option, Double_t *res) const
{
TString opt = option;
opt.ToUpper();

if (auto other = dynamic_cast<const TProfile2D *>(h2); other) {
if (fErrorMode != kERRORMEAN || other->fErrorMode != kERRORMEAN) {
Error("Chi2Test", "Chi2 tests need TProfiles in 'error of mean' mode.");
return 0;
}

opt += "WW";
opt.ReplaceAll("UU", "WW");
opt.ReplaceAll("UW", "WW");
} else if (!opt.Contains("WW")) {
Error("Chi2Test", "TProfiles need to be tested with the 'W' option. Either use option 'WW' or use "
"histogram.Chi2Test(<profile>, 'UW')");
return 0;
}

return TH1::Chi2Test(h2, opt, res);
}

////////////////////////////////////////////////////////////////////////////////
/// Copy a Profile2D histogram to a new profile2D histogram.

Expand Down
28 changes: 28 additions & 0 deletions hist/hist/src/TProfile3D.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,34 @@ Int_t TProfile3D::BufferFill(Double_t x, Double_t y, Double_t z, Double_t t, Dou
return -2;
}

////////////////////////////////////////////////////////////////////////////////
/// Run a Chi2Test between a TProfile3D and another histogram.
/// If the argument is also a TProfile3D, this calls TH1::Chi2Test() with the option "WW".
/// \see TH1::Chi2Test()

Double_t TProfile3D::Chi2Test(const TH1 *h2, Option_t *option, Double_t *res) const
{
TString opt = option;
opt.ToUpper();

if (auto other = dynamic_cast<const TProfile3D *>(h2); other) {
if (fErrorMode != kERRORMEAN || other->fErrorMode != kERRORMEAN) {
Error("Chi2Test", "Chi2 tests need TProfiles in 'error of mean' mode.");
return 0;
}

opt += "WW";
opt.ReplaceAll("UU", "WW");
opt.ReplaceAll("UW", "WW");
} else if (!opt.Contains("WW")) {
Error("Chi2Test", "TProfiles need to be tested with the 'W' option. Either use option 'WW' or use "
"histogram.Chi2Test(<profile>, 'UW')");
return 0;
}

return TH1::Chi2Test(h2, opt, res);
}

////////////////////////////////////////////////////////////////////////////////
/// Copy a Profile3D histogram to a new profile2D histogram.

Expand Down
1 change: 1 addition & 0 deletions hist/hist/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ROOT_ADD_GTEST(testTGraphSorting test_TGraph_sorting.cxx LIBRARIES Hist)
ROOT_ADD_GTEST(testSpline test_spline.cxx LIBRARIES Hist)
ROOT_ADD_GTEST(testTF1Simple test_tf1_simple.cxx LIBRARIES Hist RIO)
ROOT_ADD_GTEST(testTF1DrawCopy test_tf1_drawcopy.cxx LIBRARIES Hist)
ROOT_ADD_GTEST(test_TProfile test_TProfile.cxx LIBRARIES Hist)

if(fftw3)
ROOT_ADD_GTEST(testTF1 test_tf1.cxx LIBRARIES Hist)
Expand Down
93 changes: 93 additions & 0 deletions hist/hist/test/test_TProfile.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "gtest/gtest.h"

#include "TProfile.h"
#include "TProfile2D.h"
#include "TProfile3D.h"
#include "TRandom.h"

#include "ROOT/TestSupport.hxx"

template <typename T>
void runTest(T const &reference, T const &sameDistr, T const &differentDistr)
{
EXPECT_EQ(reference.Chi2Test(&sameDistr), reference.Chi2Test(&sameDistr, "WW"));
EXPECT_EQ(reference.Chi2Test(&sameDistr),
reference.Chi2Test(&sameDistr, "P WW UW")); // Need more than just the default option
EXPECT_EQ(reference.Chi2Test(&sameDistr), reference.Chi2Test(&sameDistr, "UW"));
EXPECT_EQ(reference.Chi2Test(&sameDistr), reference.Chi2Test(&sameDistr, "UU"));
EXPECT_EQ(reference.Chi2Test(&sameDistr), reference.Chi2Test(&sameDistr, "P UU"));

const double probSuccess = reference.Chi2Test(&sameDistr, "P");
EXPECT_GT(probSuccess, 0.1);
EXPECT_LE(probSuccess, 1.);
const double probFail = reference.Chi2Test(&differentDistr, "P");
EXPECT_LT(probFail, 0.05);
}

TEST(TProfile, Chi2Test)
{
TProfile reference("reference", "reference", 10, 0, 10);
TProfile sameDistr("sameDistr", "sameDistr", 10, 0, 10);
TProfile differentDistr("differentDistr", "differentDistr", 10, 0, 10);

gRandom->SetSeed(1);
for (unsigned int i = 0; i < 100000; i++) {
const double x = gRandom->Uniform(10.);
reference.Fill(x, gRandom->Gaus(5 + x / 2, 5.));
sameDistr.Fill(x, gRandom->Gaus(5 + x / 2, 5.));
differentDistr.Fill(x, gRandom->Gaus(20, 1.));
}

runTest(reference, sameDistr, differentDistr);
}

TEST(TProfile, Chi2TestWithWrongErrors)
{
TProfile reference("reference", "reference", 10, 0, 10);
reference.Fill(1, 2);
reference.Fill(1, 3);

for (auto err : {"s", "i", "g"}) {
ROOT::TestSupport::CheckDiagsRAII checkDiag(kError, "TProfile::Chi2Test", "error of mean", false);

TProfile sameDistr("sameDistr", "sameDistr", 10, 0, 10, err);
sameDistr.Fill(1, 2);
sameDistr.Fill(1, 3);

reference.Chi2Test(&sameDistr);
}
}

TEST(TProfile2D, Chi2Test)
{
TProfile2D reference("reference", "reference", 10, 0, 10, 10, 0, 10);
TProfile2D sameDistr("sameDistr", "sameDistr", 10, 0, 10, 10, 0, 10);
TProfile2D differentDistr("differentDistr", "differentDistr", 10, 0, 10, 10, 0, 10);

gRandom->SetSeed(1);
for (unsigned int i = 0; i < 50000; i++) {
const double x = gRandom->Uniform(10.);
reference.Fill(x, x + 1., gRandom->Gaus(5 + x / 2, 5.));
sameDistr.Fill(x, x + 1., gRandom->Gaus(5 + x / 2, 5.));
differentDistr.Fill(x, x + 1., gRandom->Gaus(20, 1.));
}

runTest(reference, sameDistr, differentDistr);
}

TEST(TProfile3D, Chi2Test)
{
TProfile3D reference("reference", "reference", 10, 0, 10, 11, 0, 11, 12, 0, 12);
TProfile3D sameDistr("sameDistr", "sameDistr", 10, 0, 10, 11, 0, 11, 12, 0, 12);
TProfile3D differentDistr("differentDistr", "differentDistr", 10, 0, 10, 11, 0, 11, 12, 0, 12);

gRandom->SetSeed(1);
for (unsigned int i = 0; i < 50000; i++) {
const double x = gRandom->Uniform(10.);
reference.Fill(x, x + 1., x + 2., gRandom->Gaus(5 + x / 2, 5.));
sameDistr.Fill(x, x + 1., x + 2., gRandom->Gaus(5 + x / 2, 5.));
differentDistr.Fill(x, x + 1., x + 2., gRandom->Gaus(20, 1.));
}

runTest(reference, sameDistr, differentDistr);
}
Loading