Home | News | Documentation | Download

GetEntries() returns a negative number


ROOT Version: 6.18/04
Platform: Ubuntu 18.04
Compiler: gcc 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)


Dear co-rooters,

I’m trying to perform a rather simple task: open a root file, read a TTree, do some calculation and add a new TBranch to the TTree.

Things work fine in small size files (i.e. <5Gb)

I tried to run that code in a ~30Gb file but I can’t get it to execute. It returns a negative number of entries and then aborts without any errors.

I believe that his is due to the file size, but is it?
Oddly enough, opening the root file in an interactive root session and issuing Tree->GetEntries() returns a reasonable number so I’m not convinced it’s that.
Any ideas?

Thanks in advance!

//Executing the macro
root [1] add_coincidences("runs_26068_26766.root.root", 500.)
Total entries found: -1747421737
         10        20        30        40        50        60        70        80        90        100 %
 ---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|    

Real time 0:00:00, CP time 0.060
//Get the entries by manually opening the file
root [2] new TFile("runs_26068_26766.root.root")
(TFile *) 0x55bfadb69100
root [3] tree->GetEntries()
(long long) 2547545559

My code is the following

#include "TFile.h"
#include "TTree.h"
#include "TBranch.h"
#include "TSystem.h"
#include "TStopwatch.h"

#include <iostream>
using namespace std;



void add_coincidences(TString filename_in, float coincidence_cut){





//This is to time the execution
TStopwatch timer;
timer.Start();





//_____________________________________________________________________________________________________________________
//(0) Usefull variables
	
	//(a) To read and add the new TBranch to the tree
	double tof, tof0; 
	double dt_min;                             
	int    detn;
	
	//(b) To calculate coincidences while looping over the tree                                 
	double tof_current  = -1.e10;
	double dt           = 0.;
	double dt_current   = 0.;
	int    detn_current = 0;
	int    ii           = 0;// For the nested loop over the tree
	
	//(c) To store the entry/row when the coincidence is found; saves a loooot of time
	float dt_min_pair_23 = 6.e6;
	float dt_min_pair_67 = 6.e6;
	int ii_pair_23       = -1;
	int ii_pair_67       = -1;
	




//_____________________________________________________________________________________________________________________	
//(1) Copy the root file, open it and get the branches

	// (a) Copy the file - the new filename will end in .root.root - I will change it in the future
	//TString new_filename_in = filename_out;
	//cout << "Copying file " << filename_in.Data() << " to " << new_filename_in.Data() << endl;
	//gSystem->Exec( TString::Format("cp %s %s", filename_in.Data(), new_filename_in.Data()) );	
	
	// (b) Open the copied file and get the DICER tree
	TFile *f_root = TFile::Open(filename_in, "UPDATE");
	TTree *t      = (TTree*)f_root->Get("DICER");

	// (c) Assign the branch addresses
	t->SetBranchAddress("ntof0", &tof0);
	t->SetBranchAddress("detn" , &detn);
	t->SetBranchAddress("ntof" , &tof);
	
	// (d) Define the new TBranch
	TBranch *bdt = t->Branch("dt_min", &dt_min);

	// (e) Get the TTree entries
	int entries = t->GetEntries();
	std::cout << "Total entries found: " << entries << std::endl;
	



	
//_____________________________________________________________________________________________________________________
// (2) Loop over the entries
	
	//(a) These are for the progress bar
	float	j = entries/100.;
	int 	n = 1;
	

	n =1;
	printf("         10        20        30        40        50        60        70        80        90        100 %%\n");
	printf(" ---------|---------|---------|---------|---------|---------|---------|---------|---------|---------|    \n");
	

	// (b) Start looping
	for (int i=0; i<entries; ++i){
		if(i == 0) {cout << "|";}
		if(i >= n*j) {cout << '|' << flush; n++;}// Progress indicator
		
		t->GetEntry(i);
		
		//Makes no sense to calculate coincidences when the T0 is bad
		if(tof0<=0){
			dt_min = -1.e10;
			bdt->Fill();
			continue;
		}
		
		//We care about coincidences only in the pairs 2/3 and 6/7
		if(detn!=2 && detn!=3 && detn!=6 && detn!= 7){
			dt_min = -detn*1.e10;
			bdt->Fill();
			continue;
		}

		//If the current event is in coincidence with a previous one, we don't need to re-calculate - 2/3 pair
		if ( i==ii_pair_23 ){
			ii_pair_23     = -1.;
			dt_min         = -dt_min_pair_23;
			dt_min_pair_23 = -6.e6;
			bdt->Fill();
			continue;
		}
		
		//If the current event is in coincidence with a previous one, we don't need to re-calculate - 6/7 pair
		if ( i==ii_pair_67 ){
			ii_pair_67     = -1.;
			dt_min         = -dt_min_pair_67;
			dt_min_pair_67 = -6.e6;
			bdt->Fill();
			continue;
		}
		
		
		// Look for coincidences in the 2/3 pair
		if(detn==2 || detn==3){
			
			dt           = detn*1.e10; // Initialise dt with a huge value
			detn_current = detn;       // Store which detector we are currently looking at
			tof_current  = tof;        // Store the tof of the current detector
			
			//Let's start nest-looping from the next line onwards; I'm relying on my break conditions here
			for( ii=i+1; ii<entries; ++ii){
				
				t->GetEntry(ii);
						
				// Applying a coincidence window/cut makes it run ~25% faster
				if ( fabs(dt)>coincidence_cut && dt!=detn_current*1.e10 ){
					ii_pair_23     = ii;                 //Grab the entry; I won't have to re-calculate coincidences in the other end
					dt_min         = 2.*coincidence_cut; //Just fill the TTree with a (maybe not so) meaningless 
					dt_min_pair_23 = dt_min;             //Grab also the coincidence time
					bdt->Fill();
					break;
				}
					
				// If there's a new T0 stop
				if( detn==200 ){
					dt_min = dt;
					bdt->Fill();
					break;
				}
				
				//Don't waste time looking detectors in the other pair
				if(detn!=2 && detn!=3){
					continue;
				}
				
				//At last, calculate the time difference in the opposite end
				if( detn!=detn_current ){
					dt_current = tof_current-tof;
					if ( fabs(dt_current) < fabs(dt) ){// |current| < |minimum|
						dt = dt_current;
						ii_pair_23     = ii;
						dt_min_pair_23 = dt;
					}
					else{//It makes no sense to continue calculating if we no longer have a minimum dt
						dt_min = dt;
						bdt->Fill();
						break;
					}
				}
  	
			}//_loop over the second loop over entries
		}//_detn = 2 || 3
	
	
		// Look for coincidences in the 6/7 pair
		else if(detn==6 || detn==7){
			
			dt           = detn*1.e10;
			detn_current = detn;//Store which detector we are looking at
			tof_current  = tof;
			
			//Let's start nest-looping from the next line onwards; I'm relying on my break conditions here
			for( ii=i+1; ii<entries; ++ii){
				
				t->GetEntry(ii);
					
					
				// Applying a coincidence window/cut makes it run ~25% faster
				if ( fabs(dt)>coincidence_cut && dt!=detn_current*1.e10 ){
					ii_pair_67     = ii;                 //Grab the entry; I won't have to re-calculate coincidences in the other end
					dt_min         = 2.*coincidence_cut; //Just fill the TTree with a (maybe not so) meaningless 
					dt_min_pair_67 = dt_min;             //Grab also the coincidence time
					bdt->Fill();
					break;
				}
					
				// If there's a new T0 stop
				if( detn==200 ){
					dt_min = dt;
					bdt->Fill();
					break;
				}
				
				//Don't waste time looking detectors in the other pair	
				if(detn!=6 && detn!=7){
					continue;
				}
				
				//At last, calculate the time difference in the opposite end
				if( detn!=detn_current ){
					dt_current = tof_current-tof;
					if ( fabs(dt_current) < fabs(dt) ){// |current| < |minimum|
						dt = dt_current;
						ii_pair_67     = ii;
						dt_min_pair_67 = dt;
					}
					else{//It makes no sense to continue calculating if we no longer have a minimum dt
						dt_min = dt;
						bdt->Fill();
						break;
					}
				}
  	
			}//_loop over the second loop over entries
		}//_detn = 6 || 7

	}//_loop over entries
	
	std::cout << std::endl;
	

	t->Write();
	f_root->Close();

	timer.Stop();
	timer.Print();

}

Hello,

Could it be because in your code the file is opened in ""UPDATE" mode while it’s not the case from the ROOT prompt? I don’t see any other difference a priori.

@pcanal any idea why GetEntries might return -1 on a tree stored in a 30 Gb file (see user’s code).

Thanks for your post!

It’s not related to the UPDATE

root [0] TFile *f1 = TFile::Open("runs_26068_26766.root.root", "UPDATE")
(TFile *) 0x557827127ef0
root [3] tree->GetEntries()
(long long) 2547545559

You meant

   Long64_t entries = t->GetEntries();
   std::cout << "Total entries found: " << entries << std::endl;

int is limited to 2.9e9 entries. It is likely that you large TTree has more entries than that.

You are perfectly right.
Thanks a lot!