5 Collection of utilities to ease interaction with ROOT.
7 Unsurprisingly, this module requires ROOT.
11 "splitROOTpath",
"createROOTpath",
"getROOTclass",
22 The ROOT interpreter likes to peek at the command line arguments and interpret
24 For example, an option `-b` will be interpreted to set ROOT in batch mode.
25 Likewise, if a `--help` argument is present on the command line, the
26 interpreter will print the ROOT help message and, even worse, halt the script.
27 This is clearly not very friendly to the script.
29 The initialization of the interpreter happens lazily the first time anything
30 is read out of `ROOT` module: `import ROOT` is not enough, but pretty much
31 everything after that involving ROOT is (exception: `ROOT.gROOT` will not
32 trigger the interpreter, but trying to get anything out of `ROOT.gROOT` will).
33 That makes it complicate to control when that happens.
35 This function triggers the interpreter initialization after having removed all
36 command line options, and finally restores them (we use a context manager to
37 show that we know Python). The loaded module is returned.
39 This function is called as soon as this module is imported. It is important
40 that this happens as early as possible, possibly as a replacement of ROOT
43 from ROOTutils import ROOT
45 from ROOTutils import *
53 try: alreadyLoaded =
'gInterpreter' in dir(ROOT)
54 except NameError: alreadyLoaded =
False
57 "ROOT module was loaded before ROOTutils.py: command line arguments may be garbled"
59 return sys.modules[
'ROOT']
65 logging.debug(
"Saving command line: %s", self.args)
66 sys.argv = sys.argv[0:1]
68 "Replaced command line %s with %s before loading ROOT module",
70 def __exit__(self, exc_type, exc_value, traceback):
72 logging.debug(
"Restored command line %s", sys.argv)
89 return "( %g, %g )" % (v.X(), v.Y())
91 return "( %g, %g, %g )" % (v.X(), v.Y(), v.Z())
93 return "( %g, %g, %g; %g )" % (v.X(), v.Y(), v.Z(), v.T())
95 ROOT.TVector2.__str__ = TVector2ToString
96 ROOT.TVector3.__str__ = TVector3ToString
97 ROOT.TLorentzVector.__str__ = TLorentzVectorToString
105 Returns the specified path split into file path and ROOT directory path.
107 The `path` is in the form:
108 "/UNIX/path/to/file.root:internal/ROOT/directory/and/object".
109 The returned value is a pair `(filePath, dirPath)`: in the example, that
110 would be `("/UNIX/path/to/file.root", "internal/ROOT/directory/and/object")`.
112 Note: for compatibility with some ROOT tradition, the separator ':' can be
118 filePath, ROOTpath = path.rsplit(
'.root')
120 raise RuntimeError(
"Path '{}' does not include a ROOT file.".
format(path))
124 return filePath, ROOTpath
131 Creates a complete ROOT directory path.
133 The `path` is in the form:
134 "/UNIX/path/to/file.root:internal/ROOT/directory/structure".
135 The ROOT file `/UNIX/path/to/file.root` will be created with the specified
136 `fileMode` (path may be relative), then the `TDirectoryFile` hierarchy
137 `internal/ROOT/directory/structure` will be created under it.
138 The return value is a pair `(file, dir)`, where `file` is a open `TFile`
139 for `/UNIX/path/to/file.root` and `dir` is the `TDirectory` object of
142 Remember to keep track of `file`, or else python may close it compromising
148 ROOTfile = ROOT.TFile(filePath, fileMode)
149 if not ROOTfile.IsOpen():
151 (
"Can't open ROOT file '{}' in '{}' mode".
format(filePath, fileMode))
154 ROOTpathElements = ROOTpath.split(
'/')
156 for ROOTdirName
in ROOTpathElements:
157 if not ROOTdirName:
continue
158 daughterDir = ROOTdir.GetDirectory(ROOTdirName)
160 daughterDir = ROOTdir.CreateDirectory(ROOTdirName)
162 raise RuntimeError(
"Can't access directory '{}' under '{}'".format
163 (ROOTdirName, ROOTdir.GetPath()))
164 ROOTdir = daughterDir
167 return ROOTfile, ROOTdir
174 Object changing ROOT directory while on scope.
176 The purpose is to make a ROOT directory current only as long as it is needed.
177 The most typical uses of this objects include the automatic restoration of
178 the previous directory as the object falls out of scope.
179 Two methods are supported:
182 def writeEverythingInto(dir, everything):
183 dirChanger = ROOTutils.DirectoryChanger(dir)
184 for item in everything: item.Write()
185 # writeEverythingInto()
187 2. local scope (equivalent to using `activateDirectory()`):
189 with DirectoryChanger(dir):
190 for item in everything: item.Write()
196 if saveDir: self.
saveDir(saveDir)
204 def saveDir(self, ROOTdir): self.oldDir = ROOTdir
207 if self.
newDir: self.newDir.cd()
210 if self.
oldDir: self.oldDir.cd()
220 def __exit__(self, exc_type, exc_value, traceback):
229 Sets a directory with `DirectoryChanger`.
233 dir = outputFile.GetDirectory("plots")
234 with activateDirectory(dir):
235 for plot in plots: item.Write()
244 """Returns the object specified by `classPath` within ROOT module.
246 Throws `AttributeError` if any object in the path is not available.
248 Example: `getROOTclass('geo::GeometryCore')` returns `ROOT.geo.GeometryCore`.
250 classPath = classPath.replace(
'::',
'.').lstrip(
'.')
252 for objName
in classPath.split(
'.'):
253 base = getattr(base, objName)
261 fileListPath:
"path of the file list",
262 comment:
"(default: '#') character used to introduce a comment" =
'#',
263 fileListSuffixes:
"suffix of entries to recursively add file lists" = [],
264 ) ->
"a list of file names":
265 """Returns a list of file names as found in the specified file list.
267 The `fileListPath` path is read as a text file; each line represents a full
269 Empty lines and lines starting with a comment character are ignored.
270 Also if blanks and a comment character are found, the content of the line
271 from the first of those blank characters on is ignored as part of a comment.
272 If `comment` is `None`, this feature is disabled.
274 If file list suffixes are specified, a line ending with any of those suffixes
275 will be considered a file list itself, and recursively expanded.
277 If `fileListPath` can't be read, an exception is raised.
283 with
open(fileListPath,
'r') as fileList:
287 if not line:
continue
289 if line.startswith(comment):
continue
291 words = line.split(comment)
293 for left, right
in zip(words[:-1], words[1:]):
294 if left
and left[-1].isspace():
295 logging.debug(
"Comment starting at line %d between '%s' and '%s'", iLine, left, right)
297 line += comment + right
302 for suffix
in fileListSuffixes:
303 if not line.endswith(suffix):
continue
304 logging.debug(
"Adding content of file list from line %d ('%s')", iLine, line)
305 extra =
expandFileList(line, comment=comment, fileListSuffixes=fileListSuffixes)
306 logging.debug(
"%d entries collected under file list '%s'", len(extra), line)
310 logging.debug(
"Line %d added to the list", iLine)
static std::string format(PyObject *obj, unsigned int pos, unsigned int indent, unsigned int maxlen, unsigned int depth)
def splitROOTpath
File management.
def TVector2ToString
Print vectors easily.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
def ROOTloader
Try to save the command line arguments from unconsiderate ROOT behaviour.
def TLorentzVectorToString
def expandFileList
this is not really specific to ROOT, but we often have ROOT file lists
auto zip(Iterables &&...iterables)
Range-for loop helper iterating across many collections at the same time.
open(RACETRACK) or die("Could not open file $RACETRACK for writing")