Array of TClonesArray

Hi rooters,

I would like to fill a tree with an array of TClonesArray:

TClonesArray *fTraj[N]; ... for(Int_t i=0;i<N;i++) { if (!fgTraj[i]) fgTraj[i] = new TClonesArray("Traj", 1000); fTraj[i] = fgTraj[i]; }

and I try to fill it like :

Traj *RootBox::AddTraj(Int_t trajID) { // Add a new hit to the list of hits in detector B TClonesArray &trajs = *fTraj[trajID]; Traj *traj = new(trajs[fNtraj[trajID]++])Traj(); return traj; }
it seems to not work fine :
Error in TObject::ReadValue: Invalid data address: result will be wrong

Thanks !

May be my question was not clear enough :blush:
so I would like to implement an Array of TClonesArray (for example 200 TclonesArray, one per Detector I would like to study).
Each object is coming from the same class : Traj
My problem is that the way I tried to fill the Array of TclonesArray does not work … :frowning:
I tried to see what’s going on by using ttree->Show() just after I fill it.
Only the first element of the table fTraj[i] ( --> fTraj[0]) is correctly filled. if i>0, fTraj[i] contains the same elements than fTraj[0] …
so it seems that the method : AddTraj(Int_t trajID) is not properly working.

Is there something wrong there ?
Is there a “limitation” to use an Array of TClonesArray ?

Thanks for your help

Hi,

On visual inspection your code seem okay. Can you provide a complete running example showing the problem?

Cheers,
Philippe

[quote=“pcanal”]Hi,

On visual inspection your code seem okay. Can you provide a complete running example showing the problem?

Cheers,
Philippe[/quote]

Hi,
here is the example : classes are in RootBox.h and RootBox.cxx
and after I load the .so, I run Iko.C to create the rootfile.
So I fill fTraj[i] up to i=3 --> when using rootfile you will see the problem …
Error in TObject::ReadValue: Invalid data address: result will be wrong
and only first element of fTraj array is filled …

Thanks again !
Cheers

Hi, I guess the file is missing …
Here it is :slight_smile:
Example.tar.gz (2.23 KB)

Hi,

I do not see any problem. I did and got:root [0] .L RootBox.cxx+ root [1] .x Iko.C x --> 1y --> 4z --> 412 x --> 2y --> 5z --> 413 x --> 3y --> 6z --> 414 x --> 4y --> 7z --> 415 x --> 5y --> 8z --> 416 x --> 6y --> 9z --> 417 x --> 7y --> 10z --> 418 x --> 8y --> 11z --> 419 x --> 9y --> 12z --> 420 x --> 10y --> 13z --> 421 x --> 2y --> 8z --> 824 x --> 4y --> 10z --> 826 x --> 6y --> 12z --> 828 x --> 8y --> 14z --> 830 x --> 10y --> 16z --> 832 x --> 12y --> 18z --> 834 x --> 14y --> 20z --> 836 x --> 16y --> 22z --> 838 x --> 18y --> 24z --> 840 x --> 20y --> 26z --> 842 x --> 3y --> 12z --> 1236 x --> 6y --> 15z --> 1239 x --> 9y --> 18z --> 1242 x --> 12y --> 21z --> 1245 x --> 15y --> 24z --> 1248 x --> 18y --> 27z --> 1251 x --> 21y --> 30z --> 1254 x --> 24y --> 33z --> 1257 x --> 27y --> 36z --> 1260 x --> 30y --> 39z --> 1263 x --> 4y --> 16z --> 1648 x --> 8y --> 20z --> 1652 x --> 12y --> 24z --> 1656 x --> 16y --> 28z --> 1660 x --> 20y --> 32z --> 1664 x --> 24y --> 36z --> 1668 x --> 28y --> 40z --> 1672 x --> 32y --> 44z --> 1676 x --> 36y --> 48z --> 1680 x --> 40y --> 52z --> 1684

Cheers,
Philippe.

Hi,

However, it seems that you are misusing/misunderstanding how the TTree structure works. [Or maybe this is just an artefact of your simplify the real code] Your code reads: T->Branch("event","RootBox",&event,8000,2); for (Int_t ev=0;ev<nev;ev++) { traj = event->AddTraj(ev); for (Int_t j=0;j<Ntraj;j++) { traj->fX = (ev+1)*(j+1); ... T->Fill(); } }Note in particular that you do not call event->Clear() in your loop.
By Definition T->Fill() copies to disk the entire event object. So the effect of the loop as is, is that the 10 event will contain exactly one Trajectory object with various value. The next 10 events will contain exactly two Trajectory object one with the same value for ALL 10 events and one with various values. The next 10 events will contain exactly 3 Trajectory object, two with the same values for ALL 10 events and one with various value for each event, etc.

Note also that given the code in the tar file and the look above, each of the TClonesArray contains at most one Trajectory.

If (and only if :slight_smile:) this code snippet represent your intent, it sounds like all you need a single TCloneArrays.

Cheers,
Philippe.

Thanks for your answers,

I put my remarks/question below :

[quote=“pcanal”]Hi,

However, it seems that you are misusing/misunderstanding how the TTree structure works. [Or maybe this is just an artefact of your simplify the real code] Your code reads: T->Branch("event","RootBox",&event,8000,2); for (Int_t ev=0;ev<nev;ev++) { traj = event->AddTraj(ev); for (Int_t j=0;j<Ntraj;j++) { traj->fX = (ev+1)*(j+1); ... T->Fill(); } }Note in particular that you do not call event->Clear() in your loop.
By Definition T->Fill() copies to disk the entire event object. So the effect of the loop as is, is that the 10 event will contain exactly one Trajectory object with various value. The next 10 events will contain exactly two Trajectory object one with the same value for ALL 10 events and one with various values. The next 10 events will contain exactly 3 Trajectory object, two with the same values for ALL 10 events and one with various value for each event, etc.

Note also that given the code in the tar file and the look above, each of the TClonesArray contains at most one Trajectory.

If (and only if :slight_smile:) this code snippet represent your intent, it sounds like all you need a single TCloneArrays.

Cheers,
Philippe.[/quote]

You’re absolutely right, I forget the event->Clear() :blush: when I created that example …
so concerning the code I really wanted to fill an array of TCloneArrays : in fact, my variable name (ev) :

represents the detector ID : I would like to fill one TCloneArray per detector. (I have maximum 20 detectors --> see in .cxx code). For each detector I fill X,Y,Z as following :

for (Int_t j=0;j<Ntraj;j++) { traj->fX = (ev+1)*(j+1); ...
ps : X, Y, Z contains have no physical meaning … :slight_smile:

Again I come back to my problem :
If you look the output rootfile, it seems that I cannot read the Traj Array … :frowning:
Each time I try to Draw :
tree->Draw(“fTraj[i].fX”) (i=0,1,2,… etc) I get the following error message :

The output you saw during the execution of Iko.C is just :

cout<< "x --> "<<(ev+1)*(j+1)<< "y --> "<<(ev+1)*(j+4)<< "z --> "<<(ev+1)*(j+412)<< endl;
and if you type : T->Show() after the tree is filled, it seems that the TCloneArray is not properly filled … :frowning:
I don’t see why the TCloneArray cannot be filled in such a way … :cry:

Thanks again :slight_smile:

Cheers

[quote]Each time I try to Draw :
tree->Draw(“fTraj[i].fX”) (i=0,1,2,… etc) I get the following error message :[/quote] This seems to actually be a problem in TTree::Draw that does not handle well an array of TClonesArray.

[quote]I would like to fill one TCloneArray per detector. (I have maximum 20 detectors --> see in .cxx code). For each detector I fill X,Y,Z as following [/quote]However you do not. In particular your TTree::Fill is most likely in the wrong place within your loops. Your loop: for (Int_t j=0;j<Ntraj;j++) { traj->fX = (ev+1)*(j+1); only set ONE trajectory (but sets it Ntraj times), is it really your intent (otherwise you need to get a new value for the ‘traj’ pointer for each iteration.

I am still unclear on how you want to organize your data. So far I understood that you have 20 detectors. For each detector you have many ‘Trajectory’. My question is how are those trajectory associated together?
Do you have the notion of ‘Events’? (i.e. is there yet another loop above the detector loop)?

My guess is that you should create one branch for each of the detectors.

Cheers,
Philippe.

Dear Philippe,

Mmh, interesting … but it seems that the problem is not coming from TTree->Draw() but it seems to me that the tree is not correctly filled. (One can follow that with TTree->Show())

Oops … :blush: yes indeed I played around with it and forgot to put it back … ! :cry:

[quote]
I am still unclear on how you want to organize your data. So far I understood that you have 20 detectors. For each detector you have many ‘Trajectory’. My question is how are those trajectory associated together?
Do you have the notion of ‘Events’? (i.e. is there yet another loop above the detector loop)?[/quote]
Ok may be that’s not the perfect way to show what I would like to do :
for each event, I have Nhits in each detector (the number of detectors can be large …):
–> so I decided to fill on TCloneArray per detector.

That would probably take more space, no ? and some variables for each detector a in common : In the TCloneArray version of the code, I would only fill them once (like EventNumber, RunNumber, etc ).

If I try to create one branch per detector, as following

for (Int_t ev=0;ev<nev;ev++) { T->Branch(Form("event_%d",ev),"RootBox",&event,8000,2); ...

it does not work … :cry: … It fills the same events for each Branch … (each Detector Branch contains the full detectors informations … :frowning: ) Do you have somewhere a working example for that kind of situation ?

Thanks again,

Cheers,
Hayg

[quote](One can follow that with TTree->Show()) [/quote]Well this one is also broken for array of TClonesArrays …

[quote]If I try to create one branch per detector, as following …t fills the same events for each Branch[/quote]As it should … you passed the same object to all the branches.

I attached a quick example showing what I mean. However I am still confused why you call your iterator over the detector ‘ev’ and why you call the branch for each detector ‘event’. (i.e. we still have a difference in our meaning of the word ‘event’).

Cheers,
Philippe.

PS. To run the example do:

root [0] .L example.C+ Info in <TUnixSystem::ACLiC>: creating shared library root [1] Create()
example.C (1.76 KB)