go-hep.org/x/hep@v0.38.1/hbook/ops_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 hbook 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "testing" 12 13 "github.com/google/go-cmp/cmp" 14 ) 15 16 func ExampleDivideH1D() { 17 18 h1 := NewH1D(5, 0, 5) 19 h1.Fill(0, 1) 20 h1.Fill(1, 2) 21 h1.Fill(2, 3) 22 h1.Fill(3, 3) 23 h1.Fill(4, 4) 24 25 h2 := NewH1D(5, 0, 5) 26 h2.Fill(0, 11) 27 h2.Fill(1, 22) 28 h2.Fill(2, 0) 29 h2.Fill(3, 33) 30 h2.Fill(4, 44) 31 32 s0, err := DivideH1D(h1, h2) 33 if err != nil { 34 panic(err) 35 } 36 s1, err := DivideH1D(h1, h2, DivIgnoreNaNs()) 37 if err != nil { 38 panic(err) 39 } 40 s2, err := DivideH1D(h1, h2, DivReplaceNaNs(1.0)) 41 if err != nil { 42 panic(err) 43 } 44 45 fmt.Println("Default:") 46 for i, pt := range s0.Points() { 47 fmt.Printf("Point %v: %.2f + %.2f - %.2f\n", i, pt.Y, pt.ErrY.Min, pt.ErrY.Min) 48 } 49 50 fmt.Println("\nDivIgnoreNaNs:") 51 for i, pt := range s1.Points() { 52 fmt.Printf("Point %v: %.2f + %.2f - %.2f\n", i, pt.Y, pt.ErrY.Min, pt.ErrY.Min) 53 } 54 55 fmt.Println("\nDivReplaceNaNs with v=1.0:") 56 for i, pt := range s2.Points() { 57 fmt.Printf("Point %v: %.2f + %.2f - %.2f\n", i, pt.Y, pt.ErrY.Min, pt.ErrY.Min) 58 } 59 60 // Output: 61 // Default: 62 // Point 0: 0.09 + 0.13 - 0.13 63 // Point 1: 0.09 + 0.13 - 0.13 64 // Point 2: NaN + 0.00 - 0.00 65 // Point 3: 0.09 + 0.13 - 0.13 66 // Point 4: 0.09 + 0.13 - 0.13 67 // 68 // DivIgnoreNaNs: 69 // Point 0: 0.09 + 0.13 - 0.13 70 // Point 1: 0.09 + 0.13 - 0.13 71 // Point 2: 0.09 + 0.13 - 0.13 72 // Point 3: 0.09 + 0.13 - 0.13 73 // 74 // DivReplaceNaNs with v=1.0: 75 // Point 0: 0.09 + 0.13 - 0.13 76 // Point 1: 0.09 + 0.13 - 0.13 77 // Point 2: 1.00 + 0.00 - 0.00 78 // Point 3: 0.09 + 0.13 - 0.13 79 // Point 4: 0.09 + 0.13 - 0.13 80 } 81 82 func TestDivideH1D(t *testing.T) { 83 h1 := NewH1D(5, 0, 5) 84 h2 := NewH1D(5, 0, 5) 85 for i := range 5 { 86 h1.Fill(float64(i), float64(i+1)) 87 h2.Fill(float64(i), float64(i+3)) 88 } 89 s, err := DivideH1D(h1, h2) 90 if err != nil { 91 t.Fatal(err) 92 } 93 94 chk, err := s.MarshalYODA() 95 if err != nil { 96 t.Fatal(err) 97 } 98 99 want := []byte(`BEGIN YODA_SCATTER2D_V2 / 100 Path: / 101 Title: "" 102 Type: Scatter2D 103 --- 104 # xval xerr- xerr+ yval yerr- yerr+ 105 5.000000e-01 5.000000e-01 5.000000e-01 3.333333e-01 4.714045e-01 4.714045e-01 106 1.500000e+00 5.000000e-01 5.000000e-01 5.000000e-01 7.071068e-01 7.071068e-01 107 2.500000e+00 5.000000e-01 5.000000e-01 6.000000e-01 8.485281e-01 8.485281e-01 108 3.500000e+00 5.000000e-01 5.000000e-01 6.666667e-01 9.428090e-01 9.428090e-01 109 4.500000e+00 5.000000e-01 5.000000e-01 7.142857e-01 1.010153e+00 1.010153e+00 110 END YODA_SCATTER2D_V2 111 112 `) 113 114 if !reflect.DeepEqual(chk, want) { 115 t.Fatalf("divide(num,den) differ:\n%s\n", 116 cmp.Diff( 117 string(chk), 118 string(want), 119 ), 120 ) 121 } 122 } 123 124 func TestAddH1DPanics(t *testing.T) { 125 for _, tc := range []struct { 126 h1, h2 *H1D 127 panics error 128 }{ 129 { 130 h1: NewH1D(10, 0, 10), 131 h2: NewH1D(5, 0, 10), 132 panics: fmt.Errorf("hbook: h1 and h2 have different number of bins"), 133 }, 134 { 135 h1: NewH1D(10, 0, 10), 136 h2: NewH1D(10, 1, 10), 137 panics: fmt.Errorf("hbook: h1 and h2 have different range"), 138 }, 139 { 140 h1: NewH1D(10, 0, 10), 141 h2: NewH1D(10, 0, 11), 142 panics: fmt.Errorf("hbook: h1 and h2 have different range"), 143 }, 144 { 145 h1: NewH1D(10, 0, 10), 146 h2: NewH1D(10, 1, 11), 147 panics: fmt.Errorf("hbook: h1 and h2 have different range"), 148 }, 149 } { 150 t.Run("", func(t *testing.T) { 151 if tc.panics != nil { 152 defer func() { 153 err := recover() 154 if err == nil { 155 t.Fatalf("expected a panic") 156 } 157 if got, want := err.(error).Error(), tc.panics.Error(); got != want { 158 t.Fatalf("invalid panic message.\ngot= %v\nwant=%v", got, want) 159 } 160 }() 161 } 162 _ = AddH1D(tc.h1, tc.h2) 163 }) 164 } 165 } 166 167 func TestAddH1D(t *testing.T) { 168 169 h1 := NewH1D(6, 0, 6) 170 h1.Fill(-0.5, 1) 171 h1.Fill(0, 1.5) 172 h1.Fill(0.5, 1) 173 h1.Fill(1.2, 1) 174 h1.Fill(2.1, 2) 175 h1.Fill(4.2, 1) 176 h1.Fill(5.9, 1) 177 h1.Fill(6, 0.5) 178 179 h2 := NewH1D(6, 0, 6) 180 h2.Fill(-0.5, 0.7) 181 h2.Fill(0.2, 1) 182 h2.Fill(0.7, 1.2) 183 h2.Fill(1.5, 0.8) 184 h2.Fill(2.2, 0.7) 185 h2.Fill(4.3, 1.3) 186 h2.Fill(5.2, 2) 187 h2.Fill(6.8, 1) 188 189 h3 := AddH1D(h1, h2) 190 191 got, err := h3.MarshalYODA() 192 if err != nil { 193 t.Fatalf("could not marshal to yoda: %+v", err) 194 } 195 196 want := []byte(`BEGIN YODA_HISTO1D_V2 / 197 Path: / 198 Title: "" 199 Type: Histo1D 200 --- 201 # Mean: 2.526554e+00 202 # Area: 1.770000e+01 203 # ID ID sumw sumw2 sumwx sumwx2 numEntries 204 Total Total 1.770000e+01 2.225000e+01 4.472000e+01 2.115580e+02 1.600000e+01 205 Underflow Underflow 1.700000e+00 1.490000e+00 -8.500000e-01 4.250000e-01 2.000000e+00 206 Overflow Overflow 1.500000e+00 1.250000e+00 9.800000e+00 6.424000e+01 2.000000e+00 207 # xlow xhigh sumw sumw2 sumwx sumwx2 numEntries 208 0.000000e+00 1.000000e+00 4.700000e+00 5.690000e+00 1.540000e+00 8.780000e-01 4.000000e+00 209 1.000000e+00 2.000000e+00 1.800000e+00 1.640000e+00 2.400000e+00 3.240000e+00 2.000000e+00 210 2.000000e+00 3.000000e+00 2.700000e+00 4.490000e+00 5.740000e+00 1.220800e+01 2.000000e+00 211 3.000000e+00 4.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 212 4.000000e+00 5.000000e+00 2.300000e+00 2.690000e+00 9.790000e+00 4.167700e+01 2.000000e+00 213 5.000000e+00 6.000000e+00 3.000000e+00 5.000000e+00 1.630000e+01 8.889000e+01 2.000000e+00 214 END YODA_HISTO1D_V2 215 216 `) 217 218 if !bytes.Equal(got, want) { 219 t.Fatalf("add differ:\n%s\n", 220 cmp.Diff( 221 string(got), 222 string(want), 223 ), 224 ) 225 } 226 } 227 228 func TestSubH1DPanics(t *testing.T) { 229 for _, tc := range []struct { 230 h1, h2 *H1D 231 panics error 232 }{ 233 { 234 h1: NewH1D(10, 0, 10), 235 h2: NewH1D(5, 0, 10), 236 panics: fmt.Errorf("hbook: h1 and h2 have different number of bins"), 237 }, 238 { 239 h1: NewH1D(10, 0, 10), 240 h2: NewH1D(10, 1, 10), 241 panics: fmt.Errorf("hbook: h1 and h2 have different range"), 242 }, 243 { 244 h1: NewH1D(10, 0, 10), 245 h2: NewH1D(10, 0, 11), 246 panics: fmt.Errorf("hbook: h1 and h2 have different range"), 247 }, 248 { 249 h1: NewH1D(10, 0, 10), 250 h2: NewH1D(10, 1, 11), 251 panics: fmt.Errorf("hbook: h1 and h2 have different range"), 252 }, 253 } { 254 t.Run("", func(t *testing.T) { 255 if tc.panics != nil { 256 defer func() { 257 err := recover() 258 if err == nil { 259 t.Fatalf("expected a panic") 260 } 261 if got, want := err.(error).Error(), tc.panics.Error(); got != want { 262 t.Fatalf("invalid panic message.\ngot= %v\nwant=%v", got, want) 263 } 264 }() 265 } 266 _ = SubH1D(tc.h1, tc.h2) 267 }) 268 } 269 } 270 271 func TestSubH1D(t *testing.T) { 272 h1 := NewH1D(6, 0, 6) 273 h1.Fill(-0.5, 1) 274 h1.Fill(0, 1.5) 275 h1.Fill(0.5, 1) 276 h1.Fill(1.2, 1) 277 h1.Fill(2.1, 2) 278 h1.Fill(4.2, 1) 279 h1.Fill(5.9, 1) 280 h1.Fill(6, 0.5) 281 282 h2 := NewH1D(6, 0, 6) 283 h2.Fill(-0.5, 0.7) 284 h2.Fill(0.2, 1) 285 h2.Fill(0.7, 1.2) 286 h2.Fill(1.5, 0.8) 287 h2.Fill(2.2, 0.7) 288 h2.Fill(4.3, 1.3) 289 h2.Fill(5.2, 2) 290 h2.Fill(6.8, 1) 291 292 h3 := SubH1D(h1, h2) 293 294 got, err := h3.MarshalYODA() 295 if err != nil { 296 t.Fatalf("could not marshal to yoda: %+v", err) 297 } 298 299 want := []byte(`BEGIN YODA_HISTO1D_V2 / 300 Path: / 301 Title: "" 302 Type: Histo1D 303 --- 304 # Mean: -2.573333e+01 305 # Area: 3.000000e-01 306 # ID ID sumw sumw2 sumwx sumwx2 numEntries 307 Total Total 3.000000e-01 2.225000e+01 -7.720000e+00 -4.913800e+01 1.600000e+01 308 Underflow Underflow 3.000000e-01 1.490000e+00 -1.500000e-01 7.500000e-02 2.000000e+00 309 Overflow Overflow -5.000000e-01 1.250000e+00 -3.800000e+00 -2.824000e+01 2.000000e+00 310 # xlow xhigh sumw sumw2 sumwx sumwx2 numEntries 311 0.000000e+00 1.000000e+00 3.000000e-01 5.690000e+00 -5.400000e-01 -3.780000e-01 4.000000e+00 312 1.000000e+00 2.000000e+00 2.000000e-01 1.640000e+00 -2.220446e-16 -3.600000e-01 2.000000e+00 313 2.000000e+00 3.000000e+00 1.300000e+00 4.490000e+00 2.660000e+00 5.432000e+00 2.000000e+00 314 3.000000e+00 4.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 0.000000e+00 315 4.000000e+00 5.000000e+00 -3.000000e-01 2.690000e+00 -1.390000e+00 -6.397000e+00 2.000000e+00 316 5.000000e+00 6.000000e+00 -1.000000e+00 5.000000e+00 -4.500000e+00 -1.927000e+01 2.000000e+00 317 END YODA_HISTO1D_V2 318 319 `) 320 321 if !bytes.Equal(got, want) { 322 t.Fatalf("sub differ:\n%s\n", 323 cmp.Diff( 324 string(got), 325 string(want), 326 ), 327 ) 328 } 329 }