Moving TTrees into TDirectories

I have a .root file with a bunch of trees named “something/something_else”. I want to sort these into TDirectories named “something” to make it easier to navigate. However, when I run my code, the file doesn’t change–the directories do not persist, everything is as it was. What am I doing wrong?

import ROOT
from ROOT import TFile, TDirectory, TTree

f = TFile.Open("<path to root file>",'UPDATE')
trees = []
listofsensornames = []
for k in f.GetListOfKeys():
    t = k.ReadObj()
    trees.append(t)
    tsname = t.GetName().split('/')[0]
    if not tsname in listofsensornames:
        listofsensornames.append( tsname )
listofdirectories = []
for sn in listofsensornames:
    f.cd()
    d = TDirectory(sn,sn)
    listofdirectories.append(d)
for t in trees:
    tsname = t.GetName().split('/')[0]
    for d in listofdirectories:
        if d.GetName() == tsname:
            t.SetDirectory(d)
for d in listofdirectories:
    f.cd()
    d.Write()
f.Write()
f.Close()

I think you will have to create a new file and copy the tree in the new file/directory structure…

Okay, I tried that, but the new file is just empty:

import ROOT
from ROOT import TFile, TDirectory, TTree

fold = TFile.Open("<path to root file>",'READ')
trees = []
listofsensornames = []
for k in fold.GetListOfKeys():
    t = k.ReadObj()
    trees.append(t)
    tsname = t.GetName().split('/')[0]
    if not tsname in listofsensornames:
        listofsensornames.append( tsname )
import pdb; pdb.set_trace()
fnew = TFile.Open("<path to new root file>",'RECREATE')
listofdirectories = []
for sn in listofsensornames:
    fnew.cd()
    d = TDirectory(sn,sn)
    listofdirectories.append(d)
for t in trees:
    tsname = t.GetName().split('/')[0]
    tnewname = t.GetName().split('/')[1]
    tnew = t.CloneTree()
    tnew.SetName(tnewname)
    for d in listofdirectories:
        if d.GetName() == tsname:
            tnew.SetDirectory(d)
for d in listofdirectories:
    fnew.cd()
    d.Write()
fnew.Write()
fnew.Close()
fold.Close()

Please look at the $(ROOTSYS)/tutorials/tree/copytree.C tutorial

Yeah, right after I posted I realized I wasn’t writing the new trees. But now, while the new trees get written, they are still not stored in directories:

import ROOT
from ROOT import TFile, TDirectory, TTree

fold = TFile.Open("<path to root file>",'READ')
trees = []
listofsensornames = []
for k in fold.GetListOfKeys():
    t = k.ReadObj()
    trees.append(t)
    tsname = t.GetName().split('/')[0]
    if not tsname in listofsensornames:
        listofsensornames.append( tsname )
fnew = TFile.Open("<path to new root file>",'RECREATE')
listofdirectories = []
for sn in listofsensornames:
    fnew.cd()
    d = TDirectory(sn,sn)
    d.Write()
    listofdirectories.append(d)
for t in trees:
    tsname = t.GetName().split('/')[0]
    tnewname = t.GetName().split('/')[1]
    tnew = t.CloneTree()
    tnew.SetName(tnewname)
    for d in listofdirectories:
        if d.GetName() == tsname:
            tnew.SetDirectory(d)
            tnew.Write()
            fnew.cd()
            fnew.Write()
fnew.Write()
fnew.Close()
fold.Close()

Hi,

did you try the rootcp utility?

Cheers,
D

I’ll cross-check and will come back to you

As Danilo proposed, you could try rootcp. And this code works also fine:

   TTree *oldtree;
   gSystem->Load("$ROOTSYS/test/libEvent");
   TFile *oldfile = TFile::Open("$ROOTSYS/test/Event.root");
   oldfile->GetObject("T", oldtree);
   TFile *newfile = TFile::Open("small.root","recreate");
   newfile->mkdir("something");
   newfile->cd("something");
   TTree *newtree = oldtree->CloneTree();
   newfile->Write();
   delete oldfile;
   delete newfile;

Thanks, bellenot, that works:

import ROOT
from ROOT import TFile, TDirectory, TTree

fold = TFile.Open("/eos/lhcb/user/m/mwilkins/Testbeam/June2017/fit_results_copy.root",'READ')
trees = []
listofsensornames = []
for k in fold.GetListOfKeys():
    t = k.ReadObj()
    trees.append(t)
    tsname = t.GetName().split('/')[0]
    if not tsname in listofsensornames:
        listofsensornames.append( tsname )
fnew = TFile.Open("/eos/lhcb/user/m/mwilkins/Testbeam/June2017/fit_results_copy_new.root",'RECREATE')
for sn in listofsensornames:
    fnew.cd()
    fnew.mkdir(sn)
for t in trees:
    tsname = t.GetName().split('/')[0]
    tnewname = t.GetName().split('/')[1]
    for sn in listofsensornames:
        if sn == tsname:
            fnew.cd(sn)
            tnew = t.CloneTree()
            tnew.SetName(tnewname)
            fnew.Write()
            fnew.cd()
fnew.Write()
fnew.Close()
fold.Close()

It is unclear from the rootcp documentation how one would use it to copy trees into specific directories within the new file, much less create directories in said file.

I don’t understand why the declare-TDirectory-SetDirectory approach failed, but I’ve got working code now, so who cares.

1 Like

Hi,

great that you solved this!
To create directories, you can use rootmkdir :wink:

Cheers,
D

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.