source: trunk/MagicSoft/Mars/mdata/MDataChain.cc@ 1742

Last change on this file since 1742 was 1661, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 16.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/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MDataChain
28//
29// With this chain you can concatenate simple mathematical operations on
30// members of mars containers.
31//
32// In the constructor you can give rule, like
33// "HillasSource.fDist / MHillas.fLength"
34// Where MHillas/HillasSource is the name of the parameter container in
35// the parameter list and fDist/fLength is the name of the data members
36// in the containers. The result will be fDist divided by fLength.
37//
38// You can also use brackets:
39// "HillasDource.fDist / (MHillas.fLength + MHillas.fWidth)"
40//
41// The allowed operations are: +, -, *, /
42//
43// Warning: There is no priority rule build in. So better use brackets
44// to get correct results. The rule is parsed/evaluated from the left
45// to the right, which means:
46//
47// "MHillas.fWidth + MHillas.fLength / HillasSource.fDist"
48//
49// is parses as
50//
51// "(MHillas.fWidth + MHillas.fLength) / HillasSource.fDist"
52//
53// You can also use mathmatical operators, eg:
54// "5*log10(MMcEvt.fEnergy*MHillas.fSize)"
55//
56// The allowed operators are:
57// exp(x) e^x
58// log(x) natural logarithm of x
59// pow10(x) 10^x
60// log10(x) logarithm of x to base ten
61// cos(x) cosine of x
62// sin(x) sine of x
63// tan(x) tangent of x
64// cosh(x) hyperbolic cosine of x
65// sinh(x) hyperbolic sine of x
66// tanh(x) hyperbolic tangent of x
67// acos(x) arc cosine (inverse cosine) of x
68// asin(x) arc sine (inverse sine) of x
69// atan(x) arc tangent (inverse tangent) of x
70// sqrt(x) square root of x
71// sqr(x) square of x
72// abs(x) absolute value of x, |x|
73// floor(x) round down to the nearest integer (floor(9.9)=9)
74//
75//
76// FIXME: The possibility to use other objects inheriting from MData
77// is missing.
78// Maybe we can use gInterpreter->Calc("") for this.
79// gROOT->ProcessLineFast("line");
80//
81/////////////////////////////////////////////////////////////////////////////
82
83#include "MDataChain.h"
84
85#include <math.h> // fabs on Alpha
86#include <ctype.h> // isalnum, ...
87#include <stdlib.h> // strtod, ...
88
89#include "MLog.h"
90#include "MLogManip.h"
91
92#include "MDataList.h"
93#include "MDataValue.h"
94#include "MDataMember.h"
95#include "MDataElement.h"
96
97ClassImp(MDataChain);
98
99// --------------------------------------------------------------------------
100//
101// Constructor which takes a rule and a surrounding operator as argument
102//
103MDataChain::MDataChain(const char *rule, OperatorType_t op)
104 : fOperatorType(op)
105{
106 fName = "MDataChain";
107 fTitle = rule;
108
109 fMember=ParseString(rule, 1);
110}
111
112// --------------------------------------------------------------------------
113//
114// Default constructor
115//
116MDataChain::MDataChain()
117 : fMember(NULL), fOperatorType(kENoop)
118{
119}
120
121// --------------------------------------------------------------------------
122//
123// Constructor taking a rule as an argument. For more details see
124// class description
125//
126MDataChain::MDataChain(const char *rule, const char *name, const char *title)
127 : fOperatorType(kENoop)
128{
129 fName = name ? name : "MDataChain";
130 fTitle = title ? title : rule;
131
132 *fLog << inf << "Trying to resolve rule... " << flush;
133 if (!(fMember=ParseString(rule, 1)))
134 {
135 *fLog << err << dbginf << "Parsing '" << rule << "' failed." << endl;
136 return;
137 }
138 *fLog << inf << "found: " << flush;
139 fMember->Print();
140 *fLog << endl;
141}
142
143// --------------------------------------------------------------------------
144//
145// PreProcesses all members in the list
146//
147Bool_t MDataChain::PreProcess(const MParList *pList)
148{
149 return fMember ? fMember->PreProcess(pList) : kFALSE;
150}
151
152// --------------------------------------------------------------------------
153//
154// Checks whether at least one member has the ready-to-save flag.
155//
156Bool_t MDataChain::IsReadyToSave() const
157{
158 *fLog << all << "fM=" << fMember << "/" << (int)fMember->IsReadyToSave() << " " << endl;
159 return fMember ? fMember->IsReadyToSave() : kFALSE;
160}
161
162// --------------------------------------------------------------------------
163//
164// Destructor. Delete filters.
165//
166MDataChain::~MDataChain()
167{
168 if (fMember)
169 delete fMember;
170}
171
172// --------------------------------------------------------------------------
173//
174// Returns the number of alphanumeric characters (including '.')
175// in the given string
176//
177Int_t MDataChain::IsAlNum(TString txt)
178{
179 int l = txt.Length();
180 for (int i=0; i<l; i++)
181 {
182 if (!isalnum(txt[i]) && txt[i]!='.' && /*txt[i]!='['&&txt[i]!=']'&&*/
183 ((txt[i]!='-' && txt[i]!='+') || i!=0))
184 return i;
185 }
186
187 return l;
188}
189
190Int_t MDataChain::GetBracket(TString txt, char open, char close)
191{
192 Int_t first=1;
193 for (int cnt=0; first<txt.Length(); first++)
194 {
195 if (txt[first]==open)
196 cnt++;
197 if (txt[first]==close)
198 cnt--;
199 if (cnt==-1)
200 break;
201 }
202 return first;
203}
204
205// --------------------------------------------------------------------------
206//
207// Compare a given text with the known operators. If no operator match
208// kENoop is retunred, otherwise the corresponding OperatorType_t
209//
210MDataChain::OperatorType_t MDataChain::ParseOperator(TString txt) const
211{
212 txt.ToLower();
213
214 if (txt=="abs") return kEAbs;
215 if (txt=="fabs") return kEAbs;
216 if (txt=="log") return kELog;
217 if (txt=="log10") return kELog10;
218 if (txt=="sin") return kESin;
219 if (txt=="cos") return kECos;
220 if (txt=="tan") return kETan;
221 if (txt=="sinh") return kESinH;
222 if (txt=="cosh") return kECosH;
223 if (txt=="tanh") return kETanH;
224 if (txt=="asin") return kEASin;
225 if (txt=="acos") return kEACos;
226 if (txt=="atan") return kEATan;
227 if (txt=="sqrt") return kESqrt;
228 if (txt=="sqr") return kESqr;
229 if (txt=="exp") return kEExp;
230 if (txt=="pow10") return kEPow10;
231 if (txt=="sgn") return kESgn;
232 if (txt=="floor") return kEFloor;
233 if (txt[0]=='-') return kENegative;
234 if (txt[0]=='+') return kEPositive;
235
236 return kENoop;
237}
238
239// --------------------------------------------------------------------------
240//
241// Core of the data chain. Here the chain is constructed out of the rule.
242//
243MData *MDataChain::ParseString(TString txt, Int_t level)
244{
245 MData *member0=NULL;
246
247 char type=0;
248 int nlist = 0;
249
250 while (!txt.IsNull())
251 {
252 MData *newmember = NULL;
253
254 txt = txt.Strip(TString::kBoth);
255
256 switch (txt[0])
257 {
258 case '(':
259 {
260 //
261 // Search for the corresponding bracket
262 //
263 Int_t first=GetBracket(txt, '(', ')');
264
265 if (first==txt.Length())
266 {
267 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
268 if (member0)
269 delete member0;
270 return NULL;
271 }
272
273 //
274 // Make a copy of the 'interieur' and delete the substringä
275 // including the brackets
276 //
277 TString sub = txt(1, first-1);
278 txt.Remove(0, first+1);
279
280 //
281 // Parse the substring
282 //
283 newmember = ParseString(sub, level+1);
284 if (!newmember)
285 {
286 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
287 if (member0)
288 delete member0;
289 return NULL;
290 }
291 }
292 break;
293
294 case ')':
295 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
296 if (member0)
297 delete member0;
298 return NULL;
299
300 case '+':
301 case '-':
302 case '*':
303 case '/':
304 if (member0)
305 {
306 //
307 // Check for the type of the symbol
308 //
309 char is = txt[0];
310 txt.Remove(0, 1);
311
312 //
313 // If no filter is available or the available filter
314 // is of a different symbols we have to create a new
315 // data list with the new symbol
316 //
317 if (/*!member0->InheritsFrom(MDataMember::Class()) ||*/ type!=is)
318 {
319 MDataList *list = new MDataList(is);
320 list->SetName(Form("List_%c_%d", is, 10*level+nlist++));
321
322 list->SetOwner();
323 list->AddToList(member0);
324
325 member0 = list;
326
327 type = is;
328 }
329 continue;
330 }
331
332 if (txt[0]!='-' && txt[0]!='+')
333 {
334 *fLog << err << dbginf << "Syntax Error: First argument of symbol '";
335 *fLog << txt[0] << "' missing." << endl;
336 if (member0)
337 delete member0;
338 return NULL;
339 }
340
341 // FALLTHROU
342
343 case '0':
344 case '1':
345 case '2':
346 case '3':
347 case '4':
348 case '5':
349 case '6':
350 case '7':
351 case '8':
352 case '9':
353 if ((txt[0]!='-' && txt[0]!='+') || isdigit(txt[1]) || txt[1]=='.')
354 {
355 char *end;
356 Double_t num = strtod(txt.Data(), &end);
357 if (!end || txt.Data()==end)
358 {
359 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
360 if (member0)
361 delete member0;
362 return NULL;
363 }
364
365 txt.Remove(0, end-txt.Data());
366
367 newmember = new MDataValue(num);
368 break;
369 }
370
371 // FALLTHROUH
372
373 default:
374 int i = IsAlNum(txt);
375
376 if (i==0)
377 {
378 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
379 if (member0)
380 delete member0;
381 return NULL;
382 }
383
384 TString text = txt(0, i);
385
386 txt.Remove(0, i);
387 txt = txt.Strip(TString::kBoth);
388
389 if (!txt.IsNull() && txt[0]=='[')
390 {
391 Int_t first = GetBracket(txt, '[', ']');
392 TString op = txt(1, first-1);
393 txt.Remove(0, first+1);
394
395 newmember = new MDataElement(text, atoi(op));
396 break;
397 }
398 if ((txt.IsNull() || txt[0]!='(') && text[0]!='-' && text[0]!='+')
399 {
400 newmember = new MDataMember(text.Data());
401 break;
402 }
403
404 OperatorType_t op = ParseOperator(text);
405 if (op==kENoop)
406 {
407 *fLog << err << dbginf << "Syntax Error: Operator '" << text << "' unknown." << endl;
408 if (member0)
409 delete member0;
410 return NULL;
411 }
412
413 Int_t first = GetBracket(txt, '(', ')');
414 TString sub = op==kENegative || op==kEPositive ? text.Remove(0,1) + txt : txt(1, first-1);
415 txt.Remove(0, first+1);
416
417 newmember = new MDataChain(sub, op);
418 if (!newmember->IsValid())
419 {
420 *fLog << err << dbginf << "Syntax Error: Error parsing contents '" << sub << "' of operator " << text << endl;
421 delete newmember;
422 if (member0)
423 delete member0;
424 return NULL;
425 }
426 }
427
428 if (!member0)
429 {
430 member0 = newmember;
431 continue;
432 }
433
434 if (!member0->InheritsFrom(MDataList::Class()))
435 continue;
436
437 ((MDataList*)member0)->AddToList(newmember);
438 }
439
440 return member0;
441}
442
443// --------------------------------------------------------------------------
444//
445// Returns the value described by the rule
446//
447Double_t MDataChain::GetValue() const
448{
449 if (!fMember)
450 {
451 *fLog << warn << "MDataChain not valid." << endl;
452 return 0;
453 }
454
455 const Double_t val = fMember->GetValue();
456
457 switch (fOperatorType)
458 {
459 case kEAbs: return fabs(val);
460 case kELog: return log(val);
461 case kELog10: return log10(val);
462 case kESin: return sin(val);
463 case kECos: return cos(val);
464 case kETan: return tan(val);
465 case kESinH: return sinh(val);
466 case kECosH: return cosh(val);
467 case kETanH: return tanh(val);
468 case kEASin: return asin(val);
469 case kEACos: return acos(val);
470 case kEATan: return atan(val);
471 case kESqrt: return sqrt(val);
472 case kESqr: return val*val;
473 case kEExp: return exp(val);
474 case kEPow10: return pow(10, val);
475 case kESgn: return val<0 ? -1 : 1;
476 case kENegative: return -val;
477 case kEPositive: return val;
478 case kEFloor: return floor(val);
479 case kENoop: return val;
480 }
481
482 *fLog << warn << "No Case for " << fOperatorType << " available." << endl;
483
484 return 0;
485}
486
487 /*
488void MDataChain::Print(Option_t *opt) const
489{
490 *fLog << GetRule() << flush;
491 Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class());
492
493 switch (fOperatorType)
494 {
495 case kEAbs: *fLog << "abs" << flush; break;
496 case kELog: *fLog << "log" << flush; break;
497 case kELog10: *fLog << "log10" << flush; break;
498 case kESin: *fLog << "sin" << flush; break;
499 case kECos: *fLog << "cos" << flush; break;
500 case kETan: *fLog << "tan" << flush; break;
501 case kESinH: *fLog << "sinh" << flush; break;
502 case kECosH: *fLog << "cosh" << flush; break;
503 case kETanH: *fLog << "tanh" << flush; break;
504 case kEASin: *fLog << "asin" << flush; break;
505 case kEACos: *fLog << "acos" << flush; break;
506 case kEATan: *fLog << "atan" << flush; break;
507 case kESqrt: *fLog << "sqrt" << flush; break;
508 case kEExp: *fLog << "exp" << flush; break;
509 case kEPow10: *fLog << "pow10" << flush; break;
510 case kESgn: *fLog << "sgn" << flush; break;
511 case kENegative: *fLog << "-" << flush; break;
512 case kEPositive: *fLog << "+" << flush; break;
513 case kENoop:
514 break;
515 }
516
517 if (bracket)
518 *fLog << "(" << flush;
519
520 fMember->Print();
521
522 if (bracket)
523 *fLog << ")" << flush;
524 }
525 */
526
527// --------------------------------------------------------------------------
528//
529// Builds a rule from all the chain members. This is a rule which could
530// be used to rebuild the chain.
531//
532TString MDataChain::GetRule() const
533{
534 if (!fMember)
535 return "<n/a>";
536
537 TString str;
538
539 Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class());
540
541 switch (fOperatorType)
542 {
543 case kEAbs: str += "abs" ; break;
544 case kELog: str += "log" ; break;
545 case kELog10: str += "log10"; break;
546 case kESin: str += "sin" ; break;
547 case kECos: str += "cos" ; break;
548 case kETan: str += "tan" ; break;
549 case kESinH: str += "sinh" ; break;
550 case kECosH: str += "cosh" ; break;
551 case kETanH: str += "tanh" ; break;
552 case kEASin: str += "asin" ; break;
553 case kEACos: str += "acos" ; break;
554 case kEATan: str += "atan" ; break;
555 case kESqrt: str += "sqrt" ; break;
556 case kESqr: str += "sqr" ; break;
557 case kEExp: str += "exp" ; break;
558 case kEPow10: str += "pow10"; break;
559 case kESgn: str += "sgn" ; break;
560 case kENegative: str += "-" ; break;
561 case kEPositive: str += "+" ; break;
562 case kEFloor: str += "floor"; break;
563 case kENoop:
564 break;
565 }
566
567 if (bracket)
568 str += "(";
569
570 str += fMember->GetRule();
571
572 if (bracket)
573 str += ")";
574
575 return str;
576}
577
578// --------------------------------------------------------------------------
579//
580// Return a comma seperated list of all data members used in the chain.
581// This is mainly used in MTask::AddToBranchList
582//
583TString MDataChain::GetDataMember() const
584{
585 return fMember->GetDataMember();
586}
Note: See TracBrowser for help on using the repository browser.