go-hep.org/x/hep@v0.38.1/groot/rhist/hist_example_test.go (about)

     1  // Copyright ©2018 The go-hep Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package rhist_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"log"
    11  	"math/rand/v2"
    12  	"os"
    13  	"testing"
    14  
    15  	"github.com/google/go-cmp/cmp"
    16  	"go-hep.org/x/hep/groot"
    17  	"go-hep.org/x/hep/groot/rhist"
    18  	"go-hep.org/x/hep/groot/rtypes"
    19  	"go-hep.org/x/hep/hbook"
    20  	"go-hep.org/x/hep/hbook/rootcnv"
    21  	"go-hep.org/x/hep/hbook/yodacnv"
    22  	"gonum.org/v1/gonum/stat/distuv"
    23  )
    24  
    25  func ExampleCreate_histo1D() {
    26  	const fname = "h1d_example.root"
    27  	defer os.Remove(fname)
    28  
    29  	f, err := groot.Create(fname)
    30  	if err != nil {
    31  		log.Fatal(err)
    32  	}
    33  	defer f.Close()
    34  
    35  	const npoints = 10000
    36  
    37  	// Create a normal distribution.
    38  	dist := distuv.Normal{
    39  		Mu:    0,
    40  		Sigma: 1,
    41  		Src:   rand.New(rand.NewPCG(0, 0)),
    42  	}
    43  
    44  	// Draw some random values from the standard
    45  	// normal distribution.
    46  	h := hbook.NewH1D(20, -4, +4)
    47  	for range npoints {
    48  		v := dist.Rand()
    49  		h.Fill(v, 1)
    50  	}
    51  	h.Fill(-10, 1) // fill underflow
    52  	h.Fill(-20, 2)
    53  	h.Fill(+10, 3) // fill overflow
    54  
    55  	fmt.Printf("original histo:\n")
    56  	fmt.Printf("w-mean:    %.7f\n", h.XMean())
    57  	fmt.Printf("w-rms:     %.7f\n", h.XRMS())
    58  
    59  	hroot := rhist.NewH1DFrom(h)
    60  
    61  	err = f.Put("h1", hroot)
    62  	if err != nil {
    63  		log.Fatal(err)
    64  	}
    65  
    66  	err = f.Close()
    67  	if err != nil {
    68  		log.Fatalf("error closing ROOT file: %v", err)
    69  	}
    70  
    71  	r, err := groot.Open(fname)
    72  	if err != nil {
    73  		log.Fatal(err)
    74  	}
    75  	defer r.Close()
    76  
    77  	robj, err := r.Get("h1")
    78  	if err != nil {
    79  		log.Fatal(err)
    80  	}
    81  
    82  	hr := rootcnv.H1D(robj.(rhist.H1))
    83  
    84  	fmt.Printf("\nhisto read back:\n")
    85  	fmt.Printf("r-mean:    %.7f\n", hr.XMean())
    86  	fmt.Printf("r-rms:     %.7f\n", hr.XRMS())
    87  
    88  	// Output:
    89  	// original histo:
    90  	// w-mean:    -0.0010939
    91  	// w-rms:     1.0575275
    92  	//
    93  	// histo read back:
    94  	// r-mean:    -0.0010939
    95  	// r-rms:     1.0575275
    96  }
    97  
    98  func ExampleCreate_histo2D() {
    99  	const fname = "h2d_example.root"
   100  	defer os.Remove(fname)
   101  
   102  	f, err := groot.Create(fname)
   103  	if err != nil {
   104  		log.Fatal(err)
   105  	}
   106  	defer f.Close()
   107  
   108  	const npoints = 1000
   109  
   110  	// Create a normal distribution.
   111  	dist := distuv.Normal{
   112  		Mu:    0,
   113  		Sigma: 1,
   114  		Src:   rand.New(rand.NewPCG(0, 0)),
   115  	}
   116  
   117  	// Draw some random values from the standard
   118  	// normal distribution.
   119  	h := hbook.NewH2D(5, -4, +4, 6, -4, +4)
   120  	for range npoints {
   121  		x := dist.Rand()
   122  		y := dist.Rand()
   123  		h.Fill(x, y, 1)
   124  	}
   125  	h.Fill(-10, -10, 1) // fill underflow
   126  	h.Fill(-10, +10, 1)
   127  	h.Fill(+10, -10, 1)
   128  	h.Fill(+10, +10, 3) // fill overflow
   129  
   130  	fmt.Printf("original histo:\n")
   131  	fmt.Printf("w-mean-x:    %+.6f\n", h.XMean())
   132  	fmt.Printf("w-rms-x:     %+.6f\n", h.XRMS())
   133  	fmt.Printf("w-mean-y:    %+.6f\n", h.YMean())
   134  	fmt.Printf("w-rms-y:     %+.6f\n", h.YRMS())
   135  
   136  	hroot := rhist.NewH2DFrom(h)
   137  
   138  	err = f.Put("h2", hroot)
   139  	if err != nil {
   140  		log.Fatal(err)
   141  	}
   142  
   143  	err = f.Close()
   144  	if err != nil {
   145  		log.Fatalf("error closing ROOT file: %v", err)
   146  	}
   147  
   148  	r, err := groot.Open(fname)
   149  	if err != nil {
   150  		log.Fatal(err)
   151  	}
   152  	defer r.Close()
   153  
   154  	robj, err := r.Get("h2")
   155  	if err != nil {
   156  		log.Fatal(err)
   157  	}
   158  
   159  	hr := rootcnv.H2D(robj.(rhist.H2))
   160  
   161  	fmt.Printf("\nhisto read back:\n")
   162  	fmt.Printf("w-mean-x:    %+.6f\n", hr.XMean())
   163  	fmt.Printf("w-rms-x:     %+.6f\n", hr.XRMS())
   164  	fmt.Printf("w-mean-y:    %+.6f\n", hr.YMean())
   165  	fmt.Printf("w-rms-y:     %+.6f\n", hr.YRMS())
   166  
   167  	// Output:
   168  	// original histo:
   169  	// w-mean-x:    +0.016810
   170  	// w-rms-x:     +1.256504
   171  	// w-mean-y:    +0.030289
   172  	// w-rms-y:     +1.300039
   173  	//
   174  	// histo read back:
   175  	// w-mean-x:    +0.016810
   176  	// w-rms-x:     +1.256504
   177  	// w-mean-y:    +0.030289
   178  	// w-rms-y:     +1.300039
   179  }
   180  
   181  func TestH1(t *testing.T) {
   182  	const npoints = 10000
   183  
   184  	// Create a normal distribution.
   185  	dist := distuv.Normal{
   186  		Mu:    0,
   187  		Sigma: 1,
   188  		Src:   rand.New(rand.NewPCG(0, 0)),
   189  	}
   190  
   191  	// Draw some random values from the standard
   192  	// normal distribution.
   193  	h := hbook.NewH1D(20, -4, +4)
   194  	for range npoints {
   195  		v := dist.Rand()
   196  		h.Fill(v, 1)
   197  	}
   198  	h.Fill(-10, 1) // fill underflow
   199  	h.Fill(-20, 2)
   200  	h.Fill(+10, 1) // fill overflow
   201  	h.Fill(+10, 2)
   202  	h.Annotation()["name"] = "my-name"
   203  	h.Annotation()["title"] = "my-title"
   204  
   205  	for _, tc := range []struct {
   206  		name   string
   207  		h1     rhist.H1
   208  		sumw   float64
   209  		sumw2  float64
   210  		sumwx  float64
   211  		sumwx2 float64
   212  	}{
   213  		{
   214  			name:   "TH1D",
   215  			h1:     rhist.NewH1DFrom(h),
   216  			sumw:   h.SumW(),
   217  			sumw2:  h.SumW2(),
   218  			sumwx:  h.SumWX(),
   219  			sumwx2: h.SumWX2(),
   220  		},
   221  		{
   222  			name:   "TH1F",
   223  			h1:     rhist.NewH1FFrom(h),
   224  			sumw:   h.SumW(),
   225  			sumw2:  h.SumW2(),
   226  			sumwx:  h.SumWX(),
   227  			sumwx2: h.SumWX2(),
   228  		},
   229  		{
   230  			name:   "TH1I",
   231  			h1:     rhist.NewH1IFrom(h),
   232  			sumw:   h.SumW(),
   233  			sumw2:  h.SumW2(),
   234  			sumwx:  h.SumWX(),
   235  			sumwx2: h.SumWX2(),
   236  		},
   237  	} {
   238  		t.Run(tc.name, func(t *testing.T) {
   239  			if got, want := tc.h1.SumW(), h.SumW(); got != want {
   240  				t.Fatalf("sumw: got=%v, want=%v", got, want)
   241  			}
   242  			if got, want := tc.h1.SumW2(), h.SumW2(); got != want {
   243  				t.Fatalf("sumw2: got=%v, want=%v", got, want)
   244  			}
   245  			if got, want := tc.h1.SumWX(), h.SumWX(); got != want {
   246  				t.Fatalf("sumwx: got=%v, want=%v", got, want)
   247  			}
   248  			if got, want := tc.h1.SumWX2(), h.SumWX2(); got != want {
   249  				t.Fatalf("sumwx2: got=%v, want=%v", got, want)
   250  			}
   251  
   252  			rraw, err := tc.h1.(yodacnv.Marshaler).MarshalYODA()
   253  			if err != nil {
   254  				t.Fatal(err)
   255  			}
   256  
   257  			hh := rootcnv.H1D(tc.h1)
   258  
   259  			hraw, err := hh.MarshalYODA()
   260  			if err != nil {
   261  				t.Fatal(err)
   262  			}
   263  
   264  			var hr = rtypes.Factory.Get(tc.name)().Interface().(rhist.H1)
   265  			if err := hr.(yodacnv.Unmarshaler).UnmarshalYODA(hraw); err != nil {
   266  				t.Fatal(err)
   267  			}
   268  
   269  			rgot, err := hr.(yodacnv.Marshaler).MarshalYODA()
   270  			if err != nil {
   271  				t.Fatal(err)
   272  			}
   273  
   274  			if !bytes.Equal(rgot, rraw) {
   275  				t.Fatalf("round trip error:\nraw:\n%s\ngot:\n%s\n", rraw, rgot)
   276  			}
   277  		})
   278  	}
   279  }
   280  
   281  func TestH2(t *testing.T) {
   282  	const npoints = 10000
   283  
   284  	// Create a normal distribution.
   285  	dist := distuv.Normal{
   286  		Mu:    0,
   287  		Sigma: 1,
   288  		Src:   rand.New(rand.NewPCG(0, 0)),
   289  	}
   290  
   291  	// Draw some random values from the standard
   292  	// normal distribution.
   293  	h := hbook.NewH2D(5, -4, +4, 6, -4, +4)
   294  	for range npoints {
   295  		x := dist.Rand()
   296  		y := dist.Rand()
   297  		h.Fill(x, y, 1)
   298  	}
   299  	h.Fill(+0, +5, 1) // N
   300  	h.Fill(-5, +5, 2) // N-W
   301  	h.Fill(-5, +0, 3) // W
   302  	h.Fill(-5, -5, 4) // S-W
   303  	h.Fill(+0, -5, 5) // S
   304  	h.Fill(+5, -5, 6) // S-E
   305  	h.Fill(+5, +0, 7) // E
   306  	h.Fill(+5, +5, 8) // N-E
   307  
   308  	h.Annotation()["name"] = "my-name"
   309  	h.Annotation()["title"] = "my-title"
   310  
   311  	for _, tc := range []struct {
   312  		name   string
   313  		h2     rhist.H2
   314  		sumw   float64
   315  		sumw2  float64
   316  		sumwx  float64
   317  		sumwx2 float64
   318  	}{
   319  		{
   320  			name:   "TH2D",
   321  			h2:     rhist.NewH2DFrom(h),
   322  			sumw:   h.SumW(),
   323  			sumw2:  h.SumW2(),
   324  			sumwx:  h.SumWX(),
   325  			sumwx2: h.SumWX2(),
   326  		},
   327  		{
   328  			name:   "TH2F",
   329  			h2:     rhist.NewH2FFrom(h),
   330  			sumw:   h.SumW(),
   331  			sumw2:  h.SumW2(),
   332  			sumwx:  h.SumWX(),
   333  			sumwx2: h.SumWX2(),
   334  		},
   335  		{
   336  			name:   "TH2I",
   337  			h2:     rhist.NewH2IFrom(h),
   338  			sumw:   h.SumW(),
   339  			sumw2:  h.SumW2(),
   340  			sumwx:  h.SumWX(),
   341  			sumwx2: h.SumWX2(),
   342  		},
   343  	} {
   344  		t.Run(tc.name, func(t *testing.T) {
   345  			if got, want := tc.h2.SumW(), h.SumW(); got != want {
   346  				t.Fatalf("sumw: got=%v, want=%v", got, want)
   347  			}
   348  			if got, want := tc.h2.SumW2(), h.SumW2(); got != want {
   349  				t.Fatalf("sumw2: got=%v, want=%v", got, want)
   350  			}
   351  			if got, want := tc.h2.SumWX(), h.SumWX(); got != want {
   352  				t.Fatalf("sumwx: got=%v, want=%v", got, want)
   353  			}
   354  			if got, want := tc.h2.SumWX2(), h.SumWX2(); got != want {
   355  				t.Fatalf("sumwx2: got=%v, want=%v", got, want)
   356  			}
   357  
   358  			rraw, err := tc.h2.(yodacnv.Marshaler).MarshalYODA()
   359  			if err != nil {
   360  				t.Fatal(err)
   361  			}
   362  
   363  			hh := rootcnv.H2D(tc.h2)
   364  
   365  			hraw, err := hh.MarshalYODA()
   366  			if err != nil {
   367  				t.Fatal(err)
   368  			}
   369  
   370  			var hr = rtypes.Factory.Get(tc.name)().Interface().(rhist.H2)
   371  			if err := hr.(yodacnv.Unmarshaler).UnmarshalYODA(hraw); err != nil {
   372  				t.Fatal(err)
   373  			}
   374  
   375  			rgot, err := hr.(yodacnv.Marshaler).MarshalYODA()
   376  			if err != nil {
   377  				t.Fatal(err)
   378  			}
   379  
   380  			// rounding errors... // FIXME(sbinet)
   381  			rraw = bytes.Replace(rraw,
   382  				[]byte("# Mean: (1.990041e-02, 2.039840e-04)"),
   383  				[]byte("# Mean: (1.990041e-02, 2.039841e-04)"),
   384  				-1,
   385  			)
   386  			if !bytes.Equal(rgot, rraw) {
   387  				t.Fatalf("round trip error:\n%s",
   388  					cmp.Diff(
   389  						string(rraw),
   390  						string(rgot),
   391  					),
   392  				)
   393  			}
   394  		})
   395  	}
   396  }