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

Last change on this file since 3574 was 3574, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 18.8 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 TClass *cls = IsA()->GetBaseDataMember(name);
410 if (cls)
411 {
412 TDataMember *member = cls->GetDataMember(name);
413 if (!member)
414 {
415 *fLog << err << "Datamember '" << name << "' not in " << GetDescriptor() << endl;
416 return NULL;
417 }
418
419 TMethodCall *call = member->GetterMethod();
420 if (call)
421 return call;
422 }
423
424 *fLog << warn << "No standard access for '" << name << "' in ";
425 *fLog << GetDescriptor() << " or one of its base classes." << endl;
426
427 TMethodCall *call = NULL;
428
429 *fLog << warn << "Trying to find MethodCall '" << ClassName();
430 *fLog << "::Get" << name << "' instead <LEAKS MEMORY>" << endl;
431 call = new TMethodCall(IsA(), (TString)"Get"+name, "");
432 if (call->GetMethod())
433 return call;
434
435 delete call;
436
437 *fLog << warn << "Trying to find MethodCall '" << ClassName();
438 *fLog << "::" << name << "' instead <LEAKS MEMORY>" << endl;
439 call = new TMethodCall(IsA(), name, "");
440 if (call->GetMethod())
441 return call;
442
443 delete call;
444
445 *fLog << err << "Sorry, no getter method found for " << name << endl;
446 return NULL;
447}
448
449// --------------------------------------------------------------------------
450//
451// Implementation of SavePrimitive. Used to write the call to a constructor
452// to a macro. In the original root implementation it is used to write
453// gui elements to a macro-file.
454//
455void MParContainer::SavePrimitive(ofstream &out, Option_t *o)
456{
457 static UInt_t uid = 0;
458
459 if (IsSavedAsPrimitive())
460 return;
461
462 SetUniqueID(uid++);
463 SetBit(kIsSavedAsPrimitive);
464
465 if (gListOfPrimitives && !gListOfPrimitives->FindObject(this))
466 gListOfPrimitives->Add(this);
467
468 StreamPrimitive(out);
469}
470
471// --------------------------------------------------------------------------
472//
473// Creates the string written by SavePrimitive and returns it.
474//
475void MParContainer::StreamPrimitive(ofstream &out) const
476{
477 out << " // Using MParContainer::StreamPrimitive" << endl;
478 out << " " << ClassName() << " " << GetUniqueName() << "(\"";
479 out << fName << "\", \"" << fTitle << "\");" << endl;
480}
481
482void MParContainer::GetNames(TObjArray &arr) const
483{
484 arr.AddLast(new TNamed(fName, fTitle));
485}
486
487void MParContainer::SetNames(TObjArray &arr)
488{
489 TNamed *name = (TNamed*)arr.First();
490
491 fName = name->GetName();
492 fTitle = name->GetTitle();
493
494 delete arr.Remove(name);
495 arr.Compress();
496}
497
498// --------------------------------------------------------------------------
499//
500// Creates a new instance of this class. The idea is to create a clone of
501// this class in its initial state.
502//
503MParContainer *MParContainer::New() const
504{
505 return (MParContainer*)IsA()->New();
506}
507
508// --------------------------------------------------------------------------
509//
510// Read the contents/setup of a parameter container/task from a TEnv
511// instance (steering card/setup file).
512// The key to search for in the file should be of the syntax:
513// prefix.vname
514// While vname is a name which is specific for a single setup date
515// (variable) of this container and prefix is something like:
516// evtloopname.name
517// While name is the name of the containers/tasks in the parlist/tasklist
518//
519// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
520// Job4.MImgCleanStd.CleaningLevel2: 2.5
521//
522// If this cannot be found the next step is to search for
523// MImgCleanStd.CleaningLevel1: 3.0
524// And if this doesn't exist, too, we should search for:
525// CleaningLevel1: 3.0
526//
527// Warning: The programmer is responsible for the names to be unique in
528// all Mars classes.
529//
530Bool_t MParContainer::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
531{
532 if (!IsEnvDefined(env, prefix, "", print))
533 return kFALSE;
534
535 *fLog << warn << "WARNING - Resource " << prefix+fName << " found, but no " << ClassName() << "::ReadEnv." << endl;
536 return kTRUE;
537}
538
539// --------------------------------------------------------------------------
540//
541// Write the contents/setup of a parameter container/task to a TEnv
542// instance (steering card/setup file).
543// The key to search for in the file should be of the syntax:
544// prefix.vname
545// While vname is a name which is specific for a single setup date
546// (variable) of this container and prefix is something like:
547// evtloopname.name
548// While name is the name of the containers/tasks in the parlist/tasklist
549//
550// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
551// Job4.MImgCleanStd.CleaningLevel2: 2.5
552//
553// If this cannot be found the next step is to search for
554// MImgCleanStd.CleaningLevel1: 3.0
555// And if this doesn't exist, too, we should search for:
556// CleaningLevel1: 3.0
557//
558// Warning: The programmer is responsible for the names to be unique in
559// all Mars classes.
560//
561Bool_t MParContainer::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
562{
563 if (!IsEnvDefined(env, prefix, "", print))
564 return kFALSE;
565
566 *fLog << warn << "WARNING - Resource " << prefix+fName << " found, but " << ClassName() << "::WriteEnv not overloaded." << endl;
567 return kTRUE;
568}
569
570Bool_t MParContainer::IsEnvDefined(const TEnv &env, TString prefix, TString postfix, Bool_t print) const
571{
572 if (!postfix.IsNull())
573 postfix.Insert(0, ".");
574
575 return IsEnvDefined(env, prefix+postfix, print);
576}
577
578Bool_t MParContainer::IsEnvDefined(const TEnv &env, TString name, Bool_t print) const
579{
580 if (print)
581 *fLog << all << GetDescriptor() << " - " << name << "... " << flush;
582
583 if (!((TEnv&)env).Defined(name))
584 {
585 if (print)
586 *fLog << "not found." << endl;
587 return kFALSE;
588 }
589
590 if (print)
591 *fLog << "found." << endl;
592
593 return kTRUE;
594}
595
596Int_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, Int_t dflt) const
597{
598 return GetEnvValue(env, prefix+"."+postfix, dflt);
599}
600
601Double_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, Double_t dflt) const
602{
603 return GetEnvValue(env, prefix+"."+postfix, dflt);
604}
605
606const char *MParContainer::GetEnvValue(const TEnv &env, TString prefix, TString postfix, const char *dflt) const
607{
608 return GetEnvValue(env, prefix+"."+postfix, dflt);
609}
610
611Int_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, Int_t dflt) const
612{
613 return ((TEnv&)env).GetValue(prefix, dflt);
614}
615
616Double_t MParContainer::GetEnvValue(const TEnv &env, TString prefix, Double_t dflt) const
617{
618 return ((TEnv&)env).GetValue(prefix, dflt);
619}
620
621const char *MParContainer::GetEnvValue(const TEnv &env, TString prefix, const char *dflt) const
622{
623 return ((TEnv&)env).GetValue(prefix, dflt);
624}
Note: See TracBrowser for help on using the repository browser.