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

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