TTreeReader reading branch created as leaf list

I am trying to write code to read back in a TTree that was written by another program. I have pruned the problem down to the following bits of code:

testReader.C (864 Bytes)

with dataStruct.h as
dataStruct.h (357 Bytes)

running this in root produces the following error:

root [0] .L testReader.C
root [1] rate()
Error in TTreeReaderValueBase::GetBranchDataType(): The branch first was created using a leaf list and cannot be represented as a C++ type. Please access one of its siblings using a TTreeReaderArray:
Error in TTreeReaderValueBase::GetBranchDataType(): first.intOneI
Error in TTreeReaderValueBase::GetBranchDataType(): first.intTwo
Error in TTreeReaderValueBase::GetBranchDataType(): first.floatOne
Error in TTreeReaderValueBase::GetBranchDataType(): first.floatTwo
Error in TTreeReaderValueBase::GetBranchDataType(): first.theta
Error in TTreeReaderValueBase::GetBranchDataType(): first.cosTheta
Error in TTreeReaderValueBase::GetBranchDataType(): first.sinTheta
Error in TTreeReaderValueBase::CreateProxy(): The branch first contains data of type {UNDETERMINED TYPE}, which does not have a dictionary.
(int) 1

The Three was written by
main.C (1.8 KB)

Is it impossible for me to process this TTree in this manor because it was created as a “leaf list” or am I missing a crucial point?

Thanks,

Paul


ROOT Version: 6.11/01
Platform: OSX 10.13.6
Compiler: Not Provided


1 Like

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.

Cheers,
Enrico

1 Like

Hello,

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?

Thanks,

Paul

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;
}

Hope this helps!
Enrico

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?

Thanks,

Paul

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.

Cheers,
Enrico

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.