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

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