FairShip
Loading...
Searching...
No Matches
convertTreeToRNTuple.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# SPDX-License-Identifier: LGPL-3.0-or-later
3# SPDX-FileCopyrightText: Copyright CERN for the benefit of the SHiP Collaboration
4"""
5Convert TTree to RNTuple using ROOT's RNTupleImporter.
6
7This script imports TTrees from ROOT files and converts them to RNTuple format,
8which provides better compression, faster I/O, and modern columnar storage.
9
10Usage:
11 python convertTreeToRNTuple.py -f input.root -t cbmsim -o output.root -n fairdata
12 python convertTreeToRNTuple.py -f input.root # Uses default tree/ntuple names
13
14Note:
15 RNTuple has some limitations compared to TTree:
16 - TObjArray and other legacy ROOT containers cannot be stored natively
17 - Use std::vector instead of TObjArray for RNTuple compatibility
18 - TClonesArray is also not supported; migrate to std::vector
19"""
20
21import argparse
22import sys
23
24import ROOT
25
26
27def convert_tree_to_rntuple(input_file, tree_name, output_file, ntuple_name) -> bool:
28 """
29 Convert a TTree to RNTuple format.
30
31 Args:
32 input_file: Path to input ROOT file containing TTree
33 tree_name: Name of the TTree to convert
34 output_file: Path to output ROOT file for RNTuple
35 ntuple_name: Name for the output RNTuple
36 """
37 print("Converting TTree → RNTuple")
38 print(f" Input: {input_file}:{tree_name}")
39 print(f" Output: {output_file}:{ntuple_name}")
40 print()
41
42 with ROOT.TFile.Open(input_file, "READ") as input_root_file:
43 tree = input_root_file.Get(tree_name)
44 if not tree:
45 print(f"ERROR: Tree '{tree_name}' not found in {input_file}")
46 print("Available trees:")
47 for key in input_root_file.GetListOfKeys():
48 obj = key.ReadObj()
49 if obj.InheritsFrom("TTree"):
50 print(f" - {key.GetName()}")
51 return False
52
53 num_entries = tree.GetEntries()
54 print(f"Found TTree '{tree_name}' with {num_entries} entries")
55 print()
56
57 # Convert using RNTupleImporter
58 try:
59 importer = ROOT.ROOT.Experimental.RNTupleImporter.Create(input_file, tree_name, output_file)
60
61 if not importer:
62 print("ERROR: Failed to create RNTupleImporter")
63 return False
64
65 # Set the RNTuple name (defaults to tree name if not set)
66 importer.SetNTupleName(ntuple_name)
67
68 # Optional: Configure import options
69 # importer.SetMaxUnzippedPageSize(...) # Adjust page size if needed
70 # importer.SetCompressionSettings(...) # Adjust compression (default: zstd)
71
72 print("Starting conversion...")
73 importer.Import() # Import() throws exception on failure
74
75 print("✓ Conversion complete!")
76 print()
77
78 # Verify output
79 with ROOT.TFile.Open(output_file, "READ"):
80 reader = ROOT.ROOT.RNTupleReader.Open(ntuple_name, output_file)
81 num_rntuple_entries = reader.GetNEntries()
82
83 print("Verification:")
84 print(f" TTree entries: {num_entries}")
85 print(f" RNTuple entries: {num_rntuple_entries}")
86
87 if num_entries == num_rntuple_entries:
88 print(" ✓ Entry count matches")
89 else:
90 print(" ✗ WARNING: Entry count mismatch!")
91
92 return True
93
94 except Exception as e:
95 print(f"ERROR: Exception during conversion: {e}")
96 import traceback
97
98 traceback.print_exc()
99 return False
100
101
102def main() -> int:
103 """Parse arguments and run the TTree to RNTuple conversion."""
104 parser = argparse.ArgumentParser(
105 description="Convert TTree to RNTuple using ROOT's RNTupleImporter",
106 formatter_class=argparse.RawDescriptionHelpFormatter,
107 epilog="""
108Examples:
109 # Convert cbmsim tree to fairdata RNTuple
110 %(prog)s -f ship.conical.Pythia8-TGeant4.root -t cbmsim -o output.root -n fairdata
111
112 # Use defaults (cbmsim → fairdata)
113 %(prog)s -f ship.conical.Pythia8-TGeant4.root
114
115 # Convert custom tree
116 %(prog)s -f mydata.root -t mytree -o converted.root -n myntuple
117 """,
118 )
119
120 parser.add_argument("-f", "--input-file", required=True, help="Input ROOT file containing TTree")
121 parser.add_argument(
122 "-t",
123 "--tree-name",
124 default="cbmsim",
125 help="Name of TTree to convert (default: cbmsim)",
126 )
127 parser.add_argument(
128 "-o",
129 "--output-file",
130 default=None,
131 help="Output ROOT file for RNTuple (default: <input>_rntuple.root)",
132 )
133 parser.add_argument(
134 "-n",
135 "--ntuple-name",
136 default="fairdata",
137 help="Name for output RNTuple (default: fairdata)",
138 )
139
140 args = parser.parse_args()
141
142 if args.output_file is None:
143 if args.input_file.endswith(".root"):
144 args.output_file = args.input_file.replace(".root", "_rntuple.root")
145 else:
146 args.output_file = args.input_file + "_rntuple.root"
147
148 success = convert_tree_to_rntuple(args.input_file, args.tree_name, args.output_file, args.ntuple_name)
149
150 if success:
151 print()
152 print("Success! RNTuple file created:")
153 print(f" {args.output_file}")
154 return 0
155 else:
156 print()
157 print("Conversion failed!")
158 return 1
159
160
161if __name__ == "__main__":
162 sys.exit(main())
bool convert_tree_to_rntuple(input_file, tree_name, output_file, ntuple_name)