Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:10:15

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