Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TEntryListFromFile.cxx
Go to the documentation of this file.
1 // @(#)root/tree:$Id$
2 // Author: Anna Kreshuk 17/03/2007
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TEntryListFromFile
13 \ingroup tree
14 
15 Manages entry lists from different files, when they are not loaded
16 in memory at the same time.
17 
18 This entry list should only be used when processing a TChain (see
19 TChain::SetEntryList() function). File naming convention:
20 - by default, filename_elist.root is used, where filename is the
21  name of the chain element.
22 - xxx$xxx.root - $ sign is replaced by the name of the chain element
23 If the list name is not specified (by passing filename_elist.root/listname to
24 the TChain::SetEntryList() function, the first object of class TEntryList
25 in the file is taken.
26 It is assumed that there are as many lists, as there are chain elements,
27 and they are in the same order.
28 
29 If one of the list files can't be opened, or there is an error reading a list
30 from the file, this list is skipped and the entry loop continues on the next
31 list.
32 */
33 
34 #include "TEntryListFromFile.h"
35 #include "TBuffer.h"
36 #include "TObjArray.h"
37 #include "TFile.h"
38 #include "TKey.h"
39 #include "TError.h"
40 #include "TTree.h"
41 
42 ClassImp(TEntryListFromFile);
43 
44 TEntryListFromFile::TEntryListFromFile(): TEntryList(),
45  fListFileName(""), fListName(""), fNFiles(0), fListOffset(0), fFile(0), fFileNames(0)
46 {
47  // default constructor.
48 
49 }
50 
51 ////////////////////////////////////////////////////////////////////////////////
52 /// File naming convention:
53 /// - by default, filename_elist.root is used, where filename is the
54 /// name of the chain element
55 /// - xxx$xxx.root - $ sign is replaced by the name of the chain element
56 ///
57 /// The TObjArray of chain elements is set by the TEntryListFromFile::SetFileNames()
58 /// function.
59 ///
60 /// If the list name is not specified, the first object of class TEntryList
61 /// in the file is taken.
62 ///
63 /// nfiles is the total number of files to process
64 
65 TEntryListFromFile::TEntryListFromFile(const char *filename, const char *listname, Int_t nfiles) : TEntryList(),
66  fListFileName(filename), fListName(listname), fNFiles(nfiles), fListOffset(0), fFile(0), fFileNames(0)
67 {
68  fListOffset = new Long64_t[fNFiles+1];
69  fListOffset[0]=0;
70  for (Int_t i=1; i<fNFiles+1; i++){
71  fListOffset[i]=TTree::kMaxEntries;
72  }
73  fN = TTree::kMaxEntries;
74 }
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// d-tor
78 
79 TEntryListFromFile::~TEntryListFromFile()
80 {
81  delete [] fListOffset;
82  fListOffset = 0;
83  delete fFile;
84  fFile = 0;
85 }
86 
87 ////////////////////////////////////////////////////////////////////////////////
88 /// Returns entry \#index
89 /// See also Next() for a faster alternative
90 
91 Long64_t TEntryListFromFile::GetEntry(Int_t index)
92 {
93  if (index<0) return -1;
94 
95  if (index > fListOffset[fNFiles] && fListOffset[fNFiles]!=TTree::kMaxEntries){
96  Error("GetEntry", "Index value is too large\n");
97  return -1;
98  }
99 
100  if (index==fLastIndexQueried+1)
101  return Next();
102 
103  Int_t itree =0;
104  while (!fCurrent && itree<fNFiles){
105  LoadList(itree);
106  itree++;
107  }
108  if (itree == fNFiles){
109  Error("GetEntry", "All lists are empty\n");
110  return -1;
111  }
112 
113  if (index < fListOffset[fTreeNumber]) {
114  //this entry is in one of previously opened lists
115  itree=0;
116  for (itree=0; itree<fTreeNumber; itree++){
117  if (index >= fListOffset[itree] && fListOffset[itree]!=fListOffset[itree+1])
118  break;
119  }
120  LoadList(itree);
121  }
122  else if (index >= fListOffset[fTreeNumber+1]){
123  //this entry is in one of following lists
124  itree = fTreeNumber;
125  while (itree < fNFiles){
126  itree++;
127  if (fListOffset[itree+1]==TTree::kMaxEntries){
128  //this list hasn't been loaded yet
129  LoadList(itree);
130  }
131  if (index < fListOffset[itree+1]){
132  //the entry is in this list
133  break;
134  }
135  }
136  if (fTreeNumber == fNFiles){
137  Error("GetEntry", "Entry number is too big\n");
138  return -1;
139  }
140  if (fTreeNumber!=itree)
141  LoadList(itree);
142  }
143  //now the entry is in the currently opened list
144  Long64_t localentry = index - fListOffset[fTreeNumber];
145  Long64_t retentry = fCurrent->GetEntry(localentry);
146  fLastIndexQueried = index;
147  fLastIndexReturned = retentry;
148  return retentry;
149 
150 }
151 
152 ////////////////////////////////////////////////////////////////////////////////
153 /// Return the entry corresponding to the index parameter and the
154 /// number of the tree, where this entry is
155 
156 Long64_t TEntryListFromFile::GetEntryAndTree(Int_t index, Int_t &treenum)
157 {
158  Long64_t result = GetEntry(index);
159  treenum = fTreeNumber;
160  return result;
161 }
162 
163 ////////////////////////////////////////////////////////////////////////////////
164 /// Returns the total number of entries in the list.
165 /// If some lists have not been loaded, loads them.
166 
167 Long64_t TEntryListFromFile::GetEntries()
168 {
169  if (fN==TTree::kMaxEntries){
170  for (Int_t i=0; i<fNFiles; i++){
171  if (fListOffset[i+1]==TTree::kMaxEntries){
172  LoadList(i);
173  }
174  }
175  }
176  fN = fListOffset[fNFiles];
177  fLastIndexQueried = -3;
178  return fN;
179 }
180 
181 ////////////////////////////////////////////////////////////////////////////////
182 /// Returns the next entry in the list.
183 /// Faster than GetEntry()
184 
185 Long64_t TEntryListFromFile::Next()
186 {
187  Int_t itree =0;
188  while (!fCurrent && itree<fNFiles){
189  LoadList(itree);
190  itree++;
191  }
192  if (itree == fNFiles){
193  Error("Next", "All lists are empty\n");
194  return -1;
195  }
196 
197  Long64_t retentry = fCurrent->Next();
198  if (retentry<0){
199  if (fLastIndexQueried == fListOffset[fTreeNumber+1]-1){
200  //requested entry is in the next list
201  if (fTreeNumber == fNFiles -1){
202  // Error("Next", "No more entries, last list\n");
203  return -1;
204  }
205  do{
206  //load the next non-empty list. fTreeNumber is changed by LoadList()
207  fTreeNumber++;
208  LoadList(fTreeNumber);
209  } while (fListOffset[fTreeNumber+1]==fListOffset[fTreeNumber] && fTreeNumber<fNFiles-1);
210  if (fTreeNumber == fNFiles -1 && fListOffset[fTreeNumber+1]==fListOffset[fTreeNumber]){
211  //no more lists
212  return -1;
213  }
214  retentry = fCurrent->Next();
215  } else {
216  Error("Next", "Something wrong with reading the current list, even though thefile #%d and the list exist\n", fTreeNumber);
217  return -1;
218  }
219 
220  }
221 
222  fLastIndexQueried++;
223  fLastIndexReturned = retentry;
224  return retentry;
225 
226 }
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 /// Loads the list \#listnumber
230 /// This is the only function that can modify fCurrent and fFile data members
231 
232 Int_t TEntryListFromFile::LoadList(Int_t listnumber)
233 {
234  //first close the current list
235  if (fCurrent){
236  if (fFile) {
237  delete fFile;
238  fFile = 0;
239  fCurrent = 0;
240  }
241  }
242 
243  R__ASSERT(fFileNames);
244 
245  //find the right name
246  //get the name of the corresponding chain element (with the treenumber=listnumber)
247  TNamed *nametitle = (TNamed*)fFileNames->At(listnumber);
248  TString filename_short = nametitle->GetTitle();
249  if (filename_short.Contains(".root")){
250  filename_short.Remove(filename_short.Length()-5, 5);
251  }
252  if (!strcmp(fListFileName.Data(), "")){
253  //no name supplied, use the one of the chain file
254  filename_short.Append("_elist.root");
255  //printf("filename: %s\n", filename_short.Data());
256  fFile = TFile::Open(filename_short.Data());
257  } else {
258  TString filename = fListFileName;
259  filename.ReplaceAll("$", filename_short);
260  //printf("filename: %s\n", filename.Data());
261  fFile = TFile::Open(filename.Data());
262  }
263 
264  if (!fFile || fFile->IsZombie()){
265  if (fFile) {
266  delete fFile;
267  fFile = 0;
268  }
269  fCurrent = 0;
270  fListOffset[listnumber+1] = fListOffset[listnumber];
271  return -1;
272  }
273 
274  if (!strcmp(fListName.Data(), "")){
275  TKey *key;
276  TIter nextkey(fFile->GetListOfKeys());
277  while ((key=(TKey*)nextkey())){
278  if (strcmp("TEntryList", key->GetClassName())==0){
279  //found an object of class TEntryList
280  fCurrent = (TEntryList*)key->ReadObj();
281  }
282  }
283  } else {
284  fCurrent = (TEntryList*)fFile->Get(fListName.Data());
285  }
286 
287  if (!fCurrent){
288  Error("LoadList", "List %s not found in the file\n", fListName.Data());
289  fCurrent = 0;
290  fListOffset[listnumber+1]=fListOffset[listnumber];
291  return -1;
292  }
293  fTreeNumber = listnumber;
294  Long64_t nentries = fCurrent->GetN();
295  if (fListOffset[fTreeNumber+1] != (fListOffset[fTreeNumber] + nentries)) {
296  fListOffset[fTreeNumber+1] = fListOffset[fTreeNumber] + nentries;
297  fN = fListOffset[fNFiles];
298  }
299 
300  return 1;
301 }
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 /// Print info about this list
305 
306 void TEntryListFromFile::Print(const Option_t* option) const
307 {
308  printf("total number of files: %d\n", fNFiles);
309  TFile *f;
310  TEntryList *el=0;
311  if (fFileNames==0) {
312  Error("Print","fFileNames was not set properly.");
313  } else {
314  for (Int_t listnumber=0; listnumber<fNFiles; listnumber++){
315  TNamed *nametitle = (TNamed*)fFileNames->At(listnumber);
316  TString filename_short = nametitle->GetTitle();
317  if (filename_short.Contains(".root")){
318  filename_short.Remove(filename_short.Length()-5, 5);
319  }
320  if (!strcmp(fListFileName.Data(), "")){
321  //no name supplied, use the one of the chain file
322  filename_short.Append("_elist.root");
323  //printf("filename: %s\n", filename_short.Data());
324  f = TFile::Open(filename_short.Data());
325  } else {
326  TString filename = fListFileName;
327  filename.ReplaceAll("$", filename_short);
328  //printf("filename: %s\n", filename.Data());
329  f = TFile::Open(filename.Data());
330  }
331  if (f && !f->IsZombie()){
332  if (!strcmp(fListName.Data(), "")){
333  TKey *key;
334  TIter nextkey(f->GetListOfKeys());
335  while ((key=(TKey*)nextkey())){
336  if (strcmp("TEntryList", key->GetClassName())==0){
337  //found an object of class TEntryList
338  el = (TEntryList*)key->ReadObj();
339  }
340  }
341  } else {
342  el = (TEntryList*)f->Get(fListName.Data());
343  }
344  if (el)
345  el->Print(option);
346  }
347  }
348  }
349 
350 }