File indexing completed on 2023-03-17 11:01:58
0001 #ifndef FWCore_Framework_ThinningProducer_h
0002 #define FWCore_Framework_ThinningProducer_h
0003
0004
0005
0006
0007
0008 #include "FWCore/Framework/interface/stream/EDProducer.h"
0009
0010 #include "DataFormats/Common/interface/Handle.h"
0011 #include "DataFormats/Common/interface/OrphanHandle.h"
0012 #include "DataFormats/Common/interface/ThinnedAssociation.h"
0013 #include "DataFormats/Common/interface/fillCollectionForThinning.h"
0014 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0015 #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h"
0016 #include "FWCore/Framework/interface/Event.h"
0017 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0018 #include "FWCore/Utilities/interface/EDGetToken.h"
0019 #include "FWCore/Utilities/interface/InputTag.h"
0020 #include "FWCore/Utilities/interface/propagate_const.h"
0021 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0022 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0023
0024 #include <memory>
0025 #include <optional>
0026 #include <type_traits>
0027
0028 namespace edm {
0029
0030 class EventSetup;
0031
0032 namespace detail {
0033 template <typename T>
0034 struct IsStdOptional {
0035 static constexpr bool value = false;
0036 };
0037 template <typename T>
0038 struct IsStdOptional<std::optional<T>> {
0039 static constexpr bool value = true;
0040 };
0041
0042 template <typename Item, typename Selector, typename Collection>
0043 void fillCollectionForThinning(Item const& item,
0044 Selector& selector,
0045 unsigned int iIndex,
0046 Collection& output,
0047 ThinnedAssociation& association) {
0048 using SelectorChooseReturnType = decltype(selector.choose(0U, std::declval<Item const&>()));
0049 constexpr bool isSlimming = detail::IsStdOptional<SelectorChooseReturnType>::value;
0050 if constexpr (isSlimming) {
0051 std::optional<typename SelectorChooseReturnType::value_type> obj = selector.choose(iIndex, item);
0052 if (obj.has_value()) {
0053
0054 output.push_back(std::move(*obj));
0055 association.push_back(iIndex);
0056 }
0057 } else {
0058 if (selector.choose(iIndex, item)) {
0059 output.push_back(item);
0060 association.push_back(iIndex);
0061 }
0062 }
0063 }
0064
0065 }
0066
0067 template <typename Collection, typename Selector>
0068 class ThinningProducer : public stream::EDProducer<> {
0069 public:
0070 explicit ThinningProducer(ParameterSet const& pset);
0071 ~ThinningProducer() override;
0072
0073 static void fillDescriptions(ConfigurationDescriptions& descriptions);
0074
0075 void produce(Event& event, EventSetup const& eventSetup) override;
0076
0077 void registerThinnedAssociations(ProductRegistry const& productRegistry,
0078 ThinnedAssociationsHelper& thinnedAssociationsHelper) override;
0079
0080 private:
0081 edm::propagate_const<std::unique_ptr<Selector>> selector_;
0082 edm::EDGetTokenT<Collection> inputToken_;
0083 edm::InputTag inputTag_;
0084 edm::EDPutTokenT<Collection> outputToken_;
0085 edm::EDPutTokenT<ThinnedAssociation> thinnedOutToken_;
0086
0087 using SelectorChooseReturnType =
0088 decltype(selector_->choose(0U, std::declval<typename detail::ElementType<Collection>::type const>()));
0089 static constexpr bool isSlimming = detail::IsStdOptional<SelectorChooseReturnType>::value;
0090 static_assert(
0091 std::is_same_v<SelectorChooseReturnType, bool> || isSlimming,
0092 "Selector::choose() must return bool (for pure thinning) or std::optional<ElementType> (for slimming)");
0093 };
0094
0095 template <typename Collection, typename Selector>
0096 ThinningProducer<Collection, Selector>::ThinningProducer(ParameterSet const& pset)
0097 : selector_(new Selector(pset, consumesCollector())) {
0098 inputTag_ = pset.getParameter<InputTag>("inputTag");
0099 inputToken_ = consumes<Collection>(inputTag_);
0100
0101 outputToken_ = produces<Collection>();
0102 thinnedOutToken_ = produces<ThinnedAssociation>();
0103 }
0104
0105 template <typename Collection, typename Selector>
0106 ThinningProducer<Collection, Selector>::~ThinningProducer() {}
0107
0108 template <typename Collection, typename Selector>
0109 void ThinningProducer<Collection, Selector>::fillDescriptions(ConfigurationDescriptions& descriptions) {
0110 ParameterSetDescription desc;
0111 desc.setComment("Produces thinned collections and associations to them");
0112 desc.add<edm::InputTag>("inputTag");
0113 Selector::fillPSetDescription(desc);
0114 descriptions.addWithDefaultLabel(desc);
0115 }
0116
0117 template <typename Collection, typename Selector>
0118 void ThinningProducer<Collection, Selector>::produce(Event& event, EventSetup const& eventSetup) {
0119 auto inputCollection = event.getHandle(inputToken_);
0120
0121 edm::Event const& constEvent = event;
0122 selector_->preChoose(inputCollection, constEvent, eventSetup);
0123
0124 Collection thinnedCollection;
0125 ThinnedAssociation thinnedAssociation;
0126
0127 unsigned int iIndex = 0;
0128 for (auto iter = inputCollection->begin(), iterEnd = inputCollection->end(); iter != iterEnd; ++iter, ++iIndex) {
0129 using namespace detail;
0130 fillCollectionForThinning(*iter, *selector_, iIndex, thinnedCollection, thinnedAssociation);
0131 }
0132 selector_->reset();
0133
0134 OrphanHandle<Collection> orphanHandle = event.emplace(outputToken_, std::move(thinnedCollection));
0135
0136 thinnedAssociation.setParentCollectionID(inputCollection.id());
0137 thinnedAssociation.setThinnedCollectionID(orphanHandle.id());
0138 event.emplace(thinnedOutToken_, std::move(thinnedAssociation));
0139 }
0140
0141 template <typename Collection, typename Selector>
0142 void ThinningProducer<Collection, Selector>::registerThinnedAssociations(
0143 ProductRegistry const& productRegistry, ThinnedAssociationsHelper& thinnedAssociationsHelper) {
0144 BranchID associationID;
0145 BranchID thinnedCollectionID;
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158 std::vector<BranchID> parentCollectionIDs;
0159
0160 ProductRegistry::ProductList const& productList = productRegistry.productList();
0161 for (auto const& product : productList) {
0162 BranchDescription const& desc = product.second;
0163 if (desc.dropped()) {
0164
0165
0166
0167 continue;
0168 }
0169 if (desc.unwrappedType().typeInfo() == typeid(Collection)) {
0170 if (desc.produced() && desc.moduleLabel() == moduleDescription().moduleLabel() &&
0171 desc.productInstanceName().empty()) {
0172 thinnedCollectionID = desc.branchID();
0173 }
0174 if (desc.moduleLabel() == inputTag_.label() && desc.productInstanceName() == inputTag_.instance()) {
0175 if (inputTag_.willSkipCurrentProcess()) {
0176 if (!desc.produced()) {
0177 parentCollectionIDs.push_back(desc.branchID());
0178 }
0179 } else if (inputTag_.process().empty() || inputTag_.process() == desc.processName()) {
0180 if (desc.produced()) {
0181 parentCollectionIDs.push_back(desc.originalBranchID());
0182 } else {
0183 parentCollectionIDs.push_back(desc.branchID());
0184 }
0185 }
0186 }
0187 }
0188 if (desc.produced() && desc.unwrappedType().typeInfo() == typeid(ThinnedAssociation) &&
0189 desc.moduleLabel() == moduleDescription().moduleLabel() && desc.productInstanceName().empty()) {
0190 associationID = desc.branchID();
0191 }
0192 }
0193 if (parentCollectionIDs.empty()) {
0194
0195
0196
0197 thinnedAssociationsHelper.addAssociation(BranchID(), associationID, thinnedCollectionID, isSlimming);
0198 } else {
0199 for (auto const& parentCollectionID : parentCollectionIDs) {
0200 thinnedAssociationsHelper.addAssociation(parentCollectionID, associationID, thinnedCollectionID, isSlimming);
0201 }
0202 }
0203 }
0204 }
0205 #endif