ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/TAM/src/TAMOutput.cxx
Revision: 1.1
Committed: Tue May 27 19:13:21 2008 UTC (16 years, 11 months ago) by loizides
Content type: text/plain
Branch: MAIN
CVS Tags: MITHEP_2_0_x
Log Message:
TAM trunk 5120

File Contents

# User Rev Content
1 loizides 1.1 //
2     // $Id: TAMOutput.cxx 5120 2008-05-07 18:17:33Z loizides $
3     //
4    
5     #include "TAMOutput.h"
6    
7    
8     #ifndef G__API_H
9     #include "Api.h"
10     #endif
11     #ifndef ROOT_Riostream
12     #include "Riostream.h"
13     #endif
14     #ifndef ROOT_RVersion
15     #include "RVersion.h"
16     #endif
17     #ifndef ROOT_TIterator
18     #include "TIterator.h"
19     #endif
20     #ifndef ROOT_TObjArray
21     #include "TObjArray.h"
22     #endif
23     #ifndef ROOT_TError
24     #include "TError.h"
25     #endif
26     #ifndef ROOT_TH1
27     #include "TH1.h"
28     #endif
29     #ifndef ROOT_TROOT
30     #include "TROOT.h"
31     #endif
32     #ifndef ROOT_TDataMember
33     #include "TDataMember.h"
34     #endif
35     #ifndef TAM_TAModule
36     #include "TAModule.h"
37     #endif
38    
39    
40     //////////////////////////////////////////////////////////////////////////
41     // //
42     // TAMOutput //
43     // //
44     // Stores the output objects of a module for use with the Proof //
45     // facility. This object is itself a list of all sub modules output //
46     // objects, so that whatever TAModule hierarchy exists is duplicated in //
47     // the TAMOutput hierarchy. Thus, only the tree of TAMOutput objects //
48     // needs to be streamed in to the master from the worker computers when //
49     // merging output objects in a Proof analsys, and not the complete //
50     // TAModule objects themselves. This is useful since an TAModule object //
51     // is in principal arbitrarily large, and only the list of output //
52     // objects needs to be merged. //
53     // //
54     // This class provides the functionality to merge the list of output //
55     // objects correctly throughout the hierarchy of TAMOutput objects. //
56     // //
57     // The existence of this class is hidden to classes inheritting from //
58     // TAModule. Such end-user modules need only add the desired output //
59     // objects (such as histograms) to their output list by calling //
60     // TAModule::AddOutput(TObject*&). //
61     // //
62     // Author : Corey Reed 07/20/2004 //
63     // //
64     //////////////////////////////////////////////////////////////////////////
65    
66     ClassImp(TAMOutput)
67     ClassImp(TAMOutput::TAMModInspector)
68     ClassImp(TAMOutput::TAMModInspector::TAMModMember)
69    
70    
71     #if ROOT_VERSION_CODE < ROOT_VERSION(5,11,3)
72     #define R__ASSERT(e) \
73     if (!(e)) Fatal("", kAssertMsg, _QUOTE_(e), __LINE__, __FILE__)
74     #endif
75    
76    
77     //______________________________________________________________________________
78     TAMOutput::TAMModInspector::TAMModInspector()
79     {
80     // Default constructor.
81    
82     fOutputMembers.SetOwner(kTRUE);
83     }
84    
85    
86     //______________________________________________________________________________
87     TAMOutput::TAMModInspector::~TAMModInspector()
88     {
89     // Destructor.
90     }
91    
92    
93     //______________________________________________________________________________
94     void TAMOutput::TAMModInspector::AddOutput(TObject* obj, const void* adr)
95     {
96     // Set the title of the TAMModMember for this object to the name of the obj.
97    
98     TAMModMember* mem = FindModMemberWithAddr(adr);
99     if (mem!=0) {
100     mem->SetName(obj->GetName());
101     } // else output object is not (pointed to by) a member of the module
102     }
103    
104    
105     //______________________________________________________________________________
106     void TAMOutput::TAMModInspector::Inspect(TClass* cl, const Char_t* parent,
107     const Char_t* name, const void* addr)
108     {
109     // Set the address of the mod member to addr.
110     // If no mod member yet exists for this member, make it (but with no name).
111    
112     if (cl->InheritsFrom(TAModule::Class())) {
113     TAMModMember* mem = FindModMemberWithMemberName(name);
114     if (mem==0) {
115     if ( (cl!=0) && (name!=0) && (addr!=0) ) {
116     TString fullname(parent);
117     fullname.Append(name);
118     fOutputMembers.Add(new TAMModMember(0, fullname.Data(),
119     const_cast<void*>(addr), cl));
120     } else {
121     ::Error("TAMOutput::TAMModInspector::Inspect",
122     "Can not store TAMModMember with class at %p, "
123     "name=%s, addr=%p",
124     static_cast<void*>(cl),
125     name, static_cast<const void*>(addr));
126     }
127     } else {
128     mem->fAddr = const_cast<void*>(addr);
129     }
130     } // else don't bother; it can't point to an output object
131     }
132    
133    
134     //______________________________________________________________________________
135     void TAMOutput::TAMModInspector::RemoveOutput(TObject* obj)
136     {
137     // Remove the TAMModMember for this object.
138    
139     TAMModMember* mem = dynamic_cast<TAMModMember*>(
140     fOutputMembers.FindObject(obj->GetName()));
141     if (mem!=0) {
142     fOutputMembers.Remove(mem);
143     }
144     }
145    
146    
147     //______________________________________________________________________________
148     TAMOutput::TAMModInspector::TAMModMember*
149     TAMOutput::TAMModInspector::FindModMemberWithAddr(const void* addr)
150     {
151     // Find the mod member that has the specified address
152    
153     TIter nextmem(fOutputMembers.MakeIterator());
154     TAMModMember* mem=0;
155     while ( (mem = dynamic_cast<TAMModMember*>(nextmem())) ) {
156     if (mem->fAddr == addr) return mem;
157     }
158     return 0;
159     }
160    
161    
162     //______________________________________________________________________________
163     TAMOutput::TAMModInspector::TAMModMember*
164     TAMOutput::TAMModInspector::FindModMemberWithMemberName(const Char_t* mn)
165     {
166     // Find the mod member that has the specified member name.
167    
168     TIter nextmem(fOutputMembers.MakeIterator());
169     TString memname(mn);
170     TAMModMember* mem=0;
171     while ( (mem = dynamic_cast<TAMModMember*>(nextmem())) ) {
172     if (memname.CompareTo(mem->GetTitle())==0) return mem;
173     }
174     return 0;
175     }
176    
177    
178     //______________________________________________________________________________
179     void TAMOutput::TAMModInspector::SetMemberAddrFor(TObject* obj,
180     const UInt_t verbose)
181     {
182     // Find the specified module's member for the specified object
183     // and make the member point to the specified object.
184     // If the member is not a pointer, does nothing.
185    
186     if (obj!=0) {
187     TAMModMember* mem = dynamic_cast<TAMModMember*>(
188     fOutputMembers.FindObject(obj->GetName()));
189     if (mem!=0) {
190     // it's silly, but mem->fMClass comes from IsA(), which does
191     // not "load" the class, so the data member list is empty.
192     TClass* cl = TClass::GetClass(mem->fMClass->GetName());
193     if (cl!=0) {
194     // test if the module's member is actually a pointer to a class
195     // (as opposed to an array of pointers,
196     // an instance of the class, etc.)
197     TDataMember* dm = cl->GetDataMember(mem->GetTitle());
198     if (dm!=0) {
199     TString memberString(dm->GetTypeName());
200     memberString += "*";
201     if (memberString.CompareTo(dm->GetFullTypeName())==0) {
202     void*& modobj = *(static_cast<void**>(mem->fAddr));
203     if (modobj!=obj) {
204     if (modobj!=0) {
205     ::Warning("TAMOutput::TAMModInspector::"
206     "SetMemberAddrFor",
207     "Module pointer [%s] is pointing to "
208     "non-zero address "
209     "%p. Setting it to point to "
210     "output object [%s] at %p. "
211     "Possible memory leak/stomp.",
212     mem->GetTitle(),
213     static_cast<void*>(modobj),
214     obj->GetName(),
215     static_cast<void*>(obj));
216     }
217     modobj = obj;
218     } // else it's already pointing to the right place
219     } else {
220     // not a pointer to a class
221     if (verbose>9) {
222     ::Warning("TAMOutput::TAMModInspector::"
223     "SetMemberAddrFor",
224     "Module member [%s] is of type "
225     "[%s], not a pointer "
226     "to a class (inheriting from TObject). "
227     "Could not "
228     "automatically make this member "
229     "point to [%s] "
230     "from the output list.\n"
231     "Set verbosity below 10 to "
232     "remove this message.",
233     mem->GetTitle(), dm->GetFullTypeName(),
234     obj->GetName());
235     }
236     }
237     } else {
238     ::Error("TAMOutput::TAMModInspector::SetMemberAddrFor",
239     "Could not get data member (%p) [%s] of module [%s]. "
240     "Could not set member address for object [%s].",
241     static_cast<void*>(dm),
242     mem->GetTitle(), mem->fMClass->GetName(),
243     obj->GetName());
244     }
245     } else {
246     ::Error("TAMOutput::TAMModInspector::SetMemberAddrFor",
247     "No class info for the module. "
248     "Can not set member address for [%s].",
249     obj->GetName());
250     }
251     } // else output object is not (pointed to by) a member of the module
252     } else {
253     ::Error("TAMOutput::TAMModInspector::SetMemberAddrFor",
254     "Can not set member address for null object.");
255     }
256     }
257    
258    
259     //______________________________________________________________________________
260     void TAMOutput::TAMModInspector::Streamer(TBuffer &R__b)
261     {
262     // Stream an object of class TAMOutput::TAMModInspector.
263    
264     //This works around a msvc bug and should be harmless on other platforms
265     typedef TAMOutput::TAMModInspector thisClass;
266     UInt_t R__s, R__c;
267     if (R__b.IsReading()) {
268     Version_t R__v = R__b.ReadVersion(&R__s, &R__c); if (R__v) { }
269     fOutputMembers.Streamer(R__b);
270     R__b.CheckByteCount(R__s, R__c, thisClass::IsA());
271     } else {
272     R__c = R__b.WriteVersion(thisClass::IsA(), kTRUE);
273     fOutputMembers.Streamer(R__b);
274     R__b.SetByteCount(R__c, kTRUE);
275     }
276     }
277    
278    
279     //______________________________________________________________________________
280     TAMOutput::TAMOutput() :
281     fMod(0)
282     {
283     // Default constructor.
284    
285     SetOwner(kTRUE);
286     fOutput.SetOwner(kFALSE);
287     }
288    
289    
290     //______________________________________________________________________________
291     TAMOutput::TAMOutput(TAModule* mod) :
292     fMod(mod)
293     {
294     // Normal constructor.
295    
296     SetOwner(kTRUE);
297     fOutput.SetOwner(kFALSE);
298     fCurOutput.SetOwner(kFALSE);
299     if (mod!=0) SetName(mod->GetName());
300     }
301    
302    
303     //______________________________________________________________________________
304     TAMOutput::~TAMOutput()
305     {
306     // Destructor.
307     }
308    
309    
310     //______________________________________________________________________________
311     void TAMOutput::Browse(TBrowser* b)
312     {
313     // Browse the output of this module
314    
315     fOutput.Browse(b);
316     TList::Browse(b);
317     }
318    
319    
320     //______________________________________________________________________________
321     void TAMOutput::CallMerge(TObject* obj, TList& list)
322     {
323     // Uses CINT to call merge on 'obj' given a list of all the
324     // objects from the worker computers that correspond to 'obj'.
325     // If no merge function exists for 'obj', it simply adds all the
326     // objects in list to the output list of this module.
327     // To be called only by MergeOutput(TCollection*)
328    
329     R__ASSERT(obj);
330    
331     Long_t offset=0;
332     G__ClassInfo ci(obj->ClassName());
333     G__CallFunc cf;
334    
335     if (ci.IsValid()) {
336     cf.SetFuncProto(&ci, "Merge", "TCollection*", &offset);
337     }
338     if (cf.IsValid()) {
339     cf.SetArg((Long_t)&list);
340     cf.Exec(obj);
341     } else {
342     // No Merge interface, return individual objects
343     TObject* obj=0;
344     while ( (obj = list.First()) ) {
345     fCurOutput.Add(obj);
346     list.Remove(obj);
347     }
348     }
349     }
350    
351    
352     //______________________________________________________________________________
353     void TAMOutput::CheckHistDir(TObject* obj)
354     {
355     // If obj is a histogram, set directory to null.
356    
357     if (obj->InheritsFrom(TH1::Class())) {
358     TH1* hist = dynamic_cast<TH1*>(obj);
359     if (hist!=0) hist->SetDirectory(0);
360     }
361     }
362    
363    
364     //______________________________________________________________________________
365     void TAMOutput::DeleteIterators(vector<TIterator*>& iters) {
366     // Deletes each iterator in the vector.
367    
368     vector<TIterator*>::const_iterator send = iters.end();
369     for (vector<TIterator*>::iterator siter = iters.begin();
370     siter!=send; siter++) {
371     delete (*siter);
372     }
373     }
374    
375    
376     //______________________________________________________________________________
377     TAMOutput* TAMOutput::FindModOutput(const TAModule* mod)
378     {
379     // Finds the TAMOutput object associated with the specified TAModule
380     // (either being this one, or one of its sub modules).
381     // Returns 0 if no such TAMOutput object is found.
382    
383     if (fMod==mod) {
384     return this;
385     } else {
386     TIter nextModOutput(MakeIterator());
387     TAMOutput* out=0, * tout=0;
388     while ( (out = dynamic_cast<TAMOutput*>(nextModOutput())) ) {
389     tout = out->FindModOutput(mod);
390     if (tout!=0) return tout;
391     }
392     }
393     return 0;
394     }
395    
396    
397     //______________________________________________________________________________
398     TAMOutput* TAMOutput::FindModOutput(const Char_t* name)
399     {
400     // Finds the (first) TAMOutput object with the specified name
401     // (either being this one, or one of its sub modules)
402     // Returns 0 if no such TAMOutput object is found.
403     TString nm(name);
404     if (nm.CompareTo(GetName())==0) {
405     return this;
406     } else {
407     TIter nextModOutput(MakeIterator());
408     TAMOutput* out=0, * tout=0;
409     while ( (out = dynamic_cast<TAMOutput*>(nextModOutput())) ) {
410     tout = out->FindModOutput(name);
411     if (tout!=0) return tout;
412     }
413     }
414     return 0;
415     }
416    
417    
418     //______________________________________________________________________________
419     TObject* TAMOutput::FindOutput(const Char_t* obj)
420     {
421     // Finds the object with the specified name in the list of output objects
422     // of this module.
423     // First check the saved output, then check the output for this current
424     // processing.
425    
426     TObject* fobj = fOutput.FindObject(obj);
427     if (fobj==0) {
428     fobj = fCurOutput.FindObject(obj);
429     }
430     return fobj;
431     }
432    
433    
434     //______________________________________________________________________________
435     TObject* TAMOutput::FindOutput(const TObject* obj)
436     {
437     // Finds the specified object in the list of output objects of this module.
438     // First check the saved output, then check the output for this current
439     // processing.
440    
441     TObject* fobj = fOutput.FindObject(obj);
442     if (fobj==0) {
443     fobj = fCurOutput.FindObject(obj);
444     }
445     return fobj;
446    
447     }
448    
449    
450     //______________________________________________________________________________
451     TObject* TAMOutput::FindOutput(const Char_t* module, const Char_t* obj) {
452     // Finds the specified object from the output of the specified module
453     // Note: "module" must be either this module, or a submodule of this module
454     // First check the saved output, then check the output for this current
455     // processing.
456    
457     TAMOutput* outmod = FindModOutput(module);
458     if (outmod!=0) {
459     TObject* outp = outmod->FindOutput(obj);
460     if (outp==0) {
461     Warning("FindOutput",
462     "Could not find output named [%s] in module [%s].",
463     obj, outmod->GetName());
464     }
465     return outp;
466     } else {
467     Warning("FindOutput","Could not find (sub)module with name [%s].",
468     module);
469     }
470     return 0;
471     }
472    
473    
474     //______________________________________________________________________________
475     void TAMOutput::ls(Option_t* option) const
476     {
477     // List the output objects inside this module and its submodules.
478    
479     TROOT::IndentLevel();
480     cout << "Output of " << GetName() << ":" << endl;
481    
482     fOutput.ls(option);
483    
484     TROOT::IncreaseDirLevel();
485     TList::ls(option);
486     TROOT::DecreaseDirLevel();
487     }
488    
489    
490     //______________________________________________________________________________
491     void TAMOutput::Merge(TCollection* list)
492     {
493     // Called by Proof after SlaveTerminate() and before Terminate()
494     // to merge the output objects from each worker ("slave") computer.
495     // First merge the actual output objects from this module, then
496     // recursively proceed through the sub modules to merge their objects.
497    
498     // merge this module's output objects
499     MergeOutput(list);
500    
501     // then merge its sub modules' objects:
502     if (!IsEmpty()) { // (if we have any sub modules)
503     TAMOutput* out=0, * tout=0;
504     // for each slave, get an iterator over sub modules
505     // can't use any TCollection since TIterators are not TObjects
506     vector<TIterator*> slaveIters;
507     TIter nextSlave(list);
508     while ( (tout = dynamic_cast<TAMOutput*>(nextSlave())) ) {
509     slaveIters.push_back(tout->MakeIterator());
510     }
511    
512     // loop over sub modules
513     TIter nextModOutput(MakeIterator());
514     while ( (out = dynamic_cast<TAMOutput*>(nextModOutput())) ) {
515     // make a list of sub modules from each slave
516     TObjArray subList(list->GetSize());
517    
518     vector<TIterator*>::const_iterator send = slaveIters.end();
519     for (vector<TIterator*>::iterator siter = slaveIters.begin();
520     siter!=send; siter++) {
521     // add the object corresponding to 'out' from each slave
522     subList.Add((*siter)->Next());
523     }
524     // merge the list of sub modules
525     out->Merge(&subList);
526     }
527    
528     // cleanup
529     DeleteIterators(slaveIters);
530     }
531    
532     }
533    
534    
535     //______________________________________________________________________________
536     void TAMOutput::MergeOutput(TCollection* list)
537     {
538     // Merges the actual output objects in fCurOutput given a list of
539     // all the TAMOutput objects from the worker computers that
540     // correspond to this one.
541     // To be called only by Merge(TCollection*)
542    
543     if (!(fCurOutput.IsEmpty())) { // (if there are any output objects)
544     TAMOutput* tout=0;
545     // for each slave, get an iterator over the fCurOutput list
546     // can't use any TCollection since TIterators are not TObjects
547     vector<TIterator*> slaveIters;
548     TIter nextSlave(list);
549     while ( (tout = dynamic_cast<TAMOutput*>(nextSlave())) ) {
550     slaveIters.push_back(tout->GetCurOutputList()->MakeIterator());
551     }
552    
553     // loop over fCurOutput
554     TIter nextOutputObj(fCurOutput.MakeIterator());
555     TObject* outObj=0;
556     while ( (outObj = nextOutputObj()) ) {
557     // make a list of 'outObj' from each slave
558     TList objsToMerge;
559    
560     vector<TIterator*>::const_iterator send = slaveIters.end();
561     for (vector<TIterator*>::iterator siter = slaveIters.begin();
562     siter!=send; siter++) {
563     // add the object corresponding to 'outObj' from each slave
564     objsToMerge.AddLast((*siter)->Next());
565     }
566     // merge 'outObj'
567     CallMerge(outObj, objsToMerge);
568     }
569    
570     // cleanup
571     DeleteIterators(slaveIters);
572     }
573    
574     }
575    
576    
577     //______________________________________________________________________________
578     void TAMOutput::NullClassFor(void* adr, const Char_t* tid) const
579     {
580     // Print warning that the class for the pointer sent to AddOutput() is not
581     // in the ROOT class dictionary.
582    
583     Error("AddOutput",
584     "(%s): Could not get class info for object at %p with typeid %s.",
585     GetName(), adr, tid);
586     }
587    
588    
589     //______________________________________________________________________________
590     void TAMOutput::NullObjInAddOutput() const
591     {
592     // Print warning that a null pointer was sent to AddOutput().
593     Error("AddOutput",
594     "(%s): Can not add null object to output.", GetName());
595     }
596    
597    
598     //______________________________________________________________________________
599     void TAMOutput::Print(Option_t *wildcard) const
600     {
601     // Print the output objects inside this module and its submodules.
602    
603     TROOT::IndentLevel();
604     cout << "Output of " << GetName() << ":" << endl;
605    
606     fOutput.Print(wildcard);
607    
608     TROOT::IncreaseDirLevel();
609     TList::Print(wildcard);
610     TROOT::DecreaseDirLevel();
611     }
612    
613    
614     //______________________________________________________________________________
615     void TAMOutput::Print(Option_t* wildcard, Option_t* option) const
616     {
617     // Print the output objects inside this module and its submodules.
618    
619     #if ROOT_VERSION_CODE > ROOT_VERSION(4,0,8)
620     cout << "Output of " << GetName() << ":" << endl;
621     fOutput.Print(wildcard,option);
622     TList::Print(wildcard,option);
623     #else
624     // backward compatible
625     Warning("Print","This version of Root does not handle wildcards.");
626     Print(option);
627     #endif
628     }
629    
630    
631     //______________________________________________________________________________
632     void TAMOutput::RemoveOutput(TObject* obj)
633     {
634     // Removes the object from the list of output objects of this module.
635    
636     fInspector.RemoveOutput(obj);
637     fOutput.Remove(obj);
638     fCurOutput.Remove(obj);
639     }
640    
641    
642     //______________________________________________________________________________
643     void TAMOutput::SetAllOutputMembers(const Bool_t setAddresses) {
644     // Recursively set the module's output members.
645     // If setAddresses is true, make them point to the output objects.
646    
647     SetOutputMembers(setAddresses);
648    
649     TIter nextout(MakeIterator());
650     TAMOutput* out=0;
651     while ( (out = dynamic_cast<TAMOutput*>(nextout())) ) {
652     out->SetAllOutputMembers(setAddresses);
653     }
654     }
655    
656    
657     //______________________________________________________________________________
658     void TAMOutput::SetOutputMembers(const Bool_t setAddresses)
659     {
660     // Det the module's output members.
661     // If setAddresses is true, make them point to the output objects.
662    
663     R__ASSERT(fMod!=0);
664    
665     // first update the addresses of the members
666     Char_t parent[kParentStrLen];
667     memset(parent, 0, kParentStrLen * sizeof(Char_t));
668     fMod->ShowMembers(fInspector, parent);
669    
670     if (setAddresses) {
671     // loop through output objects and set the corresponding members
672     TIter nextout(fCurOutput.MakeIterator());
673     TObject* obj=0;
674     while ( (obj = nextout()) ) {
675     fInspector.SetMemberAddrFor(obj, fMod->GetVerbosity());
676     }
677     }
678     }
679    
680    
681     //______________________________________________________________________________
682     void TAMOutput::StoreAllOutputObjs()
683     {
684     // Recursively set move output objects from fCutOutput to fOutput
685     // to be called after Merge, but before Terminate.
686     // To be called only by TAModule.
687    
688     StoreOutputObjs();
689    
690     TIter nextout(MakeIterator());
691     TAMOutput* out=0;
692     while ( (out = dynamic_cast<TAMOutput*>(nextout())) ) {
693     out->StoreAllOutputObjs();
694     }
695     }
696    
697    
698     //______________________________________________________________________________
699     void TAMOutput::StoreOutputObjs()
700     {
701     // Iterate over fCurOutput and move the objects to fOutput
702     // to be called after Merge, but before Terminate.
703     // To be called only by StoreAllOutputObjs.
704    
705     if (fCurOutput.IsEmpty()==kFALSE) { // (if there are any output objects)
706     // loop over fCurOutput
707     TIter nextOutputObj(fCurOutput.MakeIterator());
708     TObject* outObj=0;
709     while ( (outObj = nextOutputObj()) ) {
710     fOutput.Add(outObj);
711     }
712     fCurOutput.Clear("nodelete");
713     }
714     }
715    
716    
717     //______________________________________________________________________________
718     void TAMOutput::WarnNameDuplicate(const TObject* obj) const
719     {
720     // Print warning that the output list already contains an object with
721     // the same name.
722    
723     Warning("AddOutput",
724     "(%s): Output list already contains object with name [%s]. "
725     "Adding object at %p with duplicate name.",
726     GetName(),
727     (obj!=0) ? obj->GetName() : "",
728     static_cast<const void*>(obj));
729     }
730    
731    
732     #if ROOT_VERSION_CODE > ROOT_VERSION(4,0,8)
733     //______________________________________________________________________________
734     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize)
735     {
736     // For this (newer) root version, put the code in the const function.
737     // Wow this is ugly.. but it's backward compatible!
738    
739     return (static_cast<const TAMOutput*>(this))->Write(name,option,bsize);
740     }
741    
742     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize) const
743     #else
744     //______________________________________________________________________________
745     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize) const
746     {
747     // For older root, put the code in the non-const function (so TList::Write
748     // can be called).
749     // Wow this is ugly.. but it's backward compatible!
750    
751     return (const_cast<TAMOutput*>(this))->Write(name,option,bsize);
752     }
753    
754     //______________________________________________________________________________
755     Int_t TAMOutput::Write(const char* name, Int_t option, Int_t bsize)
756     #endif
757     {
758     // Write all output objects.
759     // Default behavior is to go through this module and all sub modules and
760     // write all the output objects, flattening the module hierarchy.
761     // If the 'TObject::kSingleKey' option is specified, the TAMOutput
762     // objects themselves will be written, thus preserving the module hierarchy.
763    
764     if ( (option & TObject::kSingleKey) ) {
765     // here, the TList write will work just fine since it will actually
766     // call the streamer on the module output objects
767     // (through TObject::Write)
768     return TList::Write(name, option, bsize);
769     } else {
770     // flatten the module hierarchy and dump all output objects to the file
771     Int_t nbytes = 0;
772     fOutput.Write(name, option, bsize);
773     TIter nextMod(MakeIterator());
774     TObject* obj=0;
775     while ( (obj = nextMod()) ) {
776     nbytes += obj->Write(name, option, bsize);
777     }
778     return nbytes;
779     }
780     }
781