|
| 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 <memory> |
| 32 | +#include <string> |
| 33 | +#include <string_view> |
| 34 | +#include <utility> |
| 35 | +#include <vector> |
| 36 | + |
| 37 | +#include <TBufferFile.h> |
| 38 | + |
| 39 | +#include "DataFormats/Provenance/interface/BranchDescription.h" |
| 40 | +#include "FWCore/Framework/interface/Event.h" |
| 41 | +#include "FWCore/Framework/interface/GenericHandle.h" |
| 42 | +#include "FWCore/Framework/interface/GenericProduct.h" |
| 43 | +#include "FWCore/Framework/interface/global/EDProducer.h" |
| 44 | +#include "FWCore/MessageLogger/interface/MessageLogger.h" |
| 45 | +#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" |
| 46 | +#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h" |
| 47 | +#include "FWCore/ParameterSet/interface/ParameterSet.h" |
| 48 | +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" |
| 49 | +#include "FWCore/Reflection/interface/ObjectWithDict.h" |
| 50 | +#include "FWCore/Utilities/interface/BranchPattern.h" |
| 51 | + |
| 52 | +namespace edmtest { |
| 53 | + |
| 54 | + class GenericCloner : public edm::global::EDProducer<> { |
| 55 | + public: |
| 56 | + explicit GenericCloner(edm::ParameterSet const&); |
| 57 | + ~GenericCloner() override = default; |
| 58 | + |
| 59 | + void produce(edm::StreamID, edm::Event&, edm::EventSetup const&) const override; |
| 60 | + |
| 61 | + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); |
| 62 | + |
| 63 | + private: |
| 64 | + struct Entry { |
| 65 | + edm::TypeWithDict objectType_; |
| 66 | + edm::TypeWithDict wrappedType_; |
| 67 | + edm::EDGetToken getToken_; |
| 68 | + edm::EDPutToken putToken_; |
| 69 | + }; |
| 70 | + |
| 71 | + std::vector<edm::BranchPattern> eventPatterns_; |
| 72 | + std::vector<Entry> eventProducts_; |
| 73 | + std::string label_; |
| 74 | + bool verbose_; |
| 75 | + }; |
| 76 | + |
| 77 | + GenericCloner::GenericCloner(edm::ParameterSet const& config) |
| 78 | + : eventPatterns_(edm::branchPatterns(config.getParameter<std::vector<std::string>>("eventProducts"))), |
| 79 | + label_(config.getParameter<std::string>("@module_label")), |
| 80 | + verbose_(config.getUntrackedParameter<bool>("verbose")) { |
| 81 | + eventProducts_.reserve(eventPatterns_.size()); |
| 82 | + |
| 83 | + callWhenNewProductsRegistered([this](edm::BranchDescription const& branch) { |
| 84 | + static const std::string_view kPathStatus("edm::PathStatus"); |
| 85 | + static const std::string_view kEndPathStatus("edm::EndPathStatus"); |
| 86 | + |
| 87 | + switch (branch.branchType()) { |
| 88 | + case edm::InEvent: |
| 89 | + if (branch.className() == kPathStatus or branch.className() == kEndPathStatus) |
| 90 | + return; |
| 91 | + for (auto& pattern : eventPatterns_) |
| 92 | + if (pattern.match(branch)) { |
| 93 | + Entry product; |
| 94 | + product.objectType_ = branch.unwrappedType(); |
| 95 | + product.wrappedType_ = branch.wrappedType(); |
| 96 | + // TODO move this to EDConsumerBase::consumes() ? |
| 97 | + product.getToken_ = this->consumes( |
| 98 | + edm::TypeToGet{branch.unwrappedTypeID(), edm::PRODUCT_TYPE}, |
| 99 | + edm::InputTag{branch.moduleLabel(), branch.productInstanceName(), branch.processName()}); |
| 100 | + product.putToken_ = this->produces(branch.unwrappedTypeID(), branch.productInstanceName()); |
| 101 | + eventProducts_.push_back(product); |
| 102 | + |
| 103 | + if (verbose_) { |
| 104 | + edm::LogInfo("GenericCloner") |
| 105 | + << label_ << " will clone Event product " << branch.friendlyClassName() << '_' |
| 106 | + << branch.moduleLabel() << '_' << branch.productInstanceName() << '_' << branch.processName(); |
| 107 | + } |
| 108 | + break; |
| 109 | + } |
| 110 | + break; |
| 111 | + |
| 112 | + case edm::InLumi: |
| 113 | + case edm::InRun: |
| 114 | + case edm::InProcess: |
| 115 | + // lumi, run and process products are not supported |
| 116 | + break; |
| 117 | + |
| 118 | + default: |
| 119 | + throw edm::Exception(edm::errors::LogicError) |
| 120 | + << "Unexpected branch type " << branch.branchType() << "\nPlease contact a Framework developer\n"; |
| 121 | + } |
| 122 | + }); |
| 123 | + } |
| 124 | + |
| 125 | + void GenericCloner::produce(edm::StreamID /*unused*/, edm::Event& event, edm::EventSetup const& /*unused*/) const { |
| 126 | + for (auto& product : eventProducts_) { |
| 127 | + edm::GenericHandle handle(product.objectType_); |
| 128 | + event.getByToken(product.getToken_, handle); |
| 129 | + edm::ObjectWithDict const* object = handle.product(); |
| 130 | + |
| 131 | + TBufferFile send_buffer(TBuffer::kWrite); |
| 132 | + send_buffer.WriteObjectAny(object->address(), product.objectType_.getClass(), false); |
| 133 | + int size = send_buffer.Length(); |
| 134 | + |
| 135 | + TBufferFile recv_buffer(TBuffer::kRead, size); |
| 136 | + std::memcpy(recv_buffer.Buffer(), send_buffer.Buffer(), size); |
| 137 | + |
| 138 | + void* clone_ptr = reinterpret_cast<void*>(recv_buffer.ReadObjectAny(product.objectType_.getClass())); |
| 139 | + auto clone = std::make_unique<edm::GenericProduct>(); |
| 140 | + clone->object_ = edm::ObjectWithDict(product.objectType_, clone_ptr); |
| 141 | + clone->wrappedType_ = product.wrappedType_; |
| 142 | + |
| 143 | + // specialise Event::put for GenericProduct |
| 144 | + event.put(product.putToken_, std::move(clone)); |
| 145 | + } |
| 146 | + } |
| 147 | + |
| 148 | + void GenericCloner::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { |
| 149 | + descriptions.setComment( |
| 150 | + R"(This EDProducer will clone all the event products declared by its configuration, using their ROOT dictionaries. |
| 151 | +
|
| 152 | +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>"). |
| 153 | +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). |
| 154 | +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). |
| 155 | +
|
| 156 | +Glob expressions ("?" and "*") are supported in module labels and within the individual fields of branch names, similar to an OutputModule's "keep" statements. |
| 157 | +Use "*" to clone all products. |
| 158 | +
|
| 159 | +For example, in the case of Alpaka-based modules running on a device, using |
| 160 | +
|
| 161 | + eventProducts = cms.untracked.vstring( "module" ) |
| 162 | +
|
| 163 | +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. |
| 164 | +To clone only the host product, the branch can be specified explicitly with |
| 165 | +
|
| 166 | + eventProducts = cms.untracked.vstring( "HostProductType_module_*_*" ) |
| 167 | +
|
| 168 | +.)"); |
| 169 | + |
| 170 | + edm::ParameterSetDescription desc; |
| 171 | + desc.add<std::vector<std::string>>("eventProducts", {}) |
| 172 | + ->setComment("List of modules or branches whose event products will be cloned."); |
| 173 | + desc.addUntracked<bool>("verbose", false) |
| 174 | + ->setComment("Print the branch names of the products that will be cloned."); |
| 175 | + descriptions.addWithDefaultLabel(desc); |
| 176 | + } |
| 177 | + |
| 178 | +} // namespace edmtest |
| 179 | + |
| 180 | +#include "FWCore/Framework/interface/MakerMacros.h" |
| 181 | +DEFINE_FWK_MODULE(edmtest::GenericCloner); |
0 commit comments