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

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