File indexing completed on 2024-04-06 12:12:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
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
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
0064 type_ = kAny;
0065 moduleLabel_ = glob_to_regex(label);
0066 productInstanceName_ = kAny;
0067 processName_ = kAny;
0068 } else if (fields == 4) {
0069
0070
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
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 }
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 }
0256
0257 #include "FWCore/Framework/interface/MakerMacros.h"
0258 using edm::GenericConsumer;
0259 DEFINE_FWK_MODULE(GenericConsumer);