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

Last change on this file since 1666 was 1666, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 11.9 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 newfilter = new MFDataChain(text.Data(), c, num);
247 newfilter->SetName(Form("Chain%02d%c%f", level, c, num));
248 }
249 else
250 {
251 newfilter = new MFDataMember(text.Data(), c, num);
252 newfilter->SetName(Form("%s%c%f", text.Data(), c, num));
253 }
254
255 return newfilter;
256}
257// --------------------------------------------------------------------------
258//
259// Parse a text string. Returns a corresponding filter of filter list.
260//
261MFilter *MF::ParseString(TString txt, Int_t level)
262{
263 MFilter *filter0=NULL;
264
265 TString type;
266 int nlist = 0;
267
268 while (!txt.IsNull())
269 {
270 MFilter *newfilter = NULL;
271
272 txt = txt.Strip(TString::kBoth);
273
274 //*fLog << all << setw(level) << " " << "Text: " << level << " '" << txt << "'" << endl;
275
276 switch (txt[0])
277 {
278 case '(':
279 {
280 //
281 // Search for the corresponding bracket
282 //
283 Int_t first=1;
284 for (int cnt=0; first<txt.Length(); first++)
285 {
286 if (txt[first]=='(')
287 cnt++;
288 if (txt[first]==')')
289 cnt--;
290
291 if (cnt==-1)
292 break;
293 }
294
295 if (first==txt.Length())
296 {
297 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
298 if (filter0)
299 delete filter0;
300 return NULL;
301 }
302
303 //
304 // Make a copy of the 'interieur' and delete the substringä
305 // including the brackets
306 //
307 TString sub = txt(1, first-1);
308 txt.Remove(0, first+1);
309
310 //
311 // Parse the substring
312 //
313 newfilter = ParseString(sub, level+1);
314 if (!newfilter)
315 {
316 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
317 if (filter0)
318 delete filter0;
319 return NULL;
320 }
321 }
322 break;
323
324 case ')':
325 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
326 if (filter0)
327 delete filter0;
328 return NULL;
329
330
331 case '&':
332 case '|':
333 case '^':
334 if (filter0)
335 {
336 //
337 // Check for the type of the conditional
338 //
339 TString is = txt[0];
340 txt.Remove(0, 1);
341
342 if (is==txt[0] && is!='^')
343 {
344 is += txt[0];
345 txt.Remove(0, 1);
346 }
347
348 //
349 // If no filter is available or the available filter
350 // is of a different conditional we have to create a new
351 // filter list with the new conditional
352 //
353 if (!filter0->InheritsFrom(MFilterList::Class()) || type!=is)
354 {
355 MFilterList *list = new MFilterList(is);
356 list->SetName(Form("List_%s_%d", (const char*)is, 10*level+nlist++));
357
358 list->SetOwner();
359 list->AddToList(filter0);
360 filter0 = list;
361
362 type = is;
363 }
364 continue;
365 }
366
367 *fLog << err << dbginf << "Syntax Error: First argument of condition missing." << endl;
368 if (filter0)
369 delete filter0;
370 return NULL;
371
372 default:
373 newfilter = ParseRule(txt, filter0, level++);
374 if (!newfilter)
375 {
376 if (filter0)
377 delete filter0;
378 return NULL;
379 }
380 }
381
382 if (!filter0)
383 {
384 filter0 = newfilter;
385 continue;
386 }
387
388 if (!filter0->InheritsFrom(MFilterList::Class()))
389 continue;
390
391 ((MFilterList*)filter0)->AddToList(newfilter);
392 }
393
394 return filter0;
395}
396
397// --------------------------------------------------------------------------
398//
399// PreProcess all filters.
400//
401Bool_t MF::PreProcess(MParList *plist)
402{
403 if (!fFilter)
404 {
405 *fLog << err << dbginf << "No filter rule available." << endl;
406 return kFALSE;
407 }
408
409 if (!fFilter->PreProcess(plist))
410 {
411 *fLog << err << dbginf << "PreProcessing filters in ";
412 *fLog << fName << " failed." << endl;
413 return kFALSE;
414 }
415
416 return kTRUE;
417}
418
419// --------------------------------------------------------------------------
420//
421// Process all filters.
422//
423Bool_t MF::Process()
424{
425 return fFilter->Process();
426}
427
428// --------------------------------------------------------------------------
429//
430// Postprocess all filters.
431//
432Bool_t MF::PostProcess()
433{
434 return fFilter->PostProcess();
435}
436
437// --------------------------------------------------------------------------
438//
439// Return the result of the filter rule.
440//
441Bool_t MF::IsExpressionTrue() const
442{
443 return fFilter->IsExpressionTrue();
444}
445
446void MF::StreamPrimitive(ofstream &out) const
447{
448 out << " MF " << GetUniqueName();
449
450 if (!fFilter)
451 {
452 out << ";" << endl;
453 return;
454 }
455
456 out << "(\"" << fFilter->GetRule() << "\"";
457 if (fName!=gsDefName || fTitle!=gsDefTitle)
458 {
459 out << "(\"" << fName << "\"";
460 if (fTitle!=gsDefTitle)
461 out << ", \"" << fTitle << "\"";
462 }
463 out << ");" << endl;
464
465}
466
Note: See TracBrowser for help on using the repository browser.