ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/MitAna/TAM/src/TAMOutput.cxx
Revision: 1.9
Committed: Fri May 18 18:34:54 2012 UTC (12 years, 11 months ago) by bendavid
Content type: text/plain
Branch: MAIN
CVS Tags: Mit_032, Mit_031, Mit_030, Mit_029c, Mit_029b, Mit_030_pre1, Mit_029a, Mit_029, Mit_029_pre1, Mit_028a, HEAD
Changes since 1.8: +7 -3 lines
Log Message:
handle trees written to temp files during event loop

File Contents

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