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

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