Adding array of struct to a Tree

Hi,

next question regarding Trees. How do I add an array of a struct to a Tree?
If I have, eg:

[code]TTree* testTree = new Tree(“something”,“TestTree”);

struct {
int test2;
double test3;
} test1[20][30];

testTree->Branch(“test1”,&test1, “test1[20]/ XX”)
testTree->Fill()
[/code]

What should I use for the XX in the code, because it is no standard data type?

BR

Hi,

The leaflist technique to add branch does NOT support array of struct (but it support struct of arrays).[code]
TTree* testTree = new Tree(“something”,“TestTree”);
struct {
int test2[20][30]
double test3[20][30]
} test1;

testTree->Branch(“test2”,&test1.test2, “test2[20][30]/I”);
testTree->Branch(“test3”,&test1.test3, “test3[20][30]/D”);
testTree->Fill();[/code]

I strongly suggest that you move to using the object based technique to add branch:[code]// Script.C
class test1 {
public:
test1() : test2(0), test3(0) []
int test2;
double test3;
};
class Holder {
public:
test1 values[20][30];
};

TTree createTree() {
TTree
testTree = new Tree(“something”,“TestTree”);
Holder holder;
testTree->Branch(“event.”,&holder);
testTree->Fill();
testTree->ResetBranchAddresses();
return testTree;
}[/code]and use with ACLiCroot [] .L Script.C+

Cheers,
Philippe.

Thank’s so far.
If I am using an external compiler (gcc) I will have to generate a dictionary with rootcint to make the object based technique work, I guess. Am I right?

BR

Hi,

[quote] I will have to generate a dictionary with rootcint to make the object based technique work[/quote]Yes.

Philippe.

Okay. One question left.
If I look at your first code example would it also be possible to add the struct like this?

[code]TTree* testTree = new Tree(“something”,“TestTree”);
struct {
int test2[20][30]
double test3[20][30]
} test1;

testTree->Branch(“test2”,&test1, “test2[20]/I:test3[20]/D”);
testTree->Fill();[/code]

Please say yes.

BR

Hi,

[quote]Please say yes.[/quote]Well actually the answer is no (in particular because the 2 declared sizes do not match) but the first code example I gave does not require a dictionary (so I do not see why you would need to use or prefer the code in your last question).

Cheers,
Philippe.

The thing is that I have a lot of structs with also a lot of internal arrays and I wonder now if I have to read in and write out all of these internal arrays seperately, because I am exchanging data between my classes with Trees.
I cant do this either?

[code]TTree* testTree = new Tree(“something”,“TestTree”);
struct {
int test2[20][30]
double test3[20][30]
} test1;

testTree->Branch(“test2”,&test1, “test2[20][30]/I:test3[20][30]/D”);
testTree->Fill();[/code]
And I guess it is also not possible to read the data out of the Tree, which is generated in your first code example, like this:

[code]struct {
int test2[20][30]
double test3[20][30]
} test4;

testTree->SetBranchAddress(“test1”, &test4);
testTree->GetEntry(0);
[/code]

BR

[quote]The thing is that I have a lot of structs with also a lot of internal arrays[/quote]Then it would be simplier and less error-prone to simply create dictionaries for those structs. This is as simple as writing a linkdef.h file://struct_linkdef.h #ifdef __MAKECINT__ #pragma link C++ class test1+; #pragma link C++ class test2+; etc. #endifand adding to your Makefile something like:[code]MyDict.cxx: $(HEADERS) struct_linkdef.h
[TAB] rootcint -f $@ -c $(CXXFLAGS) -p $^

libMyLib.so: MyDict.cxx $(SOURCES)
[TAB] g++ -shared -o$@ root-config --ldflags $(CXXFLAGS) -I$(ROOTSYS)/include $^[/code]

Cheers,
Philippe.

PS. [quote]And I guess it is also not possible to read the data out of the Tree, which is generated in your first code example, like this:[/quote]that’s right you can not.

[quote]I cant do this either? … “test2[20][30]/I:test3[20][30]/D”[/quote]It will probably work but I do not recommend it.

Thank you very much. Some question remain not crystal clear. I am sorry to bug you even more but I am kind of brain dead today.

So I only have to create the header file and add it to my make file?

Do I also have to create a mydict.cxx file and add it to the make file?

Where should the linkdef.h be included?

Could you please give me again one code example on how I will use the Trees afterwards?

Did I understand it right that when this dictionary is created that I can use the struct as a single object but it is still not possible to add an array of this object to a Tree?

BR

Hi,

Please see root.cern.ch/drupal/faq#n676
and root.cern.ch/download/doc/15AddingaClass.pdf

[quote]So I only have to create the header file and add it to my make file?[/quote]Yes.

[quote]Do I also have to create a mydict.cxx file and add it to the make file?[/quote]Yes for example using a variation of the Makefile code snippet I provided.

[quote]Where should the linkdef.h be included?[/quote]It should only be used as an argument to the rootcint command.

[quote]Could you please give me again one code example on how I will use the Trees afterwards?
[/quote]

testTree->SetBranchAddress("test1", &test4); testTree->GetEntry(0);

[quote]Did I understand it right that when this dictionary is created that I can use the struct as a single object but it is still not possible to add an array of this object to a Tree?[/quote]Correct. But you can add a collection of those objects (either a TClonesArray if you inherit from TObject or std::vector if you generate the dictionary for the vector class).

Cheers,.
Philippe.

Thank you very much! I will try your suggestions.

BR

Hmmm. Regretfully some problems again. When I try to generate the dictionary I get those errors.

$ rootcint -f Dict.cpp -c TDummy1.h TDummy2.h linkDef.h Error: link requested for unknown class teststruct1 linkDef.h:3: Error: link requested for unknown class teststruct2 linkDef.h:4: Error: link requested for unknown class linkDef G__auto4142LinkDef.h:9: Warning: Error occurred during reading source files Warning: Error occurred during dictionary source generation !!!Removing Dict.cpp Dict.h !!! Error: rootcint: error loading headers...
The TDummy1.h file looks like this:

[code]#ifndef TDUMMY1_H
#define TDUMMY1_H

#include
#include

#include <TTree.h>

class TDummy1
{
public:
typedef struct {
int testint1;
int testintarray1D1[40];
int testintarray2D1[40][40];
} teststruct1;

teststruct1 teststruct;

teststruct1 teststructarray1D1[40];

//teststruct1 teststructarray2D1[40][40];

std::vector<teststruct1> vteststruct1D1;
std::vector<std::vector<teststruct1> > vteststruct2D1;

TTree* outputTree;
void fillData();
void transVector();
void writeTree();
TDummy1();

};

#endif // TDUMMY1_H[/code]
The TDummy2.h the same but instead of teststruct1 it is teststruct2.

The linkDef.h:

//linkDef.h #ifdef __MAKECINT__ #pragma link C++ class teststruct1+; #pragma link C++ class teststruct2+; #pragma link C++ class vector<teststruct1>+; #pragma link C++ class vector<vector<teststruct1> >+; #pragma link C++ class vector<teststruct2>+; #pragma link C++ class vector<vector<teststruct2> >+; #endif

Any advice?

Hi,

[quote]Error: link requested for unknown class teststruct1 linkDef.h:3:[/quote]Is an accurate error isn’t it? Didn’t you mean to talk about ‘TDummy1::teststruct1’ ?

Cheers,
Philippe.

So I should write TDummy1::teststruct1 instead of teststruct1 in the linkDef.h? Is this correct? I hope I did understand you right.

BR

Yes, in the linkdef you need to use the fully qualified name of all the classes.

Philippe.

Thank you. Slowly it is getting more and more clear. But I get a different error now.
My linkDef.h no reads like this,

//linkDef.h #ifdef __MAKECINT__ #pragma link C++ class TDummy1::teststruct1+; #pragma link C++ class TDummy2::teststruct2+; #pragma link C++ class vector<TDummy1::teststruct1>+; #pragma link C++ class vector<vector<TDummy1::teststruct1> >+; #pragma link C++ class vector<TDummy2::teststruct2>+; #pragma link C++ class vector<vector<TDummy2::teststruct2> >+; #endif
and I get …

$ rootcint -f Dict.cpp -c TDummy1.h TDummy2.h linkDef.h Error: link requested for unknown class linkDef G__auto4172LinkDef.h:9: Warning: Error occurred during reading source files Warning: Error occurred during dictionary source generation !!!Removing Dict.cpp Dict.h !!! Error: rootcint: error loading headers...

Where did I forget something again?

BR

Never mind. In this case I found the answer myself. It is a wonder :wink: .
One has to name the definition header file LinkDef.h. It is case sensitive.
But if I try to compile the whole thing (added Dict.cpp to my make file). I get a bunch of errors.

$ make [ 25%] Building CXX object CMakeFiles/dictionary_test.dir/Dict.cpp.o /home/adonai/projects/dictionary_test/Dict.cpp: In function ‘ROOT::TGenericClassInfo* ROOT::GenerateInitInstanceLocal(const TDummy1::teststruct1*)’: /home/adonai/projects/dictionary_test/Dict.cpp:52: error: ‘ROOT::Shadow::TDummy1’ has not been declared /home/adonai/projects/dictionary_test/Dict.cpp: In function ‘ROOT::TGenericClassInfo* ROOT::GenerateInitInstanceLocal(const TDummy2::teststruct2*)’: /home/adonai/projects/dictionary_test/Dict.cpp:94: error: ‘ROOT::Shadow::TDummy2’ has not been declared /home/adonai/projects/dictionary_test/Dict.cpp: In function ‘void ROOT::TDummy1cLcLteststruct1_ShowMembers(void*, TMemberInspector&)’: /home/adonai/projects/dictionary_test/Dict.cpp:128: error: ‘ROOT::Shadow::TDummy1’ has not been declared /home/adonai/projects/dictionary_test/Dict.cpp:128: error: expected initializer before ‘ShadowClass’ /home/adonai/projects/dictionary_test/Dict.cpp:129: error: ‘ShadowClass’ was not declared in this scope /home/adonai/projects/dictionary_test/Dict.cpp:129: error: ‘sobj’ was not declared in this scope /home/adonai/projects/dictionary_test/Dict.cpp:129: error: expected primary-expression before ‘)’ token /home/adonai/projects/dictionary_test/Dict.cpp:129: error: expected ‘;’ before ‘obj’ /home/adonai/projects/dictionary_test/Dict.cpp: In function ‘void ROOT::TDummy2cLcLteststruct2_ShowMembers(void*, TMemberInspector&)’: /home/adonai/projects/dictionary_test/Dict.cpp:167: error: ‘ROOT::Shadow::TDummy2’ has not been declared /home/adonai/projects/dictionary_test/Dict.cpp:167: error: expected initializer before ‘ShadowClass’ /home/adonai/projects/dictionary_test/Dict.cpp:168: error: ‘ShadowClass’ was not declared in this scope /home/adonai/projects/dictionary_test/Dict.cpp:168: error: ‘sobj’ was not declared in this scope /home/adonai/projects/dictionary_test/Dict.cpp:168: error: expected primary-expression before ‘)’ token /home/adonai/projects/dictionary_test/Dict.cpp:168: error: expected ‘;’ before ‘obj’ make[2]: *** [CMakeFiles/dictionary_test.dir/Dict.cpp.o] Fehler 1 make[1]: *** [CMakeFiles/dictionary_test.dir/all] Fehler 2 make: *** [all] Fehler 2

I don’t know.

BR

HI,

You need to either add#pragma link C++ class TDummy1+; to the linkdef file or add ClassDef(teststruct1,2); inside the declaration of the class teststruct1.

Cheers,
Philippe.

Thank you very much again. Just a moment before you posted, I was to post that it compiled now. I modified my LinkDef.h file:

//linkDef.h #ifdef __MAKECINT__ #pragma link C++ class TDummy1+; #pragma link C++ class TDummy2+; #pragma link C++ class TDummy1::teststruct1+; #pragma link C++ class TDummy2::teststruct2+; #pragma link C++ class vector<teststruct1>+; #pragma link C++ class vector<vector<teststruct1> >+; #pragma link C++ class vector<teststruct2>+; #pragma link C++ class vector<vector<teststruct2> >+; #endif
and also the TDummy classes (added ClassDef and ClassImp) EDIT: as well as #include "RTypes.h"
TDummy1.h:

[code]#ifndef TDUMMY1_H
#define TDUMMY1_H

#include
#include

#include “Rtypes.h”
#include “TTree.h”

class TDummy1
{
public:
typedef struct teststruct1 {
int testint1;
int testintarray1D1[40];
int testintarray2D1[40][40];
} teststruct1;

teststruct1 teststruct;

teststruct1 teststructarray1D1[40];

//teststruct1 teststructarray2D1[40][40];

typedef std::vector<teststruct1> vteststruct1D;
typedef std::vector<std::vector<teststruct1> > vteststruct2D;

vteststruct1D vteststruct1D1;
vteststruct2D vteststruct2D1;

public:

TTree* outputTree;

void fillData();
void transVector();
void writeTree();
TDummy1();
  
ClassDef(TDummy1,1);

};

#endif // TDUMMY1_H[/code]
TDummy1.cpp (first lines):

[code]#include “TDummy1.h”

ClassImp(TDummy1);[/code]

Does this look correct?

BR

[quote]Does this look correct?[/quote]Not quite yet.
I think you need to use:#pragma link C++ class vector<TDummy1::teststruct1>+; #pragma link C++ class vector<vector<TDummy1::teststruct1> >+; #pragma link C++ class vector<TDummy2::teststruct2>+; #pragma link C++ class vector<vector<TDummy2::teststruct2> >+;

Cheers,
Philippe