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

Last change on this file since 1621 was 1588, checked in by tbretz, 23 years ago
*** empty log message ***
File size: 10.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// The allowed logigal conditionals are:
47// &&: logical and
48// ||: logical or
49// ^: exclusive or
50//
51// As conditional signs, for now, only:
52// <, >
53// are allowed.
54//
55// Warning: There is no priority rule build in. So better use brackets
56// to get correct results. The rule is parsed/evaluated from the left
57// to the right, which means:
58//
59// "MHillas.fSize>200 || MHillas.fWidth<0.5 && MHillas.fLength<0.6"
60//
61// is parses as
62//
63// "(MHillas.fSize>200 || MHillas.fWidth<0.5) && MHillas.fLength<0.6"
64//
65//
66// FIXME: The possibility to use also complete filters is missing.
67// Maybe we can use gInterpreter->Calc("") for this.
68// gROOT->ProcessLineFast("line");
69//
70/////////////////////////////////////////////////////////////////////////////
71#include "MF.h"
72
73#include <ctype.h> // isalnum, ...
74#include <stdlib.h> // strtod, ...
75#include <fstream.h> // ofstream, ...
76
77#include <TMethodCall.h>
78
79#include "MParList.h"
80
81#include "MFilterList.h"
82#include "MFDataMember.h"
83
84#include "MLog.h"
85#include "MLogManip.h"
86
87ClassImp(MF);
88
89const TString MF::gsDefName = "MF";
90const TString MF::gsDefTitle = "Filter setup by a text-rule";
91
92// --------------------------------------------------------------------------
93//
94// Default Constructor. Don't use.
95//
96MF::MF() : fFilter(NULL)
97{
98 fName = gsDefName.Data();
99 fTitle = gsDefTitle.Data();
100}
101
102// --------------------------------------------------------------------------
103//
104// Constructor. For the text describing the filter rule please see
105// the class description above.
106//
107MF::MF(const char *text, const char *name, const char *title)
108{
109 fName = name ? name : gsDefName.Data();
110 fTitle = title ? title : gsDefTitle.Data();
111
112 *fLog << inf << "Trying to resolve filter rule..." << endl;
113 if (!(fFilter=ParseString(text, 1)))
114 {
115 *fLog << err << dbginf << "Parsing '" << text << "' failed." << endl;
116 return;
117 }
118
119 *fLog << inf << endl;
120 *fLog << "Using Filter rule " << fFilter->GetName();
121 *fLog << " for " << fName << ":" << endl;
122 fFilter->Print();
123 *fLog << endl << endl;
124}
125
126// --------------------------------------------------------------------------
127//
128// Destructor. Delete filters.
129//
130MF::~MF()
131{
132 if (fFilter)
133 delete fFilter;
134}
135
136// --------------------------------------------------------------------------
137//
138// Returns the number of alphanumeric characters (including '.')
139// in the given string
140//
141Int_t MF::IsAlNum(TString txt)
142{
143 int l = txt.Length();
144 for (int i = 0; i<l; i++)
145 if (!isalnum(txt[i]) && txt[i]!='.')
146 return i;
147
148 return l;
149}
150
151// --------------------------------------------------------------------------
152//
153// Parse a text string. Returns a corresponding filter of filter list.
154//
155MFilter *MF::ParseString(TString txt, Int_t level)
156{
157 MFilter *filter0=NULL;
158
159 TString type;
160 int nlist = 0;
161
162 while (!txt.IsNull())
163 {
164 MFilter *newfilter = NULL;
165
166 txt = txt.Strip(TString::kBoth);
167
168 //*fLog << all << setw(level) << " " << "Text: " << level << " '" << txt << "'" << endl;
169
170 switch (txt[0])
171 {
172 case '(':
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 if (filter0)
193 delete filter0;
194 return NULL;
195 }
196
197 //
198 // Make a copy of the 'interieur' and delete the substringä
199 // including the brackets
200 //
201 TString sub = txt(1, first-1);
202 txt.Remove(0, first+1);
203
204 //
205 // Parse the substring
206 //
207 newfilter = ParseString(sub, level+1);
208 if (!newfilter)
209 {
210 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
211 if (filter0)
212 delete filter0;
213 return NULL;
214 }
215 }
216 break;
217
218 case ')':
219 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
220 if (filter0)
221 delete filter0;
222 return NULL;
223
224 case '&':
225 case '|':
226 case '^':
227 if (filter0)
228 {
229 //
230 // Check for the type of the conditional
231 //
232 TString is = txt[0];
233 txt.Remove(0, 1);
234
235 if (is==txt[0] && is!='^')
236 {
237 is += txt[0];
238 txt.Remove(0, 1);
239 }
240
241 //
242 // If no filter is available or the available filter
243 // is of a different conditional we have to create a new
244 // filter list with the new conditional
245 //
246 if (!filter0->InheritsFrom(MFilterList::Class()) || type!=is)
247 {
248 MFilterList *list = new MFilterList(is);
249 list->SetName(Form("List_%s_%d", (const char*)is, 10*level+nlist++));
250
251 list->SetOwner();
252 list->AddToList(filter0);
253 filter0 = list;
254
255 type = is;
256 }
257 continue;
258 }
259
260 *fLog << err << dbginf << "Syntax Error: First argument of condition missing." << endl;
261 if (filter0)
262 delete filter0;
263 return NULL;
264
265 default:
266 int i = IsAlNum(txt);
267
268 if (i==0)
269 {
270 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
271 if (filter0)
272 delete filter0;
273 return NULL;
274 }
275
276 TString text = txt(0, i);
277
278 txt.Remove(0, i);
279 txt = txt.Strip(TString::kBoth);
280
281 if (txt.IsNull())
282 {
283 *fLog << err << dbginf << "Syntax Error: No conditional in '" << text << "'" << endl;
284 if (filter0)
285 delete filter0;
286 return NULL;
287 }
288
289 char c;
290 switch (txt[0])
291 {
292 case '>':
293 case '<':
294 c = txt[0];
295 txt.Remove(0, 1);
296 break;
297
298 default:
299 *fLog << err << dbginf << "Syntax Error: Conditional '" << txt[0] << "' unknown." << endl;
300 if (filter0)
301 delete filter0;
302 return NULL;
303 }
304
305 char *end;
306 Double_t num = strtod(txt.Data(), &end);
307 if (!end || txt.Data()==end)
308 {
309 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
310 if (filter0)
311 delete filter0;
312 return NULL;
313 }
314
315 txt.Remove(0, end-txt.Data());
316
317 newfilter = new MFDataMember(text.Data(), c, num);
318 newfilter->SetName(Form("%s%c%f", text.Data(), c, num));
319 }
320
321 if (!filter0)
322 {
323 filter0 = newfilter;
324 continue;
325 }
326
327 if (!filter0->InheritsFrom(MFilterList::Class()))
328 continue;
329
330 ((MFilterList*)filter0)->AddToList(newfilter);
331 }
332
333 return filter0;
334}
335
336// --------------------------------------------------------------------------
337//
338// PreProcess all filters.
339//
340Bool_t MF::PreProcess(MParList *plist)
341{
342 if (!fFilter)
343 {
344 *fLog << err << dbginf << "No filter rule available." << endl;
345 return kFALSE;
346 }
347
348 if (!fFilter->PreProcess(plist))
349 {
350 *fLog << err << dbginf << "PreProcessing filters in ";
351 *fLog << fName << " failed." << endl;
352 return kFALSE;
353 }
354
355 return kTRUE;
356}
357
358// --------------------------------------------------------------------------
359//
360// Process all filters.
361//
362Bool_t MF::Process()
363{
364 return fFilter->Process();
365}
366
367// --------------------------------------------------------------------------
368//
369// Postprocess all filters.
370//
371Bool_t MF::PostProcess()
372{
373 return fFilter->PostProcess();
374}
375
376// --------------------------------------------------------------------------
377//
378// Return the result of the filter rule.
379//
380Bool_t MF::IsExpressionTrue() const
381{
382 return fFilter->IsExpressionTrue();
383}
384
385void MF::StreamPrimitive(ofstream &out) const
386{
387 out << " MF " << GetUniqueName();
388
389 if (!fFilter)
390 {
391 out << ";" << endl;
392 return;
393 }
394
395 out << "(\"" << fFilter->GetRule() << "\"";
396 if (fName!=gsDefName || fTitle!=gsDefTitle)
397 {
398 out << "(\"" << fName << "\"";
399 if (fTitle!=gsDefTitle)
400 out << ", \"" << fTitle << "\"";
401 }
402 out << ");" << endl;
403
404}
405
Note: See TracBrowser for help on using the repository browser.