Variable length arrays in trees and classes from MakeClass

Hello,

I have in my tree several variable length arrays, similar to the examples given in the manual:

Tree->Branch("nTracks",(void *)&Tracks, "nTracks/I");
Tree->Branch("px",(void *)px, "px[nTracks]/F");

The number of tracks is of course random, from say 10 to 100.

I then need a small class to do some calculations. I get the skeleton with the “MakeClass” method. There, for the variable array “px”, I get

where this number 10 is of course the maximum number of tracks (maximum array length) per event I had in the tree from which the MakeClass method generates the skeleton.

But what if I had 50 tracks per events in my next tree? If you leave the size declaration at 10 and try to access track 11, you get a segmentation violation obviously.
It seems to me that I have to change the declaration of px[10] to px[50] either manually or get a new class through MakeClass. Does it mean that the class thus derived can only work for trees with a particular number of tracks, or maximum number of tracks?
Right now I have to tell people whom I give the code to change the 10 to whatever maximum number they get… not very user friendly!

How can I modify the declaration of “px”, or the class, such that it is not tied to a particular number of tracks, and that the same code can be used no matter this number, and not be changed each time?

Thanks for your help,

Thomas Speer.

If you have a collection of files (a TChain) and call MakeClass
on this chain, the code generated will be for the largest arrays in all
the files.
You can always change by hand the maximum dimensions.
You can see these parameters at the top of the include file.

rene

Hello,

Thanks for your prompt answer!
Yes, I agree that the generated code takes the largest number into account, and that it can quite easily be changed by hand. But if tomorrow I have a new tree, or I give this class to a colleague, I (or anybody else) do have to change that number by hand? No automatic way? Each time you have a new tree, you have to look at the maximum number of tracks, and increase the relevant number in the class declaration if needed? This is more troublesome when you share the code with multiple users, whom you all have to tell “Be carefull, etc,etc…”.! :confused:
Since I would like to use these classes for validation, where I want a script to do several things, it means that it can not really be automatic, since it should need to know the maximum length beforehand!

Cheers,

Thomas.

Thomas,

Why do you use TTree::MakeClass and not your original class
with support for fully dynamic structures?

Rene

Hi,

If for some odd reason your original classes are not available for your automatic validation, you can use TTree::MakeProxy instead of MakeClass. MakeProxy is solving a lot of the problems present in MakeClass (including the issue of array sizes).

Cheers,
Philippe.

Hello,

Sorry for the stupid question (newbe!): Which class do you refer to? The class which was used to create the TTree? It is part of a large reconstrction programm, and thus can not be used outside of it.

About the MakeProxy: I have now tried to used it, but find nearly no documentation on it. When I try to get a simple test running on that TTree using

tree->Process("proxyTest.h+","",1)

I have the following problem: in my tree, I have a branch with 3 variables, the 3 coordinates of a vertex:

vertexTree->Branch("simPos",(void *)result->simVertexPos(),"X/F:Y/F:Z/F");

The code which is generated by MakeProxy (VertexFitter->MakeProxy(“proxyTest”,“myScript.C”)) includes:

   struct TPx_simPos
   {
      TPx_simPos(TBranchProxyDirector* director,const char *top,const char *mid=0) :
         ffPrefix     (top,mid),
         obj          (director, top, mid),
         simPos       (director, "simPos"),
         simPos       (director, "simPos"),
         simPos       (director, "simPos")
      {};
      TPx_simPos(TBranchProxyDirector* director, TBranchProxy *parent, const char *membername) :
         ffPrefix     (""),
         obj          (director, parent, membername),
         simPos       (director, "simPos"),
         simPos       (director, "simPos"),
         simPos       (director, "simPos")
      {};
      TBranchProxyHelper ffPrefix;
      InjecTBranchProxyInterface();
      TBranchProxy obj;

      TFloatProxy   simPos;
      TFloatProxy   simPos;
      TFloatProxy   simPos;
   };

The output I get from the above Process method is then

(The 3 dots… are mine to ease the reading) Lines 76 and 77 are just the 2 last lines in the code excerpt: TFloatProxy simPos

Am I doing something wrong? I am using root 4.01/02

Cheers,

Thomas.

Unfortunately this type of TTree is not yet supported by ROOT (the fix will be uploaded in CVS shortly).
However, note that we discourage the usage of this syntax because it is not as sturdy as the alternative (part of the issue has to do with data member alignment possibly not being correctly guessed in this case).

Instead we recommend to either separate each of the value in 3 different branches or to generate the dictionary for your class and simply use the syntax:

simPos *pos = result->simVertexPos(); vertexTree->Branch("simPos",&pos);

Cheers,
Philippe.

OK, so now I removed all the simPos branches, to leave only the variable arrays as described in the first post (The nTracks and, say, px). I generate the .h with

where myScript.C contains only:

and try to get it running on 1 event using

I assumed this was the way to proceed, since there is nearly no documentation on this! The result I get is:

[quote]Info in TUnixSystem::ACLiC: creating shared library …/proxyTest_h.so
…/fileYav36Q.cxx: In member function ROOT::TBranchProxy& ROOT::TBranchProxy::operator=(const ROOT::TBranchProxy&)': .../fileYav36Q.cxx:498: non-static const memberconst TString ROOT::TBranchProxy::fBranchName’, can’t use default assignment operator
…/fileYav36Q.cxx:498: non-static const member const TString ROOT::TBranchProxy::fDataMember', can't use default assignment operator .../fileYav36Q.cxx:498: non-static const memberconst Bool_t ROOT::TBranchProxy::fIsMember’, can’t use default assignment operator
g++: …/fileYav36Q.o: No such file or directory
Error in : Compilation failed!
Error in TSelector::GetSelector: file proxyTest.h+ does not have a valid class deriving from TSelector
(long long)-1
[/quote]

Would a simple code like the tree2r example work also on variable length arrays? The example unfortunately reads only a single branch, and not the array! It is a pitty, since the tree2w writes just such an array!

Cheers,

Thomas.

Hi,

Both the original problem (simPos duplication) and your latest problem (operator=) have now been solved in the CVS repository.

You are correctly using the MakeProxy.

You might be able to work around the operator= problem by adding to your myScript.C the lines:

private: proxyTest& operator=(const proxyTest&); proxyTest(const proxyTest&); public:

[quote]Would a simple code like the tree2r example work also on variable length arrays? The example unfortunately reads only a single branch, and not the array! It is a pitty, since the tree2w writes just such an array!

[/quote] static Float_t vect[7]; t2->SetBranchAddress("vect",vect);