TTree and two-dimensional branches

Hello,

the following macro will yield the correct (well, expected) histogram only on the left but not on the right pad:

int branch()
{
  UChar_t njt;
  Float_t jtpt[10][1];
  
  TTree*   tree     = new TTree("t","t");
  TBranch* b_njt  = tree->Branch("njt", &njt,"njt/b");
  TBranch* b_jtpt = tree->Branch("jtpt",jtpt,"jtpt[njt][1]/F");
  
  for (unsigned ievt=0;ievt<1000;ievt++) {
    njt = gRandom->Integer(9);
    for (unsigned ijt=0;ijt<njt;ijt++) {
      jtpt[ijt][0] = 50.*gRandom->Exp(1.0);
    }
    tree->Fill();
  }
  
  gStyle->SetOptStat(1111);
  TCanvas* c = new TCanvas("c","c",0,500,1000,400);
  c->Divide(2,1);
  c->cd(1);
  tree->Draw("jtpt[][0]");
  c->cd(2);
  tree->Draw("jtpt");
  
  return 0;
}

Why? Is the ‘draw all’ not supported for two-dimensional branches?

I have browsed the forum for related posts and while I couldn’t find anything, I found a post which claimed that the array counter (njt above) must be Int_t?! Is that true, and also that it doesn’t save space to save it e.g. as an UChar_t? I have done that for a long time and didn’t experience problems.

One more thing (I suspect this is about C++ not ROOT): why can I not pass a two dimensional array (Float_t jtpt[10][1]) to a branch defined as “jtpt[njt]/F”, or in other words what is the difference between a 2D array with one of its dimension 1 and a 1D array?

Thanks a lot,
Philipp

Hi Philipp,

This is indeed a bug in the ’ tree->Draw(“jtpt”);’ which because of the size [1] is actually plotting only half the elements. If you have a size of 2 or more it works as expected.

[quote]I have browsed the forum for related posts and while I couldn’t find anything, I found a post which claimed that the array counter (njt above) must be Int_t?! Is that true, and also that it doesn’t save space to save it e.g. as an UChar_t? I have done that for a long time and didn’t experience problems. [/quote]This is correct the code assume that the index is an Int_t. However on little endian processors, the correct number is found ; the same code will fail on big endian processors.

why can I not pass a two dimensional array (Float_t jtpt[10][1]) to a branch defined as "jtpt[njt]/F", In my test this works as you would expect.

[quote] or in other words what is the difference between a 2D array with one of its dimension 1 and a 1D array? [/quote]The C++ type is different by the in-memory representation is the same.

Cheers,
Philippe.

Hi Philippe,

thank you for the clarification, the [1] case doesn’t make that much sense anyway. I concluded that there would be a general problem in this respect with two-dimensional arrays, good to know there is not! :slight_smile:

You are right, the Float_t jtpt[10][1] works indeed with “jtptp[10]/F” as you say!

However, what doesn’t work is:

Float_t** jtpt = new Float_t*[10]; for (Int_t i=0;i<10;i++) jtpt[i] = new Float_t[1];

which I hoped to be equivalent to Float_t jtpt[10][1], but it is not. What I am trying to do is to dynamically decide wether a branch represents a one- or two-dimensional array, using the Float_t**. Is there any way to resolve this?

Thanks,

Philipp

[quote]which I hoped to be equivalent to Float_t jtpt[10][1][/quote]Even-though both can be used using the C++ code, their memory layout is very different, and indeed ‘tptp[10]/F’ can not handle the array of pointers to arrays. If you need a flexible construct I recommend that you use a vector<vector > (for which you will need to generate a dictionary).

Cheers,
Philippe.