All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LVDSgates_module.cc
Go to the documentation of this file.
1 /**
2  * @file LVDSgates_module.cc
3  * @brief Combines discriminated PMT outputs into V1730 LVDS gates.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date December 13, 2019
6  */
7 
8 // ICARUS libraries
14 #include "icaruscode/IcarusObj/OpDetWaveformMeta.h" // sbn::OpDetWaveformMeta
16 
17 // LArSoft libraries
19 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
22 #include "larcorealg/CoreUtils/StdUtils.h" // util::to_string()
23 #include "larcorealg/CoreUtils/values.h" // util::const_values()
24 #include "larcorealg/CoreUtils/get_elements.h" // util::get_elements()
26 // #include "larcorealg/CoreUtils/DebugUtils.h" // lar::debug::::static_assert_on<>
27 
28 // framework libraries
29 #include "art/Framework/Services/Registry/ServiceHandle.h"
30 #include "art/Framework/Core/EDProducer.h"
31 #include "art/Framework/Core/ModuleMacros.h"
32 #include "art/Framework/Principal/Event.h"
33 #include "art/Framework/Principal/Handle.h"
34 #include "canvas/Utilities/InputTag.h"
35 #include "canvas/Utilities/Exception.h"
36 #include "messagefacility/MessageLogger/MessageLogger.h"
37 #include "fhiclcpp/types/OptionalAtom.h"
38 #include "fhiclcpp/types/Atom.h"
39 #include "fhiclcpp/types/Sequence.h"
40 #include "cetlib_except/exception.h"
41 
42 
43 // C/C++ standard libraries
44 #include <map>
45 #include <set>
46 #include <vector>
47 #include <string>
48 #include <memory> // std::unique_ptr
49 #include <utility> // std::move()
50 #include <cassert>
51 #include <cstddef> // std::size_t
52 
53 
54 //------------------------------------------------------------------------------
55 namespace icarus::trigger { class LVDSgates; }
56 
57 /**
58  * @brief Combines discriminated PMT outputs into V1730 LVDS gates.
59  *
60  * This module simulates the combination of discriminated PMT outputs
61  * by the V1730 board LVDS output.
62  *
63  *
64  * Input data products
65  * ====================
66  *
67  * * `std::vector<icarus::trigger::OpticalTriggerGateData_t>` (labels out of
68  * `TriggerGatesTag` and `Thresholds`): full sets of discriminated waveforms,
69  * each waveform possibly covering multiple optical channels,
70  * and their associations to optical waveform metadata. One set per threshold.
71  *
72  *
73  * Requirements
74  * -------------
75  *
76  * The algorithms require that the list of discriminated waveforms has in each
77  * position the waveform from the optical detector channel number matching the
78  * position (e.g. entry `0` will be the discriminated waveform from channel 0,
79  * and so forth). No gaps are allowed: if no signal is present above threshold
80  * for a certain channel, a discriminated waveform should appear for that
81  * channel, with a gate always closed.
82  *
83  *
84  * Output data products
85  * =====================
86  *
87  * * `std::vector<icarus::trigger::OpticalTriggerGateData_t>` (instance name:
88  * concatenation of input module label and instance name of the input gates;
89  * the former is omitted if it is `TriggerGatesTag`): sets of gates combined
90  * according to the configuration; one set per input threshold.
91  * * `art::Assns<icarus::trigger::OpticalTriggerGateData_t, sbn::OpDetWaveformMeta>`
92  * (instance name: same as above): associations between each
93  * produced gate and the metadata of the optical waveforms providing the
94  * original data.
95  * * `art::Assns<icarus::trigger::OpticalTriggerGateData_t, raw::OpDetWaveform>`
96  * (instance name: same as above; optional): associations between each
97  * produced gate and the optical waveforms providing the original data.
98  * It is produced only if `ProduceWaveformAssns` configuration parameter is
99  * `true`, and it relies on the assumption that there is an association
100  * available between each `sbn::OpDetWaveformMeta` and its
101  * `raw::OpDetWaveform`, produced by the same module (i.e. with the same input
102  * tag) as the one of the original `sbn::OpDetWaveformMeta` data product
103  * itself.
104  *
105  *
106  * Configuration parameters
107  * =========================
108  *
109  * A terse description of the parameters is printed by running
110  * `lar --print-description LVDSgates`.
111  *
112  * * `TriggerGatesTag` (string, default: `discrimopdaq`): name of the module
113  * instance which produced the discriminated waveforms; it must not include
114  * any instance name, as the instance names will be automatically added from
115  * `Thresholds` parameter. This value is used as module name for all
116  * thresholds which do not specify one.
117  * * `Thresholds` (list of tags, mandatory): list of the discrimination
118  * thresholds to consider. A data product containing a digital signal is
119  * read for each one of the thresholds; each threshold entry is expected
120  * to be a input tag in the form `"[ModuleLabel:]InstanceName"`, and if the
121  * module label part is not specified, the one from `TriggerGatesTag` is
122  * used as default. In this way, thresholds can be specified simply by a
123  * number, e.g. `[ 200, 400, 600 ]`, which will be translated into e.g.
124  * `"discrimopdaq:200"`, `"discrimopdaq:400"` and `"discrimopdaq:600"`,
125  * while a full specification can be also used: `[ 200, "discrim:config" ]`
126  * will turn into `"discrimopdaq:200"` and `"discrim:config"` (to specify
127  * a label with no instance name, set it ending with a colon, like in
128  * `"discrim:"`).
129  * * `ChannelPairing` (list of integral number lists): channels to combine;
130  * each element of this list is itself a list of optical detector channel
131  * numbers. The channels within each group are combined according to
132  * `CombinationMode`, resulting in a single combined gate associated to
133  * all the channels in the group.
134  * All optical detector channels *must* appear in the configuration, and
135  * each channel can be combined only in one group. Groups must not be empty.
136  * * `IgnoreChannels` (list of integral numbers, optional): ID of the optical
137  * detector channels to skip.
138  * * `CombinationMode` (either: `"disable"`, `"input1"`, `"input2"`, `"AND"`
139  * or `"OR"`): for each group of channels defined in `ChannelPairing`,
140  * the selected operation is used to combine all the channels in the group:
141  * * `disable`: all channels are discarded, and the resulting gates are
142  * all closed all the way;
143  * * `input1`: the first channel in the pairing is kept, and the others
144  * are discarded;
145  * * `input2`: the second channel in the pairing is kept, and the others
146  * are discarded;
147  * * `AND`: all channels are combined in a AND, resulting in a gate open
148  * only at the time when all the channel gates in the group are open;
149  * if there is a single channel in the group, the combined gate is a
150  * copy of it;
151  * * `OR`: all channels are combined in a OR, resulting in a gate open
152  * at every time when any of the channel gates in the group is open;
153  * if there is a single channel in the group, the combined gate is a
154  * copy of it.
155  * All pairings undergo the same operation (it is not possible, for example,
156  * disabling only one group of channels and combining the other groups with
157  * a `AND`).
158  * * `ProduceWaveformAssns` (flag, default: `true`): produce also associations
159  * between each gate and the `raw::OpDetWaveform` which contributed to it.
160  * * `LogCategory` (string): name of the output stream category for console
161  * messages (managed by MessageFacility library).
162  *
163  *
164  *
165  */
166 class icarus::trigger::LVDSgates: public art::EDProducer {
167 
168  public:
169 
171 
172  /// Available operations for the combination of channels.
173  enum class ComboMode { disable, Input1, Input2, AND, OR };
174 
175  // --- BEGIN Configuration ---------------------------------------------------
176  struct Config {
177 
178  using Name = fhicl::Name;
179  using Comment = fhicl::Comment;
180 
181  /// Selector for `CombinationMode` parameter.
183  {
184  { ComboMode::disable, "disable", "off" },
185  { ComboMode::Input1, "input1" },
186  { ComboMode::Input2, "input2" },
187  { ComboMode::AND, "AND" },
188  { ComboMode::OR, "OR" }
189  };
190 
191  fhicl::OptionalAtom<std::string> TriggerGatesTag {
192  Name("TriggerGatesTag"),
193  Comment("label of trigger gate extraction module (no instance name)")
194  };
195 
196  fhicl::Sequence<std::string> Thresholds {
197  Name("Thresholds"),
198  Comment
199  ("thresholds to consider (full tag or instance name of TriggerGatesTag)")
200  };
201 
202  fhicl::Sequence<fhicl::Sequence<raw::Channel_t>> ChannelPairing {
203  Name("ChannelPairing"),
204  Comment
205  ("grouping of optical detector channels (e.g.: [ [ 0, 2 ], [ 4, 6 ], [ 8 ], ... ])")
206  };
207 
208  fhicl::Sequence<raw::Channel_t> IgnoreChannels {
209  Name("IgnoreChannels"),
210  Comment
211  ("optical detector channels to ignore (e.g.: [ 54, 58, 67, 76, ... ])")
212  };
213 
214  fhicl::Atom<std::string> CombinationMode {
215  Name("CombinationMode"),
216  Comment("channel combination mode: " + CombinationModeSelector.optionListString())
217  };
218 
219  fhicl::Atom<bool> ProduceWaveformAssns {
220  Name("ProduceWaveformAssns"),
221  Comment
222  ("also produce gate/waveform associations together with gate/metadata"),
223  true
224  };
225 
226  fhicl::Atom<std::string> LogCategory {
227  Name("LogCategory"),
228  Comment("name of the category used for the output"),
229  "LVDSgates" // default
230  };
231 
232 
234  {
235  try {
237  }
239  throw art::Exception(art::errors::Configuration)
240  << "Invalid value for 'CombinationMode' parameter: '" << e.label()
241  << "'; valid options: "
243  }
244  } // getCombinationMode()
245 
246  }; // struct Config
247 
248  using Parameters = art::EDProducer::Table<Config>;
249 
250  // --- END Configuration -----------------------------------------------------
251 
252 
253  // --- BEGIN Constructors ----------------------------------------------------
254  explicit LVDSgates(Parameters const& config);
255 
256  // Plugins should not be copied or assigned.
257  LVDSgates(LVDSgates const&) = delete;
258  LVDSgates(LVDSgates&&) = delete;
259  LVDSgates& operator=(LVDSgates const&) = delete;
260  LVDSgates& operator=(LVDSgates&&) = delete;
261 
262  // --- END Constructors ------------------------------------------------------
263 
264 
265  // --- BEGIN Framework hooks -------------------------------------------------
266 
267  /// Fills the plots. Also extracts the information to fill them with.
268  virtual void produce(art::Event& event) override;
269 
270  // --- END Framework hooks ---------------------------------------------------
271 
272 
273  private:
274 
275  /// Type of member function to combine the current gate with another one.
278 
279  /// Reconstituted trigger gate type internally used.
282 
283 
284  // --- BEGIN Configuration variables -----------------------------------------
285 
286  /// Information for each source.
287  struct SourceInfo_t {
288  art::InputTag inputTag;
289  std::string outputInstanceName;
290  };
291 
292  /// ADC thresholds to read, and the input tag connected to their data.
293  std::map<std::string, SourceInfo_t> fADCthresholds;
294 
295  /// Pairing of optical detector channels.
296  std::vector<std::vector<raw::Channel_t>> fChannelPairing;
297  ComboMode fComboMode; ///< The operation used to combinate channels.
298 
299  std::vector<raw::Channel_t> fIgnoreChannels;
300 
301  /// Whether to produce gate/waveform associations.
303 
304  std::string fLogCategory; ///< Message facility stream category for output.
305 
306  // --- END Configuration variables -------------------------------------------
307 
308 
309  /// Completely processes the data for the specified threshold.
310  void produceThreshold(
311  art::Event& event,
313  std::string const& thresholdStr,
314  SourceInfo_t const& srcInfo
315  ) const;
316 
317  /**
318  * @brief Removes all the channel in `ignoreChannels` from `channelPairing`.
319  * @return a copy of `channelPairing` with no element from `ignoreChannels`
320  *
321  * Channel lists in the returned list may become empty.
322  */
323  std::vector<std::vector<raw::Channel_t>> removeChannels(
324  std::vector<std::vector<raw::Channel_t>> channelPairing,
325  std::vector<raw::Channel_t> const& ignoreChannels
326  ) const;
327 
328 
329  // --- BEGIN -- Combination modes --------------------------------------------
330  /// Combination function for the `disable` mode.
332  std::vector<TrackedTriggerGate_t> const&,
333  std::vector<raw::Channel_t> const& pairing
334  ) const;
335 
336  /// Combination function for the `input1` and `input2` modes.
338  std::vector<TrackedTriggerGate_t> const&,
339  std::vector<raw::Channel_t> const& pairing, std::size_t chosenIndex
340  ) const;
341 
342  /// Combination function for the `AND` and `OR` modes; `op` is from `GateOps`.
343  template <typename Op>
345  std::vector<TrackedTriggerGate_t> const& gates,
346  std::vector<raw::Channel_t> const& pairing,
347  Op combine
348  ) const;
349 
350  /// Performs the combination of a group of channels.
352  std::vector<TrackedTriggerGate_t> const& gates,
353  std::vector<raw::Channel_t> const& pairing,
354  ComboMode comboMode
355  ) const;
356  // --- END -- Combination modes ----------------------------------------------
357 
358 
359 
360  // --- BEGIN -- Checks -------------------------------------------------------
361  /// Checks the pairing configuration, throws on error.
362  /// Returns the number of configured channels.
363  unsigned int checkPairings() const;
364 
365  /// Input requirement check. Throws if requirements fail.
366  void checkInput(std::vector<TrackedTriggerGate_t> const& gates) const;
367 
368  // --- END -- Checks ---------------------------------------------------------
369 
370 
371  /// Adds the associated waveforms into the map.
372  static void UpdateWaveformMap(
374  art::Assns<TriggerGateData_t, sbn::OpDetWaveformMeta> const& assns
375  );
376 
377  /// Assembles trigger gates from `dataTag` data products in `event`.
378  static std::vector<TrackedTriggerGate_t> ReadTriggerGates(
379  art::Event const& event, art::InputTag const& dataTag,
381  );
382 
383  /// Converts a threshold string into an input tag.
384  static art::InputTag makeTag
385  (std::string const& thresholdStr, std::string const& defModule);
386 
387  /// Converts an input tag into an instance name for the corresponding output.
388  static std::string makeOutputInstanceName
389  (art::InputTag const& inputTag, std::string const& defModule);
390 
391 }; // class icarus::trigger::LVDSgates
392 
393 
394 
395 //------------------------------------------------------------------------------
396 //--- Implementation
397 //------------------------------------------------------------------------------
399  (Parameters const& config)
400  : art::EDProducer(config)
401  // configuration
402  , fChannelPairing(config().ChannelPairing())
403  , fComboMode(config().getCombinationMode())
404  , fIgnoreChannels(config().IgnoreChannels())
405  , fProduceWaveformAssns(config().ProduceWaveformAssns())
406  , fLogCategory(config().LogCategory())
407 {
408  //
409  // more complex parameter parsing
410  //
411  std::string const discrModuleLabel = config().TriggerGatesTag().value_or("");
412  for (std::string const& thresholdStr: config().Thresholds()) {
413  art::InputTag const inputTag = makeTag(thresholdStr, discrModuleLabel);
414  fADCthresholds[thresholdStr]
415  = { inputTag, makeOutputInstanceName(inputTag, discrModuleLabel) };
416  } // for all thresholds
417 
418  //
419  // configuration validation
420  //
421  unsigned int nConfiguredChannels = checkPairings();
422 
423  //
424  // configuration report (short)
425  //
426  {
427  mf::LogInfo log(fLogCategory);
428  log << nConfiguredChannels
429  << " optical channels configured to be combined into "
430  << fChannelPairing.size() << " LVDS outputs.";
431  log << "\nignored " << fIgnoreChannels.size() << " channels.";
432  log << "\nConfigured " << fADCthresholds.size() << " thresholds (ADC):";
433  for (auto const& [ threshold, srcInfo ]: fADCthresholds) {
434  log << "\n * " << threshold
435  << " (from '" << srcInfo.inputTag.encode() << "')";
436  }
437  } // local block
438 
439 
440  using icarus::trigger::OpticalTriggerGateData_t; // for convenience
441 
442  //
443  // input data declaration
444  //
445  for (auto const& [ inputTag, outName ]: util::const_values(fADCthresholds)) {
446  consumes<std::vector<OpticalTriggerGateData_t>>(inputTag);
447  consumes<art::Assns<OpticalTriggerGateData_t, sbn::OpDetWaveformMeta>>
448  (inputTag);
449  } // for
450 
451 
452  //
453  // output data declaration
454  //
455  for (auto const& [ inputTag, outName ]: util::const_values(fADCthresholds)) {
456  produces<std::vector<OpticalTriggerGateData_t>>(outName);
457  produces<art::Assns<OpticalTriggerGateData_t, raw::OpDetWaveform>>(outName);
458  if (fProduceWaveformAssns) {
459  produces<art::Assns<OpticalTriggerGateData_t, sbn::OpDetWaveformMeta>>
460  (outName);
461  }
462  } // for
463 
464 
465 } // icarus::trigger::LVDSgates::LVDSgates()
466 
467 
468 //------------------------------------------------------------------------------
469 void icarus::trigger::LVDSgates::produce(art::Event& event) {
470 
472 
473  for (auto const& [ thresholdStr, srcInfo ]: fADCthresholds) {
474 
475  produceThreshold(event, waveformMap, thresholdStr, srcInfo);
476 
477  } // for all thresholds
478 
479 } // icarus::trigger::LVDSgates::produce()
480 
481 
482 //------------------------------------------------------------------------------
483 
484 //------------------------------------------------------------------------------
486  art::Event& event,
488  std::string const& thresholdStr,
489  SourceInfo_t const& srcInfo
490 ) const {
491 
492  auto const& [ dataTag, outputInstanceName ] = srcInfo;
493 
494  mf::LogDebug(fLogCategory)
495  << "Processing threshold " << thresholdStr
496  << " from '" << dataTag.encode() << "'";
497 
498  using icarus::trigger::OpticalTriggerGateData_t; // for convenience
499 
500  std::vector<TrackedTriggerGate_t> const& gates
501  = ReadTriggerGates(event, dataTag, waveformMap);
502 
503  checkInput(gates);
504 
505  std::vector<TrackedTriggerGate_t> combinedGates;
506 
507  std::vector<std::vector<raw::Channel_t>> const cleanedChannels
509 
510  for (std::vector<raw::Channel_t> const& pairing: cleanedChannels) {
511  if (pairing.empty()) continue; // ???
512 
513  combinedGates.push_back(combineChannels(gates, pairing, fComboMode));
514 
515  } // for
516 
517  // transform the data; after this line, `gates` is not usable any more
518  art::PtrMaker<OpticalTriggerGateData_t> const makeGatePtr
519  (event, outputInstanceName);
520  auto [ outputGates, outputAssns ]
522  (std::move(combinedGates), makeGatePtr, waveformMap);
523 
524  mf::LogTrace(fLogCategory)
525  << "Threshold " << thresholdStr << " ('" << dataTag.encode() << "'): "
526  << gates.size() << " input channels, "
527  << outputGates.size() << " output channels (+"
528  << outputAssns.size() << " associations to waveforms) into '"
529  << moduleDescription().moduleLabel() << ":" << outputInstanceName << "'"
530  ;
531 
532 
533  if (fProduceWaveformAssns) {
534 
535  // produce one gate-waveform association for each gate-metadata one;
536  // do it now while the gate/metadata association is still locally available
537  icarus::trigger::OpDetWaveformMetaMatcher waveformMetaMatcher{ event };
538  art::Assns<OpticalTriggerGateData_t, raw::OpDetWaveform> outputWaveAssns;
539  for (auto const [ gatePtr, metaPtr ]: outputAssns)
540  outputWaveAssns.addSingle(gatePtr, waveformMetaMatcher(metaPtr));
541 
542  event.put(
543  std::make_unique<art::Assns<OpticalTriggerGateData_t, raw::OpDetWaveform>>
544  (std::move(outputWaveAssns)),
545  outputInstanceName
546  );
547 
548  } // if fProduceWaveformAssns
549 
550  event.put(
551  std::make_unique<std::vector<OpticalTriggerGateData_t>>
552  (std::move(outputGates)),
553  outputInstanceName
554  );
555  event.put(
556  std::make_unique<art::Assns<OpticalTriggerGateData_t, sbn::OpDetWaveformMeta>>
557  (std::move(outputAssns)),
558  outputInstanceName
559  );
560 
561 } // icarus::trigger::LVDSgates::produceThreshold()
562 
563 
564 //------------------------------------------------------------------------------
566  std::vector<TrackedTriggerGate_t> const& gates,
567  std::vector<raw::Channel_t> const& pairing,
568  ComboMode comboMode
569 ) const -> TrackedTriggerGate_t {
570 
571  namespace GateOps = icarus::trigger::GateOps;
572 
573  switch (comboMode) {
574  case ComboMode::disable:
575  return discardChannels(gates, pairing);
576  case ComboMode::AND:
577  return binaryCombineChannel(gates, pairing, GateOps::Min);
578  case ComboMode::OR:
579  return binaryCombineChannel(gates, pairing, GateOps::Max);
580  case ComboMode::Input1:
581  return selectChannel(gates, pairing, 0U);
582  case ComboMode::Input2:
583  return selectChannel(gates, pairing, 1U);
584  default:
585  throw art::Exception(art::errors::LogicError)
586  << "Unexpected combination mode (#" << static_cast<int>(comboMode)
587  << ").\n";
588  } // switch(comboMode)
589 } // icarus::trigger::LVDSgates::combineChannels()
590 
591 
592 //------------------------------------------------------------------------------
593 std::vector<std::vector<raw::Channel_t>> icarus::trigger::LVDSgates::removeChannels(
594  std::vector<std::vector<raw::Channel_t>> channelPairing,
595  std::vector<raw::Channel_t> const& ignoreChannels
596  ) const {
597 
598  for (std::vector<raw::Channel_t>& channels: channelPairing) {
599  for (unsigned int j = channels.size(); j-- > 0; ) {
600  std::vector<raw::Channel_t>::const_iterator const it
601  = find(ignoreChannels.begin(), ignoreChannels.end(), channels[j]);
602  if (it != fIgnoreChannels.end()) {
603  channels.erase(channels.begin() + j);
604  }
605  }
606  }
607 
608  return channelPairing;
609 
610 } // icarus::trigger::LVDSgates::removeChannels()
611 
612 
613 //------------------------------------------------------------------------------
615  std::vector<TrackedTriggerGate_t> const& gates,
616  std::vector<raw::Channel_t> const& pairing
617 ) const -> TrackedTriggerGate_t {
619  for (raw::Channel_t channel: pairing) gate.gate().addChannel(channel);
620  for (auto const& srcGate: gates) gate.tracking().add(srcGate.tracking());
621  return gate;
622 } // icarus::trigger::LVDSgates::combineChannels()
623 
624 
625 //------------------------------------------------------------------------------
627  std::vector<TrackedTriggerGate_t> const& gates,
628  std::vector<raw::Channel_t> const& pairing,
629  std::size_t chosenIndex
630 ) const -> TrackedTriggerGate_t {
631  // requiring that gates are at an index matching their channel number
632  TrackedTriggerGate_t gate { gates[pairing[chosenIndex]] };
633  for (raw::Channel_t channel: pairing) {
634  mf::LogTrace(fLogCategory) << "Input: " << gates[channel].gate();
635  gate.gate().addChannel(channel);
636  }
637  mf::LogTrace(fLogCategory) << "Output: " << gate.gate();
638  for (auto const& srcGate: gates) gate.tracking().add(srcGate.tracking());
639  return gate;
640 } // icarus::trigger::LVDSgates::selectChannel()
641 
642 
643 //------------------------------------------------------------------------------
644 template <typename Op>
646  std::vector<TrackedTriggerGate_t> const& gates,
647  std::vector<raw::Channel_t> const& pairing,
648  Op combine
649 ) const -> TrackedTriggerGate_t {
650  if (pairing.empty()) return discardChannels(gates, pairing);
651 
652 #if 1
653 
654  auto byIndex = [&gates](std::size_t index) -> TrackedTriggerGate_t const&
655  { return gates[index]; };
656 
657 # if 0
658  // C++20: the following loses the debug output:
659 
661  (combine, pairing | std::ranges::views::transform(byIndex));
662 # else
663 
665  (combine, util::make_transformed_span(pairing, byIndex));
666 
667 # endif // 0
668 
669 #else
670  auto iChannel = pairing.begin();
671  auto cend = pairing.end();
672 
673  // requiring that gates are at an index matching their channel number
674  TrackedTriggerGate_t gate { gates[*iChannel] };
675 
676  mf::LogTrace(fLogCategory) << "Input: " << gates[*iChannel].gate();
677  while (++iChannel != cend) {
678 
679  mf::LogTrace(fLogCategory) << "Input: " << gates[*iChannel].gate();
680  gate = icarus::trigger::OpGates(combine, gate, gates[*iChannel]);
681 
682  } // while
683  mf::LogTrace(fLogCategory) << "Output: " << gate.gate();
684 
685  return gate;
686 #endif // 0
687 } // icarus::trigger::LVDSgates::binaryCombineChannel()
688 
689 
690 //------------------------------------------------------------------------------
692 
693  //
694  // collect all the errors first
695  //
696  auto const& geom = *(lar::providerFrom<geo::Geometry>());
697 
698 
699  // collect configured and duplicate channel numbers
700  unsigned int nEmptyGroups = 0U;
701  std::set<raw::Channel_t> configuredChannels, duplicateChannels;
702  for (auto const& pairing: fChannelPairing) {
703  if (pairing.empty()) {
704  ++nEmptyGroups;
705  continue;
706  }
707  for (raw::Channel_t channel: pairing) {
708  if (!configuredChannels.insert(channel).second)
709  duplicateChannels.insert(channel);
710  } // for channel
711  } // for pairing
712 
713  // collect invalid channel numbers
714  std::vector<raw::Channel_t> invalidChannels;
715  for (raw::Channel_t channel: configuredChannels) {
716  if (!geom.IsValidOpChannel(channel)) invalidChannels.push_back(channel);
717  } // for configured channels
718 
719  // collect missing channels
720  auto const endChannel = geom.MaxOpChannel() + 1U;
721  std::vector<raw::Channel_t> missingChannels;
722  for (auto channel: util::counter<raw::Channel_t>(endChannel)) {
723  if (!geom.IsValidOpChannel(channel)) continue;
724  if (configuredChannels.count(channel) > 0U) continue;
725  missingChannels.push_back(channel);
726  } // for channel
727 
728  // no error? good we are
729  if (invalidChannels.empty()
730  && missingChannels.empty()
731  && duplicateChannels.empty()
732  && (nEmptyGroups == 0U)
733  ) {
734  return configuredChannels.size();
735  }
736 
737  // error? good we are not
738  art::Exception e(art::errors::Configuration);
739  e << "The pairing configuration of " << configuredChannels.size()
740  << " optical channels in `ChannelPairing` presents the following errors.\n";
741  if (!invalidChannels.empty()) {
742  auto iChannel = invalidChannels.cbegin();
743  auto const cend = invalidChannels.cend();
744  e
745  << invalidChannels.size()
746  << " channel numbers do not represent valid channels: " << *iChannel;
747  while (++iChannel != cend) e << ", " << *iChannel;
748  e << ".\n";
749  } // if invalid channels
750 
751  if (!missingChannels.empty()) {
752  auto iChannel = missingChannels.cbegin();
753  auto const cend = missingChannels.cend();
754  e
755  << missingChannels.size()
756  << " channels do not appear in the configuration: " << *iChannel;
757  while (++iChannel != cend) e << ", " << *iChannel;
758  e << ".\n";
759  } // if missing channels
760 
761  if (!duplicateChannels.empty()) {
762  auto iChannel = duplicateChannels.cbegin();
763  auto const cend = duplicateChannels.cend();
764  e
765  << duplicateChannels.size()
766  << " channels are specified more than once: " << *iChannel;
767  while (++iChannel != cend) e << ", " << *iChannel;
768  e << ".\n";
769  } // if duplicate channels
770 
771  if (nEmptyGroups > 0U) {
772  e << nEmptyGroups << " channel groups are empty.";
773  }
774 
775  throw e;
776 } // icarus::trigger::LVDSgates::checkPairings()
777 
778 
779 //------------------------------------------------------------------------------
781  (std::vector<TrackedTriggerGate_t> const& gates) const
782 {
783  /*
784  * check that
785  * * each gate has a single channel
786  * * each gate is in the position matching its channel number
787  */
788 
790 
791  for (auto const& [ iGate, gate ]: util::enumerate(gatesIn(gates))) {
792  // gate is a OpticalTriggerGateData_t
793 
794  auto const expectedChannel = static_cast<raw::Channel_t>(iGate);
795 
796  if (gate.nChannels() != 1U) {
797  cet::exception e("LVDSgates");
798  e << "Requirement failure: gate #" << iGate << " includes ";
799  if (!gate.hasChannels())
800  e << "no channels";
801  else {
802  auto const& channels = gate.channels();
803  auto iChannel = channels.begin();
804  auto const cend = channels.end();
805  e << gate.nChannels() << " channels (" << *iChannel;
806  while (++iChannel != cend) e << ", " << *iChannel;
807  e << ")";
808  }
809  e << " should have exactly one channel (" << expectedChannel << ").\n";
810  throw e;
811  }
812 
813  if (gate.channel() != expectedChannel) {
814  throw cet::exception("LVDSgates")
815  << "Requirement failure: gate #" << iGate << " gate covers channel "
816  << gate.channel() << ", should cover " << expectedChannel
817  << " instead.\n";
818  }
819 
820  } // for
821 
822  MF_LOG_TRACE(fLogCategory)
823  << "LVDSgates[" << moduleDescription().moduleLabel() << "]: input checked.";
824 
825 } // icarus::trigger::LVDSgates::checkInput()
826 
827 
828 //------------------------------------------------------------------------------
831  art::Assns<TriggerGateData_t, sbn::OpDetWaveformMeta> const& assns
832 ) {
833 
834  for (art::Ptr<sbn::OpDetWaveformMeta> const& wave: util::get_elements<1U>(assns))
835  map.emplace(wave.get(), wave);
836 
837 } // icarus::trigger::LVDSgates::UpdateWaveformMap()
838 
839 
840 //------------------------------------------------------------------------------
842  art::Event const& event,
843  art::InputTag const& dataTag,
845 ) -> std::vector<TrackedTriggerGate_t> {
847 
848  auto const& assns =
849  event.getProduct<art::Assns<OpticalTriggerGateData_t, sbn::OpDetWaveformMeta>>
850  (dataTag);
851 
852  UpdateWaveformMap(waveformMap, assns);
853 
855  (event.getProduct<std::vector<OpticalTriggerGateData_t>>(dataTag), assns);
856 
857 } // icarus::trigger::LVDSgates::ReadTriggerGates()
858 
859 
860 //------------------------------------------------------------------------------
862  (std::string const& thresholdStr, std::string const& defModule)
863 {
864  return (thresholdStr.find(':') != std::string::npos)
865  ? art::InputTag{ thresholdStr }
866  : defModule.empty()
867  ? throw (art::Exception(art::errors::Configuration)
868  << "No default module label (`TriggerGatesTag`) specified"
869  ", and it's needed for threshold '"
870  << thresholdStr << "'.\n")
871  : art::InputTag{ defModule, thresholdStr }
872  ;
873 } // icarus::trigger::LVDSgates::makeTag()
874 
875 
876 //------------------------------------------------------------------------------
878  (art::InputTag const& inputTag, std::string const& defModule)
879 {
880  return (inputTag.label() == defModule)
881  ? inputTag.instance()
882  : inputTag.instance().empty()
883  ? inputTag.label(): inputTag.label() + inputTag.instance()
884  ;
885 } // icarus::trigger::LVDSgates::makeTag()
886 
887 
888 //------------------------------------------------------------------------------
889 DEFINE_ART_MODULE(icarus::trigger::LVDSgates)
890 
891 
892 //------------------------------------------------------------------------------
BEGIN_PROLOG BeamGateDuration pmtthr physics producers trigtilewindowORS Thresholds
art::EDProducer::Table< Config > Parameters
Utilities related to art service access.
fhicl::Sequence< std::string > Thresholds
Utilities for the conversion of trigger gate data formats.
static constexpr Sample_t transform(Sample_t sample)
Helper to select an string option among a set of allowed choices.
Definition of util::get_elements() and util::get_const_elements().
static art::InputTag makeTag(std::string const &thresholdStr, std::string const &defModule)
Converts a threshold string into an input tag.
TrackedTriggerGate_t binaryCombineChannel(std::vector< TrackedTriggerGate_t > const &gates, std::vector< raw::Channel_t > const &pairing, Op combine) const
Combination function for the AND and OR modes; op is from GateOps.
A wrapper to trigger gate objects tracking the input of operations.
util::MultipleChoiceSelection< ComboMode > const CombinationModeSelector
Selector for CombinationMode parameter.
fhicl::Sequence< fhicl::Sequence< raw::Channel_t > > ChannelPairing
Option_t const & parse(std::string const &label) const
Returns the option matching the specified label.
auto gatesIn(TrackingGateColl &trackingGates)
void produceThreshold(art::Event &event, icarus::trigger::OpDetWaveformMetaDataProductMap_t &waveformMap, std::string const &thresholdStr, SourceInfo_t const &srcInfo) const
Completely processes the data for the specified threshold.
Derivative information from raw::OpDetWaveform data.
std::vector< icarus::trigger::OpticalTriggerGateData_t > transformIntoOpticalTriggerGate(Gates &&gates)
Returns the trigger gates in serializable format.
decltype(auto) const_values(Coll &&coll)
Range-for loop helper iterating across the constant values of the specified collection.
TrackedTriggerGate_t discardChannels(std::vector< TrackedTriggerGate_t > const &, std::vector< raw::Channel_t > const &pairing) const
Combination function for the disable mode.
std::string optionListString(std::string const &sep=", ") const
Returns a string with the (main) name of all options.
fhicl::Sequence< raw::Channel_t > IgnoreChannels
void add(TrackedType tracked)
Add an object to the list of tracked objects, if it&#39;s not present yet.
auto cend(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:579
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
static std::string makeOutputInstanceName(art::InputTag const &inputTag, std::string const &defModule)
Converts an input tag into an instance name for the corresponding output.
auto OpGateColl(Op op, GateColl const &gates)
Computes the result of an operation on all gates from collection.
ComboMode
Available operations for the combination of channels.
TrackedTriggerGate_t combineChannels(std::vector< TrackedTriggerGate_t > const &gates, std::vector< raw::Channel_t > const &pairing, ComboMode comboMode) const
Performs the combination of a group of channels.
virtual void produce(art::Event &event) override
Fills the plots. Also extracts the information to fill them with.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Access the description of detector geometry.
TrackingInfo const & tracking() const
Returns the tracking information.
void checkInput(std::vector< TrackedTriggerGate_t > const &gates) const
Input requirement check. Throws if requirements fail.
LVDSgates & operator=(LVDSgates const &)=delete
Logical multi-level gate associated to one or more readout channels.
static std::vector< TrackedTriggerGate_t > ReadTriggerGates(art::Event const &event, art::InputTag const &dataTag, icarus::trigger::OpDetWaveformMetaDataProductMap_t &waveformMap)
Assembles trigger gates from dataTag data products in event.
Object to facilitate the discovery of the raw::OpDetWaveform a sbn::OpDetWaveformMeta objects comes f...
bool fProduceWaveformAssns
Whether to produce gate/waveform associations.
auto make_transformed_span(BIter begin, EIter end, Op &&op)
Definition: span.h:294
Simple type definitions for trigger algorithms.
A trigger gate data object for optical detector electronics.
icarus::trigger::ReadoutTriggerGate< TriggerGateTick_t, TriggerGateTicks_t, raw::Channel_t > OpticalTriggerGateData_t
Type of trigger gate data serialized into art data products.
Utilities for the conversion of trigger gate data formats.
BEGIN_PROLOG vertical distance to the surface Name
AGate OpGates(Op op, AGate A, BGate const &B, OGates const &...others)
Applies an operation to two gates.
fhicl::Atom< std::string > LogCategory
Utilities for matching raw::OpDetWaveform and their sbn::OpDetWaveformMeta.
TriggerGate_t const & gate() const &
Returns the enclosed gate.
Logical multi-level gate associated to one or more waveforms.
Functions pulling in STL customization if available.
do i e
fhicl::Atom< std::string > CombinationMode
A simple alias for a most commonly used TrackedTriggerGate type.
std::vector< icarus::trigger::TrackedOpticalTriggerGate< OpDetInfo > > FillTriggerGates(std::vector< icarus::trigger::OpticalTriggerGateData_t > const &gates, art::Assns< icarus::trigger::OpticalTriggerGateData_t, OpDetInfo > const &gateToWaveformInfo)
Creates a gate object out of trigger gate data products.
std::map< std::string, SourceInfo_t > fADCthresholds
ADC thresholds to read, and the input tag connected to their data.
Combines discriminated PMT outputs into V1730 LVDS gates.
std::string fLogCategory
Message facility stream category for output.
std::vector< std::vector< raw::Channel_t > > removeChannels(std::vector< std::vector< raw::Channel_t >> channelPairing, std::vector< raw::Channel_t > const &ignoreChannels) const
Removes all the channel in ignoreChannels from channelPairing.
LVDSgates(Parameters const &config)
Definition of util::values() and util::const_values().
fhicl::OptionalAtom< std::string > TriggerGatesTag
std::vector< std::vector< raw::Channel_t > > fChannelPairing
Pairing of optical detector channels.
static void UpdateWaveformMap(icarus::trigger::OpDetWaveformMetaDataProductMap_t &map, art::Assns< TriggerGateData_t, sbn::OpDetWaveformMeta > const &assns)
Adds the associated waveforms into the map.
TrackedTriggerGate_t selectChannel(std::vector< TrackedTriggerGate_t > const &, std::vector< raw::Channel_t > const &pairing, std::size_t chosenIndex) const
Combination function for the input1 and input2 modes.
util::DataProductPointerMap_t< sbn::OpDetWaveformMeta > OpDetWaveformMetaDataProductMap_t
Map util::DataProductPointerMap_t for sbn::OpDetWaveformMeta objects.
OpticalTriggerGateData_t GateData_t
Type for gate data access.
ComboMode fComboMode
The operation used to combinate channels.
art framework interface to geometry description
OpticalTriggerGate &(OpticalTriggerGate::*)(OpticalTriggerGate const &) BinaryCombinationFunc_t
Type of member function to combine the current gate with another one.
unsigned int checkPairings() const
std::vector< raw::Channel_t > fIgnoreChannels