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

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