source: trunk/MagicSoft/Mars/mfbase/MF.cc@ 5711

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