I am trying to write a TObjArray of TTrees in ROOT 6.02.03 (x86_64-slc6-gcc48-opt). Starting from a TFile with several trees and running the code below, some of vectors are not readable / empty when doing a Scan. Am I doing something wrong?
In previous versions, the code that created this TObjArray (instead of writing the trees individually) used to work fine. The files can be found on /afs/cern.ch/user/b/blenzi/public/MVACalib.
Thanks in advance,
Bruno
import ROOT
f = ROOT.TFile('MVACalib_electron.weights.root')
fout = ROOT.TFile('MVACalib_electron.weights1.root', 'recreate')
opt = ROOT.TObject.kSingleKey
o = ROOT.TObjArray()
for i in range(102):
tree = f.Get('BDT%s' % i)
_ = o.Add( tree.CloneTree() )
for key in f.GetListOfKeys():
obj = f.Get( key.GetName() )
_ = fout.cd()
# do not write the TTrees again
if isinstance(obj, ROOT.TTree):
continue
# copy other TObjArrays
elif isinstance(obj, ROOT.TObjArray):
_ = obj.Clone().Write(key.GetName(), opt)
else:
_ = obj.Clone().Write()
fout.cd()
_ = o.Write('trees', opt)
fout.Close()
What is the purpose of storing the TTree object as part of a TObjArray. When being created (during TTree::CloneTree) they are automatically added to the list of object of the TFile and thus already part of a collection.
Why are you calling Clone in _ = obj.Clone().Write(key.GetName(), opt)
TFile* MVACalib_electron.weights1.root
KEY: TObjArray variables;1 An array of objects
KEY: TObjArray formulae;1 An array of objects
KEY: TObjArray shifts;1 An array of objects
KEY: TH2Poly hPoly;1 NoTitle
KEY: TObjArray trees;1 An array of objects
where trees, shifts and variables have the same number of entries and are aligned.
The issue is that your use case is in between two supported use case. One is the most common one where the TTree ‘belongs to’ (is attached to) a TDirectoryFile (for example the TFile itself) and one, less common, where the TTree is not attached to a TDirectoryFile is keeps all its data in memory. [As is in your example the output TTree are actually insert in both the TObjArray and the TFile and if you make a call to fout->Write() you would end up with (correct) copy of the TTree header in the TFile list of keys.
To properly handle you case you need to add several tweaks to work around the normal assumptions.[code]import ROOT
f = ROOT.TFile(‘MVACalib_electron.weights.root’)
fout = ROOT.TFile(‘MVACalib_electron.weights2.root’, ‘recreate’)
opt = ROOT.TObject.kSingleKey
o = ROOT.TObjArray()
for i in range(102):
tree = f.Get(‘BDT%s’ % i)
otree = tree.CloneTree()
otree.FlushBaskets() # make sure all baskets are stored individually
fout.Remove(otree) # avoid double ownership
_ = o.Add( otree )
for key in f.GetListOfKeys():
obj = f.Get( key.GetName() )
_ = fout.cd()