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

Last change on this file since 1435 was 1283, checked in by tbretz, 23 years ago
*** empty log message ***
File size: 10.1 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 <stdlib.h> // strtod, ...
74#include <ctype.h> // isalnum, ...
75
76#include <TMethodCall.h>
77
78#include "MParList.h"
79
80#include "MFilterList.h"
81#include "MFDataMember.h"
82
83#include "MLog.h"
84#include "MLogManip.h"
85
86ClassImp(MF);
87
88// --------------------------------------------------------------------------
89//
90// Constructor. For the text describing the filter rule please see
91// the class description above.
92//
93MF::MF(const char *text, const char *name, const char *title)
94{
95 fName = name ? name : "MF";
96 fTitle = title ? title : "Filter using a text";
97
98 *fLog << inf << "Trying to resolve filter rule..." << endl;
99 if (!(fFilter=ParseString(text, 1)))
100 {
101 *fLog << err << dbginf << "Parsing '" << text << "' failed." << endl;
102 return;
103 }
104
105 *fLog << inf << endl;
106 *fLog << "Using Filter rule " << fFilter->GetName();
107 *fLog << " for " << fName << ":" << endl;
108 fFilter->Print();
109 *fLog << endl << endl;
110}
111
112// --------------------------------------------------------------------------
113//
114// Destructor. Delete filters.
115//
116MF::~MF()
117{
118 if (fFilter)
119 delete fFilter;
120}
121
122// --------------------------------------------------------------------------
123//
124// Returns the number of alphanumeric characters (including '.')
125// in the given string
126//
127Int_t MF::IsAlNum(TString txt)
128{
129 int l = txt.Length();
130 for (int i = 0; i<l; i++)
131 if (!isalnum(txt[i]) && txt[i]!='.')
132 return i;
133
134 return l;
135}
136
137// --------------------------------------------------------------------------
138//
139// Parse a text string. Returns a corresponding filter of filter list.
140//
141MFilter *MF::ParseString(TString txt, Int_t level)
142{
143 MFilter *filter0=NULL;
144
145 TString type;
146 int nlist = 0;
147
148 while (!txt.IsNull())
149 {
150 MFilter *newfilter = NULL;
151
152 txt = txt.Strip(TString::kBoth);
153
154 //*fLog << all << setw(level) << " " << "Text: " << level << " '" << txt << "'" << endl;
155
156 switch (txt[0])
157 {
158 case '(':
159 {
160 //
161 // Search for the corresponding bracket
162 //
163 Int_t first=1;
164 for (int cnt=0; first<txt.Length(); first++)
165 {
166 if (txt[first]=='(')
167 cnt++;
168 if (txt[first]==')')
169 cnt--;
170
171 if (cnt==-1)
172 break;
173 }
174
175 if (first==txt.Length())
176 {
177 *fLog << err << dbginf << "Syntax Error: ')' missing." << endl;
178 if (filter0)
179 delete filter0;
180 return NULL;
181 }
182
183 //
184 // Make a copy of the 'interieur' and delete the substringä
185 // including the brackets
186 //
187 TString sub = txt(1, first-1);
188 txt.Remove(0, first+1);
189
190 //
191 // Parse the substring
192 //
193 newfilter = ParseString(sub, level+1);
194 if (!newfilter)
195 {
196 *fLog << err << dbginf << "Parsing '" << sub << "' failed." << endl;
197 if (filter0)
198 delete filter0;
199 return NULL;
200 }
201 }
202 break;
203
204 case ')':
205 *fLog << err << dbginf << "Syntax Error: Too many ')'" << endl;
206 if (filter0)
207 delete filter0;
208 return NULL;
209
210 case '&':
211 case '|':
212 case '^':
213 if (filter0)
214 {
215 //
216 // Check for the type of the conditional
217 //
218 TString is = txt[0];
219 txt.Remove(0, 1);
220
221 if (is==txt[0] && is!='^')
222 {
223 is += txt[0];
224 txt.Remove(0, 1);
225 }
226
227 //
228 // If no filter is available or the available filter
229 // is of a different conditional we have to create a new
230 // filter list with the new conditional
231 //
232 if (!filter0->InheritsFrom(MFilterList::Class()) || type!=is)
233 {
234 MFilterList *list = new MFilterList(is);
235 list->SetName(Form("List_%s_%d", (const char*)is, 10*level+nlist++));
236
237 list->SetOwner();
238 list->AddToList(filter0);
239 filter0 = list;
240
241 type = is;
242 }
243 continue;
244 }
245
246 *fLog << err << dbginf << "Syntax Error: First argument of condition missing." << endl;
247 if (filter0)
248 delete filter0;
249 return NULL;
250
251 default:
252 int i = IsAlNum(txt);
253
254 if (i==0)
255 {
256 *fLog << err << dbginf << "Syntax Error: Name of data member missing in '" << txt << "'" << endl;
257 if (filter0)
258 delete filter0;
259 return NULL;
260 }
261
262 TString text = txt(0, i);
263
264 txt.Remove(0, i);
265 txt = txt.Strip(TString::kBoth);
266
267 if (txt.IsNull())
268 {
269 *fLog << err << dbginf << "Syntax Error: No conditional in '" << text << "'" << endl;
270 if (filter0)
271 delete filter0;
272 return NULL;
273 }
274
275 char c;
276 switch (txt[0])
277 {
278 case '>':
279 case '<':
280 c = txt[0];
281 txt.Remove(0, 1);
282 break;
283
284 default:
285 *fLog << err << dbginf << "Syntax Error: Conditional '" << txt[0] << "' unknown." << endl;
286 if (filter0)
287 delete filter0;
288 return NULL;
289 }
290
291 char *end;
292 Double_t num = strtod(txt.Data(), &end);
293 if (!end || txt.Data()==end)
294 {
295 *fLog << err << dbginf << "Error trying to convert '" << txt << "' to value." << endl;
296 if (filter0)
297 delete filter0;
298 return NULL;
299 }
300
301 txt.Remove(0, end-txt.Data());
302
303 newfilter = new MFDataMember(text.Data(), c, num);
304 newfilter->SetName(Form("%s%c%f", text.Data(), c, num));
305 }
306
307 if (!filter0)
308 {
309 filter0 = newfilter;
310 continue;
311 }
312
313 if (!filter0->InheritsFrom(MFilterList::Class()))
314 continue;
315
316 ((MFilterList*)filter0)->AddToList(newfilter);
317 }
318
319 return filter0;
320}
321
322// --------------------------------------------------------------------------
323//
324// PreProcess all filters.
325//
326Bool_t MF::PreProcess(MParList *plist)
327{
328 if (!fFilter)
329 {
330 *fLog << err << dbginf << "No filter rule available." << endl;
331 return kFALSE;
332 }
333
334 if (!fFilter->PreProcess(plist))
335 {
336 *fLog << err << dbginf << "PreProcessing filters in ";
337 *fLog << fName << " failed." << endl;
338 return kFALSE;
339 }
340
341 return kTRUE;
342}
343
344// --------------------------------------------------------------------------
345//
346// Process all filters.
347//
348Bool_t MF::Process()
349{
350 return fFilter->Process();
351}
352
353// --------------------------------------------------------------------------
354//
355// Postprocess all filters.
356//
357Bool_t MF::PostProcess()
358{
359 return fFilter->PostProcess();
360}
361
362// --------------------------------------------------------------------------
363//
364// Return the result of the filter rule.
365//
366Bool_t MF::IsExpressionTrue() const
367{
368 return fFilter->IsExpressionTrue();
369}
Note: See TracBrowser for help on using the repository browser.