Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:12:49

0001 /*
0002  *  This EDAnalyzer will depend on all the event, lumi, run or process products declared by its configuration, both
0003  *  transient and persistent.
0004  *
0005  *  The dependencies can be specified either as module labels (e.g. "<module label>") or as branch names (e.g. 
0006  *  "<product type>_<module label>_<instance name>_<process name>").
0007  *  If a module label is used, no underscore ("_") must be present; this module will depend all the products produced
0008  *  by that module, including those produced by the Transformer functionality (such as the implicitly copied-to-host
0009  *  products in case of Alpaka-based modules).
0010  *  If a branch name is used, all four fields must be present, separated by underscores; this module will depend only
0011  *  on the matching product(s).
0012  *  
0013  *  Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names,
0014  *  similar to an OutputModule's "keep" statements.
0015  *  Use "*" to depend on all products of a given category.
0016  *
0017  *  For example, in the case of Alpaka-based modules running on a device, using
0018  *
0019  *      eventProducts = cms.untracked.vstring( "module" )
0020  *
0021  *  will cause "module" to run, along with automatic copy of its device products to the host.
0022  *  To avoid the copy, the DeviceProduct branch can be specified explicitly with
0023  *
0024  *      eventProducts = cms.untracked.vstring( "*DeviceProduct_module_*_*" )
0025  *
0026  *  .
0027  */
0028 
0029 #include <algorithm>
0030 #include <string>
0031 #include <regex>
0032 #include <vector>
0033 
0034 #include <boost/algorithm/string/replace.hpp>
0035 
0036 #include "DataFormats/Provenance/interface/BranchDescription.h"
0037 #include "FWCore/Framework/interface/global/EDAnalyzer.h"
0038 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0039 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0040 #include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h"
0041 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0042 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0043 
0044 namespace {
0045   struct ProductBranch {
0046   public:
0047     ProductBranch(std::string const& label) {
0048       static const char kSeparator = '_';
0049       static const char kWildcard = '*';
0050       static const std::regex kAny{".*"};
0051 
0052       // wildcard
0053       if (label == kWildcard) {
0054         type_ = kAny;
0055         moduleLabel_ = kAny;
0056         productInstanceName_ = kAny;
0057         processName_ = kAny;
0058         return;
0059       }
0060 
0061       int fields = std::count(label.begin(), label.end(), kSeparator) + 1;
0062       if (fields == 1) {
0063         // convert the module label into a regular expression
0064         type_ = kAny;
0065         moduleLabel_ = glob_to_regex(label);
0066         productInstanceName_ = kAny;
0067         processName_ = kAny;
0068       } else if (fields == 4) {
0069         // split the branch name into <product type>_<module label>_<instance name>_<process name>
0070         // and convert the glob expressions into regular expressions
0071         size_t first = 0, last = 0;
0072         last = label.find(kSeparator, first);
0073         type_ = glob_to_regex(label.substr(first, last - first));
0074         first = last + 1;
0075         last = label.find(kSeparator, first);
0076         moduleLabel_ = glob_to_regex(label.substr(first, last - first));
0077         first = last + 1;
0078         last = label.find(kSeparator, first);
0079         productInstanceName_ = glob_to_regex(label.substr(first, last - first));
0080         first = last + 1;
0081         last = label.find(kSeparator, first);
0082         processName_ = glob_to_regex(label.substr(first, last - first));
0083       } else {
0084         // invalid input
0085         throw edm::Exception(edm::errors::Configuration) << "Invalid module label or branch name: \"" << label << "\"";
0086       }
0087     }
0088 
0089     bool match(edm::BranchDescription const& branch) const {
0090       return (std::regex_match(branch.friendlyClassName(), type_) and
0091               std::regex_match(branch.moduleLabel(), moduleLabel_) and
0092               std::regex_match(branch.productInstanceName(), productInstanceName_) and
0093               std::regex_match(branch.processName(), processName_));
0094     }
0095 
0096   private:
0097     static std::regex glob_to_regex(std::string pattern) {
0098       boost::replace_all(pattern, "*", ".*");
0099       boost::replace_all(pattern, "?", ".");
0100       return std::regex(pattern);
0101     }
0102 
0103     std::regex type_;
0104     std::regex moduleLabel_;
0105     std::regex productInstanceName_;
0106     std::regex processName_;
0107   };
0108 
0109   std::vector<ProductBranch> make_patterns(std::vector<std::string> const& labels) {
0110     std::vector<ProductBranch> patterns;
0111     patterns.reserve(labels.size());
0112     for (auto const& label : labels)
0113       patterns.emplace_back(label);
0114     return patterns;
0115   }
0116 }  // namespace
0117 
0118 namespace edm {
0119   class GenericConsumer : public edm::global::EDAnalyzer<> {
0120   public:
0121     explicit GenericConsumer(ParameterSet const&);
0122     ~GenericConsumer() override = default;
0123 
0124     void analyze(StreamID, Event const&, EventSetup const&) const override {}
0125 
0126     static void fillDescriptions(ConfigurationDescriptions& descriptions);
0127 
0128   private:
0129     std::vector<ProductBranch> eventProducts_;
0130     std::vector<ProductBranch> lumiProducts_;
0131     std::vector<ProductBranch> runProducts_;
0132     std::vector<ProductBranch> processProducts_;
0133     std::string label_;
0134     bool verbose_;
0135   };
0136 
0137   GenericConsumer::GenericConsumer(ParameterSet const& config)
0138       : eventProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("eventProducts"))),
0139         lumiProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("lumiProducts"))),
0140         runProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("runProducts"))),
0141         processProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("processProducts"))),
0142         label_(config.getParameter<std::string>("@module_label")),
0143         verbose_(config.getUntrackedParameter<bool>("verbose")) {
0144     callWhenNewProductsRegistered([this](edm::BranchDescription const& branch) {
0145       static const std::string kPathStatus("edm::PathStatus");
0146       static const std::string kEndPathStatus("edm::EndPathStatus");
0147 
0148       switch (branch.branchType()) {
0149         case InEvent:
0150           if (branch.className() == kPathStatus or branch.className() == kEndPathStatus)
0151             return;
0152           for (auto const& label : eventProducts_)
0153             if (label.match(branch)) {
0154               this->consumes(edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
0155                              edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
0156               if (verbose_) {
0157                 edm::LogVerbatim("GenericConsumer")
0158                     << label_ << " consumes Event product " << branch.friendlyClassName() << '_' << branch.moduleLabel()
0159                     << '_' << branch.productInstanceName() << '_' << branch.processName() << '\n';
0160               }
0161               break;
0162             }
0163           break;
0164 
0165         case InLumi:
0166           for (auto const& label : lumiProducts_)
0167             if (label.match(branch)) {
0168               this->consumes<edm::InLumi>(
0169                   edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
0170                   edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
0171               if (verbose_) {
0172                 edm::LogVerbatim("GenericConsumer")
0173                     << label_ << " consumes LuminosityBlock product " << branch.friendlyClassName() << '_'
0174                     << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName()
0175                     << '\n';
0176               }
0177               break;
0178             }
0179           break;
0180 
0181         case InRun:
0182           for (auto const& label : runProducts_)
0183             if (label.match(branch)) {
0184               this->consumes<edm::InRun>(
0185                   edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
0186                   edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
0187               if (verbose_) {
0188                 edm::LogVerbatim("GenericConsumer")
0189                     << label_ << " consumes Run product " << branch.friendlyClassName() << '_' << branch.moduleLabel()
0190                     << '_' << branch.productInstanceName() << '_' << branch.processName() << '\n';
0191               }
0192               break;
0193             }
0194           break;
0195 
0196         case InProcess:
0197           for (auto const& label : processProducts_)
0198             if (label.match(branch)) {
0199               this->consumes<edm::InProcess>(
0200                   edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
0201                   edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
0202               if (verbose_) {
0203                 edm::LogVerbatim("GenericConsumer")
0204                     << label_ << " consumes Process product " << branch.friendlyClassName() << '_'
0205                     << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName()
0206                     << '\n';
0207               }
0208               break;
0209             }
0210           break;
0211 
0212         default:
0213           throw Exception(errors::LogicError)
0214               << "Unexpected branch type " << branch.branchType() << "\nPlease contact a Framework developer\n";
0215       }
0216     });
0217   }
0218 
0219   void GenericConsumer::fillDescriptions(ConfigurationDescriptions& descriptions) {
0220     descriptions.setComment(
0221         R"(This EDAnalyzer will depend on all the event, lumi, run or process products declared by its configuration, both transient and persistent.
0222 
0223 The dependencies can be specified either as module labels (e.g. "<module label>") or as branch names (e.g. "<product type>_<module label>_<instance name>_<process name>").
0224 If a module label is used, no underscore ("_") must be present; this module will depend all the products produced by that module, including those produced by the Transformer functionality (such as the implicitly copied-to-host products in case of Alpaka-based modules).
0225 If a branch name is used, all four fields must be present, separated by underscores; this module will depend only on the matching product(s).
0226 
0227 Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar to an OutputModule's "keep" statements.
0228 Use "*" to depend on all products of a given category.
0229 
0230 For example, in the case of Alpaka-based modules running on a device, using
0231 
0232     eventProducts = cms.untracked.vstring( "module" )
0233 
0234 will cause "module" to run, along with automatic copy of its device products to the host.
0235 To avoid the copy, the DeviceProduct branch can be specified explicitly with
0236 
0237     eventProducts = cms.untracked.vstring( "*DeviceProduct_module_*_*" )
0238 
0239 .)");
0240 
0241     ParameterSetDescription desc;
0242     desc.addUntracked<std::vector<std::string>>("eventProducts", {})
0243         ->setComment("List of modules or branches whose event products this module will depend on.");
0244     desc.addUntracked<std::vector<std::string>>("lumiProducts", {})
0245         ->setComment("List of modules or branches whose lumi products this module will depend on.");
0246     desc.addUntracked<std::vector<std::string>>("runProducts", {})
0247         ->setComment("List of modules or branches whose run products this module will depend on.");
0248     desc.addUntracked<std::vector<std::string>>("processProducts", {})
0249         ->setComment("List of modules or branches whose process products this module will depend on.");
0250     desc.addUntracked<bool>("verbose", false)
0251         ->setComment("Print the actual branch names for which the dependency are declared.");
0252     descriptions.addWithDefaultLabel(desc);
0253   }
0254 
0255 }  // namespace edm
0256 
0257 #include "FWCore/Framework/interface/MakerMacros.h"
0258 using edm::GenericConsumer;
0259 DEFINE_FWK_MODULE(GenericConsumer);