Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-01-22 07:34:02

0001 #include "TriggerSelector.h"
0002 
0003 #include "DataFormats/Common/interface/HLTPathStatus.h"
0004 #include "DataFormats/Common/interface/TriggerResults.h"
0005 #include "FWCore/Framework/interface/EventSelector.h"
0006 #include "FWCore/Framework/interface/TriggerNamesService.h"
0007 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0008 #include "FWCore/Utilities/interface/RegexMatch.h"
0009 
0010 #include <iostream>
0011 #include <algorithm>
0012 
0013 #include <boost/regex.hpp>
0014 #include <memory>
0015 
0016 namespace dqmservices {
0017 
0018   // compatibility constructor
0019 
0020   TriggerSelector::TriggerSelector(Strings const& pathspecs, Strings const& triggernames) : useOld_(true) {
0021     acceptAll_ = false;
0022     eventSelector_ = std::make_shared<edm::EventSelector>(pathspecs, triggernames);
0023   }
0024 
0025   TriggerSelector::TriggerSelector(std::string const& expression, Strings const& triggernames) : useOld_(false) {
0026     init(trim(expression), triggernames);
0027   }
0028 
0029   void TriggerSelector::init(std::string const& expression, Strings const& triggernames) {
0030     // debug_ = true;
0031     if (expression.empty()) {
0032       acceptAll_ = true;
0033       return;
0034     }
0035     if (expression.size() == 1 && expression.at(0) == '*')
0036       acceptAll_ = true;
0037     else
0038       acceptAll_ = false;
0039 
0040     // replace all possible alternate operators (.AND. and .OR.)
0041     {
0042       using namespace boost;
0043       std::string temp;
0044       temp = regex_replace(expression, regex(".AND."), "&&");
0045       expression_ = regex_replace(temp, regex(".and."), "&&");
0046       temp = regex_replace(expression_, regex(".OR."), "||");
0047       expression_ = regex_replace(temp, regex(".or."), "||");
0048     }
0049 
0050     // build decision tree
0051     masterElement_ = std::make_shared<TreeElement>(expression_, triggernames);
0052   }
0053 
0054   bool TriggerSelector::acceptEvent(edm::TriggerResults const& tr) const {
0055     if (useOld_) {
0056       return eventSelector_->acceptEvent(tr);
0057     }
0058 
0059     if (acceptAll_)
0060       return true;
0061 
0062     return masterElement_->returnStatus(tr);
0063   }
0064 
0065   bool TriggerSelector::acceptEvent(unsigned char const* array_of_trigger_results, int number_of_trigger_paths) const {
0066     if (useOld_)
0067       return eventSelector_->acceptEvent(array_of_trigger_results, number_of_trigger_paths);
0068 
0069     if (acceptAll_)
0070       return true;
0071 
0072     // Form HLTGlobalStatus object to represent the array_of_trigger_results
0073     edm::HLTGlobalStatus tr(number_of_trigger_paths);
0074     int byteIndex = 0;
0075     int subIndex = 0;
0076     for (int pathIndex = 0; pathIndex < number_of_trigger_paths; ++pathIndex) {
0077       int state = array_of_trigger_results[byteIndex] >> (subIndex * 2);
0078       state &= 0x3;
0079       edm::HLTPathStatus pathStatus(static_cast<edm::hlt::HLTState>(state));
0080       tr[pathIndex] = pathStatus;
0081       ++subIndex;
0082       if (subIndex == 4) {
0083         ++byteIndex;
0084         subIndex = 0;
0085       }
0086     }
0087     // Now make the decision, based on the HLTGlobalStatus tr,
0088     // which we have created from the supplied array of results
0089     masterElement_->returnStatus(tr);
0090     return masterElement_->returnStatus(tr);
0091   }
0092 
0093   TriggerSelector::TreeElement::TreeElement(std::string const& inputString,
0094                                             Strings const& tr,
0095                                             TreeElement* parentElement)
0096       : op_(NonInit), trigBit_(-1) {
0097     std::string str_ = trim(inputString);
0098     children_.clear();
0099     parent_ = parentElement;
0100 
0101     size_t offset_ = 0;
0102     bool occurrences_ = false;
0103 
0104     if (str_.empty())
0105       throw edm::Exception(edm::errors::Configuration) << "Syntax Error (empty element)";
0106 
0107     static const size_t bopsSize_ = 2;
0108     static const std::string binaryOperators_[bopsSize_] = {"||", "&&"};
0109 
0110     for (size_t opr = 0; opr < bopsSize_; opr++) {
0111       bool exitloop_ = false;
0112       while (!exitloop_) {
0113         size_t t_end_;
0114 
0115         std::string tmpStr = str_.substr(offset_);
0116         t_end_ = tmpStr.find(binaryOperators_[opr]);
0117         if (debug_)
0118           std::cout << "offset: " << offset_ << " length: " << t_end_ << " string: " << tmpStr << std::endl;
0119 
0120         if (t_end_ == std::string::npos) {
0121           // right side element
0122           if (occurrences_)
0123             children_.push_back(new TreeElement(tmpStr, tr, this));
0124           break;
0125         }
0126         t_end_ += offset_;
0127         if (t_end_ == 0 || t_end_ + 2 >= str_.size())
0128           throw edm::Exception(edm::errors::Configuration) << "Syntax Error (operator is not unary)\n";
0129         else {
0130           // count bracket in preceeding part
0131           size_t brackets_ = 0;
0132           for (size_t k = offset_; k < t_end_; k++) {
0133             if (str_.at(k) == '(') {
0134               brackets_++;
0135             } else if (str_.at(k) == ')') {
0136               if (brackets_ == 0) {
0137                 throw edm::Exception(edm::errors::Configuration) << "Syntax Error (brackets)\n";
0138               } else {
0139                 brackets_--;
0140               }
0141             }
0142           }
0143           if (brackets_ == 0) {
0144             std::string next = str_.substr(offset_, t_end_ - offset_);
0145             children_.push_back(new TreeElement(next, tr, this));
0146             occurrences_ = true;
0147             offset_ = t_end_ + 2;
0148           } else {
0149             // operator is inside brackets, find another
0150             int bracketcnt_ = 0;
0151             for (size_t k = offset_; true; k++) {
0152               if (k >= str_.size()) {
0153                 if (bracketcnt_ != 0)
0154                   throw edm::Exception(edm::errors::Configuration) << "Syntax Error (brackets)\n";
0155                 exitloop_ = true;
0156                 if (occurrences_) {
0157                   children_.push_back(new TreeElement(str_.substr(offset_), tr, this));
0158                 }
0159                 break;
0160               }
0161               // look for another operator
0162               if (k >= t_end_ + 2 && bracketcnt_ == 0) {
0163                 std::string temp = str_.substr(k);
0164                 size_t pos = temp.find(binaryOperators_[opr]);
0165                 if (pos == std::string::npos) {
0166                   exitloop_ = true;
0167                   if (occurrences_) {
0168                     children_.push_back(new TreeElement(str_.substr(offset_), tr, this));
0169                   }
0170                   break;
0171                 } else {
0172                   int brcount_ = 0;
0173                   for (size_t s = 0; s < pos; s++) {
0174                     // counting check of brackets from last position to operator
0175                     if (temp.at(pos) == '(') {
0176                       brcount_++;
0177                     } else if (temp.at(pos) == ')') {
0178                       if (brcount_ == 0) {
0179                         throw edm::Exception(edm::errors::Configuration) << "Syntax error (brackets)\n";
0180                       } else {
0181                         brcount_--;
0182                       }
0183                     }
0184                   }
0185                   if (brcount_ != 0)
0186                     throw edm::Exception(edm::errors::Configuration) << "Syntax error (brackets)\n";
0187 
0188                   children_.push_back(new TreeElement(str_.substr(offset_, pos + k), tr, this));
0189                   offset_ = k + pos + 2;
0190                   occurrences_ = true;
0191                   if (offset_ >= str_.size())
0192                     throw edm::Exception(edm::errors::Configuration) << "Syntax Error (operator is not unary)\n";
0193                   break;
0194                 }
0195               }
0196 
0197               if (str_.at(k) == '(')
0198                 bracketcnt_++;
0199               if (str_.at(k) == ')')
0200                 bracketcnt_--;
0201             }
0202           }
0203         }
0204       }
0205       if (occurrences_) {
0206         if (opr == 0)
0207           op_ = OR;
0208         else
0209           op_ = AND;
0210         return;
0211       }
0212     }
0213 
0214     if (str_.empty()) {
0215       op_ = AND;
0216       if (debug_)
0217         std::cout << "warning: empty element (will return true)" << std::endl;
0218       return;
0219     }
0220 
0221     if (str_.at(0) == '!') {
0222       op_ = NOT;
0223       std::string next = str_.substr(1);
0224       children_.push_back(new TreeElement(next, tr, this));
0225       return;
0226     }
0227     size_t beginBlock_ = str_.find('(');
0228     size_t endBlock_ = str_.rfind(')');
0229     bool found_lbracket = (beginBlock_ != std::string::npos);
0230     bool found_rbracket = (endBlock_ != std::string::npos);
0231 
0232     if (found_lbracket != found_rbracket) {
0233       throw edm::Exception(edm::errors::Configuration) << "Syntax Error (brackets)\n";
0234     } else if (found_lbracket && found_rbracket) {
0235       if (beginBlock_ >= endBlock_) {
0236         throw edm::Exception(edm::errors::Configuration) << "Syntax Error (brackets)\n";
0237       }
0238       if (beginBlock_ != 0 || endBlock_ != str_.size() - 1)
0239         throw edm::Exception(edm::errors::Configuration) << "Syntax Error (invalid character)\n";
0240 
0241       std::string next = str_.substr(beginBlock_ + 1, endBlock_ - beginBlock_ - 1);
0242 
0243       children_.push_back(new TreeElement(next, tr, this));
0244       op_ = BR;  // a bracket
0245       return;
0246     } else if (!found_lbracket && !found_rbracket)  // assume single trigger or wildcard (parsing)
0247     {
0248       bool ignore_if_missing = true;
0249       size_t chr_pos = str_.find('@');
0250       if (chr_pos != std::string::npos) {
0251         ignore_if_missing = false;
0252         str_ = str_.substr(0, chr_pos);
0253       }
0254 
0255       std::vector<Strings::const_iterator> matches = edm::regexMatch(tr, str_);
0256       if (matches.empty()) {
0257         if (!ignore_if_missing)  // && !edm::is_glob(str_))
0258           throw edm::Exception(edm::errors::Configuration) << "Trigger name (or match) not present";
0259         else {
0260           if (debug_)
0261             std::cout << "TriggerSelector: Couldn't match any triggers from: " << str_ << std::endl
0262                       << "                 Node will not be added " << std::endl;
0263           op_ = OR;
0264           return;
0265         }
0266       }
0267       if (matches.size() == 1) {
0268         // Single Trigger match
0269         trigBit_ = distance(tr.begin(), matches[0]);
0270         if (debug_)
0271           std::cout << "added trigger path: " << trigBit_ << std::endl;
0272         return;
0273       }
0274       if (matches.size() > 1) {
0275         op_ = OR;
0276         for (size_t l = 0; l < matches.size(); l++)
0277           children_.push_back(new TreeElement(*(matches[l]), tr, this));
0278       }
0279     }
0280   }
0281 
0282   std::string TriggerSelector::trim(std::string input) {
0283     if (!input.empty()) {
0284       std::string::size_type pos = input.find_first_not_of(' ');
0285       if (pos != std::string::npos)
0286         input.erase(0, pos);
0287 
0288       pos = input.find_last_not_of(' ');
0289       if (pos != std::string::npos)
0290         input.erase(pos + 1);
0291     }
0292     return input;
0293   }
0294 
0295   std::string TriggerSelector::makeXMLString(std::string const& input) {
0296     std::string output;
0297     if (!input.empty()) {
0298       for (size_t pos = 0; pos < input.size(); pos++) {
0299         char ch = input.at(pos);
0300         if (ch == '&')
0301           output.append("&amp;");
0302         else
0303           output.append(1, ch);
0304       }
0305     }
0306     return output;
0307   }
0308 
0309   bool TriggerSelector::TreeElement::returnStatus(edm::HLTGlobalStatus const& trStatus) const {
0310     if (children_.empty()) {
0311       if (op_ == OR || op_ == NOT)
0312         return false;
0313       if (op_ == AND || op_ == BR)
0314         return true;
0315 
0316       if (trigBit_ < 0 || (unsigned int)trigBit_ >= trStatus.size())
0317         throw edm::Exception(edm::errors::Configuration) << "Internal Error: array out of bounds.";
0318 
0319       if ((trStatus[trigBit_]).state() == edm::hlt::Pass)
0320         return true;
0321       // else if ((trStatus[trigBit]).state() == edm::hlt::Fail) return false;
0322 
0323       return false;
0324     }
0325     if (op_ == NOT) {  // NEGATION
0326       return !children_[0]->returnStatus(trStatus);
0327     }
0328     if (op_ == BR) {  // BRACKET
0329       return children_[0]->returnStatus(trStatus);
0330     }
0331     if (op_ == AND) {  // AND
0332       bool status = true;
0333       for (size_t i = 0; i < children_.size(); i++)
0334         status = status && children_[i]->returnStatus(trStatus);
0335       return status;
0336     } else if (op_ == OR) {  // OR
0337       bool status = false;
0338       for (size_t i = 0; i < children_.size(); i++)
0339         status = status || children_[i]->returnStatus(trStatus);
0340       return status;
0341     }
0342     throw edm::Exception(edm::errors::Configuration)
0343         << "Internal error: reached end of returnStatus(...), op:state = " << op_;
0344     return false;
0345   }
0346 
0347   TriggerSelector::TreeElement::~TreeElement() {
0348     for (std::vector<TreeElement*>::iterator it = children_.begin(); it != children_.end(); it++)
0349       delete *it;
0350     children_.clear();
0351   }
0352 }  // namespace dqmservices