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

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