All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TriggerGateData.h
Go to the documentation of this file.
1 /**
2  * @file sbnobj/ICARUS/PMT/Trigger/Data/TriggerGateData.h
3  * @brief A logical multilevel gate for triggering.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date April 1, 2019
6  * @see `sbnobj/ICARUS/PMT/Trigger/Data/TriggerGateData.tcc`
7  *
8  * This is a header only library.
9  *
10  * @bug This class is too much for a data product. Merging utilities,
11  * and maybe more things, should be moved out of it.
12  *
13  */
14 
15 #ifndef SBNOBJ_ICARUS_PMT_TRIGGER_DATA_TRIGGERGATEDATA_H
16 #define SBNOBJ_ICARUS_PMT_TRIGGER_DATA_TRIGGERGATEDATA_H
17 
18 // C/C++ standard libraries
19 #include <vector>
20 #include <iosfwd> // std::ostream
21 #include <optional>
22 #include <limits>
23 #include <utility> // std::pair, std::move()
24 #include <type_traits> // std::make_signed_t
25 
26 
27 // --- BEGIN -- Preliminary declarations and definitions -----------------------
28 namespace icarus::trigger {
29 
30  //----------------------------------------------------------------------------
31 
32  namespace details {
33 
34  /// Type of events that can happen at a certain tick of a trigger gate.
35  enum class TriggerGateEventType {
36  Unknown, ///< Unknown state. This can't be good.
37  Set, ///< Set the level, overriding the previous level.
38  Shift ///< Relative shift, _adding_ an offset to the previous level.
39  }; // TriggerGateEventType
40 
41  template
42  <typename ClockTick = unsigned int, typename OpeningCount = unsigned int>
44 
45  static constexpr ClockTick MinTick
46  = std::numeric_limits<ClockTick>::min();
47 
48  /// The event which yielded this status.
50 
51  /// When the status starts being valid.
52  ClockTick tick { std::numeric_limits<ClockTick>::lowest() };
53 
54  OpeningCount opening { 0 }; ///< The total opening of the gate.
55 
56  // default constructor is needed by ROOT I/O
57  constexpr TriggerGateStatus() = default;
58  constexpr TriggerGateStatus
59  (TriggerGateEventType event, ClockTick tick, OpeningCount opening)
60  : event(event), tick(tick), opening(opening)
61  {}
62 
63  /// Comparison: are all fields matching?
64  bool operator== (TriggerGateStatus const& other) const
65  {
66  return (event == other.event)
67  && (tick == other.tick) && (opening == other.opening);
68  }
69 
70  /// Comparison: is any field not matching?
71  bool operator!= (TriggerGateStatus const& other) const
72  {
73  return (event != other.event)
74  || (tick != other.tick) || (opening != other.opening);
75  }
76 
77  }; // struct TriggerGateStatus
78 
79 
80  } // namespace details
81 
82  //
83  // declarations
84  //
85  template <typename Tick, typename TickInterval>
87 
88 
89  template <typename TK, typename TI>
90  std::ostream& operator<< (std::ostream&, TriggerGateData<TK, TI> const&);
91 
92  template <typename TK, typename TI>
93  std::ostream& operator<<
94  (std::ostream&, typename TriggerGateData<TK, TI>::Status const&);
95 
96 
97 } // namespace icarus::trigger
98 // --- END -- Preliminary declarations and definitions -------------------------
99 
100 
101 //------------------------------------------------------------------------------
102 /**
103  * @brief Logical multi-level gate.
104  * @tparam Tick type used to count the ticks
105  * @tparam TickInterval type used to quantify tick difference
106  *
107  * A `TriggerGate` object tracks a logical multi-level gate, that is a gate
108  * whose level can be not only `0` or `1`, but an arbitrary integral number.
109  * The gate level is defined as a positive number. The general convention is
110  * that a level of `0` means the gate is closed, while any other level
111  * (typically `1`) means it's open. In a multi-level gate, one can choose to
112  * interpret the gate as open only if it reaches a chosen level higher than `1`.
113  * The time domain of the gate is measured in ticks, which in this context are
114  * @ref DetectorClocksIntroClocks "optical detector clock ticks" defined on
115  * the @ref DetectorClocksElectronicsTime "electronics time scale".
116  * That means that tick #0 is set
117  * @ref DetectorClocksElectronicsStartTime "at the origin of that time scale".
118  * The gate is unlimited, i.e. it can accommodate changes on any time tick
119  * from #0 on (up to the machine limitations, `MaxTick`). For practical
120  * purposes, `lastTick()` is instrumental to find the tick of the last gate
121  * change.
122  *
123  * Internally, the gate is represented by "events". The first event, at tick
124  * #0, sets the level of the gate to the lowest possible (`0`, _closed_).
125  * Each event may change the level at a given tick and all the following ones
126  * until `MaxTick`. An actual gate is therefore defined by two events, an
127  * opening event (that is an increase in level) and a closing one (a shift of
128  * the same amount in the opposite direction).
129  *
130  */
131 template <typename Tick, typename TickInterval>
133 
134  public:
135 
136  // --- BEGIN -- Data type definitions ----------------------------------------
138 
139  /// Type of a point in time, measured in ticks.
140  using ClockTick_t = Tick;
141 
142  /// Type of a time interval, measured in ticks.
143  using ClockTicks_t = TickInterval;
144 
145  /// Type of count of number of open channels.
146  using OpeningCount_t = unsigned int;
147 
148  /// Type representing a variation of open channels.
149  using OpeningDiff_t = std::make_signed_t<OpeningCount_t>;
150 
151  // --- END -- Data type definitions ------------------------------------------
152 
153 
154  /// An unbearably small tick number.
155  static constexpr ClockTick_t MinTick
156  = std::numeric_limits<ClockTick_t>::min();
157 
158  /// An unbearably large tick number.
159  static constexpr ClockTick_t MaxTick
160  = std::numeric_limits<ClockTick_t>::max();
161 
162 
163  /// Constructor: a closed gate for the channel in `waveform`.
165 
166 
167  // --- BEGIN Query -----------------------------------------------------------
168  /// @name Query
169  /// @{
170 
171  /// Returns the number of ticks this gate covers.
172  ClockTick_t lastTick() const { return fGateLevel.back().tick; }
173 
174  /// Returns the opening count of the gate at the specified `tick`.
176 
177  /// Returns whether this gate never opened.
178  bool alwaysClosed() const { return findOpenStatus() == fGateLevel.end(); }
179 
180  /// Returns whether the gate is open at all at the specified `tick`.
181  bool isOpen(ClockTick_t tick) const { return openingCount(tick) > 0U; }
182 
183  /**
184  * @brief Returns the tick at which the gate opened.
185  * @param minOpening minimum count to consider the gate open _(default: `1`)_
186  * @param start first tick to check (_by default, the first available one_)
187  * @param end if getting to this tick, give up (_by default, to the end_)
188  * @return the tick at which the gate opened, or `end` if never
189  * @see `findClose()`, `findMaxOpen()`
190  *
191  * If the count is already above (or equal to) `minOpening` at the specified
192  * `start` tick, the current level is ignored and only the next change which
193  * keeps the gate open is reported.
194  */
196  OpeningCount_t minOpening = 1U,
198  ) const;
199 
200  /**
201  * @brief Returns the tick at which the gate closed.
202  * @param minOpening minimum count to consider the gate open (default: `1`)
203  * @param start first tick to check _(by default, the first available one)_
204  * @param end if getting to this tick, give up _(by default, to the end)_
205  * @return the tick at which the gate closed, or `end` if never
206  * @see `findOpen()`
207  *
208  * The closing is defined as the opening count being changed to strictly below
209  * `minOpening`.
210  *
211  * If the count is already below `minOpening` at the specified `start` tick,
212  * the current level is ignored and only the next change which
213  * keeps the gate closed is reported.
214  */
216  OpeningCount_t minOpening = 1U,
218  ) const;
219 
220  /**
221  * @brief Returns the tick at which the gate has the maximum opening.
222  * @param start first tick to check _(by default, the first available one)_
223  * @param end if getting to this tick, give up _(by default, to the end)_
224  * @return the first tick with the maximum opening, or `end` if never
225  */
227  (ClockTick_t start = MinTick, ClockTick_t end = MaxTick) const;
228 
229  /**
230  * @brief Returns the range of trigger opening values in the specified range.
231  * @param start the first tick to consider
232  * @param end the first tick to exclude
233  * @return a pair, { lower, upper } opening values
234  *
235  * This method returns the lowest opening value seen in the tick range, and
236  * the lowest opening value above that one _not seen_ in the same range.
237  * Therefore, a gate always closed (opening value `0`) in the full range will
238  * return `{ 0, 1 }`, a gate always opened (opening value `1`) will return
239  * `{ 1, 2 }`, a gate which opened or closed within the tick range will return
240  * `{ 0, 2 }`. In case the tick range is empty, the returned value contains
241  * the same value for both extremes.
242  *
243  * This function does not describe where the two extreme counts were found.
244  */
245  std::pair<OpeningCount_t, OpeningCount_t> openingRange
246  (ClockTick_t start, ClockTick_t end) const;
247 
248  // --- END Query -------------------------------------------------------------
249 
250 
251  // --- BEGIN Gate opening and closing operations -----------------------------
252  /// @name Gate opening and closing operations
253  /// @{
254 
255  /// Changes the opening to match `openingCount` at the specified time.
257 
258  /// Open this gate at the specified time (increase the opening by `count`).
260  { openBetween(tick, MaxTick, count); }
261 
262  /// Open this gate at the specified time (increase the opening by 1).
263  void openAt(ClockTick_t tick) { openAt(tick, 1); }
264 
265  /// Open this gate at specified `start` tick, and close it at `end` tick.
267 
268  /// Open this gate at the specified time, and close it `length` ticks later.
270  { openBetween(tick, tick + length, count); }
271 
272  /// Close this gate at the specified time (decrease the opening by `count`).
274  { return openAt(tick, -count); }
275 
276  /// Close this gate at the specified time.
277  void closeAt(ClockTick_t tick) { closeAt(tick, 1); }
278 
279  /// Completely close this gate at the specified time.
281 
282  /// Sets the gate levels in the state at construction.
284 
285  /// @}
286  // --- END Gate opening and closing operations -------------------------------
287 
288 
289  // --- BEGIN Combination operations ------------------------------------------
290  /// @name Combination operations
291  /// @{
292 
293 
294  /**
295  * @brief Combines with a gate, keeping the minimum opening among the two.
296  * @param other gate to combine to
297  * @return this object
298  * @see `Max()`
299  *
300  * Multi-level equivalent of an _and_ logical operation.
301  */
302  triggergatedata_t& Min(triggergatedata_t const& other);
303 
304  /**
305  * @brief Combines with a gate, keeping the maximum opening among the two.
306  * @param other gate to combine to
307  * @return this object
308  * @see `Min()`, `Sum()`
309  *
310  * Multi-level equivalent of an _or_ logical operation.
311  */
312  triggergatedata_t& Max(triggergatedata_t const& other);
313 
314  /**
315  * @brief Combines with a gate, keeping the sum of openings of the two.
316  * @param other gate to combine to
317  * @return this object
318  * @see `Min()`, `Max()`
319  */
320  triggergatedata_t& Sum(triggergatedata_t const& other);
321 
322  /**
323  * @brief Combines with a gate, keeping the product of openings of the two.
324  * @param other gate to combine to
325  * @return this object
326  * @see `Min()`, `Max()`, `Sum()`
327  *
328  * Multi-level equivalent of an extended _and_.
329  */
330  triggergatedata_t& Mul(triggergatedata_t const& other);
331 
332  /**
333  * @brief Returns a gate with the minimum opening between the specified two.
334  * @param a first gate
335  * @param b second gate
336  * @return gate with at every tick the minimum opening among `a` and `b`
337  * @see `Max()`
338  *
339  * Multi-level equivalent of an _and_ logical operation.
340  */
341  static triggergatedata_t Min
342  (triggergatedata_t const& a, triggergatedata_t const& b);
343 
344  /**
345  * @brief Returns a gate with the maximum opening between the specified two.
346  * @param a first gate
347  * @param b second gate
348  * @return gate with at every tick the maximum opening among `a` and `b`
349  * @see `Min()`, `Sum()`
350  *
351  * Multi-level equivalent of an _or_ logical operation.
352  */
353  static triggergatedata_t Max
354  (triggergatedata_t const& a, triggergatedata_t const& b);
355 
356  /**
357  * @brief Returns a gate with opening sum of the specified two.
358  * @param a first gate
359  * @param b second gate
360  * @return gate with at every tick the total opening of `a` and `b`
361  * @see `Max()`
362  */
363  static triggergatedata_t Sum
364  (triggergatedata_t const& a, triggergatedata_t const& b);
365 
366  /**
367  * @brief Returns a gate with opening product of the specified two.
368  * @param a first gate
369  * @param b second gate
370  * @return gate with at every tick the product of openings of `a` and `b`
371  * @see `Max()`, `Sum()`
372  */
373  static triggergatedata_t Mul
374  (triggergatedata_t const& a, triggergatedata_t const& b);
375 
376 
377  /**
378  * @brief Returns a gate combination of the openings of two other gates.
379  * @tparam Op binary operation: `OpeningCount_t` (x2) to `OpeningCount_t`
380  * @param op symmetric binary combination operation
381  * @param a first gate
382  * @param b second gate
383  * @param aDelay ticks of delay to be added to the first gate
384  * @param bDelay ticks of delay to be added to the second gate
385  * @return gate with opening combination of `a` and `b`
386  *
387  * For this algorithm to work, the operation needs to be symmetric, i.e.
388  * `op(c1, c2) == op(c2, c1)` for every valid combinations of counts
389  * `c1` and `c2`.
390  *
391  */
392  template <typename Op>
394  Op&& op, triggergatedata_t const& a, triggergatedata_t const& b,
395  ClockTicks_t aDelay = ClockTicks_t{},
396  ClockTicks_t bDelay = ClockTicks_t{}
397  );
398 
399  /// @}
400  // --- END Combination operations --------------------------------------------
401 
402 
403  // standard comparison operators: all must be the same
404  bool operator== (TriggerGateData const&) const;
405  bool operator!= (TriggerGateData const&) const;
406 
407  protected:
408 
409  // --- BEGIN Gate data types -------------------------------------------------
412 
413  /// Type to describe the time evolution of the gate.
414  using GateEvolution_t = std::vector<Status>;
415 
416  /// Protected constructor: set the data directly.
418  : fGateLevel(std::move(gateLevel)) {}
419 
420 
421  friend std::ostream& operator<< <ClockTick_t, ClockTicks_t>
422  (std::ostream&, triggergatedata_t const&);
423  friend std::ostream& operator<< <ClockTick_t, ClockTicks_t>
424  (std::ostream&, Status const&);
425 
426 
427  private:
428 
429  // --- BEGIN Private gate data types -----------------------------------------
430  using status_iterator = typename GateEvolution_t::iterator;
431  using status_const_iterator = typename GateEvolution_t::const_iterator;
432 
433  /// Comparison by tick number.
434  struct CompareTick {
435  static constexpr ClockTick_t tickOf(ClockTick_t tick) { return tick; }
436  static constexpr ClockTick_t tickOf(Status const& status)
437  { return status.tick; }
438  template <typename A, typename B>
439  bool operator() (A&& a, B&& b) const { return tickOf(a) < tickOf(b); }
440  }; // CompareTick
441 
442  // --- END Private gate data types -------------------------------------------
443 
444 
445  // This can't be `constexpr` because it's of a nested class type and we can't
446  // call its constructor(s) during class definition. It sucks.
447  /// A new gate starts with this status: opening level set to 0.
448  static Status const NewGateStatus;
449 
450 
451  GateEvolution_t fGateLevel; ///< Evolution of the gate in time.
452 
453 
454  /// Returns a const-iterator to the status current at `tick`, or no value.
455  std::optional<status_const_iterator> findLastStatusFor
456  (ClockTick_t tick) const;
457 
458  /// Returns an iterator to the status current at `tick`, or no value.
459  std::optional<status_iterator> findLastStatusFor(ClockTick_t tick);
460 
461  /// Returns an iterator to the status current at `tick`.
462  /// @throw cet::exception if tick can't be handled
464 
465  /// Returns a const-iterator to the status current at `tick`.
466  /// @throw cet::exception if tick can't be handled
468 
469  /// Returns an iterator to the first status for which `op(status)` is true.
470  template <typename Op>
472  (Op op, ClockTick_t start = MinTick, ClockTick_t end = MaxTick) const;
473 
474  /// Returns an iterator to the first open status (@see `findOpen()`).
476  OpeningCount_t minOpening = 1U,
478  ) const;
479 
480  /// Returns an iterator to the first close status (@see `findClose()`).
482  OpeningCount_t minOpening = 1U,
484  ) const;
485 
486  /// Returns an iterator to the maximum open status (@see `findMaxOpen()`).
488  (ClockTick_t start = MinTick, ClockTick_t end = MaxTick) const;
489 
490  /// Maintenance operation: removes unconsequential stati.
491  void compact();
492 
493 
494  /// Helper returning the starting state of the levels at construction time.
496 
497 }; // class icarus::trigger::TriggerGateData<>
498 
499 
500 //------------------------------------------------------------------------------
501 //--- Template implementation
502 //------------------------------------------------------------------------------
503 
504 #include "sbnobj/ICARUS/PMT/Trigger/Data/TriggerGateData.tcc"
505 
506 //------------------------------------------------------------------------------
507 
508 
509 
510 #endif // SBNOBJ_ICARUS_PMT_TRIGGER_DATA_TRIGGERGATEDATA_H
511 
Set the level, overriding the previous level.
typename GateEvolution_t::iterator status_iterator
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
triggergatedata_t & Sum(triggergatedata_t const &other)
Combines with a gate, keeping the sum of openings of the two.
typename GateEvolution_t::const_iterator status_const_iterator
triggergatedata_t & Min(triggergatedata_t const &other)
Combines with a gate, keeping the minimum opening among the two.
static constexpr ClockTick_t MaxTick
An unbearably large tick number.
status_const_iterator findMaxOpenStatus(ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns an iterator to the maximum open status (.
status_const_iterator findStatus(Op op, ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns an iterator to the first status for which op(status) is true.
static constexpr ClockTick_t MinTick
An unbearably small tick number.
void closeAllAt(ClockTick_t tick)
Completely close this gate at the specified time.
static triggergatedata_t SymmetricCombination(Op &&op, triggergatedata_t const &a, triggergatedata_t const &b, ClockTicks_t aDelay=ClockTicks_t{}, ClockTicks_t bDelay=ClockTicks_t{})
Returns a gate combination of the openings of two other gates.
ClockTick tick
When the status starts being valid.
static Status const NewGateStatus
A new gate starts with this status: opening level set to 0.
void closeAt(ClockTick_t tick, OpeningDiff_t count)
Close this gate at the specified time (decrease the opening by count).
Relative shift, adding an offset to the previous level.
bool operator==(TriggerGateStatus const &other) const
Comparison: are all fields matching?
bool operator==(TriggerGateData const &) const
bool operator!=(TriggerGateStatus const &other) const
Comparison: is any field not matching?
process_name gaushit a
void compact()
Maintenance operation: removes unconsequential stati.
TriggerGateData(GateEvolution_t &&gateLevel)
Protected constructor: set the data directly.
void openBetween(ClockTick_t start, ClockTick_t end, OpeningDiff_t count=1)
Open this gate at specified start tick, and close it at end tick.
triggergatedata_t & Mul(triggergatedata_t const &other)
Combines with a gate, keeping the product of openings of the two.
triggergatedata_t & Max(triggergatedata_t const &other)
Combines with a gate, keeping the maximum opening among the two.
void clear()
Sets the gate levels in the state at construction.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
status_const_iterator findOpenStatus(OpeningCount_t minOpening=1U, ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns an iterator to the first open status (.
details::TriggerGateStatus< ClockTick_t, OpeningCount_t > Status
OpeningCount_t openingCount(ClockTick_t tick) const
Returns the opening count of the gate at the specified tick.
TriggerGateEventType event
The event which yielded this status.
OpeningCount opening
The total opening of the gate.
ClockTick_t lastTick() const
Returns the number of ticks this gate covers.
unsigned int OpeningCount_t
Type of count of number of open channels.
ClockTick_t findOpen(OpeningCount_t minOpening=1U, ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns the tick at which the gate opened.
Unknown state. This can&#39;t be good.
status_iterator findLastStatusForTickOrThrow(ClockTick_t tick)
void openAt(ClockTick_t tick, OpeningDiff_t count)
Open this gate at the specified time (increase the opening by count).
TriggerGateData()
Constructor: a closed gate for the channel in waveform.
static constexpr ClockTick_t tickOf(ClockTick_t tick)
TriggerGateData< Tick, TickInterval > triggergatedata_t
This type.
bool operator!=(TriggerGateData const &) const
bool isOpen(ClockTick_t tick) const
Returns whether the gate is open at all at the specified tick.
std::optional< status_const_iterator > findLastStatusFor(ClockTick_t tick) const
Returns a const-iterator to the status current at tick, or no value.
void closeAt(ClockTick_t tick)
Close this gate at the specified time.
ClockTick_t findMaxOpen(ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns the tick at which the gate has the maximum opening.
Logical multi-level gate.
GateEvolution_t fGateLevel
Evolution of the gate in time.
void setOpeningAt(ClockTick_t tick, OpeningCount_t openingCount)
Changes the opening to match openingCount at the specified time.
static GateEvolution_t startingGateLevel()
Helper returning the starting state of the levels at construction time.
TriggerGateEventType
Type of events that can happen at a certain tick of a trigger gate.
void openAt(ClockTick_t tick)
Open this gate at the specified time (increase the opening by 1).
std::size_t count(Cont const &cont)
std::make_signed_t< OpeningCount_t > OpeningDiff_t
Type representing a variation of open channels.
TickInterval ClockTicks_t
Type of a time interval, measured in ticks.
void openFor(ClockTick_t tick, ClockTicks_t length, OpeningDiff_t count=1)
Open this gate at the specified time, and close it length ticks later.
float A
Definition: dedx.py:137
Tick ClockTick_t
Type of a point in time, measured in ticks.
bool alwaysClosed() const
Returns whether this gate never opened.
std::vector< Status > GateEvolution_t
Type to describe the time evolution of the gate.
ClockTick_t findClose(OpeningCount_t minOpening=1U, ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns the tick at which the gate closed.
std::pair< OpeningCount_t, OpeningCount_t > openingRange(ClockTick_t start, ClockTick_t end) const
Returns the range of trigger opening values in the specified range.
status_const_iterator findCloseStatus(OpeningCount_t minOpening=1U, ClockTick_t start=MinTick, ClockTick_t end=MaxTick) const
Returns an iterator to the first close status (.
static constexpr ClockTick_t tickOf(Status const &status)