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

     1  // Copyright ©2019 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_test
     6  
     7  import (
     8  	"bytes"
     9  	"compress/flate"
    10  	"fmt"
    11  	"log"
    12  	"reflect"
    13  
    14  	"go-hep.org/x/hep/groot"
    15  	"go-hep.org/x/hep/groot/rcmd"
    16  	"go-hep.org/x/hep/groot/rdict"
    17  	"go-hep.org/x/hep/groot/rtree"
    18  )
    19  
    20  func Example_createFlatNtuple() {
    21  	type Data struct {
    22  		I32    int32
    23  		F64    float64
    24  		Str    string
    25  		ArrF64 [5]float64
    26  		N      int32
    27  		SliF64 []float64
    28  	}
    29  	const (
    30  		fname = "../testdata/groot-flat-ntuple.root"
    31  		nevts = 5
    32  	)
    33  	func() {
    34  		f, err := groot.Create(fname)
    35  		if err != nil {
    36  			log.Fatalf("%+v", err)
    37  		}
    38  		defer f.Close()
    39  
    40  		var evt Data
    41  
    42  		wvars := []rtree.WriteVar{
    43  			{Name: "I32", Value: &evt.I32},
    44  			{Name: "F64", Value: &evt.F64},
    45  			{Name: "Str", Value: &evt.Str},
    46  			{Name: "ArrF64", Value: &evt.ArrF64},
    47  			{Name: "N", Value: &evt.N},
    48  			{Name: "SliF64", Value: &evt.SliF64, Count: "N"},
    49  		}
    50  		tree, err := rtree.NewWriter(f, "mytree", wvars)
    51  		if err != nil {
    52  			log.Fatalf("could not create tree writer: %+v", err)
    53  		}
    54  		defer tree.Close()
    55  
    56  		fmt.Printf("-- created tree %q:\n", tree.Name())
    57  		for i, b := range tree.Branches() {
    58  			fmt.Printf("branch[%d]: name=%q, title=%q\n", i, b.Name(), b.Title())
    59  		}
    60  
    61  		for i := range nevts {
    62  			evt.I32 = int32(i)
    63  			evt.F64 = float64(i)
    64  			evt.Str = fmt.Sprintf("evt-%0d", i)
    65  			evt.ArrF64 = [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}
    66  			evt.N = int32(i)
    67  			evt.SliF64 = []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i]
    68  			_, err = tree.Write()
    69  			if err != nil {
    70  				log.Fatalf("could not write event %d: %+v", i, err)
    71  			}
    72  		}
    73  		fmt.Printf("-- filled tree with %d entries\n", tree.Entries())
    74  
    75  		err = tree.Close()
    76  		if err != nil {
    77  			log.Fatalf("could not write tree: %+v", err)
    78  		}
    79  
    80  		err = f.Close()
    81  		if err != nil {
    82  			log.Fatalf("could not close tree: %+v", err)
    83  		}
    84  	}()
    85  
    86  	func() {
    87  		fmt.Printf("-- read back ROOT file\n")
    88  		f, err := groot.Open(fname)
    89  		if err != nil {
    90  			log.Fatalf("could not open ROOT file: %+v", err)
    91  		}
    92  		defer f.Close()
    93  
    94  		obj, err := f.Get("mytree")
    95  		if err != nil {
    96  			log.Fatalf("%+v", err)
    97  		}
    98  
    99  		tree := obj.(rtree.Tree)
   100  
   101  		var data Data
   102  		r, err := rtree.NewReader(tree, rtree.ReadVarsFromStruct(&data))
   103  		if err != nil {
   104  			log.Fatal(err)
   105  		}
   106  		defer r.Close()
   107  
   108  		err = r.Read(func(ctx rtree.RCtx) error {
   109  			fmt.Printf("entry[%d]: %+v\n", ctx.Entry, data)
   110  			return nil
   111  		})
   112  
   113  		if err != nil {
   114  			log.Fatal(err)
   115  		}
   116  	}()
   117  
   118  	// Output:
   119  	// -- created tree "mytree":
   120  	// branch[0]: name="I32", title="I32/I"
   121  	// branch[1]: name="F64", title="F64/D"
   122  	// branch[2]: name="Str", title="Str/C"
   123  	// branch[3]: name="ArrF64", title="ArrF64[5]/D"
   124  	// branch[4]: name="N", title="N/I"
   125  	// branch[5]: name="SliF64", title="SliF64[N]/D"
   126  	// -- filled tree with 5 entries
   127  	// -- read back ROOT file
   128  	// entry[0]: {I32:0 F64:0 Str:evt-0 ArrF64:[0 1 2 3 4] N:0 SliF64:[]}
   129  	// entry[1]: {I32:1 F64:1 Str:evt-1 ArrF64:[1 2 3 4 5] N:1 SliF64:[1]}
   130  	// entry[2]: {I32:2 F64:2 Str:evt-2 ArrF64:[2 3 4 5 6] N:2 SliF64:[2 3]}
   131  	// entry[3]: {I32:3 F64:3 Str:evt-3 ArrF64:[3 4 5 6 7] N:3 SliF64:[3 4 5]}
   132  	// entry[4]: {I32:4 F64:4 Str:evt-4 ArrF64:[4 5 6 7 8] N:4 SliF64:[4 5 6 7]}
   133  }
   134  
   135  func Example_createFlatNtupleWithLZMA() {
   136  	type Data struct {
   137  		I32    int32
   138  		F64    float64
   139  		Str    string
   140  		ArrF64 [5]float64
   141  		N      int32
   142  		SliF64 []float64
   143  	}
   144  	const (
   145  		fname = "../testdata/groot-flat-ntuple-with-lzma.root"
   146  		nevts = 5
   147  	)
   148  	func() {
   149  		f, err := groot.Create(fname)
   150  		if err != nil {
   151  			log.Fatalf("%+v", err)
   152  		}
   153  		defer f.Close()
   154  
   155  		var evt Data
   156  
   157  		wvars := []rtree.WriteVar{
   158  			{Name: "I32", Value: &evt.I32},
   159  			{Name: "F64", Value: &evt.F64},
   160  			{Name: "Str", Value: &evt.Str},
   161  			{Name: "ArrF64", Value: &evt.ArrF64},
   162  			{Name: "N", Value: &evt.N},
   163  			{Name: "SliF64", Value: &evt.SliF64, Count: "N"},
   164  		}
   165  		tree, err := rtree.NewWriter(f, "mytree", wvars, rtree.WithLZMA(flate.BestCompression), rtree.WithBasketSize(32*1024))
   166  		if err != nil {
   167  			log.Fatalf("could not create tree writer: %+v", err)
   168  		}
   169  		defer tree.Close()
   170  
   171  		fmt.Printf("-- created tree %q:\n", tree.Name())
   172  		for i, b := range tree.Branches() {
   173  			fmt.Printf("branch[%d]: name=%q, title=%q\n", i, b.Name(), b.Title())
   174  		}
   175  
   176  		for i := range nevts {
   177  			evt.I32 = int32(i)
   178  			evt.F64 = float64(i)
   179  			evt.Str = fmt.Sprintf("evt-%0d", i)
   180  			evt.ArrF64 = [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}
   181  			evt.N = int32(i)
   182  			evt.SliF64 = []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i]
   183  			_, err = tree.Write()
   184  			if err != nil {
   185  				log.Fatalf("could not write event %d: %+v", i, err)
   186  			}
   187  		}
   188  		fmt.Printf("-- filled tree with %d entries\n", tree.Entries())
   189  
   190  		err = tree.Close()
   191  		if err != nil {
   192  			log.Fatalf("could not write tree: %+v", err)
   193  		}
   194  
   195  		err = f.Close()
   196  		if err != nil {
   197  			log.Fatalf("could not close tree: %+v", err)
   198  		}
   199  	}()
   200  
   201  	func() {
   202  		fmt.Printf("-- read back ROOT file\n")
   203  		f, err := groot.Open(fname)
   204  		if err != nil {
   205  			log.Fatalf("could not open ROOT file: %+v", err)
   206  		}
   207  		defer f.Close()
   208  
   209  		obj, err := f.Get("mytree")
   210  		if err != nil {
   211  			log.Fatalf("%+v", err)
   212  		}
   213  
   214  		tree := obj.(rtree.Tree)
   215  
   216  		var data Data
   217  		r, err := rtree.NewReader(tree, rtree.ReadVarsFromStruct(&data))
   218  		if err != nil {
   219  			log.Fatal(err)
   220  		}
   221  		defer r.Close()
   222  
   223  		err = r.Read(func(ctx rtree.RCtx) error {
   224  			fmt.Printf("entry[%d]: %+v\n", ctx.Entry, data)
   225  			return nil
   226  		})
   227  
   228  		if err != nil {
   229  			log.Fatal(err)
   230  		}
   231  	}()
   232  
   233  	// Output:
   234  	// -- created tree "mytree":
   235  	// branch[0]: name="I32", title="I32/I"
   236  	// branch[1]: name="F64", title="F64/D"
   237  	// branch[2]: name="Str", title="Str/C"
   238  	// branch[3]: name="ArrF64", title="ArrF64[5]/D"
   239  	// branch[4]: name="N", title="N/I"
   240  	// branch[5]: name="SliF64", title="SliF64[N]/D"
   241  	// -- filled tree with 5 entries
   242  	// -- read back ROOT file
   243  	// entry[0]: {I32:0 F64:0 Str:evt-0 ArrF64:[0 1 2 3 4] N:0 SliF64:[]}
   244  	// entry[1]: {I32:1 F64:1 Str:evt-1 ArrF64:[1 2 3 4 5] N:1 SliF64:[1]}
   245  	// entry[2]: {I32:2 F64:2 Str:evt-2 ArrF64:[2 3 4 5 6] N:2 SliF64:[2 3]}
   246  	// entry[3]: {I32:3 F64:3 Str:evt-3 ArrF64:[3 4 5 6 7] N:3 SliF64:[3 4 5]}
   247  	// entry[4]: {I32:4 F64:4 Str:evt-4 ArrF64:[4 5 6 7 8] N:4 SliF64:[4 5 6 7]}
   248  }
   249  
   250  func Example_createFlatNtupleFromStruct() {
   251  	type Data struct {
   252  		I32    int32
   253  		F64    float64
   254  		Str    string
   255  		ArrF64 [5]float64
   256  		N      int32
   257  		SliF64 []float64 `groot:"SliF64[N]"`
   258  	}
   259  	const (
   260  		fname = "../testdata/groot-flat-ntuple-with-struct.root"
   261  		nevts = 5
   262  	)
   263  	func() {
   264  		f, err := groot.Create(fname)
   265  		if err != nil {
   266  			log.Fatalf("%+v", err)
   267  		}
   268  		defer f.Close()
   269  
   270  		var evt Data
   271  
   272  		tree, err := rtree.NewWriter(f, "mytree", rtree.WriteVarsFromStruct(&evt))
   273  		if err != nil {
   274  			log.Fatalf("could not create tree writer: %+v", err)
   275  		}
   276  		defer tree.Close()
   277  
   278  		fmt.Printf("-- created tree %q:\n", tree.Name())
   279  		for i, b := range tree.Branches() {
   280  			fmt.Printf("branch[%d]: name=%q, title=%q\n", i, b.Name(), b.Title())
   281  		}
   282  
   283  		for i := range nevts {
   284  			evt.I32 = int32(i)
   285  			evt.F64 = float64(i)
   286  			evt.Str = fmt.Sprintf("evt-%0d", i)
   287  			evt.ArrF64 = [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}
   288  			evt.N = int32(i)
   289  			evt.SliF64 = []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i]
   290  			_, err = tree.Write()
   291  			if err != nil {
   292  				log.Fatalf("could not write event %d: %+v", i, err)
   293  			}
   294  		}
   295  		fmt.Printf("-- filled tree with %d entries\n", tree.Entries())
   296  
   297  		err = tree.Close()
   298  		if err != nil {
   299  			log.Fatalf("could not write tree: %+v", err)
   300  		}
   301  
   302  		err = f.Close()
   303  		if err != nil {
   304  			log.Fatalf("could not close tree: %+v", err)
   305  		}
   306  	}()
   307  
   308  	func() {
   309  		fmt.Printf("-- read back ROOT file\n")
   310  		f, err := groot.Open(fname)
   311  		if err != nil {
   312  			log.Fatalf("could not open ROOT file: %+v", err)
   313  		}
   314  		defer f.Close()
   315  
   316  		obj, err := f.Get("mytree")
   317  		if err != nil {
   318  			log.Fatalf("%+v", err)
   319  		}
   320  
   321  		tree := obj.(rtree.Tree)
   322  
   323  		var data Data
   324  		r, err := rtree.NewReader(tree, rtree.ReadVarsFromStruct(&data))
   325  		if err != nil {
   326  			log.Fatal(err)
   327  		}
   328  		defer r.Close()
   329  
   330  		err = r.Read(func(ctx rtree.RCtx) error {
   331  			fmt.Printf("entry[%d]: %+v\n", ctx.Entry, data)
   332  			return nil
   333  		})
   334  
   335  		if err != nil {
   336  			log.Fatal(err)
   337  		}
   338  	}()
   339  
   340  	// Output:
   341  	// -- created tree "mytree":
   342  	// branch[0]: name="I32", title="I32/I"
   343  	// branch[1]: name="F64", title="F64/D"
   344  	// branch[2]: name="Str", title="Str/C"
   345  	// branch[3]: name="ArrF64", title="ArrF64[5]/D"
   346  	// branch[4]: name="N", title="N/I"
   347  	// branch[5]: name="SliF64", title="SliF64[N]/D"
   348  	// -- filled tree with 5 entries
   349  	// -- read back ROOT file
   350  	// entry[0]: {I32:0 F64:0 Str:evt-0 ArrF64:[0 1 2 3 4] N:0 SliF64:[]}
   351  	// entry[1]: {I32:1 F64:1 Str:evt-1 ArrF64:[1 2 3 4 5] N:1 SliF64:[1]}
   352  	// entry[2]: {I32:2 F64:2 Str:evt-2 ArrF64:[2 3 4 5 6] N:2 SliF64:[2 3]}
   353  	// entry[3]: {I32:3 F64:3 Str:evt-3 ArrF64:[3 4 5 6 7] N:3 SliF64:[3 4 5]}
   354  	// entry[4]: {I32:4 F64:4 Str:evt-4 ArrF64:[4 5 6 7 8] N:4 SliF64:[4 5 6 7]}
   355  }
   356  
   357  func Example_createEventNtupleNoSplit() {
   358  	type P4 struct {
   359  		Px float64 `groot:"px"`
   360  		Py float64 `groot:"py"`
   361  		Pz float64 `groot:"pz"`
   362  		E  float64 `groot:"ene"`
   363  	}
   364  
   365  	type Particle struct {
   366  		ID int32 `groot:"id"`
   367  		P4 P4    `groot:"p4"`
   368  	}
   369  
   370  	type Event struct {
   371  		I32 int32      `groot:"i32"`
   372  		F64 float64    `groot:"f64"`
   373  		Str string     `groot:"str"`
   374  		Arr [5]float64 `groot:"arr"`
   375  		Sli []float64  `groot:"sli"`
   376  		P4  P4         `groot:"p4"`
   377  		Ps  []Particle `groot:"mc"`
   378  	}
   379  
   380  	// register streamers
   381  	for _, typ := range []reflect.Type{
   382  		reflect.TypeOf(P4{}),
   383  		reflect.TypeOf(Particle{}),
   384  		reflect.TypeOf(Event{}),
   385  	} {
   386  
   387  		rdict.StreamerInfos.Add(rdict.StreamerOf(
   388  			rdict.StreamerInfos,
   389  			typ,
   390  		))
   391  	}
   392  
   393  	const (
   394  		fname = "../testdata/groot-event-ntuple-nosplit.root"
   395  		nevts = 5
   396  	)
   397  
   398  	func() {
   399  		f, err := groot.Create(fname)
   400  		if err != nil {
   401  			log.Fatalf("could not create ROOT file: %+v", err)
   402  		}
   403  		defer f.Close()
   404  
   405  		var (
   406  			evt   Event
   407  			wvars = []rtree.WriteVar{
   408  				{Name: "evt", Value: &evt},
   409  			}
   410  		)
   411  
   412  		tree, err := rtree.NewWriter(f, "mytree", wvars)
   413  		if err != nil {
   414  			log.Fatalf("could not create tree writer: %+v", err)
   415  		}
   416  		defer tree.Close()
   417  
   418  		fmt.Printf("-- created tree %q:\n", tree.Name())
   419  		for i, b := range tree.Branches() {
   420  			fmt.Printf("branch[%d]: name=%q, title=%q\n", i, b.Name(), b.Title())
   421  		}
   422  
   423  		for i := range nevts {
   424  			evt.I32 = int32(i)
   425  			evt.F64 = float64(i)
   426  			evt.Str = fmt.Sprintf("evt-%0d", i)
   427  			evt.Arr = [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}
   428  			evt.Sli = []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i]
   429  			evt.P4 = P4{Px: float64(i), Py: float64(i + 1), Pz: float64(i + 2), E: float64(i + 3)}
   430  			evt.Ps = []Particle{
   431  				{ID: int32(i), P4: evt.P4},
   432  				{ID: int32(i + 1), P4: evt.P4},
   433  				{ID: int32(i + 2), P4: evt.P4},
   434  				{ID: int32(i + 3), P4: evt.P4},
   435  				{ID: int32(i + 4), P4: evt.P4},
   436  			}[:i]
   437  
   438  			_, err = tree.Write()
   439  			if err != nil {
   440  				log.Fatalf("could not write event %d: %+v", i, err)
   441  			}
   442  		}
   443  		fmt.Printf("-- filled tree with %d entries\n", tree.Entries())
   444  
   445  		err = tree.Close()
   446  		if err != nil {
   447  			log.Fatalf("could not write tree: %+v", err)
   448  		}
   449  
   450  		err = f.Close()
   451  		if err != nil {
   452  			log.Fatalf("could not close tree: %+v", err)
   453  		}
   454  	}()
   455  
   456  	{
   457  		fmt.Printf("-- read back ROOT file\n")
   458  		out := new(bytes.Buffer)
   459  		err := rcmd.List(out, fname, rcmd.ListTrees(true))
   460  		if err != nil {
   461  			log.Fatalf("could not list ROOT file content: %+v", err)
   462  		}
   463  		fmt.Printf("%s\n", out.String())
   464  	}
   465  
   466  	{
   467  		var (
   468  			deep   = true
   469  			filter = func(name string) bool { return true }
   470  		)
   471  		out := new(bytes.Buffer)
   472  		err := rcmd.Dump(out, fname, deep, filter)
   473  		if err != nil {
   474  			log.Fatalf("could not dump ROOT file: %+v", err)
   475  		}
   476  		fmt.Printf("%s\n", out.String())
   477  	}
   478  
   479  	// Output:
   480  	// -- created tree "mytree":
   481  	// branch[0]: name="evt", title="evt"
   482  	// -- filled tree with 5 entries
   483  	// -- read back ROOT file
   484  	// === [../testdata/groot-event-ntuple-nosplit.root] ===
   485  	// version: 63602
   486  	//   TTree mytree          (entries=5)
   487  	//     evt "evt"   TBranchElement
   488  	//
   489  	// key[000]: mytree;1 "" (TTree)
   490  	// [000][evt]: {0 0 evt-0 [0 1 2 3 4] [] {0 1 2 3} []}
   491  	// [001][evt]: {1 1 evt-1 [1 2 3 4 5] [1] {1 2 3 4} [{1 {1 2 3 4}}]}
   492  	// [002][evt]: {2 2 evt-2 [2 3 4 5 6] [2 3] {2 3 4 5} [{2 {2 3 4 5}} {3 {2 3 4 5}}]}
   493  	// [003][evt]: {3 3 evt-3 [3 4 5 6 7] [3 4 5] {3 4 5 6} [{3 {3 4 5 6}} {4 {3 4 5 6}} {5 {3 4 5 6}}]}
   494  	// [004][evt]: {4 4 evt-4 [4 5 6 7 8] [4 5 6 7] {4 5 6 7} [{4 {4 5 6 7}} {5 {4 5 6 7}} {6 {4 5 6 7}} {7 {4 5 6 7}}]}
   495  
   496  }
   497  
   498  func Example_createEventNtupleFullSplit() {
   499  	type P4 struct {
   500  		Px float64 `groot:"px"`
   501  		Py float64 `groot:"py"`
   502  		Pz float64 `groot:"pz"`
   503  		E  float64 `groot:"ene"`
   504  	}
   505  
   506  	type Particle struct {
   507  		ID int32 `groot:"id"`
   508  		P4 P4    `groot:"p4"`
   509  	}
   510  
   511  	type Event struct {
   512  		I32 int32      `groot:"i32"`
   513  		F64 float64    `groot:"f64"`
   514  		Str string     `groot:"str"`
   515  		Arr [5]float64 `groot:"arr"`
   516  		Sli []float64  `groot:"sli"`
   517  		P4  P4         `groot:"p4"`
   518  		Ps  []Particle `groot:"mc"`
   519  	}
   520  
   521  	// register streamers
   522  	for _, typ := range []reflect.Type{
   523  		reflect.TypeOf(P4{}),
   524  		reflect.TypeOf(Particle{}),
   525  		reflect.TypeOf(Event{}),
   526  	} {
   527  
   528  		rdict.StreamerInfos.Add(rdict.StreamerOf(
   529  			rdict.StreamerInfos,
   530  			typ,
   531  		))
   532  	}
   533  
   534  	const (
   535  		fname = "../testdata/groot-event-ntuple-fullsplit.root"
   536  		nevts = 5
   537  	)
   538  
   539  	func() {
   540  		f, err := groot.Create(fname)
   541  		if err != nil {
   542  			log.Fatalf("could not create ROOT file: %+v", err)
   543  		}
   544  		defer f.Close()
   545  
   546  		var (
   547  			evt   Event
   548  			wvars = rtree.WriteVarsFromStruct(&evt)
   549  		)
   550  
   551  		tree, err := rtree.NewWriter(f, "mytree", wvars)
   552  		if err != nil {
   553  			log.Fatalf("could not create tree writer: %+v", err)
   554  		}
   555  		defer tree.Close()
   556  
   557  		fmt.Printf("-- created tree %q:\n", tree.Name())
   558  		for i, b := range tree.Branches() {
   559  			fmt.Printf("branch[%d]: name=%q, title=%q\n", i, b.Name(), b.Title())
   560  		}
   561  
   562  		for i := range nevts {
   563  			evt.I32 = int32(i)
   564  			evt.F64 = float64(i)
   565  			evt.Str = fmt.Sprintf("evt-%0d", i)
   566  			evt.Arr = [5]float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}
   567  			evt.Sli = []float64{float64(i), float64(i + 1), float64(i + 2), float64(i + 3), float64(i + 4)}[:i]
   568  			evt.P4 = P4{Px: float64(i), Py: float64(i + 1), Pz: float64(i + 2), E: float64(i + 3)}
   569  			evt.Ps = []Particle{
   570  				{ID: int32(i), P4: evt.P4},
   571  				{ID: int32(i + 1), P4: evt.P4},
   572  				{ID: int32(i + 2), P4: evt.P4},
   573  				{ID: int32(i + 3), P4: evt.P4},
   574  				{ID: int32(i + 4), P4: evt.P4},
   575  			}[:i]
   576  
   577  			_, err = tree.Write()
   578  			if err != nil {
   579  				log.Fatalf("could not write event %d: %+v", i, err)
   580  			}
   581  		}
   582  		fmt.Printf("-- filled tree with %d entries\n", tree.Entries())
   583  
   584  		err = tree.Close()
   585  		if err != nil {
   586  			log.Fatalf("could not write tree: %+v", err)
   587  		}
   588  
   589  		err = f.Close()
   590  		if err != nil {
   591  			log.Fatalf("could not close tree: %+v", err)
   592  		}
   593  	}()
   594  
   595  	{
   596  		fmt.Printf("-- read back ROOT file\n")
   597  		out := new(bytes.Buffer)
   598  		err := rcmd.List(out, fname, rcmd.ListTrees(true))
   599  		if err != nil {
   600  			log.Fatalf("could not list ROOT file content: %+v", err)
   601  		}
   602  		fmt.Printf("%s\n", out.String())
   603  	}
   604  
   605  	{
   606  		var (
   607  			deep   = true
   608  			filter = func(name string) bool { return true }
   609  		)
   610  		out := new(bytes.Buffer)
   611  		err := rcmd.Dump(out, fname, deep, filter)
   612  		if err != nil {
   613  			log.Fatalf("could not dump ROOT file: %+v", err)
   614  		}
   615  		fmt.Printf("%s\n", out.String())
   616  	}
   617  
   618  	// Output:
   619  	// -- created tree "mytree":
   620  	// branch[0]: name="i32", title="i32/I"
   621  	// branch[1]: name="f64", title="f64/D"
   622  	// branch[2]: name="str", title="str/C"
   623  	// branch[3]: name="arr", title="arr[5]/D"
   624  	// branch[4]: name="sli", title="sli"
   625  	// branch[5]: name="p4", title="p4"
   626  	// branch[6]: name="mc", title="mc"
   627  	// -- filled tree with 5 entries
   628  	// -- read back ROOT file
   629  	// === [../testdata/groot-event-ntuple-fullsplit.root] ===
   630  	// version: 63602
   631  	//   TTree mytree             (entries=5)
   632  	//     i32 "i32/I"    TBranch
   633  	//     f64 "f64/D"    TBranch
   634  	//     str "str/C"    TBranch
   635  	//     arr "arr[5]/D" TBranch
   636  	//     sli "sli"      TBranchElement
   637  	//     p4  "p4"       TBranchElement
   638  	//     mc  "mc"       TBranchElement
   639  	//
   640  	// key[000]: mytree;1 "" (TTree)
   641  	// [000][i32]: 0
   642  	// [000][f64]: 0
   643  	// [000][str]: evt-0
   644  	// [000][arr]: [0 1 2 3 4]
   645  	// [000][sli]: []
   646  	// [000][p4]: {0 1 2 3}
   647  	// [000][mc]: []
   648  	// [001][i32]: 1
   649  	// [001][f64]: 1
   650  	// [001][str]: evt-1
   651  	// [001][arr]: [1 2 3 4 5]
   652  	// [001][sli]: [1]
   653  	// [001][p4]: {1 2 3 4}
   654  	// [001][mc]: [{1 {1 2 3 4}}]
   655  	// [002][i32]: 2
   656  	// [002][f64]: 2
   657  	// [002][str]: evt-2
   658  	// [002][arr]: [2 3 4 5 6]
   659  	// [002][sli]: [2 3]
   660  	// [002][p4]: {2 3 4 5}
   661  	// [002][mc]: [{2 {2 3 4 5}} {3 {2 3 4 5}}]
   662  	// [003][i32]: 3
   663  	// [003][f64]: 3
   664  	// [003][str]: evt-3
   665  	// [003][arr]: [3 4 5 6 7]
   666  	// [003][sli]: [3 4 5]
   667  	// [003][p4]: {3 4 5 6}
   668  	// [003][mc]: [{3 {3 4 5 6}} {4 {3 4 5 6}} {5 {3 4 5 6}}]
   669  	// [004][i32]: 4
   670  	// [004][f64]: 4
   671  	// [004][str]: evt-4
   672  	// [004][arr]: [4 5 6 7 8]
   673  	// [004][sli]: [4 5 6 7]
   674  	// [004][p4]: {4 5 6 7}
   675  	// [004][mc]: [{4 {4 5 6 7}} {5 {4 5 6 7}} {6 {4 5 6 7}} {7 {4 5 6 7}}]
   676  }