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

Last change on this file since 19496 was 19345, checked in by tbretz, 6 years ago
Improves the behaviour with RecursiveRemove. Strictly speaking this change might only be necessary if a class contains more than one member which is bound to recursive remove. Onth other hand setting all members to NULL which might be affected by RecursiveRemove is not wrong either.
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 {
543 delete fFormula;
544 fFormula = 0;
545 }
546}
547
548// --------------------------------------------------------------------------
549//
550// CopyConstructor
551//
552MDataPhrase::MDataPhrase(MDataPhrase &ts)
553{
554 TFormula *f = ts.fFormula;
555
556 fName = "MDataPhrase";
557 fTitle = f ? f->GetExpFormula() : (TString)"";
558
559 fFormula = f ? (TFormula*)f->Clone() : 0;
560 fFormula->SetBit(kMustCleanup);
561 gROOT->GetListOfFunctions()->Remove(fFormula);
562
563 fMembers.SetOwner();
564
565 TObject *o = NULL;
566 TIter Next(&ts.fMembers);
567 while ((o=Next()))
568 fMembers.AddLast(o->Clone());
569
570 // Make sure that all object deleted are also deleted from this list
571 gROOT->GetListOfCleanups()->Add(this);
572 // Make sure that this doesn't remain in ListOfCleanups after deletion
573 SetBit(kMustCleanup);
574}
575
576// --------------------------------------------------------------------------
577//
578// Evaluates and returns the result of the member list.
579//
580Double_t MDataPhrase::Eval(const Double_t *x) const
581{
582 const Int_t n = fMembers.GetEntriesFast();
583
584 if (fMembers.GetSize()<n)
585 {
586 *fLog << err << "ERROR - MDataPhrase::GetValue: Size mismatch!" << endl;
587 return 0;
588 }
589
590 // This is to get rid of the cost-qualifier for this->fStorage
591 Double_t *arr = fStorage.GetArray();
592
593 // Evaluate parameters (the access with TObjArray::UncheckedAt is
594 // roughly two times faster than with a TIter and rougly three
595 // times than accessing a TOrdCollection. However this might still
596 // be quite harmless compared to the time needed by GetValue)
597 for (Int_t i=0; i<n; i++)
598 arr[i] = static_cast<MData*>(fMembers.UncheckedAt(i))->GetValue();
599
600 // Evaluate function
601 return fFormula->EvalPar(x, arr);
602}
603
604// --------------------------------------------------------------------------
605//
606// Returns kTRUE if all members of fMemebers are valid and fFormula!=NULL
607//
608Bool_t MDataPhrase::IsValid() const
609{
610 TIter Next(&fMembers);
611
612 MData *data = NULL;
613 while ((data=(MData*)Next()))
614 if (!data->IsValid())
615 return kFALSE;
616
617 return fFormula ? kTRUE : kFALSE;
618}
619
620// --------------------------------------------------------------------------
621//
622// Checks whether at least one member has the ready-to-save flag.
623//
624Bool_t MDataPhrase::IsReadyToSave() const
625{
626 TIter Next(&fMembers);
627
628 MData *data = NULL;
629
630 while ((data=(MData*)Next()))
631 if (data->IsReadyToSave())
632 return kTRUE;
633
634 return kFALSE;
635}
636
637// --------------------------------------------------------------------------
638//
639// PreProcesses all members in the list
640//
641Bool_t MDataPhrase::PreProcess(const MParList *plist)
642{
643 if (!fFormula)
644 {
645 *fLog << err << "Error - So far no valid phrase was setup." << endl;
646 return kFALSE;
647 }
648
649 TIter Next(&fMembers);
650
651 MData *member=NULL;
652
653 //
654 // loop over all members
655 //
656 while ((member=(MData*)Next()))
657 if (!member->PreProcess(plist))
658 {
659 *fLog << err << "Error - Preprocessing Data Member ";
660 *fLog << member->GetName() << " in " << fName << endl;
661 return kFALSE;
662 }
663
664 // For speed reasons MArrayD instead of TArrayD is used
665 // (no range check is done when accessing). The storage is
666 // allocated (Set) only when its size is changing. If GetValue
667 // is called many times this should improve the speed significantly
668 // because the necessary memory is already allocated and doesn't need
669 // to be freed. (Just a static variable is not enough, because there
670 // may be several independant objects of this class)
671 fStorage.Set(fMembers.GetSize());
672
673 return kTRUE;
674}
675
676// --------------------------------------------------------------------------
677//
678// Builds a rule from all the list members. This is a rule which could
679// be used to rebuild the list using the constructor of a MDataChain
680//
681TString MDataPhrase::GetRule() const
682{
683 if (!fFormula)
684 return "<empty>";
685
686 TString rule = fFormula->GetTitle(); //fFormula->GetExpFormula();
687
688 MData *member = NULL;
689
690 Int_t i=0;
691 TIter Next(&fMembers);
692 while ((member=(MData*)Next()))
693 {
694 TString r = member->GetRule();
695 r.ReplaceAll("]", "\\]");
696 rule.ReplaceAll(Form("[%d]", i++), r);
697 }
698 rule.ReplaceAll("\\]", "]");
699
700 return rule;
701}
702
703// --------------------------------------------------------------------------
704//
705// This returns the rule as seen/interpreted by the TFormula. Mainly
706// for debugging purposes
707//
708TString MDataPhrase::GetRuleRaw() const
709{
710 if (!fFormula)
711 return "<empty>";
712
713 return fFormula->GetExpFormula();
714}
715
716// --------------------------------------------------------------------------
717//
718// Return the value converted to a Bool_t
719//
720Bool_t MDataPhrase::GetBool() const
721{
722 return TMath::Nint(GetValue())!=0;
723}
724
725/*
726// --------------------------------------------------------------------------
727//
728// Return a comma seperated list of all data members used in the chain.
729// This is mainly used in MTask::AddToBranchList
730//
731TString MDataPhrase::GetDataMember() const
732{
733 TString str;
734
735 TIter Next(&fMembers);
736
737 MData *member=(MData*)Next();
738
739 if (!member->GetDataMember().IsNull())
740 str += member->GetDataMember();
741
742 while ((member=(MData*)Next()))
743 {
744 if (!member->GetDataMember().IsNull())
745 {
746 str += ",";
747 str += member->GetDataMember();
748 }
749 }
750
751 return str;
752}
753*/
754void MDataPhrase::SetVariables(const TArrayD &arr)
755{
756 fMembers.R__FOR_EACH(MData, SetVariables)(arr);
757}
758
759// --------------------------------------------------------------------------
760//
761// Check for corresponding entries in resource file and setup data phrase.
762//
763// Assuming your MDataChain is called (Set/GetName): MyData
764//
765// Now setup the condition, eg:
766// MyData.Rule: log10(MHillas.fSize)
767// or
768// MyData.Rule: log10(MHillas.fSize) - 4.1
769//
770// If you want to use more difficult rules you can split the
771// condition into subrules. Subrules are identified
772// by {}-brackets. Avoid trailing 0's! For example:
773//
774// MyData.Rule: log10(MHillas.fSize) + {0} - {1}
775// MyData.0: 5.5*MHillas.fSize
776// MyData.1: 2.3*log10(MHillas.fSize)
777//
778// The numbering must be continous and start with 0. You can use
779// a subrules more than once. All {}-brackets are simply replaced
780// by the corresponding conditions. The rules how conditions can
781// be written can be found in the class description of MDataChain.
782//
783Int_t MDataPhrase::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
784{
785 Bool_t rc = kFALSE;
786 if (!IsEnvDefined(env, prefix, "Rule", print))
787 return rc;
788
789 TString rule = GetEnvValue(env, prefix, "Rule", "");
790
791 Int_t idx=0;
792 while (1)
793 {
794 TString cond;
795 if (IsEnvDefined(env, prefix, Form("%d", idx), print))
796 {
797 cond += "(";
798 cond += GetEnvValue(env, prefix, Form("%d", idx), "");
799 cond += ")";
800 }
801
802 if (cond.IsNull())
803 break;
804
805 rule.ReplaceAll(Form("{%d}", idx), cond);
806 idx++;
807 }
808
809 if (rule.IsNull())
810 {
811 *fLog << warn << "MDataPhrase::ReadEnv - ERROR: Empty rule found." << endl;
812 return kERROR;
813 }
814
815 if (!SetRule(rule))
816 return kERROR;
817
818 if (print)
819 *fLog << inf << "found: " << GetRule() << endl;
820
821 return kTRUE;
822}
Note: See TracBrowser for help on using the repository browser.