How to read a struct from a Tree?

Dears,

I was able to store a struct in a Tree using the code “store_struct.C” in attachment. Now I’m trying to read the struct from the Tree using the code “test.C”. There’s no error message from Root but the values returned are all zeros (“0”) and this is not the correct values. Someone knows what is missing to get the correct values?
store_struct.C (1.6 KB)
test.C (637 Bytes)

Hi,

The fundamental problem is in the ‘leaflist’ technique you are using. This technique is very sensitive to variable alignment and padding. The struct you are working with is: struct particle{ Int_t id[6]; Double_t pt[6]; Double_t pt_res[6]; Double_t eta[6]; Double_t eta_res[6]; Double_t phi[6]; Double_t phi_res[6]; };where most often the assuming made by the compiler or the interpreter differs from the one made by TTree (naming whether there is padding between id and pt). You should be able to work around the problem by sorting the data member for the largest to the smallest. struct particle{ Double_t pt[6]; Double_t pt_res[6]; Double_t eta[6]; Double_t eta_res[6]; Double_t phi[6]; Double_t phi_res[6]; Int_t id[6]; };… and of course change the leaflist accordingly …

This fragility is why we moved away from the leaflist and rely on the compiler and interpreter to give the information. For example, if you move the struct definition outside the function:[code]struct particle{
Int_t id[6];
Double_t pt[6];
Double_t pt_res[6];
Double_t eta[6];
Double_t eta_res[6];
Double_t phi[6];
Double_t phi_res[6];
};

void store_struct(TString file_name) {[/code]and then you can simplify the branch creation:

particle Particle; nt->Branch("Particle",&Particle);
and similarly in the reading part: particle *Particle = nullptr; nt->SetBranchAddress("Particle",&Particle);.

In order for this to work, you need to have the dictionary generated for ‘particle’ … which can be done automatically by with ACLiC by just doing:.L store_struct.C+

Cheers,
Philippe.

Dear Philippe,

If I sort the data member for the largest to the smallest I still need of a dictionary? I tried to do that without create the dictionary, but the values are wrong yet although they are not zero more. There’s no way to make this work without create the dictionary?

Hi,

There should. I could not reproduce your problem as I am missing your input file. If you were to provide it, I will take a further look.

Cheers,
Philippe.

I will appreciate your help. I put the input file in attachment… from that file you can use the store_struct.C to store the structure and then the other code to read…
NewVBF_QED2_QCD2_BKG_FastME_1.root (1.67 MB)

t->SetBranchAddress(“Particle”, &Particle.pt[0]);

Dears,

I solved the problem with the suggestion from Philippe! Actually I don’t need to do some compilation to get a dictionary. I created a file.h (that is also a dictionary rsrs) with the structure a I want to use and I used the declaration “particle *Paricle” to read the struct from the tree. And I just had to change the way to call the members from that structure. Thank you guys to the help!

Hi,

Note that the technique you are now using is much safer :slight_smile: … Nonetheless, once you sorted the member, the code you wrote originally was intended to work and has now been fixed in v6.08.

Cheers,
Philippe.

I believe the original code of “test.C” is broken.
The “Particle” branch in the “VBF” tree is defined as “pt[6]/D :pt_res[6]/D : …”.
So, the following two calls should work:
t->SetBranchAddress(“Particle”, &Particle.pt[0]); // a pointer to a Double_t
t->SetBranchAddress(“Particle”, (Double_t*)&Particle); // a pointer to a Double_t
while the original call should generate a runtime error:
t->SetBranchAddress(“Particle”, &Particle); // a pointer so some unrelated object
(and indeed, the “branch address” was not set, though there was no error reported).

Hi Pepe,

t->SetBranchAddress("Particle", &Particle.pt[0]); // a pointer to a Double_t t->SetBranchAddress("Particle", (Double_t*)&Particle); // a pointer to a Double_tThose two do work indeed but they work by ‘trusting’ the user that the memory following those address is ‘as expected’ by the leaflist (this assumption is why leaflist should not be used any longer for structs).

t->SetBranchAddress("Particle", &Particle); // a pointer so some unrelated objectAs of today, this also work if and only if the first data member of Particle is of the ‘right’ type (double in this case) other wise it will issue an error message. [The bug fixed today is that the code was correctly detecting this case and was then suppressing the error message but was then not setting the address anyway [i.e. was considering it an error but did not warn about it].

So now, the 3rd option work in the same condition: both requires that it starts with a double and trusts ‘trusting’ the user that the memory following those address is ‘as expected’.

Cheers,
Philippe.

I still believe that an explicit casting should be mandatory in order to enforce that the user makes sure that the given pointer is in agreement with branch variables.

If you want to allow it to be “automatic” then please add a check: “sizeof(*pointer) >= sum_of_branch_variables_lengths”.

Hi Pepe,

Fair enough, this was not too hard to add (it is now in the master).

Cheers,
Philippe.