Track.h
Go to the documentation of this file.
1 /**
2  * @file lardata/RecoBaseProxy/Track.h
3  * @brief Offers `proxy::Tracks` and `proxy::Track` class for
4  * `recob::Track` access.
5  * @author Gianluca Petrillo (petrillo@fnal.gov)
6  * @date July 27, 2017
7  *
8  */
9 
10 /**
11  * @defgroup LArSoftProxyTracks proxy::Tracks (recob::Track proxy)
12  * @brief Proxy for a `recob::Track` collection.
13  * @ingroup LArSoftProxyReco
14  *
15  *
16  * Track proxies is a way to facilitate the navigation of `recob::Track` data
17  * objects.
18  * The ensemble of fundamental data of a track collection includes:
19  * * the tracks themselves, in a `std::vector<recob::Track>` collection
20  * * the associated hits, in a `art::Assns<recob::Track, recob::Hit>` data
21  * product
22  *
23  * Special customisations are provided for:
24  * * the associated hits (automatically pulled in): the
25  * information is provided with `recob::Hit` tag, with the
26  * dedicated accessor `hits()`, `nHits()` and `hitAtPoint()` of the track
27  * proxy and with `hitPtr()` and `hit()` when accessing a single point
28  * * the track fit information: include it with `withFitHitInfo()`; the
29  * information is provided with `recob::TrackFitHitInfo` tag, with the
30  * dedicated accessor `fitInfoAtPoint()` of the track proxy and with
31  * `fitInfoPtr()` when accessing a single point
32  *
33  * LArSoft prescribes conventions to be followed, which include:
34  * * a track has at least two trajectory points
35  * * for each track, there is one hit per trajectory point
36  * * the association between tracks and hits is created with tracks as first
37  * ("left") element, and hits as second one ("right")
38  * * hits in the association are in a well-defined order: first are the hits of
39  * the first track, sorted in the same way as their trajectory points; then
40  * the second track hits come, likewise; and all tracks follow in order;
41  * this is called the "one-to-many sequential association" requirement
42  * documented in `ProxyBase.h`.
43  *
44  * For track data products respecting this convention, a track proxy provides
45  * an interface to navigate the track information.
46  *
47  * @note The interface is experimental, and it is likely not to include all the
48  * features you may need. If you find a missing feature, or find a use
49  * case violating an assumption, or you find the interface cumbersome to
50  * use, please contact the author for a discussion on how to improve this
51  * utility.
52  *
53  *
54  * Obtaining a track proxy
55  * ========================
56  *
57  * Track proxies are created by specifying the tag of the tracks, and the event
58  * to read them from.
59  *
60  * To create a track proxy:
61  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
62  * auto tracks = proxy::getCollection<proxy::Tracks>(event, tracksTag);
63  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
64  * Here we ask `getCollection()` to create a proxy of category `proxy::Tracks`.
65  * Each proxy is a different beast which needs to be explicitly supported:
66  * here support for the proxy to `recob::Track` is described.
67  *
68  * The additional customizations for track proxy are described above.
69  * For example, if the module with label `fitTag` stored the fit information for
70  * the track, that information can be merged as:
71  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
72  * auto tracks = proxy::getCollection<proxy::Tracks>
73  * (event, tracksTag, withFitHitInfo(fitTag));
74  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75  * while in the more likely case where that information was produced together
76  * with the tracks,
77  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
78  * auto tracks = proxy::getCollection<proxy::Tracks>
79  * (event, tracksTag, withFitHitInfo());
80  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81  * will suffice. After this, the interface specific to `recob::TrackFitHitInfo`
82  * will be available. Otherwise, any attempt to use it will cause (complicate)
83  * compilation errors.
84  *
85  * In addition, any type of data can be associated using the generic collection
86  * proxy interface (`withAssociated()`, `withParallelData()`, etc.).
87  *
88  *
89  * The C++ type of `tracks` object should not matter to the user, and it depends
90  * on which additional data are merged in.
91  *
92  *
93  * Types of proxies, and what to do with them
94  * ===========================================
95  *
96  * Currently there are three different type of proxy-like objects for tracks.
97  * Each one supports a specific concept:
98  *
99  * * `proxy::Tracks` represents the whole collection of tracks; it covers
100  * the tracks themselves, and their associated hits. It is obtained by calling
101  * `getCollection()` as described above.
102  * * `proxy::Track` represents a single track; the list of hits and points,
103  * and of course the `recob::Track` object itself, can be accessed through it.
104  * Track proxies are obtained from a track collection proxy (`proxy::Tracks`).
105  * * `proxy::TrackPoint` represents a single trajectory point in a track.
106  * It provide access to position and momentum of the track at that point,
107  * associated hit and point flags. Track point proxies are obtained from a
108  * track proxy (`proxy::Track`).
109  *
110  * For the details of the interface and the information that is exposed by each
111  * of these proxy classes, please refer to each class documentation. In
112  * particular, see `proxy::Tracks` documentation for more usage examples.
113  *
114  * @note The interface allows by deliberate design only read-only access to the
115  * underlying data.
116  *
117  *
118  * @section LArSoftProxyTracksTech Technical details
119  *
120  * @subsection LArSoftProxyTracksTechDetails Track collection proxy
121  *
122  * The track collection proxy object is derived from
123  * `proxy::CollectionProxyBase`, which points to the original (track) data
124  * product.
125  * In addition, it contains a `proxy::details::AssociatedData` object for
126  * the `recob::Track`--`recob::Hit` association list.
127  *
128  * The `proxy::Tracks` interface is currently quite limited: it only allows to
129  * access a track by index, or to iterate through all of them, in addition to
130  * know how many tracks are available (`size()`).
131  *
132  * The object returned when accessing the single track information,
133  * `proxy::Track`, actually contains enough information so that it is
134  * independent of the track collection proxy. This is derived from the generic
135  * collection element proxy object (`proxy::CollectionProxyElement`).
136  *
137  * The object describing the information of a single point has the interface of
138  * `TrackPointWrapper`. The underlying storage includes pointers to the track,
139  * the associated hit, and the index of the point in the track. This is
140  * track-specific and it is not part of the generic proxy infrastructure.
141  *
142  *
143  * @subsection LArSoftProxyTracksCustom Track proxy as an example of proxy customization
144  *
145  * The proxy utilities provide the basic functionality of the track proxy,
146  * including the track collection proxy, representing all the tracks in the
147  * event, and the track proxy, representing a single track. Access to a third
148  * tier, the single trajectory point, as proxy is not covered by the basic
149  * framework, and it has been implemented here from scratch.
150  *
151  * The most relevant customization pertains proxy to the single track. The proxy
152  * is derived from `proxy::details::CollectionProxyElement` for basic
153  * functionality, which is enriched by a custom interface that does not in fact
154  * add functionality, except for the trajectory point proxy described below.
155  * The customizations are fairly trivial, overlaying user-friendly names on the
156  * existing functionality. A step beyond that is the access to data that might
157  * not be present, that is the fit information. The proxy takes the necessary
158  * steps to determine (statically) whether that information is present, and to
159  * provide a null pointer to the information if that is not the case. This is
160  * a functionality that can't be completely implemented by the basic proxy code,
161  * since that generic code has no clue about what type of null pointer to return
162  * when the tag `Tracks::TrackFitHitInfoTag` is unknown. This information is
163  * provided by the track proxy via the `getIf()` call.
164  * For convenience, `proxy::Track` is defined as alias of this single track
165  * proxy.
166  *
167  * The collection proxy customization is way more straightforward.
168  * A proxy "tag" is defined, `proxy::Tracks`, with the only purpose of
169  * identifying the collection proxy for tracks. For convenience, it hosts a
170  * definition used internally to identify one of the optional auxiliary data,
171  * and the type of the main data product, but both definitions are contingent
172  * and their presence in there is only to centralize some customization in a
173  * single place.
174  * Traits (`CollectionProxyMakerTraits<Tracks>`) are specialized to inform that
175  * this `proxy::Tracks` proxy relies on `std::vector<recob::Track>` as main
176  * data product collection type (`std::vector<recob::Track>` is learned from
177  * `proxy::Tracks`, but again, this is a contingent detail). The only other
178  * customization we need is to have for our proxy our element class above: since
179  * we can use the standard collection base, just with the custom element, we
180  * define `collection_proxy_impl_t` in that way.
181  * Finally, the creation of the collection proxy is customised by specializing
182  * `CollectionProxyMaker` (`CollectionProxyMaker<Tracks>`). That class normally
183  * takes care of creating the whole proxy, and our purpose is to have it always
184  * add the associated hits as auxiliary data, so that the caller does not have
185  * to explicitly use `withAssociated<recob::Hit>()` in `getCollection()`.
186  * The simple customization does exactly that, under the hood.
187  * As candy, some customized functions may be provided for convenience, like
188  * `withFitHitInfo()` as alias of `withAssociated<recob::TrackFitHitInfo>()`.
189  *
190  *
191  * The trajectory point proxy has been implemented from scratch here, and it is
192  * much less refined than the generic proxy code. It is based on a data
193  * structure with a selected list of pointers to the actual data. This structure
194  * is implemented as a `std::tuple`. On top of it, a wrapper provides the
195  * interface (by interface substitution). This choice is non-essential and has
196  * been taken to stress the separation between data storage and interface.
197  * Point data structures are created by the proxy on demand, and they are
198  * designed so that they don't become invalid when the original proxies fall out
199  * of scope, at the price of added memory usage (the minimal information would
200  * be a pointer to the track proxy and a point index).
201  *
202  * Summary of the customization procedure:
203  * -# define the tag to identify the proxy (`proxy::Tracks`)
204  * -# choose what type of object that will be (`proxy::CollectionProxyBase`
205  * should do for most)
206  * -# (_optional_) customize the element type; deriving it from
207  * `proxy::CollectionProxyElement` is recommended
208  * -# define the main data product type (`std::vector<recob::Track>`) and set
209  * the traits of the collection proxy, often deriving them from
210  * `proxy::CollectionProxyMakerTraits` with the main data product type as
211  * template argument is enough; in this example, we specified a collection
212  * proxy object with customized element though
213  * -# customize the creation of the proxy collection, if special logic or
214  * default components are specified for the proxy (here,
215  * `withAssociated<recob::Hit>()`);
216  * in this case, `proxy::CollectionProxyMaker` must be specialized (for
217  * `proxy::Tracks`), and a starting point may be to derive the
218  * specialization from `proxy::CollectionProxyMakerBase` and redefine its
219  * `make()` member
220  *
221  *
222  * @subsection LArSoftProxyTracksOverhead Overhead
223  *
224  * See the notes on @ref LArSoftProxyOverhead "overhead" in `ProxyBase.h`.
225  *
226  *
227  */
228 
229 #ifndef LARDATA_RECOBASEPROXY_TRACK_H
230 #define LARDATA_RECOBASEPROXY_TRACK_H
231 
232 
233 // LArSoft libraries
234 #include "lardata/RecoBaseProxy/ProxyBase.h" // proxy namespace
238 #include "lardataobj/RecoBase/Hit.h"
240 
241 // framework libraries
243 
244 #include <limits>
245 #include <tuple>
246 #include <vector>
247 
248 namespace proxy {
249 
250  //----------------------------------------------------------------------------
251  // forward declarations
252  template <typename TrackProxy>
254 
255  template <typename Data>
257 
258  //----------------------------------------------------------------------------
259  namespace details {
260 
261  template <typename CollProxy>
263 
264  template <typename T>
265  struct isTrackProxy;
266 
267  template <typename Obj>
269 
270  template <typename Data>
271  struct StaticAsserts<TrackPointWrapper<Data>>: public std::true_type {
273 
274  static_assert(sizeof(Wrapper_t) == 1U, "Wrapper carries data!");
275 
276  static_assert(std::is_same<
277  std::decay_t<decltype(std::declval<Wrapper_t>().position())>,
279  >(),
280  "position() is not a recob::Track::Point_t"
281  );
282  static_assert(std::is_same<
283  std::decay_t<decltype(std::declval<Wrapper_t>().momentum())>,
285  >(),
286  "momentum() is not a recob::Track::Vector_t"
287  );
288  static_assert(std::is_same<
289  std::decay_t<decltype(std::declval<Wrapper_t>().flags())>,
291  >(),
292  "flags() is not a recob::Track::PointFlags_t"
293  );
294  static_assert(std::is_same<
295  std::decay_t<decltype(std::declval<Wrapper_t>().hitPtr())>,
297  >(),
298  "hit() is not a art::Ptr<recob::Hit>"
299  );
300  static_assert(std::is_same<
301  std::decay_t<decltype(std::declval<Wrapper_t>().index())>,
302  std::size_t
303  >(),
304  "index() is not a std::size_t"
305  );
306 
307  }; // StaticAsserts<TrackPointWrapper<Data>>
308 
309  } // namespace details
310 
311 
312  //----------------------------------------------------------------------------
313 
314  /**
315  * @brief Proxy tag for a `recob::Track` collection proxy.
316  * @see `proxy::TrackCollectionProxyElement`
317  * @ingroup LArSoftProxyTracks
318  *
319  * This type can be used to get a proxy for `recob::Track` collection:
320  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
321  * auto tracks = proxy::getCollection<proxy::Tracks>(event, tracksTag);
322  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
323  *
324  * An example of usage for a simple track processing loop:
325  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
326  * void MyAnalyzer::analyze(art::Event const& event) {
327  *
328  * auto tracks = proxy::getCollection<proxy::Tracks>
329  * (event, tracksTag, proxy::withFitHitInfo());
330  *
331  * if (tracks.empty()) {
332  * mf::LogVerbatim("TrackProxyTest")
333  * << "No tracks in '" << tracksTag.encode() << "'";
334  * return;
335  * }
336  *
337  * mf::LogVerbatim("TrackProxyTest") << "Collection '" << tracksTag.encode()
338  * << "' contains " << tracks.size() << " tracks.";
339  *
340  * for (auto track: tracks) {
341  *
342  * recob::Track const& trackRef = track.track();
343  *
344  * mf::LogVerbatim log("TrackProxyTest");
345  * log << "[#" << track.index() << "] track " << trackRef
346  * << "\n with " << trackRef.NPoints() << " points and "
347  * << track.nHits() << " hits:";
348  *
349  * for (auto const& point: track.points()) {
350  * log <<
351  * "\n [#" << point.index() << "] at " << point.position()
352  * << " (momentum: " << point.momentum() << "), flags: "
353  * << point.flags();
354  *
355  * recob::Hit const* hit = point.hit();
356  * if (hit) {
357  * log << " with a Q=" << hit->Integral() << " hit on channel "
358  * << hit->Channel() << " at tick " << hit->PeakTime()
359  * << ", measured: " << point.fitInfoPtr()->hitMeas();
360  * }
361  * else
362  * log << " (no associated hit)";
363  *
364  * } // for points in track
365  *
366  * } // for track
367  *
368  * } // MyAnalyzer::analyze()
369  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
370  * In this example, the track proxy accesses the track itself, its associated
371  * hits (always implicitly present) and the track fit hit information
372  * (explicitly requested). Since both those data products are produced by the
373  * same module as the track, there is no need to specify their producer module
374  * label.
375  *
376  * Unfortunately, the proxy object (`tracks` in the example) can be of a
377  * different class depending on which data is merged into it: a proxy created
378  * by `getCollection<proxy::Tracks>(event, tag, proxy::withFitHitInfo())` has
379  * different type than e.g. `getCollection<proxy::Tracks>(event, tag)`.
380  * This implies than when passing proxies as arguments to functions, template
381  * types must be used. For example, the following code is equivalent to the
382  * one above, but with methods processing a single track (a track proxy) and
383  * a single trajectory point (a track point proxy):
384  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
385  * template <typename TrackPoint>
386  * void MyAnalyzer::processPoint(TrackPoint const& point) const {
387  *
388  * mf::LogVerbatim log("TrackProxyTest");
389  * log <<
390  * " [#" << point.index() << "] at " << point.position()
391  * << " (momentum: " << point.momentum() << "), flags: "
392  * << point.flags();
393  *
394  * recob::Hit const* hit = point.hit();
395  * if (hit) {
396  * log << " with a Q=" << hit->Integral() << " hit on channel "
397  * << hit->Channel() << " at tick " << hit->PeakTime()
398  * << ", measured: " << point.fitInfoPtr()->hitMeas();
399  * }
400  * else
401  * log << " (no associated hit)";
402  *
403  * } // MyAnalyzer::processPoint()
404  *
405  *
406  * //------------------------------------------------------------------------------
407  * template <typename Track>
408  * void MyAnalyzer::processTrack(Track const& track) const {
409  *
410  * recob::Track const& trackRef = track.track();
411  *
412  * mf::LogVerbatim("TrackProxyTest")
413  * << "[#" << track.index() << "] track " << trackRef
414  * << "\n with " << trackRef.NPoints() << " points and " << track.nHits()
415  * << " hits:";
416  *
417  * for (auto point: track.points()) {
418  * processPoint(point);
419  * } // for points in track
420  *
421  * } // MyAnalyzer::processTrack()
422  *
423  *
424  * //------------------------------------------------------------------------------
425  * void MyAnalyzer::proxyUsageExample(art::Event const& event) {
426  *
427  * auto tracks = proxy::getCollection<proxy::Tracks>
428  * (event, tracksTag, proxy::withFitHitInfo());
429  *
430  * if (tracks.empty()) {
431  * mf::LogVerbatim("TrackProxyTest") << "No tracks in '"
432  * << tracksTag.encode() << "'";
433  * return;
434  * }
435  *
436  * mf::LogVerbatim("TrackProxyTest") << "Collection '" << tracksTag.encode()
437  * << "' contains " << tracks.size() << " tracks.";
438  *
439  * for (auto track: tracks) {
440  *
441  * processTrack(track);
442  *
443  * } // for track
444  *
445  * } // MyAnalyzer::proxyUsageExample()
446  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
447  *
448  * As any other proxy object, other data can be merged to the proxy, but no
449  * custom interface will be available. For example:
450  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
451  * auto tracks = proxy::getCollection<proxy::Tracks>(
452  * event, tracksTag,
453  * proxy::withParallelData<recob::TrackMomentumFit>(momTag)
454  * );
455  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
456  * will add a data product `std::vector<recob::TrackMomentumFit>` expected to
457  * have one element (of type `recob::TrackMomentumFit`) per track, which will
458  * be accessed with the generic proxy interface:
459  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
460  * for (auto track: tracks) {
461  * recob::TrackMomentumFit const& momFit
462  * = track.get<recob::TrackMomentumFit>();
463  * // ...
464  * }
465  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466  * The other common features of proxy collections are supported, like tagging
467  * of different instances of the same data types:
468  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
469  * struct MCS {};
470  * struct Range {};
471  * auto tracks = proxy::getCollection<proxy::Tracks>(
472  * event, tracksTag,
473  * proxy::withParallelDataAs<recob::TrackMomentumFit, Range>(rangeMomTag),
474  * proxy::withParallelDataAs<recob::TrackMomentumFit, MCS>(MCStag)
475  * );
476  * for (auto track: tracks) {
477  * recob::TrackMomentumFit const& rangeMom = track.get<Range>();
478  * recob::TrackMomentumFit const& MCSmom = track.get<MCS>();
479  * // ...
480  * }
481  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
482  *
483  * A new, filtered collection of proxies can be created with obvious means and
484  * with a less-than-friendly declaration:
485  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
486  * std::vector<decltype(tracks)::element_proxy_t> longTracks;
487  * for (auto track: tracks) {
488  * if (track->Length() >= 30.0) longTracks.push_back(track);
489  * }
490  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
491  * The collection thus created (`longTracks`) is valid also after the
492  * collection proxy (`tracks`) has fallen out of scope.
493  *
494  *
495  * @note `proxy::Tracks` is *not* the type of the collection proxy returned
496  * by `getCollection()`.
497  */
498  struct Tracks {
499 
500  /// Type of the main collection.
501  using TrackDataProduct_t = std::vector<recob::Track>;
502 
503  /// Tag used for the "standard" track trajectory information.
505 
506  /// Tag used for the "standard" track fit information.
508 
509  /// Tag used for the associated hits.
511 
512  /// Types of tracks and trajectories.
513  typedef enum {
514  Unfitted, ///< Represents a track trajectory before the final fit.
515  Fitted, ///< Represents a track trajectory from the final fit.
516  NTypes ///< Number of supported track types.
517  } TrackType_t;
518 
519  }; // struct Tracks
520 
521 
522 
523  //----------------------------------------------------------------------------
524  //--- track point information
525  //---
526  /**
527  * @brief Container of track point information.
528  * @see `proxy::Track`, `proxy::TrackPointWrapper`
529  * @ingroup LArSoftProxyTracks
530  *
531  * This class contains some information pertaining a single point of a
532  * `recob::Track`.
533  *
534  * The information is not extensible via the usual proxy mechanisms. The data
535  * supported is stored in `proxy::TrackPointData` class, and it currently
536  * includes:
537  * * the `recob::Track` the point belongs to
538  * * the position, momentum and flags of the point
539  * * the hit associated to the point
540  * * the index of the point in its track
541  * * fit information
542  *
543  * The access interface is determined by `proxy::TrackPointWrapper`.
544  *
545  * An object of this type is returned when accessing a single track point from
546  * a track proxy. While the data itself is not copied, this object owns some
547  * pointers to the actual data, and once created it is independent of the
548  * track proxy which created it.
549  *
550  */
551  using TrackPointData = std::tuple<
552  recob::Track const*,
554  recob::TrackFitHitInfo const*,
555  std::size_t
556  >;
557 
558  /**
559  * @brief Wrapper for a track data proxy.
560  * @tparam Data the point data type; requirements are described below
561  * @ingroup LArSoftProxyTracks
562  *
563  * This class provides a user interface to data pertaining a single trajectory
564  * point of a `recob::Track`.
565  *
566  *
567  * Implementation details
568  * -----------------------
569  *
570  * This type wraps a generic data structure with tuple interface.
571  * It is expected that the following information is returned:
572  *
573  * * pointer to point position as `recob::Track::Point_t` from
574  * `std::get<0>(Data const&)`
575  * * pointer to momentum at point as `recob::Track::Vector_t` from
576  * `std::get<1>(Data const&)`
577  * * pointer to flags as `recob::Track::PointFlags_t` from
578  * `std::get<2>(Data const&)`
579  * * pointer to associated hit as `art::Ptr<recob::Hit>` from
580  * `std::get<3>(Data const&)`
581  *
582  * The "pointers" can be any object returning the required type when
583  * dereferenced.
584  *
585  */
586  template <typename Data>
587  class TrackPointWrapper {
589  using Wrapped_t = std::add_const_t<Data>;
590 
591  static constexpr std::size_t TrackIndex = 0;
592  static constexpr std::size_t HitIndex = 1;
593  static constexpr std::size_t FitHitInfoIndex = 2;
594  static constexpr std::size_t IndexIndex = 3;
595  static constexpr std::size_t NIndices = 4;
596 
597  static_assert(std::tuple_size<Data>::value == NIndices,
598  "Unexpected data size.");
599 
600  Wrapped_t const& base() const
601  { return reinterpret_cast<Wrapped_t const&>(*this); }
602 
603  template <std::size_t N>
604  auto get() const -> decltype(auto) { return std::get<N>(base()); }
605 
606  protected:
607  TrackPointWrapper() = default;
608  TrackPointWrapper(TrackPointWrapper const&) = default;
610  TrackPointWrapper& operator=(TrackPointWrapper const&) = default;
611  TrackPointWrapper& operator=(TrackPointWrapper&&) = default;
612 
613  public:
614 
615  /// Returns the track this point belongs to.
616  recob::Track const& track() const
617  { return *get<TrackIndex>(); }
618 
619  /// Returns the position of the trajectory point.
620  /// @see `recob::Track::LocationAtPoint()`
621  auto position() const -> decltype(auto)
622  { return track().Trajectory().LocationAtPoint(index()); }
623 
624  /// Returns the momentum vector of the trajectory point.
625  /// @see `recob::Track::MomentumVectorAtPoint()`
626  auto momentum() const -> decltype(auto)
627  { return track().Trajectory().MomentumVectorAtPoint(index()); }
628 
629  /**
630  * @{
631  * @name Flags interface
632  */
633 
634  /// Returns the flags associated with the trajectory point.
635  /// @see `recob::Track::FlagsAtPoint()`
636  auto flags() const -> decltype(auto)
637  { return track().Trajectory().FlagsAtPoint(index()); }
638 
639  /**
640  * @brief Returns whether the trajectory point is valid.
641  *
642  * Even if the trajectory point (position and momentum) are not valid,
643  * the hit is still associated to the track/tracjectory.
644  */
645  bool isPointValid() const { return flags().isPointValid(); }
646 
647  /// @}
648 
649  /**
650  * @brief Returns the hit associated with the trajectory point.
651  * @return an _art_ pointer to the hit associated to this point
652  */
653  art::Ptr<recob::Hit> hitPtr() const { return get<HitIndex>(); }
654 
655  /**
656  * @brief Returns fit info associated with the trajectory point.
657  * @return a pointer to the fit info, or `nullptr` if not merged in proxy
658  *
659  * If the track proxy this point comes from had no fit information,
660  * `nullptr` is returned.
661  * The fit information is extracted using the tag in
662  * `proxy::Tracks::TrackFitHitInfoTag`.
663  */
664  recob::TrackFitHitInfo const* fitInfoPtr() const
665  { return get<FitHitInfoIndex>(); }
666 
667  /// Returns the index of this point in the trajectory.
668  auto index() const -> decltype(auto) { return get<IndexIndex >(); }
669 
670  /// Returns a pointer to the hit on the trajectory point, if any.
671  recob::Hit const* hit() const
672  { decltype(auto) ptr = hitPtr(); return ptr? ptr.get(): nullptr; }
673 
674  }; // TrackPointWrapper<>
675 
676 
677  /**
678  * @brief Type of track point information.
679  * @ingroup LArSoftProxyTracks
680  * @see `proxy::TrackPointWrapper`
681  *
682  * For its interface, see `proxy::TrackPointWrapper`.
683  */
684  struct TrackPoint
685  : private TrackPointData
686  , public TrackPointWrapper<TrackPointData>
687  {
691 
692  private:
693  static constexpr bool asserts
695  }; // class TrackPoint
696 
697 
698  /**
699  * @brief Returns an object with information about the specified track point.
700  * @tparam TrackProxy an instance of proxy::Track template
701  * @param track the track (proxy) the points belong to
702  * @param index the index of the point within the track
703  * @return a `TrackPointData` object with information on that point
704  *
705  * For an interface to the point information, see `TrackPointWrapper`.
706  */
707  template <typename TrackProxy>
709  (TrackProxy const& track, std::size_t index)
710  {
711  static_assert(details::isTrackProxy<TrackProxy>(), "Not a proxy::Track!");
712  return {
713  &(track.track()),
714  track.hitAtPoint(index),
715  track.fitInfoAtPoint(index),
716  index
717  };
718  } // makeTrackPointData()
719 
720 
721  //--------------------------------------------------------------------------
722  /**
723  * @brief Class for track proxy elements.
724  * @tparam CollProxy type of track proxy collection to get data from
725  * @see `proxy::TrackPoint`, `proxy::TrackPointWrapper`
726  * @ingroup LArSoftProxyTracks
727  *
728  * For details on the track point interface see `proxy::TrackPoint`.
729  */
730  template <typename CollProxy>
732  : public CollectionProxyElement<CollProxy>
733  {
734  using base_t = CollectionProxyElement<CollProxy>; ///< Base type.
735  using base_t::base_t; // inherit constructors
736 
737  /// This type.
739 
740  public:
741  /// Iterator for trajectory point information.
743 
744  /// Returns the pointed track.
745  recob::Track const& track() const { return base_t::operator*(); }
746 
747  /**
748  * @brief Returns the requested trajectory from the proxy.
749  * @param type type of the track trajectory to be returned
750  * @return a reference to the requested track trajectory
751  *
752  */
753  recob::TrackTrajectory const* operator()
754  (proxy::Tracks::TrackType_t type) const noexcept;
755 
756  // --- BEGIN Direct hit interface ------------------------------------------
757  /**
758  * @name Direct hit interface.
759  *
760  * The track prescription requires one hit per trajectory point.
761  *
762  * @note Remember that in particular cases there might be a hit without
763  * point of vice versa. In those cases, the point will have a dummy
764  * value, or the hit pointer will have `isNull()` true. In the former
765  * case, the point flag `isPointValid()` should be unset.
766  *
767  * The interface at track proxy level allows for both access to the whole
768  * sequence of hits, or to the hit of a specific point:
769  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
770  * assert(track.nHits() > 0);
771  * auto const& hits = track.hits();
772  * art::Ptr<recob::Hit> maxHit = hits[0]; // direct access
773  * for (art::Ptr<recob::Hit> const& hit: hits) {
774  * if (hit.isNull()) continue;
775  * if (maxHit.isNull() || maxHit->Charge() < hit->Charge())
776  * maxHit = hit;
777  * } // for
778  *
779  * art::Ptr<recob::Hit> lastHit = track.hitAtPoint(track.nHits() - 1U);
780  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
781  */
782  /// @{
783 
784  /**
785  * @brief Returns a collection-like range of hits of this track, at point
786  * order.
787  * @return a range of _art_ pointers to hits
788  *
789  * One hit is expected per trajectory point. Hits can be missing, in which
790  * case the art pointer will have `isNull()` as `true`.
791  */
792  auto hits() const -> decltype(auto)
793  { return base_t::template get<Tracks::HitTag>(); }
794 
795  /// Returns an art pointer to the hit associated with the specified point.
796  auto hitAtPoint(std::size_t index) const -> decltype(auto)
797  { return hits()[index]; }
798 
799  /// Returns the number of hits associated with this track.
800  std::size_t nHits() const { return hits().size(); }
801 
802  /// @}
803  // --- END Direct hit interface --------------------------------------------
804 
805 
806  /// Returns fit info for the specified point (`nullptr` if not available).
807  recob::TrackFitHitInfo const* fitInfoAtPoint(std::size_t index) const;
808 
809 
810  // --- BEGIN Direct track trajectory interface -----------------------------
811  /**
812  * @name Direct track trajectory interface
813  * @see `proxy::TrackPoint`
814  *
815  * The interface allows to check if this track has a trajectory associated
816  * with it, and to obtain a reference to it or its _art_ pointer.
817  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
818  * bool hasTraj = proxy.hasOriginalTrajectory();
819  * if (hasTraj) {
820  * recob::TrackTrajectory const& trajectory = proxy.originalTrajectory();
821  * // ...
822  * }
823  * art::Ptr<recob::TrackTrajectory> const& trajectoryPtr
824  * = proxy.originalTrajectoryPtr();
825  * if (!trajectoryPtr.isNull()) {
826  * recob::TrackTrajectory const& trajectory = *trajectoryPtr;
827  * // ...
828  * }
829  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
830  *
831  * @note This interface can't be used if the track trajectory information
832  * has not been merged into the proxy (typically via
833  * `proxy::withOriginalTrajectory()`).
834  */
835  /// @{
836 
837  /// Returns whether this track is associated to a trajectory.
839  { return !originalTrajectoryPtr().isNull(); }
840 
841  /// Returns an _art_ pointer to the associated trajectory.
842  /// @return pointer to the associated trajectory (`isNull()` `true` if none)
844  { return base_t::template get<Tracks::TrackTrajectoryTag>(); }
845 
846  /**
847  * @brief Returns a reference to the associated trajectory.
848  * @return the associated trajectory as a constant reference
849  * @see `originalTrajectoryPtr()`, `hasOriginalTrajectory()`
850  *
851  * If the track is not associated to any trajectory, the return value is
852  * undefined. This condition should be checked beforehand, e.g. with
853  * `hasTrajectory()`.
854  */
856  { return *originalTrajectoryPtr(); }
857 
858  /// @}
859  // --- END Direct track trajectory interface -------------------------------
860 
861 
862  // --- BEGIN Point-by-point iteration interface ----------------------------
863  /**
864  * @name Point-by-point iteration interface
865  *
866  * The points on track can be accessed individually with a special,
867  * non-extensible proxy.
868  *
869  * In this example, points are accessed via iteration:
870  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
871  * unsigned int nPoints = track.nPoints();
872  * unsigned int nValidHits = 0;
873  * for (auto point: track.points()) {
874  * if (!point.hit().isNull()) ++nValidHits;
875  * }
876  * unsigned int nValidPoints = std::count_if
877  * (track.beginPoint(), track.endPoint(), &TrackPoint::isPointValid);
878  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
879  * Random (index-based) access is also available:
880  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
881  * if (track.nPoints() > 1) {
882  * auto point = track.point(1); // or track[1]
883  * // ...
884  * }
885  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
886  */
887  /// @{
888 
889  /**
890  * @brief Returns an iterable range with point-by-point information.
891  * @see `proxy::TrackPoint`, `proxy::TrackPointWrapper`
892  *
893  * The interface of the elements is documented in `TrackPointWrapper`.
894  * Example:
895  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
896  * for (auto const& pointInfo: track.points()) {
897  *
898  * if (!pointInfo.flags().isPointValid()) continue;
899  *
900  * auto const& pos = pointInfo.position();
901  *
902  * // ...
903  *
904  * } // for point
905  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
906  * will iterate through all points (including the invalid ones, hence the
907  * check).
908  */
909  auto points() const
911 
912  /**
913  * @brief Returns an iterable range with only points matching the `mask`.
914  * @tparam Pred type of predicate to test on points
915  * @param pred predicate to be fulfilled by the points
916  * @return an object that can be forward-iterated
917  * @see `points()`, `pointsWithFlags()`
918  *
919  * This methods is used in a way similar to `points()`, with the addition of
920  * specifying a criterium (predicate) defining the selected points.
921  * The iteration will happen only through the points which fulfil the
922  * predicate.
923  *
924  * The interface of the elements is documented in `TrackPointWrapper`.
925  * Example:
926  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
927  * auto farPoints = [](auto const& pointInfo)
928  * { return pointInfo.isPointValid() && pointInfo.position().Z() > 50.; };
929  * for (auto const& pointInfo: track.selectPoints(farPoints)) {
930  *
931  * auto const& pos = pointInfo.position();
932  *
933  * // ...
934  *
935  * } // for point
936  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
937  * will iterate through all points which are valid and whose position is
938  * at _z_ absolute coordinate larger than 50 centimeters (whatever it
939  * means).
940  *
941  *
942  * Requirements
943  * -------------
944  *
945  * * `Pred` is a unary function object which can accept a `TrackPoint`
946  * object as its sole argument and which returns a value convertible to
947  * `bool`
948  *
949  */
950  template <typename Pred>
951  auto selectPoints(Pred&& pred) const;
952 
953  /**
954  * @brief Returns an iterable range with only points matching the `mask`.
955  * @param mask point flag mask to be matched
956  * @return an object that can be forward-iterated
957  * @see `points()`, `util::flags::BitMask::match()`
958  *
959  * This methods is used in a way similar to `points()`, with the addition of
960  * specifying a `mask` of flags. The iteration will happen only through the
961  * points which match the mask. that is for which
962  * `pointInfo.flags().match(mask)` is `true`.
963  *
964  * The interface of the elements is documented in `TrackPointWrapper`.
965  * Example:
966  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
967  * for (auto const& pointInfo
968  * : track.pointsWithFlags(-recob::TrajectoryPointFlags::flag::NoPoint)
969  * )
970  * {
971  *
972  * auto const& pos = pointInfo.position();
973  *
974  * // ...
975  *
976  * } // for point
977  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
978  * will iterate through only the points which _do not_ have the `NoPoint`
979  * flag set (which have in fact a valid position).
980  */
981  auto pointsWithFlags
983 
984  /// Returns the number of trajectory points in the track.
985  std::size_t nPoints() const { return track().NPoints(); }
986 
987  /// Returns the iterator to the data of the first point.
988  point_iterator beginPoint() const { return { *this, 0 }; }
989 
990  /// Returns the iterator past the last point.
991  point_iterator endPoint() const { return { *this, nPoints() }; }
992 
993  /// @{
994  /// Extracts information from the specified point.
995  TrackPoint point(std::size_t index) const
996  { return { makeTrackPointData(track(), index) }; }
997 
998  TrackPoint operator[](std::size_t index) const
999  { return point(index); }
1000 
1001  /// @}
1002  // --- END Point-by-point iteration interface ------------------------------
1003 
1004 
1005  // --- BEGIN Additional utilities ------------------------------------------
1006  /// @name Additional utilities
1007  /// @{
1008 
1009 
1010  /// @}
1011  // --- END Additional utilities --------------------------------------------
1012 
1013  private:
1015  { return hasOriginalTrajectory()? &originalTrajectory(): nullptr; }
1016 
1017  }; // TrackCollectionProxyElement<>
1018 
1019 
1020  /**
1021  * @brief Proxy to an element of a proxy collection of `recob::Track` objects.
1022  * @tparam TrackCollProxy type of the track collection proxy
1023  * @ingroup LArSoftProxyTracks
1024  *
1025  * This class is the proxy equivalent of `recob::Track`, which exposes data
1026  * associated with the track.
1027  * An object of this type is returned when accessing a single track from a
1028  * track collection proxy. While the data itself is not copied, this object
1029  * owns some pointers to the actual data, and once created it is independent
1030  * of the track collection proxy which created it.
1031  *
1032  * The interface is currently defined by
1033  * `proxy::TrackCollectionProxyElement`.
1034  */
1035  template <typename TrackCollProxy>
1037 
1038 
1039 
1040  // --- BEGIN Auxiliary data --------------------------------------------------
1041  /**
1042  * @name Auxiliary data
1043  *
1044  * These functions may be used as arguments to
1045  * `proxy::getCollection<proxy::Tracks>()` call to
1046  * @ref LArSoftProxyDefinitionMerging "merge" of some data associated to the
1047  * tracks.
1048  *
1049  * @{
1050  */
1051 
1052  /**
1053  * @brief Adds `recob::TrackTrajectory` information to the proxy.
1054  * @param inputTag the data product label to read the data from
1055  * @return an object driving `getCollection()` to use `recob::TrackTrajectory`
1056  * @ingroup LArSoftProxyTracks
1057  * @see `proxy::withOriginalTrajectory()`,
1058  * `proxy::Tracks`, `proxy::getCollection()`
1059  *
1060  * The behaviour of this function is like `withOriginalTrajectory()`, but
1061  * reading the original trajectories from the association with the specified
1062  * label rather than the label of the tracks in the proxy.
1063  */
1064  inline auto withOriginalTrajectory(art::InputTag const& inputTag)
1065  {
1066  return proxy::withZeroOrOneAs
1068  }
1069 
1070  /**
1071  * @brief Adds `recob::TrackTrajectory` information to the proxy.
1072  * @return an object driving `getCollection()` to use `recob::TrackTrajectory`
1073  * @ingroup LArSoftProxyTracks
1074  * @see `proxy::withOriginalTrajectory(art::InputTag const&)`,
1075  * `proxy::Tracks`,
1076  * `proxy::TrackCollectionProxyElement::hasOriginalTrajectory()`,
1077  * `proxy::TrackCollectionProxyElement::originalTrajectory()`,
1078  * `proxy::TrackCollectionProxyElement::originalTrajectoryPtr()`
1079  *
1080  * The information from the associated trajectories is merged in the proxy.
1081  * That association data product must have the same input tag as the track
1082  * collection data product. To specify a different one, use
1083  * `withOriginalTrajectory(art::InputTag const&)`.
1084  *
1085  * The data is available through the regular interface via tag
1086  * `recob::TrackTrajectory`, or via custom interface, e.g.:
1087  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
1088  * auto tracks = proxy::getCollection<proxy::Tracks>
1089  * (event, tracksTag, proxy::withOriginalTrajectory());
1090  *
1091  * for (auto const& trackProxy: tracks) {
1092  *
1093  * if (!trackProxy.hasOriginalTrajectory()) continue;
1094  *
1095  * const auto& track = *trackProxy;
1096  * recob::TrackTrajectory const& original = trackProxy.originalTrajectory();
1097  * recob::TrackTrajectory const& fitted = track.Trajectory();
1098  *
1099  * // ...
1100  *
1101  * } // for tracks
1102  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1103  * Note the subtle difference between the two inner lines: `trackProxy` is a
1104  * track proxy, and the first line is accessing its interface. The second line
1105  * is talking to the track object (`recob::Track`, actually) directly. The
1106  * same effect is obtained using directly the proxy, but with the indirection
1107  * operator (`->`) instead of the member operator (`.`):
1108  * `trackProxy->Trajectory()`.
1109  *
1110  * The `recob::TrackTrajectory` information is required to be from a _art_
1111  * association with `recob::Track`. The association must fulfil the
1112  * @ref LArSoftProxyDefinitionOneToZeroOrOneSeqAssn "one-to-(zero-or-one) sequential association"
1113  * requirements.
1114  */
1116  {
1117  return proxy::withZeroOrOneAs
1119  }
1120 
1121  //----------------------------------------------------------------------------
1122  /**
1123  * @brief Adds `recob::TrackFitHitInfo` information to the proxy.
1124  * @param inputTag the data product label to read the data from
1125  * @return an object driving `getCollection()` to use `recob::TrackFitHitInfo`
1126  * @ingroup LArSoftProxyTracks
1127  * @see `proxy::Tracks`, `proxy::getCollection()`, `proxy::withFitHitInfo()`
1128  *
1129  * This function behaves like `withFitHitInfo()`, but allows to use `inputTag`
1130  * as input tag, instead of the same label as for the track collection.
1131  * See `proxy::withFitHitInfo()` for explanations and examples.
1132  */
1133  inline auto withFitHitInfo(art::InputTag const& inputTag)
1134  {
1136  <std::vector<recob::TrackFitHitInfo>, Tracks::TrackFitHitInfoTag>
1137  (inputTag);
1138  }
1139 
1140  /**
1141  * @brief Adds `recob::TrackFitHitInfo` information to the proxy.
1142  * @return an object driving `getCollection()` to use `recob::TrackFitHitInfo`
1143  * @ingroup LArSoftProxyTracks
1144  * @see `proxy::withFitHitInfo(art::InputTag const&)`,
1145  * `proxy::Tracks`, `proxy::getCollection()`
1146  *
1147  * A `recob::TrackFitHitInfo`data product is read from the event and merged
1148  * into the proxy being created by `proxy::getCollection()`.
1149  * The data product has the same input tag as the track data product; if a
1150  * different one is needed, use `proxy::withFitHitInfo(art::InputTag const&)`
1151  * instead.
1152  *
1153  * Example of usage (more can be found in `TrackProxyTest::testTracks()`):
1154  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
1155  * auto tracks = proxy::getCollection<proxy::Tracks>
1156  * (event, tracksTag, proxy::withFitHitInfo());
1157  *
1158  * for (auto const& trackInfo: tracks) {
1159  *
1160  * for (auto const& point: track.points()) {
1161  *
1162  * auto const& pos = point.position();
1163  * auto const* hit = point.hit();
1164  * auto const* fitInfo = point.fitInfoPtr();
1165  *
1166  * // ...
1167  *
1168  * } // for point
1169  *
1170  * } // for tracks
1171  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1172  * The proxy helps associating the right set of `recob::TrackFitHitInfo` for
1173  * each `track` in the outer loop (not shown in the example: it might have
1174  * looked like `auto const& fitInfo = tracks.get<recob::TrackFitHitInfo>()`).
1175  * It also helps to pick the fit information of the current `point` in the
1176  * inner loop of the example (`fitInfo` will never be `nullptr` here, since
1177  * we _did_ merge the fit information).
1178  *
1179  * The collection of `recob::TrackFitHitInfo` is required to be a
1180  * `std::vector<std::vector<recob::TrackFitHitInfo>>`, where the first index
1181  * addresses which track the information is about, and the second index which
1182  * point within that track.
1183  *
1184  * The data is also available through the regular interface via tag
1185  * `recob::TrackFitHitInfo`.
1186  *
1187  * The data must satisfy the
1188  * @ref LArSoftProxyDefinitionParallelData "parallel data product"
1189  * requirement.
1190  */
1191  inline auto withFitHitInfo()
1192  {
1194  <std::vector<recob::TrackFitHitInfo>, Tracks::TrackFitHitInfoTag>();
1195  }
1196 
1197  /// @}
1198  // --- END Auxiliary data ----------------------------------------------------
1199 
1200  //----------------------------------------------------------------------------
1201  /// Define the traits of `proxy::Tracks` proxy.
1202  template <>
1204  : public CollectionProxyMakerTraits<Tracks::TrackDataProduct_t>
1205  {
1206  // default traits, plus a collection proxy class with a custom element:
1207  template <typename MainColl, typename... AuxColl>
1209  = CollectionProxyBase<Track, MainColl, AuxColl...>;
1210  };
1211 
1212 
1213  //----------------------------------------------------------------------------
1214  /// Specialization to create a proxy for `recob::Track` collection.
1215  template <>
1217  : public CollectionProxyMakerBase<Tracks>
1218  {
1219 
1220  /// Base class.
1222 
1223  /**
1224  * @brief Creates and returns a collection proxy for `recob::Track` based on
1225  * `proxy::Tracks` tag and with the requested associated data.
1226  * @tparam Event type of the event to read the information from
1227  * @tparam WithArgs type of arguments for associated data
1228  * @param event event to read the information from
1229  * @param tag input tag of the `recob::Track` collection data product
1230  * @param withArgs optional associated objects to be included
1231  * @return a collection proxy to `recob::Track` collection with `tag`
1232  *
1233  * For each argument in `withArgs`, an action is taken. Usually that is to
1234  * add an association to the proxy.
1235  * Associated hits (tag: `recob::Hit`) are automatically added to the proxy
1236  * and must not be explicitly specified.
1237  */
1238  template <typename Event, typename... WithArgs>
1239  static auto make
1240  (Event const& event, art::InputTag const& tag, WithArgs&&... withArgs)
1241  {
1242  // automatically add associated hits with the same input tag;
1243  // IDEA: allow a withAssociated<recob::Hit>() from withArgs to override
1244  // this one; the pattern may be:
1245  // - if withArgs contains a withAssociated<recob::Hit>(), produce a new
1246  // withArgs with that one pushed first
1247  // - otherwise, produce a new withArgs with a new
1248  // withAssociated<recob::Hit>(tag) as first element
1249  // In principle there is no need for these hits to be first; code might
1250  // be simpler when assuming that though.
1251  return maker_base_t::make(
1252  event, tag,
1253  withAssociatedAs<recob::Hit, Tracks::HitTag>(),
1254  std::forward<WithArgs>(withArgs)...
1255  );
1256  } // make()
1257 
1258  }; // struct CollectionProxyMaker<>
1259 
1260 
1261  /// "Converts" point data into a `proxy::TrackPointWrapper`.
1262  template <typename Data>
1263  auto wrapTrackPoint(Data const& wrappedData)
1264  {
1266  return reinterpret_cast<TrackPointWrapper<Data> const&>(wrappedData);
1267  }
1268 
1269  /// Iterator for points of a track proxy. Only supports range-for loops.
1270  /// @ingroup LArSoftProxyReco
1271  template <typename TrackProxy>
1272  class TrackPointIterator {
1273 
1274  /*
1275  * So, let's go through the list of iterator traits from cppreference.com:
1276  * [x] Iterator
1277  * [x] CopyConstructible
1278  * [x] CopyAssignable
1279  * [x] Destructible
1280  * [x] lvalues are Swappable
1281  * [x] value_type
1282  * [x] difference_type
1283  * [x] reference
1284  * [x] pointer
1285  * [x] iterator_category
1286  * [x] operator*()
1287  * [x] operator++()
1288  * [ ] InputIterator
1289  * [x] Iterator (above)
1290  * [x] EqualityComparable (operator== (A, B))
1291  * [x] operator!= ()
1292  * [ ] reference operator*() (convertible to value_type)
1293  * [ ] operator->()
1294  * [x] It& operator++()
1295  * [x] operator++(int)
1296  * [x] *i++ equivalent to { auto v = *i; ++i; return v; }
1297  * [ ] Forward Iterator
1298  * [ ] InputIterator (above)
1299  * [x] DefaultConstructible
1300  * [x] multipass guarantee: a == b => ++a == ++b
1301  * [ ] reference = value_type const&
1302  * [x] It operator++(int)
1303  * [ ] *i++ returns reference
1304  * That's it! :-|
1305  */
1306 
1307  using track_proxy_t = TrackProxy;
1308 
1309  track_proxy_t const* track = nullptr;
1311 
1312  public:
1313 
1314  /// @name Iterator traits
1315  /// @{
1316  using difference_type = std::ptrdiff_t;
1318  using pointer = TrackPoint const*;
1319  using reference = TrackPoint; // booo!
1320  // not quite an input iterator (see above)
1321  using iterator_category = std::input_iterator_tag;
1322  /// @}
1323 
1324  TrackPointIterator() = default;
1325 
1326  TrackPointIterator(track_proxy_t const& track, std::size_t index)
1327  : track(&track), index(index)
1328  {}
1329 
1330  TrackPointIterator& operator++() { ++index; return *this; }
1331 
1333  { auto it = *this; this->operator++(); return it; }
1334 
1335  // we make sure the return value is a temporary
1337  { return static_cast<value_type>(makeTrackPointData(*track, index)); }
1338 
1340  { return (index == other.index) && (track == other.track); }
1341 
1343  { return (index != other.index) || (track != other.track); }
1344 
1345  }; // class TrackPointIterator
1346 
1347 
1348 } // namespace proxy
1349 
1350 
1351 namespace proxy {
1352 
1353  //----------------------------------------------------------------------------
1354  namespace details {
1355 
1356  //--------------------------------------------------------------------------
1357  template <typename T>
1358  struct isTrackProxy: public std::false_type {};
1359 
1360  template <typename TrackCollProxy>
1361  struct isTrackProxy<Track<TrackCollProxy>>: public std::true_type {};
1362 
1363 
1364  //--------------------------------------------------------------------------
1365  /// Structure for range-for iteration.
1366  template <typename CollProxy>
1367  struct TrackPointIteratorBox {
1370 
1371  TrackPointIteratorBox(track_proxy_t const& track): track(&track) {}
1372 
1374  { return track->beginPoint(); }
1375 
1377  { return track->endPoint(); }
1378 
1379  private:
1380  track_proxy_t const* track = nullptr;
1381 
1382  }; // TrackPointIteratorBox<>
1383 
1384 
1385  //--------------------------------------------------------------------------
1386 
1387  } // namespace details
1388 
1389  //----------------------------------------------------------------------------
1390  template <typename CollProxy>
1391  recob::TrackTrajectory const*
1394  {
1395  switch (type) {
1396  case proxy::Tracks::Fitted:
1397  return &(track().Trajectory());
1399  return originalTrajectoryCPtr();
1400  default:
1401  return nullptr;
1402  } // switch
1403  } // TrackCollectionProxyElement<>::operator()
1404 
1405 
1406  //----------------------------------------------------------------------------
1407  template <typename CollProxy>
1408  recob::TrackFitHitInfo const*
1410  (std::size_t index) const
1411  {
1412  if constexpr (base_t::template has<Tracks::TrackFitHitInfoTag>()) {
1413  auto const& fitInfo = base_t::template get<Tracks::TrackFitHitInfoTag>();
1414  return &(fitInfo[index]);
1415  }
1416  else return nullptr;
1417  } // TrackCollectionProxyElement<>::fitInfoAtPoint()
1418 
1419 
1420  //----------------------------------------------------------------------------
1421  template <typename CollProxy>
1422  template <typename Pred>
1424  { return util::filterRangeFor(points(), std::forward<Pred>(pred)); }
1425 
1426 
1427  //----------------------------------------------------------------------------
1428  template <typename CollProxy>
1431  {
1432  return
1433  selectPoints([mask](auto&& point) { return point.flags().match(mask); });
1434  } // TrackCollectionProxyElement<>::pointsWithFlags()
1435 
1436 
1437  //----------------------------------------------------------------------------
1438 
1439 } // namespace proxy
1440 
1441 
1442 #endif // LARDATA_RECOBASEPROXY_TRACK_H
auto hitAtPoint(std::size_t index) const -> decltype(auto)
Returns an art pointer to the hit associated with the specified point.
Definition: Track.h:796
TrackPointIterator operator++(int)
Definition: Track.h:1332
TrackProxy track_proxy_t
Definition: Track.h:1307
auto withOriginalTrajectory(art::InputTag const &inputTag)
Adds recob::TrackTrajectory information to the proxy.
Definition: Track.h:1064
std::size_t nPoints() const
Returns the number of trajectory points in the track.
Definition: Track.h:985
Collection of data type definitions for collection proxies.
const_iterator begin() const
Definition: Track.h:1373
auto selectPoints(Pred &&pred) const
Returns an iterable range with only points matching the mask.
Definition: Track.h:1423
std::vector< recob::Track > TrackDataProduct_t
Type of the main collection.
Definition: Track.h:501
std::ptrdiff_t difference_type
Definition: Track.h:1316
art::Ptr< recob::TrackTrajectory > const & originalTrajectoryPtr() const
Definition: Track.h:843
art::Ptr< recob::Hit > hitPtr() const
Returns the hit associated with the trajectory point.
Definition: Track.h:653
Class to assemble the required proxy.
std::input_iterator_tag iterator_category
Definition: Track.h:1321
recob::TrackFitHitInfo const * fitInfoAtPoint(std::size_t index) const
Returns fit info for the specified point (nullptr if not available).
Definition: Track.h:1410
Proxy tag for a recob::Track collection proxy.
Definition: Track.h:498
bool isPointValid() const
Returns whether the trajectory point is valid.
Definition: Track.h:645
STL namespace.
auto position() const -> decltype(auto)
Definition: Track.h:621
Structure for range-for iteration.
Definition: Track.h:262
auto filterRangeFor(Range &&range, Pred &&pred) -> decltype(auto)
Provides iteration only through elements passing a condition.
Base utilities for the implementation of data product facades.
auto hits() const -> decltype(auto)
Returns a collection-like range of hits of this track, at point order.
Definition: Track.h:792
bool operator==(TrackPointIterator const &other) const
Definition: Track.h:1339
Class for track proxy elements.
Definition: Track.h:731
std::tuple< recob::Track const *, art::Ptr< recob::Hit >, recob::TrackFitHitInfo const *, std::size_t > TrackPointData
Container of track point information.
Definition: Track.h:556
Base representation of a collection of proxied objects.
TrackPointData makeTrackPointData(TrackProxy const &track, std::size_t index)
Returns an object with information about the specified track point.
Definition: Track.h:709
tracking::Vector_t Vector_t
Definition: Track.h:54
Type of track point information.
Definition: Track.h:684
A class containing a set of flags.
Definition: BitMask.h:420
Wrapper for a track data proxy.
Definition: Track.h:256
TrackPointIteratorBox(track_proxy_t const &track)
Definition: Track.h:1371
TrackPoint(TrackPointData const &data)
Definition: Track.h:689
TrackPointIterator(track_proxy_t const &track, std::size_t index)
Definition: Track.h:1326
recob::TrackTrajectory const * originalTrajectoryCPtr() const noexcept
Definition: Track.h:1014
A trajectory in space reconstructed from hits.
Object storing per-hit information from a track fit.
TrackPoint(TrackPointData &&data)
Definition: Track.h:690
const_iterator end() const
Definition: Track.h:1376
std::add_const_t< TrackPointData > Wrapped_t
Definition: Track.h:589
def move(depos, offset)
Definition: depos.py:107
Class to assemble the required proxy.
TrackPoint operator[](std::size_t index) const
Definition: Track.h:998
auto wrapTrackPoint(Data const &wrappedData)
"Converts" point data into a proxy::TrackPointWrapper.
Definition: Track.h:1263
auto withParallelDataAs(Args &&...args)
Helper function to merge an auxiliary data product into the proxy.
static int max(int a, int b)
auto index() const -> decltype(auto)
Returns the index of this point in the trajectory.
Definition: Track.h:668
std::size_t nHits() const
Returns the number of hits associated with this track.
Definition: Track.h:800
unique_ptr< InputSource > make(ParameterSet const &conf, InputSourceDescription &desc)
point_iterator endPoint() const
Returns the iterator past the last point.
Definition: Track.h:991
value_type operator*() const
Definition: Track.h:1336
An element of a collection proxy.
auto flags() const -> decltype(auto)
Definition: Track.h:636
recob::TrackFitHitInfo const * fitInfoPtr() const
Returns fit info associated with the trajectory point.
Definition: Track.h:664
Declaration of signal hit object.
TrackPoint point(std::size_t index) const
Definition: Track.h:995
recob::Hit const * hit() const
Returns a pointer to the hit on the trajectory point, if any.
Definition: Track.h:671
auto pointsWithFlags(recob::TrackTrajectory::PointFlags_t::Mask_t mask) const
Returns an iterable range with only points matching the mask.
Definition: Track.h:1430
typename track_proxy_t::point_iterator const_iterator
Definition: Track.h:1369
Represents a track trajectory before the final fit.
Definition: Track.h:514
Definition: types.h:32
track_proxy_t const * track
Definition: Track.h:1309
tracking::Point_t Point_t
Definition: Track.h:53
static QCString type
Definition: declinfo.cpp:672
Provides recob::Track data product.
TrackType_t
Types of tracks and trajectories.
Definition: Track.h:513
Utilities to manipulate range for loops.
auto withFitHitInfo(art::InputTag const &inputTag)
Adds recob::TrackFitHitInfo information to the proxy.
Definition: Track.h:1133
point_iterator beginPoint() const
Returns the iterator to the data of the first point.
Definition: Track.h:988
TrackCollectionProxyElement< TrackCollProxy > Track
Proxy to an element of a proxy collection of recob::Track objects.
Definition: Track.h:1036
bool hasOriginalTrajectory() const
Returns whether this track is associated to a trajectory.
Definition: Track.h:838
auto momentum() const -> decltype(auto)
Definition: Track.h:626
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
recob::TrackTrajectory const & originalTrajectory() const
Returns a reference to the associated trajectory.
Definition: Track.h:855
Represents a track trajectory from the final fit.
Definition: Track.h:515
auto points() const
Returns an iterable range with point-by-point information.
Definition: Track.h:909
def momentum(x1, x2, x3, scale=1.)
QuadExpr operator*(double v, const QuadExpr &e)
Definition: QuadExpr.h:39
TrackPoint const * pointer
Definition: Track.h:1318
recob::Track const & track() const
Returns the track this point belongs to.
Definition: Track.h:616
bool operator!=(TrackPointIterator const &other) const
Definition: Track.h:1342
Wrapped_t const & base() const
Definition: Track.h:600
Set of flags pertaining a point of the track.
TrackPointIterator & operator++()
Definition: Track.h:1330
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
Definition: Track.h:49
Event finding and building.
recob::Track const & track() const
Returns the pointed track.
Definition: Track.h:745
auto withZeroOrOneAs(Args &&...args)
Definition: withZeroOrOne.h:81