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

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