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 )