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

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