Display members of class, itself generating a vector, member of a class, used in a branch

Dear rooters,

my two questions are loosely summarized in the subject…

I create a TTree with a branch that contains a class Physics, i.e. this kind of approach:
https://root.cern.ch/doc/master/classTTree.html#addingacolumnofobjs
Now this class Physics has as a member a vector of class Data, here is a simplified example:

class Data {
public:
  Data(){};
  ~Data(){};
  friend std::ostream& operator<<( std::ostream& os, const Data& NPPData );
public:
  unsigned short ID;
public:
  Data(unsigned short ID_) : ID(ID_) {};
  ClassDef(Data, 1)  
}

class Physics {
private:
  vector<Data> NP;
public:
  Physics(){};
  ~Physics(){};
  friend std::ostream& operator<<( std::ostream& os, const Physics& NPP);
  ClassDef(Physics, 1) 
}

I also have a linkdef.h file to generate the dictionary:

#ifdef __CINT__
#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class Data+ ;
#pragma link C++ class Physics+ ;
#pragma link C++ class vector<Data>+ ;
#endif

Everything compile, the TTree is generated and I can draw the member of the Data class, i.e.

tree->Draw("NP.ID")
tree->Scan("NP.ID","","",5)
***********************************
*    Row   * Instance *     NP.ID *
***********************************
*        0 *        0 *           *
*        1 *        0 *           *
*        2 *        0 *           *
*        3 *        0 *        90 *
*        3 *        1 *        66 *
*        3 *        2 *        38 *
*        3 *        3 *        18 *
*        3 *        4 *        89 *
*        3 *        5 *        41 *
*        3 *        6 *        19 *
*        4 *        0 *           *
***********************************

works and give me what I expect.
Now I would like to see the details of Data members when I do a Print, but as you can see below the display stops at vector<Data> :

******************************************************************************
*Tree    :PhysicsTree:                                                              *
*Entries : 13877025 : Total =      1244231045 bytes  File  Size =  322446257 *
*        :          : Tree compression factor =   3.86                       *
******************************************************************************
*Branch  : Physics                                                                                *
*Entries : 13877025 : BranchElement (see below)                              *
*............................................................................*
*Br    0 :NP        : vector<Data>                                                           *
*Entries : 13877025 : Total  Size=  483516781 bytes  File Size  =  196297478 *
*Baskets :     1500 : Basket Size=   25600000 bytes  Compression=   2.46     *
*............................................................................*

I would like the corresponding line to look like:

*Br    0 :NP        : vector<Data>           .ID/I                                                *

Is it possible? And if yes, what am I missing? Note that I can not access the splitlevel of the branch as this is located in a common code for all collaborators (my code in embedded in a much bigger one).

When I use “TBrowser” I can see the leaves but then I have the following error message:

Error in <TClass::LoadClassInfo>: no interpreter information for class Data is available even though it has a TClass initialization routine.

I checked the forum for this error but could not find a similar case as mine. What I am missing?
Thank you very much in advance


ROOT Version: 6.28/06
Platform: Linux ubuntu20 5.4.0-187-generic
Compiler: linuxx8664gcc


I think @florine has some experience with debugging TTree printing.

Florine, you have some intuition about the problem?

Otherwise, we’ll have to wait for our TTree expert @pcanal to be back from vacation.

Hi @gib,

Apologies for my delayed answer. I am by no means a TTree expert and I will let @pcanal give the final verdict, but I’m afraid that without changing the splitlevel, this is not possible. Based on the snippets you provided it appears that the NP branch has been written with split level 1. With a splitlevel 2, it would look something like this, which is a bit closer to your desired output:

******************************************************************************
*Tree    :T         : T                                                      *
*Entries :       10 : Total =            2281 bytes  File  Size =       2297 *
*        :          : Tree compression factor =   1.00                       *
******************************************************************************
*Branch  :Physics                                                            *
*Entries :       10 : BranchElement (see below)                              *
*............................................................................*
*Br    0 :NP        : Int_t NP_                                              *
*Entries :       10 : Total  Size=       1650 bytes  File Size  =        154 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    1 :NP.ID     : UShort_t ID[NP_]                                       *
*Entries :       10 : Total  Size=        736 bytes  File Size  =        177 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*

Hello,
Thank you very much for your answer. This is what I thought, I will see if I can get access to the splitlevel in the framework I am working with.

This being said, do you have any idea of the origin of the error/warning message ?

Thank you in advance

Hi @gib,

I tried to reproduce the error with the information from your original post, but so far haven’t been able to. Could you share a reproducer with me? If you cannot share the data publicly, a DM or email also works!

Dear all

I have been working on this in the past days, but still no luck:

  1. Make my Data class inherits from TObject
  2. Add ClassImp
  3. Reorder the linkdef so that the declaration of the vector of class arrives first (Chapter: Addinga Class)

Now I have another issue while developing the code that I think might be connected.

But first note that my Data is more complex (I sent the real code to @florine) and I think for to continue the discussion I’d better uses the real names:

  1. The class is named NebulaPlusPlasticData
  2. The main class that is declared as branch to NebulaPlusPhysics and contains a vector<NebulaPlusPlasticData>
  3. All this is within a namespace named nebula_plus

So here my errors: I add a method Beta() to NebulaPlusPlasticData class.

Cling can see it alright:

root> nebula_plus::NebulaPlusPlasticData c
(nebula_plus::NebulaPlusPlasticData &) Name: nebula_plus::NebulaPlusPlasticData Title: 
root> c.Beta()
(double) -nan

but then, if load a TFile that contains my tree:

root> nebula_plus::NebulaPlusPlasticData c
ROOT_prompt_1:1:36: error: variable has incomplete type 'nebula_plus::NebulaPlusPlasticData'
nebula_plus::NebulaPlusPlasticData c
                                   ^
libNPNebulaPlus dictionary forward declarations' payload:5:94: note: forward declaration of 'nebula_plus::NebulaPlusPlasticData'
namespace nebula_plus{class __attribute__((annotate("$clingAutoload$NebulaPlusPhysics.h")))  NebulaPlusPlasticData;}

And an another strange behavior comes when I try to call the method:

root:2151613:2> PhysicsTree->Scan("NP@.Beta()")
Error in <TTreeFormula::DefinedVariable>: Unknown method:Beta() in vector<nebula_plus::NebulaPlusPlasticData>
Error in <TTreeFormula::Compile>:  Bad numerical expression : "NP@.Beta()"

Should for this last error modify the linkdef and add more pragma?
Thank you very much in advance,

Hi @gib,

To make sure I understand correctly what you are trying to do: you have an existing TTree with NebulaPlusPhysics branches, and you’ve added NebulaPlusPlasticData::Beta after this TTree was already created? This is moving a quite a bit beyond my area of expertise, but I think you will need to specify some schema evolution rules to make it work. This is explained here: I/O Concepts - ROOT.

I’m pinging @pcanal here as well, he can probably give a more definitive answer than me at this point. Sorry I cannot be of more help at this point, I hope you manage to resolve the issues you’re running into!

@florine
Thank you for your reply.

you have an existing TTree with NebulaPlusPhysics branches, and you’ve added NebulaPlusPlasticData::Beta after this TTree was already created?

No I am still in the process of generating the best data structure, so I create the TTree with the branches every time from the beginning.
The main class which defines the branch is NebulaPlusPhysics which contains a vector of NebulaPlusPlasticData class (my detector is made of multiple identical sub-detectors). This data class contains members and methods (here one of them is Beta()).
In the generate tree I can access (and see via TBrowser) all the members but not the methods!
I will have a look at the link you gave me (but I am afraid also that it will be behind my expertise)
Best

Since the TTree is not split it will not give you the information but you can get it with:

TClass::GetClass("Data")->GetStreamerInfo()->ls();

@pcanal

Thank you very much for the precision. This is what thought.

Any idea on the missing member issue?
My guess is that it could be because of at least the fact that I generate a vector with my class.
So I tested this hypothesis by creating two pieces of code:

 TTree *t = new TTree();
  auto d =  nebula_plus::NebulaPlusPlasticData();
  t->Branch("test",&d);
  t->Fill();
  t->Scan("test@.Beta()");

This works, no complain from cling.
Now the following code:

  TTree *t = new TTree();
  vector<nebula_plus::NebulaPlusPlasticData> vec;
  auto d =  nebula_plus::NebulaPlusPlasticData();
  vec.push_back(d);
  t->Branch("test",&vec);
  t->Fill();
  t->Scan("test@.Beta()");

give me the “expected” error:

Error in <TTreeFormula::DefinedVariable>: Unknown method:Beta() in vector<nebula_plus::NebulaPlusPlasticData>
Error in <TTreeFormula::Compile>:  Bad numerical expression : "test@.Beta()"

This is a syntax error from my part:

t->Scan("test.Beta()");

Does not complain.

So I am lost… this is what I think in do in my dynamic library that define my main class of physics… Is there something more I should do in the linkdef to propagate the existence of the methods? Because now with my real code:

PhysicsTree->Draw("NP.Beta()")
Error in <TClass::LoadClassInfo>: no interpreter information for class nebula_plus::NebulaPlusPlasticData is available even though it has a TClass initialization routine.
Error in <TClass::LoadClassInfo>: no interpreter information for class nebula_plus::NebulaPlusPlasticData is available even though it has a TClass initialization routine.
Error in <TTreeFormula::DefinedVariable>: Unknown method:Beta() in nebula_plus::NebulaPlusPlasticData
Error in <TTreeFormula::Compile>:  Bad numerical expression : "NP.Beta()"
Info in <TSelectorDraw::AbortProcess>: Variable compilation failed: {NP.Beta(),}

Best

The ‘@’ sign request for the following expression to be applied to the std::vector itself rather than its content. So indeed

t->Scan("test.Beta()");

will/should call Beta() on each of the elements in the vector.

Error in <TClass::LoadClassInfo>: no interpreter information for class nebula_plus::NebulaPlusPlasticData is available even though it has a TClass initialization routine.

is indicative that at runtime, root.exe was unable to find the header file for nebula_plus::NebulaPlusPlasticData.