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

Last change on this file since 1177 was 1159, checked in by blanch, 23 years ago
The dependence on the directory names has been removed from the include files.
File size: 22.1 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
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 fChain->SetBranchStatus(name, kTRUE);
219}
220
221// --------------------------------------------------------------------------
222//
223// Set branch status of branch name
224//
225void MReadTree::SetBranchStatus(const char *name, Bool_t status)
226{
227 fChain->SetBranchStatus(name, status);
228
229 *fLog << inf << (status ? "Enabled" : "Disabled");
230 *fLog << " subbranch '" << name << "'." << endl;
231}
232
233// --------------------------------------------------------------------------
234//
235// Checks whether a branch with the given name exists in the chain
236// and sets the branch status of this branch corresponding to status.
237//
238void MReadTree::SetBranchStatus(TObject *branch, Bool_t status)
239{
240 //
241 // Get branch name
242 //
243 const char *name = branch->GetName();
244
245 //
246 // Check whether this branch really exists
247 //
248 if (fChain->GetBranch(name))
249 SetBranchStatus(name, status);
250
251 //
252 // Remove trailing '.' if one and try to enable the subbranch without
253 // the master barnch name. This is to be compatible with older mars
254 // and camera files.
255 //
256 const char *dot = strrchr(name, '.');
257 if (!dot)
258 return;
259
260 if (fChain->GetBranch(dot+1))
261 SetBranchStatus(dot+1, status);
262}
263
264// --------------------------------------------------------------------------
265//
266// Set the status of all branches in the list to status.
267//
268void MReadTree::SetBranchStatus(const TList *list, Bool_t status)
269{
270 //
271 // Loop over all subbranches in this master branch
272 //
273 TIter Next(list);
274
275 TObject *obj;
276 while ((obj=Next()))
277 SetBranchStatus(obj, status);
278}
279
280// --------------------------------------------------------------------------
281//
282// This is the implementation of the Auto Enabling Scheme.
283// For more information see MTask::AddBranchToList.
284// This function loops over all tasks and its filters in the tasklist
285// and enables all branches which are requested by the tasks and its
286// filters.
287//
288// To enable 'unknown' branches which are not in the branchlist of
289// the tasks you can call EnableBranch
290//
291void MReadTree::EnableBranches(MParList *plist)
292{
293 //
294 // check whether branch choosing must be switched on
295 //
296 EnableBranchChoosing();
297
298 //
299 // request the tasklist from the parameter list.
300 // FIXME: Tasklist can have a different name
301 //
302 const MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
303 if (!tlist)
304 {
305 *fLog << warn << "Cannot use auto enabeling scheme for branches. 'MTaskList' not found." << endl;
306 return;
307 }
308
309 //
310 // This loop is not necessary. We could do it like in the commented
311 // loop below. But this loop makes sure, that we don't try to enable
312 // one branch several times. This would not harm, but we would get
313 // an output for each attempt. To have several outputs for one subbranch
314 // may confuse the user, this we don't want.
315 // This loop creates a new list of subbranches and for each branch
316 // which is added we check before whether it already exists or not.
317 //
318 TList list;
319
320 MTask *task;
321 TIter NextTask(tlist->GetList());
322 while ((task=(MTask*)NextTask()))
323 {
324 TObject *obj;
325
326 TIter NextTBranch(task->GetListOfBranches());
327 while ((obj=NextTBranch()))
328 if (!list.FindObject(obj->GetName()))
329 list.Add(obj);
330
331 const MFilter *filter = task->GetFilter();
332
333 if (!filter)
334 continue;
335
336 TIter NextFBranch(filter->GetListOfBranches());
337 while ((obj=NextFBranch()))
338 if (!list.FindObject(obj->GetName()))
339 list.Add(obj);
340 }
341
342 SetBranchStatus(&list, kTRUE);
343/*
344 //
345 // Loop over all tasks iand its filters n the task list.
346 //
347 MTask *task;
348 TIter NextTask(tlist->GetList());
349 while ((task=(MTask*)NextTask()))
350 {
351 SetBranchStatus(task->GetListOfBranches(), kTRUE);
352
353 const MFilter *filter = task->GetFilter();
354 if (!filter)
355 continue;
356
357 SetBranchStatus(filter->GetListOfBranches(), kTRUE);
358
359 }
360*/
361}
362
363// --------------------------------------------------------------------------
364//
365// The disables all subbranches of the given master branch.
366//
367void MReadTree::DisableSubBranches(TBranch *branch)
368{
369 //
370 // This is not necessary, it would work without. But the output
371 // may confuse the user...
372 //
373 if (fAutoEnable || fBranchChoosing)
374 return;
375
376 SetBranchStatus(branch->GetListOfBranches(), kFALSE);
377}
378
379// --------------------------------------------------------------------------
380//
381// The PreProcess loops (till now) over the branches in the given tree.
382// It checks if the corresponding containers (containers with the same
383// name than the branch name) are existing in the Parameter Container List.
384// If not, a container of objec type 'branch-name' is created (everything
385// after the last semicolon in the branch name is stripped). Only
386// branches which don't have a veto (see VetoBranch) are enabled If the
387// object isn't found in the root dictionary (a list of classes known by the
388// root environment) the branch is skipped and an error message is printed
389// out.
390//
391Bool_t MReadTree::PreProcess(MParList *pList)
392{
393 //
394 // Make sure, that all the following calls doesn't result in
395 // Notifications. This may be dangerous, because the notified
396 // tasks are not preprocessed.
397 //
398 fChain->SetNotify(NULL);
399
400 //
401 // get number of events in this tree
402 //
403 fNumEntries = (UInt_t)fChain->GetEntries();
404
405 if (!fNumEntries)
406 {
407 *fLog << warn << dbginf << "No entries found in file(s)." << endl;
408 return kFALSE;
409 }
410
411 //
412 // output logging information
413 //
414 *fLog << inf << fNumEntries << " entries found in file(s)." << endl;
415
416 //
417 // Get all branches of this tree and
418 // create the Iterator to loop over all branches
419 //
420 TIter Next(fChain->GetListOfBranches());
421 TBranch *branch=NULL;
422
423 Int_t num=0;
424 //
425 // loop over all tasks for processing
426 //
427 while ( (branch=(TBranch*)Next()) )
428 {
429 //
430 // Get Name of Branch and Object
431 //
432 const char *bname = branch->GetName();
433
434 TString oname(bname);
435 if (oname.EndsWith("."))
436 oname.Remove(oname.Length()-1);
437
438 //
439 // Check if enabeling the branch is allowed
440 //
441 if (fVetoList->FindObject(oname))
442 {
443 *fLog << inf << "Master branch " << bname << " has veto... skipped." << endl;
444 DisableSubBranches(branch);
445 continue;
446 }
447
448 //
449 // Create a pointer to the pointer to the object in which the
450 // branch data is stored. The pointers are stored in the TChain
451 // object and we get the pointers from there to delete it.
452 //
453 MParContainer **pcont= new MParContainer*;
454
455 //
456 // check if object is existing in the list
457 //
458 *pcont=pList->FindCreateObj(oname);
459
460 if (!*pcont)
461 {
462 //
463 // if class is not existing in the (root) environment
464 // we cannot proceed reading this branch
465 //
466 *fLog << warn << dbginf << "Warning: Class '" << oname << "' not existing in dictionary. Branch skipped." << endl;
467 DisableSubBranches(branch);
468 continue;
469 }
470
471 //
472 // Check whether a Pointer to a pointer already exists, if
473 // we created one already delete it.
474 //
475 TChainElement *element = (TChainElement*)fChain->GetStatus()->FindObject(bname);
476 if (element)
477 delete (MParContainer**)element->GetBaddress();
478
479 //
480 // here pcont is a pointer the to container in which the data from
481 // the actual branch should be stored - enable branch.
482 //
483 fChain->SetBranchAddress(bname, pcont);
484 *fLog << inf << "Master branch address " << bname << " setup for reading." << endl;
485
486 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
487 //branch->SetAutoDelete();
488
489 num++;
490 }
491
492 *fLog << inf << "MReadTree setup " << num << " master branches addresses." << endl;
493
494 //
495 // If auto enabling scheme isn't disabled, do auto enabling
496 //
497 if (fAutoEnable)
498 EnableBranches(pList);
499
500 //
501 // If a progress bar is given set its range.
502 //
503 if (fProgress)
504 fProgress->SetRange(0, fNumEntries);
505
506 //
507 // Now we can start notifying. Reset tree makes sure, that TChain thinks
508 // that the correct file is not yet initialized and reinitilizes it
509 // as soon as the first event is read. This is necessary to call
510 // the notifiers when the first event is read, but after the
511 // PreProcess-function.
512 //
513 fChain->ResetTree();
514 fChain->SetNotify(this);
515
516 return kTRUE;
517}
518
519// --------------------------------------------------------------------------
520//
521// Set the ready to save flag of all containers which branchaddresses are
522// set for. This is necessary to copy data.
523//
524void MReadTree::SetReadyToSave(Bool_t flag)
525{
526 TIter Next(fChain->GetStatus());
527
528 TChainElement *element = NULL;
529 while ((element=(TChainElement*)Next()))
530 {
531 //
532 // Check whether the branch is enabled
533 //
534 if (!element->GetStatus())
535 continue;
536
537 //
538 // Get the pointer to the pointer of the corresponding container
539 //
540 MParContainer **pcont = (MParContainer**)element->GetBaddress();
541
542 //
543 // Check whether the pointer is not NULL
544 //
545 if (!pcont || !*pcont)
546 continue;
547
548 //
549 // Set the ready to save status of the container.
550 //
551 (*pcont)->SetReadyToSave(flag);
552 }
553
554 //
555 // Set the ready to save status of this task (used?), too
556 //
557 MTask::SetReadyToSave(flag);
558}
559
560// --------------------------------------------------------------------------
561//
562// The Process-function reads one event from the tree (this contains all
563// enabled branches) and increases the position in the file by one event.
564// (Remark: The position can also be set by some member functions
565// If the end of the file is reached the Eventloop is stopped.
566//
567#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
568//#include "../mraw/MRawEvtData.h"
569#include "MRawEvtData.h"
570#endif
571Bool_t MReadTree::Process()
572{
573 //
574 // This is necessary due to a bug in TChain::LoadTree in root.
575 // will be fixed in 3.03
576 //
577 if (fNumEntry >= fNumEntries)
578 return kFALSE;
579
580#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
581 //
582 // This fixes 99.9% of a memory leak using a root version prior
583 // to 3.02/??
584 //
585 TChainElement *element=NULL;
586 TIter Next(fChain->GetStatus());
587 while ((element=(TChainElement*)Next()))
588 {
589 MParContainer **c = (MParContainer**)element->GetBaddress();
590 if (!c) continue;
591 if ((*c)->InheritsFrom(MRawEvtData::Class()))
592 ((MRawEvtData*)(*c))->DeletePixels(kFALSE);
593
594 }
595#endif
596
597 Bool_t rc = fChain->GetEntry(fNumEntry++) != 0;
598
599 if (rc)
600 SetReadyToSave();
601
602 return rc;
603}
604
605// --------------------------------------------------------------------------
606//
607// Get the Event with the current EventNumber fNumEntry
608//
609Bool_t MReadTree::GetEvent()
610{
611 Bool_t rc = fChain->GetEntry(fNumEntry) != 0;
612
613 if (rc)
614 SetReadyToSave();
615
616 return rc;
617}
618
619// --------------------------------------------------------------------------
620//
621// Decrease the number of the event which is read by Process() next
622// by one or more
623//
624Bool_t MReadTree::DecEventNum(UInt_t dec)
625{
626 if (fNumEntry-dec >= fNumEntries)
627 {
628 *fLog << warn << "MReadTree::DecEventNum: WARNING - Event " << fNumEntry << "-";
629 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range." << endl;
630 return kFALSE;
631 }
632
633 fNumEntry -= dec;
634 return kTRUE;
635}
636
637// --------------------------------------------------------------------------
638//
639// Increase the number of the event which is read by Process() next
640// by one or more
641//
642Bool_t MReadTree::IncEventNum(UInt_t inc)
643{
644 if (fNumEntry+inc >= fNumEntries)
645 {
646 *fLog << warn << "MReadTree::IncEventNum: WARNING - Event " << fNumEntry << "+";
647 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range." << endl;
648 return kFALSE;
649 }
650
651 fNumEntry += inc;
652 return kTRUE;
653}
654
655// --------------------------------------------------------------------------
656//
657// This function makes Process() read event number nr next
658//
659// Remark: You can use this function after instatiating you MReadTree-object
660// to set the event number from which you want to start reading.
661//
662Bool_t MReadTree::SetEventNum(UInt_t nr)
663{
664 if (nr >= fNumEntries)
665 {
666 *fLog << warn << "MReadTree::SetEventNum: WARNING - " << nr << " out of Range." << endl;
667 return kFALSE;
668 }
669
670 fNumEntry = nr;
671 return kTRUE;
672}
673
674// --------------------------------------------------------------------------
675//
676// For the branch with the given name:
677// 1) no object is automatically created
678// 2) the branch address for this branch is not set
679// (because we lack the object, see 1)
680// 3) The whole branch (exactly: all its subbranches) are disabled
681// this means are not read in memory by TTree:GetEntry
682//
683void MReadTree::VetoBranch(const char *name)
684{
685 fVetoList->Add(new TNamed(name, ""));
686}
687
688// --------------------------------------------------------------------------
689//
690// Return the name of the file we are actually reading from.
691//
692const char *MReadTree::GetFileName() const
693{
694 return fChain->GetFile()->GetName();
695}
696
697// --------------------------------------------------------------------------
698//
699// This schedules a TObject which Notify(9 function is called in case
700// of MReadTree (TChain) switches from one file in the chain to another
701// one.
702//
703void MReadTree::AddNotify(TObject *obj)
704{
705 fNotify->Add(obj);
706}
707
708void MReadTree::Print(Option_t *o) const
709{
710 *fLog << all << GetDescriptor() << dec << endl;
711 *fLog << setfill('-') << setw(strlen(GetDescriptor())) << "" << endl;
712 *fLog << " Files:" << endl;
713
714 int i = 0;
715 TIter Next(fChain->GetListOfFiles());
716 TObject *obj = NULL;
717 while ((obj=Next()))
718 *fLog << " " << i++ << ") " << obj->GetName() << endl;
719
720 *fLog << " Entries: " << fNumEntries << endl;
721 *fLog << " Next Entry: " << fNumEntry << endl;
722}
Note: See TracBrowser for help on using the repository browser.