source: trunk/MagicSoft/Mars/mfileio/MReadTree.cc@ 5710

Last change on this file since 5710 was 5692, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 35.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@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2005
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// ToDo:
52// -----
53// - Auto Scheme and Branch choosing doesn't work for memory trees
54//
55/////////////////////////////////////////////////////////////////////////////
56#include "MReadTree.h"
57
58#include <fstream>
59
60#include <TFile.h> // TFile::GetName
61#include <TSystem.h> // gSystem->ExpandPath
62#include <TChainElement.h>
63#include <TOrdCollection.h>
64
65#include "MChain.h"
66#include "MFilter.h"
67#include "MParList.h"
68#include "MTaskList.h"
69
70#include "MLog.h"
71#include "MLogManip.h"
72
73
74ClassImp(MReadTree);
75
76using namespace std;
77
78// --------------------------------------------------------------------------
79//
80// Default constructor. Use this constructor (ONLY) if you want to
81// access a memory tree (a TTree not stored in a file) created by
82// MWriteRootFile or manually.
83//
84MReadTree::MReadTree(TTree *tree)
85 : fNumEntry(0), fNumEntries(0), fBranchChoosing(kFALSE), fAutoEnable(kTRUE)
86{
87 fName = "MRead";
88 fTitle = "Task to loop over all events in one single tree";
89
90 fVetoList = new TList;
91 fVetoList->SetOwner();
92
93 fNotify = new TList;
94
95 fChain = NULL;
96
97 fTree = tree;
98 SetBit(kChainWasChanged);
99
100 if (fTree)
101 fAutoEnable = kFALSE;
102 /*
103 if (!fTree)
104 return;
105
106 TIter Next(fTree->GetListOfBranches());
107 TBranch *b=0;
108 while ((b=(TBranch*)Next()))
109 b->ResetAddress();
110 */
111}
112
113// --------------------------------------------------------------------------
114//
115// Constructor. It creates an TChain instance which represents the
116// the Tree you want to read and adds the given file (if you gave one).
117// More files can be added using MReadTree::AddFile.
118// Also an empty veto list is created. This list is used if you want to
119// veto (disable or "don't enable") a branch in the tree, it vetos also
120// the creation of the corresponding object.
121// An empty list of TObjects are also created. This objects are called
122// at any time the TChain starts to read from another file.
123//
124MReadTree::MReadTree(const char *tname, const char *fname,
125 const char *name, const char *title)
126 : fNumEntry(0), fNumEntries(0), fBranchChoosing(kFALSE), fAutoEnable(kTRUE)
127{
128 fName = name ? name : "MRead";
129 fTitle = title ? title : "Task to loop over all events in one single tree";
130
131 fVetoList = new TList;
132 fVetoList->SetOwner();
133
134 fNotify = new TList;
135
136 //
137 // open the input stream
138 //
139 fChain = new MChain(tname);
140 fTree = fChain;
141
142 // root 3.02:
143 // In TChain::Addfile remove the limitation that the file name must contain
144 // the string ".root". ".root" is necessary only in case one wants to specify
145 // a Tree in a subdirectory of a Root file with eg, the format:
146
147 if (fname)
148 AddFile(fname);
149}
150
151// --------------------------------------------------------------------------
152//
153// Destructor. It deletes the TChain and veto list object
154//
155MReadTree::~MReadTree()
156{
157 //
158 // Delete all the pointers to pointers to the objects where the
159 // branche data gets stored. FIXME: When PreProcessed twice this
160 // creates a memory leak!
161 //
162 if (fChain) // FIXME: MEMORY LEAK for fTree!=0
163 {
164 TIter Next(fChain->GetStatus());
165
166 TChainElement *element = NULL;
167 while ((element=(TChainElement*)Next()))
168 if (element->GetBaddress())
169 delete (MParContainer**)element->GetBaddress();
170
171 //
172 // Delete the chain and the veto list
173 //
174#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,00)
175 if (fChain->GetFile())
176 delete fChain->GetFile();
177#endif
178 delete fChain;
179 }
180
181 /* This is AND MUST be done in PostProcess. See there for more details
182 else
183 {
184 TIter Next(fTree->GetListOfBranches());
185
186 TBranch *element = NULL;
187 while ((element=(TBranch*)Next()))
188 if (element->GetAddress())
189 delete (MParContainer**)element->GetAddress();
190 }
191 */
192
193 delete fNotify;
194 delete fVetoList;
195}
196
197Byte_t MReadTree::IsFileValid(const char *name)
198{
199 ifstream fin(name);
200 if (!fin)
201 return 0;
202
203 Char_t c[4];
204 fin.read(c, 4);
205 if (!fin)
206 return 0;
207
208 return c[0]=='r'&& c[1]=='o' && c[2]=='o' && c[3]=='t' ? 1 : 0;
209}
210
211// --------------------------------------------------------------------------
212//
213// This check whether all branches in the tree have the same size. If
214// this is not the case the events in the different branches cannot
215// be ordered correctly.
216//
217Bool_t MReadTree::CheckBranchSize()
218{
219 //if (!fChain) // >FIXME: fTree!=0
220 // return kTRUE;
221
222 TArrayI entries(fChain ? fChain->GetStatus()->GetSize() : fTree->GetListOfBranches()->GetSize());
223 Int_t num=0;
224
225 // Loop over all branches which have a corresponding container
226 /*
227 if (fChain)
228 {
229 TIter Next(fChain->GetStatus());
230
231 TChainElement *element = NULL;
232 while ((element=(TChainElement*)Next()))
233 {
234 // Get branch name and find pointer to corresponding branch
235 const TString name = element->GetName();
236 const TBranch *b = fChain->FindBranch(name);
237
238 // Skip element without corresponding branches (like "*")
239 if (!b)
240 continue;
241
242 entries[num++] = (Int_t)b->GetEntries();
243 }
244 }
245 else */
246 {
247 TIter Next(fTree->GetListOfBranches());
248
249 TBranch *element = NULL;
250 while ((element=(TBranch*)Next()))
251 entries[num++] = (Int_t)element->GetEntries();
252 }
253
254 // Check the number of entries of the branches pair-wise
255 for (int i=0; i<num; i++)
256 for (int j=i; j<num; j++)
257 {
258 if (entries[i]==entries[j])
259 continue;
260
261 *fLog << err << "ERROR - File corruption detected:" << endl;
262 *fLog << " Due to several circumstances (such at a bug in MReadTree or wrong" << endl;
263 *fLog << " usage of the file UPDATE mode) you may have produced a file in which" << endl;
264 *fLog << " at least two branches in the same tree (" << fTree->GetName() << ") have different" << endl;
265 *fLog << " number of entries. Sorry, but this file (" << GetFileName() << ")" << endl;
266 *fLog << " is unusable." << endl;
267 return kFALSE;
268 }
269
270 return kTRUE;
271}
272
273// --------------------------------------------------------------------------
274//
275// If the owner flag is set all TObjects which are scheduled via
276// AddNotify are deleted by the destructor of MReadTree
277//
278void MReadTree::SetOwner(Bool_t flag)
279{
280 flag ? fNotify->SetBit(kIsOwner) : fNotify->ResetBit(kIsOwner);
281}
282
283// --------------------------------------------------------------------------
284//
285// This function is called each time MReadTree changes the file to read
286// from. It calls all TObject::Notify() functions which are scheduled
287// via AddNotify.
288//
289Bool_t MReadTree::Notify()
290{
291 //
292 // Do a consistency check for all branches
293 //
294 if (!CheckBranchSize())
295 return kFALSE;
296
297 *fLog << inf << GetDescriptor() << ": Switching to #" << GetFileIndex();
298 *fLog << " '" << GetFileName() << "' (before event #";
299 *fLog << GetNumEntry()-1 << ")" << endl;
300
301 if (!fNotify)
302 return kTRUE;
303
304 TIter Next(fNotify);
305 TObject *o=NULL;
306 while ((o=Next()))
307 if (!o->Notify())
308 {
309 *fLog << err << "Calling Notify() for object " << o->GetName() << " failed... abort." << endl;
310 return kFALSE;
311 }
312
313 return kTRUE;
314}
315
316// --------------------------------------------------------------------------
317//
318// If you want to read the given tree over several files you must add
319// the files here before PreProcess is called. Be careful: If the tree
320// doesn't have the same contents (branches) it may confuse your
321// program (trees which are are not existing in later files are not read
322// anymore, tree wich are not existing in the first file are never read)
323//
324// Name may use the wildcarding notation, eg "xxx*.root" means all files
325// starting with xxx in the current file system directory.
326//
327// AddFile returns the number of files added to the chain.
328//
329// For more information see TChain::Add
330//
331Int_t MReadTree::AddFile(const char *fname, Int_t entries)
332{
333 if (!fChain)
334 {
335 *fLog << err << "MReadTree::AddFile - ERROR: You cannot add a file, because MReadTree" << endl;
336 *fLog << " handles a memory based tree or its default" << endl;
337 *fLog << " constructor was called." << endl;
338 return 0;
339 }
340
341#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,01)
342 //
343 // This is a workaround to get rid of crashed if the file doesn't
344 // exist due to non initialized TFile::fProcessIDs
345 //
346 // (Code taken from TFile::TFile
347 //
348 TString newname; // char-array must overcome comming block
349
350 if (strrchr(fname, '?') || strrchr(fname, '*'))
351 {
352 *fLog << warn;
353 *fLog<< "WARNING: Using widcards with older root versions:" << endl;
354 *fLog << " You may encounter crashes closing the files..." << endl;
355 }
356 else
357 {
358 const char *name;
359
360 if ((name = gSystem->ExpandPathName(fname)))
361 {
362 newname = name;
363 delete [] name;
364 }
365
366 if (newname.IsNull())
367 {
368 *fLog << err << dbginf << "Error expanding path " << fname << "." << endl;
369 return 0;
370 }
371
372 if (gSystem->AccessPathName(newname, kFileExists))
373 {
374 *fLog << err << "ERROR - File '" << fname << "' does not exist." << endl;
375 return 0;
376 }
377
378 fname = newname.Data();
379 }
380#endif
381
382 //
383 // FIXME! A check is missing whether the file already exists or not.
384 //
385 const Int_t numfiles = fChain->Add(fname, entries<0?TChain::kBigNumber:entries);
386
387 if (numfiles>0)
388 {
389 SetBit(kChainWasChanged);
390 *fLog << inf << GetDescriptor() << " - AddFile: " << numfiles << " files added from " << fname << "." << endl;
391 }
392 else
393 *fLog << warn << "WARNING: '" << fname << "' not added to " << GetDescriptor() << endl;
394
395 return numfiles;
396}
397
398/*
399 // --------------------------------------------------------------------------
400 //
401 //
402 Int_t MReadTree::AddFile(const TChainElement &obj)
403 {
404 return AddFile(obj.GetTitle(), obj.GetEntries());
405 }
406*/
407
408// --------------------------------------------------------------------------
409//
410// Adds all files from another MReadTree to this instance
411//
412// Returns the number of file which were added
413//
414Int_t MReadTree::AddFiles(const MReadTree &read)
415{
416 if (!fChain)
417 {
418 *fLog << err << "MReadTree::AddFiles - ERROR: You cannot add a file, because MReadTree" << endl;
419 *fLog << " handles a memory based tree or its default" << endl;
420 *fLog << " constructor was called." << endl;
421 return 0;
422 }
423
424 const Int_t rc = fChain->Add(read.fChain);
425
426 if (rc>0)
427 SetBit(kChainWasChanged);
428
429 /*
430 Int_t rc = 0;
431
432 TIter Next(read.fChain->GetListOfFiles());
433 TObject *obj = NULL;
434 while ((obj=Next()))
435 rc += AddFile(*(TChainElement*)obj);
436 */
437
438 return rc;
439}
440
441// --------------------------------------------------------------------------
442//
443// Sort the files by their file-names
444//
445void MReadTree::SortFiles()
446{
447 if (fChain)
448 fChain->GetListOfFiles()->Sort();
449}
450
451// --------------------------------------------------------------------------
452//
453// This function is called if Branch choosing method should get enabled.
454// Branch choosing means, that only the enabled branches are read into
455// memory. To use an enableing scheme we have to disable all branches first.
456// This is done, if this function is called the first time.
457//
458void MReadTree::EnableBranchChoosing()
459{
460 if (fBranchChoosing)
461 return;
462
463 *fLog << inf << GetDescriptor() << ": Branch choosing enabled (only enabled branches are read)." << endl;
464 fTree->SetBranchStatus("*", kFALSE); // *CHANGED-fChain-to-fTree*
465 fBranchChoosing = kTRUE;
466}
467
468// --------------------------------------------------------------------------
469//
470// The first time this function is called all branches are disabled.
471// The given branch is enabled. By enabling only the branches you
472// are processing you can speed up your calculation many times (up to
473// a factor of 10 or 20)
474//
475void MReadTree::EnableBranch(const char *name)
476{
477 if (!fChain)
478 {
479 *fLog << warn << "MReadTree::EnableBranch - WARNING: EnableBranch doesn't work with memory based trees... ignored." << endl;
480 return;
481 }
482
483 if (fChain->GetListOfFiles()->GetEntries()==0)
484 {
485 *fLog << err << "Chain contains no file... Branch '";
486 *fLog << name << "' ignored." << endl;
487 return;
488 }
489
490 EnableBranchChoosing();
491
492 TNamed branch(name, "");
493 SetBranchStatus(&branch, kTRUE);
494}
495
496// --------------------------------------------------------------------------
497//
498// Set branch status of branch name
499//
500void MReadTree::SetBranchStatus(const char *name, Bool_t status)
501{
502 fTree->SetBranchStatus(name, status); // *CHANGED-fChain-to-fTree*
503
504 *fLog << inf << (status ? "Enabled" : "Disabled");
505 *fLog << " subbranch '" << name << "'." << endl;
506}
507
508// --------------------------------------------------------------------------
509//
510// Checks whether a branch with the given name exists in the chain
511// and sets the branch status of this branch corresponding to status.
512//
513void MReadTree::SetBranchStatus(TObject *branch, Bool_t status)
514{
515 //
516 // Get branch name
517 //
518 const char *name = branch->GetName();
519
520 //
521 // Check whether this branch really exists
522 //
523 TString bn(name);
524 if (bn.EndsWith("*"))
525 bn.Remove(bn.Length()-1);
526
527 if (fTree->GetBranch(bn)) // *CHANGED-fChain-to-fTree*
528 SetBranchStatus(name, status);
529
530 //
531 // Remove trailing '.' if one and try to enable the subbranch without
532 // the master branch name. This is to be compatible with older mars
533 // and camera files.
534 //
535 const char *dot = strrchr(name, '.');
536 if (!dot)
537 return;
538
539 if (fTree->GetBranch(dot+1)) // *CHANGED-fChain-to-fTree*
540 SetBranchStatus(dot+1, status);
541}
542
543// --------------------------------------------------------------------------
544//
545// Set the status of all branches in the list to status.
546//
547void MReadTree::SetBranchStatus(const TList *list, Bool_t status)
548{
549 //
550 // Loop over all subbranches in this master branch
551 //
552 TIter Next(list);
553
554 TObject *obj;
555 while ((obj=Next()))
556 SetBranchStatus(obj, status);
557}
558
559// --------------------------------------------------------------------------
560//
561// This is the implementation of the Auto Enabling Scheme.
562// For more information see MTask::AddBranchToList.
563// This function loops over all tasks and its filters in the tasklist
564// and enables all branches which are requested by the tasks and its
565// filters.
566//
567// To enable 'unknown' branches which are not in the branchlist of
568// the tasks you can call EnableBranch
569//
570void MReadTree::EnableBranches(MParList *plist)
571{
572 //
573 // check whether branch choosing must be switched on
574 //
575 EnableBranchChoosing();
576
577 //
578 // request the tasklist from the parameter list.
579 // FIXME: Tasklist can have a different name
580 //
581 const MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
582 if (!tlist)
583 {
584 *fLog << warn << GetDescriptor() << "Cannot use auto enabeling scheme for branches. 'MTaskList' not found." << endl;
585 return;
586 }
587
588 //
589 // This loop is not necessary. We could do it like in the commented
590 // loop below. But this loop makes sure, that we don't try to enable
591 // one branch several times. This would not harm, but we would get
592 // an output for each attempt. To have several outputs for one subbranch
593 // may confuse the user, this we don't want.
594 // This loop creates a new list of subbranches and for each branch
595 // which is added we check before whether it already exists or not.
596 //
597 TList list;
598
599 MTask *task;
600 TIter NextTask(tlist->GetList());
601 while ((task=(MTask*)NextTask()))
602 {
603 TObject *obj;
604
605 TIter NextTBranch(task->GetListOfBranches());
606 while ((obj=NextTBranch()))
607 if (!list.FindObject(obj->GetName()))
608 list.Add(obj);
609
610 const MFilter *filter = task->GetFilter();
611
612 if (!filter)
613 continue;
614
615 TIter NextFBranch(filter->GetListOfBranches());
616 while ((obj=NextFBranch()))
617 if (!list.FindObject(obj->GetName()))
618 list.Add(obj);
619 }
620
621 SetBranchStatus(&list, kTRUE);
622/*
623 //
624 // Loop over all tasks iand its filters n the task list.
625 //
626 MTask *task;
627 TIter NextTask(tlist->GetList());
628 while ((task=(MTask*)NextTask()))
629 {
630 SetBranchStatus(task->GetListOfBranches(), kTRUE);
631
632 const MFilter *filter = task->GetFilter();
633 if (!filter)
634 continue;
635
636 SetBranchStatus(filter->GetListOfBranches(), kTRUE);
637
638 }
639*/
640}
641
642// --------------------------------------------------------------------------
643//
644// If the chain has been changed (by calling AddFile or using a file
645// in the constructors argument) the number of entries is newly
646// calculated from the files in the chain - this may take a while.
647// The number of entries is returned.
648//
649UInt_t MReadTree::GetEntries()
650{
651 if (TestBit(kChainWasChanged))
652 {
653 // *CHANGED-fChain-to-fTree*
654 *fLog << inf << "Scanning chain " << fTree->GetName() << "... " << flush;
655 fNumEntries = (UInt_t)fTree->GetEntries();
656 *fLog << fNumEntries << " events found." << endl;
657 ResetBit(kChainWasChanged);
658 }
659 return fNumEntries==TChain::kBigNumber ? 0 : fNumEntries;
660}
661
662// --------------------------------------------------------------------------
663//
664// The disables all subbranches of the given master branch.
665//
666void MReadTree::DisableSubBranches(TBranch *branch)
667{
668 //
669 // This is not necessary, it would work without. But the output
670 // may confuse the user...
671 //
672 if (fAutoEnable || fBranchChoosing)
673 return;
674
675 SetBranchStatus(branch->GetListOfBranches(), kFALSE);
676}
677
678// --------------------------------------------------------------------------
679//
680// The PreProcess loops (till now) over the branches in the given tree.
681// It checks if the corresponding containers (containers with the same
682// name than the branch name) are existing in the Parameter Container List.
683// If not, a container of objec type 'branch-name' is created (everything
684// after the last semicolon in the branch name is stripped). Only
685// branches which don't have a veto (see VetoBranch) are enabled If the
686// object isn't found in the root dictionary (a list of classes known by the
687// root environment) the branch is skipped and an error message is printed
688// out.
689// If a selector is specified it is preprocessed after the
690// MReadTree::PreProcess
691//
692Int_t MReadTree::PreProcess(MParList *pList)
693{
694 fTaskList = (MTaskList*)pList->FindObject("MTaskList");
695 if (!fTaskList)
696 *fLog << warn << "WARNING - Standard tasklist MTaskList not found... ignoring Stream-ID." << endl;
697
698 //
699 // Make sure, that all the following calls doesn't result in
700 // Notifications. This may be dangerous, because the notified
701 // tasks are not preprocessed.
702 //
703 fTree->SetNotify(NULL); //*CHANGED-fChain-to-fTree*
704
705 //
706 // It seems, that TFile and TTree are not completely independant if
707 // many times the same file is openes (MReadReports) and some of
708 // the files in the chains don't have one tree. TChain::fTreeNumber
709 // is already set before LoadTree from GetFile is called and
710 // it crashes. ResetTree makes sure, that the tree number is -1
711 //
712 if (fChain) // *CHANGED-fChain-to-fTree*
713 fChain->ResetTree();
714 // Maybe this would be enough, but the above might be safer...
715 //if (fChain->GetTreeNumber()==0)
716 // fChain->ResetTree();
717
718 //
719 // check for files and for the tree!
720 //
721 if (fChain && !fChain->GetFile()) // *CHANGED-fChain-to-fTree*
722 {
723 *fLog << err << GetDescriptor() << ": No file or no tree with name " << fChain->GetName() << " in file." << endl;
724 return kFALSE;
725 }
726
727 //
728 // get number of events in this tree
729 //
730 if (!GetEntries())
731 {
732 *fLog << err << GetDescriptor() << ": No entries found in file(s)" << endl;
733 return kFALSE;
734 }
735
736 //
737 // output logging information
738 //
739 *fLog << inf << fNumEntries << " entries found in file(s)." << endl;
740
741 //
742 // Get all branches of this tree and
743 // create the Iterator to loop over all branches
744 //
745 TIter Next(fTree->GetListOfBranches()); // *CHANGED-fChain-to-fTree*
746 TBranch *branch=NULL;
747
748 Int_t num=0;
749
750 //
751 // loop over all tasks for processing
752 //
753 while ( (branch=(TBranch*)Next()) )
754 {
755 //
756 // Get Name of Branch and Object
757 //
758 const char *bname = branch->GetName();
759
760 TString oname(bname);
761 if (oname.EndsWith("."))
762 oname.Remove(oname.Length()-1);
763
764 //
765 // Check if enabeling the branch is allowed
766 //
767 if (fVetoList->FindObject(oname))
768 {
769 *fLog << inf << "Master branch " << bname << " has veto... skipped." << endl;
770 DisableSubBranches(branch);
771 continue;
772 }
773
774 //
775 // Create a pointer to the pointer to the object in which the
776 // branch data is stored. The pointers are stored in the TChain
777 // object and we get the pointers from there to delete it.
778 //
779 MParContainer **pcont= new MParContainer*;
780
781#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
782 const char *classname = oname;
783#else
784 const char *classname = branch->GetClassName();
785#endif
786
787 //
788 // check if object is existing in the list
789 //
790 *pcont=pList->FindCreateObj(classname, oname);
791
792 if (!*pcont)
793 {
794 //
795 // if class is not existing in the (root) environment
796 // we cannot proceed reading this branch
797 //
798 *fLog << warn << dbginf << "Warning: Class '" << classname;
799 *fLog << "' for " << oname << " not existing in dictionary. Branch skipped." << endl;
800 DisableSubBranches(branch);
801 continue;
802 }
803
804 //
805 // Check whether a Pointer to a pointer already exists.
806 // If we created one already, delete it.
807 //
808 // *CHANGED-fChain-to-fTree*
809 if (fChain)
810 {
811 TChainElement *element = (TChainElement*)fChain->GetStatus()->FindObject(bname);
812 if (element)
813 delete (MParContainer**)element->GetBaddress();
814 }
815 /* This can't be done here for memory trees - see
816 PostProcess for more details.
817 else
818 {
819 TBranch *branch = (TBranch*)fTree->GetBranch(bname);
820 if (branch)
821 {
822 *fLog << bname << " " << (void*)branch->GetAddress() << " " << pcont << endl;
823 delete (MParContainer**)branch->GetAddress();
824 }
825 }
826 */
827
828 //
829 // here pcont is a pointer the to container in which the data from
830 // the actual branch should be stored - enable branch.
831 //
832 fTree->SetBranchAddress(bname, pcont); // *CHANGED-fChain-to-fTree*
833
834 *fLog << inf << "Master branch address '" << bname << "' [";
835 *fLog << classname << "] setup for reading." << endl;
836
837 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
838 //branch->SetAutoDelete();
839
840 num++;
841 }
842
843 *fLog << inf << GetDescriptor() << " setup " << num << " master branches addresses." << endl;
844
845 //
846 // If auto enabling scheme isn't disabled, do auto enabling
847 //
848 if (fAutoEnable)
849 EnableBranches(pList);
850
851 //
852 // Now we can start notifying. Reset tree makes sure, that TChain thinks
853 // that the correct file is not yet initialized and reinitilizes it
854 // as soon as the first event is read. This is necessary to call
855 // the notifiers when the first event is read, but after the
856 // PreProcess-function.
857 //
858 if (fChain)
859 fChain->ResetTree(); // *CHANGED-fChain-to-fTree*
860
861 fTree->SetNotify(this); // *CHANGED-fChain-to-fTree*
862
863 const Int_t rc = GetSelector() ? GetSelector()->CallPreProcess(pList) : kTRUE;
864 if (rc!=kTRUE || fChain)
865 return rc;
866
867 return Notify();
868}
869
870// --------------------------------------------------------------------------
871//
872// Set the ready to save flag of all containers which branchaddresses are
873// set for. This is necessary to copy data.
874//
875void MReadTree::SetReadyToSave(Bool_t flag)
876{
877 if (!fChain)
878 return;
879
880 TIter Next(fChain->GetStatus());
881
882 TChainElement *element = NULL;
883 while ((element=(TChainElement*)Next()))
884 {
885 //
886 // Check whether the branch is enabled
887 //
888 if (!element->GetStatus())
889 continue;
890
891 //
892 // Get the pointer to the pointer of the corresponding container
893 //
894 MParContainer **pcont = (MParContainer**)element->GetBaddress();
895
896 //
897 // Check whether the pointer is not NULL
898 //
899 if (!pcont || !*pcont)
900 continue;
901
902 //
903 // Set the ready to save status of the container.
904 //
905 (*pcont)->SetReadyToSave(flag);
906 }
907
908 //
909 // Set the ready to save status of this task (used?), too
910 //
911 MTask::SetReadyToSave(flag);
912}
913
914// --------------------------------------------------------------------------
915//
916// The Process-function reads one event from the tree (this contains all
917// enabled branches) and increases the position in the file by one event.
918// (Remark: The position can also be set by some member functions
919// If the end of the file is reached the Eventloop is stopped.
920// In case an event selector is given its value is checked before
921// reading the event. If it returns kAFLSE the event is skipped.
922//
923#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
924#include "MRawEvtData.h"
925#endif
926Int_t MReadTree::Process()
927{
928 //
929 // This is necessary due to a bug in TChain::LoadTree in root.
930 // will be fixed in 3.03
931 //
932#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,01)
933 if (fNumEntry >= GetEntries())
934 return kFALSE;
935#endif
936
937#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
938 //
939 // This fixes 99.9% of a memory leak using a root version prior
940 // to 3.02/??
941 //
942 TChainElement *element=NULL;
943 TIter Next(fChain->GetStatus());
944 while ((element=(TChainElement*)Next()))
945 {
946 MParContainer **c = (MParContainer**)element->GetBaddress();
947 if (!c) continue;
948 if ((*c)->InheritsFrom(MRawEvtData::Class()))
949 static_cast<MRawEvtData*>(*c)->DeletePixels(kFALSE);
950
951 }
952#endif
953
954 if (GetSelector())
955 {
956 //
957 // Make sure selector is processed
958 //
959 if (!GetSelector()->CallProcess())
960 {
961 *fLog << err << dbginf << "Processing Selector failed." << endl;
962 return kFALSE;
963 }
964
965 //
966 // Skip Event
967 //
968 if (!GetSelector()->IsConditionTrue())
969 {
970 fNumEntry++;
971 return kCONTINUE;
972 }
973 }
974
975 const Bool_t rc = fTree->GetEntry(fNumEntry++) != 0; // *CHANGED-fChain-to-fTree*
976
977 if (fTaskList)
978 fTaskList->SetStreamId(fTree->GetName()); // *CHANGED-fChain-to-fTree*
979
980 if (rc)
981 SetReadyToSave();
982
983 return rc;
984}
985
986// --------------------------------------------------------------------------
987//
988// If a selector is given the selector is post processed
989//
990Int_t MReadTree::PostProcess()
991{
992 // In the case of a memory tree I don't know how we can
993 // make a decision in PreProcess between a self allocated
994 // memory address or a pending address set long before.
995 // So we delete the stuff in PostProcess and not the destructor
996 // (which might seg faullt if PreProcess has never been called)
997 if (!fChain)
998 {
999 TIter Next(fTree->GetListOfBranches());
1000 TBranch *b=0;
1001 while ((b=(TBranch*)Next()))
1002 {
1003 if (b->GetAddress())
1004 {
1005 delete b->GetAddress();
1006 b->ResetAddress();
1007 }
1008 }
1009 }
1010
1011 return GetSelector() ? GetSelector()->CallPostProcess() : kTRUE;
1012}
1013
1014// --------------------------------------------------------------------------
1015//
1016// Get the Event with the current EventNumber fNumEntry
1017//
1018Bool_t MReadTree::GetEvent()
1019{
1020 Bool_t rc = fTree->GetEntry(fNumEntry) != 0; // *CHANGED-fChain-to-fTree*
1021
1022 if (rc)
1023 SetReadyToSave();
1024
1025 return rc;
1026}
1027
1028// --------------------------------------------------------------------------
1029//
1030// Decrease the number of the event which is read by Process() next
1031// by one or more
1032//
1033Bool_t MReadTree::DecEventNum(UInt_t dec)
1034{
1035 if (fNumEntry-dec >= GetEntries())
1036 {
1037 *fLog << warn << GetDescriptor() << ": DecEventNum, WARNING - Event " << fNumEntry << "-";
1038 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range (>=";
1039 *fLog << GetEntries() << ")." << endl;
1040 return kFALSE;
1041 }
1042
1043 fNumEntry -= dec;
1044 return kTRUE;
1045}
1046
1047// --------------------------------------------------------------------------
1048//
1049// Increase the number of the event which is read by Process() next
1050// by one or more
1051//
1052Bool_t MReadTree::IncEventNum(UInt_t inc)
1053{
1054 if (fNumEntry+inc >= GetEntries())
1055 {
1056 *fLog << warn << GetDescriptor() << ": IncEventNum, WARNING - Event " << fNumEntry << "+";
1057 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range (>=";
1058 *fLog << GetEntries() << ")." << endl;
1059 return kFALSE;
1060 }
1061
1062 fNumEntry += inc;
1063 return kTRUE;
1064}
1065
1066// --------------------------------------------------------------------------
1067//
1068// This function makes Process() read event number nr next
1069//
1070// Remark: You can use this function after instatiating you MReadTree-object
1071// to set the event number from which you want to start reading.
1072//
1073Bool_t MReadTree::SetEventNum(UInt_t nr)
1074{
1075 if (nr!=0 && nr >= GetEntries())
1076 {
1077 *fLog << warn << GetDescriptor() << ": SetEventNum, WARNING - " << nr << " out of Range." << endl;
1078 return kFALSE;
1079 }
1080
1081 fNumEntry = nr;
1082 return kTRUE;
1083}
1084
1085// --------------------------------------------------------------------------
1086//
1087// For the branch with the given name:
1088// 1) no object is automatically created
1089// 2) the branch address for this branch is not set
1090// (because we lack the object, see 1)
1091// 3) The whole branch (exactly: all its subbranches) are disabled
1092// this means are not read in memory by TTree:GetEntry
1093//
1094void MReadTree::VetoBranch(const char *name)
1095{
1096 fVetoList->Add(new TNamed(name, ""));
1097}
1098
1099// --------------------------------------------------------------------------
1100//
1101// Return the name of the file we are actually reading from.
1102//
1103TString MReadTree::GetFileName() const
1104{
1105 const TFile *file = fChain ? fChain->GetFile() : fTree->GetCurrentFile();
1106
1107 if (!file)
1108 return TString("<unknown>");
1109
1110 TString name(file->GetName());
1111 name.Remove(0, name.Last('/')+1);
1112 return name;
1113}
1114
1115// --------------------------------------------------------------------------
1116//
1117// Return the number of the file in the chain, -1 in case of an error
1118//
1119Int_t MReadTree::GetFileIndex() const
1120{
1121 return fChain ? fChain->GetTreeNumber() : 0;
1122 /*
1123 const TString filename = fChain->GetFile()->GetName();
1124
1125 int i=0;
1126 TObject *file = NULL;
1127
1128 TIter Next(fChain->GetListOfFiles());
1129 while ((file=Next()))
1130 {
1131 if (filename==gSystem->ExpandPathName(file->GetTitle()))
1132 return i;
1133 i++;
1134 }
1135 return -1;
1136 */
1137}
1138
1139// --------------------------------------------------------------------------
1140//
1141// This schedules a TObject which Notify(9 function is called in case
1142// of MReadTree (TChain) switches from one file in the chain to another
1143// one.
1144//
1145void MReadTree::AddNotify(TObject *obj)
1146{
1147 fNotify->Add(obj);
1148}
1149
1150void MReadTree::Print(Option_t *o) const
1151{
1152 *fLog << all << underline << GetDescriptor() << ":" << endl << dec;
1153 *fLog << " Files [Tree]:" << endl;
1154
1155 int i = 0;
1156 TIter Next(fChain->GetListOfFiles());
1157 TObject *obj = NULL;
1158 while ((obj=Next()))
1159 *fLog << " " << i++ << ") " << obj->GetTitle() << " [" << obj->GetName() << "]" << endl;
1160
1161 *fLog << " Total Number of Entries: " << fNumEntries << endl;
1162 *fLog << " Next Entry to read: " << fNumEntry << endl;
1163}
1164
1165// --------------------------------------------------------------------------
1166//
1167// Implementation of SavePrimitive. Used to write the call to a constructor
1168// to a macro. In the original root implementation it is used to write
1169// gui elements to a macro-file.
1170//
1171void MReadTree::StreamPrimitive(ofstream &out) const
1172{
1173 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
1174 out << fChain->GetName() << "\", \"" << fName << "\", \"" << fTitle << "\");" << endl;
1175
1176 TIter Next(fChain->GetListOfFiles());
1177 TObject *obj = NULL;
1178 while ((obj=Next()))
1179 out << " " << GetUniqueName() << ".AddFile(\"" << obj->GetTitle() << "\");" << endl;
1180
1181 if (!fAutoEnable)
1182 out << " " << GetUniqueName() << ".DisableAutoScheme();" << endl;
1183
1184 if (fNumEntry!=0)
1185 out << " " << GetUniqueName() << ".SetEventNum(" << fNumEntry << ");" << endl;
1186
1187
1188}
Note: See TracBrowser for help on using the repository browser.