Copying a tree

Hi,

I try to copy a rather complicated tree (which has TClonesArrays and tons of branches). However so far I have been quite unsuccessfull. Here’s what I’m doing:

data::Loop() {
TFile* output=new TFile(“output.root”,“RECREATE”);
TTree* newtree = (TTree*)fChain->GetTree()->CloneTree(0);

Int_t nbytes = 0, nb = 0;
for (Int_t jentry=0; jentry<nentries;jentry++) {


newtree->Fill();
}
newtree->Write();
output->Write();
output->Close();
}

For each branch I get an error message like “Error in TBranchElement::Fill: attempt to fill branch LeadMuons while addresss is not set”, but I cannot find an obvious error. I’ve already checked the tutorials copytree and copytree2 for help, but also no success. I’m using root version Version 3.05/00.

Thanks for help!
Carsten

If you want to copy a Tree without setting the branch addresses move to version 3.10/02 or newer.
See TTree::CopyTree documentation

Rene

Hi,

I still can’t get it to work. I’ve switched to root version 3.10/02d, and I’m now doing the following within my loop method:

TFile newfile = new TFile(“small.root”,“recreate”);
TTree
newtree = (TTree*)fChain->GetTree()->CloneTree();
Int_t nbytes = 0, nb = 0;
for (Int_t jentry=0; jentry<nentries;jentry++) {
Int_t ientry = LoadTree(jentry);
if (ientry < 0) break;
nb = fChain->GetEntry(jentry); nbytes += nb;

newtree->CopyTree("LETM_Nelectron>1");

}
newtree->Write();
newfile->Write();
newfile->Close();

However I can’t even get it compiled. I just get error messages from g++ like:
main.o: In function main': main.o(.text+0x1c1): undefined reference toTStorage::ObjectAlloc(unsigned int)'
main.o(.text+0x1da): undefined reference to TChain::TChain(char const *, char const *)' main.o(.text+0x2e3): undefined reference toTString::TString(char const *)‘
main.o(.text+0x2ff): undefined reference to TString::TString(char const *)' main.o(.text+0x333): undefined reference toTString::Replace(int, int, char const *, int)’

Thanks for any help!
Carsten

It looks like you have a mismatch in your PATH, LD_LIBRARY_PATH,
mixing code compiled with different compilers.

Rene

Hi,

I’ve got the library paths etc. sorted out, and now everything compiles smoothly. However it still doesn’t run, I get the following error message(s):

Error in TBranchElement::Fill: attempt to fill branch obj while addresss is not set
Error in TBranchElement::Fill: attempt to fill branch AllElectrons while addresss is not set
:
:

Debugging the old fashioned way by inserting some cout’s into the code I’ve found that the problem occurs at the following point:

cout << “a”<< endl;
TFile newfile = new TFile(“small.root”,“recreate”);
TTree
newtree = (TTree*)fChain->GetTree()->CloneTree();
cout << “b”<< endl;

‘a’ is printed on the screen, but ‘b’ never appears. So something is wrong the way I’m doing it (see also message above). But what??

Thanks for help.
Carsten

As indicated in my previous mail and also indicated by the error message, you must set the top level address before copying the tree.
See example in tutorial copytree.C

Rene

Hi,

the top level address is exactly the problem. The example works fine, but my tree is much more complicated…

The was generated tree in the following way:

header file
TTree *_tsm;
TSM_AElectrons *AllElectrons;
TSM_AJets05 *AllJets05;
etc.

cpp file
AllElectrons = new TSM_AElectrons;
AllJets05 = new TSM_AJets05;
etc.

_tsm = new TTree(“tsm”,“tsm”);
cn_objects = new ObjectsClass(); //needed for taus, tracks and CalCells
_tsm->Branch(“obj”,“ObjectsClass”,&cn_objects);
_tsm->Branch(“AllElectrons”,“TSM_AElectrons”, &AllElectrons);
etc.

So how would I have to tell my new program the top level address? I hope that I don’t need the header files with the full declaration of e.g. “TSM_AElectron”. Because these header files include tons of other header files - which is a nearly impossible task to figure out…

Cheers,
Carsten

Hi,

Hopefully this is just a typo but you wrote:[code]
TTree* newtree = (TTree*)fChain->GetTree()->CloneTree();
Int_t nbytes = 0, nb = 0;
for (Int_t jentry=0; jentry<nentries;jentry++) {
Int_t ientry = LoadTree(jentry);
if (ientry < 0) break;
nb = fChain->GetEntry(jentry); nbytes += nb;

newtree->CopyTree("LETM_Nelectron>1"); 

}
[/code]

is very unlikely to be want you want. This does another copy of the new tree!!! I think you meant:

Now, of course, you need to have access to LETM_Nelectron. Your easiest bet is probably to use a class create with MakeClass from your tree.
Cheers,
Philippe

Hi,

I’ve implemented your ideas, but still I’m struggling with the address of the branches. Actually now we’re back to the starting point:

Error in TBranchElement::Fill: attempt to fill branch AllElectrons while addresss is not set

I already went through the MakeClass steps and produced a base clase, otherwise I wouldn’t be able to access any variables in my tree in the first place. But how do I set the address (see error above) correctly? All branch addresses are already set in the file produced by MakeClass, so what more do I have to do?

Cheers,
Carsten

Hi Carsten,

Humm … The problem is that the MakeClass skeleton throws off the default memory setting mechanism (making it unsatisfying for CloneTree).

In your simple case, you can actually do away from the MakeClass and simplify your code greatly:TFile *newfile = new TFile("small.root","recreate"); TTree* newtree = (TTree*)fChain->CopyTree("LETM_Nelectron>1"); newfile->Write(); newfile->Close();
That’s it :slight_smile:

Now, for a more complex case, you can do (again without MakeClass):[code]LETM_Nelectron *elec = 0;
fChain->SetBranchAddress(“LETM_Nelectron”,&elec)

TFile newfile = new TFile(“small.root”,“recreate”);
TTree
newtree = (TTree*)fChain->CloneTree();
Int_t nbytes = 0, nb = 0;
for (Int_t jentry=0; jentry<nentries;jentry++) {
Int_t ientry = LoadTree(jentry);
if (ientry < 0) break;
nb = fChain->GetEntry(jentry); nbytes += nb;

if (elec && elec->SomeValue()>somevalue) {
newtree->Fill();
}
}
newtree->Write();
newfile->Write();
newfile->Close();
[/code]
This assumes that you have the compiled code/shared library for LETM_Nelectron.

If you do not have this libray, you should take a look at the code in TTreePlayer::CopyTree and use a TTreeFormula.

Cheers,
Philippe.

Hi Philippe,

your first solution didn’t work. I tried to do on the root commad line, but I just get the reply that the address for the branches is not set. Since you said that I need the shared library of my class definition for that, this is not an option for me (for various reasons I’m not able to do a shared library).

The second solution also doesn’t work due to the same reason.

I’ve already looked at the CopyTree method and the accompanying examples. However here I also have to set the branch addresses resp. load the shared library. If not than I just don’t understand it.

I’m wondering if it’s not possible to write out a subsample of my events using only the information provided by MakeClass. The resulting two MakeClass files have all the necessary information, so why shouldn’t that be possible? As far as I understand it it’s just a matter of getting the branch addresses correctly. So can somebody show me how to do that?

Cheers,
Carsten

Hi,

This is unexpected with ROOT 3.10/02 (but this is the normal behavior with older version). If it really fails with 3.10/02, please send me how to exactly reproduce your failure (from your description the root file and your script should be enough).

Cheers,
Philippe.

Hi Philippe,

TFile *newfile = new TFile("small.root","recreate"); TTree* newtree = (TTree*)fChain->CopyTree("LETM_Nelectron>1"); newfile->Write(); newfile->Close();

is indeed working. I was using an old root version, and not 3.10/02 (although I thought that I was using it).
This little piece of code seems to do exactly what I want. Now I’m wondering if I can put whatever I want as a selection. So would it be possible to put a formula in it? I guess so, but I just want to make sure.

How about if I want to calculate a value where I first have to loop over e.g. the number of electrons in the event. How do I do that?

Thanks for being so patient with me.
Cheers,
Carsten

Yes anything that you can usually put in TTree::Draw.

You’re going to have to have to grab the individual values using TTreeFormula (see code in TTreePlayer::CopyTree).

Cheers,
Philippe.

Stupid question, but where exactly do I find the code? I can only find the header files…

Cheers,
Carsten

Go to TTreePlayer::CopyTree. Or look at $ROOTSYS/treeplayer/src/TTreePlayer.cxx.

Cheers,
Philippe.

Hi,

I’m chaining 5 root files (which do have the same tree) together and try to skim them. However I get the following error message:

root [1] .X make_subsample.C
Error in TObjArray::At: index 74 out of bounds (size: 74, this: 0x087a86d0)
Error in TObjArray::At: index 75 out of bounds (size: 74, this: 0x087a86d0)

If I do file by file everything works smoothly… Any idea what’s going on?

Cheers,
Carsten

Hi,

It is hard to know where this happens.

Do:

root [] .T root [] .X make_subsample.C
Send me the result.

Cheers,
Philippe.

Hi,

trying to make the selection a bit more sophisticatd I’ve tried to implement the TTree::CopyTree method as a function in my make_subsample.C macro. Obviously I’m not a C++ expert, otherwise I would have gotten it to work. Something goes wrong with the TFormula, root complains that no dictionary is available for it. Corrections are welcome, I’m going to look at it tomorrow again since I’m dead tired now.

Cheers,
Carsten
make_subsample2.C (2.55 KB)

Hi Carsten,

[quote]root [1] .X make_subsample.C
Error in TObjArray::At: index 74 out of bounds (size: 74, this: 0x087a86d0)
Error in TObjArray::At: index 75 out of bounds (size: 74, this: 0x087a86d0) [/quote]

This problem is caused by the fact that the class TSM_AElectrions has been modified BUT its version number has not been increased. This is compounded by a bug in the code supposed to detect this case.

When you have a class with a Streamer member function you always have to increase the version number when modify the content. (In particular when you have a ClassDef). If you class do not have a ClassDef, you have to use something like:// Set a version number of the MyClass TClass object RootClassVersion(MyClass,2);in one of your .cc files.

If your class do not have a Streamer member function, for version of ROOT older than 4.00/01, you still need to use the RootClassVersion. For version of ROOT newer then 4.00/01, this requirement has been lifted (a checksum is generated in this case). Of course, we are talking about the version of ROOT, writing the files.

In ROOT 3.10/02, in order to read your files, you HAVE TO read your files from the largest size of the class TSM_AElectrions to the smallest. In your example, this means reversing the order.

Once we fix the bug, your current order should work but might result in a drop of data. This is because TTree::Copy only copies the branches that exist in the first file in the chain.

Cheers,
Philippe.