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

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