|
| 1 | +/* |
| 2 | + * This EDProducer will clone all the event products declared by its configuration, using their ROOT dictionaries. |
| 3 | + * |
| 4 | + * The products can be specified either as module labels (e.g. "<module label>") or as branch names (e.g. |
| 5 | + * "<product type>_<module label>_<instance name>_<process name>"). |
| 6 | + * |
| 7 | + * If a module label is used, no underscore ("_") must be present; this module will clone all the products produced by |
| 8 | + * 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 clone only on |
| 11 | + * 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 clone all products. |
| 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, and will attempt to clone |
| 22 | + * all device and host products. |
| 23 | + * To clone only the host product, the branch can be specified explicitly with |
| 24 | + * |
| 25 | + * eventProducts = cms.untracked.vstring( "HostProductType_module_*_*" ) |
| 26 | + * |
| 27 | + * . |
| 28 | + */ |
| 29 | + |
| 30 | +#include <cstring> |
| 31 | +#include <iostream> |
| 32 | +#include <memory> |
| 33 | +#include <string> |
| 34 | +#include <string_view> |
| 35 | +#include <utility> |
| 36 | +#include <vector> |
| 37 | + |
| 38 | +#include <TBufferFile.h> |
| 39 | + |
| 40 | +#include "DataFormats/Provenance/interface/ProductDescription.h" |
| 41 | +#include "DataFormats/Provenance/interface/ProductNamePattern.h" |
| 42 | +#include "FWCore/Framework/interface/Event.h" |
| 43 | +#include "FWCore/Framework/interface/WrapperBaseHandle.h" |
| 44 | +#include "FWCore/Framework/interface/WrapperBaseOrphanHandle.h" |
| 45 | +#include "FWCore/Framework/interface/global/EDProducer.h" |
| 46 | +#include "FWCore/MessageLogger/interface/MessageLogger.h" |
| 47 | +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" |
| 48 | +#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h" |
| 49 | +#include "FWCore/ParameterSet/interface/ParameterSet.h" |
| 50 | +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" |
| 51 | +#include "FWCore/Reflection/interface/ObjectWithDict.h" |
| 52 | +#include "FWCore/Utilities/interface/EDMException.h" |
| 53 | + |
| 54 | +namespace edmtest { |
| 55 | + |
| 56 | + class GenericClonerAlt : public edm::global::EDProducer<> { |
| 57 | + public: |
| 58 | + explicit GenericClonerAlt(edm::ParameterSet const&); |
| 59 | + ~GenericClonerAlt() override = default; |
| 60 | + |
| 61 | + void produce(edm::StreamID, edm::Event&, edm::EventSetup const&) const override; |
| 62 | + |
| 63 | + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); |
| 64 | + |
| 65 | + private: |
| 66 | + struct Entry { |
| 67 | + edm::TypeWithDict objectType_; |
| 68 | + edm::TypeWithDict wrappedType_; |
| 69 | + edm::EDGetToken getToken_; |
| 70 | + edm::EDPutToken putToken_; |
| 71 | + }; |
| 72 | + |
| 73 | + std::vector<edm::ProductNamePattern> eventPatterns_; |
| 74 | + std::vector<Entry> eventProducts_; |
| 75 | + std::string label_; |
| 76 | + bool verbose_; |
| 77 | + }; |
| 78 | + |
| 79 | + GenericClonerAlt::GenericClonerAlt(edm::ParameterSet const& config) |
| 80 | + : eventPatterns_(edm::productPatterns(config.getParameter<std::vector<std::string>>("eventProducts"))), |
| 81 | + label_(config.getParameter<std::string>("@module_label")), |
| 82 | + verbose_(config.getUntrackedParameter<bool>("verbose")) { |
| 83 | + eventProducts_.reserve(eventPatterns_.size()); |
| 84 | + |
| 85 | + callWhenNewProductsRegistered([this](edm::ProductDescription const& product) { |
| 86 | + static const std::string_view kPathStatus("edm::PathStatus"); |
| 87 | + static const std::string_view kEndPathStatus("edm::EndPathStatus"); |
| 88 | + |
| 89 | + switch (product.branchType()) { |
| 90 | + case edm::InEvent: |
| 91 | + if (product.className() == kPathStatus or product.className() == kEndPathStatus) { |
| 92 | + return; |
| 93 | + } |
| 94 | + for (auto& pattern : eventPatterns_) { |
| 95 | + if (pattern.match(product)) { |
| 96 | + // check that the product is not transient |
| 97 | + if (product.transient()) { |
| 98 | + edm::LogWarning("GenericCloner") << "Event product " << product.branchName() << " of type " |
| 99 | + << product.unwrappedType() << " is transient, will not be cloned."; |
| 100 | + break; |
| 101 | + } |
| 102 | + if (verbose_) { |
| 103 | + edm::LogInfo("GenericCloner") |
| 104 | + << "will clone Event product " << product.branchName() << " of type " << product.unwrappedType(); |
| 105 | + } |
| 106 | + Entry entry; |
| 107 | + entry.objectType_ = product.unwrappedType(); |
| 108 | + entry.wrappedType_ = product.wrappedType(); |
| 109 | + // TODO move this to EDConsumerBase::consumes() ? |
| 110 | + entry.getToken_ = this->consumes( |
| 111 | + edm::TypeToGet{product.unwrappedTypeID(), edm::PRODUCT_TYPE}, |
| 112 | + edm::InputTag{product.moduleLabel(), product.productInstanceName(), product.processName()}); |
| 113 | + entry.putToken_ = this->produces(product.unwrappedTypeID(), product.productInstanceName()); |
| 114 | + eventProducts_.emplace_back(std::move(entry)); |
| 115 | + break; |
| 116 | + } |
| 117 | + } |
| 118 | + break; |
| 119 | + |
| 120 | + case edm::InLumi: |
| 121 | + case edm::InRun: |
| 122 | + case edm::InProcess: |
| 123 | + // lumi, run and process products are not supported |
| 124 | + break; |
| 125 | + |
| 126 | + default: |
| 127 | + throw edm::Exception(edm::errors::LogicError) |
| 128 | + << "Unexpected product type " << product.branchType() << "\nPlease contact a Framework developer."; |
| 129 | + } |
| 130 | + }); |
| 131 | + } |
| 132 | + |
| 133 | + void GenericClonerAlt::produce(edm::StreamID /*unused*/, edm::Event& event, edm::EventSetup const& /*unused*/) const { |
| 134 | + for (auto& product : eventProducts_) { |
| 135 | + edm::Handle<edm::WrapperBase> handle(product.objectType_.typeInfo()); |
| 136 | + event.getByToken(product.getToken_, handle); |
| 137 | + edm::WrapperBase const* wrapper = handle.product(); |
| 138 | + |
| 139 | + // write the wrapper into a TBuffer |
| 140 | + TBufferFile buffer(TBuffer::kWrite); |
| 141 | + product.wrappedType_.getClass()->Streamer(const_cast<edm::WrapperBase*>(wrapper), buffer); |
| 142 | + |
| 143 | + // read back a copy of the product form the TBuffer |
| 144 | + buffer.SetReadMode(); |
| 145 | + buffer.SetBufferOffset(0); |
| 146 | + std::unique_ptr<edm::WrapperBase> clone( |
| 147 | + reinterpret_cast<edm::WrapperBase*>(product.wrappedType_.getClass()->New())); |
| 148 | + product.wrappedType_.getClass()->Streamer(clone.get(), buffer); |
| 149 | + |
| 150 | + // move the wrapper into the Event |
| 151 | + event.put(product.putToken_, std::move(clone)); |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + void GenericClonerAlt::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { |
| 156 | + descriptions.setComment( |
| 157 | + R"(This EDProducer will clone all the event products declared by its configuration, using their ROOT dictionaries. |
| 158 | +
|
| 159 | +The products 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>"). |
| 160 | +If a module label is used, no underscore ("_") must be present; this module will clone 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). |
| 161 | +If a branch name is used, all four fields must be present, separated by underscores; this module will clone only on the matching product(s). |
| 162 | +
|
| 163 | +Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar to an OutputModule's "keep" statements. |
| 164 | +Use "*" to clone all products. |
| 165 | +
|
| 166 | +For example, in the case of Alpaka-based modules running on a device, using |
| 167 | +
|
| 168 | + eventProducts = cms.untracked.vstring( "module" ) |
| 169 | +
|
| 170 | +will cause "module" to run, along with automatic copy of its device products to the host, and will attempt to clone all device and host products. |
| 171 | +To clone only the host product, the branch can be specified explicitly with |
| 172 | +
|
| 173 | + eventProducts = cms.untracked.vstring( "HostProductType_module_*_*" ) |
| 174 | +
|
| 175 | +.)"); |
| 176 | + |
| 177 | + edm::ParameterSetDescription desc; |
| 178 | + desc.add<std::vector<std::string>>("eventProducts", {}) |
| 179 | + ->setComment("List of modules or branches whose event products will be cloned."); |
| 180 | + desc.addUntracked<bool>("verbose", false) |
| 181 | + ->setComment("Print the branch names of the products that will be cloned."); |
| 182 | + descriptions.addWithDefaultLabel(desc); |
| 183 | + } |
| 184 | + |
| 185 | +} // namespace edmtest |
| 186 | + |
| 187 | +#include "FWCore/Framework/interface/MakerMacros.h" |
| 188 | +DEFINE_FWK_MODULE(edmtest::GenericClonerAlt); |
0 commit comments