Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-10-06 02:53:58

0001 // Change Log
0002 //
0003 // 1 - M Fischler 2/8/08 Enable partial wildcards, as in HLT* or !CAL*
0004 //           A version of this code with cerr debugging traces has
0005 //           been placed in the doc area.
0006 //           See ../doc/EventSelector-behavior.doc for details of
0007 //           reactions to Ready or Exception states.
0008 // 1a M Fischler 2/13/08 Clear the all_must_fail_ array at the start of initPathNames.
0009 //           This is needed in the case of paths with wildcards,
0010 //           on explicit processes other than a current process
0011 //           (in which case initPathNames() is called whenever the trigger
0012 //           PSetID changes, and we don't want the old array
0013 //           contents to stick around.
0014 //
0015 // 2 - M Fischler 2/21/08 (In preparation for "exception-awareness" features):
0016 //           Factored out the decision making logic from the
0017 //           two forms of acceptEvent, into the single routine
0018 //           selectionDecision().
0019 //
0020 // 3 - M Fischler 2/25/08 (Toward commit of "exception-awareness" features):
0021 //           @exception and noexception& features
0022 //
0023 // 4- M Fischler 2/28/08 Repair ommision in selectionIsValid when pathspecs
0024 //          is just "!*"
0025 //
0026 // 5- M Fischler 3/3/08 testSelectionOverlap and maskTriggerResults appropriate
0027 //          for the new forms of pathspecs
0028 //
0029 // 6 - K Biery 03/24/08 modified maskTriggerResults (no longer static) to
0030 //                      avoid performance penalty of creating a new
0031 //                      EventSelector instance for each call (in static case)
0032 //
0033 
0034 #include "FWCore/Framework/interface/EventSelector.h"
0035 #include "FWCore/ServiceRegistry/interface/Service.h"
0036 #include "FWCore/Framework/interface/TriggerNamesService.h"
0037 #include "FWCore/Utilities/interface/RegexMatch.h"
0038 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0039 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0040 #include "FWCore/ParameterSet/interface/Registry.h"
0041 
0042 #include <algorithm>
0043 #include <cctype>
0044 #include <cassert>
0045 
0046 namespace edm {
0047   using Strings = EventSelector::Strings;
0048   EventSelector::EventSelector(Strings const& pathspecs, Strings const& pathNames)
0049       : pathspecs_(initPathSpecs(pathspecs)),
0050         results_from_current_process_(true),
0051         accept_all_(initAcceptAll()),
0052         absolute_acceptors_(),
0053         conditional_acceptors_(),
0054         exception_acceptors_(),
0055         all_must_fail_(),
0056         all_must_fail_noex_(),
0057         psetID_(),
0058         nPathNames_(0) {
0059     initPathNames(pathNames);
0060   }
0061 
0062   EventSelector::EventSelector(Strings const& pathspecs)
0063       : pathspecs_(initPathSpecs(pathspecs)),
0064         results_from_current_process_(false),
0065         accept_all_(initAcceptAll()),
0066         absolute_acceptors_(),
0067         conditional_acceptors_(),
0068         exception_acceptors_(),
0069         all_must_fail_(),
0070         all_must_fail_noex_(),
0071         psetID_(),
0072         nPathNames_(0) {}
0073 
0074   EventSelector::EventSelector(ParameterSet const& config, Strings const& pathNames)
0075       : pathspecs_(config.empty() ? Strings() : initPathSpecs(config.getParameter<Strings>("SelectEvents"))),
0076         results_from_current_process_(true),
0077         accept_all_(initAcceptAll()),
0078         absolute_acceptors_(),
0079         conditional_acceptors_(),
0080         exception_acceptors_(),
0081         all_must_fail_(),
0082         all_must_fail_noex_(),
0083         psetID_(),
0084         nPathNames_(0) {
0085     initPathNames(pathNames);
0086   }
0087 
0088   Strings EventSelector::initPathSpecs(Strings const& pathSpecs) {
0089     Strings trimmedPathSpecs(pathSpecs);
0090     for (auto& pathspecifier : trimmedPathSpecs) {
0091       pathspecifier.erase(std::remove_if(pathspecifier.begin(),
0092                                          pathspecifier.end(),
0093                                          [](char c) { return std::isspace(static_cast<unsigned char>(c)); }),
0094                           pathspecifier.end());  // whitespace eliminated
0095     }
0096     // Return value optimization should avoid another copy;
0097     return trimmedPathSpecs;
0098   }
0099 
0100   bool EventSelector::initAcceptAll() {
0101     if (pathspecs_.empty()) {
0102       return true;
0103     }
0104     // The following are for the purpose of establishing accept_all_ by
0105     // virtue of an inclusive set of paths:
0106     bool unrestricted_star = false;
0107     bool negated_star = false;
0108     bool exception_star = false;
0109 
0110     for (auto const& pathspecifier : pathspecs_) {
0111       if (pathspecifier == "*")
0112         unrestricted_star = true;
0113       if (pathspecifier == "!*")
0114         negated_star = true;
0115       if (pathspecifier == "exception@*")
0116         exception_star = true;
0117     }
0118     return (unrestricted_star && negated_star && exception_star);
0119   }
0120 
0121   void EventSelector::initPathNames(Strings const& pathNames) {
0122     if (accept_all_) {
0123       return;
0124     }
0125     // std::cerr << "### init entered\n";
0126     absolute_acceptors_.clear(), conditional_acceptors_.clear(), exception_acceptors_.clear(), all_must_fail_.clear();
0127     all_must_fail_noex_.clear();
0128     nPathNames_ = pathNames.size();
0129 
0130     for (auto const& pathspecifier : pathspecs_) {
0131       std::string basePathSpec(pathspecifier);
0132       bool noex_demanded = false;
0133       std::string::size_type and_noexception = pathspecifier.find("&noexception");
0134       if (and_noexception != std::string::npos) {
0135         basePathSpec = pathspecifier.substr(0, and_noexception);
0136         noex_demanded = true;
0137       }
0138       std::string::size_type and_noex = pathspecifier.find("&noex");
0139       if (and_noex != std::string::npos) {
0140         basePathSpec = pathspecifier.substr(0, and_noexception);
0141         noex_demanded = true;
0142       }
0143       and_noexception = basePathSpec.find("&noexception");
0144       and_noex = basePathSpec.find("&noex");
0145       if (and_noexception != std::string::npos || and_noex != std::string::npos)
0146         throw edm::Exception(errors::Configuration) << "EventSelector::init, An OutputModule is using SelectEvents\n"
0147                                                        "to request a trigger name, but specifying &noexceptions twice\n"
0148                                                     << "The improper trigger name is: " << pathspecifier << "\n";
0149 
0150       std::string realname(basePathSpec);
0151       bool negative_criterion = false;
0152       if (basePathSpec[0] == '!') {
0153         negative_criterion = true;
0154         realname = basePathSpec.substr(1, std::string::npos);
0155       }
0156       bool exception_spec = false;
0157       if (realname.find("exception@") == 0) {
0158         exception_spec = true;
0159         realname = realname.substr(10, std::string::npos);
0160         // strip off 10 chars, which is length of "exception@"
0161       }
0162       if (negative_criterion && exception_spec)
0163         throw edm::Exception(errors::Configuration) << "EventSelector::init, An OutputModule is using SelectEvents\n"
0164                                                        "to request a trigger name starting with !exception@.\n"
0165                                                        "This is not supported.\n"
0166                                                     << "The improper trigger name is: " << pathspecifier << "\n";
0167       if (noex_demanded && exception_spec)
0168         throw edm::Exception(errors::Configuration) << "EventSelector::init, An OutputModule is using SelectEvents\n"
0169                                                        "to request a trigger name starting with exception@ "
0170                                                        "and also demanding no &exceptions.\n"
0171                                                     << "The improper trigger name is: " << pathspecifier << "\n";
0172 
0173       // instead of "see if the name can be found in the full list of paths"
0174       // we want to find all paths that match this name.
0175       std::vector<Strings::const_iterator> matches = regexMatch(pathNames, realname);
0176 
0177       if (matches.empty() && !is_glob(realname)) {
0178         throw edm::Exception(errors::Configuration) << "EventSelector::init, An OutputModule is using SelectEvents\n"
0179                                                        "to request a trigger name that does not exist\n"
0180                                                     << "The unknown trigger name is: " << realname << "\n";
0181       }
0182       if (matches.empty() && is_glob(realname)) {
0183         LogWarning("Configuration") << "EventSelector::init, An OutputModule is using SelectEvents\n"
0184                                        "to request a wildcarded trigger name that does not match any trigger \n"
0185                                     << "The wildcarded trigger name is: " << realname << "\n";
0186       }
0187 
0188       if (!negative_criterion && !noex_demanded && !exception_spec) {
0189         for (unsigned int t = 0; t != matches.size(); ++t) {
0190           BitInfo bi(distance(pathNames.begin(), matches[t]), true);
0191           absolute_acceptors_.push_back(bi);
0192         }
0193       } else if (!negative_criterion && noex_demanded) {
0194         for (unsigned int t = 0; t != matches.size(); ++t) {
0195           BitInfo bi(distance(pathNames.begin(), matches[t]), true);
0196           conditional_acceptors_.push_back(bi);
0197         }
0198       } else if (exception_spec) {
0199         for (unsigned int t = 0; t != matches.size(); ++t) {
0200           BitInfo bi(distance(pathNames.begin(), matches[t]), true);
0201           exception_acceptors_.push_back(bi);
0202         }
0203       } else if (negative_criterion && !noex_demanded) {
0204         if (matches.empty()) {
0205           throw edm::Exception(errors::Configuration)
0206               << "EventSelector::init, An OutputModule is using SelectEvents\n"
0207                  "to request all fails on a set of trigger names that do not exist\n"
0208               << "The problematic name is: " << pathspecifier << "\n";
0209 
0210         } else if (matches.size() == 1) {
0211           BitInfo bi(distance(pathNames.begin(), matches[0]), false);
0212           absolute_acceptors_.push_back(bi);
0213         } else {
0214           Bits mustfail;
0215           for (unsigned int t = 0; t != matches.size(); ++t) {
0216             BitInfo bi(distance(pathNames.begin(), matches[t]), false);
0217             // We set this to false because that will demand bits are Fail.
0218             mustfail.push_back(bi);
0219           }
0220           all_must_fail_.push_back(mustfail);
0221         }
0222       } else if (negative_criterion && noex_demanded) {
0223         if (matches.empty()) {
0224           throw edm::Exception(errors::Configuration)
0225               << "EventSelector::init, An OutputModule is using SelectEvents\n"
0226                  "to request all fails on a set of trigger names that do not exist\n"
0227               << "The problematic name is: " << pathspecifier << "\n";
0228 
0229         } else if (matches.size() == 1) {
0230           BitInfo bi(distance(pathNames.begin(), matches[0]), false);
0231           conditional_acceptors_.push_back(bi);
0232         } else {
0233           Bits mustfail;
0234           for (unsigned int t = 0; t != matches.size(); ++t) {
0235             BitInfo bi(distance(pathNames.begin(), matches[t]), false);
0236             mustfail.push_back(bi);
0237           }
0238           all_must_fail_noex_.push_back(mustfail);
0239         }
0240       }
0241     }  // end of the for loop on pathspecs
0242 
0243     // std::cerr << "### init exited\n";
0244 
0245   }  // EventSelector::init
0246 
0247   bool EventSelector::acceptEvent(TriggerResults const& tr) {
0248     if (accept_all_)
0249       return true;
0250 
0251     if (!results_from_current_process_) {
0252       // The path names for prior processes may be different in different runs.
0253       // Check for this, and modify the selector accordingly if necessary.
0254       if (!psetID_.isValid() || psetID_ != tr.parameterSetID()) {
0255         Strings pathNames;
0256         bool fromPSetRegistry = false;
0257         Service<service::TriggerNamesService> tns;
0258         if (tns->getTrigPaths(tr, pathNames, fromPSetRegistry)) {
0259           initPathNames(pathNames);
0260           if (fromPSetRegistry) {
0261             psetID_ = tr.parameterSetID();
0262           } else {
0263             // This can only happen for very old data, when the path names were stored
0264             // in TriggerResults itself, rather than in the parameter set registry.
0265             psetID_.reset();
0266           }
0267         } else {
0268           // This should never happen
0269           throw edm::Exception(errors::Unknown)
0270               << "EventSelector::acceptEvent cannot find the trigger names for\n"
0271                  "a process for which the configuration has requested that the\n"
0272                  "OutputModule use TriggerResults to select events from.  This should\n"
0273                  "be impossible, please send information to reproduce this problem to\n"
0274                  "the edm developers.\n";
0275         }
0276       }
0277     }
0278 
0279     // Now make the decision, based on the supplied TriggerResults tr,
0280     // which of course can be treated as an HLTGlobalStatus by inheritance
0281 
0282     return selectionDecision(tr);
0283 
0284   }  // acceptEvent(TriggerResults const& tr)
0285 
0286   bool EventSelector::acceptEvent(unsigned char const* array_of_trigger_results, int number_of_trigger_paths) const {
0287     // This should never occur unless someone uses this function in
0288     // an incorrect way ...
0289     if (!results_from_current_process_) {
0290       throw edm::Exception(errors::Configuration) << "\nEventSelector.cc::acceptEvent, you are attempting to\n"
0291                                                   << "use a bit array for trigger results instead of the\n"
0292                                                   << "TriggerResults object for a previous process.  This\n"
0293                                                   << "will not work and ought to be impossible\n";
0294     }
0295 
0296     if (accept_all_)
0297       return true;
0298 
0299     // Form HLTGlobalStatus object to represent the array_of_trigger_results
0300     HLTGlobalStatus tr(number_of_trigger_paths);
0301     int byteIndex = 0;
0302     int subIndex = 0;
0303     for (int pathIndex = 0; pathIndex < number_of_trigger_paths; ++pathIndex) {
0304       int state = array_of_trigger_results[byteIndex] >> (subIndex * 2);
0305       state &= 0x3;
0306       HLTPathStatus pathStatus(static_cast<hlt::HLTState>(state));
0307       tr[pathIndex] = pathStatus;
0308       ++subIndex;
0309       if (subIndex == 4) {
0310         ++byteIndex;
0311         subIndex = 0;
0312       }
0313     }
0314 
0315     // Now make the decision, based on the HLTGlobalStatus tr,
0316     // which we have created from the supplied array of results
0317 
0318     return selectionDecision(tr);
0319 
0320   }  // acceptEvent(array_of_trigger_results, number_of_trigger_paths)
0321 
0322   bool EventSelector::selectionDecision(HLTGlobalStatus const& tr) const {
0323     if (accept_all_)
0324       return true;
0325 
0326     bool exceptionPresent = false;
0327     bool exceptionsLookedFor = false;
0328 
0329     if (acceptOneBit(absolute_acceptors_, tr))
0330       return true;
0331     if (acceptOneBit(conditional_acceptors_, tr)) {
0332       exceptionPresent = containsExceptions(tr);
0333       if (!exceptionPresent)
0334         return true;
0335       exceptionsLookedFor = true;
0336     }
0337     if (acceptOneBit(exception_acceptors_, tr, hlt::Exception))
0338       return true;
0339 
0340     for (auto const& bit : all_must_fail_) {
0341       if (acceptAllBits(bit, tr))
0342         return true;
0343     }
0344     for (auto const& bitn : all_must_fail_noex_) {
0345       if (acceptAllBits(bitn, tr)) {
0346         if (!exceptionsLookedFor)
0347           exceptionPresent = containsExceptions(tr);
0348         return (!exceptionPresent);
0349       }
0350     }
0351 
0352     // If we have not accepted based on any of the acceptors, nor on any one of
0353     // the all_must_fail_ collections, then we reject this event.
0354 
0355     return false;
0356 
0357   }  // selectionDecision()
0358 
0359   // Obsolete...
0360   bool EventSelector::acceptTriggerPath(HLTPathStatus const& pathStatus, BitInfo const& pathInfo) const {
0361     return (((pathStatus.state() == hlt::Pass) && (pathInfo.accept_state_)) ||
0362             ((pathStatus.state() == hlt::Fail) && !(pathInfo.accept_state_)) ||
0363             ((pathStatus.state() == hlt::Exception)));
0364   }
0365 
0366   // Indicate if any bit in the trigger results matches the desired value
0367   // at that position, based on the Bits array.  If s is Exception, this
0368   // looks for a Exceptionmatch; otherwise, true-->Pass, false-->Fail.
0369   bool EventSelector::acceptOneBit(Bits const& b, HLTGlobalStatus const& tr, hlt::HLTState const& s) const {
0370     bool lookForException = (s == hlt::Exception);
0371     for (auto const& bit : b) {
0372       hlt::HLTState bstate = lookForException ? hlt::Exception : bit.accept_state_ ? hlt::Pass : hlt::Fail;
0373       if (tr[bit.pos_].state() == bstate)
0374         return true;
0375     }
0376     return false;
0377   }  // acceptOneBit
0378 
0379   // Indicate if *every* bit in the trigger results matches the desired value
0380   // at that position, based on the Bits array: true-->Pass, false-->Fail.
0381   bool EventSelector::acceptAllBits(Bits const& b, HLTGlobalStatus const& tr) const {
0382     for (auto const& bit : b) {
0383       hlt::HLTState bstate = bit.accept_state_ ? hlt::Pass : hlt::Fail;
0384       if (tr[bit.pos_].state() != bstate)
0385         return false;
0386     }
0387     return true;
0388   }  // acceptAllBits
0389 
0390   /**
0391    * Tests if the specified trigger selection list (pathspecs) is valid
0392    * in the context of the specified full trigger list.  Each element in
0393    * the selection list is tested to see if it possible for some
0394    * combination of trigger results to satisfy the selection.  If all
0395    * selection elements can be satisfied one way or another, then this
0396    * method returns true.  If one or more selection elements could never
0397    * be satisfied given the input full trigger list, then this method
0398    * returns false.  At some level, this method tests whether the selection
0399    * list is a "subset" of the full path list.
0400    *
0401    * @param pathspecs The trigger selection list (vector of string).
0402    * @param fullPathList The full list of path names (vector of string).
0403    * @return true if the selection list is valid, false otherwise.
0404    */
0405   bool EventSelector::selectionIsValid(Strings const& pathspecs, Strings const& fullPathList) {
0406     // an empty selection list is not valid
0407     // (we default an empty "SelectEvents" parameter to {"*","!*"} in
0408     // the getEventSelectionVString method below to help avoid this)
0409     if (pathspecs.empty()) {
0410       return false;
0411     }
0412 
0413     // loop over each element in the selection list
0414     for (unsigned int idx = 0; idx < pathspecs.size(); idx++) {
0415       Strings workingList;
0416       workingList.push_back(pathspecs[idx]);
0417 
0418       // catch exceptions from the EventSelector constructor
0419       // (and anywhere else) and mark those as failures.
0420       // The EventSelector constructor seems to do the work of
0421       // checking if the selection is outside the full trigger list.
0422       try {
0423         // create an EventSelector instance for this selection
0424         EventSelector evtSelector(workingList, fullPathList);
0425 
0426         // create the TriggerResults instance that we'll use for testing
0427         unsigned int fullPathCount = fullPathList.size();
0428         HLTGlobalStatus hltGS(fullPathCount);
0429         TriggerResults sampleResults(hltGS, fullPathList);
0430 
0431         // loop over each path
0432         bool oneResultMatched = false;
0433         for (unsigned int iPath = 0; iPath < fullPathCount; iPath++) {
0434           // loop over the possible values for the path status
0435           for (int iState = static_cast<int>(hlt::Pass); iState <= static_cast<int>(hlt::Exception); iState++) {
0436             sampleResults[iPath] = HLTPathStatus(static_cast<hlt::HLTState>(iState), 0);
0437             if (evtSelector.wantAll() || evtSelector.acceptEvent(sampleResults)) {
0438               oneResultMatched = true;
0439               break;
0440             }
0441 
0442             sampleResults.reset(iPath);
0443           }
0444 
0445           if (oneResultMatched)
0446             break;
0447         }
0448 
0449         // Finally, check in case the selection element was a wildcarded
0450         // negative such as "!*":
0451 
0452         if (!oneResultMatched) {
0453           for (unsigned int iPath = 0; iPath < fullPathCount; iPath++) {
0454             sampleResults[iPath] = HLTPathStatus(hlt::Fail, 0);
0455           }
0456           if (evtSelector.acceptEvent(sampleResults)) {
0457             oneResultMatched = true;
0458           }
0459         }
0460 
0461         // if none of the possible trigger results matched the
0462         // selection element, then we declare the whole selection
0463         // list invalid
0464         if (!oneResultMatched) {
0465           return false;
0466         }
0467       } catch (edm::Exception const&) {
0468         return false;
0469       }
0470     }
0471 
0472     // if we made it to this point, then it must have been possible
0473     // to satisfy every selection element one way or another
0474     return true;
0475   }
0476 
0477   /**
0478    * Tests if the specified trigger selection lists (path specs) overlap,
0479    * where "overlap" means that a valid trigger result (given the full
0480    * trigger list) could satisfy both selections.
0481    *
0482    * @param pathspec1 The first trigger selection list (vector of string).
0483    * @param pathspec2 The second trigger selection list (vector of string).
0484    * @param fullPathList The full list of trigger names (vector of string).
0485    * @return OverlapResult which indicates the degree of overlap.
0486    */
0487   evtSel::OverlapResult EventSelector::testSelectionOverlap(Strings const& pathspec1,
0488                                                             Strings const& pathspec2,
0489                                                             Strings const& fullPathList) {
0490     bool overlap = false;
0491 
0492     // first, test that the selection lists are valid
0493     if (!selectionIsValid(pathspec1, fullPathList) || !selectionIsValid(pathspec2, fullPathList)) {
0494       return evtSel::InvalidSelection;
0495     }
0496 
0497     // catch exceptions from the EventSelector constructor
0498     // (and anywhere else) and mark those as failures
0499     try {
0500       // create an EventSelector instance for each selection list
0501       EventSelector a(pathspec1, fullPathList);
0502       EventSelector b(pathspec2, fullPathList);
0503 
0504       unsigned int N = fullPathList.size();
0505 
0506       // create the expanded masks for the various decision lists in a and b
0507       std::vector<bool> aPassAbs = expandDecisionList(a.absolute_acceptors_, true, N);
0508       std::vector<bool> aPassCon = expandDecisionList(a.conditional_acceptors_, true, N);
0509       std::vector<bool> aFailAbs = expandDecisionList(a.absolute_acceptors_, false, N);
0510       std::vector<bool> aFailCon = expandDecisionList(a.conditional_acceptors_, false, N);
0511       std::vector<bool> aExc = expandDecisionList(a.exception_acceptors_, true, N);
0512       std::vector<std::vector<bool> > aMustFail;
0513       for (unsigned int m = 0; m != a.all_must_fail_.size(); ++m) {
0514         aMustFail.push_back(expandDecisionList(a.all_must_fail_[m], false, N));
0515       }
0516       std::vector<std::vector<bool> > aMustFailNoex;
0517       for (unsigned int m = 0; m != a.all_must_fail_noex_.size(); ++m) {
0518         aMustFailNoex.push_back(expandDecisionList(a.all_must_fail_noex_[m], false, N));
0519       }
0520 
0521       std::vector<bool> bPassAbs = expandDecisionList(b.absolute_acceptors_, true, N);
0522       std::vector<bool> bPassCon = expandDecisionList(b.conditional_acceptors_, true, N);
0523       std::vector<bool> bFailAbs = expandDecisionList(b.absolute_acceptors_, false, N);
0524       std::vector<bool> bFailCon = expandDecisionList(b.conditional_acceptors_, false, N);
0525       std::vector<bool> bExc = expandDecisionList(b.exception_acceptors_, true, N);
0526       std::vector<std::vector<bool> > bMustFail;
0527       for (unsigned int m = 0; m != b.all_must_fail_.size(); ++m) {
0528         bMustFail.push_back(expandDecisionList(b.all_must_fail_[m], false, N));
0529       }
0530       std::vector<std::vector<bool> > bMustFailNoex;
0531       for (unsigned int m = 0; m != b.all_must_fail_noex_.size(); ++m) {
0532         bMustFailNoex.push_back(expandDecisionList(b.all_must_fail_noex_[m], false, N));
0533       }
0534 
0535       std::vector<bool> aPass = combine(aPassAbs, aPassCon);
0536       std::vector<bool> bPass = combine(bPassAbs, bPassCon);
0537       std::vector<bool> aFail = combine(aFailAbs, aFailCon);
0538       std::vector<bool> bFail = combine(bFailAbs, bFailCon);
0539 
0540       // Check for overlap in the primary masks
0541       overlap = overlapping(aPass, bPass) || overlapping(aFail, bFail) || overlapping(aExc, bExc);
0542       if (overlap)
0543         return identical(a, b, N) ? evtSel::ExactMatch : evtSel::PartialOverlap;
0544 
0545       // Check for overlap of a primary fail mask with a must fail mask
0546       for (unsigned int f = 0; f != aMustFail.size(); ++f) {
0547         overlap = overlapping(aMustFail[f], bFail);
0548         if (overlap)
0549           return evtSel::PartialOverlap;
0550         for (unsigned int g = 0; g != bMustFail.size(); ++g) {
0551           overlap = subset(aMustFail[f], bMustFail[g]);
0552           if (overlap)
0553             return evtSel::PartialOverlap;
0554         }
0555         for (unsigned int g = 0; g != bMustFailNoex.size(); ++g) {
0556           overlap = subset(aMustFail[f], bMustFailNoex[g]);
0557           if (overlap)
0558             return evtSel::PartialOverlap;
0559         }
0560       }
0561       for (unsigned int f = 0; f != aMustFailNoex.size(); ++f) {
0562         overlap = overlapping(aMustFailNoex[f], bFail);
0563         if (overlap)
0564           return evtSel::PartialOverlap;
0565         for (unsigned int g = 0; g != bMustFail.size(); ++g) {
0566           overlap = subset(aMustFailNoex[f], bMustFail[g]);
0567           if (overlap)
0568             return evtSel::PartialOverlap;
0569         }
0570         for (unsigned int g = 0; g != bMustFailNoex.size(); ++g) {
0571           overlap = subset(aMustFailNoex[f], bMustFailNoex[g]);
0572           if (overlap)
0573             return evtSel::PartialOverlap;
0574         }
0575       }
0576       for (unsigned int g = 0; g != bMustFail.size(); ++g) {
0577         overlap = overlapping(bMustFail[g], aFail);
0578         if (overlap)
0579           return evtSel::PartialOverlap;
0580       }
0581       for (unsigned int g = 0; g != bMustFailNoex.size(); ++g) {
0582         overlap = overlapping(bMustFail[g], aFail);
0583         if (overlap)
0584           return evtSel::PartialOverlap;
0585       }
0586 
0587     } catch (edm::Exception const&) {
0588       return evtSel::InvalidSelection;
0589     }
0590 
0591     // If we get to here without overlap becoming true, there is no overlap
0592 
0593     return evtSel::NoOverlap;
0594 
0595   }  // testSelectionOverlap
0596 
0597 #ifdef REMOVE
0598   /**
0599    * Tests if the specified trigger selection lists (path specs) overlap,
0600    * where "overlap" means that a valid trigger result (given the full
0601    * trigger list) could satisfy both selections.
0602    *
0603    * @param pathspec1 The first trigger selection list (vector of string).
0604    * @param pathspec2 The second trigger selection list (vector of string).
0605    * @param fullPathList The full list of trigger names (vector of string).
0606    * @return OverlapResult which indicates the degree of overlap.
0607    */
0608   evtSel::OverlapResult EventSelector::testSelectionOverlap(Strings const& pathspec1,
0609                                                             Strings const& pathspec2,
0610                                                             Strings const& fullPathList) {
0611     // first, test that the selection lists are valid
0612     if (!selectionIsValid(pathspec1, fullPathList) || !selectionIsValid(pathspec2, fullPathList)) {
0613       return evtSel::InvalidSelection;
0614     }
0615 
0616     // initialize possible states
0617     bool noOverlap = true;
0618     bool exactMatch = true;
0619 
0620     // catch exceptions from the EventSelector constructor
0621     // (and anywhere else) and mark those as failures
0622     try {
0623       // create an EventSelector instance for each selection list
0624       EventSelector selector1(pathspec1, fullPathList);
0625       EventSelector selector2(pathspec2, fullPathList);
0626 
0627       // create the TriggerResults instance that we'll use for testing
0628       unsigned int fullPathCount = fullPathList.size();
0629       HLTGlobalStatus hltGS(fullPathCount);
0630       TriggerResults sampleResults(hltGS, fullPathList);
0631 
0632       // loop over each path
0633       for (unsigned int iPath = 0; iPath < fullPathCount; iPath++) {
0634         // loop over the possible values for the path status
0635         for (int iState = static_cast<int>(hlt::Pass); iState <= static_cast<int>(hlt::Exception); iState++) {
0636           sampleResults[iPath] = HLTPathStatus(static_cast<hlt::HLTState>(iState), 0);
0637           bool accept1 = selector1.wantAll() || selector1.acceptEvent(sampleResults);
0638           bool accept2 = selector2.wantAll() || selector2.acceptEvent(sampleResults);
0639           if (accept1 != accept2) {
0640             exactMatch = false;
0641           }
0642           if (accept1 && accept2) {
0643             noOverlap = false;
0644           }
0645           sampleResults.reset(iPath);
0646         }
0647       }
0648     } catch (edm::Exception const& excpt) {
0649       return evtSel::InvalidSelection;
0650     }
0651 
0652     if (exactMatch) {
0653       return evtSel::ExactMatch;
0654     }
0655     if (noOverlap) {
0656       return evtSel::NoOverlap;
0657     }
0658     return evtSel::PartialOverlap;
0659   }
0660 #endif
0661 
0662   /**
0663    * Applies a trigger selection mask to a specified trigger result object.
0664    * Within the trigger result object, each path status is left unchanged
0665    * if it satisfies the trigger selection (path specs) or cleared if it
0666    * does not satisfy the trigger selection.  In this way, the resulting
0667    * trigger result object contains only path status values that "pass"
0668    * the selection criteria.
0669    *
0670    * @param inputResults The raw trigger results object that will be masked.
0671    * @return a copy of the input trigger results object with only the path
0672    *         status results that match the trigger selection.
0673    * @throws edm::Exception if the number of paths in the TriggerResults
0674    *         object does not match the specified full trigger list, or
0675    *         if the trigger selection is invalid in the context of the
0676    *         full trigger list.
0677    */
0678   std::shared_ptr<TriggerResults> EventSelector::maskTriggerResults(TriggerResults const& inputResults) {
0679     // fetch and validate the total number of paths
0680     unsigned int fullPathCount = nPathNames_;
0681     unsigned int N = fullPathCount;
0682     if (fullPathCount != inputResults.size()) {
0683       throw edm::Exception(errors::EventCorruption)
0684           << "EventSelector::maskTriggerResults, the TriggerResults\n"
0685           << "size (" << inputResults.size() << ") does not match the number of paths in the\n"
0686           << "full trigger list (" << fullPathCount << ").\n";
0687     }
0688 
0689     // create a suitable global status object to work with, all in Ready state
0690     HLTGlobalStatus mask(fullPathCount);
0691 
0692     // Deal with must_fail acceptors that would cause selection
0693     for (unsigned int m = 0; m < this->all_must_fail_.size(); ++m) {
0694       std::vector<bool> f = expandDecisionList(this->all_must_fail_[m], false, N);
0695       bool all_fail = true;
0696       for (unsigned int ipath = 0; ipath < N; ++ipath) {
0697         if ((f[ipath]) && (inputResults[ipath].state() != hlt::Fail)) {
0698           all_fail = false;
0699           break;
0700         }
0701       }
0702       if (all_fail) {
0703         for (unsigned int ipath = 0; ipath < N; ++ipath) {
0704           if (f[ipath]) {
0705             mask[ipath] = hlt::Fail;
0706           }
0707         }
0708       }
0709     }
0710     for (unsigned int m = 0; m < this->all_must_fail_noex_.size(); ++m) {
0711       std::vector<bool> f = expandDecisionList(this->all_must_fail_noex_[m], false, N);
0712       bool all_fail = true;
0713       for (unsigned int ipath = 0; ipath < N; ++ipath) {
0714         if ((f[ipath]) && (inputResults[ipath].state() != hlt::Fail)) {
0715           all_fail = false;
0716           break;
0717         }
0718       }
0719       if (all_fail) {
0720         for (unsigned int ipath = 0; ipath < N; ++ipath) {
0721           if (f[ipath]) {
0722             mask[ipath] = hlt::Fail;
0723           }
0724         }
0725       }
0726     }  // factoring opportunity - work done for fail_noex_ is same as for fail_
0727 
0728     // Deal with normal acceptors that would cause selection
0729     std::vector<bool> aPassAbs = expandDecisionList(this->absolute_acceptors_, true, N);
0730     std::vector<bool> aPassCon = expandDecisionList(this->conditional_acceptors_, true, N);
0731     std::vector<bool> aFailAbs = expandDecisionList(this->absolute_acceptors_, false, N);
0732     std::vector<bool> aFailCon = expandDecisionList(this->conditional_acceptors_, false, N);
0733     std::vector<bool> aExc = expandDecisionList(this->exception_acceptors_, true, N);
0734     for (unsigned int ipath = 0; ipath < N; ++ipath) {
0735       hlt::HLTState s = inputResults[ipath].state();
0736       if (((aPassAbs[ipath]) && (s == hlt::Pass)) || ((aPassCon[ipath]) && (s == hlt::Pass)) ||
0737           ((aFailAbs[ipath]) && (s == hlt::Fail)) || ((aFailCon[ipath]) && (s == hlt::Fail)) ||
0738           ((aExc[ipath]) && (s == hlt::Exception))) {
0739         mask[ipath] = s;
0740       }
0741     }
0742 
0743     // Based on the global status for the mask, create and return a
0744     // TriggerResults
0745     auto maskedResults = std::make_shared<TriggerResults>(mask, inputResults.parameterSetID());
0746     return maskedResults;
0747   }  // maskTriggerResults
0748 
0749 #ifdef REMOVE
0750   /**
0751    * Applies a trigger selection mask to a specified trigger result object.
0752    * Within the trigger result object, each path status is left unchanged
0753    * if it satisfies the trigger selection (path specs) or cleared if it
0754    * does not satisfy the trigger selection.  In this way, the resulting
0755    * trigger result object contains only path status values that "pass"
0756    * the selection criteria.
0757    *
0758    * @param pathspecs The trigger selection list (vector of string).
0759    * @param inputResults The raw trigger results object that will be masked.
0760    * @param fullPathList The full list of trigger names (vector of string).
0761    * @return a copy of the input trigger results object with only the path
0762    *         status results that match the trigger selection.
0763    * @throws edm::Exception if the number of paths in the TriggerResults
0764    *         object does not match the specified full trigger list, or
0765    *         if the trigger selection is invalid in the context of the
0766    *         full trigger list.
0767    */
0768   std::shared_ptr<TriggerResults> EventSelector::maskTriggerResults(Strings const& pathspecs,
0769                                                                     TriggerResults const& inputResults,
0770                                                                     Strings const& fullPathList) {
0771     // fetch and validate the total number of paths
0772     unsigned int fullPathCount = fullPathList.size();
0773     if (fullPathCount != inputResults.size()) {
0774       throw edm::Exception(errors::EventCorruption)
0775           << "EventSelector::maskTriggerResults, the TriggerResults\n"
0776           << "size (" << inputResults.size() << ") does not match the number of paths in the\n"
0777           << "full trigger list (" << fullPathCount << ").\n";
0778     }
0779 
0780     // create a working copy of the TriggerResults object
0781     HLTGlobalStatus hltGS(fullPathCount);
0782     auto maskedResults = std::make_shared<TriggerResults>(hltGS, inputResults.parameterSetID());
0783     for (unsigned int iPath = 0; iPath < fullPathCount; iPath++) {
0784       (*maskedResults)[iPath] = inputResults[iPath];
0785     }
0786 
0787     // create an EventSelector to use when testing if a path status passes
0788     EventSelector selector(pathspecs, fullPathList);
0789 
0790     // create the TriggerResults instance that we'll use for testing
0791     HLTGlobalStatus hltGS2(fullPathCount);
0792     TriggerResults sampleResults(hltGS2, fullPathList);
0793 
0794     // loop over each path and reset the path status if needed
0795     for (unsigned int iPath = 0; iPath < fullPathCount; iPath++) {
0796       sampleResults[iPath] = (*maskedResults)[iPath];
0797       if (!selector.wantAll() && !selector.acceptEvent(sampleResults)) {
0798         maskedResults->reset(iPath);
0799       }
0800       sampleResults.reset(iPath);
0801     }
0802     return maskedResults;
0803   }
0804 #endif
0805 
0806   /**
0807    * Returns the list of strings that correspond to the trigger
0808    * selection request in the specified parameter set (the list
0809    * of strings contained in the "SelectEvents" parameter).
0810    *
0811    * @param pset The ParameterSet that contains the trigger selection.
0812    * @return the trigger selection list (vector of string).
0813    */
0814   std::vector<std::string> EventSelector::getEventSelectionVString(ParameterSet const& pset) {
0815     // default the selection to everything (wildcard)
0816     Strings selection;
0817     selection.push_back("*");
0818     selection.push_back("!*");
0819     selection.push_back("exception@*");
0820 
0821     // the SelectEvents parameter is a ParameterSet within
0822     // a ParameterSet, so we have to pull it out twice
0823     ParameterSet selectEventsParamSet = pset.getUntrackedParameter("SelectEvents", ParameterSet());
0824     if (!selectEventsParamSet.empty()) {
0825       Strings path_specs = selectEventsParamSet.getParameter<Strings>("SelectEvents");
0826       if (!path_specs.empty()) {
0827         selection = path_specs;
0828       }
0829     }
0830 
0831     // return the result
0832     return selection;
0833   }
0834 
0835   bool EventSelector::containsExceptions(HLTGlobalStatus const& tr) const {
0836     unsigned int e = tr.size();
0837     for (unsigned int i = 0; i < e; ++i) {
0838       if (tr[i].state() == hlt::Exception)
0839         return true;
0840     }
0841     return false;
0842   }
0843 
0844   // The following routines are helpers for testSelectionOverlap
0845 
0846   bool EventSelector::identical(std::vector<bool> const& a, std::vector<bool> const& b) {
0847     unsigned int n = a.size();
0848     if (n != b.size())
0849       return false;
0850     for (unsigned int i = 0; i != n; ++i) {
0851       if (a[i] != b[i])
0852         return false;
0853     }
0854     return true;
0855   }
0856 
0857   bool EventSelector::identical(EventSelector const& a, EventSelector const& b, unsigned int N) {
0858     // create the expanded masks for the various decision lists in a and b
0859     if (!identical(expandDecisionList(a.absolute_acceptors_, true, N),
0860                    expandDecisionList(b.absolute_acceptors_, true, N)))
0861       return false;
0862     if (!identical(expandDecisionList(a.conditional_acceptors_, true, N),
0863                    expandDecisionList(b.conditional_acceptors_, true, N)))
0864       return false;
0865     if (!identical(expandDecisionList(a.absolute_acceptors_, false, N),
0866                    expandDecisionList(b.absolute_acceptors_, false, N)))
0867       return false;
0868     if (!identical(expandDecisionList(a.conditional_acceptors_, false, N),
0869                    expandDecisionList(b.conditional_acceptors_, false, N)))
0870       return false;
0871     if (!identical(expandDecisionList(a.exception_acceptors_, true, N),
0872                    expandDecisionList(b.exception_acceptors_, true, N)))
0873       return false;
0874     if (a.all_must_fail_.size() != b.all_must_fail_.size())
0875       return false;
0876 
0877     std::vector<std::vector<bool> > aMustFail;
0878     for (unsigned int m = 0; m != a.all_must_fail_.size(); ++m) {
0879       aMustFail.push_back(expandDecisionList(a.all_must_fail_[m], false, N));
0880     }
0881     std::vector<std::vector<bool> > aMustFailNoex;
0882     for (unsigned int m = 0; m != a.all_must_fail_noex_.size(); ++m) {
0883       aMustFailNoex.push_back(expandDecisionList(a.all_must_fail_noex_[m], false, N));
0884     }
0885     std::vector<std::vector<bool> > bMustFail;
0886     for (unsigned int m = 0; m != b.all_must_fail_.size(); ++m) {
0887       bMustFail.push_back(expandDecisionList(b.all_must_fail_[m], false, N));
0888     }
0889     std::vector<std::vector<bool> > bMustFailNoex;
0890     for (unsigned int m = 0; m != b.all_must_fail_noex_.size(); ++m) {
0891       bMustFailNoex.push_back(expandDecisionList(b.all_must_fail_noex_[m], false, N));
0892     }
0893 
0894     for (unsigned int m = 0; m != aMustFail.size(); ++m) {
0895       bool match = false;
0896       for (unsigned int k = 0; k != bMustFail.size(); ++k) {
0897         if (identical(aMustFail[m], bMustFail[k])) {
0898           match = true;
0899           break;
0900         }
0901       }
0902       if (!match)
0903         return false;
0904     }
0905     for (unsigned int m = 0; m != aMustFailNoex.size(); ++m) {
0906       bool match = false;
0907       for (unsigned int k = 0; k != bMustFailNoex.size(); ++k) {
0908         if (identical(aMustFailNoex[m], bMustFailNoex[k])) {
0909           match = true;
0910           break;
0911         }
0912       }
0913       if (!match)
0914         return false;
0915     }
0916 
0917     return true;
0918 
0919   }  // identical (EventSelector, EventSelector, N);
0920 
0921   std::vector<bool> EventSelector::expandDecisionList(Bits const& b, bool PassOrFail, unsigned int n) {
0922     std::vector<bool> x(n, false);
0923     for (unsigned int i = 0; i != b.size(); ++i) {
0924       if (b[i].accept_state_ == PassOrFail)
0925         x[b[i].pos_] = true;
0926     }
0927     return x;
0928   }  // expandDecisionList
0929 
0930   // Determines whether a and b share a true bit at any position
0931   bool EventSelector::overlapping(std::vector<bool> const& a, std::vector<bool> const& b) {
0932     if (a.size() != b.size())
0933       return false;
0934     for (unsigned int i = 0; i != a.size(); ++i) {
0935       if (a[i] && b[i])
0936         return true;
0937     }
0938     return false;
0939   }  // overlapping
0940 
0941   // determines whether the true bits of a are a non-empty subset of those of b,
0942   // or vice-versa.  The subset need not be proper.
0943   bool EventSelector::subset(std::vector<bool> const& a, std::vector<bool> const& b) {
0944     if (a.size() != b.size())
0945       return false;
0946     // First test whether a is a non-empty subset of b
0947     bool aPresent = false;
0948     bool aSubset = true;
0949     for (unsigned int i = 0; i != a.size(); ++i) {
0950       if (a[i]) {
0951         aPresent = true;
0952         if (!b[i]) {
0953           aSubset = false;
0954           break;
0955         }
0956       }
0957     }
0958     if (!aPresent)
0959       return false;
0960     if (aSubset)
0961       return true;
0962 
0963     // Now test whether b is a non-empty subset of a
0964     bool bPresent = false;
0965     bool bSubset = true;
0966     for (unsigned int i = 0; i != b.size(); ++i) {
0967       if (b[i]) {
0968         bPresent = true;
0969         if (!a[i]) {
0970           bSubset = false;
0971           break;
0972         }
0973       }
0974     }
0975     if (!bPresent)
0976       return false;
0977     if (bSubset)
0978       return true;
0979 
0980     return false;
0981   }  // subset
0982 
0983   // Creates a vector of bits which is the OR of a and b
0984   std::vector<bool> EventSelector::combine(std::vector<bool> const& a, std::vector<bool> const& b) {
0985     assert(a.size() == b.size());
0986     std::vector<bool> x(a.size());
0987     for (unsigned int i = 0; i != a.size(); ++i) {
0988       x[i] = a[i] || b[i];
0989     }  // a really sharp compiler will optimize the hell out of this,
0990     // exploiting word-size OR operations.
0991     return x;
0992   }  // combine
0993 
0994   void EventSelector::fillDescription(ParameterSetDescription& desc) {
0995     ParameterSetDescription selector;
0996     selector.addOptional<std::vector<std::string> >("SelectEvents");
0997     desc.addUntracked<ParameterSetDescription>("SelectEvents", selector);
0998   }
0999 
1000 }  // namespace edm