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

Last change on this file since 5773 was 5715, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 36.0 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//
289// For unknown reasons root stores the SetAutoDelete-Flag in
290// a branch having a custom streamer (eg. MRawEvtData).
291// It is not allowed that a container which is in the parameter
292// list gets a new address. Therefor we reset all the autodel flags.
293//
294// MAKE SURE THAT ALL YOPUR CUSTOM STREAMERS TAKE CARE OF ALL MEMORY
295//
296Bool_t MReadTree::Notify()
297{
298 //
299 // Do a consistency check for all branches
300 //
301 if (!CheckBranchSize())
302 return kFALSE;
303
304 *fLog << inf << GetDescriptor() << ": Switching to #" << GetFileIndex();
305 *fLog << " '" << GetFileName() << "' (before event #";
306 *fLog << GetNumEntry()-1 << ")" << endl;
307
308 //
309 // For unknown reasons root stores the SetAutoDelete-Flag in
310 // a branch having a custom streamer (eg. MRawEvtData).
311 // It is not allowed that a container which is in the parameter
312 // list gets a new address. Therefor we reset all the autodel flags.
313 //
314 // MAKE SURE THAT ALL YOPUR CUSTOM STREAMERS TAKE CARE OF ALL MEMORY
315 //
316 TIter NextB(fTree->GetListOfBranches());
317 TBranch *b=0;
318 while ((b=(TBranch*)NextB()))
319 if (b->IsAutoDelete())
320 {
321 *fLog << warn << "Branch " << b->GetName() << "->IsAutoDelete() set... resetting." << endl;
322 b->SetAutoDelete(kFALSE);
323 }
324
325 if (!fNotify)
326 return kTRUE;
327
328 TIter NextN(fNotify);
329 TObject *o=NULL;
330 while ((o=NextN()))
331 if (!o->Notify())
332 {
333 *fLog << err << "Calling Notify() for object " << o->GetName() << " failed... abort." << endl;
334 return kFALSE;
335 }
336
337 return kTRUE;
338}
339
340// --------------------------------------------------------------------------
341//
342// If you want to read the given tree over several files you must add
343// the files here before PreProcess is called. Be careful: If the tree
344// doesn't have the same contents (branches) it may confuse your
345// program (trees which are are not existing in later files are not read
346// anymore, tree wich are not existing in the first file are never read)
347//
348// Name may use the wildcarding notation, eg "xxx*.root" means all files
349// starting with xxx in the current file system directory.
350//
351// AddFile returns the number of files added to the chain.
352//
353// For more information see TChain::Add
354//
355Int_t MReadTree::AddFile(const char *fname, Int_t entries)
356{
357 if (!fChain)
358 {
359 *fLog << err << "MReadTree::AddFile - ERROR: You cannot add a file, because MReadTree" << endl;
360 *fLog << " handles a memory based tree or its default" << endl;
361 *fLog << " constructor was called." << endl;
362 return 0;
363 }
364
365#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,01)
366 //
367 // This is a workaround to get rid of crashed if the file doesn't
368 // exist due to non initialized TFile::fProcessIDs
369 //
370 // (Code taken from TFile::TFile
371 //
372 TString newname; // char-array must overcome comming block
373
374 if (strrchr(fname, '?') || strrchr(fname, '*'))
375 {
376 *fLog << warn;
377 *fLog<< "WARNING: Using widcards with older root versions:" << endl;
378 *fLog << " You may encounter crashes closing the files..." << endl;
379 }
380 else
381 {
382 const char *name;
383
384 if ((name = gSystem->ExpandPathName(fname)))
385 {
386 newname = name;
387 delete [] name;
388 }
389
390 if (newname.IsNull())
391 {
392 *fLog << err << dbginf << "Error expanding path " << fname << "." << endl;
393 return 0;
394 }
395
396 if (gSystem->AccessPathName(newname, kFileExists))
397 {
398 *fLog << err << "ERROR - File '" << fname << "' does not exist." << endl;
399 return 0;
400 }
401
402 fname = newname.Data();
403 }
404#endif
405
406 //
407 // FIXME! A check is missing whether the file already exists or not.
408 //
409 const Int_t numfiles = fChain->Add(fname, entries<0?TChain::kBigNumber:entries);
410
411 if (numfiles>0)
412 {
413 SetBit(kChainWasChanged);
414 *fLog << inf << GetDescriptor() << " - AddFile: " << numfiles << " files added from " << fname << "." << endl;
415 }
416 else
417 *fLog << warn << "WARNING: '" << fname << "' not added to " << GetDescriptor() << endl;
418
419 return numfiles;
420}
421
422/*
423 // --------------------------------------------------------------------------
424 //
425 //
426 Int_t MReadTree::AddFile(const TChainElement &obj)
427 {
428 return AddFile(obj.GetTitle(), obj.GetEntries());
429 }
430*/
431
432// --------------------------------------------------------------------------
433//
434// Adds all files from another MReadTree to this instance
435//
436// Returns the number of file which were added
437//
438Int_t MReadTree::AddFiles(const MReadTree &read)
439{
440 if (!fChain)
441 {
442 *fLog << err << "MReadTree::AddFiles - ERROR: You cannot add a file, because MReadTree" << endl;
443 *fLog << " handles a memory based tree or its default" << endl;
444 *fLog << " constructor was called." << endl;
445 return 0;
446 }
447
448 const Int_t rc = fChain->Add(read.fChain);
449
450 if (rc>0)
451 SetBit(kChainWasChanged);
452
453 /*
454 Int_t rc = 0;
455
456 TIter Next(read.fChain->GetListOfFiles());
457 TObject *obj = NULL;
458 while ((obj=Next()))
459 rc += AddFile(*(TChainElement*)obj);
460 */
461
462 return rc;
463}
464
465// --------------------------------------------------------------------------
466//
467// Sort the files by their file-names
468//
469void MReadTree::SortFiles()
470{
471 if (fChain)
472 fChain->GetListOfFiles()->Sort();
473}
474
475// --------------------------------------------------------------------------
476//
477// This function is called if Branch choosing method should get enabled.
478// Branch choosing means, that only the enabled branches are read into
479// memory. To use an enableing scheme we have to disable all branches first.
480// This is done, if this function is called the first time.
481//
482void MReadTree::EnableBranchChoosing()
483{
484 if (fBranchChoosing)
485 return;
486
487 *fLog << inf << GetDescriptor() << ": Branch choosing enabled (only enabled branches are read)." << endl;
488 fTree->SetBranchStatus("*", kFALSE); // *CHANGED-fChain-to-fTree*
489 fBranchChoosing = kTRUE;
490}
491
492// --------------------------------------------------------------------------
493//
494// The first time this function is called all branches are disabled.
495// The given branch is enabled. By enabling only the branches you
496// are processing you can speed up your calculation many times (up to
497// a factor of 10 or 20)
498//
499void MReadTree::EnableBranch(const char *name)
500{
501 if (!fChain)
502 {
503 *fLog << warn << "MReadTree::EnableBranch - WARNING: EnableBranch doesn't work with memory based trees... ignored." << endl;
504 return;
505 }
506
507 if (fChain->GetListOfFiles()->GetEntries()==0)
508 {
509 *fLog << err << "Chain contains no file... Branch '";
510 *fLog << name << "' ignored." << endl;
511 return;
512 }
513
514 EnableBranchChoosing();
515
516 TNamed branch(name, "");
517 SetBranchStatus(&branch, kTRUE);
518}
519
520// --------------------------------------------------------------------------
521//
522// Set branch status of branch name
523//
524void MReadTree::SetBranchStatus(const char *name, Bool_t status)
525{
526 fTree->SetBranchStatus(name, status); // *CHANGED-fChain-to-fTree*
527
528 *fLog << inf << (status ? "Enabled" : "Disabled");
529 *fLog << " subbranch '" << name << "'." << endl;
530}
531
532// --------------------------------------------------------------------------
533//
534// Checks whether a branch with the given name exists in the chain
535// and sets the branch status of this branch corresponding to status.
536//
537void MReadTree::SetBranchStatus(TObject *branch, Bool_t status)
538{
539 //
540 // Get branch name
541 //
542 const char *name = branch->GetName();
543
544 //
545 // Check whether this branch really exists
546 //
547 TString bn(name);
548 if (bn.EndsWith("*"))
549 bn.Remove(bn.Length()-1);
550
551 if (fTree->GetBranch(bn)) // *CHANGED-fChain-to-fTree*
552 SetBranchStatus(name, status);
553
554 //
555 // Remove trailing '.' if one and try to enable the subbranch without
556 // the master branch name. This is to be compatible with older mars
557 // and camera files.
558 //
559 const char *dot = strrchr(name, '.');
560 if (!dot)
561 return;
562
563 if (fTree->GetBranch(dot+1)) // *CHANGED-fChain-to-fTree*
564 SetBranchStatus(dot+1, status);
565}
566
567// --------------------------------------------------------------------------
568//
569// Set the status of all branches in the list to status.
570//
571void MReadTree::SetBranchStatus(const TList *list, Bool_t status)
572{
573 //
574 // Loop over all subbranches in this master branch
575 //
576 TIter Next(list);
577
578 TObject *obj;
579 while ((obj=Next()))
580 SetBranchStatus(obj, status);
581}
582
583// --------------------------------------------------------------------------
584//
585// This is the implementation of the Auto Enabling Scheme.
586// For more information see MTask::AddBranchToList.
587// This function loops over all tasks and its filters in the tasklist
588// and enables all branches which are requested by the tasks and its
589// filters.
590//
591// To enable 'unknown' branches which are not in the branchlist of
592// the tasks you can call EnableBranch
593//
594void MReadTree::EnableBranches(MParList *plist)
595{
596 //
597 // check whether branch choosing must be switched on
598 //
599 EnableBranchChoosing();
600
601 //
602 // request the tasklist from the parameter list.
603 // FIXME: Tasklist can have a different name
604 //
605 const MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
606 if (!tlist)
607 {
608 *fLog << warn << GetDescriptor() << "Cannot use auto enabeling scheme for branches. 'MTaskList' not found." << endl;
609 return;
610 }
611
612 //
613 // This loop is not necessary. We could do it like in the commented
614 // loop below. But this loop makes sure, that we don't try to enable
615 // one branch several times. This would not harm, but we would get
616 // an output for each attempt. To have several outputs for one subbranch
617 // may confuse the user, this we don't want.
618 // This loop creates a new list of subbranches and for each branch
619 // which is added we check before whether it already exists or not.
620 //
621 TList list;
622
623 MTask *task;
624 TIter NextTask(tlist->GetList());
625 while ((task=(MTask*)NextTask()))
626 {
627 TObject *obj;
628
629 TIter NextTBranch(task->GetListOfBranches());
630 while ((obj=NextTBranch()))
631 if (!list.FindObject(obj->GetName()))
632 list.Add(obj);
633
634 const MFilter *filter = task->GetFilter();
635
636 if (!filter)
637 continue;
638
639 TIter NextFBranch(filter->GetListOfBranches());
640 while ((obj=NextFBranch()))
641 if (!list.FindObject(obj->GetName()))
642 list.Add(obj);
643 }
644
645 SetBranchStatus(&list, kTRUE);
646/*
647 //
648 // Loop over all tasks iand its filters n the task list.
649 //
650 MTask *task;
651 TIter NextTask(tlist->GetList());
652 while ((task=(MTask*)NextTask()))
653 {
654 SetBranchStatus(task->GetListOfBranches(), kTRUE);
655
656 const MFilter *filter = task->GetFilter();
657 if (!filter)
658 continue;
659
660 SetBranchStatus(filter->GetListOfBranches(), kTRUE);
661
662 }
663*/
664}
665
666// --------------------------------------------------------------------------
667//
668// If the chain has been changed (by calling AddFile or using a file
669// in the constructors argument) the number of entries is newly
670// calculated from the files in the chain - this may take a while.
671// The number of entries is returned.
672//
673UInt_t MReadTree::GetEntries()
674{
675 if (TestBit(kChainWasChanged))
676 {
677 // *CHANGED-fChain-to-fTree*
678 *fLog << inf << "Scanning chain " << fTree->GetName() << "... " << flush;
679 fNumEntries = (UInt_t)fTree->GetEntries();
680 *fLog << fNumEntries << " events found." << endl;
681 ResetBit(kChainWasChanged);
682 }
683 return fNumEntries==TChain::kBigNumber ? 0 : fNumEntries;
684}
685
686// --------------------------------------------------------------------------
687//
688// The disables all subbranches of the given master branch.
689//
690void MReadTree::DisableSubBranches(TBranch *branch)
691{
692 //
693 // This is not necessary, it would work without. But the output
694 // may confuse the user...
695 //
696 if (fAutoEnable || fBranchChoosing)
697 return;
698
699 SetBranchStatus(branch->GetListOfBranches(), kFALSE);
700}
701
702// --------------------------------------------------------------------------
703//
704// The PreProcess loops (till now) over the branches in the given tree.
705// It checks if the corresponding containers (containers with the same
706// name than the branch name) are existing in the Parameter Container List.
707// If not, a container of objec type 'branch-name' is created (everything
708// after the last semicolon in the branch name is stripped). Only
709// branches which don't have a veto (see VetoBranch) are enabled If the
710// object isn't found in the root dictionary (a list of classes known by the
711// root environment) the branch is skipped and an error message is printed
712// out.
713// If a selector is specified it is preprocessed after the
714// MReadTree::PreProcess
715//
716Int_t MReadTree::PreProcess(MParList *pList)
717{
718 fTaskList = (MTaskList*)pList->FindObject("MTaskList");
719 if (!fTaskList)
720 *fLog << warn << "WARNING - Standard tasklist MTaskList not found... ignoring Stream-ID." << endl;
721
722 //
723 // Make sure, that all the following calls doesn't result in
724 // Notifications. This may be dangerous, because the notified
725 // tasks are not preprocessed.
726 //
727 fTree->SetNotify(NULL); //*CHANGED-fChain-to-fTree*
728
729 //
730 // It seems, that TFile and TTree are not completely independant if
731 // many times the same file is openes (MReadReports) and some of
732 // the files in the chains don't have one tree. TChain::fTreeNumber
733 // is already set before LoadTree from GetFile is called and
734 // it crashes. ResetTree makes sure, that the tree number is -1
735 //
736 if (fChain) // *CHANGED-fChain-to-fTree*
737 fChain->ResetTree();
738 // Maybe this would be enough, but the above might be safer...
739 //if (fChain->GetTreeNumber()==0)
740 // fChain->ResetTree();
741
742 //
743 // check for files and for the tree!
744 //
745 if (fChain && !fChain->GetFile()) // *CHANGED-fChain-to-fTree*
746 {
747 *fLog << err << GetDescriptor() << ": No file or no tree with name " << fChain->GetName() << " in file." << endl;
748 return kFALSE;
749 }
750
751 //
752 // get number of events in this tree
753 //
754 if (!GetEntries())
755 {
756 *fLog << err << GetDescriptor() << ": No entries found in file(s)" << endl;
757 return kFALSE;
758 }
759
760 //
761 // output logging information
762 //
763 *fLog << inf << fNumEntries << " entries found in file(s)." << endl;
764
765 //
766 // Get all branches of this tree and
767 // create the Iterator to loop over all branches
768 //
769 TIter Next(fTree->GetListOfBranches()); // *CHANGED-fChain-to-fTree*
770 TBranch *branch=NULL;
771
772 Int_t num=0;
773
774 //
775 // loop over all tasks for processing
776 //
777 while ( (branch=(TBranch*)Next()) )
778 {
779 //
780 // Get Name of Branch and Object
781 //
782 const char *bname = branch->GetName();
783
784 TString oname(bname);
785 if (oname.EndsWith("."))
786 oname.Remove(oname.Length()-1);
787
788 //
789 // Check if enabeling the branch is allowed
790 //
791 if (fVetoList->FindObject(oname))
792 {
793 *fLog << inf << "Master branch " << bname << " has veto... skipped." << endl;
794 DisableSubBranches(branch);
795 continue;
796 }
797
798 //
799 // Create a pointer to the pointer to the object in which the
800 // branch data is stored. The pointers are stored in the TChain
801 // object and we get the pointers from there to delete it.
802 //
803 MParContainer **pcont= new MParContainer*;
804
805#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
806 const char *classname = oname;
807#else
808 const char *classname = branch->GetClassName();
809#endif
810
811 //
812 // check if object is existing in the list
813 //
814 *pcont=pList->FindCreateObj(classname, oname);
815
816 if (!*pcont)
817 {
818 //
819 // if class is not existing in the (root) environment
820 // we cannot proceed reading this branch
821 //
822 *fLog << warn << dbginf << "Warning: Class '" << classname;
823 *fLog << "' for " << oname << " not existing in dictionary. Branch skipped." << endl;
824 DisableSubBranches(branch);
825 continue;
826 }
827
828 //
829 // Check whether a Pointer to a pointer already exists.
830 // If we created one already, delete it.
831 //
832 // *CHANGED-fChain-to-fTree*
833 if (fChain)
834 {
835 TChainElement *element = (TChainElement*)fChain->GetStatus()->FindObject(bname);
836 if (element)
837 delete (MParContainer**)element->GetBaddress();
838 }
839 /* This can't be done here for memory trees - see
840 PostProcess for more details.
841 else
842 {
843 TBranch *branch = (TBranch*)fTree->GetBranch(bname);
844 if (branch)
845 {
846 *fLog << bname << " " << (void*)branch->GetAddress() << " " << pcont << endl;
847 delete (MParContainer**)branch->GetAddress();
848 }
849 }
850 */
851
852 //
853 // here pcont is a pointer the to container in which the data from
854 // the actual branch should be stored - enable branch.
855 //
856 fTree->SetBranchAddress(bname, pcont); // *CHANGED-fChain-to-fTree*
857
858 *fLog << inf << "Master branch address '" << bname << "' [";
859 *fLog << classname << "] setup for reading." << endl;
860
861 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
862 //branch->SetAutoDelete();
863
864 num++;
865 }
866
867 *fLog << inf << GetDescriptor() << " setup " << num << " master branches addresses." << endl;
868
869 //
870 // If auto enabling scheme isn't disabled, do auto enabling
871 //
872 if (fAutoEnable)
873 EnableBranches(pList);
874
875 //
876 // Now we can start notifying. Reset tree makes sure, that TChain thinks
877 // that the correct file is not yet initialized and reinitilizes it
878 // as soon as the first event is read. This is necessary to call
879 // the notifiers when the first event is read, but after the
880 // PreProcess-function.
881 //
882 if (fChain)
883 fChain->ResetTree(); // *CHANGED-fChain-to-fTree*
884
885 fTree->SetNotify(this); // *CHANGED-fChain-to-fTree*
886
887 const Int_t rc = GetSelector() ? GetSelector()->CallPreProcess(pList) : kTRUE;
888 if (rc!=kTRUE || fChain)
889 return rc;
890
891 return Notify();
892}
893
894// --------------------------------------------------------------------------
895//
896// Set the ready to save flag of all containers which branchaddresses are
897// set for. This is necessary to copy data.
898//
899void MReadTree::SetReadyToSave(Bool_t flag)
900{
901 if (!fChain)
902 return;
903
904 TIter Next(fChain->GetStatus());
905
906 TChainElement *element = NULL;
907 while ((element=(TChainElement*)Next()))
908 {
909 //
910 // Check whether the branch is enabled
911 //
912 if (!element->GetStatus())
913 continue;
914
915 //
916 // Get the pointer to the pointer of the corresponding container
917 //
918 MParContainer **pcont = (MParContainer**)element->GetBaddress();
919
920 //
921 // Check whether the pointer is not NULL
922 //
923 if (!pcont || !*pcont)
924 continue;
925
926 //
927 // Set the ready to save status of the container.
928 //
929 (*pcont)->SetReadyToSave(flag);
930 }
931
932 //
933 // Set the ready to save status of this task (used?), too
934 //
935 MTask::SetReadyToSave(flag);
936}
937
938// --------------------------------------------------------------------------
939//
940// The Process-function reads one event from the tree (this contains all
941// enabled branches) and increases the position in the file by one event.
942// (Remark: The position can also be set by some member functions
943// If the end of the file is reached the Eventloop is stopped.
944// In case an event selector is given its value is checked before
945// reading the event. If it returns kAFLSE the event is skipped.
946//
947#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
948#include "MRawEvtData.h"
949#endif
950Int_t MReadTree::Process()
951{
952 //
953 // This is necessary due to a bug in TChain::LoadTree in root.
954 // will be fixed in 3.03
955 //
956#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,01)
957 if (fNumEntry >= GetEntries())
958 return kFALSE;
959#endif
960
961#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
962 //
963 // This fixes 99.9% of a memory leak using a root version prior
964 // to 3.02/??
965 //
966 TChainElement *element=NULL;
967 TIter Next(fChain->GetStatus());
968 while ((element=(TChainElement*)Next()))
969 {
970 MParContainer **c = (MParContainer**)element->GetBaddress();
971 if (!c) continue;
972 if ((*c)->InheritsFrom(MRawEvtData::Class()))
973 static_cast<MRawEvtData*>(*c)->DeletePixels(kFALSE);
974
975 }
976#endif
977
978 if (GetSelector())
979 {
980 //
981 // Make sure selector is processed
982 //
983 if (!GetSelector()->CallProcess())
984 {
985 *fLog << err << dbginf << "Processing Selector failed." << endl;
986 return kFALSE;
987 }
988
989 //
990 // Skip Event
991 //
992 if (!GetSelector()->IsConditionTrue())
993 {
994 fNumEntry++;
995 return kCONTINUE;
996 }
997 }
998
999 const Bool_t rc = fTree->GetEntry(fNumEntry++) != 0; // *CHANGED-fChain-to-fTree*
1000
1001 if (fTaskList)
1002 fTaskList->SetStreamId(fTree->GetName()); // *CHANGED-fChain-to-fTree*
1003
1004 if (rc)
1005 SetReadyToSave();
1006
1007 return rc;
1008}
1009
1010// --------------------------------------------------------------------------
1011//
1012// If a selector is given the selector is post processed
1013//
1014Int_t MReadTree::PostProcess()
1015{
1016 // In the case of a memory tree I don't know how we can
1017 // make a decision in PreProcess between a self allocated
1018 // memory address or a pending address set long before.
1019 // So we delete the stuff in PostProcess and not the destructor
1020 // (which might seg faullt if PreProcess has never been called)
1021 if (!fChain)
1022 {
1023 TIter Next(fTree->GetListOfBranches());
1024 TBranch *b=0;
1025 while ((b=(TBranch*)Next()))
1026 {
1027 if (b->GetAddress())
1028 {
1029 delete b->GetAddress();
1030 b->ResetAddress();
1031 }
1032 }
1033 }
1034
1035 return GetSelector() ? GetSelector()->CallPostProcess() : kTRUE;
1036}
1037
1038// --------------------------------------------------------------------------
1039//
1040// Get the Event with the current EventNumber fNumEntry
1041//
1042Bool_t MReadTree::GetEvent()
1043{
1044 Bool_t rc = fTree->GetEntry(fNumEntry) != 0; // *CHANGED-fChain-to-fTree*
1045
1046 if (rc)
1047 SetReadyToSave();
1048
1049 return rc;
1050}
1051
1052// --------------------------------------------------------------------------
1053//
1054// Decrease the number of the event which is read by Process() next
1055// by one or more
1056//
1057Bool_t MReadTree::DecEventNum(UInt_t dec)
1058{
1059 if (fNumEntry-dec >= GetEntries())
1060 {
1061 *fLog << warn << GetDescriptor() << ": DecEventNum, WARNING - Event " << fNumEntry << "-";
1062 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range (>=";
1063 *fLog << GetEntries() << ")." << endl;
1064 return kFALSE;
1065 }
1066
1067 fNumEntry -= dec;
1068 return kTRUE;
1069}
1070
1071// --------------------------------------------------------------------------
1072//
1073// Increase the number of the event which is read by Process() next
1074// by one or more
1075//
1076Bool_t MReadTree::IncEventNum(UInt_t inc)
1077{
1078 if (fNumEntry+inc >= GetEntries())
1079 {
1080 *fLog << warn << GetDescriptor() << ": IncEventNum, WARNING - Event " << fNumEntry << "+";
1081 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range (>=";
1082 *fLog << GetEntries() << ")." << endl;
1083 return kFALSE;
1084 }
1085
1086 fNumEntry += inc;
1087 return kTRUE;
1088}
1089
1090// --------------------------------------------------------------------------
1091//
1092// This function makes Process() read event number nr next
1093//
1094// Remark: You can use this function after instatiating you MReadTree-object
1095// to set the event number from which you want to start reading.
1096//
1097Bool_t MReadTree::SetEventNum(UInt_t nr)
1098{
1099 if (nr!=0 && nr >= GetEntries())
1100 {
1101 *fLog << warn << GetDescriptor() << ": SetEventNum, WARNING - " << nr << " out of Range." << endl;
1102 return kFALSE;
1103 }
1104
1105 fNumEntry = nr;
1106 return kTRUE;
1107}
1108
1109// --------------------------------------------------------------------------
1110//
1111// For the branch with the given name:
1112// 1) no object is automatically created
1113// 2) the branch address for this branch is not set
1114// (because we lack the object, see 1)
1115// 3) The whole branch (exactly: all its subbranches) are disabled
1116// this means are not read in memory by TTree:GetEntry
1117//
1118void MReadTree::VetoBranch(const char *name)
1119{
1120 fVetoList->Add(new TNamed(name, ""));
1121}
1122
1123// --------------------------------------------------------------------------
1124//
1125// Return the name of the file we are actually reading from.
1126//
1127TString MReadTree::GetFileName() const
1128{
1129 const TFile *file = fChain ? fChain->GetFile() : fTree->GetCurrentFile();
1130
1131 if (!file)
1132 return TString("<unknown>");
1133
1134 TString name(file->GetName());
1135 name.Remove(0, name.Last('/')+1);
1136 return name;
1137}
1138
1139// --------------------------------------------------------------------------
1140//
1141// Return the number of the file in the chain, -1 in case of an error
1142//
1143Int_t MReadTree::GetFileIndex() const
1144{
1145 return fChain ? fChain->GetTreeNumber() : 0;
1146 /*
1147 const TString filename = fChain->GetFile()->GetName();
1148
1149 int i=0;
1150 TObject *file = NULL;
1151
1152 TIter Next(fChain->GetListOfFiles());
1153 while ((file=Next()))
1154 {
1155 if (filename==gSystem->ExpandPathName(file->GetTitle()))
1156 return i;
1157 i++;
1158 }
1159 return -1;
1160 */
1161}
1162
1163// --------------------------------------------------------------------------
1164//
1165// This schedules a TObject which Notify(9 function is called in case
1166// of MReadTree (TChain) switches from one file in the chain to another
1167// one.
1168//
1169void MReadTree::AddNotify(TObject *obj)
1170{
1171 fNotify->Add(obj);
1172}
1173
1174void MReadTree::Print(Option_t *o) const
1175{
1176 *fLog << all << underline << GetDescriptor() << ":" << endl << dec;
1177 *fLog << " Files [Tree]:" << endl;
1178
1179 int i = 0;
1180 TIter Next(fChain->GetListOfFiles());
1181 TObject *obj = NULL;
1182 while ((obj=Next()))
1183 *fLog << " " << i++ << ") " << obj->GetTitle() << " [" << obj->GetName() << "]" << endl;
1184
1185 *fLog << " Total Number of Entries: " << fNumEntries << endl;
1186 *fLog << " Next Entry to read: " << fNumEntry << endl;
1187}
1188
1189// --------------------------------------------------------------------------
1190//
1191// Implementation of SavePrimitive. Used to write the call to a constructor
1192// to a macro. In the original root implementation it is used to write
1193// gui elements to a macro-file.
1194//
1195void MReadTree::StreamPrimitive(ofstream &out) const
1196{
1197 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
1198 out << fChain->GetName() << "\", \"" << fName << "\", \"" << fTitle << "\");" << endl;
1199
1200 TIter Next(fChain->GetListOfFiles());
1201 TObject *obj = NULL;
1202 while ((obj=Next()))
1203 out << " " << GetUniqueName() << ".AddFile(\"" << obj->GetTitle() << "\");" << endl;
1204
1205 if (!fAutoEnable)
1206 out << " " << GetUniqueName() << ".DisableAutoScheme();" << endl;
1207
1208 if (fNumEntry!=0)
1209 out << " " << GetUniqueName() << ".SetEventNum(" << fNumEntry << ");" << endl;
1210
1211
1212}
Note: See TracBrowser for help on using the repository browser.