LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
EventSelector.cc
Go to the documentation of this file.
2 
6 #include "boost/algorithm/string.hpp"
7 #include "cetlib/container_algorithms.h"
9 
10 #include <algorithm>
11 #include <cassert>
12 #include <regex>
13 
14 using namespace cet;
15 using namespace std;
16 
17 namespace art {
18 
19  EventSelector::EventSelector(Strings const& pathspecs, Strings const& names)
20  {
21  init(pathspecs, names);
22  }
23 
24  EventSelector::EventSelector(Strings const& pathspecs)
25  : results_from_current_process_(false), paths_(pathspecs)
26  {}
27 
29  Strings const& triggernames)
30  {
31  auto paths = config.get<Strings>("SelectEvents", {});
32  init(paths, triggernames);
33  }
34 
35  void
36  EventSelector::init(Strings const& paths, Strings const& triggernames)
37  {
38  accept_all_ = false;
40  exception_acceptors_.clear(), all_must_fail_.clear();
41  all_must_fail_noex_.clear();
42  nTriggerNames_ = triggernames.size();
43  notStarPresent_ = false;
44 
45  if (paths.empty()) {
46  accept_all_ = true;
47  return;
48  }
49 
50  // The following are for the purpose of establishing accept_all_ by
51  // virtue of an inclusive set of paths:
52  bool unrestricted_star = false;
53  bool negated_star = false;
54  bool exception_star = false;
55 
56  for (std::string const& pathSpecifier : paths) {
57 
58  string specifier{pathSpecifier};
59 
60  boost::erase_all(specifier, " \t"); // whitespace eliminated
61  if (specifier == "*")
62  unrestricted_star = true;
63  if (specifier == "!*")
64  negated_star = true;
65  if (specifier == "exception@*")
66  exception_star = true;
67 
68  // Remove "@noexception" from specifier
69  bool noex_demanded{false};
70  std::string const& noexLiteral{"&noexception"};
71  auto const noexception_pos = specifier.find(noexLiteral);
72  if (noexception_pos != string::npos) {
73  if (noexception_pos + noexLiteral.length() < specifier.length()) {
75  << "EventSelector::init, An OutputModule is using SelectEvents\n"
76  "to request a trigger name that has extra characters after "
77  "'&noexception'.\n"
78  << "The improper trigger name is: " << pathSpecifier << "\n";
79  }
80  specifier.erase(noexception_pos);
81  noex_demanded = true;
82  }
83 
84  // Remove '!' and "exception@"
85  bool negative_criterion{false};
86  if (specifier[0] == '!') {
87  negative_criterion = true;
88  specifier.erase(0, 1);
89  }
90  bool exception_spec{false};
91  std::string const& exLiteral{"exception@"};
92  auto const pos = specifier.find(exLiteral);
93  if (pos == 0) {
94  exception_spec = true;
95  specifier.erase(0, exLiteral.length());
96  } else if (pos != std::string::npos) {
98  << "EventSelector::init, An OutputModule is using SelectEvents\n"
99  "to request a trigger name that has disallowed characters before "
100  "'exception@'.\n"
101  << "The improper trigger name is: " << pathSpecifier << "\n";
102  }
103 
104  if (negative_criterion && exception_spec)
106  << "EventSelector::init, An OutputModule is using SelectEvents\n"
107  "to request a trigger name starting with !exception@.\n"
108  "This is not supported.\n"
109  << "The improper trigger name is: " << pathSpecifier << "\n";
110 
111  if (noex_demanded && exception_spec)
113  << "EventSelector::init, An OutputModule is using SelectEvents\n"
114  "to request a trigger name starting with exception@ "
115  "and also demanding no &exceptions.\n"
116  << "The improper trigger name is: " << pathSpecifier << "\n";
117 
118  // instead of "see if the name can be found in the full list of
119  // paths" we want to find all paths that match this name.
120  //
121  // 'specifier' now corresponds to the real trigger-path name,
122  // free of any decorations
123  std::string const& realname{specifier};
124  vector<Strings::const_iterator> matches =
125  regexMatch(triggernames, realname);
126 
127  if (matches.empty()) {
128  if (is_glob(realname)) {
129  mf::LogWarning("Configuration")
130  << "EventSelector::init, An OutputModule is using SelectEvents\n"
131  "to request a wildcarded trigger name that does not match any "
132  "trigger \n"
133  << "The wildcarded trigger name is: " << realname
134  << " (from trigger-path specification: " << pathSpecifier << ") \n";
135  } else {
137  << "EventSelector::init, An OutputModule is using SelectEvents\n"
138  "to request a trigger name that does not exist\n"
139  << "The unknown trigger name is: " << realname
140  << " (from trigger-path specification: " << pathSpecifier << ") \n";
141  }
142  }
143 
144  auto makeBitInfoPass = [&triggernames](auto m) {
145  return BitInfo(distance(triggernames.begin(), m), true);
146  };
147 
148  auto makeBitInfoFail = [&triggernames](auto m) {
149  return BitInfo(distance(triggernames.begin(), m), false);
150  };
151 
152  if (!negative_criterion && !noex_demanded && !exception_spec) {
153  cet::transform_all(
154  matches, std::back_inserter(absolute_acceptors_), makeBitInfoPass);
155  } else if (!negative_criterion && noex_demanded) {
156  cet::transform_all(
157  matches, std::back_inserter(conditional_acceptors_), makeBitInfoPass);
158  } else if (exception_spec) {
159  cet::transform_all(
160  matches, std::back_inserter(exception_acceptors_), makeBitInfoPass);
161  } else if (negative_criterion && !noex_demanded) {
162  if (matches.empty()) {
164  << "EventSelector::init, An OutputModule is using SelectEvents\n"
165  "to request all fails on a set of trigger names that do not "
166  "exist\n"
167  << "The problematic name is: " << pathSpecifier << "\n";
168 
169  } else if (matches.size() == 1) {
170  BitInfo bi(distance(triggernames.begin(), matches[0]), false);
171  absolute_acceptors_.push_back(bi);
172  } else {
173  Bits mustfail;
174  // We set this to false because that will demand bits are Fail.
175  cet::transform_all(
176  matches, std::back_inserter(mustfail), makeBitInfoFail);
177  all_must_fail_.push_back(mustfail);
178  }
179  } else if (negative_criterion && noex_demanded) {
180  if (matches.empty()) {
182  << "EventSelector::init, An OutputModule is using SelectEvents\n"
183  "to request all fails on a set of trigger names that do not "
184  "exist\n"
185  << "The problematic name is: " << pathSpecifier << "\n";
186  } else if (matches.size() == 1) {
187  BitInfo bi(distance(triggernames.begin(), matches[0]), false);
188  conditional_acceptors_.push_back(bi);
189  } else {
190  Bits mustfail;
191  cet::transform_all(
192  matches, std::back_inserter(mustfail), makeBitInfoFail);
193  all_must_fail_noex_.push_back(mustfail);
194  }
195  }
196  } // for (std::string pathSpecifier : paths)
197 
198  if (unrestricted_star && negated_star && exception_star)
199  accept_all_ = true;
200 
201  } // EventSelector::init
202 
203  bool
205  {
206  if (accept_all_)
207  return true;
208 
209  // For the current process we already initialized in the constructor,
210  // The trigger names will not change so we can skip initialization.
212 
213  // For previous processes we need to get the trigger names that
214  // correspond to the bits in TriggerResults from the ParameterSet
215  // set registry, which is stored once per file. The ParameterSetID
216  // stored in TriggerResults is the key used to find the info in the
217  // registry. We optimize using the fact the ID is unique. If the ID
218  // has not changed since the last time we initialized with new
219  // triggernames, then the names have not changed and we can skip this
220  // initialization.
221  if (!(psetID_initialized_ && psetID_ == tr.parameterSetID())) {
222 
223  Strings triggernames;
224  if (ServiceHandle<TriggerNamesService const> {}->getTrigPaths(
225  tr, triggernames)) {
226  init(paths_, triggernames);
227  psetID_ = tr.parameterSetID();
228  psetID_initialized_ = true;
229  }
230  // This should never happen
231  else {
233  << "EventSelector::acceptEvent cannot find the trigger names for\n"
234  "a process for which the configuration has requested that the\n"
235  "OutputModule use TriggerResults to select events from. This "
236  "should\n"
237  "be impossible, please send information to reproduce this "
238  "problem to\n"
239  "the art developers at artists@fnal.gov.\n";
240  }
241  }
242  }
243 
244  // Now make the decision, based on the supplied TriggerResults tr,
245  // which of course can be treated as an HLTGlobalStatus by inheritance
246 
247  return selectionDecision(tr);
248 
249  } // acceptEvent(TriggerResults const& tr)
250 
251  bool
253  {
254  if (accept_all_)
255  return true;
256 
257  bool exceptionPresent = false;
258  bool exceptionsLookedFor = false;
259 
261  return true;
263  exceptionPresent = containsExceptions(tr);
264  if (!exceptionPresent)
265  return true;
266  exceptionsLookedFor = true;
267  }
269  return true;
270 
271  for (auto const& f : all_must_fail_) {
272  if (acceptAllBits(f, tr))
273  return true;
274  }
275 
276  for (auto const& fn : all_must_fail_noex_) {
277  if (acceptAllBits(fn, tr)) {
278  if (!exceptionsLookedFor) {
279  exceptionPresent = containsExceptions(tr);
280  }
281  return !exceptionPresent;
282  }
283  }
284 
285  // If we have not accepted based on any of the acceptors, nor on any one of
286  // the all_must_fail_ collections, then we reject this event.
287 
288  return false;
289 
290  } // selectionDecision()
291 
292  // Indicate if any bit in the trigger results matches the desired value
293  // at that position, based on the Bits array. If s is Exception, this
294  // looks for a Exceptionmatch; otherwise, true-->Pass, false-->Fail.
295  bool
297  HLTGlobalStatus const& tr,
298  hlt::HLTState const& s) const
299  {
300  bool lookForException = (s == hlt::Exception);
301  for (auto const& b : bits) {
302  hlt::HLTState const bstate = lookForException ?
304  b.accept_state_ ? hlt::Pass : hlt::Fail;
305  if (tr[b.pos_].state() == bstate)
306  return true;
307  }
308  return false;
309  } // acceptOneBit
310 
311  // Indicate if *every* bit in the trigger results matches the desired value
312  // at that position, based on the Bits array: true-->Pass, false-->Fail.
313  bool
315  HLTGlobalStatus const& tr) const
316  {
317  for (auto const& b : bits) {
318  hlt::HLTState const bstate = b.accept_state_ ? hlt::Pass : hlt::Fail;
319  if (tr[b.pos_].state() != bstate)
320  return false;
321  }
322  return true;
323  } // acceptAllBits
324 
341  std::shared_ptr<TriggerResults>
343  {
344  // fetch and validate the total number of paths
345  unsigned int const N = nTriggerNames_;
346  if (N != inputResults.size()) {
348  << "EventSelector::maskTriggerResults, the TriggerResults\n"
349  << "size (" << inputResults.size()
350  << ") does not match the number of paths in the\n"
351  << "full trigger list (" << N << ").\n";
352  }
353 
354  // create a suitable global status object to work with, all in Ready state
355  HLTGlobalStatus mask{N};
356 
357  // Deal with must_fail acceptors that would cause selection
358  for (auto const& mf : all_must_fail_) {
359  vector<bool> const f = expandDecisionList(mf, false, N);
360  bool all_fail = true;
361  for (unsigned int ipath = 0; ipath < N; ++ipath) {
362  if ((f[ipath]) && (inputResults[ipath].state() != hlt::Fail)) {
363  all_fail = false;
364  break;
365  }
366  }
367  if (all_fail) {
368  for (unsigned int ipath = 0; ipath < N; ++ipath) {
369  if (f[ipath]) {
370  mask[ipath] = hlt::Fail;
371  }
372  }
373  }
374  }
375  for (auto const& mf_noex : all_must_fail_noex_) {
376  vector<bool> const f = expandDecisionList(mf_noex, false, N);
377  bool all_fail = true;
378  for (unsigned int ipath = 0; ipath < N; ++ipath) {
379  if ((f[ipath]) && (inputResults[ipath].state() != hlt::Fail)) {
380  all_fail = false;
381  break;
382  }
383  }
384  if (all_fail) {
385  for (unsigned int ipath = 0; ipath < N; ++ipath) {
386  if (f[ipath]) {
387  mask[ipath] = hlt::Fail;
388  }
389  }
390  }
391  } // factoring opportunity - work done for fail_noex_ is same as for fail_
392 
393  // Deal with normal acceptors that would cause selection
394  vector<bool> aPassAbs = expandDecisionList(absolute_acceptors_, true, N);
395  vector<bool> aPassCon = expandDecisionList(conditional_acceptors_, true, N);
396  vector<bool> aFailAbs = expandDecisionList(absolute_acceptors_, false, N);
397  vector<bool> aFailCon =
399  vector<bool> aExc = expandDecisionList(exception_acceptors_, true, N);
400 
401  for (unsigned int ipath = 0; ipath < N; ++ipath) {
402  hlt::HLTState s = inputResults[ipath].state();
403  if (((aPassAbs[ipath]) && (s == hlt::Pass)) ||
404  ((aPassCon[ipath]) && (s == hlt::Pass)) ||
405  ((aFailAbs[ipath]) && (s == hlt::Fail)) ||
406  ((aFailCon[ipath]) && (s == hlt::Fail)) ||
407  ((aExc[ipath]) && (s == hlt::Exception))) {
408  mask[ipath] = s;
409  }
410  }
411 
412  // Based on the global status for the mask, create and return a
413  // TriggerResults
414  return std::make_shared<TriggerResults>(mask,
415  inputResults.parameterSetID());
416  } // maskTriggerResults
417 
418  bool
420  {
421  unsigned int e = tr.size();
422  for (unsigned int i = 0; i < e; ++i) {
423  if (tr[i].state() == hlt::Exception)
424  return true;
425  }
426  return false;
427  }
428 
429  // The following routines are helpers for testSelectionOverlap
430 
431  bool
432  EventSelector::identical(vector<bool> const& a, vector<bool> const& b)
433  {
434  unsigned int n = a.size();
435  if (n != b.size())
436  return false;
437  for (unsigned int i = 0; i != n; ++i) {
438  if (a[i] != b[i])
439  return false;
440  }
441  return true;
442  }
443 
444  bool
446  EventSelector const& b,
447  unsigned int N)
448  {
449  // create the expanded masks for the various decision lists in a and b
452  return false;
455  return false;
458  return false;
461  return false;
464  return false;
465  if (a.all_must_fail_.size() != b.all_must_fail_.size())
466  return false;
467 
468  vector<vector<bool>> aMustFail;
469  for (unsigned int m = 0; m != a.all_must_fail_.size(); ++m) {
470  aMustFail.push_back(expandDecisionList(a.all_must_fail_[m], false, N));
471  }
472  vector<vector<bool>> aMustFailNoex;
473  for (unsigned int m = 0; m != a.all_must_fail_noex_.size(); ++m) {
474  aMustFailNoex.push_back(
475  expandDecisionList(a.all_must_fail_noex_[m], false, N));
476  }
477  vector<vector<bool>> bMustFail;
478  for (unsigned int m = 0; m != b.all_must_fail_.size(); ++m) {
479  bMustFail.push_back(expandDecisionList(b.all_must_fail_[m], false, N));
480  }
481  vector<vector<bool>> bMustFailNoex;
482  for (unsigned int m = 0; m != b.all_must_fail_noex_.size(); ++m) {
483  bMustFailNoex.push_back(
484  expandDecisionList(b.all_must_fail_noex_[m], false, N));
485  }
486 
487  for (unsigned int m = 0; m != aMustFail.size(); ++m) {
488  bool match = false;
489  for (unsigned int k = 0; k != bMustFail.size(); ++k) {
490  if (identical(aMustFail[m], bMustFail[k])) {
491  match = true;
492  break;
493  }
494  }
495  if (!match)
496  return false;
497  }
498  for (unsigned int m = 0; m != aMustFailNoex.size(); ++m) {
499  bool match = false;
500  for (unsigned int k = 0; k != bMustFailNoex.size(); ++k) {
501  if (identical(aMustFailNoex[m], bMustFailNoex[k])) {
502  match = true;
503  break;
504  }
505  }
506  if (!match)
507  return false;
508  }
509 
510  return true;
511 
512  } // identical (EventSelector, EventSelector, N);
513 
514  vector<bool>
516  bool PassOrFail,
517  unsigned int n)
518  {
519  vector<bool> x(n, false);
520  for (unsigned int i = 0; i != b.size(); ++i) {
521  if (b[i].accept_state_ == PassOrFail)
522  x[b[i].pos_] = true;
523  }
524  return x;
525  } // expandDecisionList
526 
527  // Determines whether a and b share a true bit at any position
528  bool
529  EventSelector::overlapping(vector<bool> const& a, vector<bool> const& b)
530  {
531  if (a.size() != b.size())
532  return false;
533  for (unsigned int i = 0; i != a.size(); ++i) {
534  if (a[i] && b[i])
535  return true;
536  }
537  return false;
538  } // overlapping
539 
540  // determines whether the true bits of a are a non-empty subset of those of b,
541  // or vice-versa. The subset need not be proper.
542  bool
543  EventSelector::subset(vector<bool> const& a, vector<bool> const& b)
544  {
545  if (a.size() != b.size())
546  return false;
547  // First test whether a is a non-empty subset of b
548  bool aPresent = false;
549  bool aSubset = true;
550  for (unsigned int i = 0; i != a.size(); ++i) {
551  if (a[i]) {
552  aPresent = true;
553  if (!b[i]) {
554  aSubset = false;
555  break;
556  }
557  }
558  }
559  if (!aPresent)
560  return false;
561  if (aSubset)
562  return true;
563 
564  // Now test whether b is a non-empty subset of a
565  bool bPresent = false;
566  bool bSubset = true;
567  for (unsigned int i = 0; i != b.size(); ++i) {
568  if (b[i]) {
569  bPresent = true;
570  if (!a[i]) {
571  bSubset = false;
572  break;
573  }
574  }
575  }
576  if (!bPresent)
577  return false;
578  if (bSubset)
579  return true;
580 
581  return false;
582  } // subset
583 
584  // Creates a vector of bits which is the OR of a and b
585  vector<bool>
586  EventSelector::combine(vector<bool> const& a, vector<bool> const& b)
587  {
588  assert(a.size() == b.size());
589  vector<bool> x(a.size());
590  for (unsigned int i = 0; i != a.size(); ++i) {
591  x[i] = a[i] || b[i];
592  } // a really sharp compiler will optimize the hell out of this,
593  // exploiting word-size OR operations.
594  return x;
595  } // combine
596 
597 } // art
Float_t x
Definition: compare.C:6
Float_t s
Definition: plot.C:23
EventSelector(Strings const &pathspecs, Strings const &names)
std::vector< std::vector< std::string >::const_iterator > regexMatch(std::vector< std::string > const &strings, std::regex const &regexp)
Definition: RegexMatch.cc:27
STL namespace.
bool results_from_current_process_
Definition: EventSelector.h:74
std::vector< BitInfo > Bits
Definition: EventSelector.h:65
HLTState
status of a trigger path
Definition: HLTenums.h:14
hlt::HLTState state(std::size_t const i) const
TFile f
Definition: plotHisto.C:6
bool acceptOneBit(Bits const &b, HLTGlobalStatus const &tr, hlt::HLTState const &s=hlt::Ready) const
std::vector< std::string > Strings
Definition: EventSelector.h:36
bool containsExceptions(HLTGlobalStatus const &tr) const
T get(std::string const &key) const
Definition: ParameterSet.h:231
void init(Strings const &paths, Strings const &triggernames)
static bool overlapping(std::vector< bool > const &a, std::vector< bool > const &b)
std::size_t size() const
fhicl::ParameterSetID const & parameterSetID() const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
static bool identical(std::vector< bool > const &a, std::vector< bool > const &b)
static std::vector< bool > expandDecisionList(Bits const &b, bool PassOrFail, unsigned int n)
std::vector< Bits > all_must_fail_noex_
Definition: EventSelector.h:72
bool selectionDecision(HLTGlobalStatus const &tr) const
static std::vector< bool > combine(std::vector< bool > const &a, std::vector< bool > const &b)
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
std::shared_ptr< TriggerResults > maskTriggerResults(TriggerResults const &inputResults)
HLT enums.
std::vector< Bits > all_must_fail_
Definition: EventSelector.h:71
Char_t n[5]
accept
Definition: HLTenums.h:16
reject
Definition: HLTenums.h:17
Float_t e
Definition: plot.C:34
bool acceptAllBits(Bits const &b, HLTGlobalStatus const &tr) const
static bool subset(std::vector< bool > const &a, std::vector< bool > const &b)
bool is_glob(std::string const &pattern)
Definition: RegexMatch.cc:13
fhicl::ParameterSetID psetID_
Definition: EventSelector.h:76
bool acceptEvent(TriggerResults const &)