Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:01:58

0001 #ifndef FWCore_Framework_ThinningProducer_h
0002 #define FWCore_Framework_ThinningProducer_h
0003 
0004 /** \class edm::ThinningProducer
0005 \author W. David Dagenhart, created 11 June 2014
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           // move to support std::unique_ptr<T> with edm::OwnVector<T> or std::vector<unique_ptr<T>>
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   }  // namespace detail
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     // If the InputTag does not specify the process name, it is
0148     // possible that there will be more than one match found below.
0149     // For a particular event only one match is correct and the
0150     // others will be false. It even possible for some events one
0151     // match is correct and for others another is correct. This is
0152     // a side effect of the lookup mechanisms when the process name
0153     // is not specified.
0154     // When using the registry this generates one would have to
0155     // check the ProductIDs in ThinnedAssociation product to get
0156     // the correct association. This ambiguity will probably be
0157     // rare and possibly never occur in practice.
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         // Dropped branch does not have type information, but they can
0165         // be ignored here because all of the parent/thinned/association
0166         // branches are expected to be present
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       // This could happen if the input collection was dropped. Go ahead and add
0195       // an entry and let the exception be thrown only if the module is run (when
0196       // it cannot find the product).
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 }  // namespace edm
0205 #endif