All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TriggerGateOperations.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Trigger/Utilities/TriggerGateOperations.h
3  * @brief Utilities for the conversion of trigger gate data formats.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date April 3, 2020
6  *
7  * This library is header-only.
8  */
9 
10 #ifndef ICARUSCODE_PMT_TRIGGER_UTILITIES_TRIGGERGATEOPERATIONS_H
11 #define ICARUSCODE_PMT_TRIGGER_UTILITIES_TRIGGERGATEOPERATIONS_H
12 
13 
14 // ICARUS libraries
17 
18 // C/C++ standard libraries
19 #include <iterator> // std::iterator_traits
20 
21 
22 namespace icarus::trigger {
23 
24  // --- BEGIN -- Gate operations ----------------------------------------------
25  /**
26  * @name Gate operations
27  *
28  * Currently the following operations are supported:
29  *
30  * * discrimination against a threshold: `discriminate()`;
31  * * sum of trigger gates: `sumGates()`, `sumGatesSequence()`;
32  * * maximum of trigger gates: `maxGates()`, `maxGatesSequence()`.
33  *
34  * Operations on more than one gate can take a sequence (begin and end
35  * iterators), a collection or an arbitrary number of gates.
36  */
37  /// @{
38 
39  /**
40  * @brief Returns a discriminated version of `gate`.
41  * @tparam GateObj type of gate being discriminated (and returned)
42  * @param gate the gate to be discriminated
43  * @param threshold (_default: `1`_) the discrimination threshold
44  * @param pass (_default: `1`_) discriminated gate value on test pass
45  * @param fail (_default: `0`_) discriminated gate value on test fail
46  * @return a gate resulting from the discrimination of `gate`.
47  * @see `gateAbove()`, `gateBelow()`
48  *
49  * A new gate of the same type as the input `gate` is returned.
50  * This gate has two opening count values: either `pass`, in the time
51  * intervals where the `gate` is at or above `threshold`, or `fail`,
52  * in the time intervals where the `gate` is below `threshold`.
53  *
54  * Examples:
55  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
56  * auto const discrGate = discriminate(gate, 5U, 0U, 5U);
57  * auto const discrGateNeg = discriminate(gate, 5U, 5U, 0U);
58  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
59  * will have `discrGate` as a gate with value `0U` wherever `gate` has opening
60  * count 4 or less, and `5U` where `gate` has opening count 5 or more.
61  * The gate` discrGateNeg` has the two opening values swapped and therefore
62  * results the complement of `discrGate`.
63  */
64  template <typename GateObj>
65  [[nodiscard]] GateObj discriminate(
66  GateObj const& gate,
67  typename GateObj::OpeningCount_t threshold = 1U,
68  typename GateObj::OpeningCount_t pass = 1U,
69  typename GateObj::OpeningCount_t fail = 0U
70  );
71 
72 
73  // --- BEGIN -- Gate operations: sum ----------------------------------------
74 
75  /**
76  * @brief Sums a sequence of gates.
77  * @tparam BIter type of iterator to the gates to add
78  * @tparam EIter type of iterator past-the-end of the sequence of gates to add
79  * @param begin iterator to the first gate to add
80  * @param end iterator past-the-last gate to add
81  * @return a new gate sum of all the specified ones
82  * @see `sumGates()`
83  *
84  * All gates from the first on are summed.
85  * The returned gate has the same type as the first gate.
86  */
87  template <typename BIter, typename EIter>
88  [[nodiscard]] auto sumGatesSequence(BIter const begin, EIter const end);
89 
90 
91  /**
92  * @brief Sums all the gates in a collection.
93  * @tparam GateColl type of collection of gates
94  * @param gates the collection of gates to sum
95  * @return a new gate sum of all the `gates`
96  * @see `sumGatesSequence()`
97  *
98  * All gates from the first on are summed.
99  * The returned gate has the same type as the gates in the collection.
100  */
101  template <typename GateColl>
102  [[nodiscard]] auto sumGates(GateColl const& gates);
103 
104 
105  /**
106  * @brief Sums all the specified gates.
107  * @tparam AGate type of the first gate to sum; it determines the return type
108  * @tparam BGate type of the second gate to sum
109  * @tparam OGates type of other gates to sum
110  * @param A first gate to be summed
111  * @param B second gate to be summed
112  * @param others other gates to be summed
113  * @return a new gate sum of all the argument gates, of the same type as `A`
114  * @see `sumGatesSequence()`
115  *
116  * All arguments are combined in the sum of the gates.
117  * The returned gate has the same type as the first gate.
118  *
119  * @note There must be _at least two_ gates in the arguments.
120  */
121  template <typename AGate, typename BGate, typename... OTrigGates>
122  [[nodiscard]] auto sumGates
123  (AGate A, BGate const& B, OTrigGates const&... others);
124 
125 
126  // --- END -- Gate operations: sum -------------------------------------------
127 
128 
129  // --- BEGIN -- Gate operations: multiplication ------------------------------
130 
131  /**
132  * @brief Multiplies a sequence of gates.
133  * @tparam BIter type of iterator to the gates to add
134  * @tparam EIter type of iterator past-the-end of the sequence of gates to add
135  * @param begin iterator to the first gate to add
136  * @param end iterator past-the-last gate to add
137  * @return a new gate product of all the specified ones
138  * @see `mulGates()`
139  *
140  * All gates from the first on are multiplied.
141  * The returned gate has the same type as the first gate.
142  */
143  template <typename BIter, typename EIter>
144  [[nodiscard]] auto mulGatesSequence(BIter const begin, EIter const end);
145 
146 
147  /**
148  * @brief Multiplies all the gates in a collection.
149  * @tparam GateColl type of collection of gates
150  * @param gates the collection of gates to multiply
151  * @return a new gate product of all the `gates`
152  * @see `mulGatesSequence()`
153  *
154  * All gates from the first on are summed.
155  * The returned gate has the same type as the gates in the collection.
156  */
157  template <typename GateColl>
158  [[nodiscard]] auto mulGates(GateColl const& gates);
159 
160 
161  /**
162  * @brief Multiplies all the specified gates.
163  * @tparam AGate type of the first gate to sum; it determines the return type
164  * @tparam BGate type of the second gate to sum
165  * @tparam OGates type of other gates to sum
166  * @param A first gate to be multiplied
167  * @param B second gate to be multiplied
168  * @param others other gates to be multiplied
169  * @return a new gate product of all the argument gates, of the same type as
170  * `A`
171  * @see `mulGatesSequence()`
172  *
173  * All arguments are combined in the product of the gates.
174  * The product of two gates is at each tick the product of the level of
175  * opening of the two gates at that tick.
176  * The returned gate has the same type as the first gate.
177  *
178  * @note There must be _at least two_ gates in the arguments.
179  */
180  template <typename AGate, typename BGate, typename... OTrigGates>
181  [[nodiscard]] auto mulGates
182  (AGate A, BGate const& B, OTrigGates const&... others);
183 
184 
185  // --- END -- Gate operations: multiplication --------------------------------
186 
187 
188  // --- BEGIN -- Gate operations: max ----------------------------------------
189 
190  /**
191  * @brief Computes the gate with the maximum opening of a sequence of gates.
192  * @tparam BIter type of iterator to the gates to add
193  * @tparam EIter type of iterator past-the-end of the sequence of gates to add
194  * @param begin iterator to the first gate to add
195  * @param end iterator past-the-last gate to add
196  * @return a new gate maximum of all the specified ones
197  * @see `maxGates()`
198  *
199  * For each tick, the maximum opening among all the gates in the sequence is
200  * picked.
201  * The returned gate has the same type as the first gate.
202  */
203  template <typename BIter, typename EIter>
204  [[nodiscard]] auto maxGatesSequence(BIter const begin, EIter const end);
205 
206 
207  /**
208  * @brief Computes the gate with the maximum opening of gates from collection.
209  * @tparam GateColl type of collection of gates
210  * @param gates the collection of gates to sum
211  * @return a new gate maximum of all the `gates`
212  * @see `maxGatesSequence()`
213  *
214  * For each tick, the maximum opening among all the gates in the collection is
215  * picked.
216  * The returned gate has the same type as the gates in the collection.
217  */
218  template <typename GateColl>
219  [[nodiscard]] auto maxGates(GateColl const& gates);
220 
221 
222  /**
223  * @brief Computes the gate with the maximum opening of the specified gates.
224  * @tparam AGate type of the first gate; it determines the return type
225  * @tparam BGate type of the second gate
226  * @tparam OGates type of other gates
227  * @param A first gate
228  * @param B second gate
229  * @param others other gates
230  * @return a new gate maximum of all the argument gates, of same type as `A`
231  * @see `maxGatesSequence()`
232  *
233  * For each tick, the maximum opening among all the specified gates is picked.
234  * The returned gate has the same type as the first gate.
235  *
236  * @note There must be _at least two_ gates in the arguments.
237  */
238  template <typename AGate, typename BGate, typename... OTrigGates>
239  [[nodiscard]] auto maxGates
240  (AGate A, BGate const& B, OTrigGates const&... others);
241 
242 
243  // --- END -- Gate operations: max -------------------------------------------
244 
245 
246  // --- BEGIN -- Gate operations: min ----------------------------------------
247 
248  /**
249  * @brief Computes the gate with the minimum opening of a sequence of gates.
250  * @tparam BIter type of iterator to the gates to add
251  * @tparam EIter type of iterator past-the-end of the sequence of gates to add
252  * @param begin iterator to the first gate to add
253  * @param end iterator past-the-last gate to add
254  * @return a new gate minimum of all the specified ones
255  * @see `minGates()`
256  *
257  * For each tick, the minimum opening among all the gates in the sequence is
258  * picked.
259  * The returned gate has the same type as the first gate.
260  */
261  template <typename BIter, typename EIter>
262  [[nodiscard]] auto minGatesSequence(BIter const begin, EIter const end);
263 
264 
265  /**
266  * @brief Computes the gate with the minimum opening of gates from collection.
267  * @tparam GateColl type of collection of gates
268  * @param gates the collection of gates to sum
269  * @return a new gate minimum of all the `gates`
270  * @see `minGatesSequence()`
271  *
272  * For each tick, the minimum opening among all the gates in the collection is
273  * picked.
274  * The returned gate has the same type as the gates in the collection.
275  */
276  template <typename GateColl>
277  [[nodiscard]] auto minGates(GateColl const& gates);
278 
279 
280  /**
281  * @brief Computes the gate with the minimum opening of the specified gates.
282  * @tparam AGate type of the first gate; it determines the return type
283  * @tparam BGate type of the second gate
284  * @tparam OGates type of other gates
285  * @param A first gate
286  * @param B second gate
287  * @param others other gates
288  * @return a new gate minimum of all the argument gates, of same type as `A`
289  * @see `minGatesSequence()`
290  *
291  * For each tick, the minimum opening among all the specified gates is picked.
292  * The returned gate has the same type as the first gate.
293  *
294  * @note There must be _at least two_ gates in the arguments.
295  */
296  template <typename AGate, typename BGate, typename... OTrigGates>
297  [[nodiscard]] auto minGates
298  (AGate A, BGate const& B, OTrigGates const&... others);
299 
300 
301  // --- END -- Gate operations: min -------------------------------------------
302 
303 
304  // --- BEGIN -- Gate operations: generic -------------------------------------
305 
306  /**
307  * @brief Applies an operation to two gates.
308  * @tparam Op type of binary operation `AGate (Op)(AGate, BGate)`
309  * @tparam AGate type of the first gate; it determines the return type
310  * @tparam BGate type of the second gate
311  * @tparam OGates type of other gates
312  * @param op the binary operation to apply (copied)
313  * @param A first gate
314  * @param B second gate
315  * @param others other gates
316  * @return a new gate of same type as `A`, result of the operation.
317  * @see `OpGatesSequence()`, `OpGateColl()`
318  *
319  * For each tick, the operation `op` is performed between `A`, `B` and the
320  * `others`, and the result is stored into the return value.
321  * The order of operation is the same as in the arguments:
322  * `((A op B) op others...)`.
323  * The returned gate has the same type as the first gate (`A`).
324  *
325  * Standard operations are provided in namespace `GateOps`.
326  *
327  * A specific action is performed if the gates are "tracking" (i.e. instances
328  * of `TrackedTriggerGate`), in which case tracking will also be propagated
329  * so that the result includes all the tracked objects of all the operands.
330  *
331  * @note There must be _at least two_ gates in the arguments.
332  */
333  template <typename Op, typename AGate, typename BGate, typename... OGates>
334  [[nodiscard]] AGate OpGates
335  (Op op, AGate A, BGate const& B, OGates const&... others);
336 
337  /**
338  * @brief Computes the result of an operation on all gates from collection.
339  * @tparam Op type of binary operation `AGate (Op)(AGate, BGate)`
340  * @tparam GateColl type of collection of gates
341  * @param op the binary operation to apply (copied)
342  * @param gates the collection of gates to sum
343  * @return a new gate result of `op` on all the `gates`
344  * @see `OpGates()`, `OpGatesSequence()`
345  *
346  * This is the sequential application of `op` to all `gates` via `OpGates()`,
347  * according to their order in the collection.
348  * The returned gate has the same type as the gates in the collection.
349  */
350  template <typename Op, typename GateColl>
351  [[nodiscard]] auto OpGateColl(Op op, GateColl const& gates);
352 
353  /**
354  * @brief Computes the result of an operation on all gates in the sequence.
355  * @tparam Op type of binary operation `AGate (Op)(AGate, BGate)`
356  * @tparam BIter type of iterator to the gates to add
357  * @tparam EIter type of iterator past-the-end of the sequence of gates to add
358  * @param op the binary operation to apply (copied)
359  * @param begin iterator to the first gate to add
360  * @param end iterator past-the-last gate to add
361  * @return a new gate result of `op` on all the `gates`
362  * @see `OpGates()`, `OpGateColl()`
363  *
364  * This is the sequential application of `op` to all gates from `begin` to
365  * `end` via `OpGates()`, following their order in the collection.
366  * The returned gate has the same type as the one pointed by the begin
367  * iterator (`BIter::value_type` for standard iterators).
368  */
369  template <typename Op, typename BIter, typename EIter>
370  [[nodiscard]] auto OpGatesSequence(Op op, BIter const begin, EIter const end);
371 
372  // --- END ---- Gate operations: generic -------------------------------------
373 
374 
375  /// Gate operations expressed as generic functions.
376  namespace GateOps {
377 
378  /**
379  * @name Binary gate operations.
380  *
381  * The return gate is the same type as the first operand.
382  */
383  /// @{
384 
385  inline constexpr auto Min = [](auto A, auto const& B){ A.Min(B); return A; };
386 
387  inline constexpr auto Max = [](auto A, auto const& B){ A.Max(B); return A; };
388 
389  inline constexpr auto Sum = [](auto A, auto const& B){ A.Sum(B); return A; };
390 
391  inline constexpr auto Mul = [](auto A, auto const& B){ A.Mul(B); return A; };
392 
393  /// @}
394 
395  } // namespace GateOps
396 
397 
398  /// @}
399  // --- END -- Gate operations ------------------------------------------------
400 
401 
402 } // namespace icarus::trigger
403 
404 
405 // =============================================================================
406 // === template implementation
407 // =============================================================================
408 // --- Discriminate
409 // -----------------------------------------------------------------------------
410 template <typename GateObj>
412  GateObj const& gate,
413  typename GateObj::OpeningCount_t threshold /* = 1U */,
414  typename GateObj::OpeningCount_t pass /* = 1U */,
415  typename GateObj::OpeningCount_t fail /* = 0U */
416  )
417 {
418  // we copy the gate hoping that the copy constructor takes care of everything
419  // else that we don't want to touch...
420  // that includes tracking information, if any, which is preserved untouched
421  auto discrGate { gate };
422 
423  auto const closeToOpen
424  = static_cast<typename GateObj::OpeningDiff_t>(pass - fail);
425 
426  // ... except for the data, which we do want to touch:
427  discrGate.clear();
428 
429  // set the starting level according to the discrimination
430  auto lastTick = discrGate.MinTick;
431  if (gate.openingCount(lastTick) < threshold) {
432  // gate starts from fail (most "normal" case)
433  discrGate.setOpeningAt(lastTick, fail);
434  }
435  else {
436  // gate starts from pass!
437  discrGate.setOpeningAt(lastTick, pass);
438 
439  // bring it to fail
440  lastTick = gate.findClose(threshold, ++lastTick);
441  if (lastTick != gate.MaxTick) discrGate.closeAt(lastTick, closeToOpen);
442  } // if started from above threshold
443 
444  // we are at a fail state now
445  while (lastTick < gate.MaxTick) {
446 
447  // bring it to pass...
448  lastTick = gate.findOpen(threshold, ++lastTick);
449  if (lastTick == gate.MaxTick) break;
450  discrGate.openAt(lastTick, closeToOpen);
451 
452  // ... back to fail...
453  lastTick = gate.findClose(threshold, ++lastTick);
454  if (lastTick == gate.MaxTick) break;
455  discrGate.closeAt(lastTick, closeToOpen);
456 
457  } // while last tick
458 
459  return discrGate;
460 } // icarus::trigger::discriminate()
461 
462 
463 // -----------------------------------------------------------------------------
464 // --- Generic binary operations A -> A op B
465 // -----------------------------------------------------------------------------
466 template <typename Op, typename AGate, typename BGate, typename... OGates>
468  (Op op, AGate A, BGate const& B, OGates const&... others)
469 {
470 
471  if constexpr(sizeof...(others) == 0U) { // two operands: end of recursion
472 
473  if constexpr(isTrackedTriggerGate_v<AGate>) {
474  if constexpr(isTrackedTriggerGate_v<BGate>) {
475  A.tracking().add(B.tracking());
476  }
477  A.gate() = op(std::move(A.gate()), gateIn(B));
478  return A;
479  } // if tracking
480  else return op(std::move(A), B);
481  }
482  else {
483  return OpGates(op, OpGates(op, std::move(A), B), others...);
484  }
485 
486 } // icarus::trigger::OpGates()
487 
488 
489 // -----------------------------------------------------------------------------
490 template <typename Op, typename GateColl>
491 auto icarus::trigger::OpGateColl(Op op, GateColl const& gates)
492  { return OpGatesSequence(std::move(op), begin(gates), end(gates)); }
493 
494 
495 // -----------------------------------------------------------------------------
496 template <typename Op, typename BIter, typename EIter>
497 auto icarus::trigger::OpGatesSequence(Op op, BIter const begin, EIter const end)
498 {
499 
500  using Gate_t = typename std::iterator_traits<BIter>::value_type;
501 
502  // if `gates` is empty return a default-constructed gate
503  if (begin == end) return Gate_t{};
504 
505  BIter iGate = begin;
506  Gate_t resGate = *iGate;
507  while (++iGate != end)
508  resGate = OpGates(std::move(op), std::move(resGate), *iGate);
509 
510  return resGate;
511 
512 } // icarus::trigger::OpGatesSequence()
513 
514 
515 // -----------------------------------------------------------------------------
516 // --- Sum
517 // -----------------------------------------------------------------------------
518 template <typename AGate, typename BGate, typename... OGates>
519 auto icarus::trigger::sumGates(AGate A, BGate const& B, OGates const&... others)
520  { return OpGates(GateOps::Sum, A, B, others...); }
521 
522 
523 // -----------------------------------------------------------------------------
524 template <typename BIter, typename EIter>
525 auto icarus::trigger::sumGatesSequence(BIter const begin, EIter const end)
526  { return OpGatesSequence(GateOps::Sum, begin, end); }
527 
528 
529 // -----------------------------------------------------------------------------
530 template <typename GateColl>
531 auto icarus::trigger::sumGates(GateColl const& gates)
532  { return sumGatesSequence(begin(gates), end(gates)); }
533 
534 
535 // -----------------------------------------------------------------------------
536 // --- Mul
537 // -----------------------------------------------------------------------------
538 template <typename AGate, typename BGate, typename... OGates>
539 auto icarus::trigger::mulGates(AGate A, BGate const& B, OGates const&... others)
540  { return OpGates(GateOps::Mul, A, B, others...); }
541 
542 
543 // -----------------------------------------------------------------------------
544 template <typename BIter, typename EIter>
545 auto icarus::trigger::mulGatesSequence(BIter const begin, EIter const end)
546  { return OpGatesSequence(GateOps::Mul, begin, end); }
547 
548 
549 // -----------------------------------------------------------------------------
550 template <typename GateColl>
551 auto icarus::trigger::mulGates(GateColl const& gates)
552  { return mulGatesSequence(begin(gates), end(gates)); }
553 
554 
555 // -----------------------------------------------------------------------------
556 // --- Max
557 // -----------------------------------------------------------------------------
558 template <typename AGate, typename BGate, typename... OGates>
559 auto icarus::trigger::maxGates(AGate A, BGate const& B, OGates const&... others)
560  { return OpGates(GateOps::Max, A, B, others...); }
561 
562 
563 // -----------------------------------------------------------------------------
564 template <typename BIter, typename EIter>
565 auto icarus::trigger::maxGatesSequence(BIter const begin, EIter const end)
566  { return OpGatesSequence(GateOps::Max, begin, end); }
567 
568 
569 // -----------------------------------------------------------------------------
570 template <typename GateColl>
571 auto icarus::trigger::maxGates(GateColl const& gates)
572  { return maxGatesSequence(begin(gates), end(gates)); }
573 
574 
575 // -----------------------------------------------------------------------------
576 // --- Min
577 // -----------------------------------------------------------------------------
578 template <typename AGate, typename BGate, typename... OGates>
579 auto icarus::trigger::minGates(AGate A, BGate const& B, OGates const&... others)
580  { return OpGates(GateOps::Min, A, B, others...); }
581 
582 
583 // -----------------------------------------------------------------------------
584 template <typename BIter, typename EIter>
585 auto icarus::trigger::minGatesSequence(BIter const begin, EIter const end)
586  { return OpGatesSequence(GateOps::Min, begin, end); }
587 
588 
589 // -----------------------------------------------------------------------------
590 template <typename GateColl>
591 auto icarus::trigger::minGates(GateColl const& gates)
592  { return minGatesSequence(begin(gates), end(gates)); }
593 
594 
595 // -----------------------------------------------------------------------------
596 
597 
598 #endif // ICARUSCODE_PMT_TRIGGER_UTILITIES_TRIGGERGATEOPERATIONS_H
auto maxGates(GateColl const &gates)
Computes the gate with the maximum opening of gates from collection.
auto maxGatesSequence(BIter const begin, EIter const end)
Computes the gate with the maximum opening of a sequence of gates.
auto mulGates(GateColl const &gates)
Multiplies all the gates in a collection.
auto OpGateColl(Op op, GateColl const &gates)
Computes the result of an operation on all gates from collection.
auto mulGatesSequence(BIter const begin, EIter const end)
Multiplies a sequence of gates.
A trigger gate data object for optical detector electronics.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
auto sumGates(GateColl const &gates)
Sums all the gates in a collection.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
AGate OpGates(Op op, AGate A, BGate const &B, OGates const &...others)
Applies an operation to two gates.
A wrapper to trigger gate objects tracking the contributions.
auto minGates(GateColl const &gates)
Computes the gate with the minimum opening of gates from collection.
auto sumGatesSequence(BIter const begin, EIter const end)
Sums a sequence of gates.
float A
Definition: dedx.py:137
auto OpGatesSequence(Op op, BIter const begin, EIter const end)
Computes the result of an operation on all gates in the sequence.
GateObj discriminate(GateObj const &gate, typename GateObj::OpeningCount_t threshold=1U, typename GateObj::OpeningCount_t pass=1U, typename GateObj::OpeningCount_t fail=0U)
Returns a discriminated version of gate.
auto minGatesSequence(BIter const begin, EIter const end)
Computes the gate with the minimum opening of a sequence of gates.
decltype(auto) gateIn(Gate &&gate)
Returns the trigger gate (a ReadoutTriggerGate) from the specified gate.