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

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