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:
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.
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)’
…
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:
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
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…
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
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?
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
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.
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?
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).
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
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?
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.
[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.