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 }