go-hep.org/x/hep@v0.38.1/groot/rtree/chain.go (about)

     1  // Copyright ©2018 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 rtree
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"go-hep.org/x/hep/groot/riofs"
    11  	"go-hep.org/x/hep/groot/root"
    12  )
    13  
    14  type chain struct {
    15  	trees []Tree
    16  	offs  []int64 // number of entries before this tree
    17  	tots  []int64 // total number of entries up to this tree
    18  
    19  	cur  int   // index of current tree
    20  	tree Tree  // current tree
    21  	off  int64 // current offset
    22  	tot  int64 // current number of entries
    23  }
    24  
    25  // Chain returns a Tree that is the concatenation of all the input Trees.
    26  func Chain(trees ...Tree) Tree {
    27  	if len(trees) == 0 {
    28  		return &chain{}
    29  	}
    30  	n := len(trees)
    31  	ch := &chain{
    32  		trees: make([]Tree, n),
    33  		offs:  make([]int64, n),
    34  		tots:  make([]int64, n),
    35  		cur:   -1,
    36  	}
    37  	var (
    38  		sum int64
    39  		off int64
    40  	)
    41  	for i := range trees {
    42  		t := trees[i]
    43  		n := t.Entries()
    44  		sum += n
    45  		ch.trees[i] = t
    46  		ch.offs[i] = off
    47  		ch.tots[i] = sum
    48  		off += n
    49  	}
    50  
    51  	ch.loadTree(ch.cur + 1)
    52  	return ch
    53  }
    54  
    55  // ChainOf returns a Tree, a close function and an error if any.
    56  // The tree is the logical concatenation of all the name trees
    57  // located in the input named files.
    58  // The close function allows to close all the open named files.
    59  func ChainOf(name string, files ...string) (Tree, func() error, error) {
    60  	var (
    61  		trees = make([]Tree, len(files))
    62  		fs    = make([]*riofs.File, len(files))
    63  	)
    64  
    65  	closef := func(fs []*riofs.File) {
    66  		for _, f := range fs {
    67  			if f == nil {
    68  				continue
    69  			}
    70  			f.Close()
    71  		}
    72  	}
    73  
    74  	for i, n := range files {
    75  		f, err := riofs.Open(n)
    76  		if err != nil {
    77  			closef(fs)
    78  			return nil, nil, err
    79  		}
    80  		fs[i] = f
    81  		obj, err := f.Get(name)
    82  		if err != nil {
    83  			closef(fs)
    84  			return nil, nil, err
    85  		}
    86  		t, ok := obj.(Tree)
    87  		if !ok {
    88  			closef(fs)
    89  			return nil, nil, fmt.Errorf("rtree: object %q in file %q is not a Tree", name, n)
    90  		}
    91  
    92  		trees[i] = t
    93  	}
    94  
    95  	ch := Chain(trees...)
    96  	close := func() error {
    97  		var err error
    98  		for _, f := range fs {
    99  			e := f.Close()
   100  			if e != nil && err == nil {
   101  				err = e
   102  			}
   103  		}
   104  		return err
   105  	}
   106  
   107  	return ch, close, nil
   108  }
   109  
   110  func (ch *chain) loadTree(i int) {
   111  	ch.cur = i
   112  	if ch.cur >= len(ch.trees) {
   113  		ch.tree = nil
   114  		return
   115  	}
   116  	ch.tree = ch.trees[ch.cur]
   117  	ch.off = ch.offs[ch.cur]
   118  	ch.tot = ch.tots[ch.cur]
   119  }
   120  
   121  // Class returns the ROOT class of the argument.
   122  func (*chain) Class() string {
   123  	return "TChain"
   124  }
   125  
   126  // Name returns the name of the ROOT objet in the argument.
   127  func (t *chain) Name() string {
   128  	if t.tree == nil {
   129  		return ""
   130  	}
   131  	return t.tree.Name()
   132  }
   133  
   134  // Title returns the title of the ROOT object in the argument.
   135  func (t *chain) Title() string {
   136  	if t.tree == nil {
   137  		return ""
   138  	}
   139  	return t.tree.Title()
   140  }
   141  
   142  // Entries returns the total number of entries.
   143  func (t *chain) Entries() int64 {
   144  	var v int64
   145  	for _, tree := range t.trees {
   146  		v += tree.Entries()
   147  	}
   148  	return v
   149  }
   150  
   151  // Branches returns the list of branches.
   152  func (t *chain) Branches() []Branch {
   153  	if t.tree == nil {
   154  		return nil
   155  	}
   156  	return t.tree.Branches()
   157  }
   158  
   159  // Branch returns the branch whose name is the argument.
   160  func (t *chain) Branch(name string) Branch {
   161  	if t.tree == nil {
   162  		return nil
   163  	}
   164  	return t.tree.Branch(name)
   165  }
   166  
   167  // Leaves returns direct pointers to individual branch leaves.
   168  func (t *chain) Leaves() []Leaf {
   169  	if t.tree == nil {
   170  		return nil
   171  	}
   172  	return t.tree.Leaves()
   173  }
   174  
   175  // Leaf returns the leaf whose name is the argument.
   176  func (t *chain) Leaf(name string) Leaf {
   177  	if t.tree == nil {
   178  		return nil
   179  	}
   180  	return t.tree.Leaf(name)
   181  }
   182  
   183  var (
   184  	_ root.Object = (*chain)(nil)
   185  	_ root.Named  = (*chain)(nil)
   186  	_ Tree        = (*chain)(nil)
   187  )