DetectorTimings.h
Go to the documentation of this file.
1 /**
2  * @file lardataalg/DetectorInfo/DetectorTimings.h
3  * @brief Interface to `detinfo::DetectorClocks`.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date May 30, 2019
6  *
7  */
8 
9 #ifndef LARDATAALG_DETECTORINFO_DETECTORTIMINGS_H
10 #define LARDATAALG_DETECTORINFO_DETECTORTIMINGS_H
11 
12 // LArSoft libraries
14 #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // ns. timescales
18 
19 // C/C++ standard libraries
20 #include <type_traits> // std::enable_if_t, std::is_same_v, std::void_t
21 
22 namespace detinfo {
23 
24  // ---------------------------------------------------------------------------
25  /**
26  * @brief A partial `detinfo::DetectorClocksData` supporting units.
27  *
28  * This class is instantiated based on a `detinfo::DetectorClocksData`, which
29  * is relied upon to provide the underlying functionality.
30  *
31  * Example of usage:
32  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
33  * detinfo::DetectorClocksWithUnits const& detClocks
34  * = detinfo::makeDetectorClocksWithUnits
35  * (art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob())
36  * ;
37  *
38  * util::quantities::nanosecond simulStartTime
39  * = detClocks.G4ToElecTime(0.0);
40  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
41  *
42  * The timing data is copied locally; see `detinfo::DetectorClocksData` for
43  * considerations on the validity time span of the timing information.
44  */
46 
47  /// The backend instance of `detinfo::DetectorClocksData` this object uses.
48  detinfo::DetectorClocksData fClockData; // non-const to allow copy
49 
50  public:
51  // import types
56 
57  // @{
58  /// Constructor: uses `detClocks` for internal conversions.
60  : DetectorClocksWithUnits(*detClocks)
61  {}
63  : fClockData(detClocks)
64  {}
65  // @}
66 
67  /// Returns the detector clocks data object
69  clockData() const
70  {
71  return fClockData;
72  }
73 
74  /// Equivalent to `detinfo::DetectorClocksData::TriggerTime()`.
76  TriggerTime() const
77  {
78  return microsecond{clockData().TriggerTime()};
79  }
80 
81  /// Equivalent to `detinfo::DetectorClocksData::BeamGateTime()`.
83  BeamGateTime() const
84  {
86  }
87 
88  /// Equivalent to `detinfo::DetectorClocksData::TPCTime()`.
90  TPCTime() const
91  {
92  return microsecond{clockData().TPCTime()};
93  }
94 
95  // @{
96  /// Equivalent to `detinfo::DetectorClocksData::G4ToElecTime()`.
98  G4ToElecTime(nanosecond simTime) const
99  {
100  return microsecond{clockData().G4ToElecTime(simTime.value())};
101  }
103  G4ToElecTime(double simTime) const
104  {
105  return G4ToElecTime(nanosecond{simTime});
106  }
107  // @}
108 
109  // @{
110  /// Equivalent to `detinfo::DetectorClocksData::G4ToElecTime()`.
111  ticks_d
112  TPCTick2TDC(ticks_d tpcticks) const
113  {
114  return ticks_d{clockData().TPCTick2TDC(tpcticks.value())};
115  }
116  ticks_d
117  TPCTick2TDC(double tpcticks) const
118  {
119  return TPCTick2TDC(ticks_d{tpcticks});
120  }
121  // @}
122 
123  /// Equivalent to
124  /// `detinfo::DetectorClocksData::OpticalClock().TickPeriod()`.
127  {
129  }
130 
131  /// Equivalent to
132  /// `detinfo::DetectorClocksData::OpticalClock().TickPeriod()`.
133  megahertz
135  {
137  }
138 
139  }; // class DetectorClocksWithUnits
140 
141  /// Transforms a `detinfo::DetectorClocksData` into a
142  /// `detinfo::DetectorClocksWithUnits`.
145  {
146  return detinfo::DetectorClocksWithUnits{clockData};
147  }
148 
149  // ---------------------------------------------------------------------------
150  /**
151  * @brief A class exposing an upgraded interface of
152  * `detinfo::DetectorClocksData`.
153  *
154  * This object extends `detinfo::DetectorClocksData` interface.
155  * For example, in _art_/LArSoft, one can be created as:
156  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
157  * auto const& detTimings = detinfo::makeDetectorTimings
158  * (art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob());
159  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160  * in a non-event context or, if a current event is available:
161  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
162  * auto const& detTimings = detinfo::makeDetectorTimings
163  * (art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event));
164  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
165  * It can also wrap around an existing `detinfo::DetectorClocksWithUnits`
166  * object:
167  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
168  * auto detClocksWU = detinfo::makeDetectorClocksWithUnits
169  * (lar::provider_from<detinfo::DetectorClocksService const>()->DataFor(event));
170  * auto const& timings = detinfo::makeDetectorTimings(detClocksWU);
171  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
172  *
173  * The timing data is copied locally; see `detinfo::DetectorClocksData` for
174  * considerations on the validity time span of the timing information.
175  *
176  *
177  * Data types
178  * ===========
179  *
180  * Several data types are designed to resolve the ambiguity of which time,
181  * which time scale and which time unit are used.
182  * The class distinguish between time points, which identify events in
183  * absolute terms, and time intervals and durations, which identify the time
184  * lapsed between two events or time points.
185  *
186  * The time duration is generally expressed by a single type, since it is
187  * common to all main time scales expressed in real time:
188  * * `time_interval` is natively represented in microseconds
189  *
190  * Note that while each data type has a native representation (usually
191  * microseconds), these objects can convert into other units to remain
192  * consistent. Still, they are not fool-proof...
193  *
194  * Different time point types are defined to reflect the different time
195  * scales:
196  * * `electronics_time` for times on the
197  * @ref DetectorClocksElectronicsTime "electronics time axis", starting
198  * at the @ref DetectorClocksElectronicsStartTime "electronics start time",
199  * natively expressed in microseconds. There is no clock specific to
200  * this time scale, but we identify the ticks with the TPC electronics
201  * clock. Tick types are nevertheless specific to this time scale and they
202  * are called `electronics_tick` (integral tick number) and
203  * `electronics_tick_d` (real tick number).
204  * * `TPCelectronics_time` for times on the
205  * @ref DetectorClocksTPCelectronicsTime "TPC electronics time axis",
206  * starting at the
207  * @ref DetectorClocksTPCelectronicsStartTime "TPC electronics start time",
208  * natively expressed in microseconds.
209  * Tick types are called `TPCelectronics_tick` (integral tick number)
210  * and `TPCelectronics_tick_d` (real tick number).
211  * * `optical_time` for times on the
212  * * @ref DetectorClocksOpticalElectronicsTime "optical detector electronics time axis",
213  * starting at the
214  * @ref DetectorClocksOpticalElectronicsStartTime "optical detector electronics start time",
215  * natively expressed in microseconds.
216  * Tick types are called `optical_tick` (integral tick number)
217  * and `optical_tick_d` (real tick number).
218  * @note Unfortunately, this time scale is not well defined, so it is
219  * assumed to start at the same time as the electronics scale.
220  * * `trigger_time` for times on the
221  * @ref DetectorClocksTriggerTime "trigger time axis", starting at the
222  * @ref DetectorClocksHardwareTrigger "hardware trigger time",
223  * natively expressed in microseconds.
224  * Tick types are called `trigger_tick` (integral tick number)
225  * and `trigger_tick_d` (real tick number).
226  * * `simulation_time` for times on the
227  * @ref DetectorClocksSimulationTime "simulation time axis", starting at the
228  * @ref DetectorClocksGeant4TimeStart "GEANT4 time start",
229  * natively expressed in nanoseconds.
230  *
231  *
232  * For each time scale, a "category" is defined (e.g.
233  * `electronics_time::category_t`), and traits are available for each category
234  * as `timescale_traits` objects (for example
235  * `detinfo::timescales::timescale_traits<electronics_time::category_t>`).
236  * From the traits, it is possible to access the type of time point
237  * (`time_point_t`, which is equivalent e.g. to `electronics_time`,
238  * `simulation_time` etc.) as well as the time interval type
239  * (`time_interval_t`), the tick type in integral units (`tick_t`) and real
240  * units (`tick_d_t`), the name of the time scale itself (`name()`) and
241  * little more.
242  *
243  * Note that not all time scales support all features. For example, simulation
244  * time is not actually associated to any clock, so that for example an
245  * attempt to convert a time into simulation time ticks will result in a
246  * compilation failure.
247  *
248  */
250 
251  /// The traits of a specific `TimeScale`.
252  template <typename TimeScale>
254 
255  /// The time interval type of a specific `TimeScale`.
256  template <typename TimeScale>
258 
259  /// The frequency type of a specific `TimeScale`.
260  template <typename TimeScale>
262 
263  public:
264  // --- BEGIN -- Imported time scale types ----------------------------------
265  /// @name Imported time scale types
266  /// @{
267 
273 
278 
283 
285 
290 
291  /// @}
292  // --- END -- Imported time scale types ------------------------------------
293 
294  // note that `makeDetectorTimings()` provides an additional construction way
295  // @{
296  /// Constructor: wraps around a specified `detinfo::DetectorClocksData` object.
298  : detinfo::DetectorClocksWithUnits(clockData)
299  {}
301  : detinfo::DetectorClocksWithUnits(clockData)
302  {}
303  // @}
304 
305  // --- BEGIN -- Access to underlying service providers ---------------------
306  /// @name Access to underlying service providers.
307  /// @{
308 
309  /// Returns a DetectorClocksWithUnits object.
312  {
313  return static_cast<detinfo::DetectorClocksWithUnits const&>(*this);
314  }
315 
316  /// Returns the detector clocks data.
318  clockData() const
319  {
320  return detClocksUnits().clockData();
321  }
322 
323  /// @}
324  // --- END -- Access to underlying service providers -----------------------
325 
326  // --- BEGIN -- Electronics times ------------------------------------------
327 
328  /// Returns the trigger time as a point in electronics time.
329  /// @see `detinfo::DetectorClocksData::TriggerTime()`
331  TriggerTime() const
332  {
333  return electronics_time{detClocksUnits().TriggerTime()};
334  }
335 
336  /// Returns the beam gate time as a point in electronics time.
337  /// @see `detinfo::DetectorClocksData::BeamGateTime()`
339  BeamGateTime() const
340  {
341  return electronics_time{detClocksUnits().BeamGateTime()};
342  }
343 
344  // --- END -- Electronics times --------------------------------------------
345 
346  // --- BEGIN -- Conversions ------------------------------------------------
347  /// @name Conversions
348  /// @{
349 
350  /**
351  * @brief Returns a `time` point in a different time scale.
352  * @tparam TargetTime the desired time scale
353  * @tparam FromTime the time scale the input `time` is measured in
354  * @param time the time instant to be converted, in `FromTime` scale
355  * @return the time instant converted into `TargetTime` time scale
356  *
357  * Example:
358  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
359  * simulation_time nuTime = 47.5_ns;
360  * electronics_time nuElecTime
361  * = timings.toTimeScale<electronics_time>(nuTime);
362  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
363  * is equivalent to use `detinfo::DetectorClocksData::G4ToElecTime(47.5)`.
364  */
365  template <typename TargetTime, typename FromTime>
366  TargetTime toTimeScale(FromTime time) const;
367 
368  /**
369  * @brief Returns a `time` point as a tick on a different time scale.
370  * @tparam TargetTick the desired time scale
371  * @tparam FromTime the time scale the input `time` is measured in
372  * @param time the time instant to be converted, in `FromTime` scale
373  * @return the time instant converted as tick into `TargetTick` time scale
374  *
375  * Example:
376  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
377  * simulation_time nuTime = 47.5_ns;
378  * TPCelectronics_tick_d nuTPCtick
379  * = timings.toTick<TPCelectronics_tick_d>(nuTime);
380  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
381  */
382  template <typename TargetTick, typename FromTime>
383  TargetTick toTick(FromTime time) const;
384 
385  /**
386  * @brief Returns the number of ticks corresponding to a `time` interval.
387  * @tparam Ticks type of tick interval returned
388  * @return the `time` interval expressed as number of ticks
389  *
390  * The `time` interval is represented by the number of ticks on the time
391  * scale of `Ticks` which fits in that interval.
392  * If `Ticks` is based on an integral type, the resulting number of ticks is
393  * usually truncated.
394  */
395  template <typename Ticks>
396  Ticks
397  toTicks(time_interval time) const
398  {
399  return Ticks::castFrom(time / ClockPeriodFor<Ticks>());
400  }
401 
402  /**
403  * @brief Converts a `time` point into electronics time scale.
404  * @tparam FromTime the time scale the input `time` is measured in
405  * @param time the time instant to be converted, in `FromTime` scale
406  * @return the time instant converted into electronics time scale.
407  *
408  * Example:
409  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
410  * simulation_time nuTime = 47.5_ns;
411  * electronics_time nuElecTime = timings.toElectronicsTime(nuTime);
412  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
413  * is equivalent to use `detinfo::DetectorClocksData::G4ToElecTime(47.5)`.
414  */
415  template <typename FromTime>
417  toElectronicsTime(FromTime time) const
418  {
419  return toTimeScale<electronics_time>(time);
420  }
421 
422  /**
423  * @brief Converts a `time` point into electronics tick (real).
424  * @tparam FromTime the time scale the input `time` is measured in
425  * @param time the time instant to be converted, in `FromTime` scale
426  * @return the time instant converted into electronics tick number.
427  * @see `toTick()`, `toElectronicsTime()`, `toElectronicsTick()`
428  *
429  * Example:
430  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
431  * simulation_time nuTime = 47.5_ns;
432  * electronics_tick_d nuElecTick = timings.toElectronicsTime(nuTime);
433  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
434  */
435  template <typename FromTime>
437  toElectronicsTickD(FromTime time) const
438  {
439  return toTick<electronics_tick_d>(time);
440  }
441 
442  /**
443  * @brief Converts a `time` point into electronics tick (truncated).
444  * @tparam FromTime the time scale the input `time` is measured in
445  * @param time the time instant to be converted, in `FromTime` scale
446  * @return the time instant converted into electronics tick number.
447  * @see `toTick()`, `toElectronicsTime()`, `toElectronicsTickD()`
448  *
449  * Example:
450  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
451  * simulation_time nuTime = 47.5_ns;
452  * electronics_tick_d nuElecTick = timings.toElectronicsTime(nuTime);
453  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
454  */
455  template <typename FromTime>
457  toElectronicsTick(FromTime time) const
458  {
459  return toTick<electronics_tick>(time);
460  }
461 
462  /**
463  * @brief Converts a `time` point into trigger time scale.
464  * @tparam FromTime the time scale the input `time` is measured in
465  * @param time the time instant to be converted, in `FromTime` scale
466  * @return the time instant converted into trigger time scale.
467  *
468  * Example:
469  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
470  * simulation_time nuTime = 47.5_ns;
471  * trigger_time nuTriggerTime = timings.toTriggerTime(nuTime);
472  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
473  */
474  template <typename FromTime>
476  toTriggerTime(FromTime time) const
477  {
478  return toTimeScale<trigger_time>(time);
479  }
480 
481  /**
482  * @brief Converts a `time` point into simulation time scale.
483  * @tparam FromTime the time scale the input `time` is measured in
484  * @param time the time instant to be converted, in `FromTime` scale
485  * @return the time instant converted into simulation time scale.
486  *
487  * Example:
488  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
489  * electronics_time beamTime = 47.5_ns;
490  * simulation_time firstParticleTime = timings.toSimulationTime(beamTime);
491  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
492  */
493  template <typename FromTime>
495  toSimulationTime(FromTime time) const
496  {
497  return toTimeScale<simulation_time>(time);
498  }
499 
500  /// @}
501  // --- END -- Conversions --------------------------------------------------
502 
503  // --- BEGIN -- Clocks -----------------------------------------------------
504  /// @name Clocks
505  /// @{
506 
507  /// Returns the electronics clock for the specified time scale.
508  template <typename TimeScale>
509  detinfo::ElecClock const& ClockFor() const;
510 
511  /// Returns the period of the clock for the specified time scale.
512  template <typename TimeScale>
515  {
516  return time_interval_for<TimeScale>{microsecond{ClockFor<TimeScale>().TickPeriod()}};
517  }
518 
519  /// Returns the frequency of the clock for the specified time scale.
520  template <typename TimeScale>
523  {
524  return frequency_for<TimeScale>{megahertz{ClockFor<TimeScale>().Frequency()}};
525  }
526  /// @}
527  // --- END -- Clocks -------------------------------------------------------
528 
529  // --- BEGIN -- Optical clock ----------------------------------------------
530 
531  /// Returns the duration of the optical clock period and tick.
532  auto
534  {
535  return ClockPeriodFor<optical_time>();
536  }
537 
538  /// Returns the frequency of the optical clock tick.
539  megahertz
541  {
542  return ClockFrequencyFor<optical_time>();
543  }
544 
545  /**
546  * @brief Returns the optical ticks corresponding to a `time` interval.
547  * @tparam Ticks type of tick interval returned
548  * (default: _optical_time_ticks_)
549  * @return the `time` interval expressed as number of optical ticks
550  *
551  * The `time` interval is represented by the number of optical detector
552  * electronics ticks fitting in it. If `Ticks` is based on an integral type,
553  * the resulting number of ticks is usually truncated.
554  */
555  template <typename Ticks = optical_time_ticks>
556  Ticks
558  {
559  static_assert(traits_of<Ticks>::template same_category_as<optical_tick>,
560  "Specified ticks are not for optical time scale!");
561  return toTicks<Ticks>(time);
562  }
563 
564  /**
565  * @brief Returns the `time` point converted in units of optical time ticks.
566  * @tparam TimePoint type of the time to be converted
567  * @param time time point to be converted into an optical tick
568  * @return the `time` point expressed as integral number of ticks
569  * @see `toTick()`, `toOpticalTickD()`
570  *
571  * The specified time point is converted in ticks from the start of the
572  * optical time scale (i.e., from `startTime<optical_time>()`).
573  * The ticks are from the optical detector clock (`OpticalClockPeriod()`).
574  * The number of ticks is *truncated*.
575  */
576  template <typename TimePoint>
578  toOpticalTick(TimePoint time) const
579  {
580  return toTick<optical_tick>(time);
581  }
582 
583  /**
584  * @brief Returns the `time` point converted in units of optical time ticks.
585  * @tparam TimePoint type of the time to be converted
586  * @param time time point to be converted into an optical tick
587  * @return the `time` point expressed as real number of ticks
588  * @see `toTick()`, `toOpticalTickD()`
589  *
590  * The specified time point is converted in ticks from the start of the
591  * optical time scale (i.e., from `startTime<optical_time>()`).
592  * The ticks are from the optical detector clock (`OpticalClockPeriod()`).
593  * The number of ticks may be fractional.
594  */
595  template <typename TimePoint>
597  toOpticalTickD(TimePoint time) const
598  {
599  return toTick<optical_tick_d>(time);
600  }
601 
602  // --- END -- Optical clock ------------------------------------------------
603 
604  // --- BEGIN -- Reference times --------------------------------------------
605  /// @name Reference times
606  /// @{
607  /**
608  * @brief Converts a electronics time point into a duration from the start
609  * of electronics time.
610  * @param time electronics time point to be converted
611  * @return time elapsed from the start of electronics time to `time`
612  *
613  * This is mostly a logic operation, since the value of the returned time
614  * duration is the same as the value of the `time` point (i.e. the start
615  * time is 0).
616  */
617  time_interval fromStart(electronics_time time) const;
618 
619  /**
620  * @brief Returns the start time of the specified time scale.
621  * @tparam TimePoint the type of time point on the requested scale
622  * @tparam TimeScale the type of scale to get the result in
623  * (default: `electronics_time`)
624  *
625  * This method returns the start time of a time scale, in another time
626  * scale (or in the very same, in which case the result is trivially `0`).
627  * Example:
628  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
629  * using namespace detinfo::timescales;
630  *
631  * electronics_time const TPCstartTime
632  * = detTimings.startTime<TPCelectronics_time>();
633  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
634  * sets `TPCstartTime` to the instant the TPC electronics time starts,
635  * in the electronics time scale. This example in particular is yielding
636  * the same value as calling `detinfo::DetectorClocksData::TPCTime()`.
637  *
638  *
639  * Implemented scales
640  * -------------------
641  *
642  * * all where `TimePoint` is the same as `TimeScale` (trivially, `0`)
643  * * `TPCelectronics_time` to:
644  * * `electronics_time`
645  *
646  */
647  template <typename TimePoint, typename TimeScale = electronics_time>
648  constexpr TimeScale startTime() const;
649 
650  /**
651  * @brief Returns the start tick of the specified time tick scale.
652  * @tparam TickPoint the type of tick point on the requested scale
653  * @tparam TimeTickScale the type of scale to get the result in, also a time
654  * tick point (default: `electronics_tick`)
655  *
656  * This method returns the start tick of a time tick scale, in another time
657  * tick scale (or in the very same, in which case the result is trivially
658  * `0`).
659  * Example:
660  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
661  * using namespace detinfo::timescales;
662  *
663  * electronics_time_tick const TPCstartTick
664  * = detTimings.startTick<TPCelectronics_time_tick>();
665  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
666  * sets `TPCstartTime` to the instant the TPC electronics time starts,
667  * in the electronics time tick scale. This example in particular is
668  * yielding the same value as calling
669  * `detinfo::DetectorClocksData::TPCTick2TDC(0)`.
670  *
671  * @todo The example is not even supported yet!
672  *
673  *
674  * Implemented scales
675  * -------------------
676  *
677  * * all where `TickPoint` is the same as `TimeScale` (trivially, `0`)
678  * * `TPCelectronics_time` to:
679  * * `electronics_time`
680  *
681  *
682  */
683  template <typename TickPoint, typename TimeTickScale = electronics_tick>
684  constexpr TimeTickScale startTick() const;
685 
686  /// @}
687  // --- END -- Reference times ----------------------------------------------
688 
689  private:
692 
693  }; // class DetectorTimings
694 
695  /// Returns `DetectorTimings` object from specified
696  /// `detinfo::DetectorClocksData`.
699  {
700  return detinfo::DetectorTimings{detClocks};
701  }
702 
703  /// Returns `DetectorTimings` object from specified
704  /// `detinfo::DetectorClocksData`.
707  {
708  return makeDetectorTimings(*detClocks);
709  }
710 
711  /// Returns `DetectorTimings` object from specified
712  /// `detinfo::DetectorClocksWithUnits`.
715  {
716  return static_cast<detinfo::DetectorTimings const&>(detClocksWU);
717  }
718 
719  // ---------------------------------------------------------------------------
720 
721 } // namespace detinfo
722 
723 //------------------------------------------------------------------------------
724 //--- template implementation
725 //------------------------------------------------------------------------------
726 namespace detinfo {
727 
728  // ---------------------------------------------------------------------------
729  namespace details {
730 
731  using namespace util::quantities::time_literals;
733 
734  // -------------------------------------------------------------------------
735  // --- StartTimeImpl
736  // -------------------------------------------------------------------------
737  template <typename TimePoint, typename TimeScale = TimePoint, typename = void>
738  struct StartTimeImpl {
739 
740  static constexpr TimeScale startTime [[noreturn]] (DetectorTimings const*)
741  {
742  static_assert(util::always_false_v<TimePoint>,
743  "Start time not implemented for this time in this time scale.");
744  throw false;
745  }
746 
747  }; // StartTimeImpl
748 
749  // -------------------------------------------------------------------------
750  template <typename TimePoint>
751  struct StartTimeImpl<TimePoint, TimePoint> {
752 
753  static constexpr TimePoint
755  {
756  return TimePoint{0_us};
757  }
758 
759  }; // StartTimeImpl<>
760 
761  // -------------------------------------------------------------------------
762  // --- to electronics time
763  // ---
764  template <>
767  > {
769  startTime(DetectorTimings const* detTiming)
770  {
772  }
773 
774  }; // StartTimeImpl<>
775 
776  // -------------------------------------------------------------------------
777  template <>
780  > {
783  {
785  }
786 
787  }; // StartTimeImpl<>
788 
789  // -------------------------------------------------------------------------
790  template <>
793  > {
795  startTime(DetectorTimings const* detTiming)
796  {
798  detTiming->detClocksUnits().G4ToElecTime(0.0_ns)};
799  } // startTime()
800 
801  }; // StartTimeImpl<>
802 
803  // -------------------------------------------------------------------------
804  template <>
805  struct StartTimeImpl<detinfo::timescales::trigger_time, // scale to convert the start of
806  detinfo::timescales::electronics_time // destination scale
807  > {
809  startTime(DetectorTimings const* detTiming)
810  {
811  return detTiming->TriggerTime();
812  }
813 
814  }; // StartTimeImpl<>
815 
816  // -------------------------------------------------------------------------
817  // --- from electronics time
818  // ---
819  template <typename TimeScale>
822  TimeScale, // destination
823  std::enable_if_t<!std::is_same_v<TimeScale, detinfo::timescales::electronics_time>>> {
824  static TimeScale
825  startTime(DetectorTimings const* detTiming)
826  {
827  return TimeScale{
828  -(detTiming->startTime<TimeScale, detinfo::timescales::electronics_time>().quantity())};
829  }
830 
831  }; // StartTimeImpl<>
832 
833  // -------------------------------------------------------------------------
834  // --- via electronics time
835  // ---
836 
837  /*
838  * this is a very generic version, which I hope C++ rules will prevent from
839  * clashing with:
840  * * the most generic version (this is a specialization)
841  * * the one with same target and destination (explicitly vetoed)
842  * * any one involving electronics_time (explicitly vetoed)
843  * * any full specialization (this being partial, the full ones should win)
844  */
845  template <typename TimePoint, typename TimeScale>
847  TimePoint, // source
848  TimeScale, // destination
849  std::enable_if_t<!std::is_same_v<TimePoint, detinfo::timescales::electronics_time> &&
850  !std::is_same_v<TimeScale, detinfo::timescales::electronics_time> &&
851  !std::is_same_v<TimeScale, TimePoint>>> {
852  static TimeScale
853  startTime(DetectorTimings const* detTiming)
854  {
855  return detTiming->toTimeScale<TimeScale>(detTiming->startTime<TimePoint>());
856  }
857  }; // StartTimeImpl<> (via electronics_time)
858 
859  // -------------------------------------------------------------------------
860  // --- StartTickImpl
861  // -------------------------------------------------------------------------
862  template <typename TickPoint, typename TimeTickScale = TickPoint>
864 
865  // -------------------------------------------------------------------------
866  template <typename TickPoint>
867  struct StartTickImpl<TickPoint, TickPoint> {
868 
869  static constexpr TickPoint
871  {
872  return TickPoint::castFrom(0.0);
873  }
874 
875  }; // StartTickImpl<>
876 
877  // -------------------------------------------------------------------------
878  template <>
881  > {
883  startTick(DetectorTimings const* detTiming)
884  {
886  detTiming->detClocksUnits().TPCTick2TDC(0_tickd));
887  }
888 
889  }; // StartTimeImpl<>
890 
891  // -------------------------------------------------------------------------
892  template <>
895  > {
898  {
899  return 0_tickd;
900  }
901 
902  }; // StartTickImpl<>
903 
904  // -------------------------------------------------------------------------
905 
906  // default implementation (for any time)
907  template <typename FromTime, typename TargetTime, typename = void>
909 
910  static TargetTime
911  convert(FromTime time, DetectorTimings const* timings)
912  {
913  return timings->startTime<FromTime, TargetTime>() + time.quantity();
914  }
915  };
916 
917  // special implementation when source and target are the same: passthrough
918  template <typename TargetTime>
919  struct TimeScaleConverter<TargetTime, TargetTime> {
920 
921  static TargetTime
922  convert(TargetTime time, DetectorTimings const*)
923  {
924  return time;
925  }
926 
927  }; // TimeScaleConverter<TargetTime, TargetTime>
928 
929  // special implementation for ticks as source
930  template <typename FromTick, typename TargetTime>
931  struct TimeScaleConverter<FromTick,
932  TargetTime,
933  std::enable_if_t<detinfo::timescales::is_tick_v<FromTick>>> {
934 
935  static TargetTime
936  convert(FromTick tick, DetectorTimings const* timings)
937  {
938  using FromTime = typename detinfo::timescales::timescale_traits<
939  typename FromTick::category_t>::time_point_t;
940  return timings->toTimeScale<TargetTime>(
941  FromTime{tick.value() * timings->ClockPeriodFor<FromTick>().quantity()});
942  }
943 
944  }; // TimeScaleConverter<FromTick>
945 
946  // -------------------------------------------------------------------------
947  // default implementation (for any time)
948  template <typename FromTime, typename TargetTick, typename = void>
949  struct TickConverter {
950 
951 
952  static TargetTick convert
953  (FromTime time, DetectorTimings const* timings)
954  {
955  // dispatcher
956  if constexpr(detinfo::timescales::is_tick_v<FromTime>)
957  return convertTick(time, timings);
958  else
959  return convertTime(time, timings);
960  } // convert()
961 
962 
963  static TargetTick
964  convertTime(FromTime time, DetectorTimings const* timings)
965  {
966  static_assert(!detinfo::timescales::is_tick_v<FromTime>);
967  using TargetTime = typename detinfo::timescales::timescale_traits<
968  typename TargetTick::category_t>::time_point_t;
969  auto const timeFromStart = time - timings->startTime<TargetTime, FromTime>();
970  auto const clockPeriod = timings->ClockPeriodFor<TargetTick>();
971  return TargetTick::castFrom(timeFromStart / clockPeriod);
972  } // convertTime()
973 
974  static TargetTick
975  convertTick(FromTime tick, DetectorTimings const* timings)
976  {
977  static_assert(detinfo::timescales::is_tick_v<FromTime>);
978  // effectively we must go very close to the times from the tick;
979  // so we go all the way there
980  using TargetTime = typename detinfo::timescales::timescale_traits<
981  typename TargetTick::category_t>::time_point_t;
982  auto const time = timings->toTimeScale<TargetTime>(tick);
983  return timings->toTick<TargetTick>(time);
984  } // convertTick()
985 
986  }; // TickConverter
987 
988  // -------------------------------------------------------------------------
989 
990  // -------------------------------------------------------------------------
991  template <typename TimeScale, typename = void>
992  struct ClockForImpl {
993 
994  static detinfo::ElecClock const& get [[noreturn]] (DetectorTimings const*)
995  {
996  static_assert(util::always_false_v<TimeScale>,
997  "Electronics clock not defined for this time scale.");
998  throw false;
999  }
1000 
1001  }; // struct ClockForImpl
1002 
1003  template <typename TimeScale>
1004  struct ClockForImpl<TimeScale, std::void_t<typename TimeScale::category_t>>
1005  : ClockForImpl<typename TimeScale::category_t> {};
1006 
1007  template <>
1009  static detinfo::ElecClock const&
1010  get(DetectorTimings const* timings)
1011  {
1012  return timings->clockData().TPCClock();
1013  }
1014  };
1015 
1016  template <>
1018  static detinfo::ElecClock const&
1019  get(DetectorTimings const* timings)
1020  {
1021  return timings->clockData().OpticalClock();
1022  }
1023  };
1024 
1025  template <>
1027  static detinfo::ElecClock const&
1028  get(DetectorTimings const* timings)
1029  {
1030  return timings->clockData().TriggerClock();
1031  }
1032  };
1033 
1034  template <>
1036  : ClockForImpl<detinfo::timescales::TPCelectronicsTimeCategory> {};
1037 
1038  // -------------------------------------------------------------------------
1039 
1040  } // namespace details
1041 
1042  // ---------------------------------------------------------------------------
1043  template <typename TimePoint, typename TimeScale /* = electronics_time */>
1044  constexpr TimeScale
1046  {
1048  }
1049 
1050  // ---------------------------------------------------------------------------
1051  template <typename TickPoint, typename TimeTickScale /* = electronics_tick */>
1052  constexpr TimeTickScale
1054  {
1056  }
1057 
1058  // ---------------------------------------------------------------------------
1059  template <typename TargetTime, typename FromTime>
1060  TargetTime
1062  {
1064  } // DetectorTimings::toTimeScale()
1065 
1066  // ---------------------------------------------------------------------------
1067  template <typename TargetTick, typename FromTime>
1068  TargetTick
1070  {
1072  } // DetectorTimings::toTick()
1073 
1074  // ---------------------------------------------------------------------------
1075  template <typename TimeScale>
1076  detinfo::ElecClock const&
1078  {
1080  }
1081 
1082  // ---------------------------------------------------------------------------
1083  inline auto
1085  {
1086  return time - startTime<electronics_time, electronics_time>();
1087  }
1088 
1089  // ---------------------------------------------------------------------------
1090 
1091 } // namespace detinfo
1092 
1093 //------------------------------------------------------------------------------
1094 
1095 #endif // LARDATAALG_DETECTORINFO_DETECTORTIMINGS_H
Literal constants for electronics quantities.
Definition: electronics.h:140
timescale_traits< TriggerTimeCategory >::tick_d_t trigger_tick_d
A point on the trigger time scale expressed in its ticks (real).
electronics_time BeamGateTime() const
megahertz OpticalClockFrequency() const
Dimensioned variables representing frequency quantities.
ticks_d TPCTick2TDC(double tpcticks) const
static detinfo::ElecClock const & get(DetectorTimings const *)
microsecond OpticalClockPeriod() const
timescale_traits< ElectronicsTimeCategory >::tick_t electronics_tick
A point on the electronics time scale expressed in its ticks.
megahertz OpticalClockFrequency() const
Returns the frequency of the optical clock tick.
microsecond BeamGateTime() const
Equivalent to detinfo::DetectorClocksData::BeamGateTime().
detinfo::timescales::TPCelectronics_time_ticks TPCelectronics_time_ticks
microsecond_as<> microsecond
Type of time stored in microseconds, in double precision.
Definition: spacetime.h:119
detinfo::timescales::TPCelectronics_time TPCelectronics_time
microsecond G4ToElecTime(nanosecond simTime) const
Equivalent to detinfo::DetectorClocksData::G4ToElecTime().
Ticks toTicks(time_interval time) const
Returns the number of ticks corresponding to a time interval.
static constexpr TimePoint startTime(DetectorTimings const *)
optical_tick toOpticalTick(TimePoint time) const
Returns the time point converted in units of optical time ticks.
DetectorClocksWithUnits(detinfo::DetectorClocksData const &detClocks)
trigger_time toTriggerTime(FromTime time) const
Converts a time point into trigger time scale.
detinfo::DetectorClocksData const & clockData() const
Returns the detector clocks data.
ticks_d TPCTick2TDC(ticks_d tpcticks) const
Equivalent to detinfo::DetectorClocksData::G4ToElecTime().
static constexpr detinfo::timescales::electronics_time startTime(DetectorTimings const *)
detinfo::timescales::electronics_time_ticks electronics_time_ticks
timescale_traits< TriggerTimeCategory >::tick_t trigger_tick
A point on the trigger time scale expressed in its ticks.
Category for electronics time scale.
static TargetTime convert(FromTime time, DetectorTimings const *timings)
detinfo::timescales::electronics_tick electronics_tick
util::quantities::intervals::microseconds time_interval
STL namespace.
tick_d ticks_d
Alias for common language habits.
Definition: electronics.h:90
frequency_for< TimeScale > ClockFrequencyFor() const
Returns the frequency of the clock for the specified time scale.
detinfo::timescales::TPCelectronics_tick_d TPCelectronics_tick_d
A collection of traits for a time scale.
static constexpr TimeScale startTime(DetectorTimings const *)
detinfo::DetectorClocksData const & clockData() const
Returns the detector clocks data object.
constexpr value_t value() const
Returns the value of the quantity.
Definition: quantities.h:609
detinfo::timescales::trigger_tick_d trigger_tick_d
static detinfo::timescales::electronics_time startTime(DetectorTimings const *detTiming)
static TargetTime convert(TargetTime time, DetectorTimings const *)
detinfo::timescales::electronics_time electronics_time
quantity
Definition: statistics_t.cc:15
microsecond G4ToElecTime(double simTime) const
constexpr double TickPeriod() const noexcept
A single tick period in microseconds.
Definition: ElecClock.h:352
DetectorTimings(detinfo::DetectorClocksData const &clockData)
Constructor: wraps around a specified detinfo::DetectorClocksData object.
timescale_traits< OpticalTimeCategory >::tick_interval_t optical_time_ticks
timescale_traits< TPCelectronicsTimeCategory >::tick_d_t TPCelectronics_tick_d
A point on the TPC electronics time scale expressed in its ticks (real).
timescale_traits< TriggerTimeCategory >::time_point_t trigger_time
A point in time on the trigger time scale.
timescale_traits< TriggerTimeCategory >::tick_interval_t trigger_time_ticks
An interval on the trigger time scale expressed in its ticks.
detinfo::DetectorClocksWithUnits const & detClocksUnits() const
Returns a DetectorClocksWithUnits object.
A partial detinfo::DetectorClocksData supporting units.
DetectorClocksWithUnits(detinfo::DetectorClocksData const *detClocks)
Constructor: uses detClocks for internal conversions.
timescale_traits< ElectronicsTimeCategory >::tick_interval_t electronics_time_ticks
An interval on the electronics time scale expressed in its ticks.
electronics_time toElectronicsTime(FromTime time) const
Converts a time point into electronics time scale.
typename traits_of< TimeScale >::time_interval_t time_interval_for
The time interval type of a specific TimeScale.
time_interval_for< TimeScale > ClockPeriodFor() const
Returns the period of the clock for the specified time scale.
double BeamGateTime() const
Beam gate electronics clock time in [us].
detinfo::timescales::simulation_time simulation_time
Ticks toOpticalTicks(time_interval time) const
Returns the optical ticks corresponding to a time interval.
timescale_traits< SimulationTimeCategory >::time_point_t simulation_time
A point in time on the simulation time scale.
timescale_traits< TPCelectronicsTimeCategory >::tick_interval_t TPCelectronics_time_ticks
An interval on the TPC electronics time scale expressed in its ticks.
detinfo::timescales::trigger_time_ticks trigger_time_ticks
A value measured in the specified unit.
Definition: quantities.h:566
def convert(inputfile, outputfile="wire-cell-garfield-fine-response.json.bz2", average=False, shaped=False)
Definition: garfield.py:262
microsecond TPCTime() const
Equivalent to detinfo::DetectorClocksData::TPCTime().
detinfo::DetectorTimings makeDetectorTimings(detinfo::DetectorClocksData const &detClocks)
static constexpr detinfo::timescales::electronics_tick_d startTick(DetectorTimings const *)
megahertz_as<> megahertz
Type of frequency stored in megahertz, in double precision.
Definition: frequency.h:101
simulation_time toSimulationTime(FromTime time) const
Converts a time point into simulation time scale.
detinfo::timescales::trigger_tick trigger_tick
detinfo::DetectorClocksData fClockData
The backend instance of detinfo::DetectorClocksData this object uses.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
typename traits_of< TimeScale >::frequency_t frequency_for
The frequency type of a specific TimeScale.
ElecClock const & OpticalClock() const noexcept
Borrow a const Optical clock with time set to Trigger time [us].
static TargetTick convertTick(FromTime tick, DetectorTimings const *timings)
timescale_traits< OpticalTimeCategory >::time_point_t optical_time
A point in time on the optical detector electronics time scale.
detinfo::timescales::optical_time optical_time
constexpr TimeTickScale startTick() const
Returns the start tick of the specified time tick scale.
timescale_traits< ElectronicsTimeCategory >::tick_d_t electronics_tick_d
A point on the electronics time scale expressed in its ticks (real).
static detinfo::timescales::electronics_tick_d startTick(DetectorTimings const *detTiming)
General LArSoft Utilities.
detinfo::DetectorClocksWithUnits makeDetectorClocksWithUnits(detinfo::DetectorClocksData const &clockData)
static detinfo::timescales::electronics_time startTime(DetectorTimings const *detTiming)
An interval (duration, length, distance) between two quantity points.
Definition: intervals.h:114
electronics_tick_d toElectronicsTickD(FromTime time) const
Converts a time point into electronics tick (real).
electronics_time TriggerTime() const
Category for trigger time scale.
Literal constants for time quantities.
Definition: spacetime.h:175
double TriggerTime() const
Trigger electronics clock time in [us].
detinfo::timescales::TPCelectronics_tick TPCelectronics_tick
detinfo::ElecClock const & ClockFor() const
Returns the electronics clock for the specified time scale.
detinfo::timescales::trigger_time trigger_time
Category for electronics time scale.
Category for TPC electronics time scale.
Dimensioned variables related to electronics.
timescale_traits< OpticalTimeCategory >::tick_t optical_tick
detinfo::timescales::electronics_tick_d electronics_tick_d
static TargetTick convertTime(FromTime time, DetectorTimings const *timings)
TargetTime toTimeScale(FromTime time) const
Returns a time point in a different time scale.
double G4ToElecTime(double const g4_time) const
TargetTick toTick(FromTime time) const
Returns a time point as a tick on a different time scale.
Contains all timing reference information for the detector.
Dimensioned variables representing space or time quantities.
A class exposing an upgraded interface of detinfo::DetectorClocksData.
Data types for detinfo::DetectorTimings.
nanosecond_as<> nanosecond
Type of time stored in nanoseconds, in double precision.
Definition: spacetime.h:136
constexpr double Frequency() const
Frequency in MHz.
Definition: ElecClock.h:191
detinfo::timescales::optical_tick_d optical_tick_d
static detinfo::timescales::electronics_time startTime(DetectorTimings const *detTiming)
timescale_traits< OpticalTimeCategory >::tick_d_t optical_tick_d
time_interval fromStart(electronics_time time) const
Converts a electronics time point into a duration from the start of electronics time.
timescale_traits< TPCelectronicsTimeCategory >::time_point_t TPCelectronics_time
A point in time on the TPC electronics time scale.
Class representing the time measured by an electronics clock.
Definition: ElecClock.h:91
auto OpticalClockPeriod() const
Returns the duration of the optical clock period and tick.
microsecond TriggerTime() const
Equivalent to detinfo::DetectorClocksData::TriggerTime().
optical_tick_d toOpticalTickD(TimePoint time) const
Returns the time point converted in units of optical time ticks.
detinfo::timescales::optical_time_ticks optical_time_ticks
double TPCTick2TDC(double const tick) const
timescale_traits< TPCelectronicsTimeCategory >::tick_t TPCelectronics_tick
A point on the TPC electronics time scale expressed in its ticks.
detinfo::timescales::optical_tick optical_tick
timescale_traits< ElectronicsTimeCategory >::time_point_t electronics_time
A point in time on the electronics time scale.
electronics_tick toElectronicsTick(FromTime time) const
Converts a time point into electronics tick (truncated).
static constexpr TickPoint startTick(DetectorTimings const *)
constexpr TimeScale startTime() const
Returns the start time of the specified time scale.
DetectorTimings(detinfo::DetectorClocksData const *clockData)
static TargetTick convert(FromTime time, DetectorTimings const *timings)