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

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