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 }