go-hep.org/x/hep@v0.38.1/groot/rcmd/split.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 rcmd 6 7 import ( 8 "fmt" 9 "log" 10 "path" 11 12 "go-hep.org/x/hep/groot" 13 "go-hep.org/x/hep/groot/riofs" 14 "go-hep.org/x/hep/groot/rtree" 15 ) 16 17 // Split splits the tree from the input file into multiple trees, 18 // each with nevts entries. 19 // Split returns the name of the split output files, and an error, if any. 20 func Split(oname, fname, tname string, nevts int64, verbose bool) ([]string, error) { 21 f, err := groot.Open(fname) 22 if err != nil { 23 return nil, fmt.Errorf( 24 "could not open input file %q: %w", 25 fname, err, 26 ) 27 } 28 defer f.Close() 29 30 o, err := riofs.Dir(f).Get(tname) 31 if err != nil { 32 return nil, fmt.Errorf( 33 "could not fet tree %q: %w", tname, err, 34 ) 35 } 36 37 tree, ok := o.(rtree.Tree) 38 if !ok { 39 return nil, fmt.Errorf("object %q is not a Tree", tname) 40 } 41 42 var ( 43 cur int64 44 n = tree.Entries() 45 nfiles = 0 46 ) 47 for i := 0; cur < n; i++ { 48 m, err := split(oname, tname, tree, i, cur, nevts, verbose) 49 if err != nil { 50 return nil, fmt.Errorf("could not split tree into file#%d: %w", i, err) 51 } 52 cur += m 53 nfiles++ 54 } 55 56 onames := make([]string, nfiles) 57 for i := range onames { 58 onames[i] = fmt.Sprintf( 59 "%s-%d.root", 60 oname[:len(oname)-len(".root")], i, 61 ) 62 } 63 64 return onames, nil 65 } 66 67 func split(oname, tname string, tree rtree.Tree, i int, beg, nevts int64, verbose bool) (int64, error) { 68 oname = fmt.Sprintf( 69 "%s-%d.root", 70 oname[:len(oname)-len(".root")], i, 71 ) 72 o, err := groot.Create(oname) 73 if err != nil { 74 return 0, fmt.Errorf("could not create output file %d: %w", i, err) 75 } 76 defer o.Close() 77 78 var ( 79 dirName = path.Dir(tname) 80 objName = path.Base(tname) 81 dir = riofs.Directory(o) 82 ) 83 if dirName != "/" && dirName != "" && dirName != "." { 84 _, err = riofs.Dir(o).Mkdir(dirName) 85 if err != nil { 86 return 0, fmt.Errorf("could not create output directory %q: %w", dirName, err) 87 } 88 odir, err := riofs.Dir(o).Get(dirName) 89 if err != nil { 90 return 0, fmt.Errorf("could not fetch output directory %q: %w", dirName, err) 91 } 92 dir = odir.(riofs.Directory) 93 } 94 wvars := rtree.WriteVarsFromTree(tree) 95 w, err := rtree.NewWriter( 96 dir, objName, 97 wvars, 98 rtree.WithTitle(tree.Title()), 99 ) 100 if err != nil { 101 return 0, fmt.Errorf("could not create tree writer: %w", err) 102 } 103 defer w.Close() 104 105 var ( 106 rvars = make([]rtree.ReadVar, len(wvars)) 107 src = tree 108 end = beg + nevts 109 ) 110 for i, wvar := range wvars { 111 rvars[i] = rtree.ReadVar{ 112 Name: wvar.Name, 113 Value: wvar.Value, 114 } 115 } 116 117 if end > tree.Entries() { 118 end = tree.Entries() 119 } 120 121 r, err := rtree.NewReader(src, rvars, rtree.WithRange(beg, end)) 122 if err != nil { 123 return 0, fmt.Errorf("could not create tree reader: %w", err) 124 } 125 defer r.Close() 126 127 if verbose { 128 log.Printf("splitting [%d, %d) into %q...", beg, end, oname) 129 } 130 131 _, err = rtree.Copy(w, r) 132 if err != nil { 133 return 0, fmt.Errorf("rtree: could not copy tree: %w", err) 134 } 135 136 if verbose { 137 log.Printf("splitting [%d, %d) into %q... [ok]", beg, end, oname) 138 } 139 140 return end - beg, nil 141 }