source: trunk/MagicSoft/Mars/mfilter/MF.cc@ 2194

Last change on this file since 2194 was 2173, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 12.2 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 01/2002 <mailto:tbretz@uni-sw.gwdg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MF
28//
29// With this filter you can filter in all variables from Mars parameter
30// containers.
31//
32// In the constructor you can give the filter rule, like
33// "MHillas.fLength < 15"
34// Where MHillas is the name of the parameter container in the parameter
35// list and fLength is the name of the data member which should be used
36// for the filter rule. If the name of the container is use specified
37// (MyHillas) the name to give would be:
38// "MyHillas.fLength < 15"
39//
40// Also more difficult rules are allowed, like:
41// "MHillas.fWidth<0.5 && MHillas.fLength<0.6"
42//
43// You can also use brackets:
44// "MHillas.fSize>200 || (MHillas.fWidth<0.5 && MHillas.fLength<0.6)"
45//
46// If you want to use mathematic expressions (as defined in MDataChain)
47// you must encapsulate it in {}-Brackets, eg:
48// "{log10(MHillas.fSize)}>3"
49//
50// The allowed logigal conditionals are:
51// &&: logical and
52// ||: logical or
53// ^: exclusive or
54//
55// As conditional signs, for now, only:
56// <, >
57// are allowed.
58//
59//
60// Warning: There is no priority rule build in. So better use brackets
61// to get correct results. The rule is parsed/evaluated from the left
62// to the right, which means:
63//
64// "MHillas.fSize>200 || MHillas.fWidth<0.5 && MHillas.fLength<0.6"
65//
66// is parses as
67//
68// "(MHillas.fSize>200 || MHillas.fWidth<0.5) && MHillas.fLength<0.6"
69//
70//
71// If you intend to use Data Chains in filters enclose the chains in
72// this {}-parenthesis, eg.
73//
74// "{MHillas.fSize*MHillas.fWidth}<0.5"
75//
76// FIXME: The possibility to use also complete filters is missing.
77// Maybe we can use gInterpreter->Calc("") for this.
78// gROOT->ProcessLineFast("line");
79//
80/////////////////////////////////////////////////////////////////////////////
81#include "MF.h"
82
83#include <ctype.h> // isalnum, ...
84#include <stdlib.h> // strtod, ...
85#include <fstream> // ofstream, ...
86
87#include <TMethodCall.h>
88
89#include "MParList.h"
90
91#include "MFilterList.h"
92#include "MFDataChain.h"
93#include "MFDataMember.h"
94
95#include "MLog.h"
96#include "MLogManip.h"
97
98ClassImp(MF);
99
100using namespace std;
101
102const TString MF::gsDefName = "MF";
103const TString MF::gsDefTitle = "Filter setup by a text-rule";
104
105// --------------------------------------------------------------------------
106//
107// Default Constructor. Don't use.
108//
109MF::MF() : fF(NULL)
110{
111 fName = gsDefName.Data();
112 fTitle = gsDefTitle.Data();
113}
114
115// --------------------------------------------------------------------------
116//
117// Constructor. For the text describing the filter rule please see
118// the class description above.
119//
120MF::MF(const char *text, const char *name, const char *title)
121{
122 fName = name ? name : gsDefName.Data();
123 fTitle = title ? title : gsDefTitle.Data();
124
125 *fLog << inf << "Trying to resolve filter rule..." << endl;
126 if (!(fF=ParseString(text, 1)))
127 {
128 *fLog << err << dbginf << "Parsing '" << text << "' failed." << endl;
129 return;
130 }
131
132 *fLog << inf << endl;
133 *fLog << "Using Filter rule " << fF->GetName();
134 *fLog << " for " << fName << ":" << endl;
135 fF->Print();
136 *fLog << endl << endl;
137}
138
139// --------------------------------------------------------------------------
140//
141// Destructor. Delete filters.
142//
143MF::~MF()
144{
145 if (fF)
146 delete fF;
147}
148
149// --------------------------------------------------------------------------
150//
151// Returns the number of alphanumeric characters (including '.')
152// in the given string
153//
154Int_t MF::IsAlNum(TString txt) const
155{
156 int l = txt.Length();
157 for (int i = 0; i<l; i++)
158 if (!isalnum(txt[i]) && txt[i]!='.')
159 return i;
160
161 return l;
162}
163
164MFilter *MF::ParseRule(TString &txt, MFilter *filter0, Int_t level) const
165{
166 TString text;
167
168 Bool_t isrule = kFALSE;
169
170 if (txt[0]=='{')
171 {
172 //
173 // Search for the corresponding bracket
174 //
175 Int_t first=1;
176 for (int cnt=0; first<txt.Length(); first++)
177 {
178 if (txt[first]=='{')
179 cnt++;
180 if (txt[first]=='}')
181 cnt--;
182
183 if (cnt==-1)
184 break;
185 }
186
187 if (first==txt.Length())
188 {
189 *fLog << err << dbginf << "Syntax Error: '}' missing." << endl;
190 return NULL;
191 }
192
193 //
194 // Make a copy of the 'interieur' and delete the substringä
195 // including the brackets
196 //
197 TString sub = txt(1, first-1);
198 txt.Remove(0, first+1);
199
200 text=sub;
201 isrule = kTRUE;
202 }
203 else
204 {
205 int i = IsAlNum(txt);
206
207 if (i==0)
208 {
209 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
210 return NULL;
211 }
212
213 text = txt(0, i);
214
215 txt.Remove(0, i);
216 }
217
218 txt = txt.Strip(TString::kBoth);
219
220 if (txt.IsNull())
221 {
222 *fLog << err << dbginf << "Syntax Error: No conditional in '" << text << "'" << endl;
223 return NULL;
224 }
225
226 char c;
227 switch (txt[0])
228 {
229 case '>':
230 case '<':
231 c = txt[0];
232 txt.Remove(0, 1);
233 break;
234
235 default:
236 *fLog << err << dbginf << "Syntax Error: Conditional '" << txt[0] << "' unknown." << endl;
237 return NULL;
238 }
239
240 char *end;
241 Double_t num = strtod(txt.Data(), &end);
242 if (!end || txt.Data()==end)
243 {
244 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
245 return NULL;
246 }
247
248 txt.Remove(0, end-txt.Data());
249
250 MFilter *newfilter;
251 if (isrule)
252 {
253 Int_t lvl = gLog.GetDebugLevel();
254 gLog.SetDebugLevel(1);
255 newfilter = new MFDataChain(text.Data(), c, num);
256 newfilter->SetName(Form("Chain%02d%c%f", level, c, num));
257 gLog.SetDebugLevel(lvl);
258 }
259 else
260 {
261 newfilter = new MFDataMember(text.Data(), c, num);
262 newfilter->SetName(Form("%s%c%f", text.Data(), c, num));
263 }
264
265 return newfilter;
266}
267// --------------------------------------------------------------------------
268//
269// Parse a text string. Returns a corresponding filter of filter list.
270//
271MFilter *MF::ParseString(TString txt, Int_t level)
272{
273 MFilter *filter0=NULL;
274
275 TString type;
276 int nlist = 0;
277
278 while (!txt.IsNull())
279 {
280 MFilter *newfilter = NULL;
281
282 txt = txt.Strip(TString::kBoth);
283
284 //*fLog << all << setw(level) << " " << "Text: " << level << " '" << txt << "'" << endl;
285
286 switch (txt[0])
287 {
288 case '(':
289 {
290 //
291 // Search for the corresponding bracket
292 //
293 Int_t first=1;
294 for (int cnt=0; first<txt.Length(); first++)
295 {
296 if (txt[first]=='(')
297 cnt++;
298 if (txt[first]==')')
299 cnt--;
300
301 if (cnt==-1)
302 break;
303 }
304
305 if (first==txt.Length())
306 {
307 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
308 if (filter0)
309 delete filter0;
310 return NULL;
311 }
312
313 //
314 // Make a copy of the 'interieur' and delete the substringä
315 // including the brackets
316 //
317 TString sub = txt(1, first-1);
318 txt.Remove(0, first+1);
319
320 //
321 // Parse the substring
322 //
323 newfilter = ParseString(sub, level+1);
324 if (!newfilter)
325 {
326 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
327 if (filter0)
328 delete filter0;
329 return NULL;
330 }
331 }
332 break;
333
334 case ')':
335 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
336 if (filter0)
337 delete filter0;
338 return NULL;
339
340
341 case '&':
342 case '|':
343 case '^':
344 if (filter0)
345 {
346 //
347 // Check for the type of the conditional
348 //
349 TString is = txt[0];
350 txt.Remove(0, 1);
351
352 if (is==txt[0] && is!='^')
353 {
354 is += txt[0];
355 txt.Remove(0, 1);
356 }
357
358 //
359 // If no filter is available or the available filter
360 // is of a different conditional we have to create a new
361 // filter list with the new conditional
362 //
363 if (!filter0->InheritsFrom(MFilterList::Class()) || type!=is)
364 {
365 MFilterList *list = new MFilterList(is);
366 list->SetName(Form("List_%s_%d", (const char*)is, 10*level+nlist++));
367
368 list->SetOwner();
369 list->AddToList(filter0);
370 filter0 = list;
371
372 type = is;
373 }
374 continue;
375 }
376
377 *fLog << err << dbginf << "Syntax Error: First argument of condition missing." << endl;
378 if (filter0)
379 delete filter0;
380 return NULL;
381
382 default:
383 newfilter = ParseRule(txt, filter0, level++);
384 if (!newfilter)
385 {
386 if (filter0)
387 delete filter0;
388 return NULL;
389 }
390 }
391
392 if (!filter0)
393 {
394 filter0 = newfilter;
395 continue;
396 }
397
398 if (!filter0->InheritsFrom(MFilterList::Class()))
399 continue;
400
401 ((MFilterList*)filter0)->AddToList(newfilter);
402 }
403
404 return filter0;
405}
406
407// --------------------------------------------------------------------------
408//
409// PreProcess all filters.
410//
411Bool_t MF::PreProcess(MParList *plist)
412{
413 if (!fF)
414 {
415 *fLog << err << dbginf << "No filter rule available." << endl;
416 return kFALSE;
417 }
418
419 if (!fF->CallPreProcess(plist))
420 {
421 *fLog << err << dbginf << "PreProcessing filters in ";
422 *fLog << fName << " failed." << endl;
423 return kFALSE;
424 }
425
426 return kTRUE;
427}
428
429// --------------------------------------------------------------------------
430//
431// Process all filters.
432//
433Bool_t MF::Process()
434{
435 return fF->CallProcess();
436}
437
438// --------------------------------------------------------------------------
439//
440// Postprocess all filters.
441//
442Bool_t MF::PostProcess()
443{
444 return fF->CallPostProcess();
445}
446
447// --------------------------------------------------------------------------
448//
449// Return the result of the filter rule.
450//
451Bool_t MF::IsExpressionTrue() const
452{
453 return fF->IsConditionTrue();
454}
455
456void MF::StreamPrimitive(ofstream &out) const
457{
458 out << " MF " << GetUniqueName();
459
460 if (!fF)
461 {
462 out << ";" << endl;
463 return;
464 }
465
466 out << "(\"" << fF->GetRule() << "\"";
467 if (fName!=gsDefName || fTitle!=gsDefTitle)
468 {
469 out << "(\"" << fName << "\"";
470 if (fTitle!=gsDefTitle)
471 out << ", \"" << fTitle << "\"";
472 }
473 out << ");" << endl;
474
475}
476
477void MF::Print(Option_t *opt) const
478{
479 *fLog << all << underline << GetDescriptor() << endl;
480 fF->Print();
481 *fLog << endl << endl;
482}
Note: See TracBrowser for help on using the repository browser.