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

Last change on this file since 1583 was 1583, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 25.5 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-2002
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#include "MReadTree.h"
52
53#include <fstream.h>
54
55#include <TFile.h> // TFile::GetName
56#include <TSystem.h> // gSystem->ExpandPath
57#include <TGProgressBar.h>
58#include <TChainElement.h>
59#include <TOrdCollection.h>
60
61#include "MChain.h"
62#include "MFilter.h"
63#include "MParList.h"
64#include "MTaskList.h"
65
66#include "MLog.h"
67#include "MLogManip.h"
68
69
70ClassImp(MReadTree);
71
72// --------------------------------------------------------------------------
73//
74// Default constructor. Don't use it.
75//
76MReadTree::MReadTree()
77 : fNumEntry(0), fNumEntries(0), fBranchChoosing(kFALSE), fAutoEnable(kTRUE), fProgress(NULL)
78{
79 fName = "MReadTree";
80 fTitle = "Task to loop over all events in one single tree";
81
82 fVetoList = NULL;
83 fNotify = NULL;
84
85 fChain = NULL;
86}
87
88// --------------------------------------------------------------------------
89//
90// Constructor. It creates an TChain instance which represents the
91// the Tree you want to read and adds the given file (if you gave one).
92// More files can be added using MReadTree::AddFile.
93// Also an empty veto list is created. This list is used if you want to
94// veto (disable or "don't enable") a branch in the tree, it vetos also
95// the creation of the corresponding object.
96// An empty list of TObjects are also created. This objects are called
97// at any time the TChain starts to read from another file.
98//
99MReadTree::MReadTree(const char *tname, const char *fname,
100 const char *name, const char *title)
101 : fNumEntry(0), fNumEntries(0), fBranchChoosing(kFALSE), fAutoEnable(kTRUE), fProgress(NULL)
102{
103 fName = name ? name : "MReadTree";
104 fTitle = title ? title : "Task to loop over all events in one single tree";
105
106 fVetoList = new TList;
107 fVetoList->SetOwner();
108
109 fNotify = new TList;
110
111 //
112 // open the input stream
113 //
114 fChain = new MChain(tname);
115
116 // root 3.02:
117 // In TChain::Addfile remove the limitation that the file name must contain
118 // the string ".root". ".root" is necessary only in case one wants to specify
119 // a Tree in a subdirectory of a Root file with eg, the format:
120
121 if (fname)
122 if (fChain->Add(fname)>0)
123 SetBit(kChainWasChanged);
124}
125
126// --------------------------------------------------------------------------
127//
128// Destructor. It deletes the TChain and veto list object
129//
130MReadTree::~MReadTree()
131{
132 //
133 // Delete all the pointers to pointers to the objects where the
134 // branche data gets stored.
135 //
136 TIter Next(fChain->GetStatus());
137
138 TChainElement *element = NULL;
139 while ((element=(TChainElement*)Next()))
140 delete (MParContainer**)element->GetBaddress();
141
142 //
143 // Delete the chain and the veto list
144 //
145#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,00)
146 if (fChain->GetFile())
147 delete fChain->GetFile();
148#endif
149 delete fChain;
150
151 delete fNotify;
152 delete fVetoList;
153}
154
155// --------------------------------------------------------------------------
156//
157// If the owner flag is set all TObjects which are scheduled via
158// AddNotify are deleted by the destructor of MReadTree
159//
160void MReadTree::SetOwner(Bool_t flag)
161{
162 flag ? fNotify->SetBit(kIsOwner) : fNotify->ResetBit(kIsOwner);
163}
164
165// --------------------------------------------------------------------------
166//
167// This function is called each time MReadTree changes the file to read
168// from. It calls all TObject::Notify() functions which are scheduled
169// via AddNotify.
170//
171Bool_t MReadTree::Notify()
172{
173 *fLog << inf << GetDescriptor() << ": Notify '" << fChain->GetName();
174 *fLog << "' (before processing event #" << GetEventNum()-1 << ")" << endl;
175
176 //fNotify->Notify();
177
178 return kTRUE;
179}
180
181// --------------------------------------------------------------------------
182//
183// If you want to read the given tree over several files you must add
184// the files here before PreProcess is called. Be careful: If the tree
185// doesn't have the same contents (branches) it may confuse your
186// program (trees which are are not existing in later files are not read
187// anymore, tree wich are not existing in the first file are never read)
188//
189// Name may use the wildcarding notation, eg "xxx*.root" means all files
190// starting with xxx in the current file system directory.
191//
192// AddFile returns the number of files added to the chain.
193//
194Int_t MReadTree::AddFile(const char *fname)
195{
196 //
197 // FIXME! A check is missing whether the file already exists or not.
198 //
199 //
200 // returns the number of file which were added
201 //
202
203 const Int_t numfiles = fChain->Add(fname);
204
205 if (numfiles>0)
206 SetBit(kChainWasChanged);
207
208 return numfiles;
209}
210
211// --------------------------------------------------------------------------
212//
213// Adds all files from another MReadTree to this instance
214//
215// Returns the number of file which were added
216//
217Int_t MReadTree::AddFiles(const MReadTree &read)
218{
219 Int_t rc = 0;
220
221 TIter Next(read.fChain->GetListOfFiles());
222 TObject *obj = NULL;
223 while ((obj=Next()))
224 rc += AddFile(obj->GetTitle());
225
226 if (rc>0)
227 SetBit(kChainWasChanged);
228
229 return rc;
230}
231
232// --------------------------------------------------------------------------
233//
234// This function is called if Branch choosing method should get enabled.
235// Branch choosing means, that only the enabled branches are read into
236// memory. To use an enableing scheme we have to disable all branches first.
237// This is done, if this function is called the first time.
238//
239void MReadTree::EnableBranchChoosing()
240{
241 if (fBranchChoosing)
242 return;
243
244 *fLog << inf << GetDescriptor() << ": Branch choosing method enabled (only enabled branches are read)." << endl;
245 fChain->SetBranchStatus("*", kFALSE);
246 fBranchChoosing = kTRUE;
247}
248
249// --------------------------------------------------------------------------
250//
251// The first time this function is called all branches are disabled.
252// The given branch is enabled. By enabling only the branches you
253// are processing you can speed up your calculation many times (up to
254// a factor of 10 or 20)
255//
256void MReadTree::EnableBranch(const char *name)
257{
258 EnableBranchChoosing();
259
260 TNamed branch(name, "");
261 SetBranchStatus(&branch, kTRUE);
262}
263
264// --------------------------------------------------------------------------
265//
266// Set branch status of branch name
267//
268void MReadTree::SetBranchStatus(const char *name, Bool_t status)
269{
270 fChain->SetBranchStatus(name, status);
271
272 *fLog << inf << (status ? "Enabled" : "Disabled");
273 *fLog << " subbranch '" << name << "'." << endl;
274}
275
276// --------------------------------------------------------------------------
277//
278// Checks whether a branch with the given name exists in the chain
279// and sets the branch status of this branch corresponding to status.
280//
281void MReadTree::SetBranchStatus(TObject *branch, Bool_t status)
282{
283 //
284 // Get branch name
285 //
286 const char *name = branch->GetName();
287
288 //
289 // Check whether this branch really exists
290 //
291 if (fChain->GetBranch(name))
292 SetBranchStatus(name, status);
293
294 //
295 // Remove trailing '.' if one and try to enable the subbranch without
296 // the master branch name. This is to be compatible with older mars
297 // and camera files.
298 //
299 const char *dot = strrchr(name, '.');
300 if (!dot)
301 return;
302
303 if (fChain->GetBranch(dot+1))
304 SetBranchStatus(dot+1, status);
305}
306
307// --------------------------------------------------------------------------
308//
309// Set the status of all branches in the list to status.
310//
311void MReadTree::SetBranchStatus(const TList *list, Bool_t status)
312{
313 //
314 // Loop over all subbranches in this master branch
315 //
316 TIter Next(list);
317
318 TObject *obj;
319 while ((obj=Next()))
320 SetBranchStatus(obj, status);
321}
322
323// --------------------------------------------------------------------------
324//
325// This is the implementation of the Auto Enabling Scheme.
326// For more information see MTask::AddBranchToList.
327// This function loops over all tasks and its filters in the tasklist
328// and enables all branches which are requested by the tasks and its
329// filters.
330//
331// To enable 'unknown' branches which are not in the branchlist of
332// the tasks you can call EnableBranch
333//
334void MReadTree::EnableBranches(MParList *plist)
335{
336 //
337 // check whether branch choosing must be switched on
338 //
339 EnableBranchChoosing();
340
341 //
342 // request the tasklist from the parameter list.
343 // FIXME: Tasklist can have a different name
344 //
345 const MTaskList *tlist = (MTaskList*)plist->FindObject("MTaskList");
346 if (!tlist)
347 {
348 *fLog << warn << GetDescriptor() << "Cannot use auto enabeling scheme for branches. 'MTaskList' not found." << endl;
349 return;
350 }
351
352 //
353 // This loop is not necessary. We could do it like in the commented
354 // loop below. But this loop makes sure, that we don't try to enable
355 // one branch several times. This would not harm, but we would get
356 // an output for each attempt. To have several outputs for one subbranch
357 // may confuse the user, this we don't want.
358 // This loop creates a new list of subbranches and for each branch
359 // which is added we check before whether it already exists or not.
360 //
361 TList list;
362
363 MTask *task;
364 TIter NextTask(tlist->GetList());
365 while ((task=(MTask*)NextTask()))
366 {
367 TObject *obj;
368
369 TIter NextTBranch(task->GetListOfBranches());
370 while ((obj=NextTBranch()))
371 if (!list.FindObject(obj->GetName()))
372 list.Add(obj);
373
374 const MFilter *filter = task->GetFilter();
375
376 if (!filter)
377 continue;
378
379 TIter NextFBranch(filter->GetListOfBranches());
380 while ((obj=NextFBranch()))
381 if (!list.FindObject(obj->GetName()))
382 list.Add(obj);
383 }
384
385 SetBranchStatus(&list, kTRUE);
386/*
387 //
388 // Loop over all tasks iand its filters n the task list.
389 //
390 MTask *task;
391 TIter NextTask(tlist->GetList());
392 while ((task=(MTask*)NextTask()))
393 {
394 SetBranchStatus(task->GetListOfBranches(), kTRUE);
395
396 const MFilter *filter = task->GetFilter();
397 if (!filter)
398 continue;
399
400 SetBranchStatus(filter->GetListOfBranches(), kTRUE);
401
402 }
403*/
404}
405
406// --------------------------------------------------------------------------
407//
408// If the chain has been changed (by calling AddFile or using a file
409// in the constructors argument) the number of entries is newly
410// calculated from the files in the chain - this may take a while.
411// The number of entries is returned.
412//
413UInt_t MReadTree::GetEntries()
414{
415 if (TestBit(kChainWasChanged))
416 {
417 fNumEntries = (UInt_t)fChain->GetEntries();
418 ResetBit(kChainWasChanged);
419 }
420 return fNumEntries;
421}
422
423// --------------------------------------------------------------------------
424//
425// The disables all subbranches of the given master branch.
426//
427void MReadTree::DisableSubBranches(TBranch *branch)
428{
429 //
430 // This is not necessary, it would work without. But the output
431 // may confuse the user...
432 //
433 if (fAutoEnable || fBranchChoosing)
434 return;
435
436 SetBranchStatus(branch->GetListOfBranches(), kFALSE);
437}
438
439// --------------------------------------------------------------------------
440//
441// The PreProcess loops (till now) over the branches in the given tree.
442// It checks if the corresponding containers (containers with the same
443// name than the branch name) are existing in the Parameter Container List.
444// If not, a container of objec type 'branch-name' is created (everything
445// after the last semicolon in the branch name is stripped). Only
446// branches which don't have a veto (see VetoBranch) are enabled If the
447// object isn't found in the root dictionary (a list of classes known by the
448// root environment) the branch is skipped and an error message is printed
449// out.
450//
451Bool_t MReadTree::PreProcess(MParList *pList)
452{
453 //
454 // Make sure, that all the following calls doesn't result in
455 // Notifications. This may be dangerous, because the notified
456 // tasks are not preprocessed.
457 //
458 fChain->SetNotify(NULL);
459
460 //
461 // get number of events in this tree
462 //
463 if (!GetEntries())
464 {
465 *fLog << warn << dbginf << "No entries found in file(s)" << endl;
466 return kFALSE;
467 }
468
469 //
470 // output logging information
471 //
472 *fLog << inf << fNumEntries << " entries found in file(s)." << endl;
473
474 //
475 // Get all branches of this tree and
476 // create the Iterator to loop over all branches
477 //
478 TIter Next(fChain->GetListOfBranches());
479 TBranch *branch=NULL;
480
481 Int_t num=0;
482 //
483 // loop over all tasks for processing
484 //
485 while ( (branch=(TBranch*)Next()) )
486 {
487 //
488 // Get Name of Branch and Object
489 //
490 const char *bname = branch->GetName();
491
492 TString oname(bname);
493 if (oname.EndsWith("."))
494 oname.Remove(oname.Length()-1);
495
496 //
497 // Check if enabeling the branch is allowed
498 //
499 if (fVetoList->FindObject(oname))
500 {
501 *fLog << inf << "Master branch " << bname << " has veto... skipped." << endl;
502 DisableSubBranches(branch);
503 continue;
504 }
505
506 //
507 // Create a pointer to the pointer to the object in which the
508 // branch data is stored. The pointers are stored in the TChain
509 // object and we get the pointers from there to delete it.
510 //
511 MParContainer **pcont= new MParContainer*;
512
513#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
514 const char *classname = oname;
515#else
516 const char *classname = branch->GetClassName();
517#endif
518
519 //
520 // check if object is existing in the list
521 //
522 *pcont=pList->FindCreateObj(classname, oname);
523
524 if (!*pcont)
525 {
526 //
527 // if class is not existing in the (root) environment
528 // we cannot proceed reading this branch
529 //
530 *fLog << warn << dbginf << "Warning: Class '" << classname;
531 *fLog << "' for " << oname << " not existing in dictionary. Branch skipped." << endl;
532 DisableSubBranches(branch);
533 continue;
534 }
535
536 //
537 // Check whether a Pointer to a pointer already exists.
538 // If we created one already, delete it.
539 //
540 TChainElement *element = (TChainElement*)fChain->GetStatus()->FindObject(bname);
541 if (element)
542 delete (MParContainer**)element->GetBaddress();
543
544 //
545 // here pcont is a pointer the to container in which the data from
546 // the actual branch should be stored - enable branch.
547 //
548 fChain->SetBranchAddress(bname, pcont);
549
550 *fLog << inf << "Master branch address " << bname << " [";
551 *fLog << classname << "] setup for reading." << endl;
552
553 //*fLog << "Branch " << bname << " autodel: " << (int)branch->IsAutoDelete() << endl;
554 //branch->SetAutoDelete();
555
556 num++;
557 }
558
559 *fLog << inf << GetDescriptor() << " setup " << num << " master branches addresses." << endl;
560
561 //
562 // If auto enabling scheme isn't disabled, do auto enabling
563 //
564 if (fAutoEnable)
565 EnableBranches(pList);
566
567 //
568 // If a progress bar is given set its range.
569 //
570 if (fProgress)
571 fProgress->SetRange(0, fNumEntries);
572
573 //
574 // Now we can start notifying. Reset tree makes sure, that TChain thinks
575 // that the correct file is not yet initialized and reinitilizes it
576 // as soon as the first event is read. This is necessary to call
577 // the notifiers when the first event is read, but after the
578 // PreProcess-function.
579 //
580 fChain->ResetTree();
581 fChain->SetNotify(this);
582
583 return kTRUE;
584}
585
586// --------------------------------------------------------------------------
587//
588// Set the ready to save flag of all containers which branchaddresses are
589// set for. This is necessary to copy data.
590//
591void MReadTree::SetReadyToSave(Bool_t flag)
592{
593 TIter Next(fChain->GetStatus());
594
595 TChainElement *element = NULL;
596 while ((element=(TChainElement*)Next()))
597 {
598 //
599 // Check whether the branch is enabled
600 //
601 if (!element->GetStatus())
602 continue;
603
604 //
605 // Get the pointer to the pointer of the corresponding container
606 //
607 MParContainer **pcont = (MParContainer**)element->GetBaddress();
608
609 //
610 // Check whether the pointer is not NULL
611 //
612 if (!pcont || !*pcont)
613 continue;
614
615 //
616 // Set the ready to save status of the container.
617 //
618 (*pcont)->SetReadyToSave(flag);
619 }
620
621 //
622 // Set the ready to save status of this task (used?), too
623 //
624 MTask::SetReadyToSave(flag);
625}
626
627// --------------------------------------------------------------------------
628//
629// The Process-function reads one event from the tree (this contains all
630// enabled branches) and increases the position in the file by one event.
631// (Remark: The position can also be set by some member functions
632// If the end of the file is reached the Eventloop is stopped.
633//
634#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
635#include "MRawEvtData.h"
636#endif
637Bool_t MReadTree::Process()
638{
639 //
640 // This is necessary due to a bug in TChain::LoadTree in root.
641 // will be fixed in 3.03
642 //
643#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,01)
644 if (fNumEntry >= GetEntries())
645 return kFALSE;
646#endif
647
648#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
649 //
650 // This fixes 99.9% of a memory leak using a root version prior
651 // to 3.02/??
652 //
653 TChainElement *element=NULL;
654 TIter Next(fChain->GetStatus());
655 while ((element=(TChainElement*)Next()))
656 {
657 MParContainer **c = (MParContainer**)element->GetBaddress();
658 if (!c) continue;
659 if ((*c)->InheritsFrom(MRawEvtData::Class()))
660 ((MRawEvtData*)(*c))->DeletePixels(kFALSE);
661
662 }
663#endif
664
665 Bool_t rc = fChain->GetEntry(fNumEntry++) != 0;
666
667 if (rc)
668 SetReadyToSave();
669
670 return rc;
671}
672
673// --------------------------------------------------------------------------
674//
675// Get the Event with the current EventNumber fNumEntry
676//
677Bool_t MReadTree::GetEvent()
678{
679 Bool_t rc = fChain->GetEntry(fNumEntry) != 0;
680
681 if (rc)
682 SetReadyToSave();
683
684 return rc;
685}
686
687// --------------------------------------------------------------------------
688//
689// Decrease the number of the event which is read by Process() next
690// by one or more
691//
692Bool_t MReadTree::DecEventNum(UInt_t dec)
693{
694 if (fNumEntry-dec >= GetEntries())
695 {
696 *fLog << warn << GetDescriptor() << ": DecEventNum, WARNING - Event " << fNumEntry << "-";
697 *fLog << dec << "=" << (Int_t)fNumEntry-dec << " out of Range." << endl;
698 return kFALSE;
699 }
700
701 fNumEntry -= dec;
702 return kTRUE;
703}
704
705// --------------------------------------------------------------------------
706//
707// Increase the number of the event which is read by Process() next
708// by one or more
709//
710Bool_t MReadTree::IncEventNum(UInt_t inc)
711{
712 if (fNumEntry+inc >= GetEntries())
713 {
714 *fLog << warn << GetDescriptor() << ": IncEventNum, WARNING - Event " << fNumEntry << "+";
715 *fLog << inc << "=" << (Int_t)fNumEntry+inc << " out of Range." << endl;
716 return kFALSE;
717 }
718
719 fNumEntry += inc;
720 return kTRUE;
721}
722
723// --------------------------------------------------------------------------
724//
725// This function makes Process() read event number nr next
726//
727// Remark: You can use this function after instatiating you MReadTree-object
728// to set the event number from which you want to start reading.
729//
730Bool_t MReadTree::SetEventNum(UInt_t nr)
731{
732 if (nr >= GetEntries())
733 {
734 *fLog << warn << GetDescriptor() << ": SetEventNum, WARNING - " << nr << " out of Range." << endl;
735 return kFALSE;
736 }
737
738 fNumEntry = nr;
739 return kTRUE;
740}
741
742// --------------------------------------------------------------------------
743//
744// For the branch with the given name:
745// 1) no object is automatically created
746// 2) the branch address for this branch is not set
747// (because we lack the object, see 1)
748// 3) The whole branch (exactly: all its subbranches) are disabled
749// this means are not read in memory by TTree:GetEntry
750//
751void MReadTree::VetoBranch(const char *name)
752{
753 fVetoList->Add(new TNamed(name, ""));
754}
755
756// --------------------------------------------------------------------------
757//
758// Return the name of the file we are actually reading from.
759//
760TString MReadTree::GetFileName() const
761{
762 const TFile *file = fChain->GetFile();
763
764 if (!file)
765 return TString("<unknown>");
766
767 TString name(file->GetName());
768 name.Remove(0, name.Last('/')+1);
769 return name;
770}
771
772// --------------------------------------------------------------------------
773//
774// Return the number of the file in the chain, -1 in case of an error
775//
776Int_t MReadTree::GetFileIndex() const
777{
778 return fChain->GetTreeNumber();
779 /*
780 const TString filename = fChain->GetFile()->GetName();
781
782 int i=0;
783 TObject *file = NULL;
784
785 TIter Next(fChain->GetListOfFiles());
786 while ((file=Next()))
787 {
788 if (filename==gSystem->ExpandPathName(file->GetTitle()))
789 return i;
790 i++;
791 }
792 return -1;
793 */
794}
795
796// --------------------------------------------------------------------------
797//
798// This schedules a TObject which Notify(9 function is called in case
799// of MReadTree (TChain) switches from one file in the chain to another
800// one.
801//
802void MReadTree::AddNotify(TObject *obj)
803{
804 fNotify->Add(obj);
805}
806
807void MReadTree::Print(Option_t *o) const
808{
809 *fLog << all << GetDescriptor() << dec << endl;
810 *fLog << setfill('-') << setw(strlen(GetDescriptor())) << "" << endl;
811 *fLog << " Files [Tree]:" << endl;
812
813 int i = 0;
814 TIter Next(fChain->GetListOfFiles());
815 TObject *obj = NULL;
816 while ((obj=Next()))
817 *fLog << " " << i++ << ") " << obj->GetTitle() << " [" << obj->GetName() << "]" << endl;
818
819 *fLog << " Total Number of Entries: " << fNumEntries << endl;
820 *fLog << " Next Entry to read: " << fNumEntry << endl;
821}
822
823// --------------------------------------------------------------------------
824//
825// Implementation of SavePrimitive. Used to write the call to a constructor
826// to a macro. In the original root implementation it is used to write
827// gui elements to a macro-file.
828//
829void MReadTree::StreamPrimitive(ofstream &out) const
830{
831 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
832 out << fChain->GetName() << "\", \"" << fName << "\", \"" << fTitle << "\");" << endl;
833
834 TIter Next(fChain->GetListOfFiles());
835 TObject *obj = NULL;
836 while ((obj=Next()))
837 out << " " << GetUniqueName() << ".AddFile(\"" << obj->GetTitle() << "\");" << endl;
838
839 if (!fAutoEnable)
840 out << " " << GetUniqueName() << ".DisableAutoScheme();" << endl;
841
842 if (fNumEntry!=0)
843 out << " " << GetUniqueName() << ".SetEventNum(" << fNumEntry << ");" << endl;
844
845
846}
Note: See TracBrowser for help on using the repository browser.