CMS 3D CMS Logo

GenericConsumer.cc
Go to the documentation of this file.
1 /*
2  * This EDAnalyzer will depend on all the event, lumi, run or process products declared by its configuration, both
3  * transient and persistent.
4  *
5  * The dependencies can be specified either as module labels (e.g. "<module label>") or as branch names (e.g.
6  * "<product type>_<module label>_<instance name>_<process name>").
7  * If a module label is used, no underscore ("_") must be present; this module will depend all the products produced
8  * by that module, including those produced by the Transformer functionality (such as the implicitly copied-to-host
9  * products in case of Alpaka-based modules).
10  * If a branch name is used, all four fields must be present, separated by underscores; this module will depend only
11  * on the matching product(s).
12  *
13  * Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names,
14  * similar to an OutputModule's "keep" statements.
15  * Use "*" to depend on all products of a given category.
16  *
17  * For example, in the case of Alpaka-based modules running on a device, using
18  *
19  * eventProducts = cms.untracked.vstring( "module" )
20  *
21  * will cause "module" to run, along with automatic copy of its device products to the host.
22  * To avoid the copy, the DeviceProduct branch can be specified explicitly with
23  *
24  * eventProducts = cms.untracked.vstring( "*DeviceProduct_module_*_*" )
25  *
26  * .
27  */
28 
29 #include <algorithm>
30 #include <string>
31 #include <regex>
32 #include <vector>
33 
34 #include <boost/algorithm/string/replace.hpp>
35 
43 
44 namespace {
45  struct ProductBranch {
46  public:
47  ProductBranch(std::string const& label) {
48  static const char kSeparator = '_';
49  static const char kWildcard = '*';
50  static const std::regex kAny{".*"};
51 
52  // wildcard
53  if (label == kWildcard) {
54  type_ = kAny;
55  moduleLabel_ = kAny;
56  productInstanceName_ = kAny;
57  processName_ = kAny;
58  return;
59  }
60 
61  int fields = std::count(label.begin(), label.end(), kSeparator) + 1;
62  if (fields == 1) {
63  // convert the module label into a regular expression
64  type_ = kAny;
65  moduleLabel_ = glob_to_regex(label);
66  productInstanceName_ = kAny;
67  processName_ = kAny;
68  } else if (fields == 4) {
69  // split the branch name into <product type>_<module label>_<instance name>_<process name>
70  // and convert the glob expressions into regular expressions
71  size_t first = 0, last = 0;
72  last = label.find(kSeparator, first);
73  type_ = glob_to_regex(label.substr(first, last - first));
74  first = last + 1;
75  last = label.find(kSeparator, first);
76  moduleLabel_ = glob_to_regex(label.substr(first, last - first));
77  first = last + 1;
78  last = label.find(kSeparator, first);
79  productInstanceName_ = glob_to_regex(label.substr(first, last - first));
80  first = last + 1;
81  last = label.find(kSeparator, first);
82  processName_ = glob_to_regex(label.substr(first, last - first));
83  } else {
84  // invalid input
85  throw edm::Exception(edm::errors::Configuration) << "Invalid module label or branch name: \"" << label << "\"";
86  }
87  }
88 
89  bool match(edm::BranchDescription const& branch) const {
90  return (std::regex_match(branch.friendlyClassName(), type_) and
91  std::regex_match(branch.moduleLabel(), moduleLabel_) and
92  std::regex_match(branch.productInstanceName(), productInstanceName_) and
93  std::regex_match(branch.processName(), processName_));
94  }
95 
96  private:
97  static std::regex glob_to_regex(std::string pattern) {
98  boost::replace_all(pattern, "*", ".*");
99  boost::replace_all(pattern, "?", ".");
100  return std::regex(pattern);
101  }
102 
103  std::regex type_;
104  std::regex moduleLabel_;
105  std::regex productInstanceName_;
106  std::regex processName_;
107  };
108 
109  std::vector<ProductBranch> make_patterns(std::vector<std::string> const& labels) {
110  std::vector<ProductBranch> patterns;
111  patterns.reserve(labels.size());
112  for (auto const& label : labels)
113  patterns.emplace_back(label);
114  return patterns;
115  }
116 } // namespace
117 
118 namespace edm {
120  public:
121  explicit GenericConsumer(ParameterSet const&);
122  ~GenericConsumer() override = default;
123 
124  void analyze(StreamID, Event const&, EventSetup const&) const override {}
125 
126  static void fillDescriptions(ConfigurationDescriptions& descriptions);
127 
128  private:
129  std::vector<ProductBranch> eventProducts_;
130  std::vector<ProductBranch> lumiProducts_;
131  std::vector<ProductBranch> runProducts_;
132  std::vector<ProductBranch> processProducts_;
134  bool verbose_;
135  };
136 
138  : eventProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("eventProducts"))),
139  lumiProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("lumiProducts"))),
140  runProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("runProducts"))),
141  processProducts_(make_patterns(config.getUntrackedParameter<std::vector<std::string>>("processProducts"))),
142  label_(config.getParameter<std::string>("@module_label")),
143  verbose_(config.getUntrackedParameter<bool>("verbose")) {
145  static const std::string kPathStatus("edm::PathStatus");
146  static const std::string kEndPathStatus("edm::EndPathStatus");
147 
148  switch (branch.branchType()) {
149  case InEvent:
150  if (branch.className() == kPathStatus or branch.className() == kEndPathStatus)
151  return;
152  for (auto const& label : eventProducts_)
153  if (label.match(branch)) {
154  this->consumes(edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
155  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
156  if (verbose_) {
157  edm::LogVerbatim("GenericConsumer")
158  << label_ << " consumes Event product " << branch.friendlyClassName() << '_' << branch.moduleLabel()
159  << '_' << branch.productInstanceName() << '_' << branch.processName() << '\n';
160  }
161  break;
162  }
163  break;
164 
165  case InLumi:
166  for (auto const& label : lumiProducts_)
167  if (label.match(branch)) {
168  this->consumes<edm::InLumi>(
169  edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
170  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
171  if (verbose_) {
172  edm::LogVerbatim("GenericConsumer")
173  << label_ << " consumes LuminosityBlock product " << branch.friendlyClassName() << '_'
174  << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName()
175  << '\n';
176  }
177  break;
178  }
179  break;
180 
181  case InRun:
182  for (auto const& label : runProducts_)
183  if (label.match(branch)) {
184  this->consumes<edm::InRun>(
185  edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
186  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
187  if (verbose_) {
188  edm::LogVerbatim("GenericConsumer")
189  << label_ << " consumes Run product " << branch.friendlyClassName() << '_' << branch.moduleLabel()
190  << '_' << branch.productInstanceName() << '_' << branch.processName() << '\n';
191  }
192  break;
193  }
194  break;
195 
196  case InProcess:
197  for (auto const& label : processProducts_)
198  if (label.match(branch)) {
199  this->consumes<edm::InProcess>(
200  edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
201  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
202  if (verbose_) {
203  edm::LogVerbatim("GenericConsumer")
204  << label_ << " consumes Process product " << branch.friendlyClassName() << '_'
205  << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName()
206  << '\n';
207  }
208  break;
209  }
210  break;
211 
212  default:
214  << "Unexpected branch type " << branch.branchType() << "\nPlease contact a Framework developer\n";
215  }
216  });
217  }
218 
220  descriptions.setComment(
221  R"(This EDAnalyzer will depend on all the event, lumi, run or process products declared by its configuration, both transient and persistent.
222 
223 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>").
224 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).
225 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).
226 
227 Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar to an OutputModule's "keep" statements.
228 Use "*" to depend on all products of a given category.
229 
230 For example, in the case of Alpaka-based modules running on a device, using
231 
232  eventProducts = cms.untracked.vstring( "module" )
233 
234 will cause "module" to run, along with automatic copy of its device products to the host.
235 To avoid the copy, the DeviceProduct branch can be specified explicitly with
236 
237  eventProducts = cms.untracked.vstring( "*DeviceProduct_module_*_*" )
238 
239 .)");
240 
242  desc.addUntracked<std::vector<std::string>>("eventProducts", {})
243  ->setComment("List of modules or branches whose event products this module will depend on.");
244  desc.addUntracked<std::vector<std::string>>("lumiProducts", {})
245  ->setComment("List of modules or branches whose lumi products this module will depend on.");
246  desc.addUntracked<std::vector<std::string>>("runProducts", {})
247  ->setComment("List of modules or branches whose run products this module will depend on.");
248  desc.addUntracked<std::vector<std::string>>("processProducts", {})
249  ->setComment("List of modules or branches whose process products this module will depend on.");
250  desc.addUntracked<bool>("verbose", false)
251  ->setComment("Print the actual branch names for which the dependency are declared.");
252  descriptions.addWithDefaultLabel(desc);
253  }
254 
255 } // namespace edm
256 
Log< level::Info, true > LogVerbatim
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
static void fillDescriptions(ConfigurationDescriptions &descriptions)
~GenericConsumer() override=default
void callWhenNewProductsRegistered(std::function< void(BranchDescription const &)> const &func)
GenericConsumer(ParameterSet const &)
Definition: config.py:1
EDGetTokenT< ProductType > consumes(edm::InputTag const &tag)
char const * label
std::vector< ProductBranch > runProducts_
std::vector< ProductBranch > eventProducts_
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
std::vector< ProductBranch > processProducts_
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
void analyze(StreamID, Event const &, EventSetup const &) const override
void setComment(std::string const &value)
std::vector< ProductBranch > lumiProducts_
HLT enums.
std::pair< typename Association::data_type::first_type, double > match(Reference key, Association association, bool bestMatchByMaxValue)
Generic matching function.
Definition: Utils.h:10