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

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