Hi preimer,
as per the error message, because of how the tree was written (first was written as a leaflist, not as a full object) you have to access first.intOneI, first.intTwo etc. directly when reading with TTreeReader, you can’t read all of first at the same time.
Try using TTreeReaderValue<int> intOne(theReader, "first.intOneI") and it should stop complaining.
So that will work, but I would like to preserve the structure of first and of coach classes, so that code can use first.intOne and coach.intOne. (Except for a typo, first and coach were supposed to have a member with the same name, that is first.intOne and coach.intOne.)
Is there a way to write the tree so that I can read it back in preserving the structure of the first and coach classes?
Hi Paul,
yes of course!
Do not specify a leaflist when creating the first branch, but instead write it as a (split) object.
For this to work ROOT’s interpreter will need to know about your class – if you write the file from an interpreted macro things should work (as long as the definition of the class is also interpreted), otherwise you will need to create dictionaries for the classes that you want to write to file (there should be docs available that show how to do it).
The macro approach:
// myMacro.C -- execute as `root -l -b -q myMacro.C`
struct A {
int a;
int b;
};
void write() {
TFile f("f.root", "recreate");
TTree t("t", "t");
A a{42, 84};
t.Branch("a", &a);
t.Fill();
t.Write();
}
void read() {
TFile f("f.root");
TTreeReader r("t", &f);
TTreeReaderValue<A> v(r, "a");
while (r.Next())
std::cout << v->a << " " << v->b << std::endl;
}
int myMacro() {
write();
read();
return 0;
}
This solution seems to work when I run it within root. However, if I compile it as a stand alone program and try to run it, I receive the following error message:
Pauls-MacBook-Air:treeTest reimer$ g++ -std=c++11 -I /usr/local/root-6.11/include/ v2.C -L /usr/local/root-6.11/lib/ -lCore -lTree -lTreePlayer -lRIO
Pauls-MacBook-Air:treeTest reimer$ ./a.out
Error in TTree::Branch: The pointer specified for a is not of a class or type known to ROOT
Error in TTreeReaderValueBase::CreateProxy(): The template argument type T of A accessing branch a (which contains data of type {UNDETERMINED}) is not known to ROOT. You will need to create a dictionary for it.
I could simply always run my larger program as a macro within root, but I would prefer to have a separate executable. Any suggestions?
Hi Paul,
yes as I mentioned above the ROOT interpreter needs to know about the class that you wanto to read/write.
If you execute the program as a macro, and the macro defines the class that you want to write out, by construction the interpreter (which runs the macro) will know about the class. This kind of “interpreted” I/O will work in most simple cases. Otherwise you need dictionaries.
ROOT dictionaries are the standard way to teach ROOT how to do I/O of your own classes, and will work with compiled programs as well. You can find information on how to generate dictionaries for your class in the FAQ section of the root.cern website or in ROOT’s user guide.