go-hep.org/x/hep@v0.38.1/cmd/npy2root/main_test.go (about) 1 // Copyright ©2019 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 main 6 7 import ( 8 "fmt" 9 "math" 10 "os" 11 "path/filepath" 12 "reflect" 13 "testing" 14 15 "codeberg.org/sbinet/npyio/npy" 16 "go-hep.org/x/hep/groot" 17 "go-hep.org/x/hep/groot/rtree" 18 ) 19 20 func TestConvert(t *testing.T) { 21 for _, tc := range []struct { 22 name string 23 want any 24 }{ 25 // 4 scalars 26 { 27 name: "bool_4x1", 28 want: [4]bool{true, true, false, true}, 29 }, 30 { 31 name: "uint8_4x1", 32 want: [4]uint8{0, 1, 2, 3}, 33 }, 34 { 35 name: "uint16_4x1", 36 want: [4]uint16{0, 1, 2, 3}, 37 }, 38 { 39 name: "uint32_4x1", 40 want: [4]uint32{0, 1, 2, 3}, 41 }, 42 { 43 name: "uint64_4x1", 44 want: [4]uint64{0, 1, 2, 3}, 45 }, 46 { 47 name: "int8_4x1", 48 want: [4]int8{0, 1, 2, 3}, 49 }, 50 { 51 name: "int16_4x1", 52 want: [4]int16{0, 1, 2, 3}, 53 }, 54 { 55 name: "int32_4x1", 56 want: [4]int32{0, 1, 2, 3}, 57 }, 58 { 59 name: "int64_4x1", 60 want: [4]int64{0, 1, 2, 3}, 61 }, 62 { 63 name: "float32_4x1", 64 want: [4]float32{0, 1, 2, 3}, 65 }, 66 { 67 name: "float64_4x1", 68 want: [4]float64{0, 1, 2, 3}, 69 }, 70 { 71 name: "nans_4x1", 72 want: [4]float64{math.Inf(-1), math.Inf(+1), math.NaN(), 0}, 73 }, 74 // 4 1d-arrays 75 { 76 name: "bool_4x2", 77 want: [4][2]bool{{true, false}, {true, false}, {false, true}, {true, false}}, 78 }, 79 { 80 name: "uint8_4x2", 81 want: [4][2]uint8{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 82 }, 83 { 84 name: "uint16_4x2", 85 want: [4][2]uint16{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 86 }, 87 { 88 name: "uint32_4x2", 89 want: [4][2]uint32{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 90 }, 91 { 92 name: "uint64_4x2", 93 want: [4][2]uint64{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 94 }, 95 { 96 name: "int8_4x2", 97 want: [4][2]int8{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 98 }, 99 { 100 name: "int16_4x2", 101 want: [4][2]int16{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 102 }, 103 { 104 name: "int32_4x2", 105 want: [4][2]int32{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 106 }, 107 { 108 name: "int64_4x2", 109 want: [4][2]int64{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 110 }, 111 { 112 name: "float32_4x2", 113 want: [4][2]float32{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 114 }, 115 { 116 name: "float64_4x2", 117 want: [4][2]float64{{0, 0}, {1, 1}, {2, 2}, {3, 3}}, 118 }, 119 // 4 2d-arrays 120 { 121 name: "bool_4x3x2", 122 want: [4][3][2]bool{ 123 {{true, false}, {true, false}, {true, false}}, 124 {{false, true}, {false, true}, {false, true}}, 125 {{true, false}, {true, false}, {true, false}}, 126 {{false, true}, {false, true}, {false, true}}, 127 }, 128 }, 129 { 130 name: "uint8_4x3x2", 131 want: [4][3][2]uint8{ 132 {{10, 11}, {12, 13}, {14, 15}}, 133 {{16, 17}, {18, 19}, {20, 21}}, 134 {{22, 23}, {24, 25}, {26, 27}}, 135 {{28, 29}, {30, 31}, {32, 33}}, 136 }, 137 }, 138 { 139 name: "uint16_4x3x2", 140 want: [4][3][2]uint16{ 141 {{10, 11}, {12, 13}, {14, 15}}, 142 {{16, 17}, {18, 19}, {20, 21}}, 143 {{22, 23}, {24, 25}, {26, 27}}, 144 {{28, 29}, {30, 31}, {32, 33}}, 145 }, 146 }, 147 { 148 name: "uint32_4x3x2", 149 want: [4][3][2]uint32{ 150 {{10, 11}, {12, 13}, {14, 15}}, 151 {{16, 17}, {18, 19}, {20, 21}}, 152 {{22, 23}, {24, 25}, {26, 27}}, 153 {{28, 29}, {30, 31}, {32, 33}}, 154 }, 155 }, 156 { 157 name: "uint64_4x3x2", 158 want: [4][3][2]uint64{ 159 {{10, 11}, {12, 13}, {14, 15}}, 160 {{16, 17}, {18, 19}, {20, 21}}, 161 {{22, 23}, {24, 25}, {26, 27}}, 162 {{28, 29}, {30, 31}, {32, 33}}, 163 }, 164 }, 165 { 166 name: "int8_4x3x2", 167 want: [4][3][2]int8{ 168 {{10, 11}, {12, 13}, {14, 15}}, 169 {{16, 17}, {18, 19}, {20, 21}}, 170 {{22, 23}, {24, 25}, {26, 27}}, 171 {{28, 29}, {30, 31}, {32, 33}}, 172 }, 173 }, 174 { 175 name: "int16_4x3x2", 176 want: [4][3][2]int16{ 177 {{10, 11}, {12, 13}, {14, 15}}, 178 {{16, 17}, {18, 19}, {20, 21}}, 179 {{22, 23}, {24, 25}, {26, 27}}, 180 {{28, 29}, {30, 31}, {32, 33}}, 181 }, 182 }, 183 { 184 name: "int32_4x3x2", 185 want: [4][3][2]int32{ 186 {{10, 11}, {12, 13}, {14, 15}}, 187 {{16, 17}, {18, 19}, {20, 21}}, 188 {{22, 23}, {24, 25}, {26, 27}}, 189 {{28, 29}, {30, 31}, {32, 33}}, 190 }, 191 }, 192 { 193 name: "int64_4x3x2", 194 want: [4][3][2]int64{ 195 {{10, 11}, {12, 13}, {14, 15}}, 196 {{16, 17}, {18, 19}, {20, 21}}, 197 {{22, 23}, {24, 25}, {26, 27}}, 198 {{28, 29}, {30, 31}, {32, 33}}, 199 }, 200 }, 201 { 202 name: "float32_4x3x2", 203 want: [4][3][2]float32{ 204 {{10, 11}, {12, 13}, {14, 15}}, 205 {{16, 17}, {18, 19}, {20, 21}}, 206 {{22, 23}, {24, 25}, {26, 27}}, 207 {{28, 29}, {30, 31}, {32, 33}}, 208 }, 209 }, 210 { 211 name: "float64_4x3x2", 212 want: [4][3][2]float64{ 213 {{10, 11}, {12, 13}, {14, 15}}, 214 {{16, 17}, {18, 19}, {20, 21}}, 215 {{22, 23}, {24, 25}, {26, 27}}, 216 {{28, 29}, {30, 31}, {32, 33}}, 217 }, 218 }, 219 // 3d-array 220 { 221 name: "float64_4x3x2x1", 222 want: [4][3][2][1]float64{ 223 {{{10}, {11}}, {{12}, {13}}, {{14}, {15}}}, 224 {{{16}, {17}}, {{18}, {19}}, {{20}, {21}}}, 225 {{{22}, {23}}, {{24}, {25}}, {{26}, {27}}}, 226 {{{28}, {29}}, {{30}, {31}}, {{32}, {33}}}, 227 }, 228 }, 229 // 4d-array 230 { 231 name: "float64_4x3x2x1x2", 232 want: [4][3][2][1][2]float64{ 233 {{{{10, 1}}, {{11, 2}}}, {{{12, 3}}, {{13, 4}}}, {{{14, 5}}, {{15, 6}}}}, 234 {{{{16, 1}}, {{17, 2}}}, {{{18, 3}}, {{19, 4}}}, {{{20, 5}}, {{21, 6}}}}, 235 {{{{22, 1}}, {{23, 2}}}, {{{24, 3}}, {{25, 4}}}, {{{26, 5}}, {{27, 6}}}}, 236 {{{{28, 1}}, {{29, 2}}}, {{{30, 3}}, {{31, 4}}}, {{{32, 5}}, {{33, 6}}}}, 237 }, 238 }, 239 } { 240 t.Run(tc.name, func(t *testing.T) { 241 tmp, err := os.MkdirTemp("", "npy2root-") 242 if err != nil { 243 t.Fatalf("%+v", err) 244 } 245 defer os.RemoveAll(tmp) 246 247 fname := filepath.Join(tmp, "data.npy") 248 src, err := os.Create(fname) 249 if err != nil { 250 t.Fatalf("could not create NumPy data file: %+v", err) 251 } 252 defer src.Close() 253 254 err = npy.Write(src, tc.want) 255 if err != nil { 256 t.Fatalf("could not save NumPy data file: %+v", err) 257 } 258 259 err = src.Close() 260 if err != nil { 261 t.Fatalf("could not close NumPy data file: %+v", err) 262 } 263 264 oname := filepath.Join(tmp, "out.root") 265 err = process(oname, "tree", fname) 266 if err != nil { 267 t.Fatalf("could not create ROOT data file: %+v", err) 268 } 269 270 f, err := groot.Open(oname) 271 if err != nil { 272 t.Fatalf("could not open ROOT file: %+v", err) 273 } 274 defer f.Close() 275 276 obj, err := f.Get("tree") 277 if err != nil { 278 t.Fatalf("could not get ROOT tree: %+v", err) 279 } 280 281 tree := obj.(rtree.Tree) 282 rvars := rtree.NewReadVars(tree) 283 r, err := rtree.NewReader(tree, rvars) 284 if err != nil { 285 t.Fatalf("could not create tree reader: %+v", err) 286 } 287 defer r.Close() 288 289 want := reflect.ValueOf(tc.want) 290 n := 0 291 err = r.Read(func(ctx rtree.RCtx) error { 292 i := int(ctx.Entry) 293 want := want.Index(i).Interface() 294 got := reflect.ValueOf(rvars[0].Value).Elem().Interface() 295 ok := false 296 switch want := want.(type) { 297 case float64: 298 got := got.(float64) 299 switch { 300 case math.IsNaN(want): 301 ok = math.IsNaN(got) 302 case math.IsInf(want, +1): 303 ok = math.IsInf(got, +1) 304 case math.IsInf(want, -1): 305 ok = math.IsInf(got, -1) 306 default: 307 ok = got == want 308 } 309 default: 310 ok = reflect.DeepEqual(got, want) 311 } 312 313 if !ok { 314 return fmt.Errorf("invalid value for entry %d:\ngot= %v\nwant=%v", ctx.Entry, got, want) 315 } 316 n++ 317 return nil 318 }) 319 if err != nil { 320 t.Fatalf("could not read tree: %+v", err) 321 } 322 323 if got, want := n, want.Len(); got != want { 324 t.Fatalf("invalid number of events: got=%d, want=%d", got, want) 325 } 326 }) 327 } 328 }