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

     1  // Copyright ©2020 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  	"strings"
    10  
    11  	"go-hep.org/x/hep/groot/root"
    12  )
    13  
    14  type join struct {
    15  	name     string
    16  	title    string
    17  	trees    []Tree
    18  	branches []Branch
    19  	leaves   []Leaf
    20  	bmap     map[string]Branch
    21  	lmap     map[string]Leaf
    22  }
    23  
    24  // Join returns a new Tree that represents the logical join of the input trees.
    25  // The returned tree will contain all the columns of all the input trees.
    26  // Join errors out if the input slice of trees is empty.
    27  // Join errors out if the input trees do not have the same amount of entries.
    28  // Join errors out if two trees have each a column with the same name.
    29  func Join(trees ...Tree) (Tree, error) {
    30  	if len(trees) == 0 {
    31  		return nil, fmt.Errorf("rtree: no trees to join")
    32  	}
    33  
    34  	nevts := trees[0].Entries()
    35  	for _, t := range trees[1:] {
    36  		if t.Entries() != nevts {
    37  			return nil, fmt.Errorf(
    38  				"rtree: invalid number of entries in tree %s (got=%d, want=%d)",
    39  				t.Name(), t.Entries(), nevts,
    40  			)
    41  		}
    42  	}
    43  
    44  	var (
    45  		bset     = make([]map[string]struct{}, len(trees))
    46  		branches []Branch
    47  		leaves   []Leaf
    48  		names    = make([]string, len(trees))
    49  		titles   = make([]string, len(trees))
    50  	)
    51  	for i, t := range trees {
    52  		names[i] = t.Name()
    53  		titles[i] = t.Title()
    54  		bset[i] = make(map[string]struct{}, len(t.Branches()))
    55  		for _, b := range t.Branches() {
    56  			bset[i][b.Name()] = struct{}{}
    57  		}
    58  		branches = append(branches, t.Branches()...)
    59  		leaves = append(leaves, t.Leaves()...)
    60  	}
    61  
    62  	for i, ti := range trees {
    63  		bsi := bset[i]
    64  		for j, tj := range trees[i+1:] {
    65  			bsj := bset[j+i+1]
    66  			for ki := range bsi {
    67  				if _, dup := bsj[ki]; dup {
    68  					return nil, fmt.Errorf(
    69  						"rtree: trees %s and %s both have a branch named %s",
    70  						ti.Name(), tj.Name(), ki,
    71  					)
    72  				}
    73  			}
    74  		}
    75  	}
    76  
    77  	tree := &join{
    78  		name:     "join_" + strings.Join(names, "_"),
    79  		title:    strings.Join(titles, ", "),
    80  		trees:    trees,
    81  		branches: branches,
    82  		leaves:   leaves,
    83  		bmap:     make(map[string]Branch, len(branches)),
    84  		lmap:     make(map[string]Leaf, len(leaves)),
    85  	}
    86  
    87  	for _, b := range tree.branches {
    88  		tree.bmap[b.Name()] = b
    89  	}
    90  	for _, l := range tree.leaves {
    91  		tree.lmap[l.Name()] = l
    92  	}
    93  
    94  	return tree, nil
    95  }
    96  
    97  // Class returns the ROOT class of the argument.
    98  func (*join) Class() string {
    99  	return "TJoin"
   100  }
   101  
   102  // Name returns the name of the ROOT objet in the argument.
   103  func (t *join) Name() string {
   104  	return t.name
   105  }
   106  
   107  // Title returns the title of the ROOT object in the argument.
   108  func (t *join) Title() string {
   109  	return t.title
   110  }
   111  
   112  // Entries returns the total number of entries.
   113  func (t *join) Entries() int64 {
   114  	return t.trees[0].Entries()
   115  }
   116  
   117  // Branches returns the list of branches.
   118  func (t *join) Branches() []Branch {
   119  	return t.branches
   120  }
   121  
   122  // Branch returns the branch whose name is the argument.
   123  func (t *join) Branch(name string) Branch {
   124  	return t.bmap[name]
   125  }
   126  
   127  // Leaves returns direct pointers to individual branch leaves.
   128  func (t *join) Leaves() []Leaf {
   129  	return t.leaves
   130  }
   131  
   132  // Leaf returns the leaf whose name is the argument.
   133  func (t *join) Leaf(name string) Leaf {
   134  	return t.lmap[name]
   135  }
   136  
   137  var (
   138  	_ root.Object = (*chain)(nil)
   139  	_ root.Named  = (*chain)(nil)
   140  	_ Tree        = (*chain)(nil)
   141  )
   142  var (
   143  	_ Tree = (*join)(nil)
   144  )