Problem to read tree with branches which contain arrays

I want to handle trees like this:

******************************************************************************
*Tree    :Expcvadc  : Event "Expcvadc", ID 3                                 *
*Entries :      398 : Total =           27171 bytes  File  Size =      27187 *
*        :          : Tree compression factor =   1.00                       *
******************************************************************************
*Br    0 :ADC0      : nADC0/I:ADC0[nADC0]/s                                  *
*Entries :      398 : Total  Size=      16572 bytes  File Size  =      16003 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*
*Br    1 :TIME      : nTIME/I:TIME[nTIME]/D                                  *
*Entries :      398 : Total  Size=      10216 bytes  File Size  =       9635 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*

These trees contain branches with arrays. I want to dump some values into text
file, e.g.,

     0   3958      0      1.00      1.00
     ...
     3   1926   3522      3.00      0.00
     4   3958      0      4.00      1.00
     ...
     9   3960      0     14.00      0.00

If only to handle branches with int arrays (e.g., “nADC0/I:ADC0[nADC0]/s”), the
following code works fine:

typedef struct MY_ADC_STRUCT {
  Int_t   m_nADC;
  Short_t m_ADC[16];
} MY_ADC;

ofstream fout("treedump.txt");

MY_ADC rADC0;
TFile* f=new TFile("mydata.root");
TTree* T=(TTree*) f->Get("Expcvadc");
T->SetBranchAddress("ADC0", &rADC0);
for(Long64_t i=0;i<T->GetEntries(); i++) {
  fout << i << " " << rADC0.m_ADC[0] << std::endl;
}

But if the branches contain double arrays (e.g., “nTIME/I:TIME[nTIME]/D”), the following code works
quite unexpectedly. I got only zeros.

typedef struct MY_TIME_STRUCT {
  Int_t    m_nTIME;
  Double_t m_TIME[2];
} MY_TIME;

ofstream fout("treedump.txt");

MY_TIME rTIME;
TFile* f=new TFile("mydata.root");
TTree* T=(TTree*) f->Get("Expcvadc");
T->SetBranchAddress("TIME", &rTIME);
for(Long64_t i=0;i<T->GetEntries(); i++) {
  fout << i << " " << rTIME.m_TIME[0] << std::endl;
}

I checked the ROOT manual, and searched the web. I didn’t find the reason. I
also tried the “T->MakeClass(…)” and “T->MakeSelector(…)”. At last, only the
generated selector works expectedly. All the test files including root data are
attached here.

I want to know, why the similar code works only with int arrays.
dump_test.tgz (15.4 KB)

Search for “padding” in the TTree class description:

  1. sizeof(Int_t) > sizeof(Short_t) and that’s why it works when the “MY_ADC_STRUCT” is “interpreted” or “compiled”,
  2. sizeof(Int_t) < sizeof(Double_t) and then it will only work if you create a “compiled” dictionary for the “MY_TIME_STRUCT” typedef (i.e. try to use ACLiC to load your macro, something like “.L AllMyTypedefs.cxx++”).

Well, in general, I think you should recreate your tree with “proper” padding (and alignment), but if you cannot do this, here’s a “brutal fix” for reading it (it can be used as “interpreted” or “compiled” macro): [code]#include “TFile.h”
#include “TTree.h”

#include

typedef struct MY_ADC_STRUCT {
Int_t m_nADC;
Short_t m_ADC[16];
} MY_ADC;

MY_ADC rADC0;

typedef struct MY_TIME_STRUCT {
Int_t m_nTIME;
UChar_t WTF[(8 * 2)]; // Double_t m_TIME[2];
} MY_TIME;

MY_TIME rTIME;

TFile *f = 0;
TTree *T = 0;

void trial(void) {
f = TFile::Open(“run00025.root”, “READ”);
if (!f) return; // just a precaution
// f->ls();
f->GetObject(“Expcvadc”, T);
if (!T) return; // just a precaution
// T->Print();
T->SetBranchAddress(“ADC0”, ((Int_t*)(&rADC0)));
T->SetBranchAddress(“TIME”, ((Int_t*)(&rTIME)));
Long64_t nevents = T->GetEntries();
// if (nevents > 10) nevents = 10; // dump just the first 10 entries
for(Long64_t i = 0; i < nevents; i++) {
std::cout << “… " << i << " …” << std::endl;
T->GetEntry(i);
if (rADC0.m_nADC > 0) {
std::cout << " ADC0 [ " << rADC0.m_nADC << " ] = ";
for (Int_t j = 0; j < rADC0.m_nADC; j++)
std::cout << " " << rADC0.m_ADC[j];
std::cout << std::endl;
}
if (rTIME.m_nTIME > 0) {
std::cout << " TIME [ " << rTIME.m_nTIME << " ] = ";
for (Int_t j = 0; j < rTIME.m_nTIME; j++)
std::cout << " " << (((Double_t)(&(rTIME.WTF[(8 * j)]))));
std::cout << std::endl;
}
}
}[/code]