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

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