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

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