source: trunk/MagicSoft/Mars/mbase/MReadTree.cc@ 1048

Last change on this file since 1048 was 1036, checked in by tbretz, 23 years ago
*** empty log message ***
File size: 16.5 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 12/2000 (tbretz@uni-sw.gwdg.de)
19!
20! Copyright: MAGIC Software Development, 2000-2001
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26// //
27// MReadTree //
28// //
29// This tasks opens all branches in a specified tree and creates the //
30// corresponding parameter containers if not already existing in the //
31// parameter list. //
32// //
33// The Process function reads one events from the tree. To go through the //
34// events of one tree make sure that the event number is increased from //
35// outside. It makes also possible to go back by decreasing the number. //
36// //
37// If you don't want to start reading the first event you have to call //
38// MReadTree::SetEventNum after instantiating your MReadTree-object. //
39// //
40// To make reading much faster (up to a factor of 10 to 20) you can //
41// ensure that only the data you are really processing is enabled by //
42// calling MReadTree::UseLeaf. //
43// //
44// If the chain switches from one file to another file all //
45// TObject::Notify() functions are called of TObject objects which were //
46// added to the Notifier list view MReadTree::AddNotify. If MReadTree //
47// is the owner (viw MReadTree::SetOwner) all this objects are deleted //
48// by the destructor of MReadTree //
49// //
50/////////////////////////////////////////////////////////////////////////////
51#include "MReadTree.h"
52
53#include <fstream.h>
54
55#include <TFile.h> // TFile::GetName
56#include <TChain.h>
57#include <TGProgressBar.h>
58#include <TChainElement.h>
59#include <TOrdCollection.h>
60
61#include "MLog.h"
62#include "MLogManip.h"
63
64#include "MTime.h"
65#include "MParList.h"
66#include "MTaskList.h"
67
68ClassImp(MReadTree);
69
70// --------------------------------------------------------------------------
71//
72// Default constructor. It creates an TChain instance which represents the
73// the Tree you want to read and adds the given file (if you gave one).
74// More files can be added using MReadTree::AddFile.
75// Also an empty veto list is created. This list is used if you want to
76// veto (disable or "don't enable") a branch in the tree, it vetos also
77// the creation of the corresponding object.
78// An empty list of TObjects are also created. This objects are called
79// at any time the TChain starts to read from another file.
80//
81MReadTree::MReadTree(const char *tname, const char *fname,
82 const char *name, const char *title)
83 : fNumEntry(0), fBranchChoosing(kFALSE), fAutoEnable(kTRUE), fProgress(NULL)
84{
85 fName = name ? name : "MReadTree";
86 fTitle = title ? title : "Task to loop over all events in one single tree";
87
88 fVetoList = new TOrdCollection;
89 fVetoList->SetOwner();
90
91 fNotify = new TOrdCollection;
92
93 //
94 // open the input stream
95 //
96 fChain = new TChain(tname);
97 fChain->SetNotify(this);
98
99 if (fname)
100 fChain->Add(fname);
101}
102
103// --------------------------------------------------------------------------
104//
105// Destructor. It deletes the TChain and veto list object
106//
107MReadTree::~MReadTree()
108{
109 //
110 // Delete all the pointers to pointers to the objects where the
111 // branche data gets stored.
112 //
113 TIter Next(fChain->GetStatus());
114
115 TChainElement *element = NULL;
116 while ((element=(TChainElement*)Next()))
117 delete (MParContainer**)element->GetBaddress();
118
119 //
120 // Delete the chain and the veto list
121 //
122 delete fChain;
123 delete fNotify;
124 delete fVetoList;
125}
126
127// --------------------------------------------------------------------------
128//
129// If the owner flag is set all TObjects which are scheduled via
130// AddNotify are deleted by the destructor of MReadTree
131//
132void MReadTree::SetOwner(Bool_t flag)
133{
134 flag ? fNotify->SetBit(kIsOwner) : fNotify->ResetBit(kIsOwner);
135}
136
137// --------------------------------------------------------------------------
138//
139// This function is called each time MReadTree changes the file to read
140// from. It calls all TObject::Notify() functions which are scheduled
141// via AddNotify.
142//
143Bool_t MReadTree::Notify()
144{
145 fNotify->ForEach(TObject, Notify)();
146 return kTRUE;
147}
148
149// --------------------------------------------------------------------------
150//
151// If you want to read the given tree over several files you must add
152// the files here before PreProcess is called. Be careful: If the tree
153// doesn't have the same contents (branches) it may confuse your
154// program (trees which are are not existing in later files are not read
155// anymore, tree wich are not existing in the first file are never read)
156//
157// Name may use the wildcarding notation, eg "xxx*.root" means all files
158// starting with xxx in the current file system directory.
159//
160// AddFile returns the number of files added to the chain.
161//
162Int_t MReadTree::AddFile(const char *fname)
163{
164 //
165 // FIXME! A check is missing whether the file already exists or not.
166 //
167 //
168 // returns the number of file which were added
169 //
170 return fChain->Add(fname);
171}
172
173// --------------------------------------------------------------------------
174//
175// This function is called if Branch choosing method should get enabled.
176// Branch choosing means, that only the enabled branches are read into
177// memory. To use an enableing scheme we have to disable all branches first.
178// This is done, if this function is called the first time.
179//
180void MReadTree::EnableBranchChoosing()
181{
182 if (fBranchChoosing)
183 return;
184
185 *fLog << "Branch choosing method enabled (only enabled branches are read)." << endl;
186 fChain->SetBranchStatus("*", kFALSE);
187 fBranchChoosing = kTRUE;
188}
189
190// --------------------------------------------------------------------------
191//
192// The first time this function is called all branches are disabled.
193// The given branch is enabled. By enabling only the branches you
194// are processing you can speed up your calculation many times (up to
195// a factor of 10 or 20)
196//
197void MReadTree::EnableBranch(const char *name)
198{
199 EnableBranchChoosing();
200 fChain->SetBranchStatus(name, kTRUE);
201}
202
203// --------------------------------------------------------------------------
204//
205// Checks whether a branch with the given name exists in the chain
206// and sets the branch status of this branch corresponding to status.
207//
208void MReadTree::SetBranchStatus(TObject *branch, Bool_t status)
209{
210 //
211 // Get branch name
212 //
213 const char *name = branch->GetName();
214
215 //
216 // Check whether this branch really exists
217 //
218 if (!fChain->GetBranch(name))
219 return;
220
221 //
222 // Set the branch status
223 //
224 fChain->SetBranchStatus(name, status);
225 *fLog << (status ? "Enabled" : "Disabled");
226 *fLog << " subbranch '" << name << "'." << endl;
227}
228
229// --------------------------------------------------------------------------
230//
231// Set the status of all branches in the list to status.
232//
233void MReadTree::SetBranchStatus(const TOrdCollection *list, Bool_t status)
234{
235 //
236 // Loop over all subbranches in this master branch
237 //
238 TIter Next(list);
239
240 TObject *obj;
241 while ((obj=Next()))
242 SetBranchStatus(obj, status);
243}
244
245// --------------------------------------------------------------------------
246//
247// This is the implementation of the Auto Enabling Scheme.
248// For more information see MTask::AddBranchToList.
249// This function loops over all tasks in the tasklist and enables
250// all branches which are requested by the tasks.
251//
252// To enable 'unknown' branches which are not in the Branchlist of
253// the tasks you can call EnableBranch
254//
255void MReadTree::EnableBranches(MParList *plist)
256{
257 //
258 // check whether branch choosing must be switched on
259 //
260 EnableBranchChoosing();
261
262 //
263 // request the tasklist from the parameter list.
264 // FIXME: Tasklist can have a different name
265 //
266 const MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
267 if (!tlist)
268 {
269 *fLog << "Cannot use auto enabeling scheme for branches. 'MTaskList' not found." << endl;
270 return;
271 }
272
273 //
274 // Loop over all tasks in the task list.
275 //
276 MTask *task;
277 TIter NextTask(tlist->GetList());
278 while ((task=(MTask*)NextTask()))
279 SetBranchStatus(task->GetListOfBranches(), kTRUE);
280}
281
282// --------------------------------------------------------------------------
283//
284// The disables all subbranches of the given master branch.
285//
286void MReadTree::DisableSubBranches(TBranch *branch)
287{
288 //
289 // This is not necessary, it would work without. But the output
290 // may confuse the user...
291 //
292 if (fAutoEnable || fBranchChoosing)
293 return;
294
295 SetBranchStatus(branch->GetListOfBranches(), kFALSE);
296}
297
298// --------------------------------------------------------------------------
299//
300// The PreProcess loops (till now) over the branches in the given tree.
301// It checks if the corresponding containers (containers with the same
302// name than the branch name) are existing in the Parameter Container List.
303// If not, a container of objec type 'branch-name' is created (everything
304// after the last semicolon in the branch name is stripped). Only
305// branches which don't have a veto (see VetoBranch) are enabled If the
306// object isn't found in the root dictionary (a list of classes known by the
307// root environment) the branch is skipped and an error message is printed
308// out.
309//
310Bool_t MReadTree::PreProcess(MParList *pList)
311{
312 //
313 // get number of events in this tree
314 //
315 fNumEntries = (UInt_t)fChain->GetEntries();
316
317 if (!fNumEntries)
318 {
319 *fLog << dbginf << "No entries found in file(s)." << endl;
320 return kFALSE;
321 }
322
323 //
324 // output logging information
325 //
326 *fLog << fNumEntries << " entries found in file(s)." << endl;
327
328 //
329 // Get all branches of this tree and
330 // create the Iterator to loop over all branches
331 //
332 TIter Next(fChain->GetListOfBranches());
333 TBranch *branch=NULL;
334
335 Int_t num=0;
336 //
337 // loop over all tasks for processing
338 //
339 while ( (branch=(TBranch*)Next()) )
340 {
341 //
342 // Get Name of Branch and Object
343 //
344 const char *bname = branch->GetName();
345
346 TString oname(bname);
347
348 if (oname.EndsWith("."))
349 oname.Remove(oname.Length()-1);
350
351 //
352 // Check if enabeling the branch is allowed
353 //
354 if (fVetoList->FindObject(oname))
355 {
356 *fLog << "Master branch " << bname << " has veto... skipped." << endl;
357 DisableSubBranches(branch);
358 continue;
359 }
360
361 //
362 // Create a pointer to the pointer to the object in which the
363 // branch data is stored. The pointers are stored in the TChain
364 // object and we get the pointers from there to delete it.
365 //
366 MParContainer **pcont = new MParContainer*;
367
368 //
369 // check if object is existing in the list
370 //
371 *pcont=pList->FindCreateObj(oname);
372
373 if (!*pcont)
374 {
375 //
376 // if class is not existing in the (root) environment
377 // we cannot proceed reading this branch
378 //
379 *fLog << dbginf << "Warning: Class '" << oname << "' not existing in dictionary. Branch skipped." << endl;
380 DisableSubBranches(branch);
381 continue;
382 }
383
384 //
385 // here pcont is a pointer the to container in which the data from
386 // the actual branch should be stored - enable branch.
387 //
388 fChain->SetBranchAddress(bname, pcont);
389 *fLog << "Master branch address " << bname << " setup for reading." << endl;
390
391 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
392 branch->SetAutoDelete();
393
394 num++;
395 }
396
397 *fLog << "MReadTree setup " << num << " master branches addresses." << endl;
398
399 //
400 // If auto enabling scheme isn't disabled, do auto enabling
401 //
402 if (fAutoEnable)
403 EnableBranches(pList);
404
405 //
406 // If a progress bar is given set its range.
407 //
408 if (fProgress)
409 fProgress->SetRange(0, fNumEntries);
410
411 return kTRUE;
412}
413
414// --------------------------------------------------------------------------
415//
416// The Process-function reads one event from the tree (this contains all
417// enabled branches) and increases the position in the file by one event.
418// (Remark: The position can also be set by some member functions
419// If the end of the file is reached the Eventloop is stopped.
420//
421Bool_t MReadTree::Process()
422{
423 return fChain->GetEntry(fNumEntry++) != 0;
424}
425
426// --------------------------------------------------------------------------
427//
428// Get the Event with the current EventNumber fNumEntry
429//
430Bool_t MReadTree::GetEvent()
431{
432 return fChain->GetEntry(fNumEntry) != 0;
433}
434
435// --------------------------------------------------------------------------
436//
437// Decrease the number of the event which is read by Process() next
438// by one or more
439//
440Bool_t MReadTree::DecEventNum(UInt_t dec)
441{
442 if (fNumEntry-dec >= fNumEntries)
443 {
444 *fLog << "MReadTree::DecEventNum: WARNING - Event " << fNumEntry << "-";
445 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range." << endl;
446 return kFALSE;
447 }
448
449 fNumEntry -= dec;
450 return kTRUE;
451}
452
453// --------------------------------------------------------------------------
454//
455// Increase the number of the event which is read by Process() next
456// by one or more
457//
458Bool_t MReadTree::IncEventNum(UInt_t inc)
459{
460 if (fNumEntry+inc >= fNumEntries)
461 {
462 *fLog << "MReadTree::IncEventNum: WARNING - Event " << fNumEntry << "+";
463 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range." << endl;
464 return kFALSE;
465 }
466
467 fNumEntry += inc;
468 return kTRUE;
469}
470
471// --------------------------------------------------------------------------
472//
473// This function makes Process() read event number nr next
474//
475// Remark: You can use this function after instatiating you MReadTree-object
476// to set the event number from which you want to start reading.
477//
478Bool_t MReadTree::SetEventNum(UInt_t nr)
479{
480 if (nr >= fNumEntries)
481 {
482 *fLog << "MReadTree::SetEventNum: WARNING - " << nr << " out of Range." << endl;
483 return kFALSE;
484 }
485
486 fNumEntry = nr;
487 return kTRUE;
488}
489
490// --------------------------------------------------------------------------
491//
492// For the branch with the given name:
493// 1) no object is automatically created
494// 2) the branch address for this branch is not set
495// (because we lack the object, see 1)
496// 3) The whole branch (exactly: all its subbranches) are disabled
497// this means are not read in memory by TTree:GetEntry
498//
499void MReadTree::VetoBranch(const char *name)
500{
501 TNamed *branch = new TNamed(name, "");
502 fVetoList->Add(branch);
503}
504
505// --------------------------------------------------------------------------
506//
507// Return the name of the file we are actually reading from.
508//
509const char *MReadTree::GetFileName() const
510{
511 return fChain->GetFile()->GetName();
512}
513
514// --------------------------------------------------------------------------
515//
516// This schedules a TObject which Notify(9 function is called in case
517// of MReadTree (TChain) switches from one file in the chain to another
518// one.
519//
520void MReadTree::AddNotify(TObject *obj)
521{
522 fNotify->Add(obj);
523}
Note: See TracBrowser for help on using the repository browser.