KAHIBARO
Discord Login Register

13.4. Writing a TTree to a File

Saving event data

Once you have created a TTree, defined its branches, and filled it event by event, the next step is to store it in a ROOT file so that you can reuse the data later without rerunning the whole simulation or reconstruction.

In ROOT, TTrees are written to files via the TFile class. A typical minimal pattern for writing a tree looks like this:

cpp
void write_tree_example() {
   // Create a ROOT file in "RECREATE" mode
   TFile *f = new TFile("events.root", "RECREATE");
   // Create a TTree and some variables
   TTree *t = new TTree("tree", "Simple event tree");
   float energy;
   int   multiplicity;
   // Create branches connected to the variables
   t->Branch("energy",       &energy,       "energy/F");
   t->Branch("multiplicity", &multiplicity, "multiplicity/I");
   // Fill the tree
   for (int i = 0; i < 1000; ++i) {
      energy       = i * 0.1;
      multiplicity = i % 10;
      t->Fill();
   }
   // Write the tree to the file
   t->Write();
   // Close the file
   f->Close();
}

The important steps for saving event data are the creation of the file, writing the tree, and finally closing the file. When you construct the TFile you normally pass a file name and a file mode. Some common modes are:

ModeMeaning
"RECREATE"Create a new file. If it already exists, overwrite it.
"NEW"Create a new file. If it exists already, do not overwrite and fail.
"UPDATE"Open an existing file for reading and writing. Create if it does not exist.
"READ"Open an existing file for reading only.

For writing TTrees, "RECREATE" is usually safe when you are sure you want to start from scratch, for example when you regenerate simulated data. "UPDATE" is more convenient if you plan to add a new tree or additional objects into an existing file.

Once you have filled the tree, calling t->Write() writes the current in‑memory representation of the tree into the file that is currently the directory of the tree. Normally this is the file you just created, but it is possible to have more complex directory structures handled by TDirectory which are covered elsewhere in the course.

If the tree is the main object of the file, you can also rely on writing all objects at once via the file rather than calling Write() explicitly on the tree. The code then becomes:

cpp
TFile *f = new TFile("events.root", "RECREATE");
TTree *t = new TTree("tree", "Simple event tree");
// ... define branches and fill events ...
f->Write();   // writes all objects associated with this file (including t)
f->Close();

Both patterns are widely used. Writing the tree explicitly makes it clear what is being stored, while f->Write() ensures any other histograms, graphs, or configuration objects in the same file are also saved.

To ensure your event data is correctly stored, you must:

  1. Create a TFile in a writeable mode such as "RECREATE" or "UPDATE".
  2. Fill your TTree completely before closing the file.
  3. Call Write() on the tree and/or file before calling Close().

In interactive sessions, remember that objects like TTree and TFile are normal C++ objects. If they go out of scope or ROOT takes ownership in a way you do not intend, writing may behave differently from what you expect. For simple macros and beginner workflows, keeping a pointer to the file and tree and explicitly controlling Write() and Close() is the safest pattern.

Closing files correctly

Closing the ROOT file is not just a formality. It is the moment when ROOT finalizes the file structure, updates internal metadata, and ensures that all buffered data from your tree is fully written to disk. If a program exits without closing the file properly, the file can be incomplete or even corrupted.

The basic rule is very simple. After you have called Write() on the tree or file, you must call Close() on the TFile:

cpp
TFile *f = new TFile("events.root", "RECREATE");
TTree *t = new TTree("tree", "Simple event tree");
// ... define branches, fill events ...
t->Write();   // or f->Write();
f->Close();   // finalize and close the file

The Close() method flushes all remaining buffers to disk and writes the file footer which contains the directory structure and object index. Only after a successful Close() will other ROOT sessions or programs be able to read the file reliably.

If you dynamically allocate the file with new, you can optionally delete it after closing:

cpp
f->Close();
delete f;

The delete is not required for correctness of the file on disk, but it is good practice in longer running programs to free memory. The important call is Close(). In small macros that terminate immediately, leaked memory is less of a concern, but a missing Close() can still leave an unusable .root file.

In standalone C++ programs, you can also manage the file with automatic storage using a local variable. In that case the file will be closed when it goes out of scope, but for clarity and safety it is still common to call Close() explicitly:

cpp
int main() {
   TFile f("events.root", "RECREATE");
   TTree t("tree", "Simple event tree");
   // ... set up branches and fill ...
   t.Write();
   f.Close();  // ensures file is finalized before program ends
   return 0;
}

If you open a file in "UPDATE" mode, write a tree, and then forget to close it, you might see partially updated content when you try to read it back. For long analyses that run on clusters, a missing Close() can mean many hours of processing produce an unreadable output file.

You can perform a quick check that your tree is correctly stored by reopening the file in a fresh ROOT session and listing its contents:

cpp
root[] TFile *f = TFile::Open("events.root");
root[] f->ls();          // list file contents
root[] TTree *t = (TTree*)f->Get("tree");
root[] t->Print();       // inspect the stored tree

If ls() and Get() work as expected, the file was likely closed and written correctly.

Always close your TFile with f->Close() after writing your TTree. A ROOT file that is not properly closed can be incomplete or corrupted, even if it appears on disk with the correct size and name.

By following the sequence create file, fill tree, write tree or file, close file, you ensure that your event data is safely stored and can be reliably read in later analysis steps.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!