Hall A ROOT/C++ Analyzer (podd)
Loading...
Searching...
No Matches
THaCutList.cxx
Go to the documentation of this file.
1//*-- Author : Ole Hansen 05-May-00
2
3
5//
6// THaCutList
7//
8// Class to manage dynamically-defined cuts (tests).
9//
11
12#include "THaCut.h"
13#include "THaNamedList.h"
14#include "THaCutList.h"
15#include "THaPrintOption.h"
16#include "Textvars.h"
17#include "THaGlobals.h"
18#include "FileInclude.h"
19#include "TError.h"
20#include "TList.h"
21#include "TString.h"
22#include "TClass.h"
23
24#include <iostream>
25#include <fstream>
26#include <sstream>
27#include <iomanip>
28#include <algorithm>
29#include <cstring>
30#include <string>
31#include <vector>
32#include <cassert>
33
34using namespace std;
35using namespace Podd;
36
37const char* const THaCutList::kDefaultBlockName = "Default";
38const char* const THaCutList::kDefaultCutFile = "default.cuts";
39
40//_____________________________________________________________________________
42{
43 // Print all objects in the list. Pass option 'opt' through to each object
44 // being printed. (This is the old ROOT 2.x behavior).
45
46 TIter next(this);
47 while( TObject* obj = next() )
48 obj->Print(opt);
49}
50
51//______________________________________________________________________________
53 : fCuts(new THaHashList()), fBlocks(new THaHashList()),
54 fVarList(nullptr)
55{
56 // Default constructor. No variable list is defined. Either define it
57 // later with SetList() or pass the list as an argument to Define().
58 // Allowing this constructor is not very safe ...
59
60}
61
62//______________________________________________________________________________
64 : fCuts(new THaHashList(rhs.fCuts)), fBlocks(new THaHashList(rhs.fBlocks)),
65 fVarList(rhs.fVarList)
66{
67 // Copy constructor
68
69}
70
71//______________________________________________________________________________
73 : fCuts(new THaHashList()), fBlocks(new THaHashList()),
74 fVarList(lst)
75{
76 // Constructor from variable list. Create the main lists and set the variable
77 // list.
78
79}
80
81//______________________________________________________________________________
83{
84 // Default destructor. Deletes all cuts and lists.
85
86 fCuts->Clear();
87 fBlocks->Delete();
88 delete fCuts;
89 delete fBlocks;
90}
91
92//______________________________________________________________________________
94{
95 // Remove all cuts and all blocks
96
97 fBlocks->Delete();
98 fCuts->Delete();
99}
100
101//______________________________________________________________________________
103{
104 // Clear the results of all defined cuts
105
106 TIter next( fCuts );
107 while( auto* pcut = static_cast<THaCut*>( next() ))
108 pcut->ClearResult();
109}
110
111//______________________________________________________________________________
112void THaCutList::ClearBlock( const char* block, Option_t* )
113{
114 // Clear the results of the defined cuts in the named block
115
116 TIter next( FindBlock(block) );
117 while( auto* pcut = static_cast<THaCut*>( next() ))
118 pcut->ClearResult();
119}
120
121//______________________________________________________________________________
123{
124 // Compile all cuts in the list.
125 // Since cuts are compiled when we Define() them, this routine typically only
126 // needs to be called when global variable pointers need to be updated.
127
128 vector<THaCut*> bad_cuts;
129
130 TIter next( fCuts );
131 while( auto* pcut = static_cast<THaCut*>( next() )) {
132 pcut->Compile();
133 if( pcut->IsError() ) {
134 Error( "Compile", "expression error, cut removed: %s %s block: %s",
135 pcut->GetName(), pcut->GetTitle(), pcut->GetBlockname() );
136 bad_cuts.push_back(pcut);
137 }
138 }
139 for( const auto* pbad : bad_cuts )
140 Remove( pbad->GetName() );
141}
142
143//______________________________________________________________________________
144Int_t THaCutList::Define( const char* cutname, const char* expr,
145 const char* block )
146{
147 // Define a new cut with given name in given block. If the block does not
148 // exist, it is created. This is the normal way to define a cut since
149 // there is usually just one variable list.
150 //
151 // Cut names MUST be unique and cannot be empty. Quotes and whitespace are
152 // illegal in cut names; any other characters are allowed.
153 //
154 // Symbolic variables in expressions must only refer to variables defined
155 // in the variable list OR to previously defined cuts.
156 //
157 // It is possible to use cut names from one block in definitions for a
158 // different block. This should be done with care, however, since such
159 // "external" cuts are not necessarily updated with the same frequency
160 // as the current block, depending on the design of the application.
161 //
162 // A return value of 0 indicates success, negative numbers indicate error.
163 //
164
165 if( !fVarList ) {
166 Error( "Define", "no variable list set, cut not created" );
167 return -1;
168 }
169 return Define( cutname, expr, fVarList, block );
170}
171
172//______________________________________________________________________________
173Int_t THaCutList::Define( const char* cutname, const char* expr,
174 const THaVarList* lst, const char* block )
175{
176 // Define a new cut with given name in given block with variables from
177 // given list. See description of Define() above.
178 //
179
180 static const char* here = "THaCutList::Define";
181
182 if( !cutname || !*cutname || (strspn(cutname," ")==strlen(cutname)) ) {
183 Error( here, "empty cut name, cut not created" );
184 return -4;
185 }
186 if( !expr || !*expr || (strspn(expr," ")==strlen(expr)) ) {
187 Error( here, "empty expression string, cut not created: %s", cutname );
188 return -5;
189 }
190 if( !block || !*block || (strspn(block," ")==strlen(block)) ) {
191 Error( here, "empty block name, cut not created: %s %s", cutname, expr );
192 return -6;
193 }
194 if( strpbrk(cutname,"\"'` ") ) {
195 Error( here, "illegal character(s) in cut name, cut not created: "
196 "%s %s block: %s", cutname, expr, block );
197 return -7;
198 }
199 if( fCuts->FindObject(cutname) ) {
200 Error( here, "duplicate cut name, cut not created: %s %s block: %s",
201 cutname, expr, block );
202 return -8;
203 }
204
205 // Create new cut using the given expression. Bail out if error.
206
207 auto* pcut = new THaCut( cutname, expr, block, lst, this );
208 if( pcut->IsError() ) {
209 Error( here, "expression error, cut not created: %s %s block: %s",
210 cutname, expr, block );
211 delete pcut;
212 return -3;
213 }
214
215 // Formula ok -> add it to the lists. If this is a new block, create it.
216
217 auto* plist = FindBlock( block );
218 if( !plist ) {
219 plist = new THaNamedList( block );
220 fBlocks->Add( plist );
221 }
222
223 fCuts->AddLast( pcut );
224 plist->AddLast( pcut );
225 return 0;
226}
227
228//______________________________________________________________________________
230{
231 // Evaluate all tests in all blocks. Because of possible dependencies between
232 // blocks, each block is evaluated separately in the order in which the blocks
233 // were defined.
234
235 Int_t i = 0;
236 TIter next( fBlocks );
237 while( auto* plist = static_cast<THaNamedList*>( next() ))
238 i += EvalBlock( plist );
239
240 return i;
241}
242
243//______________________________________________________________________________
245{
246 // Evaluate all cuts in the given list in the order in which they were defined.
247 // This is a static member function that can be called externally.
248 // Only TObject* in the given list that inherit from THaCut* are evaluated.
249
250 if( !plist ) return -1;
251 Int_t i = 0;
252 TIter next( plist );
253 while( TObject* pobj = next() ) {
254 if( !pobj->InheritsFrom(THaCut::Class()) ) {
255#ifdef WITH_DEBUG
256 ::Warning("THaCutList::EvalBlock()", "List contains a non-THaCut:" );
257 pobj->Print();
258#endif
259 continue;
260 }
261 static_cast<THaCut*>(pobj)->EvalCut();
262 i++;
263 }
264 return i;
265}
266
267//______________________________________________________________________________
268Int_t THaCutList::EvalBlock( const char* block )
269{
270 // Evaluate all tests in the given block in the order in which they were defined.
271 // If no argument is given, the default block is evaluated.
272
273 return EvalBlock( FindBlock( block ) );
274}
275
276//______________________________________________________________________________
277inline static bool IsComment( const string& s, string::size_type pos )
278{
279 return ( pos != string::npos && pos < s.length() &&
280 (s[pos] == '#' || s.substr(pos,2) == "//") );
281}
282
283//______________________________________________________________________________
284Int_t THaCutList::Load( const char* filename )
285{
286 // Read cut definitions from a file and create the cuts. If no filename is
287 // given, the file ./cutdef.dat is used.
288 //
289 // Lines starting with # or "//" are treated as comments.
290 // Blank lines and leading spaces are ignored.
291 //
292 // A valid cut definition consists of two fields, a cut name and the
293 // corresponding expression. The fields are separated by whitespace.
294 // Comments following the cut expression are ignored.
295 //
296 // Block names can be set using "Block:" as the cut name (without quotes)
297 // followed by the name of the block.
298 //
299 // Cuts are defined via the Define() method; see the description of
300 // Define() for more details. Examples:
301 //
302 // # This is a comment. Blank lines are ignored, so are leading spaces.
303 //
304 // xcut x>1
305 // cut1 x+y<10
306 //
307 // Block: Target_cuts
308 // cut2 x<10 || x>20 // Comment goes here
309 // zcut (z^2-2)>0 # This text is ignored
310 //
311 // A return value of 0 indicates success. Negative values indicate severe
312 // errors (e.g. file not found, read error). Positive numbers indicate the
313 // number of unprocessable lines (e.g. illegal expression, bad cutname) for
314 // which no cuts were defined.
315 //
316
317 static const char* const here = "THaCutList::Load";
318 static const char* const whtspc = " \t";
319
320 if( !filename || !*filename || strspn(filename," ") == strlen(filename) ) {
321 Error( here, "invalid file name, no cuts loaded" );
322 return -1;
323 }
324
325 ifstream ifile( filename );
326 if( !ifile ) {
327 Error( here, "error opening input file %s, no cuts loaded",
328 filename );
329 return -2;
330 }
331
332 // Read the file line by line
333 string line;
334 string block = kDefaultBlockName;
335 Int_t nlines_read = 0, nlines_ok = 0;
336
337 while( getline(ifile,line) ) {
338
339 // #include
340 if( line.substr(0,kIncTag.length()) == kIncTag &&
341 line.length() > kIncTag.length() ) {
342 string incfilename;
343 if( GetIncludeFileName(line,incfilename) != 0 ) {
344 ostringstream ostr;
345 ostr << "Error in #include specification: " << line;
346 ::Error( here, "%s", ostr.str().c_str() );
347 return -3;
348 }
349 if( CheckIncludeFilePath(incfilename) != 0 ) {
350 ostringstream ostr;
351 ostr << "Error opening include file: " << line;
352 ::Error( here, "%s", ostr.str().c_str() );
353 return -3;
354 }
355 if( incfilename == filename ) {
356 // File including itself?
357 // FIXME: does not catch including the same file via full pathname or similar
358 ostringstream ostr;
359 ostr << "File cannot include itself: " << line;
360 ::Error( here, "%s", ostr.str().c_str() );
361 return -3;
362 }
363 Load( incfilename.c_str() );
364 continue;
365 }
366
367 // Blank line or comment?
368 string::size_type start, pos = 0;
369 if( line.empty()
370 || (start = line.find_first_not_of( whtspc )) == string::npos
371 || IsComment(line, start) )
372 continue;
373
374 // Get rid of trailing comments and whitespace
375 while( (pos = line.find_first_of("#/", pos+1)) != string::npos ) {
376 if( IsComment(line, pos) ) {
377 line.erase(pos);
378 break;
379 }
380 }
381 pos = line.find_last_not_of( whtspc );
382 assert( pos != string::npos );
383 if( pos != string::npos && ++pos < line.length() )
384 line.erase(pos);
385
386 // Valid line ... start processing
387
388 // Substitute text variables
389 vector<string> lines( 1, line );
390 if( gHaTextvars->Substitute(lines) )
391 continue;
392
393 for( const auto& str : lines ) {
394 nlines_read++;
395 string arg1, arg2;
396
397 // Extract first argument (cut name or "Block:")
398 pos = str.find_first_of( whtspc, start );
399 if( pos == string::npos ) {
400 Warning( here, "ignoring label without expression, line = \"%s\"",
401 str.c_str() );
402 continue;
403 }
404 arg1 = str.substr( start, pos-start );
405
406 // Extract second argument (expression or block name)
407 pos = str.find_first_not_of( whtspc, pos );
408 assert( pos != string::npos );
409 if( pos == string::npos ) continue;
410 arg2 = str.substr( pos );
411
412 // Set block name
413 if( arg1 == "Block:" ) {
414 block = arg2;
415 nlines_ok++;
416 continue;
417 }
418
419 // Define the cut. Errors are reported by Define()
420 if( !Define( arg1.c_str(), arg2.c_str(), block.c_str() ) ) nlines_ok++;
421
422 }
423 }
424
425 ifile.close();
426 Int_t nbad = nlines_read-nlines_ok;
427 if( nbad>0 ) Warning( here, "%d cut(s) could not be defined, check input "
428 "file %s", nbad, filename );
429 return nbad;
430}
431
432//______________________________________________________________________________
434{
435 // If the print option is either "LINE" or "STATS", determine the widths
436 // of the text fields of all the cuts in the given list and append them
437 // to the print option.
438 // This is an internal utility function used by Print() and PrintBlock().
439
440 if( opt.IsLine() && !strcmp(opt.GetOption(1),"") ) {
441 vector<UInt_t> width{ 0, 0, 0, 0 };
442 TIter next( plist );
443 while( auto* pcut = static_cast<THaCut*>( next() )) {
444 width[0] = max( width[0], static_cast<UInt_t>
445 (strlen(pcut->GetName())) );
446 width[1] = max( width[1], static_cast<UInt_t>
447 (strlen(pcut->GetTitle())) );
448 width[2] = max( width[2], static_cast<UInt_t>
449 (strlen(pcut->GetBlockname())) );
450 width[3] = max( width[3], IntDigits( static_cast<Int_t>
451 (pcut->GetNPassed()) ));
452 }
453 TString newopt = opt.GetOption(0);
454 for( UInt_t i : width ) {
455 newopt += ",";
456 newopt += i;
457 }
458 opt = newopt;
459 }
460}
461
462//______________________________________________________________________________
463void THaCutList::Print( Option_t* option ) const
464{
465 // Print all cuts in all blocks.
466 // For options see THaCut.Print(). The default mode is "LINE". The
467 // widths of the text fields are determined automatically.
468 // For "LINE" and "STATS", cuts are printed grouped in blocks.
469
471 if( !strcmp(opt.GetOption(0),"") ) opt = kPRINTLINE;
472 MakePrintOption( opt, fCuts );
473 PrintHeader( opt );
474 if( opt.IsLine() ) {
475 TIter next( fBlocks );
476 while( auto* plist = static_cast<THaNamedList*>( next() )) {
477 bool is_stats = !strcmp( opt.GetOption(0), kPRINTSTATS );
478 if( is_stats && strlen( plist->GetName() ) )
479 cout << "BLOCK: " << plist->GetName() << endl;
480 plist->PrintOpt( opt.Data() );
481 if ( is_stats ) cout << endl;
482 }
483 } else
484 fCuts->PrintOpt( opt.Data() );
485}
486
487//______________________________________________________________________________
488void THaCutList::PrintBlock( const char* block, Option_t* option ) const
489{
490 // Print all cuts in the named block.
491
492 THaNamedList* plist = FindBlock( block );
493 if( !plist ) return;
495 if( !strcmp(opt.GetOption(0),"") ) opt = kPRINTLINE;
496 MakePrintOption( opt, plist );
497 PrintHeader( opt );
498 plist->PrintOpt( opt.Data() );
499}
500
501//______________________________________________________________________________
502void THaCutList::PrintCut( const char* cutname, Option_t* option ) const
503{
504 // Print the definition of a single cut
505
506 auto* pcut = dynamic_cast<THaCut*>( fCuts->FindObject( cutname ));
507 if( !pcut ) return;
508 pcut->Print( option );
509}
510
511//______________________________________________________________________________
513{
514 // Print header for Print() and PrintBlock().
515 // This is an internal function.
516
517 if( !opt.IsLine() ) return;
518 cout.flags( ios::left );
519 cout << setw( opt.GetValue(1) ) << "Name" << " "
520 << setw( opt.GetValue(2) ) << "Def" << " ";
521 if( !strcmp( opt.GetOption(), kPRINTLINE )) {
522 cout << setw(1) << "T" << " "
523 << setw( opt.GetValue(3) ) << "Block" << " ";
524 }
525 cout << setw(9) << "Called" << " "
526 << "Passed" << endl;
527 int len = max( opt.GetValue(1) + opt.GetValue(2)
528 + opt.GetValue(4) + 24, 30 );
529 if( !strcmp( opt.GetOption(), kPRINTLINE ))
530 len += max( opt.GetValue(3) + 5, 10 );
531 char* line = new char[ len+1 ];
532 for( int i=0; i<len; i++ ) line[i] = '-';
533 line[len] = '\0';
534 cout << line << endl;
535 delete [] line;
536}
537
538//______________________________________________________________________________
540{
541 // Reset all cut and block counters to zero
542
543 TIter next( fCuts );
544 while( auto* pcut = static_cast<THaCut*>( next() ))
545 pcut->Reset();
546}
547
548//______________________________________________________________________________
549Int_t THaCutList::Result( const char* cutname, EWarnMode mode )
550{
551 // Return result of the last evaluation of the named cut
552 // (0 if false, 1 if true).
553 // If cut does not exist, return -1. Also, print warning if mode=kWarn.
554
555 auto* pcut = static_cast<THaCut*>( fCuts->FindObject( cutname ));
556 if( !pcut ) {
557 if( mode == kWarn )
558 Warning("Result", "No such cut: %s", cutname );
559 return -1;
560 }
561 return static_cast<Int_t>( pcut->GetResult() );
562}
563
564//______________________________________________________________________________
565Int_t THaCutList::Remove( const char* cutname )
566{
567 // Remove the named cut completely
568
569 auto* pcut = static_cast<THaCut*>( fCuts->FindObject( cutname ));
570 if ( !pcut ) return 0;
571 const char* block = pcut->GetBlockname();
572 auto* plist = static_cast<THaNamedList*>(fBlocks->FindObject( block ));
573 if ( plist ) plist->Remove( pcut );
574 fCuts->Remove( pcut );
575 delete pcut;
576 return 1;
577}
578
579//______________________________________________________________________________
580Int_t THaCutList::RemoveBlock( const char* block )
581{
582 // Remove all cuts contained in the named block.
583
584 THaNamedList* plist = FindBlock( block );
585 if( !plist ) return -1;
586 Int_t i = 0;
587 TObjLink* lnk = plist->FirstLink();
588 while( lnk ) {
589 auto* pcut = static_cast<THaCut*>( lnk->GetObject() );
590 if( pcut ) i++;
591 lnk = lnk->Next();
592 fCuts->Remove( pcut );
593 }
594 plist->Delete(); // this should delete all pcuts
595 fBlocks->Remove( plist );
596 delete plist;
597
598 return i;
599}
600
601//______________________________________________________________________________
603{
604 // Set the pointer to the list of global variables to be used by default.
605 // Other variable lists can be used for individual cut definitions.
606
607 fVarList = lst;
608}
609
610//______________________________________________________________________________
612{
613 //Get number of printable digits of integer n.
614 //Global utility function.
615
616 if( n == 0 ) return 1;
617 int j = 0;
618 if( n<0 ) {
619 j++;
620 n *= -1;
621 }
622 while( n>0 ) {
623 n /= 10;
624 j++;
625 }
626 return j;
627}
628
629//______________________________________________________________________________
int Int_t
unsigned int UInt_t
const char Option_t
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t width
UInt_t IntDigits(Int_t n)
static bool IsComment(const string &s, string::size_type pos)
UInt_t IntDigits(Int_t n)
Option_t *const kPRINTLINE
Option_t *const kPRINTSTATS
static const char *const here
Definition THaVar.cxx:64
static TClass * Class()
virtual void PrintBlock(const char *block=kDefaultBlockName, Option_t *option="") const
virtual void PrintCut(const char *cutname, Option_t *option="") const
virtual void ClearBlock(const char *block=kDefaultBlockName, Option_t *opt="")
virtual void Clear(Option_t *opt="")
virtual ~THaCutList()
virtual void PrintHeader(const THaPrintOption &opt) const
THaHashList * fBlocks
Definition THaCutList.h:80
virtual Int_t RemoveBlock(const char *block=kDefaultBlockName)
virtual Int_t Eval()
virtual void Reset()
THaHashList * fCuts
Definition THaCutList.h:79
const THaVarList * fVarList
Definition THaCutList.h:82
virtual void SetList(THaVarList *lst)
virtual Int_t Load(const char *filename=kDefaultCutFile)
virtual Int_t Result(const char *cutname="", EWarnMode mode=kWarn)
virtual Int_t EvalBlock(const char *block=kDefaultBlockName)
virtual void Print(Option_t *option="") const
static const char *const kDefaultCutFile
Definition THaCutList.h:36
virtual Int_t Remove(const char *cutname)
static void MakePrintOption(THaPrintOption &opt, const TList *plist)
virtual void Compile()
THaNamedList * FindBlock(const char *block) const
Definition THaCutList.h:59
virtual Int_t Define(const char *cutname, const char *expr, const char *block=kDefaultBlockName)
virtual void ClearAll(Option_t *opt="")
static const char *const kDefaultBlockName
Definition THaCutList.h:35
virtual void Print(Option_t *opt="") const
Definition THaCut.cxx:200
const char * GetBlockname() const
Definition THaCut.h:32
virtual void PrintOpt(Option_t *opt) const
virtual void PrintOpt(Option_t *opt="") const
const char * Data() const
const char * GetOption(Int_t i=0) const
Bool_t IsLine() const
Int_t GetValue(Int_t i=0) const
void Delete(Option_t *option="") override
void Clear(Option_t *option="") override
TObject * Remove(TObject *obj) override
TObject * FindObject(const char *name) const override
void AddLast(TObject *obj) override
void Add(TObject *obj) override
TObject * Remove(const TObjLinkPtr_t &lnk)
virtual TObjLink * FirstLink() const
void Delete(Option_t *option="") override
TLine * line
const Int_t n
const string kIncTag
Int_t CheckIncludeFilePath(string &incfile)
Int_t GetIncludeFileName(const string &line, string &incfile)
void Error(const char *location, const char *fmt,...)
void Warning(const char *location, const char *fmt,...)
double max(double x, double y)
start
STL namespace.
ClassImp(TPyArg)