LCIO  02.17
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lcio_check_col_elements.cc
Go to the documentation of this file.
1 
13 // getopt includes
14 // http://www.ibm.com/developerworks/aix/library/au-unix-getopt.html#listing3
15 //#include <unistd.h> // for getopt
16 #include <getopt.h> // for getopt long
17 
18 // std includes
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <string>
23 #include <vector>
24 #include <sstream>
25 #include <cmath>
26 
27 // lcio includes
28 #include "lcio.h"
29 #include "IO/LCReader.h"
30 #include "IMPL/LCTOOLS.h"
31 #include "IMPL/LCCollectionVec.h"
32 //#include "EVENT/LCRunHeader.h"
33 
34 using namespace std ;
35 using namespace lcio ;
36 
37 
38 // struct for storing global options
39 struct opts_t {
40  const char* colName; // COLLECTION_NAME
41  char** inputFiles; // INPUT_FILE(S)
42  int inputFilesNum; // # of INPUT_FILE(S)
43  int verbosity; // -v option
44  bool pedantic; // -p option
45  bool average; // -a option
46  int startevent; // --startevent option
47  int maxevents; // --maxevents option
48  int expelements; // --expelements option
49  int minelements; // --minelements option
50  int maxelements; // --maxelements option
51  int abselementerror; // --abselementerror option
52  int abseventerror; // --abseventerror option
53  float relelementerror; // --relelementerror option
54  float releventerror; // --releventerror option
55  // counters
56  int elementsTotal; // total number of elements
57  int eventsTotal; // total number of events
58  int eventsFailed; // total number of events where element checking has failed
59  int eventsSkipped; // total number of events skipped (i.e. events which contain no elements)
60 } opts;
61 
62 // number of command line arguments (not including options)
63 static const int min_args = 2 ;
64 
65 // getopt string
66 // ':' after an option means that option requires an argument
67 static const char *optString = "s:n:x:m:M:pavh?" ;
68 
69 // getopt long options declarations
70 static const struct option longOpts[] = {
71  { "verbose", no_argument, NULL, 'v' },
72  { "pedantic", no_argument, NULL, 'p' },
73  { "average", no_argument, NULL, 'a' },
74  { "startevent", required_argument, NULL, 's' },
75  { "maxevents", required_argument, NULL, 'n' },
76  { "expelements", required_argument, NULL, 'x' },
77  { "minelements", required_argument, NULL, 'm' },
78  { "maxelements", required_argument, NULL, 'M' },
79  { "abselementerror", required_argument, NULL, 0 },
80  { "abseventerror", required_argument, NULL, 0 },
81  { "relelementerror", required_argument, NULL, 0 },
82  { "releventerror", required_argument, NULL, 0 },
83  { "help", no_argument, NULL, 'h' },
84  { NULL, no_argument, NULL, 0 }
85 };
86 
87 /* Display program usage, and exit.
88  */
89 void display_usage( const char* progName, const std::string& errmsg = "" )
90 {
91  stringstream msg;
92  if( errmsg != "" )
93  {
94  msg << endl << "error: " << errmsg << endl ;
95 
96  }
97 
98  msg << endl
99  << "lcio tool for checking an expected number of elements in lcio file(s) from a given collection name"
100  << endl << endl
101  << " use: " << progName << " [OPTIONS] COLLECTION_NAME INPUT_FILE(S)"
102  << endl << endl
103  << " OPTIONS:"
104  << endl << endl
105  << " -v, --verbose : increase verbosity (use -vvv for debugging)"
106  << endl
107  << " -p, --pedantic : events which contain no elements are counted as failed events and"
108  << endl
109  << " not ignored for calculating the average number of elements"
110  << endl
111  << " -a, --average : use this option to check the average number of elements instead of treating events individually"
112  << endl
113  << " -s, --startevent : start event number (default = 0)"
114  << endl
115  << " -n, --maxevents : maximum number of events (default = all events)"
116  << endl
117  << " -m, --minelements : if set this value is used as the absolute minimum number of elements (*)"
118  << endl
119  << " -M, --maxelements : if set this value is used as the absolute maximum number of elements (*)"
120  << endl
121  << " -x, --expelements : expected number of elements +- error , if no error is given the exact value is expected!"
122  << endl
123  << " --abselementerror : absolute error for elements, e.g. if expelements = 100 and abselementerror = 3, valid range will be [97-103]"
124  << endl
125  << " --relelementerror : relative error for elements, e.g. if expelements = 100 and relelementerror = 0.1, valid range will be [90 - 110]"
126  << endl
127  << " --abseventerror : absolute error for events, e.g. abseventerror = 3 means that at most 3 events may fail (**)"
128  << endl
129  << " --releventerror : relative error for events, e.g. releventerror = 0.1 means that at most 10% of the total events may fail (**)"
130  << endl << endl
131  << " (*) --minelements and --maxelements options always have priority over other options!"
132  << endl << endl
133  << " (**) --abseventerror and --releventerror options are both influenced by --pedantic option, i.e."
134  << endl
135  << " not only the events which fail the checking of elements are counted as failed, "
136  << endl
137  << " but also the ones which do not contain any elements."
138  << endl << endl << endl
139  << " EXAMPLES:"
140  << endl << endl
141  << " display stats for MCParticle collections found in simjobs.slcio:"
142  << endl
143  << " " << progName << " MCParticle simjob.slcio"
144  << endl << endl
145  << " check that MCParticle collections in simjob.slcio contain exactly 101 elements in all events:"
146  << endl
147  << " " << progName << " --expelements 101 MCParticle simjob.slcio"
148  << endl << endl
149  << " check that the average number of elements from the MCParticle collections in simjob.slcio lies between [99-101]"
150  << endl
151  << " # note that --abselementerror 1 can be left out as checking for the exact average doesn't really make much sense.."
152  << endl
153  << " " << progName << " -a --expelements 100 --abselementerror 1 MCParticle simjob.slcio"
154  << endl << endl
155  << " check that MCParticle collections in simjob.slcio contain 100 +- 3% elements in all events --> [97-103]:"
156  << endl
157  << " " << progName << " --expelements 100 --relelementerror .03 MCParticle simjob.slcio"
158  << endl << endl
159  << " check that MCParticle collections in simjob.slcio and recjob.slcio contain 100 +- 1 element where 10 events may fail the check:"
160  << endl
161  << " " << progName << " --expelements 100 --abselementerror 1 --abseventerror 10 MCParticle simjob.slcio recjobs.slcio"
162  << endl << endl
163  << " check that MCParticle collections in simjob.slcio and recjob.slcio contain 100 +- 1 element where half the events may fail the check:"
164  << endl
165  << " " << progName << " --expelements 100 --abselementerror 1 --releventerror .5 MCParticle simjob.slcio recjobs.slcio"
166  << endl << endl
167  ;
168  cerr << msg.str() << endl << endl;
169  exit( EXIT_FAILURE );
170 }
171 
172 void showopts( void )
173 {
174  cout << endl;
175  cout << "-----------------------------------" << endl ;
176  cout << "debug infos:" << endl ;
177  cout << "-----------------------------------" << endl ;
178  cout << "collectionName: " << opts.colName << endl ;
179  cout << "pedantic: " << opts.pedantic << endl ;
180  cout << "average: " << opts.average << endl ;
181  cout << "startevent: " << opts.startevent << endl ;
182  cout << "maxevents: " << opts.maxevents << endl ;
183  cout << "minelements: " << opts.minelements << endl ;
184  cout << "maxelements: " << opts.maxelements << endl ;
185  cout << "expelements: " << opts.expelements << endl ;
186  cout << "abselementerror: " << opts.abselementerror << endl ;
187  cout << "relelementerror: " << opts.relelementerror << endl ;
188  cout << "abseventerror: " << opts.abseventerror << endl ;
189  cout << "releventerror: " << opts.releventerror << endl ;
190  cout << "elementsTotal: " << opts.elementsTotal << endl ;
191  cout << "eventsTotal: " << opts.eventsTotal << endl ;
192  cout << "eventsFailed: " << opts.eventsFailed << endl ;
193  cout << "eventsSkipped: " << opts.eventsSkipped << endl ;
194  cout << "-----------------------------------" << endl ;
195  cout << endl << endl ;
196 }
197 
198 //enum loglevels { DEBUG, INFO, WARNING, ERROR };
199 
200 
201 
202 int main(int argc, char** argv ){
203 
204  int opt = 0;
205  int longIndex = 0;
206 
207  /* Initialize opts before we get to work. */
208  opts.verbosity = 0;
209  opts.colName = NULL; // COLLECTION_NAME
210  opts.inputFiles = NULL; // INPUT_FILE(S)
211  opts.inputFilesNum = 0; // # of INPUT_FILE(S)
212  opts.pedantic = false;
213  opts.average = false;
214  opts.startevent = 0; // 0 == not set
215  opts.maxevents = 0; // 0 == not set
216  opts.minelements = 0; // 0 == not set
217  opts.maxelements = 0; // 0 == not set
218  opts.expelements = 0; // 0 == not set
219  opts.abselementerror = 0; // 0 == not set
220  opts.abseventerror = 0; // 0 == not set
221  opts.relelementerror = 0; // 0 == not set
222  opts.releventerror = 0; // 0 == not set
223  //initialize counters
224  opts.elementsTotal = 0 ;
225  opts.eventsTotal = 0 ;
226  opts.eventsFailed = 0 ;
227  opts.eventsSkipped = 0 ;
228 
229  // process the arguments with getopt_long(), then populate opts.
230  opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
231  while( opt != -1 )
232  {
233  switch( opt )
234  {
235  case 'h': /* fall-through is intentional */
236  case '?':
237  display_usage( argv[0] );
238  break;
239 
240  case 'p':
241  opts.pedantic = true;
242  break;
243 
244  case 'a':
245  opts.average = true;
246  break;
247 
248  case 'v':
249  opts.verbosity++;
250  break;
251 
252  case 's':
253  opts.startevent = atoi(optarg);
254 
255  if( opts.startevent < 0 )
256  {
257  display_usage( argv[0], "invalid option: startevent must be >= 0" );
258  }
259  break;
260 
261  case 'n':
262  opts.maxevents = atoi(optarg);
263 
264  if( opts.maxevents < 1 )
265  {
266  display_usage( argv[0], "invalid option: maxevents must be >= 1" );
267  }
268  break;
269 
270  case 'x':
271  opts.expelements = atoi(optarg);
272 
273  if( opts.expelements < 1 )
274  {
275  display_usage( argv[0], "invalid option: expelements must be > 1" );
276  }
277  break;
278 
279  case 'm':
280  opts.minelements = atoi(optarg);
281 
282  if( opts.minelements < 1 )
283  {
284  display_usage( argv[0], "invalid option: minelements must be > 1" );
285  }
286  break;
287 
288  case 'M':
289  opts.maxelements = atoi(optarg);
290 
291  if( opts.maxelements < 1 )
292  {
293  display_usage( argv[0], "invalid option: maxelements must be > 1" );
294  }
295  break;
296 
297 
298  // long options without a short arg
299  case 0:
300 
301  if( strcmp( "abselementerror", longOpts[longIndex].name ) == 0 )
302  {
303  opts.abselementerror = atoi(optarg);
304 
305  if( opts.abselementerror < 1 )
306  {
307  display_usage( argv[0], "invalid option: abselementerror must be > 1" );
308  }
309  }
310 
311  if( strcmp( "abseventerror", longOpts[longIndex].name ) == 0 )
312  {
313  opts.abseventerror = atoi(optarg);
314 
315  if( opts.abseventerror < 1 )
316  {
317  display_usage( argv[0], "invalid option: abseventerror must be > 1" );
318  }
319  }
320 
321  if( strcmp( "relelementerror", longOpts[longIndex].name ) == 0 )
322  {
323  opts.relelementerror = atof(optarg);
324 
325  if( opts.relelementerror <= 0 || opts.relelementerror >= 1)
326  {
327  display_usage( argv[0], "invalid option: 0 < relelementerror < 1 , (e.g.: 0.3)" );
328  }
329  }
330 
331  if( strcmp( "releventerror", longOpts[longIndex].name ) == 0 )
332  {
333  opts.releventerror = atof(optarg);
334 
335  if( opts.releventerror <= 0 || opts.releventerror >= 1)
336  {
337  display_usage( argv[0], "invalid option: 0 < releventerror < 1 , (e.g.: 0.3)" );
338  }
339  }
340 
341  break;
342 
343 
344  default:
345  // should never get here!
346  break;
347  }
348 
349  opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
350  }
351 
352  // argc also includes command line options
353  // optind is set to the index of the first positional command line argument
354  // so (argc - optind) == total number of command line arguments (without options)
355  if( (argc - optind) < min_args )
356  {
357  display_usage( argv[0], "wrong number of arguments" );
358  }
359 
360  //if( opts.minelements == 0 && opts.maxelements == 0 && opts.expelements == 0 )
361  //{
362  // display_usage( argv[0], "one of the following options must be set: minelements, maxelements or expelements" );
363  //}
364 
365  if( opts.abselementerror > 0 && opts.relelementerror > 0 )
366  {
367  display_usage( argv[0], "abselementerror and relelementerror options are mutually exclusive" );
368  }
369 
370  if( opts.abseventerror > 0 && opts.releventerror > 0 )
371  {
372  display_usage( argv[0], "abseventerror and releventerror options are mutually exclusive" );
373  }
374 
375  if( (opts.abseventerror > 0 || opts.releventerror > 0 ) && opts.average )
376  {
377  display_usage( argv[0], "average option cannot be used in conjunction with abseventerror or releventerror options" );
378  }
379 
380 
381 
382  // check if the expected elements option is set
383  if( opts.expelements > 0 )
384  {
385  // look if any error options are used and set min and max elements appropriately
386  if( (opts.abselementerror > 0) || (opts.relelementerror > 0) )
387  {
388  if( opts.relelementerror > 0 )
389  {
391  // in case the expression above rounds to 0 we need to set it to 1
392  // to ensure minelements and maxelements are set appropriately
393  if( opts.abselementerror == 0 )
394  {
395  opts.abselementerror = 1 ;
396  }
397  }
398 
399  if( opts.abselementerror > 0 )
400  {
401  // if minelements option is set it always overwrites other options
402  if( opts.minelements == 0 )
403  {
405 
406  // make sure minelements is always >= 0
407  if( opts.minelements < 0 )
408  {
409  opts.minelements = 0;
410  }
411  }
412 
413  // if maxelements option is set it always overwrites other options
414  if( opts.maxelements == 0 )
415  {
417  }
418  }
419  }
420  else // if no error options are set, the exact number of elements is expected
421  {
422 
423  // if minelements option is set it always overwrites other options
424  if( opts.minelements == 0 )
425  {
427  if( opts.average )
428  {
429  // if average option is used we need to add a +-1 range
430  // to ensure that the avg float number lies between minelements and maxelements
431  opts.minelements-- ;
432  }
433  }
434 
435  // if maxelements option is set it always overwrites other options
436  if( opts.maxelements == 0 )
437  {
439  if( opts.average )
440  {
441  // if average option is used we need to add a +-1 range
442  // to ensure that the avg float number lies between minelements and maxelements
443  opts.maxelements++ ;
444  }
445  }
446  }
447  }
448  else // expected elements option not set
449  {
450  if( opts.abselementerror > 0 || opts.relelementerror > 0 )
451  {
452  display_usage( argv[0], "expelements option must be set if using abselementerror or relelementerror" );
453  }
454  }
455 
456  // make sure maxelements is always greater than minelements
457  if( opts.maxelements > 0 && ( opts.maxelements < opts.minelements ) )
458  {
459  display_usage( argv[0], "maxelements must be > minelements" );
460  }
461 
462  // collection name
463  opts.colName = argv[optind] ;
464  optind++; // increment optind to the next argument
465 
466  // and finally the remaining list of lcio files
467  opts.inputFiles = argv + optind;
468  opts.inputFilesNum = argc - optind;
469 
470  //showopts();
471 
472 
473  // ---------------------------------------------------------------------
474  // end of command line argument parsing
475  // ---------------------------------------------------------------------
476 
477 
478  vector<string> inputFilesVec ;
479 
480  for( int i=0 ; i < opts.inputFilesNum ; i++ ){
481  //cout << opts.inputFiles[ i ] << endl;
482  inputFilesVec.push_back( opts.inputFiles[ i ] );
483  }
484 
485  LCReader* lcReader = LCFactory::getInstance()->createLCReader() ;
486 
487  lcReader->open( inputFilesVec ) ;
488 
489  if( opts.startevent > 0 ){
490  lcReader->skipNEvents( opts.startevent );
491  }
492 
493 
494  LCEvent* event = NULL ;
495  LCCollection* elements = NULL ;
496 
497  //----------- the event loop -----------
498  try{
499  while( (event = lcReader->readNextEvent()) != 0 )
500  {
501  try
502  {
503  elements = event->getCollection( opts.colName );
504  }
505  catch( lcio::DataNotAvailableException& e )
506  {
507  //cerr << "error in event [" << opts.eventsTotal << "] no elements were found" << endl;
508  //cerr << e.what() << endl ;
509  elements = NULL ;
510  }
511 
512  if( elements != NULL )
513  {
514  int nelements = elements->getNumberOfElements() ;
515  // cout << opts.colName << " : " << nelements << endl;
516 
517  if( nelements < opts.minelements )
518  {
519  //cerr << "error in event [" << opts.eventsTotal << "]: minelements condition failed: nelements [" << nelements << "] < minelements [" << opts.minelements << "]" << endl;
520  opts.eventsFailed++ ;
521  }
522 
523  if( opts.maxelements > 0 )
524  {
525  if( nelements > opts.maxelements )
526  {
527  //cerr << "error in event [" << opts.eventsTotal << "]: maxelements condition failed: nelements [" << nelements << "] > maxelements [" << opts.maxelements << "]" << endl;
528  opts.eventsFailed++ ;
529  }
530  }
531  opts.elementsTotal += nelements ;
532  }
533  else // event which contains no elements from the given collection
534  {
535  opts.eventsSkipped++ ;
536 
537  if( opts.pedantic )
538  {
539  opts.eventsFailed++ ; // in pedantic mode events containing no elements are marked as failed
540  }
541  }
542  //LCTOOLS::dumpEvent( event ) ;
543  opts.eventsTotal++ ;
544 
546  {
547  break ;
548  }
549  }
550  }
551  catch( lcio::IOException& e )
552  //catch( ... )
553  {
554  cerr << "io error when reading data : " << e.what() << endl ;
555  }
556  // -------- end of event loop -----------
557 
558  // free lcReader
559  lcReader->close();
560  delete lcReader ;
561 
562 
563  // --------------- show some stats -------------------------------------------------------------------------
564 
565  float avg = 0 ;
566 
567  if( opts.eventsTotal > 0 )
568  {
569 
570  if( opts.pedantic )
571  {
572  avg = (float)opts.elementsTotal / opts.eventsTotal ;
573  }
574  else
575  {
577  {
578  avg = (float)opts.elementsTotal / (opts.eventsTotal - opts.eventsSkipped) ;
579  }
580  }
581 
582  if( opts.releventerror > 0 )
583  {
585  }
586 
587  cout << endl ;
588  cout << "-----------------------------------------------------------" << endl ;
589  cout << endl ;
590  cout << "found " << opts.elementsTotal << " " << opts.colName << " element(s) in " << opts.eventsTotal << " event(s)" << endl ;
591  cout << "avg number of " << opts.colName << " elements per event: " << avg << endl ;
592 
593  if( opts.eventsSkipped )
594  {
595  cout << opts.eventsSkipped << " event(s) contained no elements from " << opts.colName << endl ;
596  }
597 
598  if( opts.eventsFailed > 0 )
599  {
600  cout << opts.eventsFailed << " event" << (opts.eventsFailed==1?" has":"s have") << " failed matching the expected number of elements" << endl ;
601  }
602 
604  {
605  cerr << "no " << opts.colName << " collection was found!" << endl ;
606  return EXIT_FAILURE ;
607  }
608  }
609  else
610  {
611  cerr << "no events were found!" << endl ;
612  return EXIT_FAILURE ;
613  }
614 
615  showopts() ;
616 
617  cout << "-----------------------------------------------------------" << endl ;
618 
619  if( opts.average )
620  {
621  if( avg < opts.minelements )
622  {
623  return EXIT_FAILURE ;
624  }
625 
626  if( (opts.maxelements > 0) && (avg > opts.maxelements) )
627  {
628  return EXIT_FAILURE ;
629  }
630  }
631  else
632  {
634  {
635  return EXIT_FAILURE ;
636  }
637  }
638 
639  return EXIT_SUCCESS;
640 }
641 
T atoi(T...args)
static const char * optString
T endl(T...args)
struct opts_t opts
void showopts(void)
LCEvent * event
Definition: lsh.cc:80
STL class.
T push_back(T...args)
T exit(T...args)
int main(int argc, char **argv)
Simple program that opens existing LCIO files and appends the records needed for direct access - if t...
T strcmp(T...args)
T str(T...args)
static struct option longOpts[]
T atof(T...args)
LCReader * lcReader
Definition: lsh.cc:78
const char * colName
void display_usage(const char *progName, const std::string &errmsg="")
T round(T...args)
static const int min_args