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  }