CMS 3D CMS Logo

ThinningProducer.h
Go to the documentation of this file.
1 #ifndef FWCore_Framework_ThinningProducer_h
2 #define FWCore_Framework_ThinningProducer_h
3 
9 
23 
24 #include <memory>
25 #include <optional>
26 #include <type_traits>
27 
28 namespace edm {
29 
30  class EventSetup;
31 
32  namespace detail {
33  template <typename T>
34  struct IsStdOptional {
35  static constexpr bool value = false;
36  };
37  template <typename T>
38  struct IsStdOptional<std::optional<T>> {
39  static constexpr bool value = true;
40  };
41 
42  template <typename Item, typename Selector, typename Collection>
43  void fillCollectionForThinning(Item const& item,
44  Selector& selector,
45  unsigned int iIndex,
46  Collection& output,
48  using SelectorChooseReturnType = decltype(selector.choose(0U, std::declval<Item const&>()));
50  if constexpr (isSlimming) {
51  std::optional<typename SelectorChooseReturnType::value_type> obj = selector.choose(iIndex, item);
52  if (obj.has_value()) {
53  // move to support std::unique_ptr<T> with edm::OwnVector<T> or std::vector<unique_ptr<T>>
54  output.push_back(std::move(*obj));
55  association.push_back(iIndex);
56  }
57  } else {
58  if (selector.choose(iIndex, item)) {
59  output.push_back(item);
60  association.push_back(iIndex);
61  }
62  }
63  }
64 
65  } // namespace detail
66 
67  template <typename Collection, typename Selector>
69  public:
70  explicit ThinningProducer(ParameterSet const& pset);
71  ~ThinningProducer() override;
72 
73  static void fillDescriptions(ConfigurationDescriptions& descriptions);
74 
75  void produce(Event& event, EventSetup const& eventSetup) override;
76 
77  void registerThinnedAssociations(ProductRegistry const& productRegistry,
78  ThinnedAssociationsHelper& thinnedAssociationsHelper) override;
79 
80  private:
86 
88  decltype(selector_->choose(0U, std::declval<typename detail::ElementType<Collection>::type const>()));
90  static_assert(
91  std::is_same_v<SelectorChooseReturnType, bool> || isSlimming,
92  "Selector::choose() must return bool (for pure thinning) or std::optional<ElementType> (for slimming)");
93  };
94 
95  template <typename Collection, typename Selector>
97  : selector_(new Selector(pset, consumesCollector())) {
98  inputTag_ = pset.getParameter<InputTag>("inputTag");
99  inputToken_ = consumes<Collection>(inputTag_);
100 
101  outputToken_ = produces<Collection>();
102  thinnedOutToken_ = produces<ThinnedAssociation>();
103  }
104 
105  template <typename Collection, typename Selector>
107 
108  template <typename Collection, typename Selector>
111  desc.setComment("Produces thinned collections and associations to them");
112  desc.add<edm::InputTag>("inputTag");
114  descriptions.addWithDefaultLabel(desc);
115  }
116 
117  template <typename Collection, typename Selector>
119  auto inputCollection = event.getHandle(inputToken_);
120 
121  edm::Event const& constEvent = event;
122  selector_->preChoose(inputCollection, constEvent, eventSetup);
123 
124  Collection thinnedCollection;
125  ThinnedAssociation thinnedAssociation;
126 
127  unsigned int iIndex = 0;
128  for (auto iter = inputCollection->begin(), iterEnd = inputCollection->end(); iter != iterEnd; ++iter, ++iIndex) {
129  using namespace detail;
130  fillCollectionForThinning(*iter, *selector_, iIndex, thinnedCollection, thinnedAssociation);
131  }
132  selector_->reset();
133 
134  OrphanHandle<Collection> orphanHandle = event.emplace(outputToken_, std::move(thinnedCollection));
135 
136  thinnedAssociation.setParentCollectionID(inputCollection.id());
137  thinnedAssociation.setThinnedCollectionID(orphanHandle.id());
138  event.emplace(thinnedOutToken_, std::move(thinnedAssociation));
139  }
140 
141  template <typename Collection, typename Selector>
143  ProductRegistry const& productRegistry, ThinnedAssociationsHelper& thinnedAssociationsHelper) {
144  BranchID associationID;
145  BranchID thinnedCollectionID;
146 
147  // If the InputTag does not specify the process name, it is
148  // possible that there will be more than one match found below.
149  // For a particular event only one match is correct and the
150  // others will be false. It even possible for some events one
151  // match is correct and for others another is correct. This is
152  // a side effect of the lookup mechanisms when the process name
153  // is not specified.
154  // When using the registry this generates one would have to
155  // check the ProductIDs in ThinnedAssociation product to get
156  // the correct association. This ambiguity will probably be
157  // rare and possibly never occur in practice.
158  std::vector<BranchID> parentCollectionIDs;
159 
160  ProductRegistry::ProductList const& productList = productRegistry.productList();
161  for (auto const& product : productList) {
162  BranchDescription const& desc = product.second;
163  if (desc.dropped()) {
164  // Dropped branch does not have type information, but they can
165  // be ignored here because all of the parent/thinned/association
166  // branches are expected to be present
167  continue;
168  }
169  if (desc.unwrappedType().typeInfo() == typeid(Collection)) {
170  if (desc.produced() && desc.moduleLabel() == moduleDescription().moduleLabel() &&
171  desc.productInstanceName().empty()) {
172  thinnedCollectionID = desc.branchID();
173  }
174  if (desc.moduleLabel() == inputTag_.label() && desc.productInstanceName() == inputTag_.instance()) {
175  if (inputTag_.willSkipCurrentProcess()) {
176  if (!desc.produced()) {
177  parentCollectionIDs.push_back(desc.branchID());
178  }
179  } else if (inputTag_.process().empty() || inputTag_.process() == desc.processName()) {
180  if (desc.produced()) {
181  parentCollectionIDs.push_back(desc.originalBranchID());
182  } else {
183  parentCollectionIDs.push_back(desc.branchID());
184  }
185  }
186  }
187  }
188  if (desc.produced() && desc.unwrappedType().typeInfo() == typeid(ThinnedAssociation) &&
189  desc.moduleLabel() == moduleDescription().moduleLabel() && desc.productInstanceName().empty()) {
190  associationID = desc.branchID();
191  }
192  }
193  if (parentCollectionIDs.empty()) {
194  // This could happen if the input collection was dropped. Go ahead and add
195  // an entry and let the exception be thrown only if the module is run (when
196  // it cannot find the product).
197  thinnedAssociationsHelper.addAssociation(BranchID(), associationID, thinnedCollectionID, isSlimming);
198  } else {
199  for (auto const& parentCollectionID : parentCollectionIDs) {
200  thinnedAssociationsHelper.addAssociation(parentCollectionID, associationID, thinnedCollectionID, isSlimming);
201  }
202  }
203  }
204 } // namespace edm
205 #endif
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
void setThinnedCollectionID(ProductID const &v)
ProductList const & productList() const
void fillCollectionForThinning(Item const &item, Selector &selector, unsigned int iIndex, Collection &output, ThinnedAssociation &association)
std::string const & instance() const
Definition: InputTag.h:37
std::map< BranchKey, BranchDescription > ProductList
decltype(selector_->choose(0U, std::declval< typename detail::ElementType< Collection >::type const >())) SelectorChooseReturnType
std::string const & label() const
Definition: InputTag.h:36
edm::propagate_const< std::unique_ptr< Selector > > selector_
edm::EDPutTokenT< Collection > outputToken_
typename std::remove_reference< decltype(*std::declval< Collection >().begin())>::type type
std::tuple< layerClusterToCaloParticle, caloParticleToLayerCluster > association
ThinningProducer(ParameterSet const &pset)
edm::EDGetTokenT< Collection > inputToken_
edm::EDPutTokenT< ThinnedAssociation > thinnedOutToken_
optional
Definition: Types.py:198
void produce(Event &event, EventSetup const &eventSetup) override
void addAssociation(BranchID const &, BranchID const &, BranchID const &, bool slimmed)
Definition: value.py:1
ProductID id() const
Functor that operates on <T>
Definition: Selector.h:22
void registerThinnedAssociations(ProductRegistry const &productRegistry, ThinnedAssociationsHelper &thinnedAssociationsHelper) override
void fillPSetDescription(edm::ParameterSetDescription &desc)
void setParentCollectionID(ProductID const &v)
static constexpr bool isSlimming
HLT enums.
bool willSkipCurrentProcess() const
Definition: InputTag.h:42
std::string const & process() const
Definition: InputTag.h:40
static void fillDescriptions(ConfigurationDescriptions &descriptions)
def move(src, dest)
Definition: eostools.py:511
Definition: event.py:1