Updating Trees in Already Existing Rootfiles

Hello Rooters,

Here is my dilemma:

I have a rootfile with a tree that already exists called “MCA927”, in this tree there are many branches. I then run a root macro to add branches to this tree. But, here is the catch, every time I run my macro it creates these branches over and over again. I want these branches to be written once and if I do run it again, then I would like them to be overwritten. My code is below for reference. Thanks a bunch!!

void MCA927RawViewer(char filename[130], bool ToCal){
	TFile *file = new TFile(filename, "update");  //update appends to the rootfile
	TTree *t = (TTree*)gDirectory->Get("MCA927");
	
	UInt_t spLength = 0;

	Double_t liveTime = 0.0;
	Double_t totLiveTime = 0.0;
	
	Double_t realTime = 0.0;
	Double_t totRealTime = 0.0;
	Int_t runNumber = 0;
	Int_t nentries = Int_t(t->GetEntries());

	//new branches to add to the tree
	TBranch *TotalLiveTime = t->Branch("totLiveTime",&totLiveTime,"totLiveTime/D");
	TBranch *TotalRealTime = t->Branch("totRealTime",&totRealTime,"totRealTime/D");
	
	t->SetBranchAddress("spLength",&spLength);
	t->GetEntry(0);
	const UInt_t kSpLength = spLength;
	UInt_t spectrum[kSpLength];	
	
	TString histname_1 = filename;
	TString histname = "(File: " + histname_1 + "): Raw Counts vs. Bin Number";
	TH1F *uncal = new TH1F("uncal", histname , spLength, 0.0, spLength);
	
	t->SetBranchAddress("spectrum", &spectrum);
	t->SetBranchAddress("spLength", &spLength);
	t->SetBranchAddress("runNumber",&runNumber);	
	t->SetBranchAddress("liveTime", &liveTime);
	t->SetBranchAddress("realTime", &realTime);
	
	//the outer loop loops over the sub runs, the inner loop adds the bin content from each sub-run
	for (Int_t j = 0; j < nentries; j++) {
		t->GetEntry(j);
		totLiveTime += liveTime;
		totRealTime += realTime;
		for (UInt_t i = 0; i < kSpLength; i++) {
			uncal->AddBinContent(i,spectrum[i]);
		}
	}

	TotalLiveTime->Fill();
	TotalRealTime->Fill();
	uncal->GetYaxis()->SetTitle("Counts");
	uncal->GetXaxis()->SetTitle("Bin Number");
	uncal->GetXaxis()->CenterTitle();
	uncal->GetYaxis()->CenterTitle();	
	
	uncal->Write("", TObject::kOverwrite);  //overwrite here so we dont keep creating new keys
  t->Write("", TObject::kOverwrite);
	t->Print();
	delete file;
	if (ToCal == true) {CalibrateAndSave(filename,kSpLength);}
}//end program

Hi,

one of the fundamental concepts of TTrees is that they are write once, read many. I.e. you cannot change a TTree. Instead, create a new TTree with only the updated branches and put them into a separate file. When you want to analyze the old TTree overlayed with the updated branches you simply add the old TTree as a friend of the new one.

Cheers, Axel.

I also found myself recently in the situation of wanting to overwrite a few branches in an existing ttree. I think I’ve finally been able to accomplish this in the way Axel suggests:
[ul]create a new file,
then CloneTree() to create new tree,
then SetBranchAddress() to new variables for the branches you want to change,
then loop through entries of the old tree and set the new variables as you like, doing a tree.Fill() as you go
then save the new tree[/ul]

I do this in a script addJetPassingCuts.py, also shown here which basically updates a few branches that are arrays related to jet variables.

[code]#

Run by typing:

python addJetPassingCuts.py

Creates new TTree in new TFile storing

only jets that meet requirements in a

new array of jets.

Michael Anderson

Jan 29, 2010

from ROOT import TFile, TTree # Import any ROOT class you want
from array import array # used to make Float_t array ROOT wants
from datetime import datetime # used in output filename
from math import sqrt
import sys

########################################

Variables

ttreeName = “NTuples/Analysis” # TTree name in all files

listOfFiles = [“testing.root”]
#“MinimumBias_BeamCommissioning09-Jan23ReReco_jetCuts.root”,
#“MinBias_Summer09-STARTUP3X_V8P_900GeV-v1_jetCuts.root”]

END of Varibles

########################################

########################################

Extra Functions

def deltaPhi(phi1, phi2):
dPhi = abs(phi1-phi2)
if dPhi<=3.141592653:
return dPhi
else:
return 6.2831853-dPhi

def deltaR(eta1, phi1, eta2, phi2):
dEta = eta1-eta2
dPhi = deltaPhi(phi1, phi2)
return sqrt(dEtadEta+dPhidPhi)
########################################

########################################

Main function for looping over files

for fileName in listOfFiles:
fileOriginal = TFile(fileName, “read”) # Open TFile for read-only
if fileOriginal.IsZombie():
print “Error opening %s, exiting…” % fileName
sys.exit(0)
print “Opened %s” % fileName

ttreeOriginal = TTree()                   # Create empty TTree variable, and
try:                                      # try to get TTree from file.
    fileOriginal.GetObject(ttreeName, ttreeOriginal) 
except:
    print "\nError: %s not found in %s, exiting..." % (ttreeOriginalName, fileName)
    sys.exit(0)
print "found %s." % ttreeName

fileNameNew = fileName[0:-5] + "_%s.root" % datetime.now().strftime("%b%d_%I%p")
print "Creating new file,\n  %s" % fileNameNew
fileNew  = TFile(fileNameNew, "recreate") # New file to write to

ttreeNew = ttreeOriginal.CloneTree(0)     # Clone TTree without copying entries

# Add those variables into the TTree
print "Adding new branches:\n",
maxNumNewJets = 2
newJetPt   = array( 'f', maxNumNewJets*[0] )
ttreeNew.SetBranchAddress("jetPt",newJetPt)
newJetEta  = array( 'f', maxNumNewJets*[0] )
ttreeNew.SetBranchAddress("jetEta",newJetEta)
newJetPhi  = array( 'f', maxNumNewJets*[0] )
ttreeNew.SetBranchAddress("jetPhi",newJetPhi)
newJetEmEnergyFraction = array( 'f', maxNumNewJets*[0] )
ttreeNew.SetBranchAddress("emEnergyFraction",newJetEmEnergyFraction)
newJetFHPD = array( 'f', maxNumNewJets*[0] )
ttreeNew.SetBranchAddress("fHPD",newJetFHPD)
newJetNJets = array('i', [0] )
ttreeNew.SetBranchAddress("nJets",newJetNJets)

# Loop over all entries in the old ttree
numOfEvents = ttreeOriginal.GetEntries()
status = 10
for n in xrange(numOfEvents):
    if not (n % (numOfEvents/10)):
        print "  %i" % status            # Print countdown to finish
        status -= 1
    
    newJetNJets[0] = 0                   # Record num of jets in event passing cuts in this event
    for j in range(0, maxNumNewJets):
        newJetPt[j]   = 0.0
        newJetEta[j]  = 0.0
        newJetPhi[j]  = 0.0
        newJetEmEnergyFraction[0] = 0.0
        newJetFHPD[j] = 0.0
    
    j = 0   # Index for new jet variable arrays
    ttreeOriginal.GetEntry(n)
    for i in range(0, ttreeOriginal.nJets):      # Loop over top jets until we find one passing cuts
        if ttreeOriginal.jetPt[i] < 5.0: break
        if (ttreeOriginal.emEnergyFraction[i]>0.01) and (ttreeOriginal.fHPD[i]<0.98) and \
               abs(ttreeOriginal.PHOLEAD_eta-ttreeOriginal.jetEta[i])>0.2 and \
               deltaPhi(ttreeOriginal.PHOLEAD_phi, ttreeOriginal.jetPhi[i])>0.2:  # Jet Cuts
            # Found a jet that passes cuts
            newJetNJets[0] += 1
            if (j < maxNumNewJets):
                newJetPt[j]   = ttreeOriginal.jetPt[i]
                newJetEta[j]  = ttreeOriginal.jetEta[i]
                newJetPhi[j]  = ttreeOriginal.jetPhi[i]
                newJetEmEnergyFraction[j] = ttreeOriginal.emEnergyFraction[i]
                newJetFHPD[j] = ttreeOriginal.fHPD[i]
                j += 1

    ttreeNew.Fill()  # Fill the new tree

print "done.\nCreated\n  %s\n" % fileNameNew
ttreeNew.AutoSave()
fileOriginal.Close()
fileNew.Close()[/code]