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

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