Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-01-17 23:57:39

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