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

Last change on this file since 1712 was 1668, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 12.0 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// FIXME: The possibility to use also complete filters is missing.
72// Maybe we can use gInterpreter->Calc("") for this.
73// gROOT->ProcessLineFast("line");
74//
75/////////////////////////////////////////////////////////////////////////////
76#include "MF.h"
77
78#include <ctype.h> // isalnum, ...
79#include <stdlib.h> // strtod, ...
80#include <fstream.h> // ofstream, ...
81
82#include <TMethodCall.h>
83
84#include "MParList.h"
85
86#include "MFilterList.h"
87#include "MFDataChain.h"
88#include "MFDataMember.h"
89
90#include "MLog.h"
91#include "MLogManip.h"
92
93ClassImp(MF);
94
95const TString MF::gsDefName = "MF";
96const TString MF::gsDefTitle = "Filter setup by a text-rule";
97
98// --------------------------------------------------------------------------
99//
100// Default Constructor. Don't use.
101//
102MF::MF() : fFilter(NULL)
103{
104 fName = gsDefName.Data();
105 fTitle = gsDefTitle.Data();
106}
107
108// --------------------------------------------------------------------------
109//
110// Constructor. For the text describing the filter rule please see
111// the class description above.
112//
113MF::MF(const char *text, const char *name, const char *title)
114{
115 fName = name ? name : gsDefName.Data();
116 fTitle = title ? title : gsDefTitle.Data();
117
118 *fLog << inf << "Trying to resolve filter rule..." << endl;
119 if (!(fFilter=ParseString(text, 1)))
120 {
121 *fLog << err << dbginf << "Parsing '" << text << "' failed." << endl;
122 return;
123 }
124
125 *fLog << inf << endl;
126 *fLog << "Using Filter rule " << fFilter->GetName();
127 *fLog << " for " << fName << ":" << endl;
128 fFilter->Print();
129 *fLog << endl << endl;
130}
131
132// --------------------------------------------------------------------------
133//
134// Destructor. Delete filters.
135//
136MF::~MF()
137{
138 if (fFilter)
139 delete fFilter;
140}
141
142// --------------------------------------------------------------------------
143//
144// Returns the number of alphanumeric characters (including '.')
145// in the given string
146//
147Int_t MF::IsAlNum(TString txt) const
148{
149 int l = txt.Length();
150 for (int i = 0; i<l; i++)
151 if (!isalnum(txt[i]) && txt[i]!='.')
152 return i;
153
154 return l;
155}
156
157MFilter *MF::ParseRule(TString &txt, MFilter *filter0, Int_t level) const
158{
159 TString text;
160
161 Bool_t isrule = kFALSE;
162
163 if (txt[0]=='{')
164 {
165 //
166 // Search for the corresponding bracket
167 //
168 Int_t first=1;
169 for (int cnt=0; first<txt.Length(); first++)
170 {
171 if (txt[first]=='{')
172 cnt++;
173 if (txt[first]=='}')
174 cnt--;
175
176 if (cnt==-1)
177 break;
178 }
179
180 if (first==txt.Length())
181 {
182 *fLog << err << dbginf << "Syntax Error: '}' missing." << endl;
183 return NULL;
184 }
185
186 //
187 // Make a copy of the 'interieur' and delete the substringä
188 // including the brackets
189 //
190 TString sub = txt(1, first-1);
191 txt.Remove(0, first+1);
192
193 text=sub;
194 isrule = kTRUE;
195 }
196 else
197 {
198 int i = IsAlNum(txt);
199
200 if (i==0)
201 {
202 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
203 return NULL;
204 }
205
206 text = txt(0, i);
207
208 txt.Remove(0, i);
209 }
210
211 txt = txt.Strip(TString::kBoth);
212
213 if (txt.IsNull())
214 {
215 *fLog << err << dbginf << "Syntax Error: No conditional in '" << text << "'" << endl;
216 return NULL;
217 }
218
219 char c;
220 switch (txt[0])
221 {
222 case '>':
223 case '<':
224 c = txt[0];
225 txt.Remove(0, 1);
226 break;
227
228 default:
229 *fLog << err << dbginf << "Syntax Error: Conditional '" << txt[0] << "' unknown." << endl;
230 return NULL;
231 }
232
233 char *end;
234 Double_t num = strtod(txt.Data(), &end);
235 if (!end || txt.Data()==end)
236 {
237 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
238 return NULL;
239 }
240
241 txt.Remove(0, end-txt.Data());
242
243 MFilter *newfilter;
244 if (isrule)
245 {
246 Int_t lvl = gLog.GetDebugLevel();
247 gLog.SetDebugLevel(1);
248 newfilter = new MFDataChain(text.Data(), c, num);
249 newfilter->SetName(Form("Chain%02d%c%f", level, c, num));
250 gLog.SetDebugLevel(lvl);
251 }
252 else
253 {
254 newfilter = new MFDataMember(text.Data(), c, num);
255 newfilter->SetName(Form("%s%c%f", text.Data(), c, num));
256 }
257
258 return newfilter;
259}
260// --------------------------------------------------------------------------
261//
262// Parse a text string. Returns a corresponding filter of filter list.
263//
264MFilter *MF::ParseString(TString txt, Int_t level)
265{
266 MFilter *filter0=NULL;
267
268 TString type;
269 int nlist = 0;
270
271 while (!txt.IsNull())
272 {
273 MFilter *newfilter = NULL;
274
275 txt = txt.Strip(TString::kBoth);
276
277 //*fLog << all << setw(level) << " " << "Text: " << level << " '" << txt << "'" << endl;
278
279 switch (txt[0])
280 {
281 case '(':
282 {
283 //
284 // Search for the corresponding bracket
285 //
286 Int_t first=1;
287 for (int cnt=0; first<txt.Length(); first++)
288 {
289 if (txt[first]=='(')
290 cnt++;
291 if (txt[first]==')')
292 cnt--;
293
294 if (cnt==-1)
295 break;
296 }
297
298 if (first==txt.Length())
299 {
300 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
301 if (filter0)
302 delete filter0;
303 return NULL;
304 }
305
306 //
307 // Make a copy of the 'interieur' and delete the substringä
308 // including the brackets
309 //
310 TString sub = txt(1, first-1);
311 txt.Remove(0, first+1);
312
313 //
314 // Parse the substring
315 //
316 newfilter = ParseString(sub, level+1);
317 if (!newfilter)
318 {
319 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
320 if (filter0)
321 delete filter0;
322 return NULL;
323 }
324 }
325 break;
326
327 case ')':
328 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
329 if (filter0)
330 delete filter0;
331 return NULL;
332
333
334 case '&':
335 case '|':
336 case '^':
337 if (filter0)
338 {
339 //
340 // Check for the type of the conditional
341 //
342 TString is = txt[0];
343 txt.Remove(0, 1);
344
345 if (is==txt[0] && is!='^')
346 {
347 is += txt[0];
348 txt.Remove(0, 1);
349 }
350
351 //
352 // If no filter is available or the available filter
353 // is of a different conditional we have to create a new
354 // filter list with the new conditional
355 //
356 if (!filter0->InheritsFrom(MFilterList::Class()) || type!=is)
357 {
358 MFilterList *list = new MFilterList(is);
359 list->SetName(Form("List_%s_%d", (const char*)is, 10*level+nlist++));
360
361 list->SetOwner();
362 list->AddToList(filter0);
363 filter0 = list;
364
365 type = is;
366 }
367 continue;
368 }
369
370 *fLog << err << dbginf << "Syntax Error: First argument of condition missing." << endl;
371 if (filter0)
372 delete filter0;
373 return NULL;
374
375 default:
376 newfilter = ParseRule(txt, filter0, level++);
377 if (!newfilter)
378 {
379 if (filter0)
380 delete filter0;
381 return NULL;
382 }
383 }
384
385 if (!filter0)
386 {
387 filter0 = newfilter;
388 continue;
389 }
390
391 if (!filter0->InheritsFrom(MFilterList::Class()))
392 continue;
393
394 ((MFilterList*)filter0)->AddToList(newfilter);
395 }
396
397 return filter0;
398}
399
400// --------------------------------------------------------------------------
401//
402// PreProcess all filters.
403//
404Bool_t MF::PreProcess(MParList *plist)
405{
406 if (!fFilter)
407 {
408 *fLog << err << dbginf << "No filter rule available." << endl;
409 return kFALSE;
410 }
411
412 if (!fFilter->CallPreProcess(plist))
413 {
414 *fLog << err << dbginf << "PreProcessing filters in ";
415 *fLog << fName << " failed." << endl;
416 return kFALSE;
417 }
418
419 return kTRUE;
420}
421
422// --------------------------------------------------------------------------
423//
424// Process all filters.
425//
426Bool_t MF::Process()
427{
428 return fFilter->CallProcess();
429}
430
431// --------------------------------------------------------------------------
432//
433// Postprocess all filters.
434//
435Bool_t MF::PostProcess()
436{
437 return fFilter->CallPostProcess();
438}
439
440// --------------------------------------------------------------------------
441//
442// Return the result of the filter rule.
443//
444Bool_t MF::IsExpressionTrue() const
445{
446 return fFilter->IsExpressionTrue();
447}
448
449void MF::StreamPrimitive(ofstream &out) const
450{
451 out << " MF " << GetUniqueName();
452
453 if (!fFilter)
454 {
455 out << ";" << endl;
456 return;
457 }
458
459 out << "(\"" << fFilter->GetRule() << "\"";
460 if (fName!=gsDefName || fTitle!=gsDefTitle)
461 {
462 out << "(\"" << fName << "\"";
463 if (fTitle!=gsDefTitle)
464 out << ", \"" << fTitle << "\"";
465 }
466 out << ");" << endl;
467
468}
469
Note: See TracBrowser for help on using the repository browser.