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

Last change on this file since 1555 was 1524, checked in by tbretz, 23 years ago
*** empty log message ***
File size: 15.4 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@uni-sw.gwdg.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// abs(x) absolute value of x, |x|
72//
73//
74// FIXME: The possibility to use other objects inheriting from MData
75// is missing.
76// Maybe we can use gInterpreter->Calc("") for this.
77// gROOT->ProcessLineFast("line");
78//
79/////////////////////////////////////////////////////////////////////////////
80
81#include "MDataChain.h"
82
83#include <math.h> // fabs on Alpha
84#include <ctype.h> // isalnum, ...
85#include <stdlib.h> // strtod, ...
86
87#include "MLog.h"
88#include "MLogManip.h"
89
90#include "MDataList.h"
91#include "MDataValue.h"
92#include "MDataMember.h"
93#include "MDataElement.h"
94
95ClassImp(MDataChain);
96
97MDataChain::MDataChain(const char *rule, OperatorType_t op)
98 : fOperatorType(op)
99{
100 fName = "MDataChain";
101 fTitle = rule;
102
103 fMember=ParseString(rule, 1);
104}
105
106MDataChain::MDataChain()
107 : fMember(NULL), fOperatorType(kENoop)
108{
109}
110
111MDataChain::MDataChain(const char *rule, const char *name, const char *title)
112 : fOperatorType(kENoop)
113{
114 fName = name ? name : "MDataChain";
115 fTitle = title ? title : rule;
116
117 *fLog << inf << "Trying to resolve rule... " << flush;
118 if (!(fMember=ParseString(rule, 1)))
119 {
120 *fLog << err << dbginf << "Parsing '" << rule << "' failed." << endl;
121 return;
122 }
123 *fLog << inf << "found: " << flush;
124 fMember->Print();
125 *fLog << endl;
126}
127
128// --------------------------------------------------------------------------
129//
130// PreProcesses all members in the list
131//
132Bool_t MDataChain::PreProcess(const MParList *pList)
133{
134 return fMember ? fMember->PreProcess(pList) : kFALSE;
135}
136
137// --------------------------------------------------------------------------
138//
139// Checks whether at least one member has the ready-to-save flag.
140//
141Bool_t MDataChain::IsReadyToSave() const
142{
143 *fLog << all << "fM=" << fMember << "/" << (int)fMember->IsReadyToSave() << " " << endl;
144 return fMember ? fMember->IsReadyToSave() : kFALSE;
145}
146
147// --------------------------------------------------------------------------
148//
149// Destructor. Delete filters.
150//
151MDataChain::~MDataChain()
152{
153 if (fMember)
154 delete fMember;
155}
156
157// --------------------------------------------------------------------------
158//
159// Returns the number of alphanumeric characters (including '.')
160// in the given string
161//
162Int_t MDataChain::IsAlNum(TString txt)
163{
164 int l = txt.Length();
165 for (int i=0; i<l; i++)
166 {
167 if (!isalnum(txt[i]) && txt[i]!='.' && /*txt[i]!='['&&txt[i]!=']'&&*/
168 ((txt[i]!='-' && txt[i]!='+') || i!=0))
169 return i;
170 }
171
172 return l;
173}
174
175Int_t MDataChain::GetBracket(TString txt, char open, char close)
176{
177 Int_t first=1;
178 for (int cnt=0; first<txt.Length(); first++)
179 {
180 if (txt[first]==open)
181 cnt++;
182 if (txt[first]==close)
183 cnt--;
184 if (cnt==-1)
185 break;
186 }
187 return first;
188}
189
190// --------------------------------------------------------------------------
191//
192// Compare a given text with the known operators. If no operator match
193// kENoop is retunred, otherwise the corresponding OperatorType_t
194//
195MDataChain::OperatorType_t MDataChain::ParseOperator(TString txt) const
196{
197 txt.ToLower();
198
199 if (txt=="abs") return kEAbs;
200 if (txt=="fabs") return kEAbs;
201 if (txt=="log") return kELog;
202 if (txt=="log10") return kELog10;
203 if (txt=="sin") return kESin;
204 if (txt=="cos") return kECos;
205 if (txt=="tan") return kETan;
206 if (txt=="sinh") return kESinH;
207 if (txt=="cosh") return kECosH;
208 if (txt=="tanh") return kETanH;
209 if (txt=="asin") return kEASin;
210 if (txt=="acos") return kEACos;
211 if (txt=="atan") return kEATan;
212 if (txt=="sqrt") return kESqrt;
213 if (txt=="exp") return kEExp;
214 if (txt=="pow10") return kEPow10;
215 if (txt=="sgn") return kESgn;
216 if (txt[0]=='-') return kENegative;
217 if (txt[0]=='+') return kEPositive;
218
219 return kENoop;
220}
221
222MData *MDataChain::ParseString(TString txt, Int_t level)
223{
224 MData *member0=NULL;
225
226 char type=0;
227 int nlist = 0;
228
229 while (!txt.IsNull())
230 {
231 MData *newmember = NULL;
232
233 txt = txt.Strip(TString::kBoth);
234
235 switch (txt[0])
236 {
237 case '(':
238 {
239 //
240 // Search for the corresponding bracket
241 //
242 Int_t first=GetBracket(txt, '(', ')');
243
244 if (first==txt.Length())
245 {
246 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
247 if (member0)
248 delete member0;
249 return NULL;
250 }
251
252 //
253 // Make a copy of the 'interieur' and delete the substringä
254 // including the brackets
255 //
256 TString sub = txt(1, first-1);
257 txt.Remove(0, first+1);
258
259 //
260 // Parse the substring
261 //
262 newmember = ParseString(sub, level+1);
263 if (!newmember)
264 {
265 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
266 if (member0)
267 delete member0;
268 return NULL;
269 }
270 }
271 break;
272
273 case ')':
274 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
275 if (member0)
276 delete member0;
277 return NULL;
278
279 case '+':
280 case '-':
281 case '*':
282 case '/':
283 if (member0)
284 {
285 //
286 // Check for the type of the symbol
287 //
288 char is = txt[0];
289 txt.Remove(0, 1);
290
291 //
292 // If no filter is available or the available filter
293 // is of a different symbols we have to create a new
294 // data list with the new symbol
295 //
296 if (/*!member0->InheritsFrom(MDataMember::Class()) ||*/ type!=is)
297 {
298 MDataList *list = new MDataList(is);
299 list->SetName(Form("List_%c_%d", is, 10*level+nlist++));
300
301 list->SetOwner();
302 list->AddToList(member0);
303
304 member0 = list;
305
306 type = is;
307 }
308 continue;
309 }
310
311 if (txt[0]!='-' && txt[0]!='+')
312 {
313 *fLog << err << dbginf << "Syntax Error: First argument of symbol '";
314 *fLog << txt[0] << "' missing." << endl;
315 if (member0)
316 delete member0;
317 return NULL;
318 }
319
320 // FALLTHROU
321
322 case '0':
323 case '1':
324 case '2':
325 case '3':
326 case '4':
327 case '5':
328 case '6':
329 case '7':
330 case '8':
331 case '9':
332 if ((txt[0]!='-' && txt[0]!='+') || isdigit(txt[1]) || txt[1]=='.')
333 {
334 char *end;
335 Double_t num = strtod(txt.Data(), &end);
336 if (!end || txt.Data()==end)
337 {
338 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
339 if (member0)
340 delete member0;
341 return NULL;
342 }
343
344 txt.Remove(0, end-txt.Data());
345
346 newmember = new MDataValue(num);
347 break;
348 }
349
350 // FALLTHROUH
351
352 default:
353 int i = IsAlNum(txt);
354
355 if (i==0)
356 {
357 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
358 if (member0)
359 delete member0;
360 return NULL;
361 }
362
363 TString text = txt(0, i);
364
365 txt.Remove(0, i);
366 txt = txt.Strip(TString::kBoth);
367
368 if (!txt.IsNull() && txt[0]=='[')
369 {
370 Int_t first = GetBracket(txt, '[', ']');
371 TString op = txt(1, first-1);
372 txt.Remove(0, first+1);
373
374 newmember = new MDataElement(text, atoi(op));
375 break;
376 }
377 if ((txt.IsNull() || txt[0]!='(') && text[0]!='-' && text[0]!='+')
378 {
379 newmember = new MDataMember(text.Data());
380 break;
381 }
382
383 OperatorType_t op = ParseOperator(text);
384 if (op==kENoop)
385 {
386 *fLog << err << dbginf << "Syntax Error: Operator '" << text << "' unknown." << endl;
387 if (member0)
388 delete member0;
389 return NULL;
390 }
391
392 Int_t first = GetBracket(txt, '(', ')');
393 TString sub = op==kENegative || op==kEPositive ? text.Remove(0,1) + txt : txt(1, first-1);
394 txt.Remove(0, first+1);
395
396 newmember = new MDataChain(sub, op);
397 if (!newmember->IsValid())
398 {
399 *fLog << err << dbginf << "Syntax Error: Error parsing contents '" << sub << "' of operator " << text << endl;
400 delete newmember;
401 if (member0)
402 delete member0;
403 return NULL;
404 }
405 }
406
407 if (!member0)
408 {
409 member0 = newmember;
410 continue;
411 }
412
413 if (!member0->InheritsFrom(MDataList::Class()))
414 continue;
415
416 ((MDataList*)member0)->AddToList(newmember);
417 }
418
419 return member0;
420}
421
422Double_t MDataChain::GetValue() const
423{
424 if (!fMember)
425 {
426 *fLog << warn << "MDataChain not valid." << endl;
427 return 0;
428 }
429
430 const Double_t val = fMember->GetValue();
431
432 switch (fOperatorType)
433 {
434 case kEAbs: return fabs(val);
435 case kELog: return log(val);
436 case kELog10: return log10(val);
437 case kESin: return sin(val);
438 case kECos: return cos(val);
439 case kETan: return tan(val);
440 case kESinH: return sinh(val);
441 case kECosH: return cosh(val);
442 case kETanH: return tanh(val);
443 case kEASin: return asin(val);
444 case kEACos: return acos(val);
445 case kEATan: return atan(val);
446 case kESqrt: return sqrt(val);
447 case kEExp: return exp(val);
448 case kEPow10: return pow(10, val);
449 case kESgn: return val<0 ? -1 : 1;
450 case kENegative: return -val;
451 case kEPositive: return val;
452 case kENoop: return val;
453 }
454
455 *fLog << warn << "No Case for " << fOperatorType << " available." << endl;
456
457 return 0;
458}
459
460 /*
461void MDataChain::Print(Option_t *opt) const
462{
463 *fLog << GetRule() << flush;
464 Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class());
465
466 switch (fOperatorType)
467 {
468 case kEAbs: *fLog << "abs" << flush; break;
469 case kELog: *fLog << "log" << flush; break;
470 case kELog10: *fLog << "log10" << flush; break;
471 case kESin: *fLog << "sin" << flush; break;
472 case kECos: *fLog << "cos" << flush; break;
473 case kETan: *fLog << "tan" << flush; break;
474 case kESinH: *fLog << "sinh" << flush; break;
475 case kECosH: *fLog << "cosh" << flush; break;
476 case kETanH: *fLog << "tanh" << flush; break;
477 case kEASin: *fLog << "asin" << flush; break;
478 case kEACos: *fLog << "acos" << flush; break;
479 case kEATan: *fLog << "atan" << flush; break;
480 case kESqrt: *fLog << "sqrt" << flush; break;
481 case kEExp: *fLog << "exp" << flush; break;
482 case kEPow10: *fLog << "pow10" << flush; break;
483 case kESgn: *fLog << "sgn" << flush; break;
484 case kENegative: *fLog << "-" << flush; break;
485 case kEPositive: *fLog << "+" << flush; break;
486 case kENoop:
487 break;
488 }
489
490 if (bracket)
491 *fLog << "(" << flush;
492
493 fMember->Print();
494
495 if (bracket)
496 *fLog << ")" << flush;
497 }
498 */
499
500TString MDataChain::GetRule() const
501{
502 if (!fMember)
503 return "<n/a>";
504
505 TString str;
506
507 Bool_t bracket = fOperatorType!=kENoop && !fMember->InheritsFrom(MDataList::Class());
508
509 switch (fOperatorType)
510 {
511 case kEAbs: str += "abs" ; break;
512 case kELog: str += "log" ; break;
513 case kELog10: str += "log10"; break;
514 case kESin: str += "sin" ; break;
515 case kECos: str += "cos" ; break;
516 case kETan: str += "tan" ; break;
517 case kESinH: str += "sinh" ; break;
518 case kECosH: str += "cosh" ; break;
519 case kETanH: str += "tanh" ; break;
520 case kEASin: str += "asin" ; break;
521 case kEACos: str += "acos" ; break;
522 case kEATan: str += "atan" ; break;
523 case kESqrt: str += "sqrt" ; break;
524 case kEExp: str += "exp" ; break;
525 case kEPow10: str += "pow10"; break;
526 case kESgn: str += "sgn" ; break;
527 case kENegative: str += "-" ; break;
528 case kEPositive: str += "+" ; break;
529 case kENoop:
530 break;
531 }
532
533 if (bracket)
534 str += "(";
535
536 str += fMember->GetRule();
537
538 if (bracket)
539 str += ")";
540
541 return str;
542}
Note: See TracBrowser for help on using the repository browser.