FindManyInChainP.h
Go to the documentation of this file.
1 /**
2  * @file lardata/Utilities/FindManyInChainP.h
3  * @brief Utility to navigate chains of associations.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date June 26, 2017
6  *
7  * This library is header-only.
8  *
9  */
10 
11 #ifndef LARDATA_UTILITIES_FINDMANYINCHAINP_H
12 #define LARDATA_UTILITIES_FINDMANYINCHAINP_H
13 
14 // framework
17 
18 // C/C++ standard library
19 #include <vector>
20 #include <utility> // std::forward()
21 #include <initializer_list>
22 #include <cstdlib> // std::size_t
23 
24 
25 
26 namespace lar {
27 
28  namespace details {
29 
30  template <typename T, typename R = void>
32 
33  template <typename T, typename R = void>
35 
36  template <typename H, typename R = void>
39 
40  } // namespace details
41 
42 
43  /// Type for default tag in `FindManyInChainP` constructors.
44  struct SameAsDataTag {};
45 
46  /// Value for default tag in `FindManyInChainP` constructors.
48 
49  /**
50  * @brief Query object collecting a list of associated objects.
51  * @tparam Target type of objects to be fetched
52  * @tparam Intermediate types of objects connecting to Target by association
53  *
54  * This query object collects information about all objects of type `Target`
55  * associated to each specified object of type `Source`.
56  * The `Source` type is implicitly specified in the constructor.
57  * For example, each `recob::Shower` object is expected to be associated to
58  * a number of `recob::Cluster` objects, and each one of these clusters must
59  * be associated to `recob::Hit` objects. To retrieve all the hit objects
60  * associated to a shower collection (_not recommended_):
61  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
62  * auto showers = event.getValidHandle<std::vector<recob::Shower>>(showerTag);
63  * lar::FindManyInChainP<recob::Hit, recob::Cluster> showerToHits
64  * (showers, event, showerTag);
65  *
66  * for (std::size_t iShower = 0; iShower < showers.size(); ++iShower) {
67  *
68  * recob::Shower const& shower = (*showers)[iShower];
69  *
70  * decltype(auto) showerHits = showerToHits.at(iShower);
71  *
72  * // ...
73  *
74  * } // for each shower
75  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76  * In this example, it is explicitly stated that the producer of the shower
77  * associations to clusters is the same as the producer of the showers, as the
78  * same input tag `showerTag` is used. It is also implicitly assumed that the
79  * same producer which created the associated clusters is also responsible
80  * for the creation of the associations between clusters and hits.
81  *
82  * The example shows the similarity with `art::FindManyP`. In fact, this
83  * object has a similar interface, and a similar functionality too.
84  * Nevertheless, prefer using the static member `find()` and then using
85  * its result directly, as it has a more complete interface:
86  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
87  * auto showers = event.getValidHandle<std::vector<recob::Shower>>(showerTag);
88  * std::size_t iShower = 0;
89  * for (auto const& showerHits:
90  * lar::FindManyInChainP<recob::Hit, recob::Cluster>
91  * (showers, event, showerTag)
92  * )
93  * {
94  * recob::Shower const& shower = (*showers)[iShower++];
95  * // all associated hits are already in showerHits
96  *
97  * // ...
98  *
99  * } // for each shower
100  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
101  * This is the recommended approach, as long as `lar::FindManyInChainP()` has
102  * to be called only once.
103  *
104  * @note Due to the inability to retrieve provenance information in _gallery_,
105  * this class is not compatible with _gallery_.
106  *
107  */
108  template <typename Target, typename... Intermediate>
110 
111  public:
112  using Target_t = Target; ///< Type of the associated objects.
113  using TargetPtr_t = art::Ptr<Target_t>; ///< Pointer to associated objects.
114 
115 
116  /// Type returned by `at()` method.
117  using TargetPtrCollection_t = std::vector<TargetPtr_t>;
118 
119  /**
120  * @brief Constructor: extracts target objects associated to all objects
121  * under the specified handle.
122  * @tparam Source type of source: art Handle or collection of art pointers
123  * @tparam Event type of event to be used (either _art_ or gallery `Event`)
124  * @tparam InputTags a variable number of `art::InputTag` objects
125  * @param source art Handle or collection of art pointers to source objects
126  * @param event the event to read associations and objects from
127  * @param tags input tags for each one of the required associations
128  * @see find()
129  *
130  * This constructor finds the associated objects as in `find()`, and stored
131  * the result. Access to it will be performed e.g. by the `at()` method.
132  *
133  */
134  template <typename Source, typename Event, typename... InputTags>
135  FindManyInChainP(Source&& source, Event const& event, InputTags... tags)
136  : results(find(std::forward<Source>(source), event, tags...))
137  {}
138 
139 
140 
141  /// Returns the number of `Source` objects we have information about.
142  std::size_t size() const noexcept;
143 
144  /**
145  * @brief Returns all the `Target` objects associated to specified object.
146  * @param i index of the source object to query
147  * @return a sequence of _art_ pointers to the associated `Target` objects
148  * @throw std::out_of_range if the specified index is not valid
149  *
150  * The specified index matches the index of the element in the collection
151  * this query object was constructed with. For example:
152  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
153  * auto showers
154  * = event.getValidHandle<std::vector<recob::Shower>>(showerTag);
155  * lar::FindManyInChainP<recob::Hit, recob::Cluster> showerToHits
156  * (shower, event, showerTag);
157  *
158  * for (std::size_t iShower = 0; iShower < showers.size(); ++iShower) {
159  *
160  * recob::Shower const& shower = (*showers)[iShower];
161  *
162  * decltype(auto) showerHits = showerToHits.at(iShower);
163  *
164  * // ...
165  *
166  * } // for each shower
167  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
168  * the `showerHits` will pertain the `iShower`-th `recob::Shower` (`shower`)
169  * on each iteration of the loop.
170  *
171  * The returned sequence points to objects convertible to _art_ pointers to
172  * `Target` (e.g., `art::Ptr<Target>`). The order of the objects in this
173  * sequence is not defined. The same `Target` object _may_ appear more than
174  * once if two intermediate objects are associated to the same target (or
175  * intermediate object of tier closer to the target).
176  * This sequence is of an unspecified type, guaranteed to support
177  * `std::begin()`, `std::end()`, `size()` method and to be iterable in a
178  * range-for loop.
179  * For example, it may be a STL vector returned by constant reference.
180  */
181  TargetPtrCollection_t const& at(std::size_t i) const;
182 
183 
184  /**
185  * @brief Returns target objects associated to all objects contained in the
186  * specified source.
187  * @tparam Source type of source: art Handle or collection of art pointers
188  * @tparam Event type of event to be used (either _art_ or gallery `Event`)
189  * @tparam InputTags a variable number of `art::InputTag` objects
190  * @param source art Handle or collection of art pointers to source objects
191  * @param event the event to read associations and objects from
192  * @param tags input tags for each one of the required associations
193  * @return collection of lists of pointers to associated objects, one for
194  * each source element, in the same order
195  *
196  * This methods returns a collection with an entry for each of the elements
197  * pointed by the specified handle, in the same order as they are extracted
198  * from the source collection.
199  *
200  * The input tag arguments must be convertible to `art::InputTag` type.
201  * The first tag identifies the data product containing the associations
202  * between the `Source` collection (the same pointed by `source`) and the
203  * first `Intermediate` class. The second tag likewise points to the data
204  * product containing the associations between the first and the second
205  * `Intermediate` classes. The last tag, finally, points to the data product
206  * containing the associations between the last `Intermediate` class and the
207  * `Target` class.
208  * If one tag is not specified, it is assumed that the same class that
209  * produced the `Intermediate` (or `Source`) data product also produced the
210  * association to the next `Intermediate` (or `Target`) data product.
211  * Note that:
212  * * if the tag is specified, _all_ associations are expected to come from
213  * that same tag; if the tag is _not_ specified, elements from different
214  * data products will be assumed to have different association data
215  * products too
216  * * it is possible to "omit" the explicit specification of a tag by using
217  * the `lar::SameAsData` tag
218  *
219  */
220  template <typename Source, typename Event, typename... InputTags>
221  static std::vector<TargetPtrCollection_t> find
222  (Source&& source, Event const& event, InputTags... tags);
223 
224  private:
225  std::vector<TargetPtrCollection_t> results; ///< Stored results.
226 
227  }; // class FindManyInChainP<>
228 
229 
230 } // namespace lar
231 
232 
233 //------------------------------------------------------------------------------
234 //--- template implementation
235 //---
236 #include "FindManyInChainP.tcc" // expected in the same directory as this file
237 
238 //------------------------------------------------------------------------------
239 
240 
241 #endif // LARDATA_UTILITIES_FINDMANYINCHAINP_H
FindManyInChainP(Source &&source, Event const &event, InputTags...tags)
Constructor: extracts target objects associated to all objects under the specified handle...
enable_if_type_exists_t< typename std::decay_t< H >::HandleTag, R > enable_if_is_handle_t
STL namespace.
constexpr SameAsDataTag SameAsData
Value for default tag in FindManyInChainP constructors.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
Type for default tag in FindManyInChainP constructors.
typename enable_if_type_exists< T, R >::type enable_if_type_exists_t
std::vector< TargetPtrCollection_t > results
Stored results.
Query object collecting a list of associated objects.
Target Target_t
Type of the associated objects.
std::vector< TargetPtr_t > TargetPtrCollection_t
Type returned by at() method.
LArSoft-specific namespace.
Definition: types.h:32
Definition: fwd.h:31
Event finding and building.