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

Last change on this file since 8886 was 8746, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 36.8 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 YOUR 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 YOUR 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 << " is supposed to read its tree from memory or its default or its" << endl;
344 *fLog << " default constructor was called (no tree name was given)." << 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)
398 *fLog << inf3 << 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 if (!fTree || !fChain)
707 {
708 *fLog << err << "ERROR - Something went terribly wrong!" << endl;
709 *fLog << " Maybe you called the default constructor?" << endl;
710 *fLog << " Did you forget to give a tree name in the constructor?" << endl;
711 return kFALSE;
712 }
713
714 //
715 // Make sure, that all the following calls doesn't result in
716 // Notifications. This may be dangerous, because the notified
717 // tasks are not preprocessed.
718 //
719 fTree->SetNotify(NULL); //*CHANGED-fChain-to-fTree*
720
721 //
722 // It seems, that TFile and TTree are not completely independant if
723 // many times the same file is opened (MReadReports) and some of
724 // the files in the chains don't have one tree. TChain::fTreeNumber
725 // is already set before LoadTree from GetFile is called and
726 // it crashes. ResetTree makes sure, that the tree number is -1
727 //
728 if (fChain) // *CHANGED-fChain-to-fTree*
729 fChain->ResetTree();
730 // Maybe this would be enough, but the above might be safer...
731 //if (fChain->GetTreeNumber()==0)
732 // fChain->ResetTree();
733
734 //
735 // check for files and for the tree!
736 //
737 if (fChain && !fChain->GetFile()) // *CHANGED-fChain-to-fTree*
738 {
739 *fLog << err << GetDescriptor() << ": No file or no tree with name " << fChain->GetName() << " in file." << endl;
740 return kFALSE;
741 }
742
743 //
744 // get number of events in this tree
745 //
746 if (!GetEntries())
747 {
748 *fLog << err << GetDescriptor() << ": No entries found in file(s)" << endl;
749 return kFALSE;
750 }
751
752 //
753 // output logging information
754 //
755 *fLog << inf << fNumEntries << " entries found in file(s)." << endl;
756
757 //
758 // Get all branches of this tree and
759 // create the Iterator to loop over all branches
760 //
761 TIter Next(fTree->GetListOfBranches()); // *CHANGED-fChain-to-fTree*
762 TBranch *branch=NULL;
763
764 Int_t num=0;
765
766 //
767 // loop over all tasks for processing
768 //
769 while ( (branch=(TBranch*)Next()) )
770 {
771 //
772 // Get Name of Branch and Object
773 //
774 const char *bname = branch->GetName();
775
776 TString oname(bname);
777 if (oname.EndsWith("."))
778 oname.Remove(oname.Length()-1);
779
780 //
781 // Check if enabeling the branch is allowed
782 //
783 if (fVetoList->FindObject(oname))
784 {
785 *fLog << inf << "Master branch " << bname << " has veto... skipped." << endl;
786 DisableSubBranches(branch);
787 continue;
788 }
789
790 //
791 // Create a pointer to the pointer to the object in which the
792 // branch data is stored. The pointers are stored in the TChain
793 // object and we get the pointers from there to delete it.
794 //
795 MParContainer **pcont= new MParContainer*;
796
797#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
798 const char *classname = oname;
799#else
800 const char *classname = branch->GetClassName();
801#endif
802
803 //
804 // check if object is existing in the list
805 //
806 *pcont=pList->FindCreateObj(classname, oname);
807
808 if (!*pcont)
809 {
810 //
811 // if class is not existing in the (root) environment
812 // we cannot proceed reading this branch
813 //
814 *fLog << warn << dbginf << "Warning: Class '" << classname;
815 *fLog << "' for " << oname << " not existing in dictionary. Branch skipped." << endl;
816 DisableSubBranches(branch);
817 continue;
818 }
819
820 //
821 // Check whether a Pointer to a pointer already exists.
822 // If we created one already, delete it.
823 //
824 // *CHANGED-fChain-to-fTree*
825 if (fChain)
826 {
827 TChainElement *element = (TChainElement*)fChain->GetStatus()->FindObject(bname);
828 if (element)
829 delete (MParContainer**)element->GetBaddress();
830 }
831 /* This can't be done here for memory trees - see
832 PostProcess for more details.
833 else
834 {
835 TBranch *branch = (TBranch*)fTree->GetBranch(bname);
836 if (branch)
837 {
838 *fLog << bname << " " << (void*)branch->GetAddress() << " " << pcont << endl;
839 delete (MParContainer**)branch->GetAddress();
840 }
841 }
842 */
843
844 //
845 // here pcont is a pointer the to container in which the data from
846 // the actual branch should be stored - enable branch.
847 //
848 fTree->SetBranchAddress(bname, pcont); // *CHANGED-fChain-to-fTree*
849
850 *fLog << inf2 << "Master branch address '" << bname << "' ";
851 if ((TString)bname!=(TString)classname)
852 *fLog << "[" << classname << "] ";
853 *fLog << "setup for reading." << endl;
854
855 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
856 //branch->SetAutoDelete();
857
858 num++;
859 }
860
861 *fLog << inf2 << GetDescriptor() << " setup " << num << " master branches addresses." << endl;
862
863 //
864 // If auto enabling scheme isn't disabled, do auto enabling
865 //
866 if (fAutoEnable)
867 EnableBranches(pList);
868
869 //
870 // Now we can start notifying. Reset tree makes sure, that TChain thinks
871 // that the correct file is not yet initialized and reinitilizes it
872 // as soon as the first event is read. This is necessary to call
873 // the notifiers when the first event is read, but after the
874 // PreProcess-function.
875 //
876 if (fChain)
877 fChain->ResetTree(); // *CHANGED-fChain-to-fTree*
878
879 fTree->SetNotify(this); // *CHANGED-fChain-to-fTree*
880
881 const Int_t rc = GetSelector() ? GetSelector()->CallPreProcess(pList) : kTRUE;
882 if (rc!=kTRUE || fChain)
883 return rc;
884
885 return Notify();
886}
887
888// --------------------------------------------------------------------------
889//
890// Set the ready to save flag of all containers which branchaddresses are
891// set for. This is necessary to copy data.
892//
893void MReadTree::SetReadyToSave(Bool_t flag)
894{
895 if (!fChain)
896 return;
897
898 TIter Next(fChain->GetStatus());
899
900 TChainElement *element = NULL;
901 while ((element=(TChainElement*)Next()))
902 {
903 //
904 // Check whether the branch is enabled
905 //
906 if (!element->GetStatus())
907 continue;
908
909 //
910 // Get the pointer to the pointer of the corresponding container
911 //
912 MParContainer **pcont = (MParContainer**)element->GetBaddress();
913
914 //
915 // Check whether the pointer is not NULL
916 //
917 if (!pcont || !*pcont)
918 continue;
919
920 //
921 // Set the ready to save status of the container.
922 //
923 (*pcont)->SetReadyToSave(flag);
924 }
925
926 //
927 // Set the ready to save status of this task (used?), too
928 //
929 MTask::SetReadyToSave(flag);
930}
931
932// --------------------------------------------------------------------------
933//
934// The Process-function reads one event from the tree (this contains all
935// enabled branches) and increases the position in the file by one event.
936// (Remark: The position can also be set by some member functions
937// If the end of the file is reached the Eventloop is stopped.
938// In case an event selector is given its value is checked before
939// reading the event. If it returns kAFLSE the event is skipped.
940//
941#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
942#include "MRawEvtData.h"
943#endif
944Int_t MReadTree::Process()
945{
946 //
947 // This is necessary due to a bug in TChain::LoadTree in root.
948 // will be fixed in 3.03
949 //
950#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,01)
951 if (fNumEntry >= GetEntries())
952 return kFALSE;
953#endif
954
955#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
956 //
957 // This fixes 99.9% of a memory leak using a root version prior
958 // to 3.02/??
959 //
960 TChainElement *element=NULL;
961 TIter Next(fChain->GetStatus());
962 while ((element=(TChainElement*)Next()))
963 {
964 MParContainer **c = (MParContainer**)element->GetBaddress();
965 if (!c) continue;
966 if ((*c)->InheritsFrom(MRawEvtData::Class()))
967 static_cast<MRawEvtData*>(*c)->DeletePixels(kFALSE);
968
969 }
970#endif
971
972 if (GetSelector())
973 {
974 //
975 // Make sure selector is processed
976 //
977 if (!GetSelector()->CallProcess())
978 {
979 *fLog << err << dbginf << "Processing Selector failed." << endl;
980 return kFALSE;
981 }
982
983 //
984 // Skip Event
985 //
986 if (!GetSelector()->IsConditionTrue())
987 {
988 fNumEntry++;
989 return kCONTINUE;
990 }
991 }
992
993 const Bool_t rc = fTree->GetEntry(fNumEntry++) != 0; // *CHANGED-fChain-to-fTree*
994
995 if (fTaskList)
996 fTaskList->SetStreamId(fTree->GetName()); // *CHANGED-fChain-to-fTree*
997
998 if (rc)
999 {
1000 SetReadyToSave();
1001 return kTRUE;
1002 }
1003
1004 if (fChain)
1005 switch (fChain->GetLastError())
1006 {
1007 case MChain::kFatalError:
1008 *fLog << err << GetDescriptor() << " - ERROR: Notify() failed." << endl;
1009 return kERROR;
1010 case MChain::kCannotAccessFile:
1011 *fLog << err << GetDescriptor() << " - ERROR: TChain::LoadTree is unable to access requested file." << endl;
1012 return kERROR;
1013 case MChain::kCannotAccessTree:
1014 *fLog << err << GetDescriptor() << " - ERROR: TChain::LoadTree is unable to access requested tree." << endl;
1015 return kERROR;
1016 case MChain::kOutOfRange: // no more events available
1017 return kFALSE;
1018 case MChain::kNoError: // go on!
1019 return kTRUE;
1020 }
1021
1022 return rc;
1023}
1024
1025// --------------------------------------------------------------------------
1026//
1027// If a selector is given the selector is post processed
1028//
1029Int_t MReadTree::PostProcess()
1030{
1031 // In the case of a memory tree I don't know how we can
1032 // make a decision in PreProcess between a self allocated
1033 // memory address or a pending address set long before.
1034 // So we delete the stuff in PostProcess and not the destructor
1035 // (which might seg faullt if PreProcess has never been called)
1036 if (!fChain)
1037 {
1038 TIter Next(fTree->GetListOfBranches());
1039 TBranch *b=0;
1040 while ((b=(TBranch*)Next()))
1041 {
1042 if (b->GetAddress())
1043 {
1044 delete b->GetAddress();
1045 b->ResetAddress();
1046 }
1047 }
1048 }
1049
1050 return GetSelector() ? GetSelector()->CallPostProcess() : kTRUE;
1051}
1052
1053// --------------------------------------------------------------------------
1054//
1055// Get the Event with the current EventNumber fNumEntry
1056//
1057Bool_t MReadTree::GetEvent()
1058{
1059 Bool_t rc = fTree->GetEntry(fNumEntry) != 0; // *CHANGED-fChain-to-fTree*
1060
1061 if (rc)
1062 SetReadyToSave();
1063
1064 return rc;
1065}
1066
1067// --------------------------------------------------------------------------
1068//
1069// Decrease the number of the event which is read by Process() next
1070// by one or more
1071//
1072Bool_t MReadTree::DecEventNum(UInt_t dec)
1073{
1074 if (fNumEntry-dec >= GetEntries())
1075 {
1076 *fLog << warn << GetDescriptor() << ": DecEventNum, WARNING - Event " << fNumEntry << "-";
1077 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range (>=";
1078 *fLog << GetEntries() << ")." << endl;
1079 return kFALSE;
1080 }
1081
1082 fNumEntry -= dec;
1083 return kTRUE;
1084}
1085
1086// --------------------------------------------------------------------------
1087//
1088// Increase the number of the event which is read by Process() next
1089// by one or more
1090//
1091Bool_t MReadTree::IncEventNum(UInt_t inc)
1092{
1093 if (fNumEntry+inc >= GetEntries())
1094 {
1095 *fLog << warn << GetDescriptor() << ": IncEventNum, WARNING - Event " << fNumEntry << "+";
1096 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range (>=";
1097 *fLog << GetEntries() << ")." << endl;
1098 return kFALSE;
1099 }
1100
1101 fNumEntry += inc;
1102 return kTRUE;
1103}
1104
1105// --------------------------------------------------------------------------
1106//
1107// This function makes Process() read event number nr next
1108//
1109// Remark: You can use this function after instatiating you MReadTree-object
1110// to set the event number from which you want to start reading.
1111//
1112Bool_t MReadTree::SetEventNum(UInt_t nr)
1113{
1114 if (nr!=0 && nr >= GetEntries())
1115 {
1116 *fLog << warn << GetDescriptor() << ": SetEventNum, WARNING - " << nr << " out of Range." << endl;
1117 return kFALSE;
1118 }
1119
1120 fNumEntry = nr;
1121 return kTRUE;
1122}
1123
1124// --------------------------------------------------------------------------
1125//
1126// For the branch with the given name:
1127// 1) no object is automatically created
1128// 2) the branch address for this branch is not set
1129// (because we lack the object, see 1)
1130// 3) The whole branch (exactly: all its subbranches) are disabled
1131// this means are not read in memory by TTree:GetEntry
1132//
1133void MReadTree::VetoBranch(const char *name)
1134{
1135 fVetoList->Add(new TNamed(name, ""));
1136}
1137
1138// --------------------------------------------------------------------------
1139//
1140// Return the name of the file we are actually reading from.
1141//
1142TString MReadTree::GetFullFileName() const
1143{
1144 const TFile *file = fChain ? fChain->GetFile() : fTree->GetCurrentFile();
1145
1146 if (!file)
1147 return "<unknown>";
1148
1149 return file->GetName();
1150}
1151
1152// --------------------------------------------------------------------------
1153//
1154// Get number of files in chain. (-1 is returned if chain is not
1155// initialized.
1156//
1157Int_t MReadTree::GetNumFiles() const
1158{
1159 if (!fChain)
1160 return -1;
1161
1162 return fChain->GetListOfFiles()->GetEntries();
1163}
1164
1165// --------------------------------------------------------------------------
1166//
1167// Return the number of the file in the chain, -1 in case of an error
1168//
1169Int_t MReadTree::GetFileIndex() const
1170{
1171 return fChain ? fChain->GetTreeNumber() : 0;
1172 /*
1173 const TString filename = fChain->GetFile()->GetName();
1174
1175 int i=0;
1176 TObject *file = NULL;
1177
1178 TIter Next(fChain->GetListOfFiles());
1179 while ((file=Next()))
1180 {
1181 if (filename==gSystem->ExpandPathName(file->GetTitle()))
1182 return i;
1183 i++;
1184 }
1185 return -1;
1186 */
1187}
1188
1189// --------------------------------------------------------------------------
1190//
1191// This schedules a TObject which Notify(9 function is called in case
1192// of MReadTree (TChain) switches from one file in the chain to another
1193// one.
1194//
1195void MReadTree::AddNotify(TObject *obj)
1196{
1197 fNotify->Add(obj);
1198}
1199
1200void MReadTree::Print(Option_t *o) const
1201{
1202 *fLog << all << underline << GetDescriptor() << ":" << endl << dec;
1203 *fLog << " Files [Tree]:" << endl;
1204
1205 int i = 0;
1206 TIter Next(fChain->GetListOfFiles());
1207 TObject *obj = NULL;
1208 while ((obj=Next()))
1209 *fLog << " " << i++ << ") " << obj->GetTitle() << " [" << obj->GetName() << "]" << endl;
1210
1211 *fLog << " Total Number of Entries: " << fNumEntries << endl;
1212 *fLog << " Next Entry to read: " << fNumEntry << endl;
1213}
1214
1215// --------------------------------------------------------------------------
1216//
1217// Implementation of SavePrimitive. Used to write the call to a constructor
1218// to a macro. In the original root implementation it is used to write
1219// gui elements to a macro-file.
1220//
1221void MReadTree::StreamPrimitive(ostream &out) const
1222{
1223 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
1224 out << fChain->GetName() << "\", \"" << fName << "\", \"" << fTitle << "\");" << endl;
1225
1226 TIter Next(fChain->GetListOfFiles());
1227 TObject *obj = NULL;
1228 while ((obj=Next()))
1229 out << " " << GetUniqueName() << ".AddFile(\"" << obj->GetTitle() << "\");" << endl;
1230
1231 if (!fAutoEnable)
1232 out << " " << GetUniqueName() << ".DisableAutoScheme();" << endl;
1233
1234 if (fNumEntry!=0)
1235 out << " " << GetUniqueName() << ".SetEventNum(" << fNumEntry << ");" << endl;
1236
1237
1238}
Note: See TracBrowser for help on using the repository browser.