source: trunk/Mars/mdata/MDataPhrase.cc@ 19824

Last change on this file since 19824 was 19760, checked in by tbretz, 5 years ago
They are added to the ListOfCleanups. This is implemented as a THashTable. According to the root documentation, it is required to rehash the table whenever the name of an object in the table changes. This is now guranteed if name change happens via SetName
File size: 24.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, 04/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MDataPhrase
28//
29// A MDataPhrase is a wrapper for TFormula. It supports access to data-
30// members and/or member functions acessible from the parameter list
31// via MDataMember. It supports access to elements of a MMatrix through
32// the parameter list via MDataElement and it sipports variables set
33// by SetVariables via MDataValue.
34//
35// The parsing is done by TFormula. For more information which functions
36// are supported see TFormula, TFormulaPrimitives and TFormulaMathInterface.
37//
38// The support is done by replacing the parameters with access to the
39// parameter list by parameters like [0], [1],... When evaluating
40// the TFormula first the parameters are evaluated and passed to
41// TFormula. Each parameter is evaluated only once and, if necessary,
42// passed more than once to TFormula. To store the MData* classes used
43// for parameter access a TObjArray is used. Its advantage is, that
44// it has an UncheckedAt function which saves some time, because
45// no obsolete sanity checks must be done accessing the array.
46//
47// Because everything supported by TFormula is also supported by
48// MDataPhrase also conditional expression are supported.
49//
50// For supported functions see TFormulaPrimitive and TMathInterface.
51//
52// Examples:
53//
54// Gaus, Gausn, Landau, Landaun, Pol0-Pol10, Pow2-Pow5
55//
56// In the constructor you can give rule, like
57// "HillasSource.fDist / MHillas.fLength"
58// Where MHillas/HillasSource is the name of the parameter container in
59// the parameter list and fDist/fLength is the name of the data members
60// in the containers. The result will be fDist divided by fLength.
61//
62// In case you want to access a data-member which is a data member object
63// you can acces it with (Remark: it must derive from MParContainer):
64// "MCameraLV.fPowerSupplyA.fVoltagePos5V"
65// (THIS FEATURE IS CURRENTLY NOT SUPPORTED)
66//
67// You can also use parantheses:
68// "HillasDource.fDist / (MHillas.fLength + MHillas.fWidth)"
69//
70// Additional implementations:
71//
72// isnan(x) return 1 if x is NaN (Not a Number) otherwise 0
73// finite(x) return 1 if the number is a valid double (not NaN, inf)
74//
75// NaN (Not a Number) means normally a number which is to small to be
76// stored in a floating point variable (eg. 0<x<1e-56 or similar) or
77// a number which function is not defined (like asin(1.5))
78//
79// inf is the symbol for an infinite number.
80//
81//
82// Constants
83// ---------
84//
85// Most constants you might need can be found in TMath, eg:
86// TMath::Pi(), TMath::TwoPi(), TMath::Ln10(), TMath::LogE()
87// TMath::RadToDeg(), TMath::DegToRad();
88//
89//
90// Variable Parameters
91// ------------------------
92// If you want to use variables, eg for fits you can use [0], [1], ...
93// These values are initialized with 0 and set by calling
94// SetVariables(), eg
95// [0]*MHillas.fArea
96//
97//
98// Multi-argument functions
99// ------------------------
100// You can use multi-argument functions, too. Example:
101// "TMath::Hypot(MHillas.fMeanX, MHillas.MeanY)"
102// "pow(MHillas.fMeanX*MHillas.MeanY, -1.2)"
103//
104//
105//
106// To Do:
107// - The possibility to use other objects inheriting from MData
108// is missing.
109//
110/////////////////////////////////////////////////////////////////////////////
111#include "MDataPhrase.h"
112
113#include <TMath.h>
114#include <TArrayI.h>
115#include <TPRegexp.h>
116#include <TFormula.h>
117#include <THashList.h>
118#if ROOT_VERSION_CODE >= ROOT_VERSION(5,26,00)
119#if ROOT_VERSION_CODE < ROOT_VERSION(6,00,00)
120#include <TFormulaPrimitive.h>
121#else
122#include <v5/TFormulaPrimitive.h>
123#endif
124#endif
125
126#include "MLog.h"
127#include "MLogManip.h"
128
129#include "MArrayD.h"
130
131#include "MDataValue.h"
132#include "MDataMember.h"
133#include "MDataElement.h"
134
135ClassImp(MDataPhrase);
136
137using namespace std;
138
139// --------------------------------------------------------------------------
140//
141// Check for the existance of the expression [idx] in the string
142// phrase. If existing a corresponding new MDataValue is added to
143// fMembers and index is increased by one.
144//
145// This makes the use of user-defined variables in the phrase possible.
146//
147Int_t MDataPhrase::CheckForVariable(const TString &phrase, Int_t idx)
148{
149 TString mods;
150 TArrayI pos;
151
152 while (1)
153 {
154 // \\A: matches the beginning of the string like ^ does
155 // \\Z: matches the end of the string like $ does
156 // \\W: matches any non-word character [^a-zA-Z_0-9]
157 TPRegexp reg(Form("(\\A|\\W)\\[0*%d\\](\\W|\\Z)", idx));
158 if (reg.Match(phrase, mods, 0, 130, &pos)==0)
159 break;
160
161 // [idx] already existing. Add a corresponding MDataValue
162 fMembers.AddLast(new MDataValue(0, idx));
163 idx++;
164 }
165
166 return idx;
167}
168
169// --------------------------------------------------------------------------
170//
171// Replace all expressions expr (found by a regular expression \\b%s\\b
172// with %s being the expression) in the string phrase by [idx].
173//
174// The length of [idx] is returned.
175//
176Int_t MDataPhrase::Substitute(TString &phrase, const TString &expr, Int_t idx) const
177{
178 const TString arg = Form("[%d]", idx);
179
180 TPRegexp reg(expr);
181
182 TString mods;
183 TArrayI pos;
184
185 Int_t p = 0;
186 while (1)
187 {
188 // check whether argument is found
189 if (reg.Match(phrase, mods, p, 130, &pos)==0)
190 break;
191
192 // Replace expression by argument [idx]
193 phrase.Replace(pos[0], pos[1]-pos[0], arg, arg.Length());
194
195 // Jump behind the new string which was just inserted
196 p = pos[0]+arg.Length();
197 }
198 return arg.Length();
199}
200
201TString MDataPhrase::Parse(TString phrase)
202{
203 // This is for backward compatibility with MDataChain
204 phrase.ReplaceAll("gRandom->", "TRandom::");
205 phrase.ReplaceAll("kRad2Deg", "TMath::RadToDeg()");
206 phrase.ReplaceAll("kDeg2Rad", "TMath::DegToRad()");
207 phrase.ReplaceAll(" ", "");
208
209 int idx=0;
210 int p =0;
211
212 TString mods;
213 TArrayI pos;
214/*
215 // Find all functions...
216 // The first \\w+ should also allow ::
217 TPRegexp reg = TPRegexp("[[:word:]:]+\\([^()]*\\)");
218 while (1)
219 {
220 //idx = CheckForVariables(phrase, idx);
221
222 if (reg.Match(phrase, mods, p, 130, &pos)==0)
223 break;
224
225 const Int_t len = pos[1]-pos[0];
226
227 // This is the full function with its argument(s)
228 const TString term = phrase(pos[0], len);
229
230 // Now get rid of the argument(s)
231 const TPRegexp reg3("\\([^()]+\\)");
232
233 TString func(term);
234 reg3.Substitute(func, "");
235
236 // Seems to be a special case whic is not handles by
237 // TFormulaPrimitive by known by TFormula
238 if (func.BeginsWith("TRandom::"))
239 {
240 p = pos[0]+pos[1];
241 continue;
242 }
243
244 // check whether the function is available
245 if (TFormulaPrimitive::FindFormula(func))
246 {
247 p = pos[0]+pos[1];
248 continue;
249 }
250
251 cout << "Unknown: " << func << endl;
252 // p = pos[0]+pos[1];
253 return;
254 }
255*/
256
257 p = 0;
258
259 // Find all data-members in expression such as
260 // MTest.fDataMember. Because also floating point
261 // numbers can contain a dot the result has to
262 // be checked carefully
263 // \\w: matches any word character [a-zA-Z_0-9]
264 TPRegexp reg = TPRegexp("\\w+[.]\\w+");
265 TPRegexp ishex("^0x[[:xdigit:]]+$");
266
267 while (1)
268 {
269 // If some indices are already existing
270 // initialize them by a flexible MDataValue
271 idx = CheckForVariable(phrase, idx);
272
273 // Check whether expression is found
274 if (reg.Match(phrase, mods, p, 130, &pos)==0)
275 break;
276
277 // Get expression from phrase
278 const TString expr = phrase(pos[0], pos[1]-pos[0]);
279
280 // Also hex-numbers and floats fullfill our condition...
281 // FIXME: WHY HEX NUMBERS?
282 if (!expr(ishex).IsNull() || expr.IsFloat())
283 {
284 p = pos[1];
285 continue;
286 }
287
288 // Add a corresponding MDataMember to our list
289 fMembers.AddLast(new MDataMember(expr));
290
291 // Find other occurances of arg by this regexp
292 // and start next search behind first match
293 const TString regexp = Form("\\b%s\\b", expr.Data());
294 p = pos[0] + Substitute(phrase, regexp, idx);
295
296 // Step forward to the next argument
297 idx++;
298 }
299
300 p = 0;
301
302 // Now check for matrix elemets as M[5]
303 reg = TPRegexp("\\w+\\[\\d+\\]");
304 while (1)
305 {
306 // If some indices are already existing
307 // initialize them by a MDataValue
308 idx = CheckForVariable(phrase, idx);
309
310 // Check whether expression is found
311 if (reg.Match(phrase, mods, p, 130, &pos)==0)
312 break;
313
314 // Get expression from phrase
315 TString expr = phrase(pos[0], pos[1]-pos[0]);
316
317 // Add a corresponding MDataMember to our list
318 fMembers.AddLast(new MDataElement(expr));
319
320 // Make the expression "Regular expression proofed"
321 expr.ReplaceAll("[", "\\[");
322 expr.ReplaceAll("]", "\\]");
323
324 // Find other occurances of arg by this regexp
325 // and start next search behind first match
326 const TString regexp = Form("\\b%s", expr.Data());
327 p = pos[0] + Substitute(phrase, regexp, idx);
328
329 // Step forward to the next argument
330 idx++;
331 }
332 /*
333
334 // * HOW DO WE PROCESS THE FILTERS?
335 // * DO WE NEED THIS FOR MData derived classes? Is there any need for it?
336 // * MAYBE FIRST FILTERS (MF?) MUST REPLACE {name[class]} BEFORE
337 // THE DATA PHRASSE IS CREATED?
338 // --> MFDataPhrase must have a list of MFilter. In Process first
339 // all self created MFilter are processed (see MF). Then
340 // they are evaluated and the result is given to the MDataPhrase.
341 // Can this be done using MDataMember? We replace {Name[class]}
342 // by Name.IsExpressionTrue and we need a way that MDataPhrase
343 // gets the coresponding pointer.
344 // --> Alternatively we can create a MDataPhrase which allows
345 // Pre/Processing
346 //
347 // We convert {Name[Class]} to Name.IsExpressionTrue. To process these
348 // data/filters we need a request from MFDataPhrase (new virtual
349 // memeber function?)
350 //
351 // {} Is alreaqdy used in ReadEnv.
352 //
353 // Enhance ReadEnv to allow Cut1.5 to be just a class.
354 //
355 // The difference between MFDataPhrase is
356 // MFDataPhrase only knows MDataPhrase, while
357 // MF also knows a filter-class.
358 //
359
360 p = 0;
361
362 // And now we check for other phrases or filters
363 // They are defined by a [, a pribtable character and
364 // any numer of word characters (a-zA-Z0-9_) and a closing ]
365 reg = TPRegexp("{[A-Za-z}\\w+(\\[[A-Za-z]\\w+\\])?}");
366 while (1)
367 {
368 // If some indices are already existing
369 // initialize them by a MDataValue
370 idx = CheckForVariable(phrase, idx);
371
372 // Check whether expression is found
373 if (reg.Match(phrase, mods, p, 130, &pos)==0)
374 break;
375
376 // Get expression from phrase
377 TString expr = phrase(pos[0], pos[1]-pos[0]);
378
379 // Zerlegen: {Name[Class]}
380
381 // Create a new MData object of kind
382 MData *dat = (MData*)GetNewObject(cls, MData::Class());
383 if (!dat)
384 return "";
385 dat->SetName(name);
386
387 // Add a corresponding MDataMember to our list
388 fMembers.AddLast(dat);
389
390 // Make the expression "Regular expression proofed"
391 expr.ReplaceAll("[", "\\[");
392 expr.ReplaceAll("]", "\\]");
393
394 // Find other occurances of arg by this regexp
395 // and start next search behind first match
396 p = pos[0] + Substitute(phrase, expr, idx);
397
398 // Step forward to the next argument
399 idx++;
400 }
401 */
402 // Now we have to check if there are additional indices [idx]
403 // This is mainly important if the rule has indices only!
404 while (1)
405 {
406 const Int_t newidx = CheckForVariable(phrase, idx);
407 if (newidx == idx)
408 break;
409 }
410
411 return phrase;
412}
413
414// --------------------------------------------------------------------------
415//
416// Clear Formula and corresponding data members
417//
418void MDataPhrase::Clear(Option_t *)
419{
420 fMembers.Delete();
421 if (!fFormula)
422 return;
423
424 delete fFormula;
425 fFormula = NULL;
426}
427
428void MDataPhrase::RecursiveRemove(TObject *obj)
429{
430 if (fFormula==obj)
431 fFormula = NULL;
432}
433
434
435// --------------------------------------------------------------------------
436//
437// Set a new phrase/rule. Returns kTRUE on sucess, kFALSE otherwise
438//
439Bool_t MDataPhrase::SetRule(const TString &rule)
440{
441 Clear();
442
443 const TString txt=Parse(rule);
444 if (txt.IsNull())
445 {
446 Clear();
447 return kFALSE;
448 }
449
450 fFormula = new TFormula;
451
452 fFormula->SetNameTitle(fName.IsNull()?"TFormula":fName.Data(), txt);
453 fFormula->SetBit(kMustCleanup);
454
455 // Must have a name otherwise all axis labels disappear like a miracle
456 if (fFormula->Compile())
457 {
458 *fLog << err << dbginf << "Syntax Error: TFormula::Compile failed..."<< endl;
459 *fLog << " Full Rule: " << rule << endl;
460 *fLog << " Parsed Rule: " << txt << endl;
461 Clear();
462 return kFALSE;
463 }
464
465 gROOT->GetListOfFunctions()->Remove(fFormula);
466
467 return kTRUE;
468}
469
470namespace MFastFun {
471 //
472 // Namespace with basic primitive functions registered by TFormulaPrimitive
473 // all function registerd by TFormulaPrimitive can be used in TFormula
474 //
475 Double_t Nint(Double_t x){return TMath::Nint(x);}
476 Double_t Sign(Double_t x){return x<0?-1:+1;}
477 Double_t IsNaN(Double_t x){return TMath::IsNaN(x);}
478 Double_t Finite(Double_t x){return TMath::Finite(x);}
479}
480
481// --------------------------------------------------------------------------
482//
483// Default constructor. Set a rule (phrase), see class description for more
484// details. Set a name and title. If no title is given it is set to the rule.
485//
486MDataPhrase::MDataPhrase(const char *rule, const char *name, const char *title) : fFormula(0)
487{
488#if ROOT_VERSION_CODE < ROOT_VERSION(6,00,00)
489#define TFP TFormulaPrimitive
490#else
491#define TFP ROOT::v5::TFormulaPrimitive
492#endif
493
494 // More in TFormulaPrimitive.cxx
495 // More in TFormulaMathInterface
496 if (!TFP::FindFormula("isnan"))
497 {
498 TFP::AddFormula(new TFP("log2", "log2", (TFP::GenFunc10)TMath::Log2));
499 TFP::AddFormula(new TFP("fabs", "fabs", (TFP::GenFunc10)TMath::Abs));
500 TFP::AddFormula(new TFP("floor", "floor", (TFP::GenFunc10)TMath::Floor));
501 TFP::AddFormula(new TFP("ceil", "ceil", (TFP::GenFunc10)TMath::Ceil));
502
503 TFP::AddFormula(new TFP("nint", "nint", (TFP::GenFunc10)MFastFun::Nint));
504 TFP::AddFormula(new TFP("round", "round", (TFP::GenFunc10)MFastFun::Nint));
505 TFP::AddFormula(new TFP("sgn", "sgn", (TFP::GenFunc10)MFastFun::Sign));
506
507 TFP::AddFormula(new TFP("isnan", "isnan", (TFP::GenFunc10)MFastFun::IsNaN));
508 TFP::AddFormula(new TFP("finite", "finite", (TFP::GenFunc10)MFastFun::Finite));
509 }
510
511 // TFormulaPrimitive is used to get direct acces to the function pointers
512 // GenFunc - pointers to the static function
513 // TFunc - pointers to the data member functions
514 //
515 // The following sufixes are currently used, to describe function arguments:
516 // ------------------------------------------------------------------------
517 // G - generic layout - pointer to double (arguments), pointer to double (parameters)
518 // 10 - double
519 // 110 - double, double
520 // 1110 - double, double, double
521
522 fName = name ? name : "MDataPhrase";
523 fTitle = title ? title : rule;
524
525 fMembers.SetOwner();
526
527 if (rule)
528 SetRule(rule);
529
530 // Make sure that all object deleted are also deleted from this list
531 gROOT->GetListOfCleanups()->Add(this);
532 // Make sure that this doesn't remain in ListOfCleanups after deletion
533 SetBit(kMustCleanup);
534}
535
536void MDataPhrase::SetName(const char *name)
537{
538 MData::SetName(name);
539
540 // Some code produces crashed with root 6 (6.14 and 6.18 tested)
541 //
542 // MParameterCalc calc("MCorsikaEvtHeader.fZd");
543 // MContinue cont("MPhotonEvent.GetNumPhotons<2");
544 // MTaskList tasks;
545 // tasks.AddToList(&calc);
546 // tasks.AddToList(&cont);
547 // MEnv env("ceres.rc");
548 // if (!tasks.ReadEnv(env, "", kFALSE))
549 // return kFALSE;
550 //
551
552 // From the documentation of THashList::THashList
553 //
554 // WARNING !!!
555 // If the name of an object in the HashList is modified, The hashlist
556 // must be Rehashed
557 //
558 auto table = dynamic_cast<THashList*>(gROOT->GetListOfCleanups());
559 if (table)
560 table->Rehash(THashList::kInitHashTableCapacity);
561}
562
563
564// --------------------------------------------------------------------------
565//
566// Destructor
567//
568MDataPhrase::~MDataPhrase()
569{
570 if (fFormula)
571 {
572 delete fFormula;
573 fFormula = 0;
574 }
575}
576
577// --------------------------------------------------------------------------
578//
579// CopyConstructor
580//
581MDataPhrase::MDataPhrase(MDataPhrase &ts)
582{
583 TFormula *f = ts.fFormula;
584
585 fName = "MDataPhrase";
586 fTitle = f ? f->GetExpFormula() : (TString)"";
587
588 fFormula = f ? (TFormula*)f->Clone() : 0;
589 fFormula->SetBit(kMustCleanup);
590 gROOT->GetListOfFunctions()->Remove(fFormula);
591
592 fMembers.SetOwner();
593
594 TObject *o = NULL;
595 TIter Next(&ts.fMembers);
596 while ((o=Next()))
597 fMembers.AddLast(o->Clone());
598
599 // Make sure that all object deleted are also deleted from this list
600 gROOT->GetListOfCleanups()->Add(this);
601 // Make sure that this doesn't remain in ListOfCleanups after deletion
602 SetBit(kMustCleanup);
603}
604
605// --------------------------------------------------------------------------
606//
607// Evaluates and returns the result of the member list.
608//
609Double_t MDataPhrase::Eval(const Double_t *x) const
610{
611 const Int_t n = fMembers.GetEntriesFast();
612
613 if (fMembers.GetSize()<n)
614 {
615 *fLog << err << "ERROR - MDataPhrase::GetValue: Size mismatch!" << endl;
616 return 0;
617 }
618
619 // This is to get rid of the cost-qualifier for this->fStorage
620 Double_t *arr = fStorage.GetArray();
621
622 // Evaluate parameters (the access with TObjArray::UncheckedAt is
623 // roughly two times faster than with a TIter and rougly three
624 // times than accessing a TOrdCollection. However this might still
625 // be quite harmless compared to the time needed by GetValue)
626 for (Int_t i=0; i<n; i++)
627 arr[i] = static_cast<MData*>(fMembers.UncheckedAt(i))->GetValue();
628
629 // Evaluate function
630 return fFormula->EvalPar(x, arr);
631}
632
633// --------------------------------------------------------------------------
634//
635// Returns kTRUE if all members of fMemebers are valid and fFormula!=NULL
636//
637Bool_t MDataPhrase::IsValid() const
638{
639 TIter Next(&fMembers);
640
641 MData *data = NULL;
642 while ((data=(MData*)Next()))
643 if (!data->IsValid())
644 return kFALSE;
645
646 return fFormula ? kTRUE : kFALSE;
647}
648
649// --------------------------------------------------------------------------
650//
651// Checks whether at least one member has the ready-to-save flag.
652//
653Bool_t MDataPhrase::IsReadyToSave() const
654{
655 TIter Next(&fMembers);
656
657 MData *data = NULL;
658
659 while ((data=(MData*)Next()))
660 if (data->IsReadyToSave())
661 return kTRUE;
662
663 return kFALSE;
664}
665
666// --------------------------------------------------------------------------
667//
668// PreProcesses all members in the list
669//
670Bool_t MDataPhrase::PreProcess(const MParList *plist)
671{
672 if (!fFormula)
673 {
674 *fLog << err << "Error - So far no valid phrase was setup." << endl;
675 return kFALSE;
676 }
677
678 TIter Next(&fMembers);
679
680 MData *member=NULL;
681
682 //
683 // loop over all members
684 //
685 while ((member=(MData*)Next()))
686 if (!member->PreProcess(plist))
687 {
688 *fLog << err << "Error - Preprocessing Data Member ";
689 *fLog << member->GetName() << " in " << fName << endl;
690 return kFALSE;
691 }
692
693 // For speed reasons MArrayD instead of TArrayD is used
694 // (no range check is done when accessing). The storage is
695 // allocated (Set) only when its size is changing. If GetValue
696 // is called many times this should improve the speed significantly
697 // because the necessary memory is already allocated and doesn't need
698 // to be freed. (Just a static variable is not enough, because there
699 // may be several independant objects of this class)
700 fStorage.Set(fMembers.GetSize());
701
702 return kTRUE;
703}
704
705// --------------------------------------------------------------------------
706//
707// Builds a rule from all the list members. This is a rule which could
708// be used to rebuild the list using the constructor of a MDataChain
709//
710TString MDataPhrase::GetRule() const
711{
712 if (!fFormula)
713 return "<empty>";
714
715 TString rule = fFormula->GetTitle(); //fFormula->GetExpFormula();
716
717 MData *member = NULL;
718
719 Int_t i=0;
720 TIter Next(&fMembers);
721 while ((member=(MData*)Next()))
722 {
723 TString r = member->GetRule();
724 r.ReplaceAll("]", "\\]");
725 rule.ReplaceAll(Form("[%d]", i++), r);
726 }
727 rule.ReplaceAll("\\]", "]");
728
729 return rule;
730}
731
732// --------------------------------------------------------------------------
733//
734// This returns the rule as seen/interpreted by the TFormula. Mainly
735// for debugging purposes
736//
737TString MDataPhrase::GetRuleRaw() const
738{
739 if (!fFormula)
740 return "<empty>";
741
742 return fFormula->GetExpFormula();
743}
744
745// --------------------------------------------------------------------------
746//
747// Return the value converted to a Bool_t
748//
749Bool_t MDataPhrase::GetBool() const
750{
751 return TMath::Nint(GetValue())!=0;
752}
753
754/*
755// --------------------------------------------------------------------------
756//
757// Return a comma seperated list of all data members used in the chain.
758// This is mainly used in MTask::AddToBranchList
759//
760TString MDataPhrase::GetDataMember() const
761{
762 TString str;
763
764 TIter Next(&fMembers);
765
766 MData *member=(MData*)Next();
767
768 if (!member->GetDataMember().IsNull())
769 str += member->GetDataMember();
770
771 while ((member=(MData*)Next()))
772 {
773 if (!member->GetDataMember().IsNull())
774 {
775 str += ",";
776 str += member->GetDataMember();
777 }
778 }
779
780 return str;
781}
782*/
783void MDataPhrase::SetVariables(const TArrayD &arr)
784{
785 fMembers.R__FOR_EACH(MData, SetVariables)(arr);
786}
787
788// --------------------------------------------------------------------------
789//
790// Check for corresponding entries in resource file and setup data phrase.
791//
792// Assuming your MDataChain is called (Set/GetName): MyData
793//
794// Now setup the condition, eg:
795// MyData.Rule: log10(MHillas.fSize)
796// or
797// MyData.Rule: log10(MHillas.fSize) - 4.1
798//
799// If you want to use more difficult rules you can split the
800// condition into subrules. Subrules are identified
801// by {}-brackets. Avoid trailing 0's! For example:
802//
803// MyData.Rule: log10(MHillas.fSize) + {0} - {1}
804// MyData.0: 5.5*MHillas.fSize
805// MyData.1: 2.3*log10(MHillas.fSize)
806//
807// The numbering must be continous and start with 0. You can use
808// a subrules more than once. All {}-brackets are simply replaced
809// by the corresponding conditions. The rules how conditions can
810// be written can be found in the class description of MDataChain.
811//
812Int_t MDataPhrase::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
813{
814 Bool_t rc = kFALSE;
815 if (!IsEnvDefined(env, prefix, "Rule", print))
816 return rc;
817
818 TString rule = GetEnvValue(env, prefix, "Rule", "");
819
820 Int_t idx=0;
821 while (1)
822 {
823 TString cond;
824 if (IsEnvDefined(env, prefix, Form("%d", idx), print))
825 {
826 cond += "(";
827 cond += GetEnvValue(env, prefix, Form("%d", idx), "");
828 cond += ")";
829 }
830
831 if (cond.IsNull())
832 break;
833
834 rule.ReplaceAll(Form("{%d}", idx), cond);
835 idx++;
836 }
837
838 if (rule.IsNull())
839 {
840 *fLog << warn << "MDataPhrase::ReadEnv - ERROR: Empty rule found." << endl;
841 return kERROR;
842 }
843
844 if (!SetRule(rule))
845 return kERROR;
846
847 if (print)
848 *fLog << inf << "found: " << GetRule() << endl;
849
850 return kTRUE;
851}
Note: See TracBrowser for help on using the repository browser.