go-hep.org/x/hep@v0.40.0/groot/rnpy/column.go (about) 1 // Copyright ©2022 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 rnpy 6 7 import ( 8 "fmt" 9 "reflect" 10 11 "codeberg.org/sbinet/npyio/npy" 12 "go-hep.org/x/hep/groot/root" 13 "go-hep.org/x/hep/groot/rtree" 14 ) 15 16 var ( 17 _ npy.Descr = (*root.Float16)(nil) 18 _ npy.Marshaler = (*root.Float16)(nil) 19 _ npy.Unmarshaler = (*root.Float16)(nil) 20 21 _ npy.Descr = (*root.Double32)(nil) 22 _ npy.Marshaler = (*root.Double32)(nil) 23 _ npy.Unmarshaler = (*root.Double32)(nil) 24 ) 25 26 // NewColumns returns all the ReadVars of the provided Tree as 27 // a slice of Columns. 28 // 29 // ReadVars that can not be represented as NumPy arrays are silently discarded. 30 func NewColumns(tree rtree.Tree) []Column { 31 var ( 32 rvars = rtree.NewReadVars(tree) 33 cols []Column 34 ) 35 36 for _, rvar := range rvars { 37 rv := reflect.ValueOf(rvar.Value).Elem() 38 switch rv.Kind() { 39 case reflect.Chan, reflect.Interface, 40 reflect.Struct, reflect.Slice, reflect.Map, 41 reflect.Pointer, reflect.UnsafePointer: 42 continue 43 } 44 cols = append(cols, Column{ 45 tree: tree, 46 rvar: rvar, 47 etyp: reflect.TypeOf(rvar.Value).Elem(), 48 }) 49 } 50 51 return cols 52 } 53 54 // Column provides a NumPy representation of a Branch or Leaf. 55 type Column struct { 56 tree rtree.Tree 57 rvar rtree.ReadVar 58 etyp reflect.Type 59 } 60 61 // NewColumn returns the column with the provided name and tree. 62 // 63 // NewColumn returns an error if no branch or leaf could be found. 64 // NewColumn returns an error if the branch or leaf is of an unsupported type. 65 func NewColumn(tree rtree.Tree, rvar rtree.ReadVar) (Column, error) { 66 var ( 67 rvars = rtree.NewReadVars(tree) 68 idx = -1 69 col Column 70 ) 71 72 for i := range rvars { 73 if rvars[i].Name == rvar.Name && (rvars[i].Leaf == rvar.Leaf || rvar.Leaf == "") { 74 idx = i 75 break 76 } 77 } 78 79 if idx < 0 { 80 name := rvar.Name 81 if rvar.Leaf != "" { 82 name += "." + rvar.Leaf 83 } 84 return col, fmt.Errorf("rnpy: no rvar named %q", name) 85 } 86 rvar = rvars[idx] 87 88 rv := reflect.ValueOf(rvar.Value).Elem() 89 switch rv.Kind() { 90 case reflect.Chan, reflect.Interface, 91 reflect.Struct, reflect.Slice, reflect.Map, 92 reflect.Pointer, reflect.UnsafePointer: 93 return col, fmt.Errorf("rnpy: invalid branch or leaf type %T", rv.Interface()) 94 } 95 96 col = Column{ 97 tree: tree, 98 rvar: rvar, 99 etyp: reflect.TypeOf(rvar.Value).Elem(), 100 } 101 return col, nil 102 } 103 104 // Name returns the branch name this Column is bound to. 105 func (col Column) Name() string { 106 return col.rvar.Name 107 } 108 109 // Slice reads the whole data slice from the underlying ROOT Tree 110 // into memory. 111 func (col Column) Slice() (sli any, err error) { 112 r, err := rtree.NewReader(col.tree, []rtree.ReadVar{col.rvar}) 113 if err != nil { 114 return nil, fmt.Errorf( 115 "rnpy: could not create ROOT reader for %q: %w", 116 col.rvar.Name, err, 117 ) 118 } 119 defer r.Close() 120 121 var ( 122 n = col.tree.Entries() 123 rtyp = reflect.SliceOf(col.etyp) 124 data = reflect.ValueOf(col.rvar.Value).Elem() 125 slice = reflect.MakeSlice(rtyp, int(n), int(n)) 126 i int 127 ) 128 129 err = r.Read(func(ctx rtree.RCtx) error { 130 slice.Index(i).Set(data) 131 i++ 132 return nil 133 }) 134 if err != nil { 135 return nil, fmt.Errorf( 136 "rnpy: could not read ROOT data for %q: %w", 137 col.rvar.Name, err, 138 ) 139 } 140 141 return slice.Interface(), nil 142 }