Can TClonesArray be nested?

Dear ROOTers,

I’m developing a reconstruction code with a ROOT user defined event class.
I have the need to nest TClonesArray in this way:

[code]class MyEvent : public TObject {
public:
[…]
ClassDef (MyEvent, 1)
private:
MySubEvent se;
[…] // other similar subevent classes
};

class MySubEvent : public TObject {
public:
MySubEvent() { fragments = new TClonesArray(“MyFragment”); }
[…]
ClassDef (MySubEvent, 1)
private:
TClonesArray *fragments;
[…]
};

class MyFragment : public TObject {
public:
MyFragment() { hits = new TClonesArray(“MyHit”); }
[…]
ClassDef (MyFragment, 1)
private:
TClonesArray *hits;
[…] // more simple variables
};

class MyHit : public TObject {
[…] // only simple stuff here
ClassDef (MyHit, 1)
};[/code]

My problem is that when I add the innermost TClonesArray* I get a segmentation violation at the TTree::Branch().

This is my gdb output:

code where
#0 0x40c995e5 in TBranchElement::TBranchElement(char const*, TStreamerInfo*, int, char*, int, int, int) () from /cern/root/lib/libTree.so
#1 0x40c9e533 in TBranchElement::Unroll(char const*, TClass*, TClass*, int, int, int) () from /cern/root/lib/libTree.so
#2 0x40c9988c in TBranchElement::TBranchElement(char const*, TStreamerInfo*, int, char*, int, int, int) () from /cern/root/lib/libTree.so
#3 0x40c9e533 in TBranchElement::Unroll(char const*, TClass*, TClass*, int, int, int) () from /cern/root/lib/libTree.so
#4 0x40c99936 in TBranchElement::TBranchElement(char const*, TStreamerInfo*, int, char*, int, int, int) () from /cern/root/lib/libTree.so
#5 0x40cb4403 in TTree::Bronch(char const*, char const*, void*, int, int) ()
from /cern/root/lib/libTree.so
#6 0x40cb3275 in TTree::Branch(char const*, char const*, void*, int, int) ()
from /cern/root/lib/libTree.so
#7 0x080d2e99 in bx_event_writer::begin() (this=0x890a030) at bx_writer.cc:73
#8 0x080b82df in bx_base_module::framework_begin(bx_base_module::module_role)
(this=0x890a030, role=writer) at bx_base_module.cc:60
#9 0x080b25ae in bx_base_module::begin_operation::operator()(bx_base_module*)
(this=0xbffff1ec, t=0x890a030) at bx_base_module.hh:107
#10 0x080b2324 in bx_base_module::begin_operation std::for_each<__gnu_cxx::__normal_iterator<bx_base_module**, std::vector<bx_base_module*, std::allocator<bx_base_module*> > >, bx_base_module::begin_operation>(__gnu_cxx::__normal_iterator<bx_base_module**, std::vector<bx_base_module*, std::allocator<bx_base_module*> > >, __gnu_cxx::__normal_iterator<bx_base_module**, std::vector<bx_base_module*, std::allocator<bx_base_module*> > >, bx_base_module::begin_operation) (__first=
{<iteratorstd::random_access_iterator_tag,bx_base_module*,int,bx_base_module**,bx_base_module*&> = {}, _M_current = 0x8903e00}, __last=
{<iteratorstd::random_access_iterator_tag,bx_base_module*,int,bx_base_module**,bx_base_module*&> = {}, _M_current = 0x8903e04}, __f=
{i_role = writer}) at stl_algo.h:157
#11 0x080b1d25 in bx_reco_framework::run() (this=0xbffff3b0)
at bx_reco_framework.cc:48
#12 0x080b188d in main (argc=1, argv=0xbffff414) at main.cc:16
#13 0x41297c57 in __libc_start_main () from /lib/i686/libc.so.6

[/code]

Is it a known limitation or am I doing something wrong?
Thanks a lot, bye
Davide

:cry:,

12 days and no answer … I guess I’ll never see one …
What was the matter? Incomprehensible question?
Answer unknown to the whole community?
Unintresting topic?
Writer should find another job?

Anyhow, in Italy we say: “Hope is the last one to die”, let’s see ( [-o< )

Bye
Davide

Hi,

I see that you have placed the ClassDef Macro not at the end of the class definition. According to the userguide page 197 (Automatic Schema Evolution)

[quote]When a class is defined in ROOT, it must include the ClassDef macro as the last line in the header file inside the class definition[/quote] This means you have to plave it just before the ‘}’ bracket, not at the end of the public definition.
You might want to check wether this will make a difference. Other than that I have no idea…

Cheers,

Lutz

Dear Lutz,

thank you for your hint, I applied it in my code.
Unfortunately it didn’t solve the problem.
Let’s see if magic Philippe comes out with the solution…
Thanks anyhow
Davide

Hi,

Nested ClonesArray should be possible. (Note I could not find which ROOT version you are using). However most of their advantage are unavailable.

Anyway I will try to reproduce your problem.

Cheers,
Philippe.

Hi,

I am able to reproduce this problem. This should be fixed in the next few days.

Cheers,
Philippe.

Dear Philippe,

thanks for your reply and for your effort.
I forgot to mention ROOT version: it is 3.05/07.
I will try the new 4.00/08 soon, also because I want to try with std::vector<> instead of TClonesArray.
Which features of TClonesArray would be unavailable when nested? Splitting?
Thanks again,
bye
Davide

Hi Philippe,

I’m back on this issue after some time.

I moved to root version 4.00/08, but the problem persists.
I tryied using std::vector<> instead of TClonesArray in both levels with no success.
In this latter case the crash (at the same point, i.e. at TTree::Branch() instruction) is verbose rather then a simple segmentation fault:

Fatal in <TBranchElement::>: fType==3 || fType==4 violated at line 845 of `tree/src/TBranchElement.cxx' aborting Generating stack trace... 0x40de5400 in TBranchElement::BuildTitle(char const*) + 0xe2 from /cern/root/lib/libTree.so 0x40de544e in TBranchElement::BuildTitle(char const*) + 0x130 from /cern/root/lib/libTree.so 0x40de2912 in TBranchElement::TBranchElement[in-charge](char const*, TStreamerInfo*, int, char*, int, int, int) + 0xe4a from /cern/root/lib/libTree.so 0x40de8c28 in TBranchElement::Unroll(char const*, TClass*, TClass*, int, int, int) + 0x622 from /cern/root/lib/libTree.so 0x40de29ab in TBranchElement::TBranchElement[in-charge](char const*, TStreamerInfo*, int, char*, int, int, int) + 0xee3 from /cern/root/lib/libTree.so 0x40e01ec0 in TTree::Bronch(char const*, char const*, void*, int, int) + 0x7a0 from /cern/root/lib/libTree.so 0x40e00a61 in TTree::Branch(char const*, char const*, void*, int, int) + 0x41 from /cern/root/lib/libTree.so 0x080eafc6 in bx_event_writer::begin() + 0xc22 from echidna 0x080c69b9 in bx_base_module::framework_begin(bx_base_module::module_role) + 0x45 from echidna 0x080c0e8e in bx_base_module::begin_operation::operator()(bx_base_module*) + 0x16 from echidna 0x080c0ae8 in _ZSt8for_eachIN9__gnu_cxx17__normal_iteratorIPP14bx_base_moduleSt6vectorIS3_SaIS3_EEEENS2_15begin_op + 0x3c from echidna 0x080c04e9 in bx_reco_framework::run() + 0x125 from echidna 0x080c005d in main + 0x61 from echidna 0x415897f7 in __libc_start_main + 0xc7 from /lib/i686/libc.so.6 0x080bff61 in TFile::TFile[in-charge](char const*, char const*, char const*, int) + 0x39 from echidna Aborted

How did your fix attempt go?
Shall I try the unstable version?

Thanks, ciao
Davide

Davide,

Could you send the shortest possible ruuning script reproducing your problem? I suggest making a test with version 4 first.

Rene

Dear Rene,

thanks for your reply.

Unfortunatly it’s not a simple script, but a relatively complex reconstruction program for the Borexino experiment.
I send you a tar file of the whole thing. It compiles on Debian, Redhat, Mandrake with most gcc versions now.
You may look at the code if you have time, but in order to run it, you would need a rawdata file and authorized access to our database.

The file you will be most intrested in is Echidna/root/BxEvent.hh.
In Echidna/doc/pictures/root_event.fig you also have a sketch of how the root classes are related to each other.
In particular the classes I’m referring to in my previous posts are BxLabenEvent having a TClonesArray (or std::vector<>) of BxCluster, which in turn has a TClonesArray (or std::vector<>) of BxClusteredHit. So Removing this innermost stage, commenting line 195 in BxEvent.hh and a few other related lines here and there, the crash doesn’t occur any longer. But of course I don’t want to get rid of my hits.

I’m using ROOT v4.00/08 now, which version do you suggest to try exactly?

About 1 month ago, Philippe wrote he was reproducing the problem and trying to fix it. I don’t know if he has time at the moment, but if you are in touch with him maybe he can tell you more about what he did and what the result was.

Thanks a lot, bye
Davide
echidna.tar.gz (141 KB)

I sligthly miswrote the class names above, not the concept.

In file BxEvent.hh,
it is class BxLaben which holds a TClonesArray of objects BxLabenCluster who in turn have a TClonesArray of BxLabenClusteredHit.

Sorry
Davide

We will look at this problem after CHEP.
If you could send a very short script reproducing the problem, the response could be much faster

Rene

Dear Rene’,

I extrapolated the part of code I thought it was relevant to the problem and put it into a macro for CINT.

sample_bx_classes.C contains the class definitions and should be loaded before sample_writer.C is executed.

Unfortunately the oversemplification changed things quite a bit. so here the program runs happily and writes a meaningful ROOT file. Why does the compiled version crash instead?

Another question: in the file generated by this macro I’m sending, the innermost TClonesArray is not split, i.e. I cannot Browse it in a TBrowser and I cannot TTree::Draw() its data members. Why?

If you want to run the compiled program, our system adimistrator would be happy to give you an account on our machines in Gran Sasso, where the environment is already setup.

Thank you again
Davide
sample_writer.C (595 Bytes)
sample_bx_classes.C (2.49 KB)

Dear Rene’,

After latest developments in our program, the TTree::Branch() doesn’t cause a crash any longer while using ROOT 4.00/08 and TClonesArray’s (the behaviour is unchanged with older ROOT versions or using std::vector<>). The reason of this is a mistery; I’ve been spending half a day in diffing source files with no results.

Anyhow, I think that at this point, after you’re back from the conference, you can forget about the cumbersome tar file and just look at the macro I sent you in my last post.
The remaining important question is why is the innermost TClonesArray is not split, and if/how can this be achieved.
I hope I made myself clear enough.
Thank you,
bye
Davide

Hi Davide,

TClonesArray inside TClonesArray should not be split. In principle
this was protected. However, thanks to your example, I found a case
where a protection was missing (when the top object containing the 1st
TClonesArray is itself a composite member of the top level class.
This is now protected in the CVS version.
In your case, you can circumvent the problem in two ways;
-in sample_write.C, replace
p_root_tree->Branch (“events”, “BxEvent”, &p_root_event);
by
p_root_tree->Branch (“events”, “BxEvent”, &p_root_event,32000,3);

-in the class BxLabenCluster data member declaration, replace
TClonesArray *hits; //->
by
TClonesArray *hits; //!!->

Rene

Dear ROOTers,

after months of attempts and big frustrations ( ](*,) ), I finally abandon this topic.
I will modify my event class to avoid using nested lists.
Though this will be quite uncomfortable for the users, our time is over and we need to move on.

My final result is: it is not possible to have nested lists and to enjoy the benefits of ROOT splitting.

I tried everything:

[ul]TClonesArray
TObjArray
std::vector<>
dynamic C-style arrays
static C-style arrays[/ul]

each one both as the outer and as the inner list, in any possible combination and with any ROOT version available.

I enjoyed support by Phillippe first and by Rene’ after, but unfortunately none of their suggestions worked (including the ones Rene’ sent me in private after the last post).
Finally they even stopped writing to me (I guess due to desperation… :cry: ).

Anyhow I used a lot of the time of you all, who have been very kind, so thank you for everything.
Have fun.
Davide

This should have been explicit in the documentation (maybe we are missing it). It is technically extremely difficult to implement and support the splitting of the a container inside a container (especially for TTree::Draw).

Cheers,
Philippe.