All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TriggerInfo_t.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Trigger/Algorithms/details/TriggerInfo_t.h
3  * @brief Helper class to store transient trigger result.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date April 15, 2020
6  */
7 
8 #ifndef ICARUSCODE_PMT_TRIGGER_ALGORITHMS_DETAILS_TRIGGERINFO_T_H
9 #define ICARUSCODE_PMT_TRIGGER_ALGORITHMS_DETAILS_TRIGGERINFO_T_H
10 
11 // ICARUS libraries
13 #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // optical_tick
15 
16 // C++ standard libraries
17 #include <vector>
18 #include <algorithm>
19 #include <optional>
20 #include <utility> // std::pair, std::tie()
21 #include <limits> // std::numeric_limits<>
22 #include <utility> // std::forward()
23 #include <type_traits> // std::decay_t
24 #include <cassert>
25 
26 
27 // -----------------------------------------------------------------------------
28 namespace icarus::trigger::details {
29  struct TriggerInfo_t;
30  template <typename Gate> class GateOpeningInfoExtractor;
31 } // namespace icarus::trigger::details
32 
33 // -----------------------------------------------------------------------------
34 /**
35  * @brief Helper data structure to store transient trigger result.
36  *
37  * This record maintains a list of all openings (`add()`), and has a special one
38  * (`main()`) which represents the "global" trigger.
39  *
40  * Note that unless no opening is `add()`'ed, there is always a `main()`
41  * trigger.
42  *
43  * Each trigger is described by the information in a `OpeningInfo_t` record.
44  * The records can be registered with `add()`; `replace()` changes the `main()`
45  * trigger information unconditionally, while `addAndReplaceIfEarlier()`
46  * replaces `main()` only if the argument proposes a trigger earlier than the
47  * current `main()`.
48  *
49  */
51 
53 
54  /// Type of gate opening level.
55  using Opening_t
57 
58  using LocationID_t = std::size_t; ///< Type for ID of trigger location.
59 
60  struct OpeningInfo_t {
61 
62  /// ID for a trigger in unknown location.
63  static constexpr LocationID_t UnknownLocation
64  = std::numeric_limits<std::size_t>::max();
65 
66  /// Tick at which the trigger fired.
67  optical_tick tick = std::numeric_limits<optical_tick>::min();
68 
69  Opening_t level = 0U; ///< Maximum level on the main trigger opening.
70 
71  /// Identified of the trigger location.
73 
74 
75  /// Default constructor.
76  OpeningInfo_t() = default;
77 
78  /// Constructor: specify `tick`, the rest is optional.
81  Opening_t level = 0U, std::size_t locationID = UnknownLocation
82  )
83  : tick(tick), level(level), locationID(locationID) {}
84 
85  /// Returns whether the location is set.
86  bool hasLocation() const { return locationID != UnknownLocation; }
87 
88  /// Comparison: order from time.
89  bool operator< (OpeningInfo_t const& other) const
90  { return tick < other.tick; }
91 
92  }; // OpeningInfo_t
93 
94 
95  // --- BEGIN -- Construction -------------------------------------------------
96 
97  TriggerInfo_t() = default; // no trigger
98  TriggerInfo_t(OpeningInfo_t info) { replace(std::move(info)); }
99 
100  // --- END -- Construction ---------------------------------------------------
101 
102 
103  // --- BEGIN -- Query whether the trigger fired ------------------------------
104  /// @name Query whether the trigger fired.
105  /// @{
106 
107  /// Returns whether the trigger fired.
108  bool fired() const { return !fAll.empty(); }
109 
110  /// Returns whether there is trigger information.
111  operator bool() const { return fired(); }
112 
113  /// Returns whether there is no trigger information.
114  bool operator! () const { return !fired(); }
115 
116  /// @}
117  // --- END -- Query whether the trigger fired --------------------------------
118 
119 
120  // --- BEGIN -- Modify trigger information -----------------------------------
121  /// @name Modify trigger information
122  /// @{
123 
124  /// Sets `info` as the new `main()` trigger
126  { fMain = info; add(std::move(info)); }
127 
128  /**
129  * @brief If `other` has fired, and at an earlier tick, set a new `main()`.
130  * @param other another set of triggers
131  * @return whether the `main()` information from `other` was copied
132  *
133  * If `other` has `fired()` earlier than this one (or if this one hasn't fired
134  * at all), the main trigger of `other` is adopted.
135  * In any case all openings from `other` are `add()`'ed to this one.
136  */
137  bool addAndReplaceIfEarlier(TriggerInfo_t const& other);
138 
139  /**
140  * @brief If `info` is earlier than `main()`, it is set as new `main()`.
141  * @param info the opening information candidate as new `main()`
142  * @return whether `main()` was updated.
143  *
144  * If `info` is earlier tick than `main()` (or if there is no `main()` yet,
145  * i.e. it has not `fired()`), `info` becomes the new `main()`.
146  * In all cases `info` is added (`add()`).
147  */
148  bool addAndReplaceIfEarlier(OpeningInfo_t const& info);
149 
150 
151  /// Adds an opening to `all` list (`main` is not affected). Not sorted.
152  /// If no trigger is marked as `main()`, this becomes it.
154  { if (fAll.empty()) fMain = info; fAll.push_back(std::move(info)); }
155 
156  /// Sorts `all` openings by time.
157  void sortOpenings() { std::sort(fAll.begin(), fAll.end()); }
158 
159  /// @}
160  // --- END ---- Modify trigger information -----------------------------------
161 
162 
163  // --- BEGIN -- Access to trigger information --------------------------------
164  /**
165  * @name Access to trigger information
166  *
167  * If the trigger did not fire, the result and behaviour of these methods are
168  * undefined.
169  */
170  /// @{
171 
172  /// Returns the information of the main trigger (undefined if `!fired()`).
173  OpeningInfo_t const& info() const { return main(); }
174 
175  /// Returns the time of the trigger (undefined if `!fired()`).
176  optical_tick atTick() const { return main().tick; }
177 
178  /// Returns the opening level of the trigger (undefined if `!fired()`).
179  Opening_t level() const { return main().level; }
180 
181  /// Returns the ID of the location of the trigger (undefined if `!fired()`).
182  LocationID_t location() const { return main().locationID; }
183 
184  /// Returns if the location of the trigger is set (undefined if `!fired()`).
185  bool hasLocation() const { return main().hasLocation(); }
186 
187  /// Returns the full data (undefined if `!fired()`).
188  OpeningInfo_t const& main() const { return fMain; }
189 
190  /// Returns all the registered opening in the current order (not resorted).
191  /// @see `sortOpenings()`
192  std::vector<OpeningInfo_t> const& all() const { return fAll; }
193 
194  /// Returns the number of registered triggers.
195  std::size_t nTriggers() const { return all().size(); }
196 
197  /// @}
198  // --- END -- Access to trigger information (if fired) -----------------------
199 
200  private:
201 
202  /// Main trigger (also found in `fAll`), if any.
204 
205  ///< Information about all global trigger candidates.
206  std::vector<OpeningInfo_t> fAll;
207 
208 }; // icarus::trigger::details::TriggerInfo_t
209 
210 
211 //------------------------------------------------------------------------------
212 /**
213  * @brief Helper to extract `OpeningInfo_t` from a trigger gate.
214  *
215  * Example of usage:
216  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
217  * icarus::trigger::details::TriggerInfo_t triggerInfo;
218  * icarus::trigger::details::GateOpeningInfoExtractor extractOpeningInfo
219  * { gate, { 6U } };
220  * while (extractOpeningInfo) {
221  * auto info = extractOpeningInfo();
222  * if (info) triggerInfo.add(info.value());
223  * } // while
224  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
225  * fills `triggerInfo` with all the openings equal or above level `6U`.
226  * Each opening is defined as from when `gate` reaches a specified threshold
227  * ("opening threshold") to when it reaches or goes below another one ("closing
228  * threshold"), with no dead time afterward.
229  * The time of the opening is the time when threshold is passed, but
230  * _the reported level is the maximum in the opening range_.
231  * By default, the closing threshold is one less than the opening one (i.e. as
232  * soon as the level goes below the opening threshold, the gate closes).
233  *
234  * This algorithm will not work in multi-threading.
235  */
236 template <typename Gate>
238  using Gate_t = Gate;
239  using GateData_t = std::decay_t<decltype(gateDataIn(std::declval<Gate_t>()))>;
240 
241  public:
242  using ClockTick_t = typename GateData_t::ClockTick_t;
246 
247  /// Configuration of the algorithm.
248  struct Config_t {
251  unsigned int minWidth { 1U };
252  unsigned int minGap { 0U };
254 
255  Config_t() = default;
256 
260  unsigned int minWidth = 1U,
261  unsigned int minGap = 0U,
263  )
264  : openThreshold(openThreshold), closeThreshold(closeThreshold)
266  , location(location)
267  {}
268 
269  Config_t(OpeningCount_t threshold): Config_t(threshold, threshold - 1) {}
270 
271  }; // struct Config_t
272 
273 
274  /**
275  * @brief Constructor: uses default configuration.
276  * @param gate the gate to operate on
277  * @param config configuration of the algorithm
278  * @see `configure()`
279  */
282  {}
283 
284  /**
285  * @brief Constructor: sets all configuration parameters.
286  * @param gate the gate to operate on
287  * @param config configuration of the algorithm (see `configure()`)
288  */
290  : gateSrc(gate), config(std::move(config)), gate(gateDataIn(gateSrc))
291  { restart(); }
292 
293  /**
294  * @brief Constructor: sets all configuration parameters.
295  * @param gate the gate to operate on
296  * @param threshold both opening and closing threshold
297  * @see `configure()`
298  */
300  : GateOpeningInfoExtractor(gate, Config_t{ threshold })
301  {}
302 
303  /**
304  * @brief Sets the configuration.
305  * @brief Constructor: sets all configuration parameters.
306  * @param gate the gate to operate on
307  * @param config configuration of the algorithm
308  *
309  * The configuration includes:
310  * * `openThreshold`, `closeThreshold`: the opening and closing thresholds
311  * * `minWidth`: minimum width of each opening range
312  * * `minGap`: minimum gap between successive opening ranges
313  * * `location`: location ID to add to the produced `OpeningInfo_t` records
314  */
315  void configure(Config_t config) { config = std::move(config); }
316 
317  //@{
318  /// The returned gate is at least `minWidth` ticks wide.
319  std::optional<OpeningInfo_t> operator() () { return findNextOpening(); }
320 
321  std::optional<OpeningInfo_t> findNextOpening();
322  //@}
323 
324  bool atEnd() const { return nextStart == MaxTick; }
325  operator bool() const { return !atEnd(); }
326  bool operator! () const { return atEnd(); }
327 
328  /// Resets the search from the specified time tick (beginning by default).
329  void restart(ClockTick_t fromTick = MinTick)
330  { nextStart = findOpen(fromTick); }
331 
332 
333  /// @name Configuration access
334  /// @{
335 
336  Config_t const& configuration() const { return config; }
337 
340  unsigned int minGap() const { return config.minGap; }
341  unsigned int minWidth() const { return config.minWidth; }
342  LocationID_t location() const { return config.location; }
343 
345 
346  /// @}
347 
348 
349  private:
350 
351  static constexpr ClockTick_t MinTick = GateData_t::MinTick;
352  static constexpr ClockTick_t MaxTick = GateData_t::MaxTick;
353 
354 
355  // --- BEGIN -- Configuration ------------------------------------------------
356  Gate_t const& gateSrc;
358  // --- END ---- Configuration ------------------------------------------------
359 
360 // GateData_t const& gate() { return gateDataIn(gateSrc); }
361  GateData_t const& gate;
362 
364 
365 
367  { return gate.findOpen(openThreshold(), start); }
369  { return gate.findClose(closeThreshold() + 1, start); }
370 
371  /// Returns the first closing and reopening above threshold from `start` on.
372  std::pair<ClockTick_t, ClockTick_t> findNextCloseAndOpen
373  (ClockTick_t start) const;
374 
375 }; // class icarus::trigger::details::GateOpeningInfoExtractor<>
376 
377 
378 // -----------------------------------------------------------------------------
379 // --- Inline implementation
380 // -----------------------------------------------------------------------------
381 // --- icarus::trigger::details::TriggerInfo_t
382 // -----------------------------------------------------------------------------
384  (TriggerInfo_t const& other)
385 {
386  if (!other.fired()) return false;
387 
388  bool const hadFired = fired();
389 
390  // register all triggers anyway; do not sort, do not resolve duplicates
391  fAll.reserve(nTriggers() + other.nTriggers());
392  for (OpeningInfo_t const& info: other.all()) add(info);
393 
394  if (hadFired && (other.atTick() >= atTick())) return false;
395 
396  fMain = other.main();
397  return true;
398 } // icarus::trigger::details::TriggerInfo_t::addAndReplaceIfEarlier()
399 
400 
401 // -----------------------------------------------------------------------------
404 {
405  add(info);
406  if (info.tick >= atTick()) return false;
407 
408  fMain = info;
409  return true;
410 } // icarus::trigger::details::TriggerInfo_t::addAndReplaceIfEarlier()
411 
412 
413 // -----------------------------------------------------------------------------
414 // --- icarus::trigger::details::GateOpeningInfoExtractor<>
415 // -----------------------------------------------------------------------------
416 template <typename Gate>
418  -> std::optional<OpeningInfo_t>
419 {
420  if (atEnd()) return {};
421 
422  using ClockDiff_t = decltype( ClockTick_t{} - ClockTick_t{} );
423 
424  ClockTick_t const start = nextStart;
425  ClockTick_t closing;
426  do {
427  std::tie(closing, nextStart) = findNextCloseAndOpen(nextStart);
428  if (nextStart == MaxTick) break;
429  } while(
430  (closing - start < static_cast<ClockDiff_t>(minWidth()))
431  || (nextStart - closing < static_cast<ClockDiff_t>(minGap()))
432  );
433 
434  return std::optional<OpeningInfo_t>{ std::in_place,
436  gate.openingCount(gate.findMaxOpen(start, closing)),
437  location()
438  };
439 } // icarus::trigger::details::GateOpeningInfoExtractor<>::findNextOpening()
440 
441 
442 // -----------------------------------------------------------------------------
443 template <typename Gate>
445  (ClockTick_t start) const -> std::pair<ClockTick_t, ClockTick_t>
446 {
447  ClockTick_t const closing = (gate.openingCount(start) > closeThreshold())
448  ? findClose(start): start;
449  return { closing, findOpen(closing) };
450 } // icarus::trigger::details::GateOpeningInfoExtractor<>::findNextCloseAndOpen()
451 
452 
453 // -----------------------------------------------------------------------------
454 
455 #endif // ICARUSCODE_PMT_TRIGGER_ALGORITHMS_DETAILS_TRIGGERINFO_T_H
bool addAndReplaceIfEarlier(TriggerInfo_t const &other)
If other has fired, and at an earlier tick, set a new main().
bool fired() const
Returns whether the trigger fired.
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
std::vector< OpeningInfo_t > const & all() const
std::pair< ClockTick_t, ClockTick_t > findNextCloseAndOpen(ClockTick_t start) const
Returns the first closing and reopening above threshold from start on.
void sortOpenings()
Sorts all openings by time.
LocationID_t location() const
Returns the ID of the location of the trigger (undefined if !fired()).
ClockTick_t findClose(ClockTick_t start) const
icarus::trigger::details::TriggerInfo_t::Opening_t OpeningCount_t
static constexpr bool
OpeningInfo_t const & main() const
Returns the full data (undefined if !fired()).
typename GateData_t::ClockTick_t ClockTick_t
bool hasLocation() const
Returns if the location of the trigger is set (undefined if !fired()).
bool operator<(OpeningInfo_t const &other) const
Comparison: order from time.
Definition: TriggerInfo_t.h:89
static constexpr LocationID_t UnknownLocation
ID for a trigger in unknown location.
Definition: TriggerInfo_t.h:64
std::vector< OpeningInfo_t > fAll
Helper data structure to store transient trigger result.
Definition: TriggerInfo_t.h:50
std::decay_t< decltype(gateDataIn(std::declval< Gate_t >()))> GateData_t
void restart(ClockTick_t fromTick=MinTick)
Resets the search from the specified time tick (beginning by default).
optical_tick tick
Tick at which the trigger fired.
Definition: TriggerInfo_t.h:67
LocationID_t locationID
Identified of the trigger location.
Definition: TriggerInfo_t.h:72
GateOpeningInfoExtractor(Gate_t const &gate, OpeningCount_t threshold)
Constructor: sets all configuration parameters.
std::optional< OpeningInfo_t > findNextOpening()
A trigger gate data object for optical detector electronics.
void replace(OpeningInfo_t info)
Sets info as the new main() trigger.
std::size_t LocationID_t
Type for ID of trigger location.
Definition: TriggerInfo_t.h:58
OpeningInfo_t fMain
Main trigger (also found in fAll), if any.
bool hasLocation() const
Returns whether the location is set.
Definition: TriggerInfo_t.h:86
OpeningInfo_t(optical_tick tick, Opening_t level=0U, std::size_t locationID=UnknownLocation)
Constructor: specify tick, the rest is optional.
Definition: TriggerInfo_t.h:79
Opening_t level
Maximum level on the main trigger opening.
Definition: TriggerInfo_t.h:69
unsigned int OpeningCount_t
Type of count of number of open channels.
GateOpeningInfoExtractor(Gate_t const &gate, Config_t config)
Constructor: sets all configuration parameters.
GateOpeningInfoExtractor(Gate_t const &gate)
Constructor: uses default configuration.
A wrapper to trigger gate objects tracking the contributions.
timescale_traits< OpticalTimeCategory >::tick_t optical_tick
icarus::trigger::OpticalTriggerGateData_t::GateData_t::OpeningCount_t Opening_t
Type of gate opening level.
Definition: TriggerInfo_t.h:56
optical_tick atTick() const
Returns the time of the trigger (undefined if !fired()).
void configure(Config_t config)
Sets the configuration.
icarus::trigger::details::TriggerInfo_t::LocationID_t LocationID_t
Data types for detinfo::DetectorTimings.
ClockTick_t findOpen(ClockTick_t start) const
Opening_t level() const
Returns the opening level of the trigger (undefined if !fired()).
decltype(auto) gateDataIn(Gate &&gate)
Returns the trigger data (a TriggerGateData) from the specofied gate.
Config_t(OpeningCount_t openThreshold, OpeningCount_t closeThreshold, unsigned int minWidth=1U, unsigned int minGap=0U, LocationID_t location=OpeningInfo_t::UnknownLocation)
OpeningInfo_t const & info() const
Returns the information of the main trigger (undefined if !fired()).
Helper to extract OpeningInfo_t from a trigger gate.
Definition: TriggerInfo_t.h:30
detinfo::timescales::optical_tick optical_tick
Type alias.
Definition: TriggerInfo_t.h:52
std::size_t nTriggers() const
Returns the number of registered triggers.
std::optional< OpeningInfo_t > operator()()
The returned gate is at least minWidth ticks wide.
bool operator!() const
Returns whether there is no trigger information.