Load TTree from file and store in different file

Hi
I am trying to figure out how I can save a TTree to a file different from the one where I loaded the TTree.
Lets say the tree was stored in a file called “myTree.root” and (after modifiying some entries) I want to write it to a file called “myTree2.root”.
Right now the only possible solution I am aware of is to create a second tree with the same structure in the new file and then copy all entries. However, I would like to avoid creating a second tree and also I dont think that this is the “standard” way of saving a file in a different file…

Also I am experiencing annyoing problems with write access. I am using windows 7 and root 5.30. Whenever i want to write to an existing file, i get an error : “…file is not writeable…” or “…file not openened in write mode…”. I checked the permissions for the folder, but giving full access does not help.

[quote]Whenever i want to write to an existing file[/quote]Did you open the file in ‘update’ mode?

[quote]Right now the only possible solution I am aware of is to create a second tree with the same structure in the new file and then copy all entries.[/quote]TTree are intentionally write-once-read-many-time structure, i.e. you can not modify the existing value in a TTree and thus the only way to ’ (after modifiying some entries)’ is to copy the TTree to a new file. There are a few options on how to do so (see $ROOTSYS/tutorials/tree/copytree*).

(In particular if you need to change a particular value for all entries) An alternative is to create a new TTree containing only the values (for all entries) needing to be fixed and when reading you should make this new TTree a ‘friend’ of the old one.

Cheers,
Philippe.

I tried different options and i got different error messages, I dont really remember…
I have to take a look again. But before i have another question.

When i want to use the code created by TTree->MakeClass() to create a new tree would it be the proper way to…

  1. supply another constructor, who doesnt call the Init(tree) method but a modified one, where all SetBranchAdress(…) calls are replaced by Brach(…)

  2. in my main analysis code i open a file (e.g. TFIle* myFile(“filename.root”)), then i call my new constructor and fill the tree, and finally i write the tree via myFile->Write().

thanks for help

Hi,

This sounds reasonable. To Open the output file use either TFIle* myFile(“filename.root”,“NEW”) or “RECREATE” or “UPDATE”.

Cheers,
Philippe.

Hi
thanks for the answers so far. I dont have problems anymore with writing the files, not sure what i did wrong in the first place :wink:

I implemented the way of creating a tree from scratch by using the MakeClass output as described above and it works nicely.
Now i am not sure how to proceed with my next step. I would like to use the same class to work on trees with slightly different contents. Each event contains a signal,

When creating a new tree i call

to create the branch.
My question is:
How can i change the above two lines of code to have different dimensions (first dimension fixed but second variable e.g. signal[5][100]) stored in the tree.

If it was one dimensional,

I think it would be ok to simply use

,where i replace N by the number of bins i want to store (via sprintfing). However in the 2d case I guess that i have to allocate the memory dynamically…i have to admit that I am rather new to c++ and maybe this post would better go into a c++ forum, however any help is welcome :slight_smile:

Hi,

If you want to fix the dimension for a whole TTree. You could do:this->b_signal = fChain->Branch("signal" ,signal ,TString::Format("signal[5][%d]/D",N));however you then need to very careful on how you access signal (since now the ‘semantic’ and the real dimension are different … accessing signal[2][3] would not be the 3rd element of the 2nd row (well unless N matches exactly the size …).
One thing you can do is define signal like:Float_t signal[some_very_large_number_accomodating_all_use_case];and accessing via// Set the value of signal[2][3]; signal[ 2*row_size + 3 ] = value;and defining the branch:this->b_signal = fChain->Branch("signal" ,signal ,TString::Format("signal[%d][%d]/D",column_size,row_size));

Cheers,
Philippe.

Hi
thanks for the help so far. I decided to allocate the memory dynamically and my code for the tree looks like this…

#ifndef MyTree_h
#define MyTree_h
#include <TROOT.h>
#include <TChain.h>
#include <TFile.h>

class MyTree {
public :
   TTree*        fChain;   //!< pointer to the analyzed TTree or TChain                            
   Int_t           fCurrent; //!< current Tree number in a TChain      
   Int_t           N_seg;
   Int_t           N_bins;   
   // Declaration of leaf types
   Double_t**        signal;   
   // List of branches
   TBranch        *b_signal;   //!
   MyTree(Int_t nseg,Int_t nbins);
   MyTree(TTree *tree);
   virtual ~MyTree();
   [...]
};
#endif
#ifdef MyTree_cxx
MyTree::MyTree(Int_t nseg,Int_t nbins){
   TTree* tree = new TTree("MyTree","MyTree");
   tree->GetUserInfo()->Add(new TParameter<Int_t>("N_seg",nseg));
   tree->GetUserInfo()->Add(new TParameter<Int_t>("N_bins",nbins));
   this->N_seg = nseg;
   this->N_bins = nbins;
   signal = new double*[N_seg];
   for (int i=0;i<N_seg;i++){signal[i] = new double[N_bins];} 
   InitNew(tree);
}
MyTree::MyTree(TTree *tree){
   if (tree == 0) {return;}
   cout << tree->GetUserInfo()->Print() << endl;
   //cout << tree->GetUserInfo()->Last()->GetVal() << endl;
   Init(tree);
}

[...]

void MyTree::InitNew(TTree *tree){
   // Set branch addresses and branch pointers
   if (!tree) return;
   fChain = tree;
   fCurrent = -1;
   fChain->SetMakeClass(1);
   this->b_signal    = fChain->Branch("signal"   ,signal    ,TString::Format("signal[%d][%d]/D",N_seg,N_bins));
   Notify();
}
void MyTree::Init(TTree *tree){
   if (!tree) return;
   fChain = tree;
   fCurrent = -1;
   fChain->SetMakeClass(1);
   cout << tree->GetUserInfo()->Print() << endl;
   // TODO : allocate memory
   fChain->SetBranchAddress("signal", signal, &b_signal);
   Notify();
}
[...]
#endif // #ifdef MyTree_cxx

The first constructor is used to create an empty tree with custom size of the signal. The size should be stored in the trees UserInfo. However, when I use “normal” constructor to load the tree from a file, the UserInfo is empty (size=0).

Here is the code that i used to create and save the tree and then load it again.

void TestTree(){ TFile* res = new TFile("TEST.root","RECREATE"); MyTree* t = new MyTree(3,3); res->Write(); } void TestResultTree2(){ TChain* c = new TChain("MyTree","MyTree"); c->Add("TEST.root"); c->GetUserInfo()->Print(); MyTree* t = new MyTree(c); }

In a different case it worked well to use GetUserInfo() to store some info but here i dont know what I am doing wrong. All above calls to Print() tell me that the list is empty…

Hi,

I don’t see anything odd in those code snippets, so I suspect the problem might in the code that is not listed. If you still have this problem, can you provide a complete running example showing the problem?

Cheers,
Philippe.

Hi
im sorry for posting unexecutable code… however, the only thing that was missing to make it run was the (empty) Notify() method. Meanwhile I found a way how to read the tree and getting the correct UserInfo, but still i dont really understand the behaviour.

Here is again the content of my MyTree.h (just for the sake of completeness, its the same as above with minor changes)

    #ifndef MyTree_h
    #define MyTree_h
    #include <TROOT.h>
    #include <TChain.h>
    #include <TFile.h>

    class MyTree {
    public :
       TTree*        fChain;   //!< pointer to the analyzed TTree or TChain                           
       Int_t           fCurrent; //!< current Tree number in a TChain     
       Int_t           N_seg;
       Int_t           N_bins;   
       // Declaration of leaf types
       Double_t**        signal;   
       // List of branches
       TBranch        *b_signal;   //!
       MyTree(Int_t nseg,Int_t nbins);
       MyTree(TTree *tree);
       virtual ~MyTree();
    };
    #endif

    MyTree::MyTree(Int_t nseg,Int_t nbins){
       TTree* tree = new TTree("MyTree","MyTree");
       tree->GetUserInfo()->Add(new TParameter<Int_t>("N_seg",nseg));
       tree->GetUserInfo()->Add(new TParameter<Int_t>("N_bins",nbins));
       this->N_seg = nseg;
       this->N_bins = nbins;
       signal = new double*[N_seg];
       for (int i=0;i<N_seg;i++){signal[i] = new double[N_bins];}
       InitNew(tree);
    }
    MyTree::MyTree(TTree *tree){
       if (tree == 0) {return;}
       cout << tree->GetUserInfo()->Print() << endl;
       //cout << tree->GetUserInfo()->Last()->GetVal() << endl;
       Init(tree);
    }
    void MyTree::InitNew(TTree *tree){
       // Set branch addresses and branch pointers
       if (!tree) return;
       fChain = tree;
       fCurrent = -1;
       fChain->SetMakeClass(1);
       this->b_signal    = fChain->Branch("signal"   ,signal    ,TString::Format("signal[%d][%d]/D",N_seg,N_bins));
       Notify();
    }
    void MyTree::Init(TTree *tree){
       if (!tree) return;
       fChain = tree;
       fCurrent = -1;
       fChain->SetMakeClass(1);
       cout << tree->GetUserInfo()->Print() << endl;
       // TODO : allocate memory
       fChain->SetBranchAddress("signal", signal, &b_signal);
       Notify();
    }    
    void MyTree::Notify(){}

And here is the code that i use to write the tree (TestTree()) and read it (TestTree2() and TestTree3())

#include "MyTree.h" void TestTree(){ TFile* res = new TFile("TEST.root","RECREATE"); MyTree* t = new MyTree(3,3); res->Write(); } void TestTree2(){ TChain* c = new TChain("MyTree","MyTree"); c->Add("TEST.root"); c->GetUserInfo()->Print(); MyTree* t = new MyTree(c); } void TestTree3(){ TFile *f = new TFile("TEST.root"); TTree *t1 = (TTree*)f->Get("MyTree"); t1->GetUserInfo()->Print(); MyTree* t = new MyTree(t1); t->fChain->GetUserInfo()->Print(); }

And this is what i get as output…

root [0] .L MyTreeRun.c
root [1] TestTree()
root [2] TestTree2()
Collection name='UserInfo', class='TList', size=0
Collection name='UserInfo', class='TList', size=0
0
Collection name='UserInfo', class='TList', size=0
0
root [3] TestTree3()
Collection name='UserInfo', class='TList', size=2
  TParameter<int>       N_seg = 3
  TParameter<int>       N_bins = 3
Collection name='UserInfo', class='TList', size=2
  TParameter<int>       N_seg = 3
  TParameter<int>       N_bins = 3
0
Collection name='UserInfo', class='TList', size=2
  TParameter<int>       N_seg = 3
  TParameter<int>       N_bins = 3
0
Collection name='UserInfo', class='TList', size=2
  TParameter<int>       N_seg = 3
  TParameter<int>       N_bins = 3

I guess its my misunderstanding of how to use TChains. It seems as the UserInfo is lost/not read when I read the tree from the file via a TChain. Only when I open the TTree “manually” from the file the UserInfo is correct. However, when I read the tree in this way i cannot (at least i dont know how) read from multiple files.

Hi,

Indeed the access is slightly different in this case. To get the actual information you need to access the GetUserInfo for the underlying current TTree of the TChain:c->GetTree()->GetUserInfo()->Print();

Cheers,
Philippe.

Hi
thanks again. I tried the GetTree() method but it returns a null-pointer.

void TestTree2(){
    TChain* c = new TChain("MyTree","MyTree");
    c->Add("TEST.root/MyTree");
    c->GetUserInfo()->Print();
    if (c->GetTree()== 0){cout << "NULL" << endl;}
    c->GetTree()->Print();
    c->GetTree()->GetUserInfo()->Print();
    MyTree* t = new MyTree(c);
}

running this code results in…

root [4] TestTree2()
Collection name='UserInfo', class='TList', size=0
NULL
Error: illegal pointer to class object GetTree() 0x0 3016  C:\[...]\MyTreeRun.c(14)
*** Interpreter error recovered ***

I am sure that the tree in the file is “ok” as I get the correct output when calling the constructor with the TTree (as in TestTree3()). I added the “/MyTree” to the filename when adding the file to the chain but also this didnt help.

Hi,

GetTree will return 0 until one entry is read (i.e. ch->LoadTree or ch->GetEntry is called) and from then on it will return the address of the TTree in the file being looked at.

Cheers,
Philippe.