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

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