Another ROOT mystery: GetEvent

I have a simple macro that fills a “flat” TTree (“flat” in the sense that I fill in a bunch of floats and integers, there’s no class that defines any kind of structure):

  TTree* all = new TTree("all", "all");
  int   vR[3];
  float vB[7];
  float vD[7];
  float vT[8];
  float vZ[5];
  char* formatR = "run/I:evt/I:rs/I";
  char* formatB = "mass/F:masserr/F:chi2/F:pt/F:d0/F:lxy/F:lxyerr/F";
  char* formatD = "mass/F:chi2/F:pt/F:d0/F:lxy/F:lxyerr/F:blxy/F";
  char* formatT = "pt1/F:d01/F:pt2/F:d02/F:pt3/F:d03/F:pt4/F:d04/F";
  char* formatZ = "dr/F:cos/F:mkpi1/F:mkpi2/F:pvz/F";
  all->Branch("R", vR, formatR);
  all->Branch("B", vB, formatB);
  all->Branch("D", vD, formatD);
  all->Branch("T", vT, formatT);
  all->Branch("Z", vZ, formatZ);
  ... (filling arrays vR, vB, vD, vT, vZ) ...
  all->Fill();
  ...

I then write it (TTree called “all”) out to a file named mc.root and I can read it back, plot individual variables with CINT commands (i.e., interactively), etc. However, if I make the above macro code part of compiled library/excutable, run it and try try to plot some variables I get a crash:

root [1]   TFile* fileMC = TFile::Open("mc.root");
root [2]   TTree* treeMC = (TTree*)fileMC->Get("all");
root [3]   treeMC->SetDirectory(0);
root [4]   fileMC->Close();
root [7]   treeMC->Draw("R.run")

 *** Break *** segmentation violation

The same thing happens if I do

all->GetEvent(i);

in a for loop (that’s what the real problem is). Interestingly enough I can get around the problem by starting a TBrowser and doing StartViewer on the tree (I hope this can lit some light on the problem):

root [3] tv__tree = (TTree *) gROOT->FindObject("all");
tv__tree_list->Add(tv__tree);
tv__tree->Draw("R.run")

but the good-old way (with all->GetEvent(i)) does not work… Please tell me what’s going on.

It is obvious that these two lines will generate a seg violation:

root [4] fileMC->Close(); root [7] treeMC->Draw("R.run")
Closing the file deletes treeMC

Rene

[quote=“brun”]It is obvious that these two lines will generate a seg violation:

root [4] fileMC->Close(); root [7] treeMC->Draw("R.run")
Closing the file deletes treeMC

Rene[/quote]
hm-m … but then why would the following only crash in the
last line and not in the second or third?

root [4]   fileMC->Close(); 
root [5]   treeMC->Print();
root [6]   cout << ((int)(treeMC->GetEntries())) << endl;
root [7]   treeMC->Draw("R.run") 

Just by chance, tree->Print or GetEntries do not do any memory management. tree->Draw does.
When an object is deleted, its area in memory is not immediatly deleted by C++. If you invoke a function that only uses its members without allocating new objects, the call may work (but with no guarantee).
This is a general rule (nothing to do with ROOT).

Rene

[quote=“brun”]Just by chance, tree->Print or GetEntries do not do any memory management. tree->Draw does.
When an object is deleted, its area in memory is not immediatly deleted by C++. If you invoke a function that only uses its members without allocating new objects, the call may work (but with no guarantee).
This is a general rule (nothing to do with ROOT).

Rene[/quote]

So I removed the file->Close() statement. Still get a crash:

root [1]   TFile* fileMC = TFile::Open("mc.root"); // signal MC
root [2]   TTree* treeMC = (TTree*)fileMC->Get("all");
root [3]   treeMC->SetDirectory(0);
root [4] treeMC->Draw("R.run")
<TCanvas::MakeDefCanvas>: created default TCanvas with name c1

 *** Break *** segmentation violation

To recap, if I do the above thing I get a crash. If I open mc.root in a TBrowser, click my way to the tree of interest, right click and do “StartViewer”, then tree->Draw() works:

Root >  (same ROOT session as the above crash)
root [5] TBrowser t
root [6] tv__tree = (TTree *) gROOT->FindObject("all");
tv__tree_list->Add(tv__tree);
File name : mc.root

root [6] tv__tree->Draw("R.run")
root [7]

However, if I create mc.root by running the macro interactively (as opposed to compiling the equivalent root code and running an exe), then the code with file->Close() works like a charm …

I seem to have found a solution to my problem though: if in addition to removing file->Close(), I comment out tree->SetDirectory(0), then the crashes are gone …

When you call “treeMC->SetDirectory(0);”, treeMC has no way to find
the branch buffers on disk in case the branch has more than one buffer.Why do you call “fileMC->Close” or “treeMC->SetDirectory(0);” ?

Rene

[quote=“brun”]When you call “treeMC->SetDirectory(0);”, treeMC has no way to find
the branch buffers on disk in case the branch has more than one buffer.Why do you call “fileMC->Close” or “treeMC->SetDirectory(0);” ?

Rene[/quote]
Well, my philosophy is this: “open the file, get the tree, close the file, forget about the file, play with the tree” as opposed to “open the file, get the tree, play with the tree, don’t forget to close the file after you’re done playing with the tree”. I thought that
SetDirectory(0) is exactly the trick I was looking for in order to implement my philosophy … looks like it is not. What is then the intended use of the SetDirectory(0)?

To implement what you want you have to do:

gROOT->cd(); // Insure that the current directory is not a ROOT file TTree *myMemoryTree = oldTree->CloneTree(); // now I can delete the file. This will load up all the data from the TTree into memory, assuming that you have enough memory. This will of course work only for smallish trees.

SetDirectory is usually used just after the creation of a new object to prevent it from being stored on file (and not to read the object from the file).

Cheers,
Philippe.