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

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