All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OpDetWaveformMetaMatcher.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Trigger/Utilities/OpDetWaveformMetaMatcher.h
3  * @brief Utilities for matching `raw::OpDetWaveform` and their
4  * `sbn::OpDetWaveformMeta`.
5  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
6  * @date January 10, 2022
7  */
8 
9 #ifndef ICARUSCODE_PMT_TRIGGER_UTILITIES_OPDETWAVEFORMMETAMATCHER_H
10 #define ICARUSCODE_PMT_TRIGGER_UTILITIES_OPDETWAVEFORMMETAMATCHER_H
11 
12 
13 // ICARUS libraries
14 #include "icaruscode/IcarusObj/OpDetWaveformMeta.h" // sbn::OpDetWaveformMeta
15 #include "icarusalg/Utilities/CanvasUtils.h" // util::inputTagOf()
17 
18 // LArSoft libraries
20 
21 // framework libraries
22 #include "canvas/Persistency/Common/Assns.h"
23 #include "canvas/Persistency/Common/Ptr.h"
24 #include "canvas/Persistency/Provenance/ProductID.h"
25 
26 // C/C++ standard libraries
27 #include <algorithm> // std::lower_bound()
28 #include <unordered_map>
29 // #include <utility> // std::move()
30 
31 
32 // -----------------------------------------------------------------------------
33 namespace icarus::trigger {
34  template <typename Event> class OpDetWaveformMetaMatcher;
35 }
36 /**
37  * @brief Object to facilitate the discovery of the `raw::OpDetWaveform` a
38  * `sbn::OpDetWaveformMeta` objects comes from.
39  * @tparam Event type of the framework event to read data products from
40  *
41  * This algorithm will look in the associated _art_ event for the
42  * `raw::OpDetWaveform` associated to any specified `sbn::OpDetWaveformMeta`.
43  *
44  * The `sbn::OpDetWaveformMeta` object must be specified by _art_ pointer.
45  * The algorithm assumes that the module that created the
46  * `sbn::OpDetWaveformMeta` object also created an association between it and
47  * the original `raw::OpDetWaveform`, and will read that association.
48  *
49  * Example:
50  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
51  * icarus::trigger::OpDetWaveformMetaMatcher waveformMetaMatcher{ event };
52  * art::Assns<OpticalTriggerGateData_t, raw::OpDetWaveform> waveAssns;
53  * for (auto const [ gatePtr, metaPtr ]: metaAssns)
54  * waveAssns.addSingle(gatePtr, waveformMetaMatcher(metaPtr));
55  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56  * will fill `waveAssns` with one gate/waveform association for each
57  * gate/metadata association in `metaAssns`.
58  * Note that, in this simple example, if no waveform pointer is matched to a
59  * metadata item, a null pointer to waveform is stored in the association.
60  *
61  */
62 template <typename Event>
64 
65  using Event_t = Event; ///< Type of the framework event to read data from.
66 
67  /// Type of associations used in this algorithm,
69  = art::Assns<sbn::OpDetWaveformMeta, raw::OpDetWaveform>;
70 
71  /// Compares a sbn::OpDetWaveformMeta` and an element of `WaveformMetaAssns_t`
72  struct CmpFirst {
73 
74  using Assn_t = typename WaveformMetaAssns_t::assn_t; // a pair
75  using MetaPtr_t = typename Assn_t::first_type; // an art pointer
76 
77  template <typename A, typename B>
78  bool operator() (A const& a, B const& b) const { return cmp(a, b); }
79 
80  static bool cmp(Assn_t const& a, Assn_t const& b)
81  { return cmp(a.first, b.first); }
82 
83  static bool cmp(Assn_t const& a, MetaPtr_t const& b)
84  { return cmp(a.first, b); }
85 
86  static bool cmp(MetaPtr_t const& a, Assn_t const& b)
87  { return cmp(a, b.first); }
88 
89  static bool cmp(MetaPtr_t const& a, MetaPtr_t const& b)
90  { return a.key() < b.key(); }
91 
92  }; // struct CmpFirst
93 
94 
95  Event_t const& fEvent; ///< Event to read associations from.
96 
97  /// All associations discovered so far.
98  std::unordered_map<art::ProductID, WaveformMetaAssns_t const*> fAssns;
99 
100 
101  /// Loads the association including `pid`.
102  /// @return pointer to the associations containing `pid`, `nullptr` if n/a.
103  WaveformMetaAssns_t const* loadAssociations(art::ProductID const& pid);
104 
105  /// Returns the waveform associated to `meta` if in `assns` or a null pointer.
106  art::Ptr<raw::OpDetWaveform> findAssociatedWaveform(
107  art::Ptr<sbn::OpDetWaveformMeta> const& meta,
108  WaveformMetaAssns_t const& assns
109  ) const;
110 
111  public:
112 
113  /// Constructor: associates to the specified art event.
114  OpDetWaveformMetaMatcher(Event const& event);
115 
116  // @{
117  /// Returns the waveform associated to `meta`, or a null pointer if not found.
118  art::Ptr<raw::OpDetWaveform> fetchAssociatedWaveform
119  (art::Ptr<sbn::OpDetWaveformMeta> const& meta);
120  art::Ptr<raw::OpDetWaveform> operator() // alias
121  (art::Ptr<sbn::OpDetWaveformMeta> const& meta)
122  { return fetchAssociatedWaveform(meta); }
123  // @}
124 
125 
126 }; // class icarus::trigger::OpDetWaveformMetaMatcher
127 
128 
129 
130 //------------------------------------------------------------------------------
131 //--- template implementation
132 //------------------------------------------------------------------------------
133 template <typename Event>
135  (Event const& event)
136  : fEvent(event)
137  {}
138 
139 
140 //------------------------------------------------------------------------------
141 template <typename Event>
142 art::Ptr<raw::OpDetWaveform>
144  (art::Ptr<sbn::OpDetWaveformMeta> const& meta)
145 {
146 
147  WaveformMetaAssns_t const* assns = loadAssociations(meta.id());
148  return assns
149  ? findAssociatedWaveform(meta, *assns): art::Ptr<raw::OpDetWaveform>{};
150 
151 } // icarus::trigger::OpDetWaveformMetaMatcher<>::fetchAssociatedWaveform()
152 
153 
154 //------------------------------------------------------------------------------
155 template <typename Event>
157  (art::ProductID const& pid) -> WaveformMetaAssns_t const*
158 {
159 
160  // if already there, the better
161  if (auto const itAssns = fAssns.find(pid); itAssns != fAssns.end())
162  return itAssns->second;
163 
164  // let's start optimistic: we won't find it
165  auto& assnCache = (fAssns[pid] = nullptr);
166 
167  try {
168  art::InputTag const tag = util::inputTagOf(fEvent, pid);
169 
170  auto const assnsHandle = fEvent.template getHandle<WaveformMetaAssns_t>(tag);
171  if (!assnsHandle.isValid()) return nullptr;
172  return assnCache = assnsHandle.product();
173  }
174  catch (art::Exception const& e) {
175  if (e.categoryCode() == art::errors::ProductNotFound) return nullptr;
176  throw;
177  }
178 
179 
180 } // icarus::trigger::OpDetWaveformMetaMatcher<>::loadAssociations()
181 
182 
183 //------------------------------------------------------------------------------
184 template <typename Event>
185 art::Ptr<raw::OpDetWaveform>
187  art::Ptr<sbn::OpDetWaveformMeta> const& meta,
188  WaveformMetaAssns_t const& assns
189 ) const {
190 
191  auto const key = meta.key();
192 
193  // try our luck: 1-1 association?
194  if ((assns.size() > key) && (assns.at(key).first == meta))
195  return assns[key].second;
196 
197  // nope, go binary search
198  if (auto itAssn = std::lower_bound(assns.begin(), assns.end(), meta, CmpFirst{});
199  itAssn != assns.end()
200  ) {
201  if (itAssn->first == meta) return itAssn->second;
202  }
203 
204  // still nope, go linear search
205  for (auto const& assn: assns) if (assn.first == meta) return assn.second;
206 
207  // still nope, not found!
208  return {};
209 
210 } // icarus::trigger::OpDetWaveformMetaMatcher::fetchAssociatedWaveform()
211 
212 
213 //------------------------------------------------------------------------------
214 
215 #endif // ICARUSCODE_PMT_TRIGGER_UTILITIES_OPDETWAVEFORMMETAMATCHER_H
art::Ptr< raw::OpDetWaveform > findAssociatedWaveform(art::Ptr< sbn::OpDetWaveformMeta > const &meta, WaveformMetaAssns_t const &assns) const
Returns the waveform associated to meta if in assns or a null pointer.
Derivative information from raw::OpDetWaveform data.
static bool cmp(Assn_t const &a, MetaPtr_t const &b)
static bool cmp(Assn_t const &a, Assn_t const &b)
art::Assns< sbn::OpDetWaveformMeta, raw::OpDetWaveform > WaveformMetaAssns_t
Type of associations used in this algorithm,.
process_name gaushit a
std::unordered_map< art::ProductID, WaveformMetaAssns_t const * > fAssns
All associations discovered so far.
art::Ptr< raw::OpDetWaveform > fetchAssociatedWaveform(art::Ptr< sbn::OpDetWaveformMeta > const &meta)
Returns the waveform associated to meta, or a null pointer if not found.
static bool cmp(MetaPtr_t const &a, MetaPtr_t const &b)
static bool cmp(MetaPtr_t const &a, Assn_t const &b)
Object to facilitate the discovery of the raw::OpDetWaveform a sbn::OpDetWaveformMeta objects comes f...
Event_t const & fEvent
Event to read associations from.
A trigger gate data object for optical detector electronics.
OpDetWaveformMetaMatcher(Event const &event)
Constructor: associates to the specified art event.
Compares a sbn::OpDetWaveformMeta&lt;tt&gt;and an element ofWaveformMetaAssns_t`.
art::InputTag inputTagOf(Event const &event, art::ProductID const &productID)
Reads and returns the input tag of the producer of productID.
Definition: CanvasUtils.h:108
WaveformMetaAssns_t const * loadAssociations(art::ProductID const &pid)
Helper functions based on art/canvas.
art::Ptr< raw::OpDetWaveform > operator()(art
Event Event_t
Type of the framework event to read data from.
do i e
float A
Definition: dedx.py:137