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

Last change on this file since 1085 was 1085, checked in by tbretz, 23 years ago
:q
File size: 18.7 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 <mailto: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 "MFilter.h"
66#include "MParList.h"
67#include "MTaskList.h"
68
69ClassImp(MReadTree);
70
71// --------------------------------------------------------------------------
72//
73// Default constructor. It creates an TChain instance which represents the
74// the Tree you want to read and adds the given file (if you gave one).
75// More files can be added using MReadTree::AddFile.
76// Also an empty veto list is created. This list is used if you want to
77// veto (disable or "don't enable") a branch in the tree, it vetos also
78// the creation of the corresponding object.
79// An empty list of TObjects are also created. This objects are called
80// at any time the TChain starts to read from another file.
81//
82MReadTree::MReadTree(const char *tname, const char *fname,
83 const char *name, const char *title)
84 : fNumEntry(0), fBranchChoosing(kFALSE), fAutoEnable(kTRUE), fProgress(NULL)
85{
86 fName = name ? name : "MReadTree";
87 fTitle = title ? title : "Task to loop over all events in one single tree";
88
89 fVetoList = new TList;
90 fVetoList->SetOwner();
91
92 fNotify = new TList;
93
94 //
95 // open the input stream
96 //
97 fChain = new TChain(tname);
98 fChain->SetNotify(this);
99
100 // root 3.02:
101 // In TChain::Addfile remove the limitation that the file name must contain
102 // the string ".root". ".root" is necessary only in case one wants to specify
103 // a Tree in a subdirectory of a Root file with eg, the format:
104
105 if (fname)
106 fChain->Add(fname);
107}
108
109// --------------------------------------------------------------------------
110//
111// Destructor. It deletes the TChain and veto list object
112//
113MReadTree::~MReadTree()
114{
115 //
116 // Delete all the pointers to pointers to the objects where the
117 // branche data gets stored.
118 //
119 TIter Next(fChain->GetStatus());
120
121 TChainElement *element = NULL;
122 while ((element=(TChainElement*)Next()))
123 delete (MParContainer**)element->GetBaddress();
124
125 //
126 // Delete the chain and the veto list
127 //
128 delete fChain;
129 delete fNotify;
130 delete fVetoList;
131}
132
133// --------------------------------------------------------------------------
134//
135// If the owner flag is set all TObjects which are scheduled via
136// AddNotify are deleted by the destructor of MReadTree
137//
138void MReadTree::SetOwner(Bool_t flag)
139{
140 flag ? fNotify->SetBit(kIsOwner) : fNotify->ResetBit(kIsOwner);
141}
142
143// --------------------------------------------------------------------------
144//
145// This function is called each time MReadTree changes the file to read
146// from. It calls all TObject::Notify() functions which are scheduled
147// via AddNotify.
148//
149Bool_t MReadTree::Notify()
150{
151 fNotify->ForEach(TObject, Notify)();
152 return kTRUE;
153}
154
155// --------------------------------------------------------------------------
156//
157// If you want to read the given tree over several files you must add
158// the files here before PreProcess is called. Be careful: If the tree
159// doesn't have the same contents (branches) it may confuse your
160// program (trees which are are not existing in later files are not read
161// anymore, tree wich are not existing in the first file are never read)
162//
163// Name may use the wildcarding notation, eg "xxx*.root" means all files
164// starting with xxx in the current file system directory.
165//
166// AddFile returns the number of files added to the chain.
167//
168Int_t MReadTree::AddFile(const char *fname)
169{
170 //
171 // FIXME! A check is missing whether the file already exists or not.
172 //
173 //
174 // returns the number of file which were added
175 //
176 return fChain->Add(fname);
177}
178
179// --------------------------------------------------------------------------
180//
181// This function is called if Branch choosing method should get enabled.
182// Branch choosing means, that only the enabled branches are read into
183// memory. To use an enableing scheme we have to disable all branches first.
184// This is done, if this function is called the first time.
185//
186void MReadTree::EnableBranchChoosing()
187{
188 if (fBranchChoosing)
189 return;
190
191 *fLog << inf << "Branch choosing method enabled (only enabled branches are read)." << endl;
192 fChain->SetBranchStatus("*", kFALSE);
193 fBranchChoosing = kTRUE;
194}
195
196// --------------------------------------------------------------------------
197//
198// The first time this function is called all branches are disabled.
199// The given branch is enabled. By enabling only the branches you
200// are processing you can speed up your calculation many times (up to
201// a factor of 10 or 20)
202//
203void MReadTree::EnableBranch(const char *name)
204{
205 EnableBranchChoosing();
206 fChain->SetBranchStatus(name, kTRUE);
207}
208
209// --------------------------------------------------------------------------
210//
211// Checks whether a branch with the given name exists in the chain
212// and sets the branch status of this branch corresponding to status.
213//
214void MReadTree::SetBranchStatus(TObject *branch, Bool_t status)
215{
216 //
217 // Get branch name
218 //
219 const char *name = branch->GetName();
220
221 //
222 // Check whether this branch really exists
223 //
224 if (!fChain->GetBranch(name))
225 return;
226
227 //
228 // Set the branch status
229 //
230 fChain->SetBranchStatus(name, status);
231 *fLog << inf << (status ? "Enabled" : "Disabled");
232 *fLog << " subbranch '" << name << "'." << endl;
233}
234
235// --------------------------------------------------------------------------
236//
237// Set the status of all branches in the list to status.
238//
239void MReadTree::SetBranchStatus(const TList *list, Bool_t status)
240{
241 //
242 // Loop over all subbranches in this master branch
243 //
244 TIter Next(list);
245
246 TObject *obj;
247 while ((obj=Next()))
248 SetBranchStatus(obj, status);
249}
250
251// --------------------------------------------------------------------------
252//
253// This is the implementation of the Auto Enabling Scheme.
254// For more information see MTask::AddBranchToList.
255// This function loops over all tasks and its filters in the tasklist
256// and enables all branches which are requested by the tasks and its
257// filters.
258//
259// To enable 'unknown' branches which are not in the branchlist of
260// the tasks you can call EnableBranch
261//
262void MReadTree::EnableBranches(MParList *plist)
263{
264 //
265 // check whether branch choosing must be switched on
266 //
267 EnableBranchChoosing();
268
269 //
270 // request the tasklist from the parameter list.
271 // FIXME: Tasklist can have a different name
272 //
273 const MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
274 if (!tlist)
275 {
276 *fLog << warn << "Cannot use auto enabeling scheme for branches. 'MTaskList' not found." << endl;
277 return;
278 }
279
280 //
281 // Loop over all tasks iand its filters n the task list.
282 //
283 MTask *task;
284 TIter NextTask(tlist->GetList());
285 while ((task=(MTask*)NextTask()))
286 {
287 SetBranchStatus(task->GetListOfBranches(), kTRUE);
288 const MFilter *filter = task->GetFilter();
289
290 if (filter)
291 SetBranchStatus(filter->GetListOfBranches(), kTRUE);
292
293 }
294}
295
296// --------------------------------------------------------------------------
297//
298// The disables all subbranches of the given master branch.
299//
300void MReadTree::DisableSubBranches(TBranch *branch)
301{
302 //
303 // This is not necessary, it would work without. But the output
304 // may confuse the user...
305 //
306 if (fAutoEnable || fBranchChoosing)
307 return;
308
309 SetBranchStatus(branch->GetListOfBranches(), kFALSE);
310}
311
312// --------------------------------------------------------------------------
313//
314// The PreProcess loops (till now) over the branches in the given tree.
315// It checks if the corresponding containers (containers with the same
316// name than the branch name) are existing in the Parameter Container List.
317// If not, a container of objec type 'branch-name' is created (everything
318// after the last semicolon in the branch name is stripped). Only
319// branches which don't have a veto (see VetoBranch) are enabled If the
320// object isn't found in the root dictionary (a list of classes known by the
321// root environment) the branch is skipped and an error message is printed
322// out.
323//
324Bool_t MReadTree::PreProcess(MParList *pList)
325{
326 //
327 // get number of events in this tree
328 //
329 fNumEntries = (UInt_t)fChain->GetEntries();
330
331 if (!fNumEntries)
332 {
333 *fLog << warn << dbginf << "No entries found in file(s)." << endl;
334 return kFALSE;
335 }
336
337 //
338 // output logging information
339 //
340 *fLog << inf << fNumEntries << " entries found in file(s)." << endl;
341
342 //
343 // Get all branches of this tree and
344 // create the Iterator to loop over all branches
345 //
346 TIter Next(fChain->GetListOfBranches());
347 TBranch *branch=NULL;
348
349 Int_t num=0;
350 //
351 // loop over all tasks for processing
352 //
353 while ( (branch=(TBranch*)Next()) )
354 {
355 //
356 // Get Name of Branch and Object
357 //
358 const char *bname = branch->GetName();
359
360 TString oname(bname);
361
362 if (oname.EndsWith("."))
363 oname.Remove(oname.Length()-1);
364
365 //
366 // Check if enabeling the branch is allowed
367 //
368 if (fVetoList->FindObject(oname))
369 {
370 *fLog << inf << "Master branch " << bname << " has veto... skipped." << endl;
371 DisableSubBranches(branch);
372 continue;
373 }
374
375 //
376 // Create a pointer to the pointer to the object in which the
377 // branch data is stored. The pointers are stored in the TChain
378 // object and we get the pointers from there to delete it.
379 //
380 MParContainer **pcont = new MParContainer*;
381
382 //
383 // check if object is existing in the list
384 //
385 *pcont=pList->FindCreateObj(oname);
386
387 if (!*pcont)
388 {
389 //
390 // if class is not existing in the (root) environment
391 // we cannot proceed reading this branch
392 //
393 *fLog << warn << dbginf << "Warning: Class '" << oname << "' not existing in dictionary. Branch skipped." << endl;
394 DisableSubBranches(branch);
395 continue;
396 }
397
398 //
399 // here pcont is a pointer the to container in which the data from
400 // the actual branch should be stored - enable branch.
401 //
402 fChain->SetBranchAddress(bname, pcont);
403 *fLog << inf << "Master branch address " << bname << " setup for reading." << endl;
404
405 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
406 //branch->SetAutoDelete();
407
408 num++;
409 }
410
411 *fLog << inf << "MReadTree setup " << num << " master branches addresses." << endl;
412
413 //
414 // If auto enabling scheme isn't disabled, do auto enabling
415 //
416 if (fAutoEnable)
417 EnableBranches(pList);
418
419 //
420 // If a progress bar is given set its range.
421 //
422 if (fProgress)
423 fProgress->SetRange(0, fNumEntries);
424
425 return kTRUE;
426}
427
428// --------------------------------------------------------------------------
429//
430// Set the ready to save flag of all containers which branchaddresses are
431// set for. This is necessary to copy data.
432//
433void MReadTree::SetReadyToSave(Bool_t flag)
434{
435 TIter Next(fChain->GetStatus());
436
437 TChainElement *element = NULL;
438 while ((element=(TChainElement*)Next()))
439 {
440 //
441 // Check whether the branch is enabled
442 //
443 if (!element->GetStatus())
444 continue;
445
446 //
447 // Get the pointer to the pointer of the corresponding container
448 //
449 MParContainer **pcont = (MParContainer**)element->GetBaddress();
450
451 //
452 // Check whether the pointer is not NULL
453 //
454 if (!pcont || !*pcont)
455 continue;
456
457 //
458 // Set the ready to save status of the container.
459 //
460 (*pcont)->SetReadyToSave(flag);
461 }
462
463 //
464 // Set the ready to save status of this task (used?), too
465 //
466 MTask::SetReadyToSave(flag);
467}
468
469// --------------------------------------------------------------------------
470//
471// The Process-function reads one event from the tree (this contains all
472// enabled branches) and increases the position in the file by one event.
473// (Remark: The position can also be set by some member functions
474// If the end of the file is reached the Eventloop is stopped.
475//
476Bool_t MReadTree::Process()
477{
478 Bool_t rc = fChain->GetEntry(fNumEntry++) != 0;
479
480 if (rc)
481 SetReadyToSave();
482
483 return rc;
484}
485
486// --------------------------------------------------------------------------
487//
488// Get the Event with the current EventNumber fNumEntry
489//
490Bool_t MReadTree::GetEvent()
491{
492 Bool_t rc = fChain->GetEntry(fNumEntry) != 0;
493
494 if (rc)
495 SetReadyToSave();
496
497 return rc;
498}
499
500// --------------------------------------------------------------------------
501//
502// Decrease the number of the event which is read by Process() next
503// by one or more
504//
505Bool_t MReadTree::DecEventNum(UInt_t dec)
506{
507 if (fNumEntry-dec >= fNumEntries)
508 {
509 *fLog << warn << "MReadTree::DecEventNum: WARNING - Event " << fNumEntry << "-";
510 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range." << endl;
511 return kFALSE;
512 }
513
514 fNumEntry -= dec;
515 return kTRUE;
516}
517
518// --------------------------------------------------------------------------
519//
520// Increase the number of the event which is read by Process() next
521// by one or more
522//
523Bool_t MReadTree::IncEventNum(UInt_t inc)
524{
525 if (fNumEntry+inc >= fNumEntries)
526 {
527 *fLog << warn << "MReadTree::IncEventNum: WARNING - Event " << fNumEntry << "+";
528 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range." << endl;
529 return kFALSE;
530 }
531
532 fNumEntry += inc;
533 return kTRUE;
534}
535
536// --------------------------------------------------------------------------
537//
538// This function makes Process() read event number nr next
539//
540// Remark: You can use this function after instatiating you MReadTree-object
541// to set the event number from which you want to start reading.
542//
543Bool_t MReadTree::SetEventNum(UInt_t nr)
544{
545 if (nr >= fNumEntries)
546 {
547 *fLog << warn << "MReadTree::SetEventNum: WARNING - " << nr << " out of Range." << endl;
548 return kFALSE;
549 }
550
551 fNumEntry = nr;
552 return kTRUE;
553}
554
555// --------------------------------------------------------------------------
556//
557// For the branch with the given name:
558// 1) no object is automatically created
559// 2) the branch address for this branch is not set
560// (because we lack the object, see 1)
561// 3) The whole branch (exactly: all its subbranches) are disabled
562// this means are not read in memory by TTree:GetEntry
563//
564void MReadTree::VetoBranch(const char *name)
565{
566 TNamed *branch = new TNamed(name, "");
567 fVetoList->Add(branch);
568}
569
570// --------------------------------------------------------------------------
571//
572// Return the name of the file we are actually reading from.
573//
574const char *MReadTree::GetFileName() const
575{
576 return fChain->GetFile()->GetName();
577}
578
579// --------------------------------------------------------------------------
580//
581// This schedules a TObject which Notify(9 function is called in case
582// of MReadTree (TChain) switches from one file in the chain to another
583// one.
584//
585void MReadTree::AddNotify(TObject *obj)
586{
587 fNotify->Add(obj);
588}
589
590void MReadTree::Print(Option_t *o) const
591{
592 *fLog << all << GetDescriptor() << dec << endl;
593 *fLog << setfill('-') << setw(strlen(GetDescriptor())) << "" << endl;
594 *fLog << " Files:" << endl;
595
596 int i = 0;
597 TIter Next(fChain->GetListOfFiles());
598 TObject *obj = NULL;
599 while ((obj=Next()))
600 *fLog << " " << i++ << ") " << obj->GetName() << endl;
601
602 *fLog << " Entries: " << fNumEntries << endl;
603 *fLog << " Next Entry: " << fNumEntry << endl;
604}
Note: See TracBrowser for help on using the repository browser.