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

Last change on this file since 19334 was 19334, checked in by tbretz, 6 years ago
Make sure that if root decides to delete TFormula we are not deleting it again.
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 fFormula->SetBit(kMustCleanup);
451
452 // Must have a name otherwise all axis labels disappear like a miracle
453 fFormula->SetName(fName.IsNull()?"TFormula":fName.Data());
454 if (fFormula->Compile(txt))
455 {
456 *fLog << err << dbginf << "Syntax Error: TFormula::Compile failed..."<< endl;
457 *fLog << " Full Rule: " << rule << endl;
458 *fLog << " Parsed Rule: " << txt << endl;
459 Clear();
460 return kFALSE;
461 }
462
463 gROOT->GetListOfFunctions()->Remove(fFormula);
464
465 return kTRUE;
466}
467
468namespace MFastFun {
469 //
470 // Namespace with basic primitive functions registered by TFormulaPrimitive
471 // all function registerd by TFormulaPrimitive can be used in TFormula
472 //
473 Double_t Nint(Double_t x){return TMath::Nint(x);}
474 Double_t Sign(Double_t x){return x<0?-1:+1;}
475 Double_t IsNaN(Double_t x){return TMath::IsNaN(x);}
476 Double_t Finite(Double_t x){return TMath::Finite(x);}
477}
478
479// --------------------------------------------------------------------------
480//
481// Default constructor. Set a rule (phrase), see class description for more
482// details. Set a name and title. If no title is given it is set to the rule.
483//
484MDataPhrase::MDataPhrase(const char *rule, const char *name, const char *title) : fFormula(0)
485{
486#if ROOT_VERSION_CODE < ROOT_VERSION(6,00,00)
487#define TFP TFormulaPrimitive
488#else
489#define TFP ROOT::v5::TFormulaPrimitive
490#endif
491
492 // More in TFormulaPrimitive.cxx
493 // More in TFormulaMathInterface
494 if (!TFP::FindFormula("isnan"))
495 {
496 TFP::AddFormula(new TFP("log2", "log2", (TFP::GenFunc10)TMath::Log2));
497 TFP::AddFormula(new TFP("fabs", "fabs", (TFP::GenFunc10)TMath::Abs));
498 TFP::AddFormula(new TFP("floor", "floor", (TFP::GenFunc10)TMath::Floor));
499 TFP::AddFormula(new TFP("ceil", "ceil", (TFP::GenFunc10)TMath::Ceil));
500
501 TFP::AddFormula(new TFP("nint", "nint", (TFP::GenFunc10)MFastFun::Nint));
502 TFP::AddFormula(new TFP("round", "round", (TFP::GenFunc10)MFastFun::Nint));
503 TFP::AddFormula(new TFP("sgn", "sgn", (TFP::GenFunc10)MFastFun::Sign));
504
505 TFP::AddFormula(new TFP("isnan", "isnan", (TFP::GenFunc10)MFastFun::IsNaN));
506 TFP::AddFormula(new TFP("finite", "finite", (TFP::GenFunc10)MFastFun::Finite));
507 }
508
509 // TFormulaPrimitive is used to get direct acces to the function pointers
510 // GenFunc - pointers to the static function
511 // TFunc - pointers to the data member functions
512 //
513 // The following sufixes are currently used, to describe function arguments:
514 // ------------------------------------------------------------------------
515 // G - generic layout - pointer to double (arguments), pointer to double (parameters)
516 // 10 - double
517 // 110 - double, double
518 // 1110 - double, double, double
519
520 fName = name ? name : "MDataPhrase";
521 fTitle = title ? title : rule;
522
523 fMembers.SetOwner();
524
525 if (rule)
526 SetRule(rule);
527
528 // Make sure that all object deleted are also deleted from this list
529 gROOT->GetListOfCleanups()->Add(this);
530 // Make sure that this doesn't remain in ListOfCleanups after deletion
531 SetBit(kMustCleanup);
532}
533
534// --------------------------------------------------------------------------
535//
536// Destructor
537//
538MDataPhrase::~MDataPhrase()
539{
540 if (fFormula)
541 delete fFormula;
542}
543
544// --------------------------------------------------------------------------
545//
546// CopyConstructor
547//
548MDataPhrase::MDataPhrase(MDataPhrase &ts)
549{
550 TFormula *f = ts.fFormula;
551
552 fName = "MDataPhrase";
553 fTitle = f ? f->GetExpFormula() : (TString)"";
554
555 fFormula = f ? (TFormula*)f->Clone() : 0;
556 fFormula->SetBit(kMustCleanup);
557 gROOT->GetListOfFunctions()->Remove(fFormula);
558
559 fMembers.SetOwner();
560
561 TObject *o = NULL;
562 TIter Next(&ts.fMembers);
563 while ((o=Next()))
564 fMembers.AddLast(o->Clone());
565
566 // Make sure that all object deleted are also deleted from this list
567 gROOT->GetListOfCleanups()->Add(this);
568 // Make sure that this doesn't remain in ListOfCleanups after deletion
569 SetBit(kMustCleanup);
570}
571
572// --------------------------------------------------------------------------
573//
574// Evaluates and returns the result of the member list.
575//
576Double_t MDataPhrase::Eval(const Double_t *x) const
577{
578 const Int_t n = fMembers.GetEntriesFast();
579
580 if (fMembers.GetSize()<n)
581 {
582 *fLog << err << "ERROR - MDataPhrase::GetValue: Size mismatch!" << endl;
583 return 0;
584 }
585
586 // This is to get rid of the cost-qualifier for this->fStorage
587 Double_t *arr = fStorage.GetArray();
588
589 // Evaluate parameters (the access with TObjArray::UncheckedAt is
590 // roughly two times faster than with a TIter and rougly three
591 // times than accessing a TOrdCollection. However this might still
592 // be quite harmless compared to the time needed by GetValue)
593 for (Int_t i=0; i<n; i++)
594 arr[i] = static_cast<MData*>(fMembers.UncheckedAt(i))->GetValue();
595
596 // Evaluate function
597 return fFormula->EvalPar(x, arr);
598}
599
600// --------------------------------------------------------------------------
601//
602// Returns kTRUE if all members of fMemebers are valid and fFormula!=NULL
603//
604Bool_t MDataPhrase::IsValid() const
605{
606 TIter Next(&fMembers);
607
608 MData *data = NULL;
609 while ((data=(MData*)Next()))
610 if (!data->IsValid())
611 return kFALSE;
612
613 return fFormula ? kTRUE : kFALSE;
614}
615
616// --------------------------------------------------------------------------
617//
618// Checks whether at least one member has the ready-to-save flag.
619//
620Bool_t MDataPhrase::IsReadyToSave() const
621{
622 TIter Next(&fMembers);
623
624 MData *data = NULL;
625
626 while ((data=(MData*)Next()))
627 if (data->IsReadyToSave())
628 return kTRUE;
629
630 return kFALSE;
631}
632
633// --------------------------------------------------------------------------
634//
635// PreProcesses all members in the list
636//
637Bool_t MDataPhrase::PreProcess(const MParList *plist)
638{
639 if (!fFormula)
640 {
641 *fLog << err << "Error - So far no valid phrase was setup." << endl;
642 return kFALSE;
643 }
644
645 TIter Next(&fMembers);
646
647 MData *member=NULL;
648
649 //
650 // loop over all members
651 //
652 while ((member=(MData*)Next()))
653 if (!member->PreProcess(plist))
654 {
655 *fLog << err << "Error - Preprocessing Data Member ";
656 *fLog << member->GetName() << " in " << fName << endl;
657 return kFALSE;
658 }
659
660 // For speed reasons MArrayD instead of TArrayD is used
661 // (no range check is done when accessing). The storage is
662 // allocated (Set) only when its size is changing. If GetValue
663 // is called many times this should improve the speed significantly
664 // because the necessary memory is already allocated and doesn't need
665 // to be freed. (Just a static variable is not enough, because there
666 // may be several independant objects of this class)
667 fStorage.Set(fMembers.GetSize());
668
669 return kTRUE;
670}
671
672// --------------------------------------------------------------------------
673//
674// Builds a rule from all the list members. This is a rule which could
675// be used to rebuild the list using the constructor of a MDataChain
676//
677TString MDataPhrase::GetRule() const
678{
679 if (!fFormula)
680 return "<empty>";
681
682 TString rule = fFormula->GetTitle(); //fFormula->GetExpFormula();
683
684 MData *member = NULL;
685
686 Int_t i=0;
687 TIter Next(&fMembers);
688 while ((member=(MData*)Next()))
689 {
690 TString r = member->GetRule();
691 r.ReplaceAll("]", "\\]");
692 rule.ReplaceAll(Form("[%d]", i++), r);
693 }
694 rule.ReplaceAll("\\]", "]");
695
696 return rule;
697}
698
699// --------------------------------------------------------------------------
700//
701// This returns the rule as seen/interpreted by the TFormula. Mainly
702// for debugging purposes
703//
704TString MDataPhrase::GetRuleRaw() const
705{
706 if (!fFormula)
707 return "<empty>";
708
709 return fFormula->GetExpFormula();
710}
711
712// --------------------------------------------------------------------------
713//
714// Return the value converted to a Bool_t
715//
716Bool_t MDataPhrase::GetBool() const
717{
718 return TMath::Nint(GetValue())!=0;
719}
720
721/*
722// --------------------------------------------------------------------------
723//
724// Return a comma seperated list of all data members used in the chain.
725// This is mainly used in MTask::AddToBranchList
726//
727TString MDataPhrase::GetDataMember() const
728{
729 TString str;
730
731 TIter Next(&fMembers);
732
733 MData *member=(MData*)Next();
734
735 if (!member->GetDataMember().IsNull())
736 str += member->GetDataMember();
737
738 while ((member=(MData*)Next()))
739 {
740 if (!member->GetDataMember().IsNull())
741 {
742 str += ",";
743 str += member->GetDataMember();
744 }
745 }
746
747 return str;
748}
749*/
750void MDataPhrase::SetVariables(const TArrayD &arr)
751{
752 fMembers.R__FOR_EACH(MData, SetVariables)(arr);
753}
754
755// --------------------------------------------------------------------------
756//
757// Check for corresponding entries in resource file and setup data phrase.
758//
759// Assuming your MDataChain is called (Set/GetName): MyData
760//
761// Now setup the condition, eg:
762// MyData.Rule: log10(MHillas.fSize)
763// or
764// MyData.Rule: log10(MHillas.fSize) - 4.1
765//
766// If you want to use more difficult rules you can split the
767// condition into subrules. Subrules are identified
768// by {}-brackets. Avoid trailing 0's! For example:
769//
770// MyData.Rule: log10(MHillas.fSize) + {0} - {1}
771// MyData.0: 5.5*MHillas.fSize
772// MyData.1: 2.3*log10(MHillas.fSize)
773//
774// The numbering must be continous and start with 0. You can use
775// a subrules more than once. All {}-brackets are simply replaced
776// by the corresponding conditions. The rules how conditions can
777// be written can be found in the class description of MDataChain.
778//
779Int_t MDataPhrase::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
780{
781 Bool_t rc = kFALSE;
782 if (!IsEnvDefined(env, prefix, "Rule", print))
783 return rc;
784
785 TString rule = GetEnvValue(env, prefix, "Rule", "");
786
787 Int_t idx=0;
788 while (1)
789 {
790 TString cond;
791 if (IsEnvDefined(env, prefix, Form("%d", idx), print))
792 {
793 cond += "(";
794 cond += GetEnvValue(env, prefix, Form("%d", idx), "");
795 cond += ")";
796 }
797
798 if (cond.IsNull())
799 break;
800
801 rule.ReplaceAll(Form("{%d}", idx), cond);
802 idx++;
803 }
804
805 if (rule.IsNull())
806 {
807 *fLog << warn << "MDataPhrase::ReadEnv - ERROR: Empty rule found." << endl;
808 return kERROR;
809 }
810
811 if (!SetRule(rule))
812 return kERROR;
813
814 if (print)
815 *fLog << inf << "found: " << GetRule() << endl;
816
817 return kTRUE;
818}
Note: See TracBrowser for help on using the repository browser.