source: trunk/Mars/mdata/MDataChain.cc@ 17224

Last change on this file since 17224 was 8907, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 27.2 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/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2005
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MDataChain
28// ==========
29//
30// With this chain you can concatenate simple mathematical operations on
31// members of mars containers.
32//
33//
34// Rules
35// -----
36//
37// In the constructor you can give rule, like
38// "HillasSource.fDist / MHillas.fLength"
39// Where MHillas/HillasSource is the name of the parameter container in
40// the parameter list and fDist/fLength is the name of the data members
41// in the containers. The result will be fDist divided by fLength.
42//
43// In case you want to access a data-member which is a data member object
44// you can acces it with (Remark: it must derive from MParContainer):
45// "MCameraLV.fPowerSupplyA.fVoltagePos5V"
46//
47// You can also use parantheses:
48// "HillasDource.fDist / (MHillas.fLength + MHillas.fWidth)"
49//
50//
51// Operators
52// ---------
53//
54// The allowed operations are: +, -, *, /, %, ^ and ** for ^
55//
56// While a%b returns the floating point reminder of a/b.
57// While a^b returns a to the power of b
58//
59// Priority
60// --------
61//
62// The priority of the operators is build in as:
63// ^ (highest), %, *, /, +, -
64//
65// Priorities are evaluated before parsing the rule by inserting
66// artificial paranthesis. If you find ANY problem with this please
67// report it immediatly! It is highly recommended to check the result!
68//
69// You can also use mathmatical operators, eg:
70// "5*log10(MMcEvt.fEnergy*MHillas.fSize)"
71//
72// The allowed operators are:
73// exp(x) e^x
74// log(x) natural logarithm of x
75// pow10(x) 10^x
76// log2(x) logarithm of x to base two
77// log10(x) logarithm of x to base ten
78// cos(x) cosine of x
79// sin(x) sine of x
80// tan(x) tangent of x
81// cosh(x) hyperbolic cosine of x
82// sinh(x) hyperbolic sine of x
83// tanh(x) hyperbolic tangent of x
84// acosh(x) arc hyperbolic cosine of x
85// asinh(x) arc hyperbolic sine of x
86// atanh(x) arc hyperbolic tangent of x
87// acos(x) arc cosine (inverse cosine) of x
88// asin(x) arc sine (inverse sine) of x
89// atan(x) arc tangent (inverse tangent) of x
90// sqrt(x) square root of x
91// sqr(x) square of x
92// abs(x) absolute value of x, |x|
93// floor(x) round down to the nearest integer (floor(9.9)=9)
94// ceil(x) round up to the nearest integer (floor(9.1)=10)
95// round(x) round to the nearest integer
96// r2d(x) transform radians to degrees
97// d2r(x) transform degrees to radians
98// rand(x) returns a uniform deviate on the interval ( 0, x ].
99// (gRandom->Uniform(x) is returned)
100// randp(x) returns gRandom->Poisson(x)
101// rande(x) returns gRandom->Exp(x)
102// randi(x) returns gRandom->Integer(x)
103// randg(x) returns gRandom->Gaus(0, x)
104// randl(x) returns gRandom->Landau(0, x)
105// isnan(x) return 1 if x is NaN (Not a Number) otherwise 0
106// finite(x) return 1 if the number is a valid double (not NaN, inf)
107//
108// NaN (Not a Number) means normally a number which is to small to be
109// stored in a floating point variable (eg. 0<x<1e-56 or similar) or
110// a number which function is not defined (like asin(1.5))
111//
112// inf is the symbol for an infinite number.
113//
114//
115// Constants
116// ---------
117//
118// Constants are implemented in ParseDataMember, namely:
119// kPi: TMath::Pi()
120// kRad2Deg: 180/kPi
121// kDeg2Rad: kPi/180
122//
123// You can also defined constants which are defined in TMath by:
124// kLn10 for static Double_t TMath::Ln10();
125// kLogE for static Double_t TMath::LogE();
126// kRadToDeg for static Double_t TMath::RadToDeg();
127// kDegToRad for static Double_t TMath::DegToRad();
128// ...
129//
130// Remark:
131// In older root versions only Pi() and E() are implemented
132// in TMath.
133//
134//
135// Variable Parameters
136// ------------------------
137// If you want to use variables, eg for fits you can use [0], [1], ...
138// These values are initialized with 0 and set by calling
139// SetVariables().
140//
141//
142// Multi-argument functions
143// ------------------------
144// You can use multi-argument functions, too. The access is implemented
145// via TFormula, which slows down thing a lot. If you can avoid usage
146// of such expression you accelerate the access a lot. Example:
147// "TMath::Hypot(MHillas.fMeanX, MHillas.MeanY)"
148// "pow(MHillas.fMeanX*MHillas.MeanY, -1.2)"
149// It should be possible to use all functions which are accessible
150// via the root-dictionary.
151//
152//
153// REMARK:
154// - All the random functions are returning 0 if gRandom==0
155// - You may get better results if you are using a TRandom3
156//
157// To Do:
158// - The possibility to use other objects inheriting from MData
159// is missing.
160// - By automatic pre-adding parantheses to the rule it would be possible
161// to implement priorities for operators.
162//
163/////////////////////////////////////////////////////////////////////////////
164
165#include "MDataChain.h"
166
167#include <ctype.h> // isalnum, ...
168#include <stdlib.h> // strtod, ...
169
170#include <TMath.h>
171#include <TClass.h>
172#include <TRegexp.h>
173#include <TRandom.h>
174#include <TMethodCall.h>
175
176#include "MLog.h"
177#include "MLogManip.h"
178
179#include "MDataList.h"
180#include "MDataValue.h"
181#include "MDataMember.h"
182#include "MDataFormula.h"
183#include "MDataElement.h"
184
185ClassImp(MDataChain);
186
187using namespace std;
188
189// --------------------------------------------------------------------------
190//
191// Constructor which takes a rule and a surrounding operator as argument
192//
193MDataChain::MDataChain(const char *rule, OperatorType_t op)
194 : fOperatorType(op)
195{
196 fName = "MDataChain";
197 fTitle = rule;
198
199 fMember=ParseString(rule);
200}
201
202// --------------------------------------------------------------------------
203//
204// Constructor taking a rule as an argument. For more details see
205// class description
206//
207MDataChain::MDataChain(const char *rule, const char *name, const char *title)
208 : fMember(NULL), fOperatorType(kENoop)
209{
210 fName = name ? name : "MDataChain";
211 fTitle = title ? title : rule;
212
213 if (TString(rule).IsNull())
214 return;
215
216 *fLog << inf << "Parsing rule... " << flush;
217 if (!(fMember=ParseString(rule)))
218 {
219 *fLog << err << dbginf << "Parsing '" << rule << "' failed." << endl;
220 return;
221 }
222 *fLog << inf << "found: " << GetRule() << endl;
223}
224
225// --------------------------------------------------------------------------
226//
227// PreProcesses all members in the list
228//
229Bool_t MDataChain::PreProcess(const MParList *pList)
230{
231 return fMember ? fMember->PreProcess(pList) : kFALSE;
232}
233
234// --------------------------------------------------------------------------
235//
236// Checks whether at least one member has the ready-to-save flag.
237//
238Bool_t MDataChain::IsReadyToSave() const
239{
240 *fLog << all << "fM=" << fMember << "/" << (int)fMember->IsReadyToSave() << " " << endl;
241 return fMember ? fMember->IsReadyToSave() : kFALSE;
242}
243
244// --------------------------------------------------------------------------
245//
246// Destructor. Delete filters.
247//
248MDataChain::~MDataChain()
249{
250 if (fMember)
251 delete fMember;
252}
253
254// --------------------------------------------------------------------------
255//
256// Returns the number of alphanumeric characters (including '.' and ';')
257// in the given string
258//
259Int_t MDataChain::IsAlNum(TString txt)
260{
261 int l = txt.Length();
262 for (int i=0; i<l; i++)
263 {
264 if (!isalnum(txt[i]) && txt[i]!='.' && txt[i]!=':' && txt[i]!=';' &&
265 /*txt[i]!='['&&txt[i]!=']'&&*/
266 ((txt[i]!='-' && txt[i]!='+') || i!=0))
267 return i;
268 }
269
270 return l;
271}
272
273Int_t MDataChain::GetBracket(TString txt, char open, char close)
274{
275 Int_t first=1;
276 for (int cnt=0; first<txt.Length(); first++)
277 {
278 if (txt[first]==open)
279 cnt++;
280 if (txt[first]==close)
281 cnt--;
282 if (cnt==-1)
283 break;
284 }
285 return first;
286}
287
288// --------------------------------------------------------------------------
289//
290// Compare a given text with the known operators. If no operator match
291// kENoop is retunred, otherwise the corresponding OperatorType_t
292//
293MDataChain::OperatorType_t MDataChain::ParseOperator(TString txt) const
294{
295 txt.ToLower();
296
297 if (txt=="abs") return kEAbs;
298 if (txt=="fabs") return kEAbs;
299 if (txt=="log") return kELog;
300 if (txt=="log2") return kELog2;
301 if (txt=="log10") return kELog10;
302 if (txt=="sin") return kESin;
303 if (txt=="cos") return kECos;
304 if (txt=="tan") return kETan;
305 if (txt=="sinh") return kESinH;
306 if (txt=="cosh") return kECosH;
307 if (txt=="tanh") return kETanH;
308 if (txt=="asin") return kEASin;
309 if (txt=="acos") return kEACos;
310 if (txt=="atan") return kEATan;
311 if (txt=="asinh") return kEASinH;
312 if (txt=="acosh") return kEACosH;
313 if (txt=="atanh") return kEATanH;
314 if (txt=="sqrt") return kESqrt;
315 if (txt=="sqr") return kESqr;
316 if (txt=="exp") return kEExp;
317 if (txt=="pow10") return kEPow10;
318 if (txt=="sgn") return kESgn;
319 if (txt=="floor") return kEFloor;
320 if (txt=="r2d") return kERad2Deg;
321 if (txt=="d2r") return kEDeg2Rad;
322 if (txt=="rand") return kERandom;
323 if (txt=="randp") return kERandomP;
324 if (txt=="rande") return kERandomE;
325 if (txt=="randi") return kERandomI;
326 if (txt=="randg") return kERandomG;
327 if (txt=="randl") return kERandomL;
328 if (txt=="isnan") return kEIsNaN;
329 if (txt=="finite") return kEFinite;
330 if (txt[0]=='-') return kENegative;
331 if (txt[0]=='+') return kEPositive;
332
333 return kENoop;
334}
335
336// --------------------------------------------------------------------------
337//
338// Here the names of data members are interpreted. This can be used to
339// check for constants.
340//
341MData *MDataChain::ParseDataMember(TString txt)
342{
343 //txt.ToLower();
344
345 if (txt=="kRad2Deg") return new MDataValue(kRad2Deg);
346 if (txt=="kDeg2Rad") return new MDataValue(1./kRad2Deg);
347
348 if (!txt.BeginsWith("k"))
349 return new MDataMember(txt.Data());
350
351 const TString name = txt(1, txt.Length());
352#if ROOT_VERSION_CODE < ROOT_VERSION(4,01,00)
353 TMethodCall call(TMath::Class(), name, "");
354#else
355 static TClass *const tmath = TClass::GetClass("TMath");
356 TMethodCall call(tmath, name, "");
357#endif
358
359 switch (call.ReturnType())
360 {
361 case TMethodCall::kLong:
362 Long_t l;
363 call.Execute(l);
364 return new MDataValue(l);
365 case TMethodCall::kDouble:
366 Double_t d;
367 call.Execute(d);
368 return new MDataValue(d);
369 default:
370 break;
371 }
372
373 return new MDataMember(txt.Data());
374}
375
376// --------------------------------------------------------------------------
377//
378// Remove all whitespaces
379// Replace all kind of double +/- by a single + or -
380//
381void MDataChain::SimplifyString(TString &txt) const
382{
383 txt.ReplaceAll(" ", "");
384 txt.ReplaceAll("**", "^");
385
386 while (txt.Contains("--") || txt.Contains("++") ||
387 txt.Contains("+-") || txt.Contains("-+"))
388 {
389 txt.ReplaceAll("--", "+");
390 txt.ReplaceAll("++", "+");
391 txt.ReplaceAll("-+", "-");
392 txt.ReplaceAll("+-", "-");
393 }
394}
395
396// --------------------------------------------------------------------------
397//
398// Add Parenthesis depending on the priority of the operators. The
399// priorities are defined by the default of the second argument.
400//
401void MDataChain::AddParenthesis(TString &test, const TString op) const
402{
403 // Signiture of an exponential number 1e12
404 static const TRegexp rexp("[.0123456789]e[+-][0123456789]");
405
406 const TString low = op(1, op.Length());
407 if (low.Length()==0)
408 return;
409
410 int offset = 0;
411 while (1)
412 {
413 const TString check = test(offset, test.Length());
414 if (check.IsNull())
415 break;
416
417 const Ssiz_t pos = check.First(op[0]);
418 if (pos<0)
419 break;
420
421 int cnt=0;
422
423 int i;
424 for (i=pos-1; i>=0; i--)
425 {
426 if (check[i]==')')
427 cnt++;
428 if (check[i]=='(')
429 cnt--;
430 if (cnt>0 || low.First(check[i])<0)
431 continue;
432
433 // Check if operator belongs to an exponential number
434 const TString sub(check(i-2, 4));
435 if (!sub(rexp).IsNull())
436 continue;
437 break;
438 }
439
440 cnt=0;
441 int j;
442 for (j=pos; j<check.Length(); j++)
443 {
444 if (check[j]=='(')
445 cnt++;
446 if (check[j]==')')
447 cnt--;
448 if (cnt>0 || low.First(check[j])<0)
449 continue;
450
451 // Check if operator belongs to an exponential number
452 const TString sub(check(j-2, 4));
453 if (!sub(rexp).IsNull())
454 continue;
455 break;
456 }
457
458 const TString sub = test(offset+i+1, j-i-1);
459
460 // Check if it contains operators,
461 // otherwise we can simply skip it
462 if (sub.First("%^/*+-")>=0)
463 {
464 test.Insert(offset+j, ")");
465 test.Insert(offset+i+1, "(");
466 offset += 2;
467 }
468 offset += j+1;
469 }
470
471 AddParenthesis(test, low);
472}
473
474// --------------------------------------------------------------------------
475//
476// Core of the data chain. Here the chain is constructed out of the rule.
477//
478MData *MDataChain::ParseString(TString txt, Int_t level)
479{
480 if (level==0)
481 {
482 SimplifyString(txt);
483 AddParenthesis(txt);
484 }
485
486 MData *member0=NULL;
487
488 char type=0;
489 int nlist = 0;
490
491 while (!txt.IsNull())
492 {
493 MData *newmember = NULL;
494
495 txt = txt.Strip(TString::kBoth);
496
497 switch (txt[0])
498 {
499 case '(':
500 {
501 //
502 // Search for the corresponding parantheses
503 //
504 const Int_t first=GetBracket(txt, '(', ')');
505 if (first==txt.Length())
506 {
507 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
508 if (member0)
509 delete member0;
510 return NULL;
511 }
512
513 //
514 // Make a copy of the 'interieur' and delete the substring
515 // including the brackets
516 //
517 TString sub = txt(1, first-1);
518 txt.Remove(0, first+1);
519
520 //
521 // Parse the substring
522 //
523 newmember = ParseString(sub, level+1);
524 if (!newmember)
525 {
526 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
527 if (member0)
528 delete member0;
529 return NULL;
530 }
531 }
532 break;
533
534 case ')':
535 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
536 if (member0)
537 delete member0;
538 return NULL;
539
540 case '+':
541 case '-':
542 case '*':
543 case '/':
544 case '%':
545 case '^':
546 if (member0)
547 {
548 //
549 // Check for the type of the symbol
550 //
551 char is = txt[0];
552 txt.Remove(0, 1);
553
554 //
555 // If no filter is available or the available filter
556 // is of a different symbols we have to create a new
557 // data list with the new symbol
558 //
559 if (/*!member0->InheritsFrom(MDataMember::Class()) ||*/ type!=is)
560 {
561 MDataList *list = new MDataList(is);
562 list->SetName(Form("List_%c_%d", is, 10*level+nlist++));
563
564 list->SetOwner();
565 list->AddToList(member0);
566
567 member0 = list;
568
569 type = is;
570 }
571 continue;
572 }
573
574 if (txt[0]!='-' && txt[0]!='+')
575 {
576 *fLog << err << dbginf << "Syntax Error: First argument of '";
577 *fLog << txt[0] << "' opartor missing." << endl;
578 if (member0)
579 delete member0;
580 return NULL;
581 }
582
583 // FALLTHROU
584
585 case '0':
586 case '1':
587 case '2':
588 case '3':
589 case '4':
590 case '5':
591 case '6':
592 case '7':
593 case '8':
594 case '9':
595 case '[':
596 case ']':
597 if ((txt[0]!='-' && txt[0]!='+') || isdigit(txt[1]) || txt[1]=='.')
598 {
599 if (!txt.IsNull() && txt[0]=='[')
600 {
601 Int_t first = GetBracket(txt, '[', ']');
602 TString op = txt(1, first-1);
603 txt.Remove(0, first+1);
604
605 newmember = new MDataValue(0, atoi(op));
606 break;
607 }
608
609 char *end;
610 Double_t num = strtod(txt.Data(), &end);
611 if (!end || txt.Data()==end)
612 {
613 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
614 if (member0)
615 delete member0;
616 return NULL;
617 }
618
619 txt.Remove(0, end-txt.Data());
620
621 newmember = new MDataValue(num);
622 break;
623 }
624
625 // FALLTHROUH
626
627 default:
628 int i = IsAlNum(txt);
629
630 if (i==0)
631 {
632 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
633 if (member0)
634 delete member0;
635 return NULL;
636 }
637
638 TString text = txt(0, i);
639
640 txt.Remove(0, i);
641 txt = txt.Strip(TString::kBoth);
642
643 if (!txt.IsNull() && txt[0]=='[')
644 {
645 Int_t first = GetBracket(txt, '[', ']');
646 TString op = txt(1, first-1);
647 txt.Remove(0, first+1);
648
649 newmember = new MDataElement(text, atoi(op));
650 break;
651 }
652 if ((txt.IsNull() || txt[0]!='(') && text[0]!='-' && text[0]!='+')
653 {
654 newmember = ParseDataMember(text.Data());
655 break;
656 }
657
658 OperatorType_t op = ParseOperator(text);
659
660 Int_t first = GetBracket(txt, '(', ')');
661 TString sub = op==kENegative || op==kEPositive ? text.Remove(0,1) + txt : txt(1, first-1);
662 txt.Remove(0, first+1);
663
664 if (op==kENoop)
665 {
666 newmember = new MDataFormula(Form("%s(%s)", (const char*)text, (const char*)sub));
667 if (newmember->IsValid())
668 break;
669
670 *fLog << err << dbginf << "Syntax Error: Operator '" << text << "' unknown." << endl;
671 if (member0)
672 delete member0;
673 return NULL;
674 }
675
676 newmember = new MDataChain(sub, op);
677 if (!newmember->IsValid())
678 {
679 *fLog << err << dbginf << "Syntax Error: Error parsing contents '" << sub << "' of operator " << text << endl;
680 delete newmember;
681 if (member0)
682 delete member0;
683 return NULL;
684 }
685 }
686
687 if (!member0)
688 {
689 member0 = newmember;
690 continue;
691 }
692
693 if (!member0->InheritsFrom(MDataList::Class()))
694 continue;
695
696 ((MDataList*)member0)->AddToList(newmember);
697 }
698
699 return member0;
700}
701
702// --------------------------------------------------------------------------
703//
704// Returns the value described by the rule
705//
706Double_t MDataChain::GetValue() const
707{
708 if (!fMember)
709 {
710 //*fLog << warn << "MDataChain not valid." << endl;
711 return 0;
712 }
713
714 const Double_t val = fMember->GetValue();
715
716 switch (fOperatorType)
717 {
718 case kEAbs: return TMath::Abs(val);
719 case kELog: return TMath::Log(val);
720 case kELog2: return TMath::Log2(val);
721 case kELog10: return TMath::Log10(val);
722 case kESin: return TMath::Sin(val);
723 case kECos: return TMath::Cos(val);
724 case kETan: return TMath::Tan(val);
725 case kESinH: return TMath::SinH(val);
726 case kECosH: return TMath::CosH(val);
727 case kETanH: return TMath::TanH(val);
728 case kEASin: return TMath::ASin(val);
729 case kEACos: return TMath::ACos(val);
730 case kEATan: return TMath::ATan(val);
731 case kEASinH: return TMath::ASinH(val);
732 case kEACosH: return TMath::ACosH(val);
733 case kEATanH: return TMath::ATanH(val);
734 case kESqrt: return TMath::Sqrt(val);
735 case kESqr: return val*val;
736 case kEExp: return TMath::Exp(val);
737 case kEPow10: return TMath::Power(10, val);
738 case kESgn: return val<0 ? -1 : 1;
739 case kENegative: return -val;
740 case kEPositive: return val;
741 case kEFloor: return TMath::Floor(val);
742 case kECeil: return TMath::Ceil(val);
743 case kERound: return TMath::Nint(val);
744 case kERad2Deg: return val*180/TMath::Pi();
745 case kEDeg2Rad: return val*TMath::Pi()/180;
746 case kERandom: return gRandom ? gRandom->Uniform(val) : 0;
747 case kERandomP: return gRandom ? gRandom->Poisson(val) : 0;
748 case kERandomE: return gRandom ? gRandom->Exp(val) : 0;
749 case kERandomI: return gRandom ? gRandom->Integer((int)val) : 0;
750 case kERandomG: return gRandom ? gRandom->Gaus(0, val) : 0;
751 case kERandomL: return gRandom ? gRandom->Landau(0, val) : 0;
752 case kEIsNaN: return TMath::IsNaN(val);
753 case kEFinite: return TMath::Finite(val);
754 case kENoop: return val;
755 }
756
757 *fLog << warn << "No Case for " << fOperatorType << " available." << endl;
758
759 return 0;
760}
761
762// --------------------------------------------------------------------------
763//
764// Builds a rule from all the chain members. This is a rule which could
765// be used to rebuild the chain.
766//
767TString MDataChain::GetRule() const
768{
769 if (!fMember)
770 return "<n/a>";
771
772 TString str;
773
774 Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class());
775
776 switch (fOperatorType)
777 {
778 case kEAbs: str += "abs" ; break;
779 case kELog: str += "log" ; break;
780 case kELog2: str += "log2" ; break;
781 case kELog10: str += "log10" ; break;
782 case kESin: str += "sin" ; break;
783 case kECos: str += "cos" ; break;
784 case kETan: str += "tan" ; break;
785 case kESinH: str += "sinh" ; break;
786 case kECosH: str += "cosh" ; break;
787 case kETanH: str += "tanh" ; break;
788 case kEASin: str += "asin" ; break;
789 case kEACos: str += "acos" ; break;
790 case kEATan: str += "atan" ; break;
791 case kEASinH: str += "asinh" ; break;
792 case kEACosH: str += "acosh" ; break;
793 case kEATanH: str += "atanh" ; break;
794 case kESqrt: str += "sqrt" ; break;
795 case kESqr: str += "sqr" ; break;
796 case kEExp: str += "exp" ; break;
797 case kEPow10: str += "pow10" ; break;
798 case kESgn: str += "sgn" ; break;
799 case kENegative: str += "-" ; break;
800 case kEPositive: str += "+" ; break;
801 case kEFloor: str += "floor" ; break;
802 case kECeil: str += "ceil" ; break;
803 case kERound: str += "round" ; break;
804 case kERad2Deg: str += "r2d" ; break;
805 case kEDeg2Rad: str += "d2r" ; break;
806 case kERandom: str += "rand" ; break;
807 case kERandomP: str += "randp" ; break;
808 case kERandomE: str += "rande" ; break;
809 case kERandomI: str += "randi" ; break;
810 case kERandomG: str += "randg" ; break;
811 case kERandomL: str += "randl" ; break;
812 case kEIsNaN: str += "isnan" ; break;
813 case kEFinite: str += "finite"; break;
814 case kENoop:
815 break;
816 }
817
818 if (bracket)
819 str += "(";
820
821 str += fMember->GetRule();
822
823 if (bracket)
824 str += ")";
825
826 return str;
827}
828
829// --------------------------------------------------------------------------
830//
831// Return a comma seperated list of all data members used in the chain.
832// This is mainly used in MTask::AddToBranchList
833//
834TString MDataChain::GetDataMember() const
835{
836 return fMember ? fMember->GetDataMember() : TString();
837}
838
839void MDataChain::SetVariables(const TArrayD &arr)
840{
841 if (fMember)
842 fMember->SetVariables(arr);
843}
844
845// --------------------------------------------------------------------------
846//
847// Check for corresponding entries in resource file and setup data chain.
848//
849// Assuming your MDataChain is called (Set/GetName): MyData
850//
851// Now setup the condition, eg:
852// MyData.Rule: log10(MHillas.fSize)
853// or
854// MyData.Rule: log10(MHillas.fSize) - 4.1
855//
856// If you want to use more difficult rules you can split the
857// condition into subrules. Subrules are identified
858// by {}-brackets. Avoid trailing 0's! For example:
859//
860// MyData.Rule: log10(MHillas.fSize) + {0} - {1}
861// MyData.0: 5.5*MHillas.fSize
862// MyData.1: 2.3*log10(MHillas.fSize)
863//
864// The numbering must be continous and start with 0. You can use
865// a subrules more than once. All {}-brackets are simply replaced
866// by the corresponding conditions. The rules how conditions can
867// be written can be found in the class description of MDataChain.
868//
869Int_t MDataChain::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
870{
871 Bool_t rc = kFALSE;
872 if (!IsEnvDefined(env, prefix, "Rule", print))
873 return rc;
874
875 TString rule = GetEnvValue(env, prefix, "Rule", "");
876 rule.ReplaceAll(" ", "");
877
878 Int_t idx=0;
879 while (1)
880 {
881 TString cond;
882 if (IsEnvDefined(env, prefix, Form("%d", idx), print))
883 {
884 cond += "(";
885 cond += GetEnvValue(env, prefix, Form("%d", idx), "");
886 cond += ")";
887 }
888
889 if (cond.IsNull())
890 break;
891
892 rule.ReplaceAll(Form("{%d}", idx), cond);
893 idx++;
894 }
895
896 if (fMember)
897 {
898 delete fMember;
899 fMember = 0;
900 }
901
902 if (rule.IsNull())
903 {
904 *fLog << warn << "MDataChain::ReadEnv - ERROR: Empty rule found." << endl;
905 return kERROR;
906 }
907
908 if (!(fMember=ParseString(rule)))
909 {
910 *fLog << err << "MDataChain::ReadEnv - ERROR: Parsing '" << rule << "' failed." << endl;
911 return kERROR;
912 }
913
914 if (print)
915 {
916 *fLog << inf << "found: ";
917 fMember->Print();
918 *fLog << endl;
919 }
920
921 return kTRUE;
922}
923/*
924void MDataChain::ReconstructElements()
925{
926 if (!fMember)
927 return;
928
929 if (fMember->InheritsFrom(MDataElement::Class()))
930 {
931 MData *data = ((MDataElement*)fMember)->CloneColumn();
932 delete fMember;
933 fMember = data;
934 }
935
936 fMember->ReconstructElements();
937}
938*/
Note: See TracBrowser for help on using the repository browser.