How to alter existing entries of TTree?

I would like to update some values stored in a tree.

I can open and read the tree without trouble, but don’t see how to push those changes back out to storage.

My code can be abstracted down to:

   // Open files, find trees
    TFile *f = new TFile(filename,"UPDATE");
    TTree *ct;
    f->GetObject("treename",ct);

   // Register storage
    event_t *event = new event_t;
    ct->SetbranchStatus("*",0); 
    ct->SetbranchStatus("event*",1); 
    ct->SetbranchAddress("event.", &event); 

   // Loop over the tuple
    Long64_t nc = ct->GetEntries();
    for (Long64_t j=0; j<nc; j++){
      ct->GetEntry(j);
      UpdateEntry(entry); // Make changes here
      // Do I need to do anything here? If so what?
    };

   f->Write();

Have I missed something obvious, or do I need to do something clever?

Hi,

TTree is a write-once, read many times structure. Aka. you can not modify the value. Instead of you need to partially clone it into a (new) file.

See the example $ROOTSYS/tutorials/tree/copytree3.C

Cheers,
Philippe

[quote]TTree is a write-once, read many times structure. Aka. you can not modify the value. Instead of you need to partially clone it into a (new) file.

See the example $ROOTSYS/tutorials/tree/copytree3.C
[/quote]

Ahh.

Thanks, Philippe.

So I thought I’d get clever and replace the ntuple in situ with something like this:

    // Open files, find trees 
    TFile *f = new TFile(filename,"UPDATE"); 
    TTree *ct, *nt; 
    f->GetObject("treename",ct); 

   // Register storage 
    event_t *event = new event_t; 
    Float_t otherdata;

    ct->SetbranchStatus("*",1); 

    ct->SetbranchAddress("event.", &event); 
    ct->SetbranchAddress("otherdata", &event); 

    // Move the old tree out of the way, and clone
    ct->SetName(tempname);
    nt = ct->CloneTree(0);      // Here there are two trees with the 
                                           // same name. Is this a problem?
                                           //
                                           // At this point, the new tree shares the
			                      // old tree's branch address
			                      // assignments.
    nt->SetName(treename)

   // Loop over the tuple 
    Long64_t nc = ct->GetEntries(); 
    for (Long64_t j=0; j<nc; j++){ 
      ct->GetEntry(j); 
      UpdateEntry(entry); // Make changes here 
      nt->Fill();
    }; 

    // Cleanup
    if (ct->GetEntries() == nt->GetEntries()) {
      ct->Delete();
    };

    f->Write(); 

While this works—as in I end up with a single TTree named treename containg data different from the start point—it causes the file to grow. I suppose that some of the data belonging to the original TTree is not deleted, and the new TTree’s data is simply appended to the file.

I had been trying to avoid writing to a new file because the tree I wish to change is only one of several large objects stored in the file. I have a suspision that this suggests using multiple files where I have only one right now…

Hi,

ct->Delete(); If you meant to delete the old tree from memory you should use “delete ct;”. If you meant to delete the old tree from the file, you need to do “f->Delete(“treename”);”

[quote]I suppose that some of the data belonging to the original TTree is not deleted, and the new TTree’s data is simply appended to the file. [/quote]Indeed and I think necessarily. To copy the old file you need to read it. When fill in the new tree, it write the basket along the way … and since the old tree data is still occupying space on the file … the new data has no choice but to be appended. Afterward, you can ‘delete’ the old tree data from the file but this does not shrink the size of the file (because shrink the size of the file would require shuffling the block within the file (see User’s Guide for more detail on the ROOT File organization).

Cheers,
Philippe