Reading data from TLeaf returns false values

Hello everyone,
I’m creating a data file filled with ULong64_t data read from a txt file. The code I wrote looks like this:

ULong64_t var;
TFile* output_file = new TFile("input_data.root", "RECREATE");
TTree* tree=new TTree("Data","Data");

tree->Branch("var",&var,"var/l");

while(text_file.good())
{
   if(text_file.eof()) break;
   getline(text_file,line);
   var = stol(line);
   tree->Fill();
}
output_file->Write();

Then I’m trying to read this data with another program like this:

TFile *file = new TFile("input_data.root", "READ");
TTree *tree = (TTree*) file->Get("Data");
TBranch* branch = (TBranch*) tree->GetBranch("var");
TLeaf *l_var = (TLeaf*)tree->GetLeaf("var");

const int nents = branch->GetEntries();
for(int i=0; i<nents;i++)
{
    cout << l_var->GetValueLong64(i);
}

The script above should display values stored in var leaf, but it returns random numbers instead. I suspect this is because of my data structure. When I try

l_var->GetLen()

it returns 1 instead of real number of elements in var. How should I fill the Tree for my script to work correctly?

ROOT Version: 6.19
Platform: Manjaro Gnome 3.34
Compiler: gcc 9.2


Hi,

@pcanal can surely help here.

This is supposed to be the number of elements per entry which seems to the case in the way you are reading the input file, what am I missing?

On your ‘output’ ROOT file, what does

Data->Scan("var");

prints to the screen (i.e. the expected value or ‘random numbers’?)

Thank you for your responces.

I did

tree->Scan("var");

both before writing file and after reading it in another script. It reads right values. The problem I have lies in this piece of code

const int nents = branch->GetEntries();
for(int i=0; i<nents;i++)
{
    cout << l_var->GetValueLong64(i);
}

and is twofold:

  1. When I try to set nents = l_var->GetLen() the loop iterates once as if var had one element (it has over 100k ULongs written in it)
  2. When I run the loop with right nents (over 100k) I get with l_var->GetValueLong64(i); random values (mostly 0s, sometimes other numbers) instead of values stored in “var”.

This is output of tree->print()

******************************************************************************
*Tree    :Data      : Data                                                   *
*Entries :   100231 : Total =         1609703 bytes  File  Size =      17505 *
*        :          : Tree compression factor =  91.39                       *
******************************************************************************
*Br    0 :dev_ID    : dev_ID/l                                               *
*Entries :   100231 : Total  Size=     804752 bytes  File Size  =       7312 *
*Baskets :       25 : Basket Size=      32000 bytes  Compression= 109.39     *
*............................................................................*
*Br    1 :var       : var/l                                                  *
*Entries :   100231 : Total  Size=     804659 bytes  File Size  =      10193 *
*Baskets :       25 : Basket Size=      32000 bytes  Compression=  78.48     *
*............................................................................*

According to your tree->print();, this is the right value. There is only one value per TTree entry.

When I run the loop with right nents (over 100k) I get with l_var->GetValueLong64(i); random values (mostly 0s, sometimes other numbers) instead of values stored in “var”.

Can you send me the file so I can investigate the problem?

input_data.root (452.4 KB)
timedist.cc (986 Bytes)

input_data.root is a file generated from txt file with a piece of code I posted in the first messege. Data stored in it looks correct. timedist.cc is a script with which i try to work on the data.
I’m pretty sure my problem is caused by lack of knowledge about TTree data structure and how to create it properly, because this method of getting data works on files created with other people’s scripts. I just don’t have acess to their code to see how they fill the tree.

FYI, the file contains this data:

$> root-dump ./input_data.root
>>> file[./input_data.root]
key[000]: Data;1 "Data" (TTree)
[000][dev_ID]: 7044
[000][timestamp]: 1542909667832
[001][dev_ID]: 7044
[001][timestamp]: 1542914704622
[002][dev_ID]: 7044
[002][timestamp]: 1542917044017
[003][dev_ID]: 7044
[003][timestamp]: 1542918533305
[...]
[100227][dev_ID]: 8327
[100227][timestamp]: 1549420051561
[100228][dev_ID]: 8327
[100228][timestamp]: 1549596914556
[100229][dev_ID]: 8327
[100229][timestamp]: 1549641972080
[100230][dev_ID]: 8327
[100230][timestamp]: 1549699592149

i.e. the TTree named "Data" contains 100231 entries, with every entry containing 2 scalars (dev_ID and timestamp).

This is the main problem … but let’s get back to that.

The TTree in the file input_data.root has the structure:

******************************************************************************
*Tree    :Data      : Data                                                   *
*Entries :   100231 : Total =         1609598 bytes  File  Size =     458293 *
*        :          : Tree compression factor =   3.51                       *
******************************************************************************
*Br    0 :dev_ID    : dev_ID/l                                               *
*Entries :   100231 : Total  Size=     804583 bytes  File Size  =       7474 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression= 107.54     *
*............................................................................*
*Br    1 :timestamp : timestamp/l                                            *
*Entries :   100231 : Total  Size=     804673 bytes  File Size  =     449948 *
*Baskets :       26 : Basket Size=      32000 bytes  Compression=   1.79     *
*............................................................................*

which means that there is a single value of dev_id and timestamp for each entry (i.e. l_var->GetLen() returns the expected value: “1”.

On the other hand the TTree and the TLeaf has many entries ( 100231)

The code provide loops properly (albeit in an unusual way, in particular not support TChain):

	const int nents = branch->GetEntries();
	for(int i=0; i<nentries;i++)

(as a side note the correct type for the number of entries is “Long64_t” or “long long”).

but it is then using the index variable incorrectly.:

cout << l_timestamp->GetValueLong64(i) << endl;

2 problems. The dynamic range of the parameter of GetValueLong64 is [0, l_timestamp->GetLen() [ whereas the code is passing [0, branch->GetEntries() [
and worse … it never actually loads the data.

The smallest change to make the code works is

	const int nents = branch->GetEntries();  // in rare case 2 branches may have a different number of entries, so technically the wrong branch is used here.
	for(int i=0; i<nentries;i++) {
                 l_timestamp->GetBranch()->GetEntry(i);
		cout << l_timestamp->GetValueLong64(0) << endl;
          }

and a more usual way to write this.

	for(Long64_t i=0; i < tree->GetEntriesFast(); ++i) {
               Long64_t localentry = tree->LoadTree( i ); // this is needed in case of a TChain and to enable the TTreeCache.
                l_timestamp->GetBranch()->GetEntry( localentry );
		cout << l_timestamp->GetValueLong64(0) << endl;
          }

But then we have to go back on the way you created input_data.root you may or many not have intended on having ‘arrays’ inside each entry (in which case GetLen would be greater than one). It really depends on the semantic (and ‘shape’) of your data …

Cheers,
Philippe.

Thank you for your insights. I’m selflearner and that’s why my code can be a mess.