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