go-hep.org/x/hep@v0.40.0/groot/rhist/rw_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
     6  
     7  import (
     8  	"io"
     9  	"reflect"
    10  	"testing"
    11  
    12  	"go-hep.org/x/hep/groot/internal/rtests"
    13  	"go-hep.org/x/hep/groot/rbase"
    14  	"go-hep.org/x/hep/groot/rbytes"
    15  	"go-hep.org/x/hep/groot/rcont"
    16  	"go-hep.org/x/hep/groot/riofs"
    17  	"go-hep.org/x/hep/groot/root"
    18  	"go-hep.org/x/hep/groot/rtypes"
    19  )
    20  
    21  func TestWRBuffer(t *testing.T) {
    22  	loadFrom := func(fname, key string) rtests.ROOTer {
    23  		t.Helper()
    24  
    25  		f, err := riofs.Open(fname)
    26  		if err != nil {
    27  			t.Fatal(err)
    28  		}
    29  		defer f.Close()
    30  		obj, err := riofs.Dir(f).Get(key)
    31  		if err != nil {
    32  			t.Fatal(err)
    33  		}
    34  		return obj.(rtests.ROOTer)
    35  	}
    36  
    37  	for _, tc := range []struct {
    38  		name string
    39  		want rtests.ROOTer
    40  	}{
    41  		{
    42  			name: "TH1F",
    43  			want: &H1F{
    44  				th1: th1{
    45  					Named:     *rbase.NewNamed("h1f", "my-title"),
    46  					attline:   rbase.AttLine{Color: 602, Style: 1, Width: 1},
    47  					attfill:   rbase.AttFill{Color: 0, Style: 1001},
    48  					attmarker: rbase.AttMarker{Color: 1, Style: 1, Width: 1},
    49  					ncells:    102,
    50  					xaxis: taxis{
    51  						Named: *rbase.NewNamed("xaxis", ""),
    52  						attaxis: rbase.AttAxis{
    53  							Ndivs: 510, AxisColor: 1, LabelColor: 1, LabelFont: 42, LabelOffset: 0.005, LabelSize: 0.035, Ticks: 0.03, TitleOffset: 1, TitleSize: 0.035, TitleColor: 1, TitleFont: 42,
    54  						},
    55  						nbins: 100, xmin: 0, xmax: 100,
    56  						xbins: rcont.ArrayD{Data: nil},
    57  						first: 0, last: 0, bits2: 0x0, time: false, tfmt: "",
    58  						labels:  nil,
    59  						modlabs: nil,
    60  					},
    61  					yaxis: taxis{
    62  						Named: *rbase.NewNamed("yaxis", ""),
    63  						attaxis: rbase.AttAxis{
    64  							Ndivs: 510, AxisColor: 1, LabelColor: 1, LabelFont: 42, LabelOffset: 0.005, LabelSize: 0.035, Ticks: 0.03, TitleOffset: 1, TitleSize: 0.035, TitleColor: 1, TitleFont: 42,
    65  						},
    66  						nbins: 1, xmin: 0, xmax: 1,
    67  						xbins: rcont.ArrayD{Data: nil},
    68  						first: 0, last: 0, bits2: 0x0, time: false, tfmt: "",
    69  						labels:  nil,
    70  						modlabs: nil,
    71  					},
    72  					zaxis: taxis{
    73  						Named: *rbase.NewNamed("zaxis", ""),
    74  						attaxis: rbase.AttAxis{
    75  							Ndivs: 510, AxisColor: 1, LabelColor: 1, LabelFont: 42, LabelOffset: 0.005, LabelSize: 0.035, Ticks: 0.03, TitleOffset: 1, TitleSize: 0.035, TitleColor: 1, TitleFont: 42,
    76  						},
    77  						nbins: 1, xmin: 0, xmax: 1,
    78  						xbins: rcont.ArrayD{Data: nil},
    79  						first: 0, last: 0, bits2: 0x0, time: false, tfmt: "",
    80  						labels:  nil,
    81  						modlabs: nil,
    82  					},
    83  					boffset: 0, bwidth: 1000,
    84  					entries: 10,
    85  					tsumw:   10, tsumw2: 16, tsumwx: 278, tsumwx2: 9286,
    86  					max: -1111, min: -1111,
    87  					norm:    0,
    88  					contour: rcont.ArrayD{Data: nil},
    89  					sumw2: rcont.ArrayD{
    90  						Data: []float64{
    91  							1,
    92  							0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    93  							9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    94  							1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    95  							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    96  							0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    97  							1,
    98  						},
    99  					},
   100  					opt:    "",
   101  					funcs:  *rcont.NewList("", []root.Object{}),
   102  					buffer: nil,
   103  					erropt: 0,
   104  				},
   105  				arr: rcont.ArrayF{
   106  					Data: []float32{
   107  						1,
   108  						0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   109  						3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   110  						1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   111  						0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   112  						0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   113  						1,
   114  					},
   115  				},
   116  			},
   117  		},
   118  		{
   119  			name: "TH2F",
   120  			want: &H2F{
   121  				th2: th2{
   122  					th1: th1{
   123  						Named:     *rbase.NewNamed("h2f", "my title"),
   124  						attline:   rbase.AttLine{Color: 602, Style: 1, Width: 1},
   125  						attfill:   rbase.AttFill{Color: 0, Style: 1001},
   126  						attmarker: rbase.AttMarker{Color: 1, Style: 1, Width: 1},
   127  						ncells:    144,
   128  						xaxis: taxis{
   129  							Named: *rbase.NewNamed("xaxis", ""),
   130  							attaxis: rbase.AttAxis{
   131  								Ndivs: 510, AxisColor: 1, LabelColor: 1, LabelFont: 42, LabelOffset: 0.004999999888241291, LabelSize: 0.03500000014901161,
   132  								Ticks: 0.029999999329447746, TitleOffset: 1, TitleSize: 0.03500000014901161, TitleColor: 1, TitleFont: 42,
   133  							},
   134  							nbins:   10,
   135  							xmin:    0,
   136  							xmax:    10,
   137  							xbins:   rcont.ArrayD{},
   138  							first:   0,
   139  							last:    0,
   140  							bits2:   0x0,
   141  							time:    false,
   142  							tfmt:    "",
   143  							labels:  nil,
   144  							modlabs: nil,
   145  						},
   146  						yaxis: taxis{
   147  							Named: *rbase.NewNamed("yaxis", ""),
   148  							attaxis: rbase.AttAxis{
   149  								Ndivs: 510, AxisColor: 1, LabelColor: 1, LabelFont: 42, LabelOffset: 0.004999999888241291, LabelSize: 0.03500000014901161,
   150  								Ticks: 0.029999999329447746, TitleOffset: 1, TitleSize: 0.03500000014901161, TitleColor: 1, TitleFont: 42,
   151  							},
   152  							nbins:   10,
   153  							xmin:    0,
   154  							xmax:    10,
   155  							xbins:   rcont.ArrayD{},
   156  							first:   0,
   157  							last:    0,
   158  							bits2:   0x0,
   159  							time:    false,
   160  							tfmt:    "",
   161  							labels:  nil,
   162  							modlabs: nil,
   163  						},
   164  						zaxis: taxis{
   165  							Named: *rbase.NewNamed("zaxis", ""),
   166  							attaxis: rbase.AttAxis{
   167  								Ndivs: 510, AxisColor: 1, LabelColor: 1, LabelFont: 42, LabelOffset: 0.004999999888241291, LabelSize: 0.03500000014901161,
   168  								Ticks: 0.029999999329447746, TitleOffset: 1, TitleSize: 0.03500000014901161, TitleColor: 1, TitleFont: 42,
   169  							},
   170  							nbins:   1,
   171  							xmin:    0,
   172  							xmax:    1,
   173  							xbins:   rcont.ArrayD{},
   174  							first:   0,
   175  							last:    0,
   176  							bits2:   0x0,
   177  							time:    false,
   178  							tfmt:    "",
   179  							labels:  nil,
   180  							modlabs: nil,
   181  						},
   182  						boffset: 0,
   183  						bwidth:  1000,
   184  						entries: 13,
   185  						tsumw:   9,
   186  						tsumw2:  29,
   187  						tsumwx:  21,
   188  						tsumwx2: 55,
   189  						max:     -1111,
   190  						min:     -1111,
   191  						norm:    0,
   192  						contour: rcont.ArrayD{},
   193  						sumw2: rcont.ArrayD{
   194  							Data: []float64{
   195  								1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
   196  								0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
   197  								0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0,
   198  								0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   199  								0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   200  								0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   201  								0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
   202  							},
   203  						},
   204  						opt:    "",
   205  						funcs:  *rcont.NewList("", []root.Object{}),
   206  						buffer: nil,
   207  						erropt: 0,
   208  					},
   209  					scale:   1,
   210  					tsumwy:  21,
   211  					tsumwy2: 55,
   212  					tsumwxy: 55,
   213  				},
   214  				arr: rcont.ArrayF{
   215  					Data: []float32{
   216  						1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   217  						0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
   218  						0, 1, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   219  						0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   220  						0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   221  						0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
   222  						0, 0, 0, 0, 0, 1,
   223  					},
   224  				},
   225  			},
   226  		},
   227  		{
   228  			name: "TConfidenceLevel",
   229  			want: &ConfidenceLevel{
   230  				base:   *rbase.NewObject(),
   231  				fNNMC:  3,
   232  				fDtot:  5,
   233  				fStot:  2,
   234  				fBtot:  3,
   235  				fTSD:   10,
   236  				fNMC:   11,
   237  				fMCL3S: 12,
   238  				fMCL5S: 13,
   239  				fTSB:   []float64{11, 12, 13},
   240  				fTSS:   []float64{21, 22, 23},
   241  				fLRS:   []float64{31, 32, 33},
   242  				fLRB:   []float64{41, 42, 43},
   243  				fISB:   []int32{1, 2, 3},
   244  				fISS:   []int32{4, 5, 6},
   245  			},
   246  		},
   247  		{
   248  			name: "TLimit",
   249  			want: &Limit{},
   250  		},
   251  		{
   252  			name: "TLimitDataSource",
   253  			want: &LimitDataSource{
   254  				base:     *rbase.NewObject(),
   255  				sig:      newObjArray("sig", "sig1"),
   256  				bkg:      newObjArray("bkg", "bkg1"),
   257  				data:     newObjArray("data", "data1"),
   258  				sigErr:   newObjArray("0", "1", "2"),
   259  				bkgErr:   newObjArray("3", "4", "5"),
   260  				ids:      newObjArray("6", "7", "8"),
   261  				dummyTA:  newObjArray("00", "11", "22"),
   262  				dummyIDs: newObjArray("11", "22", "33"),
   263  			},
   264  		},
   265  		{
   266  			name: "TEfficiency",
   267  			want: loadFrom("../testdata/tconfidence-level.root", "eff"),
   268  		},
   269  		{
   270  			name: "TEfficiency1D",
   271  			want: loadFrom("../testdata/tefficiency.root", "eff1"),
   272  		},
   273  		{
   274  			name: "TEfficiency2D",
   275  			want: loadFrom("../testdata/tefficiency.root", "eff2"),
   276  		},
   277  		{
   278  			name: "TEfficiency3D",
   279  			want: loadFrom("../testdata/tefficiency.root", "eff3"),
   280  		},
   281  		{
   282  			name: "TProfile",
   283  			want: loadFrom("../testdata/tprofile.root", "p1d"),
   284  		},
   285  		{
   286  			name: "TProfile2D",
   287  			want: loadFrom("../testdata/tprofile.root", "p2d"),
   288  		},
   289  		{
   290  			name: "TGraphMultiErrors",
   291  			want: loadFrom("../testdata/tgme.root", "gme"),
   292  		},
   293  		{
   294  			name: "TMultiGraph",
   295  			want: loadFrom("../testdata/tgme.root", "mg"),
   296  		},
   297  		{
   298  			name: "TScatter",
   299  			want: loadFrom("../testdata/tscatter.root", "scatter"),
   300  		},
   301  	} {
   302  		t.Run(tc.name, func(t *testing.T) {
   303  			{
   304  				wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   305  				wbuf.SetErr(io.EOF)
   306  				_, err := tc.want.MarshalROOT(wbuf)
   307  				if err == nil {
   308  					t.Fatalf("expected an error")
   309  				}
   310  				if err != io.EOF {
   311  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   312  				}
   313  			}
   314  			wbuf := rbytes.NewWBuffer(nil, nil, 0, nil)
   315  			_, err := tc.want.MarshalROOT(wbuf)
   316  			if err != nil {
   317  				t.Fatalf("could not marshal ROOT: %v", err)
   318  			}
   319  
   320  			rbuf := rbytes.NewRBuffer(wbuf.Bytes(), nil, 0, nil)
   321  			class := tc.want.Class()
   322  			obj := rtypes.Factory.Get(class)().Interface().(rbytes.Unmarshaler)
   323  			{
   324  				rbuf.SetErr(io.EOF)
   325  				err = obj.UnmarshalROOT(rbuf)
   326  				if err == nil {
   327  					t.Fatalf("expected an error")
   328  				}
   329  				if err != io.EOF {
   330  					t.Fatalf("got=%v, want=%v", err, io.EOF)
   331  				}
   332  				rbuf.SetErr(nil)
   333  			}
   334  			err = obj.UnmarshalROOT(rbuf)
   335  			if err != nil {
   336  				t.Fatalf("could not unmarshal ROOT: %v", err)
   337  			}
   338  
   339  			if !reflect.DeepEqual(obj, tc.want) {
   340  				t.Fatalf("error\ngot= %+v\nwant=%+v\n", obj, tc.want)
   341  			}
   342  		})
   343  	}
   344  }
   345  
   346  func TestReadF1(t *testing.T) {
   347  	for _, fname := range []string{
   348  		"../testdata/tformula.root",
   349  		"../testdata/tformula-v14.root",
   350  	} {
   351  		t.Run(fname, func(t *testing.T) {
   352  			f, err := riofs.Open(fname)
   353  			if err != nil {
   354  				t.Fatal(err)
   355  			}
   356  			defer f.Close()
   357  
   358  			for _, key := range []string{
   359  				"func1", "func2", "func3", "func4",
   360  				"fconv",
   361  				"fnorm",
   362  			} {
   363  				t.Run(key, func(t *testing.T) {
   364  					obj, err := f.Get(key)
   365  					if err != nil {
   366  						t.Fatalf("could not read object %q: %+v", key, err)
   367  					}
   368  					switch v := obj.(type) {
   369  					case *F1:
   370  						if got, want := v.Name(), key; got != want {
   371  							t.Fatalf("invalid name: got=%q, want=%q", got, want)
   372  						}
   373  						if got, want := v.Class(), "TF1"; got != want {
   374  							t.Fatalf("invalid class: got=%q, want=%q", got, want)
   375  						}
   376  						if got, want := v.chi2, 0.2; got != want {
   377  							t.Fatalf("invalid chi2: got=%v, want=%v", got, want)
   378  						}
   379  					case F1Composition:
   380  						// ok.
   381  					default:
   382  						t.Fatalf("invalid object type for %q", key)
   383  					}
   384  				})
   385  			}
   386  		})
   387  	}
   388  }
   389  
   390  func newObjArray(vs ...string) rcont.ObjArray {
   391  	elems := make([]root.Object, len(vs))
   392  	for i, v := range vs {
   393  		elems[i] = rbase.NewObjString(v)
   394  	}
   395  	o := rcont.NewObjArray()
   396  	o.SetElems(elems)
   397  	return *o
   398  }
   399  
   400  func TestHistObjectFinder(t *testing.T) {
   401  	h := newH1()
   402  	h.funcs.Append(rbase.NewNamed("e1", "elem-1"))
   403  	h.funcs.Append(rbase.NewNamed("e2", "elem-2"))
   404  	h.funcs.Append(rbase.NewObject())
   405  	h.funcs.Append(rbase.NewNamed("e4", "elem-4"))
   406  
   407  	if got, want := h.Keys(), []string{"e1", "e2", "e4"}; !reflect.DeepEqual(got, want) {
   408  		t.Fatalf("invalid keys: got=%q, want=%q", got, want)
   409  	}
   410  
   411  	_, err := h.Get("Not-There")
   412  	if err == nil {
   413  		t.Fatalf("expected an error")
   414  	}
   415  
   416  	got, err := h.Get("e2")
   417  	if err != nil {
   418  		t.Fatalf("could not retrieve e2: %+v", err)
   419  	}
   420  
   421  	n2, ok := got.(*rbase.Named)
   422  	if !ok {
   423  		t.Fatalf("retrieved invalid element (not a Named: %T)", got)
   424  	}
   425  	if got, want := n2.Name(), "e2"; got != want {
   426  		t.Fatalf("invalid element name: got=%q, want=%q", got, want)
   427  	}
   428  }
   429  
   430  func TestGraphObjectFinder(t *testing.T) {
   431  	g := newGraph(2)
   432  	funcs := g.funcs.(*rcont.List)
   433  	funcs.Append(rbase.NewNamed("e1", "elem-1"))
   434  	funcs.Append(rbase.NewNamed("e2", "elem-2"))
   435  	funcs.Append(rbase.NewObject())
   436  	funcs.Append(rbase.NewNamed("e4", "elem-4"))
   437  
   438  	if got, want := g.Keys(), []string{"e1", "e2", "e4"}; !reflect.DeepEqual(got, want) {
   439  		t.Fatalf("invalid keys: got=%q, want=%q", got, want)
   440  	}
   441  
   442  	_, err := g.Get("Not-There")
   443  	if err == nil {
   444  		t.Fatalf("expected an error")
   445  	}
   446  
   447  	got, err := g.Get("e2")
   448  	if err != nil {
   449  		t.Fatalf("could not retrieve e2: %+v", err)
   450  	}
   451  
   452  	n2, ok := got.(*rbase.Named)
   453  	if !ok {
   454  		t.Fatalf("retrieved invalid element (not a Named: %T)", got)
   455  	}
   456  	if got, want := n2.Name(), "e2"; got != want {
   457  		t.Fatalf("invalid element name: got=%q, want=%q", got, want)
   458  	}
   459  }