source: trunk/MagicSoft/Mars/mbase/MParContainer.cc@ 3872

Last change on this file since 3872 was 3666, checked in by tbretz, 20 years ago
*** empty log message ***
File size: 20.2 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-2004
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MParContainer
28//
29// The MParContainer class is the base class for all MARS parameter
30// containers. At the moment it is almost the same than ROOT's TNamed.
31// A TNamed contains the essential elements (name, title)
32// to identify a derived object in lists like our MParList or MTaskList.
33// The main difference is that the name and title isn't stored and read
34// to and from root files ("//!")
35//
36// MParContainer has several enhancements compared to TNamed:
37// - GetDescriptor(): returns name and class type
38// - GetUniqueName(): returns a unique name (used in StreamPrimitive)
39// - SetLogStream(MLog *lg): Set a logging stream to which loggingis stored
40// - Reset(): Reset content of class in an eventloop
41// - IsReadyToSave(): The contents are ready to be saved to a file
42// - IsSavedAsPrimitive(): A unique name for this instance is already
43// existing
44// - SetVariables(): Can be overloaded if the containers stores
45// coefficients (to be used in fits)
46// - SetDisplay(): Set a display for redirecting graphical output
47// - GetNames(): Get Name/Title from instance and store it in
48// a TObjArray (used to store the names of the
49// conteiners in a file
50// - SetNames(): vice versa
51// - ReadEnv(), WriteEnv(): Function which is used for automatical setup
52// IsEnvDefined() from a TEnv file
53//
54//////////////////////////////////////////////////////////////////////////////
55#include "MParContainer.h"
56
57#include <ctype.h> // isdigit
58#include <fstream> // ofstream, AsciiWrite
59
60#include <TEnv.h> // Env::Lookup
61#include <TClass.h> // IsA
62#include <TObjArray.h> // TObjArray
63#include <TBaseClass.h> // GetClassPointer
64#include <TMethodCall.h> // TMethodCall, AsciiWrite
65#include <TDataMember.h> // TDataMember, AsciiWrite
66#include <TVirtualPad.h> // gPad
67
68#include "MLog.h"
69#include "MLogManip.h"
70
71TList *gListOfPrimitives; // forard declaration in MParContainer.h
72
73#undef DEBUG
74//#define DEBUG
75
76ClassImp(MParContainer);
77
78using namespace std;
79
80MParContainer::MParContainer(const char *name, const char *title) :
81 fName(name), fTitle(title), fLog(&gLog), fDisplay(NULL), fReadyToSave(kFALSE)
82{
83}
84
85MParContainer::MParContainer(const TString &name, const TString &title) :
86 fName(name), fTitle(title), fLog(&gLog), fDisplay(NULL), fReadyToSave(kFALSE)
87{
88}
89
90// --------------------------------------------------------------------------
91//
92// MParContainer copy ctor
93//
94MParContainer::MParContainer(const MParContainer &named)
95{
96 fName = named.fName;
97 fTitle = named.fTitle;
98
99 fLog = named.fLog;
100
101 fReadyToSave = named.fReadyToSave;
102
103 fDisplay = named.fDisplay;
104}
105
106MParContainer::~MParContainer()
107{
108#ifdef DEBUG
109 *fLog << all << "Deleting " << GetDescriptor() << endl;
110#endif
111}
112
113// --------------------------------------------------------------------------
114//
115// MParContainer assignment operator.
116//
117MParContainer& MParContainer::operator=(const MParContainer& rhs)
118{
119 if (this == &rhs)
120 return *this;
121
122 TObject::operator=(rhs);
123
124 fName = rhs.fName;
125 fTitle = rhs.fTitle;
126
127 fLog = rhs.fLog;
128 fReadyToSave = rhs.fReadyToSave;
129
130 return *this;
131}
132
133// --------------------------------------------------------------------------
134//
135// Make a clone of an object using the Streamer facility.
136// If newname is specified, this will be the name of the new object
137//
138TObject *MParContainer::Clone(const char *newname) const
139{
140
141 MParContainer *named = (MParContainer*)TObject::Clone();
142 if (newname && strlen(newname)) named->SetName(newname);
143 return named;
144}
145
146// --------------------------------------------------------------------------
147//
148// Compare two MParContainer objects. Returns 0 when equal, -1 when this is
149// smaller and +1 when bigger (like strcmp).
150//
151Int_t MParContainer::Compare(const TObject *obj) const
152{
153 if (this == obj) return 0;
154 return fName.CompareTo(obj->GetName());
155}
156
157// --------------------------------------------------------------------------
158//
159// Copy this to obj.
160//
161void MParContainer::Copy(TObject &obj)
162#if ROOT_VERSION_CODE > ROOT_VERSION(3,04,01)
163const
164#endif
165{
166 MParContainer &cont = (MParContainer&)obj;
167
168 TObject::Copy(obj);
169
170 cont.fName = fName;
171 cont.fTitle = fTitle;
172
173 cont.fLog = fLog;
174 cont.fReadyToSave = fReadyToSave;
175}
176
177// --------------------------------------------------------------------------
178//
179// Encode MParContainer into output buffer.
180//
181void MParContainer::FillBuffer(char *&buffer)
182{
183 fName.FillBuffer(buffer);
184 fTitle.FillBuffer(buffer);
185}
186
187// --------------------------------------------------------------------------
188//
189// Returns the name of the object. If the name of the object is not the
190// class name it returns the object name and in []-brackets the class name.
191//
192const char *MParContainer::GetDescriptor() const
193{
194 //
195 // Because it returns a (const char*) we cannot return a casted
196 // local TString. The pointer would - immediatly after return -
197 // point to a random memory segment, because the TString has gone.
198 //
199 return fName==ClassName() ? ClassName() : Form("%s [%s]", fName.Data(), ClassName());
200}
201
202// --------------------------------------------------------------------------
203//
204// Return a unique name for this container. It is created from
205// the container name and the unique Id. (This is mostly used
206// in the StreamPrimitive member functions)
207//
208const TString MParContainer::GetUniqueName() const
209{
210 TString ret = ToLower(fName);
211
212 if (isdigit(ret[ret.Length()-1]))
213 ret+="_";
214
215 ret+=GetUniqueID();
216
217 return ret;
218}
219
220// --------------------------------------------------------------------------
221//
222// List MParContainer name and title.
223//
224void MParContainer::ls(Option_t *) const
225{
226 TROOT::IndentLevel();
227 *fLog << all << GetDescriptor() << " " << GetTitle() << ": kCanDelete=";
228 *fLog << Int_t(TestBit(kCanDelete)) << endl;
229}
230
231// --------------------------------------------------------------------------
232//
233// Print MParContainer name and title.
234//
235void MParContainer::Print(Option_t *) const
236{
237 *fLog << all << GetDescriptor() << " " << GetTitle() << endl;
238}
239
240// --------------------------------------------------------------------------
241//
242// Change (i.e. set) the name of the MParContainer.
243// WARNING !!
244// If the object is a member of a THashTable, THashList container
245// The HashTable must be Rehashed after SetName
246// For example the list of objects in the current directory is a THashList
247//
248void MParContainer::SetName(const char *name)
249{
250 fName = name;
251 ResetBit(kIsSavedAsPrimitive);
252 if (gPad && TestBit(kMustCleanup)) gPad->Modified();
253}
254
255// --------------------------------------------------------------------------
256//
257// Change (i.e. set) all the MParContainer parameters (name and title).
258// See also WARNING in SetName
259//
260void MParContainer::SetObject(const char *name, const char *title)
261{
262 fName = name;
263 fTitle = title;
264 ResetBit(kIsSavedAsPrimitive);
265 if (gPad && TestBit(kMustCleanup)) gPad->Modified();
266}
267
268// --------------------------------------------------------------------------
269//
270// Change (i.e. set) the title of the MParContainer.
271//
272void MParContainer::SetTitle(const char *title)
273{
274 fTitle = title;
275 ResetBit(kIsSavedAsPrimitive);
276 if (gPad && TestBit(kMustCleanup)) gPad->Modified();
277}
278
279// --------------------------------------------------------------------------
280//
281// Return size of the MParContainer part of the TObject.
282//
283Int_t MParContainer::Sizeof() const
284{
285 Int_t nbytes = fName.Sizeof() + fTitle.Sizeof();
286 return nbytes;
287}
288
289// --------------------------------------------------------------------------
290//
291// If you want to use Ascii-Input/-Output (eg. MWriteAsciiFile) of a
292// container, overload this function.
293//
294void MParContainer::AsciiRead(ifstream &fin)
295{
296 *fLog << warn << "To use the the ascii input of " << GetName();
297 *fLog << " you have to overload " << ClassName() << "::AsciiRead." << endl;
298}
299
300// --------------------------------------------------------------------------
301//
302// Write out a data member given as a TDataMember object to an output stream.
303//
304Bool_t MParContainer::WriteDataMember(ostream &out, const TDataMember *member, Double_t scale) const
305{
306 if (!member)
307 return kFALSE;
308
309 if (!member->IsPersistent() || member->Property()&kIsStatic)
310 return kFALSE;
311
312 /*const*/ TMethodCall *call = ((TDataMember*)member)->GetterMethod(); //FIXME: Root
313 if (!call)
314 {
315 *fLog << warn << "Sorry, no getter method found for " << member->GetName() << endl;
316 return kFALSE;
317 }
318
319 // For debugging: out << member->GetName() << ":";
320
321 switch (call->ReturnType())
322 {
323 case TMethodCall::kLong:
324 Long_t l;
325 call->Execute((void*)this, l); // FIXME: const, root
326 out << l << " ";
327 return kTRUE;
328
329 case TMethodCall::kDouble:
330 Double_t d;
331 call->Execute((void*)this, d); // FIXME: const, root
332 out << (scale*d) << " ";
333 return kTRUE;
334
335 default:
336 //case TMethodCall::kString:
337 //case TMethodCall::kOther:
338 /* someone may want to enhance this? */
339 return kFALSE;
340 }
341}
342
343// --------------------------------------------------------------------------
344//
345// Write out a data member given by name to an output stream.
346//
347Bool_t MParContainer::WriteDataMember(ostream &out, const char *member, Double_t scale) const
348{
349 /*const*/ TClass *cls = IsA()->GetBaseDataMember(member);
350 if (!cls)
351 return kFALSE;
352
353 return WriteDataMember(out, cls->GetDataMember(member), scale);
354}
355
356// --------------------------------------------------------------------------
357//
358// Write out a data member from a given TList of TDataMembers.
359// returns kTRUE when at least one member was successfully written
360//
361Bool_t MParContainer::WriteDataMember(ostream &out, const TList *list) const
362{
363 Bool_t rc = kFALSE;
364
365 TDataMember *data = NULL;
366
367 TIter Next(list);
368 while ((data=(TDataMember*)Next()))
369 rc |= WriteDataMember(out, data);
370
371 return rc;
372}
373
374// --------------------------------------------------------------------------
375//
376// If you want to use Ascii-Input/-Output (eg. MWriteAsciiFile) of a
377// container, you may overload this function. If you don't overload it
378// the data member of a class are written to the file in the order of
379// appearance in the class header (be more specfic: root dictionary)
380// Only data members which are of integer (Bool_t, Int_t, ...) or
381// floating point (Float_t, Double_t, ...) type are written.
382// returns kTRUE when at least one member was successfully written
383//
384Bool_t MParContainer::AsciiWrite(ostream &out) const
385{
386 // *fLog << warn << "To use the the ascii output of " << GetName();
387 // *fLog << " you have to overload " << ClassName() << "::AsciiWrite." << endl;
388
389 Bool_t rc = WriteDataMember(out, IsA()->GetListOfDataMembers());
390
391 TIter NextBaseClass(IsA()->GetListOfBases());
392 TBaseClass *base;
393 while ((base = (TBaseClass*) NextBaseClass()))
394 {
395 /*const*/ TClass *cls = base->GetClassPointer();
396
397 if (!cls)
398 continue;
399
400 if (cls->GetClassVersion())
401 rc |= WriteDataMember(out, cls->GetListOfDataMembers());
402 }
403
404 return rc;
405}
406
407TMethodCall *MParContainer::GetterMethod(const char *name) const
408{
409 const TString n(name);
410 const Int_t pos1 = n.First('.');
411
412 const TString part1 = pos1<0 ? n : n(0, pos1);
413 const TString part2 = pos1<0 ? TString("") : n(pos1+1, n.Length());
414
415 TClass *cls = IsA()->GetBaseDataMember(part1);
416 if (cls)
417 {
418 TDataMember *member = cls->GetDataMember(part1);
419 if (!member)
420 {
421 *fLog << err << "Datamember '" << part1 << "' not in " << GetDescriptor() << endl;
422 return NULL;
423 }
424
425 // This handles returning references of contained objects, eg
426 // class X { TObject fO; TObject &GetO() { return fO; } };
427 if (!member->IsBasic() && !part2.IsNull())
428 {
429 cls = gROOT->GetClass(member->GetTypeName());
430 if (!cls)
431 {
432 *fLog << err << "Datamember " << part1 << " [";
433 *fLog << member->GetTypeName() << "] not in dictionary." << endl;
434 return NULL;
435 }
436 if (!cls->InheritsFrom(MParContainer::Class()))
437 {
438 *fLog << err << "Datamember " << part1 << " [";
439 *fLog << member->GetTypeName() << "] does not inherit from ";
440 *fLog << "MParContainer." << endl;
441 return NULL;
442 }
443
444 const MParContainer *sub = (MParContainer*)((ULong_t)this+member->GetOffset());
445 return sub->GetterMethod(part2);
446 }
447
448 if (member->IsaPointer())
449 {
450 *fLog << warn << "Data-member " << part1 << " is a pointer..." << endl;
451 *fLog << dbginf << "Not yet implemented!" << endl;
452 //TClass *test = gROOT->GetClass(member->GetTypeName());
453 return 0;
454 }
455
456 TMethodCall *call = member->GetterMethod();
457 if (call)
458 return call;
459 }
460
461 *fLog << warn << "No standard access for '" << part1 << "' in ";
462 *fLog << GetDescriptor() << " or one of its base classes." << endl;
463
464 TMethodCall *call = NULL;
465
466 *fLog << warn << "Trying to find MethodCall '" << ClassName();
467 *fLog << "::Get" << part1 << "' instead <LEAKS MEMORY>" << endl;
468 call = new TMethodCall(IsA(), (TString)"Get"+part1, "");
469 if (call->GetMethod())
470 return call;
471
472 delete call;
473
474 *fLog << warn << "Trying to find MethodCall '" << ClassName();
475 *fLog << "::" << part1 << "' instead <LEAKS MEMORY>" << endl;
476 call = new TMethodCall(IsA(), part1, "");
477 if (call->GetMethod())
478 return call;
479
480 delete call;
481
482 *fLog << err << "Sorry, no getter method found for " << part1 << endl;
483 return NULL;
484}
485
486// --------------------------------------------------------------------------
487//
488// Implementation of SavePrimitive. Used to write the call to a constructor
489// to a macro. In the original root implementation it is used to write
490// gui elements to a macro-file.
491//
492void MParContainer::SavePrimitive(ofstream &out, Option_t *o)
493{
494 static UInt_t uid = 0;
495
496 if (IsSavedAsPrimitive())
497 return;
498
499 SetUniqueID(uid++);
500 SetBit(kIsSavedAsPrimitive);
501
502 if (gListOfPrimitives && !gListOfPrimitives->FindObject(this))
503 gListOfPrimitives->Add(this);
504
505 StreamPrimitive(out);
506}
507
508// --------------------------------------------------------------------------
509//
510// Creates the string written by SavePrimitive and returns it.
511//
512void MParContainer::StreamPrimitive(ofstream &out) const
513{
514 out << " // Using MParContainer::StreamPrimitive" << endl;
515 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
516 out << fName << "\", \"" << fTitle << "\");" << endl;
517}
518
519void MParContainer::GetNames(TObjArray &arr) const
520{
521 arr.AddLast(new TNamed(fName, fTitle));
522}
523
524void MParContainer::SetNames(TObjArray &arr)
525{
526 TNamed *name = (TNamed*)arr.First();
527
528 fName = name->GetName();
529 fTitle = name->GetTitle();
530
531 delete arr.Remove(name);
532 arr.Compress();
533}
534
535// --------------------------------------------------------------------------
536//
537// Creates a new instance of this class. The idea is to create a clone of
538// this class in its initial state.
539//
540MParContainer *MParContainer::New() const
541{
542 return (MParContainer*)IsA()->New();
543}
544
545// --------------------------------------------------------------------------
546//
547// Read the contents/setup of a parameter container/task from a TEnv
548// instance (steering card/setup file).
549// The key to search for in the file should be of the syntax:
550// prefix.vname
551// While vname is a name which is specific for a single setup date
552// (variable) of this container and prefix is something like:
553// evtloopname.name
554// While name is the name of the containers/tasks in the parlist/tasklist
555//
556// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
557// Job4.MImgCleanStd.CleaningLevel2: 2.5
558//
559// If this cannot be found the next step is to search for
560// MImgCleanStd.CleaningLevel1: 3.0
561// And if this doesn't exist, too, we should search for:
562// CleaningLevel1: 3.0
563//
564// Warning: The programmer is responsible for the names to be unique in
565// all Mars classes.
566//
567Bool_t MParContainer::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
568{
569 if (!IsEnvDefined(env, prefix, "", print))
570 return kFALSE;
571
572 *fLog << warn << "WARNING - Resource " << prefix+fName << " found, but no " << ClassName() << "::ReadEnv." << endl;
573 return kTRUE;
574}
575
576// --------------------------------------------------------------------------
577//
578// Write the contents/setup of a parameter container/task to a TEnv
579// instance (steering card/setup file).
580// The key to search for in the file should be of the syntax:
581// prefix.vname
582// While vname is a name which is specific for a single setup date
583// (variable) of this container and prefix is something like:
584// evtloopname.name
585// While name is the name of the containers/tasks in the parlist/tasklist
586//
587// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
588// Job4.MImgCleanStd.CleaningLevel2: 2.5
589//
590// If this cannot be found the next step is to search for
591// MImgCleanStd.CleaningLevel1: 3.0
592// And if this doesn't exist, too, we should search for:
593// CleaningLevel1: 3.0
594//
595// Warning: The programmer is responsible for the names to be unique in
596// all Mars classes.
597//
598Bool_t MParContainer::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
599{
600 if (!IsEnvDefined(env, prefix, "", print))
601 return kFALSE;
602
603 *fLog << warn << "WARNING - Resource " << prefix+fName << " found, but " << ClassName() << "::WriteEnv not overloaded." << endl;
604 return kTRUE;
605}
606
607Bool_t MParContainer::IsEnvDefined(const TEnv &env, TString prefix, TString postfix, Bool_t print) const
608{
609 if (!postfix.IsNull())
610 postfix.Insert(0, ".");
611
612 return IsEnvDefined(env, prefix+postfix, print);
613}
614
615Bool_t MParContainer::IsEnvDefined(const TEnv &env, TString name, Bool_t print) const
616{
617 if (print)
618 *fLog << all << GetDescriptor() << " - " << name << "... " << flush;
619
620 if (!((TEnv&)env).Defined(name))
621 {
622 if (print)
623 *fLog << "not found." << endl;
624 return kFALSE;
625 }
626
627 if (print)
628 *fLog << "found." << endl;
629
630 return kTRUE;
631}
632
633Int_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, Int_t dflt) const
634{
635 return GetEnvValue(env, prefix+"."+postfix, dflt);
636}
637
638Double_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, Double_t dflt) const
639{
640 return GetEnvValue(env, prefix+"."+postfix, dflt);
641}
642
643const char *MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, const char *dflt) const
644{
645 return GetEnvValue(env, prefix+"."+postfix, dflt);
646}
647
648Int_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, Int_t dflt) const
649{
650 return ((TEnv&)env).GetValue(prefix, dflt);
651}
652
653Double_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, Double_t dflt) const
654{
655 return ((TEnv&)env).GetValue(prefix, dflt);
656}
657
658const char *MParContainer::GetEnvValue(const TEnv &env, TString prefix, const char *dflt) const
659{
660 return ((TEnv&)env).GetValue(prefix, dflt);
661}
Note: See TracBrowser for help on using the repository browser.