All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TriggerDecoderV2_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////
2 //
3 // File: TriggerDecoderV2_tool.cc
4 //
5 // Description: Extracting ICARUS trigger fragment information from new fragment necessary after trigger information
6 //
7 // Author: Jacob Zettlemoyer, FNAL
8 //
9 ///////////////////////////////////////////////
10 
11 #include "art/Framework/Core/EDProducer.h"
12 #include "art/Framework/Core/ConsumesCollector.h"
13 #include "art/Framework/Core/ProducesCollector.h"
14 #include "art/Framework/Principal/Run.h"
15 #include "art/Framework/Principal/Event.h"
16 #include "art/Framework/Principal/Handle.h"
17 #include "art/Framework/Services/Registry/ServiceHandle.h"
18 #include "art/Persistency/Common/PtrMaker.h"
19 #include "art/Utilities/ToolMacros.h"
20 #include "cetlib/cpu_timer.h"
21 #include "fhiclcpp/ParameterSet.h"
22 #include "messagefacility/MessageLogger/MessageLogger.h"
23 
26 #include "lardataalg/Utilities/quantities/spacetime.h" // util::quantities::nanosecond
27 #include "lardataobj/RawData/ExternalTrigger.h" //JCZ: TBD, placeholder for now to represent the idea
28 #include "lardataobj/RawData/TriggerData.h" // raw::Trigger
29 #include "lardataobj/Simulation/BeamGateInfo.h" //JCZ:, another placeholder I am unsure if this and above will be combined at some point into a dedicated object
30 
31 #include "sbndaq-artdaq-core/Overlays/ICARUS/ICARUSTriggerV2Fragment.hh"
32 
40 #include "icarusalg/Utilities/BinaryDumpUtils.h" // hexdump() DEBUG
41 
42 #include <cstdlib>
43 #include <iostream>
44 #include <iomanip> // std::setw(), std::setfill()
45 #include <string_view>
46 #include <memory>
47 #include <array>
48 
49 
50 using namespace std::string_literals;
51 
52 namespace daq
53 {
54 
55  /**
56  * @brief Tool decoding the trigger information from DAQ.
57  *
58  * Produces:
59  * * `std::vector<raw::ExternalTrigger>` containing the absolute trigger time
60  * stamp from the White Rabbit system, and a trigger count;
61  * it always includes a single entry (zero _might_ be supported).
62  * * `std::vector<raw::Trigger>` containing:
63  * * `TriggerTime()`: the relative time of the trigger as reported in the
64  * White Rabbit timestamp, measured in the
65  * @ref DetectorClocksElectronicsTime "electronics time scale" (for
66  * ICARUS it will always be
67  * `detinfo::DetectorClocksData::TriggerTime()`).
68  * * `BeamGateTime()`: relative time of the announced arrival of the beam,
69  * also in @ref DetectorClocksElectronicsTime "electronics time scale".
70  * * `TriggerCount()`: the trigger count from the beginning of the run.
71  * * `TriggerBits()`: includes the beam(s) with an open gate when the
72  * trigger happened (currently only one beam gate per trigger);
73  * definitions are in `sbn::beamType` namespace.
74  *
75  * It always includes a single entry (zero _might_ be supported).
76  * * `std::vector<sim::BeamGateInfo>` containing information on the "main"
77  * beam gate associated to each trigger (a way to say that if by any
78  * chance there are more than one bits set for the trigger, this gate
79  * will pick only one of them):
80  * * `Start()`: relative time of the announced arrival of the beam, in
81  * @ref DetectorClocksSimulationTime "simulation time scale".
82  * * `Width()`: duration of the gate, in nanoseconds; read from trigger
83  * configuration if specified (`TrigConfigLabel`), set to `0`
84  * otherwise.
85  * * `BeamType()`: the type of the beam gate being described (BNB, NuMI).
86  * * `sbn::ExtraTriggerInfo`: the most complete collection of information,
87  * duplicating also some from the other data products.
88  * Note that differently from the usual, this is a _single object_, not
89  * a collection; also, this data product has no instance name.
90  * The information already available includes:
91  * * `sourceType`: the type of beam or trigger source, a value from
92  * `sbn::triggerSource` (equivalent to `raw::Trigger::TriggerBits()`,
93  * but in the form of an enumerator rather than a bit mask).
94  * Also called gate type.
95  * * `triggerTimestamp`: same as `raw::ExternalTrigger::GetTrigTime()`
96  * (nanoseconds from the Epoch, Coordinated Universal Time).
97  * * `beamGateTimestamp`: absolute time of the beam gate opening as
98  * reported by the trigger hardware, directly comparable with
99  * `triggerTimestamp` (same scale and unit).
100  * * `enableGateTimestamp`: absolute time of the enable gate opening as
101  * reported by the trigger hardware, directly comparable with
102  * `triggerTimestamp` (same scale and unit). This is the gate that
103  * enables the generation of trigger primitives and the off-spill
104  * readout of PMT. Its duration can be found in the trigger
105  * configuration data product (`icarus::TriggerConfiguration`).
106  * * `triggerID`: same as `raw::ExternalTrigger::GetTrigID()`. Should
107  * match the event number.
108  * * `gateID`: the count of gates since the beginning of the run, as
109  * reported by the trigger hardware.
110  * * `gateCountFromPreviousTrigger`: number of gates since the last
111  * trigger: specifically, if this trigger is e.g. from off-beam BNB
112  * gate, this is the number of off-beam BNB gates from the last
113  * off-beam BNB trigger (minimum number is `1`, since that gate is
114  * included).
115  * * `previousTriggerTimestamp`: absolute timestamp of the previous
116  * trigger from this source. For example, if this trigger is from an
117  * off-beam BNB gate, this represents the previous off-beam BNB
118  * trigger.
119  * * `gateCount`: total number of gates of this type (triggered or not)
120  * from the beginning of the run (minimum `1` since this one is
121  * included). For example, if this trigger is from an off-beam BNB
122  * gate, this is the number of off-beam BNB gates from the beginning
123  * of the run.
124  * * `triggerCount`: total number of triggers from gates of this type
125  * from the beginning of the run (minimum `1` since this one is
126  * included). For example, if this trigger is from an off-beam BNB
127  * gate, this is the number of off-beam BNB triggers from the
128  * beginning of the run.
129  * * `anyTriggerCountFromPreviousTrigger`: number of triggers that
130  * occurred since the last trigger of this time (the one with
131  * timestamp `previousTriggerTimestamp`). For example, if this trigger
132  * is from an off-beam BNB gate, this is the number of triggers from
133  * any gate (including also e.g. off-beam NuMI, BNB, calibration...)
134  * that occurred from the previous off-beam BNB trigger.
135  * * `anyGateCountFromAnyPreviousTrigger`: how many gates have passed
136  * since the last trigger (reported by `anyPreviousTriggerTimestamp`).
137  * The minimum value is `1`.
138  * * `anyPreviousTriggerTimestamp`: absolute timestamp of the previous
139  * trigger (from any source). For example, if this trigger is from an
140  * off-beam BNB gate, and the previous was from a NuMI gate, this
141  * represents that previous (NuMI) trigger.
142  * * `anyPreviousTriggerSourceType`: the type of gate of the previous
143  * trigger (the one reported by `anyPreviousTriggerTimestamp`).
144  * * `WRtimeToTriggerTime` (nanoseconds): correction added to the
145  * GPS/White Rabbit time to obtain the trigger timestamp (normally
146  * it's the conversion from TAI to NTP timestamps).
147  * * `triggerLocationBits`: whether the trigger came from the east or west
148  * cryostat (currently the triggers combine the two opposite PMT
149  * walls, so there is no TPC-level granularity).
150  * * `cryostats`: information per cryostat (east first, then west).
151  * Note however that only the cryostats that are mentioned in
152  * `triggerLocationBits` have the information filled.
153  * * `triggerCount`: number of triggers in this cryostat fired during
154  * the trigger window; only the first one becomes the global
155  * trigger, but we still keep the count of how many happen.
156  * Its value is `0` when trigger happened from elsewhere.
157  * * `LVDSstatus`: information per PMT wall (i.e. TPC; east first, then
158  * west) of the LVDS signals of the discriminated PMT pairs at the
159  * time of the global trigger. All bits are `0` when trigger
160  * happened elsewhere. Otherwise, the encoding is currently
161  * implemented in terms of hardware connectors as follows:
162  * * east wall: `00<C3P2><C3P1><C3P0>00<C2P2><C2P1><C2P0>`
163  * * west wall: `00<C1P2><C1P1><C1P0>00<C0P2><C0P1><C0P0>`
164  *
165  * For the expected matching with PMT, see the documentation of
166  * `sbn::ExtraTriggerInfo::CryostatInfo::LVDSstatus`.
167  *
168  * Information may be missing. If a count is not available, its value is
169  * set to `0` (which is an invalid value because their valid range starts
170  * with `1` since they include the current event), and if a timestamp is
171  * not available it is set to `sbn::ExtraTriggerInfo::NoTimestamp`; these
172  * two conditions can be checked with static methods
173  * `sbn::ExtraTriggerInfo::isValidTimestamp()`
174  * and `sbn::ExtraTriggerInfo::isValidCount()` respectively.
175  *
176  * Besides the main data product (empty instance name) an additional
177  * `std::vector<raw::ExternalTrigger>` data product with instance name
178  * `"previous"` is also produced, which relays the same kind of information
179  * but for the _previous_ trigger. This information also comes from the
180  * trigger DAQ. If no previous trigger is available, this collection will be
181  * empty.
182  *
183  *
184  * Timestamps and corrections
185  * ---------------------------
186  *
187  * The reference trigger time is driven by the trigger fragment time, which
188  * is expected to have been derived from the actual trigger time from the
189  * White Rabbit system properly corrected to UTC by the board reader.
190  *
191  * All absolute timestamps are corrected to be on that same scale.
192  * The absolute timestamps related to the White Rabbit time are added an
193  * offset to achieve this correction; this offset is stored in the data
194  * product (`sbn::ExtraTriggerInfo::WRtimeToTriggerTime`).
195  *
196  *
197  * Configuration
198  * --------------
199  *
200  * * `TrigConfigLabel` (input tag, mandatory): tag of the trigger
201  * configuration data product (see `icarus::TriggerConfigurationExtractor`
202  * module) to be used. Specifying its tag is mandatory, but if it is
203  * explicitly specified empty, the decoder will try to work around its
204  * absence.
205  * * `DiagnosticOutput` (flag, default: `false`): prints on console trigger
206  * data diagnostics (including a full dump of the parsed content).
207  * * `Debug` (flag, default: `false`): prints on console decoding debug
208  * information, including a dump of the trigger data fragment.
209  *
210  */
211  class TriggerDecoder : public IDecoder
212  {
215  public:
216  explicit TriggerDecoder(fhicl::ParameterSet const &pset);
217 
218  virtual void consumes(art::ConsumesCollector& collector) override;
219  virtual void produces(art::ProducesCollector&) override;
220  virtual void configure(const fhicl::ParameterSet&) override;
221  virtual void initializeDataProducts() override;
222  virtual void setupRun(art::Run const& run) override;
223  virtual void process_fragment(const artdaq::Fragment &fragment) override;
224  virtual void outputDataProducts(art::Event &event) override;
225 
226  private:
227  using TriggerCollection = std::vector<raw::ExternalTrigger>;
228  using TriggerPtr = std::unique_ptr<TriggerCollection>;
229  using RelativeTriggerCollection = std::vector<raw::Trigger>;
230  using BeamGateInfoCollection = std::vector<sim::BeamGateInfo>;
231  using BeamGateInfoPtr = std::unique_ptr<BeamGateInfoCollection>;
232  using ExtraInfoPtr = std::unique_ptr<sbn::ExtraTriggerInfo>;
233  TriggerPtr fTrigger;
234  TriggerPtr fPrevTrigger;
235  std::unique_ptr<RelativeTriggerCollection> fRelTrigger;
236  ExtraInfoPtr fTriggerExtra;
237  BeamGateInfoPtr fBeamGateInfo;
238  art::InputTag fTriggerConfigTag; ///< Data product with hardware trigger configuration.
239  bool fDiagnosticOutput; ///< Produces large number of diagnostic messages, use with caution!
240  bool fDebug; ///< Use this for debugging this tool
241 
242  long fLastEvent = 0;
243 
244  detinfo::DetectorTimings const fDetTimings; ///< Detector clocks and timings.
245 
246  /// Cached pointer to the trigger configuration of the current run, if any.
247  icarus::TriggerConfiguration const* fTriggerConfiguration = nullptr;
248 
249 
250  /// Creates a `ICARUSTriggerInfo` from a generic fragment.
251  icarus::ICARUSTriggerV2Fragment makeTriggerFragment
252  (artdaq::Fragment const& fragment) const;
253 
254  /// Parses the trigger data packet with the "standard" parser.
255  icarus::ICARUSTriggerInfo parseTriggerString(std::string_view data) const;
256 
257  /// Parses the trigger data packet with a CSV parser.
258  icarus::KeyValuesData parseTriggerStringAsCSV
259  (std::string const& data) const;
260 
261  /// Name of the data product instance for the current trigger.
262  static std::string const CurrentTriggerInstanceName;
263 
264  /// Name of the data product instance for the previous trigger.
265  static std::string const PreviousTriggerInstanceName;
266 
267  static constexpr double UnknownBeamTime = std::numeric_limits<double>::max();
268 
269  /// Codes of gate types from the trigger hardware.
270  struct TriggerGateTypes {
271  static constexpr int BNB { 1 };
272  static constexpr int NuMI { 2 };
273  static constexpr int OffbeamBNB { 3 };
274  static constexpr int OffbeamNuMI { 4 };
275  static constexpr int Calib { 5 };
276  };
277 
278  static constexpr nanoseconds BNBgateDuration { 1600. };
279  static constexpr nanoseconds NuMIgateDuration { 9500. };
280 
281  static std::string_view firstLine
282  (std::string const& s, std::string const& endl = "\0\n\r"s);
283 
284  /// Combines second and nanosecond counts into a 64-bit timestamp.
285  static std::uint64_t makeTimestamp(unsigned int s, unsigned int ns)
286  { return s * 1000000000ULL + ns; }
287  /// Returns the difference `a - b`.
288  static long long int timestampDiff(std::uint64_t a, std::uint64_t b)
289  { return static_cast<long long int>(a) - static_cast<long long int>(b); }
290 
291  /// Encodes the `connectorWord` LVDS bits from the specified `cryostat`
292  /// and `connector` into the format required by `sbn::ExtraTriggerInfo`.
293  static std::uint64_t encodeLVDSbits
294  (short int cryostat, short int connector, std::uint64_t connectorWord);
295 
296  /// Returns the beam type corresponding to the specified trigger `source`.
297  static sim::BeamType_t simGateType(sbn::triggerSource source);
298 
299  };
300 
301 
302  std::string const TriggerDecoder::CurrentTriggerInstanceName {};
303  std::string const TriggerDecoder::PreviousTriggerInstanceName { "previous" };
304 
305 
306  TriggerDecoder::TriggerDecoder(fhicl::ParameterSet const &pset)
307  : fDetTimings
308  { art::ServiceHandle<detinfo::DetectorClocksService>()->DataForJob() }
309  {
310  this->configure(pset);
311  }
312 
313 
314  void TriggerDecoder::consumes(art::ConsumesCollector& collector) {
315  collector.consumes<icarus::TriggerConfiguration, art::InRun>
317  }
318 
319  void TriggerDecoder::produces(art::ProducesCollector& collector)
320  {
321  collector.produces<TriggerCollection>(CurrentTriggerInstanceName);
322  collector.produces<TriggerCollection>(PreviousTriggerInstanceName);
326  }
327 
328 
329  void TriggerDecoder::configure(fhicl::ParameterSet const &pset)
330  {
331  fTriggerConfigTag = pset.get<std::string>("TrigConfigLabel");
332  fDiagnosticOutput = pset.get<bool>("DiagnosticOutput", false);
333  fDebug = pset.get<bool>("Debug", false);
334  if (pset.has_key("TimeOffset")) {
335  if (auto offset = pset.get<long long int>("TimeOffset"); offset == 0) {
336  mf::LogWarning("TriggerDecoder")
337  << "Configuration parameter 'TimeOffset' has been dropped.\n";
338  }
339  else { // unforgiving: dropping non-zero offset changes output
340  throw art::Exception(art::errors::Configuration)
341  << "Adding offset (configuration parameter 'TimeOffset', here set to "
342  << offset << " seconds) is not supported any more.\n";
343  }
344  }
345  return;
346  }
347 
349  {
350  //use until different object chosen
351  //fTrigger = new raw::Trigger();
352  fTrigger = std::make_unique<TriggerCollection>();
353  fPrevTrigger = std::make_unique<TriggerCollection>();
354  fRelTrigger = std::make_unique<RelativeTriggerCollection>();
356  fTriggerExtra = std::make_unique<sbn::ExtraTriggerInfo>();
357  return;
358  }
359 
360 
361  icarus::ICARUSTriggerV2Fragment TriggerDecoder::makeTriggerFragment
362  (artdaq::Fragment const& fragment) const
363  {
364  try {
365  return icarus::ICARUSTriggerV2Fragment { fragment };
366  }
367  catch(std::exception const& e) {
368  mf::LogSystem("TriggerDecoder")
369  << "Error while creating trigger fragment from:\n"
370  << sbndaq::dumpFragment(fragment)
371  << "\nError message: " << e.what();
372  throw;
373  }
374  catch(...) {
375  mf::LogSystem("TriggerDecoder")
376  << "Unidentified exception while creating trigger fragment from:"
377  << sbndaq::dumpFragment(fragment);
378  throw;
379  }
380  } // TriggerDecoder::makeTriggerFragment()
381 
382 
383  icarus::ICARUSTriggerInfo TriggerDecoder::parseTriggerString
384  (std::string_view data) const
385  {
386  try {
387  return icarus::parse_ICARUSTriggerV2String(data.data());
388  }
389  catch(std::exception const& e) {
390  mf::LogSystem("TriggerDecoder")
391  << "Error while running standard parser on " << data.length()
392  << "-char long trigger string:\n==>|" << data
393  << "|<==\nError message: " << e.what();
394  throw;
395  }
396  catch(...) {
397  mf::LogSystem("TriggerDecoder")
398  << "Unidentified exception while running standard parser on "
399  << data.length() << "-char long trigger string:\n==>|" << data << "|.";
400  throw;
401  }
402  } // TriggerDecoder::parseTriggerString()
403 
404 
406  (std::string const& data) const
407  {
409  parser.addPatterns({
410  { "Cryo. (EAST|WEST) Connector . and .", 1U }
411  , { "Trigger Type", 1U }
412  });
413  std::string_view const dataLine = firstLine(data);
414  try {
415  return parser(dataLine);
416  }
418  mf::LogError("TriggerDecoder")
419  << "Error parsing " << dataLine.length()
420  << "-char long trigger string:\n==>|" << dataLine
421  << "|<==\nError message: " << e.what() << std::endl;
422  throw;
423  }
424  } // TriggerDecoder::parseTriggerStringAsCSV()
425 
426 
427  void TriggerDecoder::setupRun(art::Run const& run) {
428 
430  ? nullptr
431  : &(run.getProduct<icarus::TriggerConfiguration>(fTriggerConfigTag))
432  ;
433 
434  } // TriggerDecoder::setupRun()
435 
436 
437  void TriggerDecoder::process_fragment(const artdaq::Fragment &fragment)
438  {
439  // artdaq_ts is reworked by the trigger board reader to match the corrected
440  // trigger time; to avoid multiple (potentially inconsistent) corrections,
441  // the decoder trusts it and references all the times with respect to it.
442  uint64_t const artdaq_ts = fragment.timestamp();
443  icarus::ICARUSTriggerV2Fragment frag { makeTriggerFragment(fragment) };
444  std::string data = frag.GetDataString();
445  char *buffer = const_cast<char*>(data.c_str());
446 
447  icarus::ICARUSTriggerInfo datastream_info = parseTriggerString(buffer);
448  uint64_t const raw_wr_ts // this is raw, unadultered, uncorrected
449  = makeTimestamp(frag.getWRSeconds(), frag.getWRNanoSeconds());
450 
451  // correction (explicitly converted to signed)
452  int64_t const WRtimeToTriggerTime
453  = static_cast<int64_t>(artdaq_ts) - raw_wr_ts;
454  auto const correctWRtime = [WRtimeToTriggerTime](uint64_t time)
455  { return time + WRtimeToTriggerTime; };
456  assert(correctWRtime(raw_wr_ts) == artdaq_ts);
457 
458  //
459  // we parse again the trigger string for information that was not saved
460  // by the board reader in the trigger fragment nor in `datastream_info`
461  //
462  auto const parsedData = parseTriggerStringAsCSV(data);
463 
464  unsigned int beamgate_count { std::numeric_limits<unsigned int>::max() };
465  std::uint64_t beamgate_ts { artdaq_ts }; // we cheat
466  /* [20210717, petrillo@slac.stanford.edu] `(pBeamGateInfo->nValues() == 3)`:
467  * this is an attempt to "support" a few Run0 runs (6017 to roughly 6043)
468  * which have the beam gate information truncated; this workaround should
469  * be removed when there is enough ICARUS data that these runs become
470  * uninteresting.
471  */
472  if (auto pBeamGateInfo = parsedData.findItem("Beam_TS")) {
473  /*
474  * The Veto Business:
475  *
476  * to better cover the pre-spill time, a trigger primitive is issued
477  * in advance of the actual beam gate, but during the additional time
478  * the global trigger is vetoed.
479  * So the physical beam gate signal starts in advance of the beam gate,
480  * and teh actual beam gate is expected after the veto time has passed.
481  * The hardware tagging the beam gate time does not know of this, and it
482  * marks the beam gate to start at the opening of the physical signal
483  * (at the beginning of the vetoed time).
484  * This is all a trick for PMT readout, nothing should depend on it,
485  * so we correct that as soon as we can and then forget it.
486  * The amount of veto time is written in the trigger configuration;
487  * if that configuration is not available, this code assumes there was
488  * no veto.
489  */
490  int64_t const triggerVetoDurationNS
492 
493 
494  // if gate information is found, it must be complete
495  beamgate_count = pBeamGateInfo->getNumber<unsigned int>(0U);
496 
497  uint64_t const raw_bg_ts = makeTimestamp( // raw and uncorrected too...
498  pBeamGateInfo->getNumber<unsigned int>(1U),
499  pBeamGateInfo->getNumber<unsigned int>(2U)
500  )
501  + triggerVetoDurationNS // ... but remove the veto time
502  ;
503 
504  // assuming the raw times from the fragment are on the same time scale
505  // (same offset corrections)
506  beamgate_ts += raw_bg_ts - raw_wr_ts;
507 
508  } // if has gate information
509  std::uint64_t enablegate_ts { artdaq_ts };
510  if (auto pEnableGateInfo = parsedData.findItem("Enable_TS"))
511  {
512  // if gate information is found, it must be complete
513  //enablegate_count = pEnableGateInfo->getNumber<unsigned int>(0U);
514 
515  uint64_t const raw_en_ts = makeTimestamp( // raw and uncorrected too
516  pEnableGateInfo->getNumber<unsigned int>(1U),
517  pEnableGateInfo->getNumber<unsigned int>(2U)
518  );
519 
520  // assuming the raw times from the fragment are on the same time scale
521  // (same offset corrections)
522 
523  enablegate_ts += raw_en_ts - raw_wr_ts;
524  } // if has gate information
525 
526  // --- END ---- TEMPORARY --------------------------------------------------
527 
528  if(fDiagnosticOutput || fDebug)
529  {
530  std::cout << "Full Timestamp = " << artdaq_ts
531  << "\nBeam gate " << beamgate_count << " at "
532  << (beamgate_ts/1'000'000'000) << "." << std::setfill('0')
533  << std::setw(9) << (beamgate_ts%1'000'000'000) << std::setfill(' ')
534  << " s (" << timestampDiff(beamgate_ts, artdaq_ts)
535  << " ns relative to trigger)"
536  << "\nParsed data (from " << data.size() << " characters): "
537  << parsedData << std::endl;
538 
539  if (fDebug) { // this grows tiresome quickly when processing many events
540  std::cout << "Trigger packet content:\n" << data
541  << "\nFull trigger fragment dump:"
542  << sbndaq::dumpFragment(fragment) << std::endl;
543  }
544  }
545  //
546  // extra trigger info
547  //
548  sbn::triggerSource beamGateBit;
549  switch (datastream_info.gate_type) {
550  case TriggerGateTypes::BNB:{
551  beamGateBit = sbn::triggerSource::BNB;
552  fTriggerExtra->gateCountFromPreviousTrigger = frag.getDeltaGatesBNB();
553  fTriggerExtra->previousTriggerTimestamp = frag.getLastTimestampBNB();
554  fTriggerExtra->gateCount = datastream_info.gate_id_BNB;
555  fTriggerExtra->triggerCount = frag.getTotalTriggerBNB();
556  fTriggerExtra->anyTriggerCountFromPreviousTrigger = frag.getLastTriggerBNB();
557  break;
558  }
560  beamGateBit = sbn::triggerSource::NuMI;
561  fTriggerExtra->gateCountFromPreviousTrigger = frag.getDeltaGatesNuMI();
562  fTriggerExtra->previousTriggerTimestamp = frag.getLastTimestampNuMI();
563  fTriggerExtra->gateCount = datastream_info.gate_id_NuMI;
564  fTriggerExtra->triggerCount = frag.getTotalTriggerNuMI();
565  fTriggerExtra->anyTriggerCountFromPreviousTrigger = frag.getLastTriggerNuMI();
566  break;
567  }
569  beamGateBit = sbn::triggerSource::OffbeamBNB;
570  fTriggerExtra->gateCountFromPreviousTrigger = frag.getDeltaGatesBNBOff();
571  fTriggerExtra->previousTriggerTimestamp= frag.getLastTimestampBNBOff();
572  fTriggerExtra->gateCount = datastream_info.gate_id_BNBOff;
573  fTriggerExtra->triggerCount = frag.getTotalTriggerBNBOff();
574  fTriggerExtra->anyTriggerCountFromPreviousTrigger = frag.getLastTriggerBNBOff();
575  break;
576  }
578  beamGateBit = sbn::triggerSource::OffbeamNuMI;
579  fTriggerExtra->gateCountFromPreviousTrigger = frag.getDeltaGatesNuMIOff();
580  fTriggerExtra->previousTriggerTimestamp= frag.getLastTimestampNuMIOff();
581  fTriggerExtra->gateCount = datastream_info.gate_id_NuMIOff;
582  fTriggerExtra->triggerCount = frag.getTotalTriggerNuMIOff();
583  fTriggerExtra->anyTriggerCountFromPreviousTrigger = frag.getLastTriggerNuMIOff();
584  break;
585  }
587  beamGateBit = sbn::triggerSource::Calib;
588  fTriggerExtra->gateCountFromPreviousTrigger = frag.getDeltaGatesCalib();
589  fTriggerExtra->previousTriggerTimestamp = frag.getLastTimestampCalib();
590  //fTriggerExtra->gateCount = datastream_info.gate_id_calib;
591  fTriggerExtra->triggerCount = frag.getTotalTriggerCalib();
592  fTriggerExtra->anyTriggerCountFromPreviousTrigger = frag.getLastTriggerCalib();
593  break;
594  }
595  default: beamGateBit = sbn::triggerSource::Unknown;
596  } // switch gate type
597 
598  fTriggerExtra->sourceType = beamGateBit;
599  fTriggerExtra->triggerTimestamp = artdaq_ts;
600  fTriggerExtra->beamGateTimestamp = beamgate_ts;
601  fTriggerExtra->enableGateTimestamp = enablegate_ts;
602  fTriggerExtra->triggerID = datastream_info.wr_event_no; //all triggers (event ID)
603  fTriggerExtra->gateID = datastream_info.gate_id; //all gate types (gate ID)
604  fTriggerExtra->anyGateCountFromAnyPreviousTrigger = frag.getDeltaGates();
605  fTriggerExtra->anyPreviousTriggerTimestamp = frag.getLastTimestamp();
606  sbn::triggerSource previousTriggerSourceBit;
607  if(frag.getLastTriggerType() == 1)
608  previousTriggerSourceBit = sbn::triggerSource::BNB;
609  else if(frag.getLastTriggerType() == 2)
610  previousTriggerSourceBit = sbn::triggerSource::NuMI;
611  else if(frag.getLastTriggerType() == 3)
612  previousTriggerSourceBit = sbn::triggerSource::OffbeamBNB;
613  else if(frag.getLastTriggerType() == 4)
614  previousTriggerSourceBit = sbn::triggerSource::OffbeamNuMI;
615  else if(frag.getLastTriggerType() == 5)
616  previousTriggerSourceBit = sbn::triggerSource::Calib;
617  else
618  previousTriggerSourceBit = sbn::triggerSource::Unknown;
619  fTriggerExtra->anyPreviousTriggerSourceType = previousTriggerSourceBit;
620 
621  fTriggerExtra->WRtimeToTriggerTime = WRtimeToTriggerTime;
622  sbn::bits::triggerLocationMask locationMask;
623  // trigger location: 0x01=EAST; 0x02=WEST; 0x07=ALL
624  int const triggerLocation = parsedData.getItem("Trigger Source").getNumber<int>(0);
625  if(triggerLocation == 1)
626  locationMask = mask(sbn::triggerLocation::CryoEast);
627  else if(triggerLocation == 2)
628  locationMask = mask(sbn::triggerLocation::CryoWest);
629  else if(triggerLocation == 7)
630  locationMask = mask(sbn::triggerLocation::CryoEast, sbn::triggerLocation::CryoWest);
631  fTriggerExtra->triggerLocationBits = locationMask;
633  = {
634  // triggerCount
635  (fTriggerExtra->triggerID <= 1)
636  ? 0UL: parsedData.getItem("Cryo1 EAST counts").getNumber<unsigned long int>(0),
637  // LVDSstatus
638  {
639  (triggerLocation & 1) // EE
640  ? encodeLVDSbits(
641  sbn::ExtraTriggerInfo::EastCryostat, 2, /* any of the connectors */
642  parsedData.getItem("Cryo1 EAST Connector 2 and 3").getNumber<std::uint64_t>(0, 16)
643  )
644  : 0ULL,
645  (triggerLocation & 1) // EW
646  ? encodeLVDSbits(
647  sbn::ExtraTriggerInfo::EastCryostat, 0, /* any of the connectors */
648  parsedData.getItem("Cryo1 EAST Connector 0 and 1").getNumber<std::uint64_t>(0, 16)
649  )
650  : 0ULL
651  }
652  };
654  = {
655  // triggerCount
656  (fTriggerExtra->triggerID <= 1)
657  ? 0UL: parsedData.getItem("Cryo2 WEST counts").getNumber<unsigned long int>(0),
658  // LVDSstatus
659  {
660  (triggerLocation & 2) // WE
661  ? encodeLVDSbits(
662  sbn::ExtraTriggerInfo::WestCryostat, 2, /* any of the connectors */
663  parsedData.getItem("Cryo2 WEST Connector 2 and 3").getNumber<std::uint64_t>(0, 16)
664  )
665  : 0ULL,
666  (triggerLocation & 2) // WW
667  ? encodeLVDSbits(
668  sbn::ExtraTriggerInfo::WestCryostat, 0, /* any of the connectors */
669  parsedData.getItem("Cryo2 WEST Connector 0 and 1").getNumber<std::uint64_t>(0, 16)
670  )
671  : 0ULL
672  }
673  };
674 
675  // we expect the LVDS status bits to follow this pattern:
676  for (auto const& cryoInfo [[maybe_unused]]: fTriggerExtra->cryostats)
677  for (auto LVDS [[maybe_unused]]: cryoInfo.LVDSstatus)
678  assert((LVDS & 0xFF000000FF000000) == 0);
679 
680  //
681  // absolute time trigger (raw::ExternalTrigger)
682  //
683  fTrigger->emplace_back
684  (fTriggerExtra->triggerID, artdaq_ts);//fTriggerExtra->triggerTimestamp);
685 
686  //
687  // previous absolute time trigger (raw::ExternalTrigger)
688  //
689  uint64_t lastTrigger = 0;
690  if(fTriggerExtra->triggerID == 1)
691  {
692  fLastEvent = 0;
693  }
694  else
695  {
696  fLastEvent = fTriggerExtra->triggerID - 1;
697  lastTrigger = fTriggerExtra->anyPreviousTriggerTimestamp;
698  fPrevTrigger->emplace_back(fLastEvent, lastTrigger);
699  }
700 
701  //
702  // beam gate
703  //
704 
705  // beam gate width (read in microseconds, but we use it in nanoseconds)
707  ? fTriggerConfiguration->getGateWidth(value(beamGateBit))
708  : 0.0
709  };
710 
711  // beam gate - trigger: hope it's negative...
712  nanoseconds const gateStartFromTrigger{
713  static_cast<double>(timestampDiff
714  (fTriggerExtra->beamGateTimestamp, fTriggerExtra->triggerTimestamp)
715  )
716  }; // narrowing!!
717  auto const elecGateStart = fDetTimings.TriggerTime() + gateStartFromTrigger;
718  auto const simGateStart = fDetTimings.toSimulationTime(elecGateStart);
719  fBeamGateInfo->emplace_back
720  (simGateStart.value(), gateWidth.value(), simGateType(beamGateBit));
721 
722  //
723  // relative time trigger (raw::Trigger)
724  //
725  fRelTrigger->emplace_back(
726  static_cast<unsigned int>(datastream_info.wr_event_no), // counter
727  fDetTimings.TriggerTime().value(), // trigger_time
728  elecGateStart.value(), // beamgate_time
729  mask(beamGateBit) // bits
730  );
731 
732  //Once we have full trigger data object, set up and place information into there
733  return;
734  }
735 
736  void TriggerDecoder::outputDataProducts(art::Event &event)
737  {
738  //Place trigger data object into raw data store
739  event.put(std::move(fTrigger), CurrentTriggerInstanceName);
740  event.put(std::move(fRelTrigger), CurrentTriggerInstanceName);
741  event.put(std::move(fPrevTrigger), PreviousTriggerInstanceName);
742  event.put(std::move(fBeamGateInfo), CurrentTriggerInstanceName);
743  event.put(std::move(fTriggerExtra));
744  return;
745  }
746 
747  std::string_view TriggerDecoder::firstLine
748  (std::string const& s, std::string const& endl /* = "\0\n\r" */)
749  {
750  return { s.data(), std::min(s.find_first_of(endl), s.size()) };
751  }
752 
753 
754  std::uint64_t TriggerDecoder::encodeLVDSbits
755  (short int cryostat, short int connector, std::uint64_t connectorWord)
756  {
757  /*
758  * Encoding of the LVDS channels from the trigger:
759  * * east wall: `00<C0P2><C0P1><C0P0>00<C1P2><C1P1><C1P0>`
760  * * west wall: `00<C2P2><C2P1><C2P0>00<C3P2><C3P1><C3P0>`
761  * The prescription from `sbn::ExtraTriggerInfo` translates into:
762  * * east wall: `00<C3P2><C3P1><C3P0>00<C2P2><C2P1><C2P0>`
763  * * west wall: `00<C1P2><C1P1><C1P0>00<C0P2><C0P1><C0P0>`
764  * Therefore, the two 32-bit half-words need to be swapped
765  * This holds for both cryostats, and both walls.
766  */
767 
768  std::uint64_t lsw = connectorWord & 0xFFFFFFFFULL;
769  std::uint64_t msw = connectorWord >> 32ULL;
770  assert(connectorWord == ((msw << 32ULL) | lsw));
771  std::swap(lsw, msw);
772  return (msw << 32ULL) | lsw;
773  } // TriggerDecoder::encodeLVDSbits()
774 
775 
777  {
778  switch (source) {
779  case sbn::triggerSource::BNB:
780  case sbn::triggerSource::OffbeamBNB:
781  return sim::kBNB;
782  case sbn::triggerSource::NuMI:
783  case sbn::triggerSource::OffbeamNuMI:
784  return sim::kNuMI;
785  case sbn::triggerSource::Calib:
786  return sim::kUnknown;
787  default:
788  mf::LogWarning("TriggerDecoder") << "Unsupported trigger source " << name(source);
789  return sim::kUnknown;
790  } // switch source
791  } // TriggerDecoder::simGateType()
792 
793 
794  DEFINE_ART_CLASS_TOOL(TriggerDecoder)
795 
796 }
Definitions of the trigger bits for SBN.
virtual void produces(art::ProducesCollector &) override
The space point building should output the hit collection for those hits which combine to form space ...
Parser to fill a KeyValuesData structure out of a character buffer.
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Definition: CORSIKAGen.fcl:7
detinfo::DetectorTimings const fDetTimings
Detector clocks and timings.
bool fDiagnosticOutput
Produces large number of diagnostic messages, use with caution!
virtual void initializeDataProducts() override
Initialize any data products the tool will output.
microsecond_as<> microsecond
Type of time stored in microseconds, in double precision.
Definition: spacetime.h:119
do source
This provides an art tool interface definition for tools which &quot;decode&quot; artdaq fragments into LArSoft...
std::unique_ptr< TriggerCollection > TriggerPtr
std::unique_ptr< sbn::ExtraTriggerInfo > ExtraInfoPtr
icarus::TriggerConfiguration const * fTriggerConfiguration
Cached pointer to the trigger configuration of the current run, if any.
static constexpr std::size_t EastCryostat
Mnemonic index for the east cryostat.
virtual void process_fragment(const artdaq::Fragment &fragment) override
Given a set of recob hits, run DBscan to form 3D clusters.
float getGateWidth(std::size_t source) const
returns the effective gate width corrected for the veto delay in us
static std::string const CurrentTriggerInstanceName
Name of the data product instance for the current trigger.
BeamGateInfoPtr fBeamGateInfo
std::vector< sim::BeamGateInfo > BeamGateInfoCollection
Simple parser for comma-separated text.
Unknown beam type.
Definition: BeamTypes.h:10
Information from the configuration of the ICARUS trigger readout.
triggerLocation
Location or locations generating a trigger.
Definition: BeamBits.h:113
std::unique_ptr< BeamGateInfoCollection > BeamGateInfoPtr
static std::string const PreviousTriggerInstanceName
Name of the data product instance for the previous trigger.
NuMI.
Definition: BeamTypes.h:12
Interface to detinfo::DetectorClocks.
process_name gaushit a
util::quantities::nanosecond nanoseconds
Simple parsed data format.
virtual void configure(const fhicl::ParameterSet &) override
Interface for configuring the particular algorithm tool.
icarus::ICARUSTriggerUDPFragment makeTriggerFragment(artdaq::Fragment const &fragment) const
Creates a ICARUSTriggerInfo from a generic fragment.
constexpr mask_t< EnumType > mask(EnumType bit, OtherBits...otherBits)
Returns a mask with all specified bits set.
Additional information on trigger.
bool fDebug
Use this for debugging this tool.
A value measured in the specified unit.
Definition: quantities.h:566
Collection of items with key/values structure.
simulation_time toSimulationTime(FromTime time) const
Converts a time point into simulation time scale.
art::InputTag fTriggerConfigTag
Data product with hardware trigger configuration.
virtual void outputDataProducts(art::Event &event) override
Output the data products to the event store.
KeyedCSVparser & addPatterns(std::initializer_list< std::pair< std::regex, unsigned int >> patterns)
Adds known patterns.
static constexpr std::size_t WestCryostat
Mnemonic index for the west cryostat.
Utility to dump a artDAQ fragment on screen.
virtual void consumes(art::ConsumesCollector &collector) override
Declare to the framework what you expect to read.
electronics_time TriggerTime() const
static std::uint64_t encodeLVDSbits(short int cryostat, short int connector, std::uint64_t connectorWord)
std::unique_ptr< RelativeTriggerCollection > fRelTrigger
static long long int timestampDiff(std::uint64_t a, std::uint64_t b)
Returns the difference a - b.
icarus::KeyValuesData parseTriggerStringAsCSV(std::string const &data) const
Parses the trigger data packet with a CSV parser.
static std::uint64_t makeTimestamp(unsigned int s, unsigned int ns)
Combines second and nanosecond counts into a 64-bit timestamp.
BNB.
Definition: BeamTypes.h:11
details::DumpFragWrap dumpFragment(artdaq::Fragment const &frag)
Dump a artDAQ fragment into an output stream.
then echo File list $list not found else cat $list while read file do echo $file sed s
Definition: file_to_url.sh:60
Dimensioned variables representing space or time quantities.
A class exposing an upgraded interface of detinfo::DetectorClocksData.
std::vector< raw::Trigger > RelativeTriggerCollection
nanosecond_as<> nanosecond
Type of time stored in nanoseconds, in double precision.
Definition: spacetime.h:136
std::vector< raw::ExternalTrigger > TriggerCollection
Tool decoding the trigger information from DAQ.
Codes of gate types from the trigger hardware.
virtual void setupRun(art::Run const &run) override
Preparation to process a new run.
do i e
triggerSource
Type of beam or beam gate or other trigger source.
Definition: BeamBits.h:97
then echo fcl name
Data product holding additional trigger information.
temporary value
static sim::BeamType_t simGateType(sbn::triggerSource source)
Returns the beam type corresponding to the specified trigger source.
static std::string_view firstLine(std::string const &s, std::string const &endl="\0\n\r"s)
unsigned int vetoDelay
Veto (this delay has to be subtracted to the gate width ). Value is in ns.
util::quantities::microsecond microseconds
BeamType_t
Defines category of beams to be stored in sim::BeamGateInfo.
Definition: BeamTypes.h:9
BEGIN_PROLOG could also be cout
Functions to dump the content of binary data chunks to console.
icarus::ICARUSTriggerInfo parseTriggerString(std::string_view data) const
Parses the trigger data packet with the &quot;standard&quot; parser.
nanosecond nanoseconds
Alias for common language habits.
Definition: spacetime.h:139