go-hep.org/x/hep@v0.38.1/hbook/rootcnv/root_test.go (about) 1 // Copyright ©2017 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 rootcnv_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "log" 11 "math/rand/v2" 12 "reflect" 13 "runtime" 14 "testing" 15 16 "github.com/google/go-cmp/cmp" 17 "go-hep.org/x/hep/groot" 18 "go-hep.org/x/hep/groot/rhist" 19 "go-hep.org/x/hep/groot/rtypes" 20 "go-hep.org/x/hep/hbook" 21 "go-hep.org/x/hep/hbook/rootcnv" 22 "go-hep.org/x/hep/hbook/yodacnv" 23 "gonum.org/v1/gonum/stat/distuv" 24 ) 25 26 func ExampleH1D() { 27 f, err := groot.Open("testdata/gauss-h1.root") 28 if err != nil { 29 log.Fatal(err) 30 } 31 defer f.Close() 32 33 obj, err := f.Get("h1d") 34 if err != nil { 35 log.Fatal(err) 36 } 37 38 var ( 39 root = obj.(*rhist.H1D) 40 h = rootcnv.H1D(root) 41 ) 42 43 fmt.Printf("name: %q\n", root.Name()) 44 fmt.Printf("mean: %v\n", h.XMean()) 45 fmt.Printf("std-dev: %v\n", h.XStdDev()) 46 fmt.Printf("std-err: %v\n", h.XStdErr()) 47 48 // Output: 49 // name: "h1d" 50 // mean: 0.028120158262930028 51 // std-dev: 2.5450388861661377 52 // std-err: 0.025447023184829384 53 } 54 55 func ExampleH2D() { 56 f, err := groot.Open("testdata/gauss-h2.root") 57 if err != nil { 58 log.Fatal(err) 59 } 60 defer f.Close() 61 62 obj, err := f.Get("h2d") 63 if err != nil { 64 log.Fatal(err) 65 } 66 67 var ( 68 root = obj.(*rhist.H2D) 69 h = rootcnv.H2D(root) 70 ) 71 72 fmt.Printf("name: %q\n", root.Name()) 73 fmt.Printf("x-mean: %v\n", h.XMean()) 74 fmt.Printf("x-std-dev: %v\n", h.XStdDev()) 75 fmt.Printf("x-std-err: %v\n", h.XStdErr()) 76 fmt.Printf("y-mean: %v\n", h.YMean()) 77 fmt.Printf("y-std-dev: %v\n", h.YStdDev()) 78 fmt.Printf("y-std-err: %v\n", h.YStdErr()) 79 80 // Output: 81 // name: "h2d" 82 // x-mean: -0.005792199729986178 83 // x-std-dev: 2.270805729597938 84 // x-std-err: 0.06540325772462689 85 // y-mean: 0.8942018621292575 86 // y-std-dev: 1.830794214602073 87 // y-std-err: 0.05273014080318356 88 } 89 90 func ExampleS2D() { 91 f, err := groot.Open("../../groot/testdata/graphs.root") 92 if err != nil { 93 log.Fatal(err) 94 } 95 defer f.Close() 96 97 obj, err := f.Get("tgae") 98 if err != nil { 99 log.Fatal(err) 100 } 101 102 var ( 103 root = obj.(rhist.GraphErrors) 104 g = rootcnv.S2D(root) 105 ) 106 107 fmt.Printf("name: %q\n", g.Annotation()["name"]) 108 fmt.Printf("title: %q\n", g.Annotation()["title"]) 109 fmt.Printf("#pts: %v\n", g.Len()) 110 for i, pt := range g.Points() { 111 x := pt.X 112 y := pt.Y 113 xlo := pt.ErrX.Min 114 xhi := pt.ErrX.Max 115 ylo := pt.ErrY.Min 116 yhi := pt.ErrY.Max 117 fmt.Printf("(x,y)[%d] = (%+e +/- [%+e, %+e], %+e +/- [%+e, %+e])\n", i, x, xlo, xhi, y, ylo, yhi) 118 } 119 120 // Output: 121 // name: "tgae" 122 // title: "graph with asymmetric errors" 123 // #pts: 4 124 // (x,y)[0] = (+1.000000e+00 +/- [+1.000000e-01, +2.000000e-01], +2.000000e+00 +/- [+3.000000e-01, +4.000000e-01]) 125 // (x,y)[1] = (+2.000000e+00 +/- [+2.000000e-01, +4.000000e-01], +4.000000e+00 +/- [+6.000000e-01, +8.000000e-01]) 126 // (x,y)[2] = (+3.000000e+00 +/- [+3.000000e-01, +6.000000e-01], +6.000000e+00 +/- [+9.000000e-01, +1.200000e+00]) 127 // (x,y)[3] = (+4.000000e+00 +/- [+4.000000e-01, +8.000000e-01], +8.000000e+00 +/- [+1.200000e+00, +1.600000e+00]) 128 } 129 130 func TestH1D(t *testing.T) { 131 f, err := groot.Open("testdata/gauss-h1.root") 132 if err != nil { 133 t.Fatal(err) 134 } 135 defer f.Close() 136 137 for _, test := range []struct { 138 name string 139 want []byte 140 }{ 141 { 142 name: "h1d", 143 want: []byte(`BEGIN YODA_HISTO1D_V2 /h1d 144 Path: /h1d 145 Title: h1d 146 Type: Histo1D 147 --- 148 # Mean: 2.812016e-02 149 # Area: 1.100600e+04 150 # ID ID sumw sumw2 sumwx sumwx2 numEntries 151 Total Total 1.100600e+04 1.211000e+04 3.094905e+02 7.128989e+04 1.000400e+04 152 Underflow Underflow 2.000000e+00 2.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 153 Overflow Overflow 4.000000e+00 8.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 154 # xlow xhigh sumw sumw2 sumwx sumwx2 numEntries 155 -4.000000e+00 -3.200000e+00 6.600000e+00 7.260000e+00 0.000000e+00 0.000000e+00 6.000000e+00 156 -3.200000e+00 -2.400000e+00 7.260000e+01 7.986000e+01 0.000000e+00 0.000000e+00 6.600000e+01 157 -2.400000e+00 -1.600000e+00 5.434000e+02 5.977400e+02 0.000000e+00 0.000000e+00 4.940000e+02 158 -1.600000e+00 -8.000000e-01 1.708300e+03 1.879130e+03 0.000000e+00 0.000000e+00 1.553000e+03 159 -8.000000e-01 2.220446e-16 3.130600e+03 3.443660e+03 0.000000e+00 0.000000e+00 2.846000e+03 160 0.000000e+00 8.000000e-01 3.136100e+03 3.449710e+03 0.000000e+00 0.000000e+00 2.851000e+03 161 8.000000e-01 1.600000e+00 1.753400e+03 1.928740e+03 0.000000e+00 0.000000e+00 1.594000e+03 162 1.600000e+00 2.400000e+00 5.401000e+02 5.941100e+02 0.000000e+00 0.000000e+00 4.910000e+02 163 2.400000e+00 3.200000e+00 1.012000e+02 1.113200e+02 0.000000e+00 0.000000e+00 9.200000e+01 164 3.200000e+00 4.000000e+00 7.700000e+00 8.470000e+00 0.000000e+00 0.000000e+00 7.000000e+00 165 END YODA_HISTO1D_V2 166 167 `), 168 }, 169 { 170 name: "h1f", 171 want: []byte(`BEGIN YODA_HISTO1D_V2 /h1f 172 Path: /h1f 173 Title: h1f 174 Type: Histo1D 175 --- 176 # Mean: 2.812016e-02 177 # Area: 1.100600e+04 178 # ID ID sumw sumw2 sumwx sumwx2 numEntries 179 Total Total 1.100600e+04 1.211000e+04 3.094905e+02 7.128989e+04 1.000400e+04 180 Underflow Underflow 2.000000e+00 2.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 181 Overflow Overflow 4.000000e+00 8.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 182 # xlow xhigh sumw sumw2 sumwx sumwx2 numEntries 183 -4.000000e+00 -3.200000e+00 6.600000e+00 7.260000e+00 0.000000e+00 0.000000e+00 6.000000e+00 184 -3.200000e+00 -2.400000e+00 7.259995e+01 7.986000e+01 0.000000e+00 0.000000e+00 6.600000e+01 185 -2.400000e+00 -1.600000e+00 5.434013e+02 5.977400e+02 0.000000e+00 0.000000e+00 4.940000e+02 186 -1.600000e+00 -8.000000e-01 1.708276e+03 1.879130e+03 0.000000e+00 0.000000e+00 1.553000e+03 187 -8.000000e-01 2.220446e-16 3.130664e+03 3.443660e+03 0.000000e+00 0.000000e+00 2.846000e+03 188 0.000000e+00 8.000000e-01 3.136165e+03 3.449710e+03 0.000000e+00 0.000000e+00 2.851000e+03 189 8.000000e-01 1.600000e+00 1.753375e+03 1.928740e+03 0.000000e+00 0.000000e+00 1.594000e+03 190 1.600000e+00 2.400000e+00 5.401014e+02 5.941100e+02 0.000000e+00 0.000000e+00 4.910000e+02 191 2.400000e+00 3.200000e+00 1.011999e+02 1.113200e+02 0.000000e+00 0.000000e+00 9.200000e+01 192 3.200000e+00 4.000000e+00 7.700000e+00 8.470000e+00 0.000000e+00 0.000000e+00 7.000000e+00 193 END YODA_HISTO1D_V2 194 195 `), 196 }, 197 { 198 name: "h1d-var", 199 want: []byte(`BEGIN YODA_HISTO1D_V2 /h1d-var 200 Path: /h1d-var 201 Title: h1d-var 202 Type: Histo1D 203 --- 204 # Mean: 2.812016e-02 205 # Area: 1.100600e+04 206 # ID ID sumw sumw2 sumwx sumwx2 numEntries 207 Total Total 1.100600e+04 1.211000e+04 3.094905e+02 7.128989e+04 1.000400e+04 208 Underflow Underflow 2.000000e+00 2.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 209 Overflow Overflow 4.000000e+00 8.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 210 # xlow xhigh sumw sumw2 sumwx sumwx2 numEntries 211 -4.000000e+00 -3.200000e+00 6.600000e+00 7.260000e+00 0.000000e+00 0.000000e+00 6.000000e+00 212 -3.200000e+00 -2.400000e+00 7.259995e+01 7.986000e+01 0.000000e+00 0.000000e+00 6.600000e+01 213 -2.400000e+00 -1.600000e+00 5.434013e+02 5.977400e+02 0.000000e+00 0.000000e+00 4.940000e+02 214 -1.600000e+00 -8.000000e-01 1.708276e+03 1.879130e+03 0.000000e+00 0.000000e+00 1.553000e+03 215 -8.000000e-01 0.000000e+00 3.130664e+03 3.443660e+03 0.000000e+00 0.000000e+00 2.846000e+03 216 0.000000e+00 8.000000e-01 3.136165e+03 3.449710e+03 0.000000e+00 0.000000e+00 2.851000e+03 217 8.000000e-01 1.600000e+00 1.753375e+03 1.928740e+03 0.000000e+00 0.000000e+00 1.594000e+03 218 1.600000e+00 2.400000e+00 5.401014e+02 5.941100e+02 0.000000e+00 0.000000e+00 4.910000e+02 219 2.400000e+00 3.200000e+00 1.011999e+02 1.113200e+02 0.000000e+00 0.000000e+00 9.200000e+01 220 3.200000e+00 4.000000e+00 7.700000e+00 8.470000e+00 0.000000e+00 0.000000e+00 7.000000e+00 221 END YODA_HISTO1D_V2 222 223 `), 224 }, 225 { 226 name: "h1f-var", 227 want: []byte(`BEGIN YODA_HISTO1D_V2 /h1f-var 228 Path: /h1f-var 229 Title: h1f-var 230 Type: Histo1D 231 --- 232 # Mean: 2.812016e-02 233 # Area: 1.100600e+04 234 # ID ID sumw sumw2 sumwx sumwx2 numEntries 235 Total Total 1.100600e+04 1.211000e+04 3.094905e+02 7.128989e+04 1.000400e+04 236 Underflow Underflow 2.000000e+00 2.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 237 Overflow Overflow 4.000000e+00 8.000000e+00 0.000000e+00 0.000000e+00 2.000000e+00 238 # xlow xhigh sumw sumw2 sumwx sumwx2 numEntries 239 -4.000000e+00 -3.200000e+00 6.600000e+00 7.260000e+00 0.000000e+00 0.000000e+00 6.000000e+00 240 -3.200000e+00 -2.400000e+00 7.259995e+01 7.986000e+01 0.000000e+00 0.000000e+00 6.600000e+01 241 -2.400000e+00 -1.600000e+00 5.434013e+02 5.977400e+02 0.000000e+00 0.000000e+00 4.940000e+02 242 -1.600000e+00 -8.000000e-01 1.708276e+03 1.879130e+03 0.000000e+00 0.000000e+00 1.553000e+03 243 -8.000000e-01 0.000000e+00 3.130664e+03 3.443660e+03 0.000000e+00 0.000000e+00 2.846000e+03 244 0.000000e+00 8.000000e-01 3.136165e+03 3.449710e+03 0.000000e+00 0.000000e+00 2.851000e+03 245 8.000000e-01 1.600000e+00 1.753375e+03 1.928740e+03 0.000000e+00 0.000000e+00 1.594000e+03 246 1.600000e+00 2.400000e+00 5.401014e+02 5.941100e+02 0.000000e+00 0.000000e+00 4.910000e+02 247 2.400000e+00 3.200000e+00 1.011999e+02 1.113200e+02 0.000000e+00 0.000000e+00 9.200000e+01 248 3.200000e+00 4.000000e+00 7.700000e+00 8.470000e+00 0.000000e+00 0.000000e+00 7.000000e+00 249 END YODA_HISTO1D_V2 250 251 `), 252 }, 253 } { 254 t.Run(test.name, func(t *testing.T) { 255 obj, err := f.Get(test.name) 256 if err != nil { 257 t.Fatalf("error: %+v", err) 258 } 259 260 var ( 261 rhisto = obj.(rhist.H1) 262 h = rootcnv.H1D(rhisto) 263 buf = new(bytes.Buffer) 264 ) 265 266 err = yodacnv.Write(buf, h) 267 if err != nil { 268 t.Fatalf("YODA error: %+v", err) 269 } 270 271 if !reflect.DeepEqual(buf.Bytes(), test.want) { 272 fatalf := t.Fatalf 273 if runtime.GOOS == "darwin" { 274 fatalf = t.Logf 275 } 276 fatalf("invalid h1:\n%s", 277 cmp.Diff( 278 string(test.want), 279 buf.String(), 280 ), 281 ) 282 } 283 }) 284 } 285 } 286 287 func TestH2D(t *testing.T) { 288 f, err := groot.Open("testdata/gauss-h2.root") 289 if err != nil { 290 t.Fatal(err) 291 } 292 defer f.Close() 293 294 for _, test := range []struct { 295 name string 296 want []byte 297 }{ 298 { 299 name: "h2f", 300 want: []byte(`BEGIN YODA_HISTO2D_V2 /h2f 301 Path: /h2f 302 Title: h2f 303 Type: Histo2D 304 --- 305 # Mean: (-5.792200e-03, 8.942019e-01) 306 # Volume: 1.083600e+04 307 # ID ID sumw sumw2 sumwx sumwx2 sumwy sumwy2 sumwxy numEntries 308 Total Total 1.083600e+04 9.740400e+04 -6.276428e+01 5.583048e+04 9.689571e+03 4.495449e+04 -1.878975e+02 1.000800e+04 309 # 2D outflow persistency not currently supported until API is stable 310 # xlow xhigh ylow yhigh sumw sumw2 sumwx sumwx2 sumwy sumwy2 sumwxy numEntries 311 0.000000e+00 1.000000e+00 0.000000e+00 1.000000e+00 5.010000e+02 5.010000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 5.010000e+02 312 0.000000e+00 1.000000e+00 1.000000e+00 2.000000e+00 4.880000e+02 4.880000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 4.880000e+02 313 0.000000e+00 1.000000e+00 2.000000e+00 3.000000e+00 3.140000e+02 3.140000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 3.140000e+02 314 1.000000e+00 2.000000e+00 0.000000e+00 1.000000e+00 3.850000e+02 3.850000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 3.850000e+02 315 1.000000e+00 2.000000e+00 1.000000e+00 2.000000e+00 3.790000e+02 3.790000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 3.790000e+02 316 1.000000e+00 2.000000e+00 2.000000e+00 3.000000e+00 2.210000e+02 2.210000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 2.210000e+02 317 2.000000e+00 3.000000e+00 0.000000e+00 1.000000e+00 2.280000e+02 2.280000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 2.280000e+02 318 2.000000e+00 3.000000e+00 1.000000e+00 2.000000e+00 2.320000e+02 2.320000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 2.320000e+02 319 2.000000e+00 3.000000e+00 2.000000e+00 3.000000e+00 1.640000e+02 1.640000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 1.640000e+02 320 END YODA_HISTO2D_V2 321 322 `), 323 }, 324 { 325 name: "h2d", 326 want: []byte(`BEGIN YODA_HISTO2D_V2 /h2d 327 Path: /h2d 328 Title: h2d 329 Type: Histo2D 330 --- 331 # Mean: (-5.792200e-03, 8.942019e-01) 332 # Volume: 1.083600e+04 333 # ID ID sumw sumw2 sumwx sumwx2 sumwy sumwy2 sumwxy numEntries 334 Total Total 1.083600e+04 9.740400e+04 -6.276428e+01 5.583048e+04 9.689571e+03 4.495449e+04 -1.878975e+02 1.000800e+04 335 # 2D outflow persistency not currently supported until API is stable 336 # xlow xhigh ylow yhigh sumw sumw2 sumwx sumwx2 sumwy sumwy2 sumwxy numEntries 337 0.000000e+00 1.000000e+00 0.000000e+00 1.000000e+00 5.010000e+02 5.010000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 5.010000e+02 338 0.000000e+00 1.000000e+00 1.000000e+00 2.000000e+00 4.880000e+02 4.880000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 4.880000e+02 339 0.000000e+00 1.000000e+00 2.000000e+00 3.000000e+00 3.140000e+02 3.140000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 3.140000e+02 340 1.000000e+00 2.000000e+00 0.000000e+00 1.000000e+00 3.850000e+02 3.850000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 3.850000e+02 341 1.000000e+00 2.000000e+00 1.000000e+00 2.000000e+00 3.790000e+02 3.790000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 3.790000e+02 342 1.000000e+00 2.000000e+00 2.000000e+00 3.000000e+00 2.210000e+02 2.210000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 2.210000e+02 343 2.000000e+00 3.000000e+00 0.000000e+00 1.000000e+00 2.280000e+02 2.280000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 2.280000e+02 344 2.000000e+00 3.000000e+00 1.000000e+00 2.000000e+00 2.320000e+02 2.320000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 2.320000e+02 345 2.000000e+00 3.000000e+00 2.000000e+00 3.000000e+00 1.640000e+02 1.640000e+02 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 1.640000e+02 346 END YODA_HISTO2D_V2 347 348 `), 349 }, 350 } { 351 t.Run(test.name, func(t *testing.T) { 352 obj, err := f.Get(test.name) 353 if err != nil { 354 t.Fatalf("error: %+v", err) 355 } 356 var ( 357 rhisto = obj.(rhist.H2) 358 h = rootcnv.H2D(rhisto) 359 buf = new(bytes.Buffer) 360 ) 361 362 err = yodacnv.Write(buf, h) 363 if err != nil { 364 t.Fatalf("YODA error: %+v", err) 365 } 366 367 if !reflect.DeepEqual(buf.Bytes(), test.want) { 368 t.Fatalf("invalid h2d:\n%s", 369 cmp.Diff( 370 string(test.want), 371 buf.String(), 372 ), 373 ) 374 } 375 }) 376 } 377 } 378 379 func TestFromH1D(t *testing.T) { 380 const npoints = 10000 381 382 // Create a normal distribution. 383 dist := distuv.Normal{ 384 Mu: 0, 385 Sigma: 1, 386 Src: rand.New(rand.NewPCG(0, 0)), 387 } 388 389 // Draw some random values from the standard 390 // normal distribution. 391 h := hbook.NewH1D(20, -4, +4) 392 for range npoints { 393 v := dist.Rand() 394 h.Fill(v, 1) 395 } 396 h.Fill(-10, 1) // fill underflow 397 h.Fill(-20, 2) 398 h.Fill(+10, 1) // fill overflow 399 h.Fill(+10, 2) 400 h.Annotation()["name"] = "my-name" 401 h.Annotation()["title"] = "my-title" 402 403 for _, tc := range []struct { 404 name string 405 h1 rhist.H1 406 sumw float64 407 sumw2 float64 408 sumwx float64 409 sumwx2 float64 410 }{ 411 { 412 name: "TH1D", 413 h1: rootcnv.FromH1D(h), 414 sumw: h.SumW(), 415 sumw2: h.SumW2(), 416 sumwx: h.SumWX(), 417 sumwx2: h.SumWX2(), 418 }, 419 } { 420 t.Run(tc.name, func(t *testing.T) { 421 if got, want := tc.h1.SumW(), h.SumW(); got != want { 422 t.Fatalf("sumw: got=%v, want=%v", got, want) 423 } 424 if got, want := tc.h1.SumW2(), h.SumW2(); got != want { 425 t.Fatalf("sumw2: got=%v, want=%v", got, want) 426 } 427 if got, want := tc.h1.SumWX(), h.SumWX(); got != want { 428 t.Fatalf("sumwx: got=%v, want=%v", got, want) 429 } 430 if got, want := tc.h1.SumWX2(), h.SumWX2(); got != want { 431 t.Fatalf("sumwx2: got=%v, want=%v", got, want) 432 } 433 434 rraw, err := tc.h1.(yodacnv.Marshaler).MarshalYODA() 435 if err != nil { 436 t.Fatal(err) 437 } 438 439 hh := rootcnv.H1D(tc.h1) 440 441 hraw, err := hh.MarshalYODA() 442 if err != nil { 443 t.Fatal(err) 444 } 445 446 var hr = rtypes.Factory.Get(tc.name)().Interface().(rhist.H1) 447 if err := hr.(yodacnv.Unmarshaler).UnmarshalYODA(hraw); err != nil { 448 t.Fatal(err) 449 } 450 451 rgot, err := hr.(yodacnv.Marshaler).MarshalYODA() 452 if err != nil { 453 t.Fatal(err) 454 } 455 456 if !bytes.Equal(rgot, rraw) { 457 t.Fatalf("round trip error:\nraw:\n%s\ngot:\n%s\n", rraw, rgot) 458 } 459 }) 460 } 461 } 462 463 func TestFromH2D(t *testing.T) { 464 const npoints = 10000 465 466 // Create a normal distribution. 467 dist := distuv.Normal{ 468 Mu: 0, 469 Sigma: 1, 470 Src: rand.New(rand.NewPCG(0, 0)), 471 } 472 473 // Draw some random values from the standard 474 // normal distribution. 475 h := hbook.NewH2D(5, -4, +4, 6, -4, +4) 476 for range npoints { 477 x := dist.Rand() 478 y := dist.Rand() 479 h.Fill(x, y, 1) 480 } 481 h.Fill(+0, +5, 1) // N 482 h.Fill(-5, +5, 2) // N-W 483 h.Fill(-5, +0, 3) // W 484 h.Fill(-5, -5, 4) // S-W 485 h.Fill(+0, -5, 5) // S 486 h.Fill(+5, -5, 6) // S-E 487 h.Fill(+5, +0, 7) // E 488 h.Fill(+5, +5, 8) // N-E 489 490 h.Annotation()["name"] = "my-name" 491 h.Annotation()["title"] = "my-title" 492 493 for _, tc := range []struct { 494 name string 495 h2 rhist.H2 496 sumw float64 497 sumw2 float64 498 sumwx float64 499 sumwx2 float64 500 }{ 501 { 502 name: "TH2D", 503 h2: rootcnv.FromH2D(h), 504 sumw: h.SumW(), 505 sumw2: h.SumW2(), 506 sumwx: h.SumWX(), 507 sumwx2: h.SumWX2(), 508 }, 509 } { 510 t.Run(tc.name, func(t *testing.T) { 511 if got, want := tc.h2.SumW(), h.SumW(); got != want { 512 t.Fatalf("sumw: got=%v, want=%v", got, want) 513 } 514 if got, want := tc.h2.SumW2(), h.SumW2(); got != want { 515 t.Fatalf("sumw2: got=%v, want=%v", got, want) 516 } 517 if got, want := tc.h2.SumWX(), h.SumWX(); got != want { 518 t.Fatalf("sumwx: got=%v, want=%v", got, want) 519 } 520 if got, want := tc.h2.SumWX2(), h.SumWX2(); got != want { 521 t.Fatalf("sumwx2: got=%v, want=%v", got, want) 522 } 523 524 rraw, err := tc.h2.(yodacnv.Marshaler).MarshalYODA() 525 if err != nil { 526 t.Fatal(err) 527 } 528 529 hh := rootcnv.H2D(tc.h2) 530 531 hraw, err := hh.MarshalYODA() 532 if err != nil { 533 t.Fatal(err) 534 } 535 536 var hr = rtypes.Factory.Get(tc.name)().Interface().(rhist.H2) 537 if err := hr.(yodacnv.Unmarshaler).UnmarshalYODA(hraw); err != nil { 538 t.Fatal(err) 539 } 540 541 rgot, err := hr.(yodacnv.Marshaler).MarshalYODA() 542 if err != nil { 543 t.Fatal(err) 544 } 545 546 // rounding errors... // FIXME(sbinet) 547 rraw = bytes.Replace(rraw, 548 []byte("# Mean: (1.990041e-02, 2.039840e-04)"), 549 []byte("# Mean: (1.990041e-02, 2.039841e-04)"), 550 -1, 551 ) 552 if !bytes.Equal(rgot, rraw) { 553 t.Fatalf("round trip error:\n%s\n", 554 cmp.Diff( 555 string(rraw), 556 string(rgot), 557 ), 558 ) 559 } 560 }) 561 } 562 } 563 564 func TestFromS2D(t *testing.T) { 565 hg := hbook.NewS2D( 566 hbook.Point2D{X: 1, Y: 1, ErrX: hbook.Range{Min: 1, Max: 2}, ErrY: hbook.Range{Min: 3, Max: 4}}, 567 hbook.Point2D{X: 2, Y: 1.5, ErrX: hbook.Range{Min: 1, Max: 2}, ErrY: hbook.Range{Min: 3, Max: 4}}, 568 hbook.Point2D{X: -1, Y: +2, ErrX: hbook.Range{Min: 1, Max: 2}, ErrY: hbook.Range{Min: 3, Max: 4}}, 569 ) 570 571 rg := rootcnv.FromS2D(hg) 572 573 hr := rootcnv.S2D(rg) 574 575 want, err := hg.MarshalYODA() 576 if err != nil { 577 t.Fatal(err) 578 } 579 580 got, err := hr.MarshalYODA() 581 if err != nil { 582 t.Fatal(err) 583 } 584 585 if !bytes.Equal(got, want) { 586 t.Fatalf("invalid s2d:\n%s", 587 cmp.Diff( 588 string(want), 589 string(got), 590 ), 591 ) 592 } 593 }