GenericConsumer

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
/*
 *  This EDAnalyzer will depend on all the event, lumi, run or process products declared by its configuration, both
 *  transient and persistent.
 *
 *  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>").
 *  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).
 *  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).
 *  
 *  Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names,
 *  similar to an OutputModule's "keep" statements.
 *  Use "*" to depend on all products of a given category.
 *
 *  For example, in the case of Alpaka-based modules running on a device, using
 *
 *      eventProducts = cms.untracked.vstring( "module" )
 *
 *  will cause "module" to run, along with automatic copy of its device products to the host.
 *  To avoid the copy, the DeviceProduct branch can be specified explicitly with
 *
 *      eventProducts = cms.untracked.vstring( "*DeviceProduct_module_*_*" )
 *
 *  .
 */

#include <algorithm>
#include <string>
#include <regex>
#include <vector>

#include <boost/algorithm/string/replace.hpp>

#include "DataFormats/Provenance/interface/ProductDescription.h"
#include "DataFormats/Provenance/interface/ProductNamePattern.h"
#include "FWCore/Framework/interface/global/EDAnalyzer.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h"

namespace edm {
  class GenericConsumer : public edm::global::EDAnalyzer<> {
  public:
    explicit GenericConsumer(ParameterSet const&);
    ~GenericConsumer() override = default;

    void analyze(StreamID, Event const&, EventSetup const&) const override {}

    static void fillDescriptions(ConfigurationDescriptions& descriptions);

  private:
    std::vector<edm::ProductNamePattern> eventProducts_;
    std::vector<edm::ProductNamePattern> lumiProducts_;
    std::vector<edm::ProductNamePattern> runProducts_;
    std::vector<edm::ProductNamePattern> processProducts_;
    std::string label_;
    bool verbose_;
  };

  GenericConsumer::GenericConsumer(ParameterSet const& config)
      : eventProducts_(edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("eventProducts"))),
        lumiProducts_(edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("lumiProducts"))),
        runProducts_(edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("runProducts"))),
        processProducts_(
            edm::productPatterns(config.getUntrackedParameter<std::vector<std::string>>("processProducts"))),
        label_(config.getParameter<std::string>("@module_label")),
        verbose_(config.getUntrackedParameter<bool>("verbose")) {
    callWhenNewProductsRegistered([this](edm::ProductDescription const& branch) {
      static const std::string kPathStatus("edm::PathStatus");
      static const std::string kEndPathStatus("edm::EndPathStatus");

      switch (branch.branchType()) {
        case InEvent:
          if (branch.className() == kPathStatus or branch.className() == kEndPathStatus)
            return;
          for (auto const& label : eventProducts_)
            if (label.match(branch)) {
              this->consumes(edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
                             edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
              if (verbose_) {
                edm::LogVerbatim("GenericConsumer")
                    << label_ << " consumes Event product " << branch.friendlyClassName() << '_' << branch.moduleLabel()
                    << '_' << branch.productInstanceName() << '_' << branch.processName() << '\n';
              }
              break;
            }
          break;

        case InLumi:
          for (auto const& label : lumiProducts_)
            if (label.match(branch)) {
              this->consumes<edm::InLumi>(
                  edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
                  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
              if (verbose_) {
                edm::LogVerbatim("GenericConsumer")
                    << label_ << " consumes LuminosityBlock product " << branch.friendlyClassName() << '_'
                    << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName()
                    << '\n';
              }
              break;
            }
          break;

        case InRun:
          for (auto const& label : runProducts_)
            if (label.match(branch)) {
              this->consumes<edm::InRun>(
                  edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
                  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
              if (verbose_) {
                edm::LogVerbatim("GenericConsumer")
                    << label_ << " consumes Run product " << branch.friendlyClassName() << '_' << branch.moduleLabel()
                    << '_' << branch.productInstanceName() << '_' << branch.processName() << '\n';
              }
              break;
            }
          break;

        case InProcess:
          for (auto const& label : processProducts_)
            if (label.match(branch)) {
              this->consumes<edm::InProcess>(
                  edm::TypeToGet{branch.unwrappedTypeID(), PRODUCT_TYPE},
                  edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()});
              if (verbose_) {
                edm::LogVerbatim("GenericConsumer")
                    << label_ << " consumes Process product " << branch.friendlyClassName() << '_'
                    << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName()
                    << '\n';
              }
              break;
            }
          break;

        default:
          throw Exception(errors::LogicError)
              << "Unexpected branch type " << branch.branchType() << "\nPlease contact a Framework developer\n";
      }
    });
  }

  void GenericConsumer::fillDescriptions(ConfigurationDescriptions& descriptions) {
    descriptions.setComment(
        R"(This EDAnalyzer will depend on all the event, lumi, run or process products declared by its configuration, both transient and persistent.

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>").
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).
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).

Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar to an OutputModule's "keep" statements.
Use "*" to depend on all products of a given category.

For example, in the case of Alpaka-based modules running on a device, using

    eventProducts = cms.untracked.vstring( "module" )

will cause "module" to run, along with automatic copy of its device products to the host.
To avoid the copy, the DeviceProduct branch can be specified explicitly with

    eventProducts = cms.untracked.vstring( "*DeviceProduct_module_*_*" )

.)");

    ParameterSetDescription desc;
    desc.addUntracked<std::vector<std::string>>("eventProducts", {})
        ->setComment("List of modules or branches whose event products this module will depend on.");
    desc.addUntracked<std::vector<std::string>>("lumiProducts", {})
        ->setComment("List of modules or branches whose lumi products this module will depend on.");
    desc.addUntracked<std::vector<std::string>>("runProducts", {})
        ->setComment("List of modules or branches whose run products this module will depend on.");
    desc.addUntracked<std::vector<std::string>>("processProducts", {})
        ->setComment("List of modules or branches whose process products this module will depend on.");
    desc.addUntracked<bool>("verbose", false)
        ->setComment("Print the actual branch names for which the dependency are declared.");
    descriptions.addWithDefaultLabel(desc);
  }

}  // namespace edm

#include "FWCore/Framework/interface/MakerMacros.h"
using edm::GenericConsumer;
DEFINE_FWK_MODULE(GenericConsumer);