DetectorTimingsStandard_test.cc
Go to the documentation of this file.
1 /**
2  * @file DetectorTimingsStandard_test.cc
3  * @brief Test of `detinfo::DetectorTimings` with `DetectorClocksStandard`.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date June 27, 2019
6  */
7 
8 // LArSoft libraries
9 #include "larcorealg/CoreUtils/DebugUtils.h" // lar::debug::static_assert_on<>()
10 #include "larcorealg/CoreUtils/MetaUtils.h" // util::is_same_decay_v
17 #include "lardataalg/Utilities/quantities/frequency.h" // megahertz
18 #include "lardataalg/Utilities/quantities/spacetime.h" // microsecond, ...
19 
20 // framework libraries
21 #include "messagefacility/MessageLogger/MessageLogger.h" // mf namespace
22 
23 #include <limits>
24 
25 //------------------------------------------------------------------------------
26 //--- static tests
27 //------------------------------------------------------------------------------
28 void StaticChecks() {
29  using namespace detinfo::timescales;
30  static_assert(!is_tick_v<electronics_time>);
31  static_assert( is_tick_v<electronics_tick>);
32  static_assert( is_tick_v<electronics_tick_d>);
33  static_assert( is_tick_v<electronics_time_ticks>);
34  static_assert( is_tick_v<electronics_time_ticks_d>);
35  static_assert(!is_tick_v<TPCelectronics_time>);
36  static_assert( is_tick_v<TPCelectronics_tick>);
37  static_assert( is_tick_v<TPCelectronics_tick_d>);
38  static_assert( is_tick_v<TPCelectronics_time_ticks>);
39  static_assert( is_tick_v<TPCelectronics_time_ticks_d>);
40  static_assert(!is_tick_v<trigger_time>);
41  static_assert( is_tick_v<trigger_tick>);
42  static_assert( is_tick_v<trigger_tick_d>);
43  static_assert( is_tick_v<trigger_time_ticks>);
44  static_assert( is_tick_v<trigger_time_ticks_d>);
45  static_assert(!is_tick_v<simulation_time>);
46  static_assert(!is_tick_v<optical_time>);
47  static_assert( is_tick_v<optical_tick>);
48  static_assert( is_tick_v<optical_tick_d>);
49  static_assert( is_tick_v<optical_time_ticks>);
50  static_assert( is_tick_v<optical_time_ticks_d>);
51 } // StaticChecks()
52 
53 
54 //------------------------------------------------------------------------------
55 //--- The test environment
56 //---
57 
58 /*
59  * TesterEnvironment, configured with a "standard" configuration object, is used
60  * in a non-Boost-unit-test context.
61  * It provides:
62  *
63  */
65 
66 namespace {
67  double
68  close_in_value(double const a, double const b)
69  {
70  return std::abs(a - b) < std::numeric_limits<double>::epsilon();
71  }
72 }
73 
74 //------------------------------------------------------------------------------
75 //--- The tests
76 //---
77 unsigned int
79 {
80 
81  unsigned int nErrors = 0U;
82 
83  //
84  // trigger time
85  //
86  double const expectedTime = timings.clockData().TriggerTime(); // us
87 
88  // `TriggerTime()` returns a time in electronics time scale [us]
89  auto const time = timings.TriggerTime();
90  static_assert(util::is_same_decay_v<decltype(time.quantity()), util::quantities::microsecond>);
91 
92  if (time.value() == expectedTime) {
93  mf::LogVerbatim("DetectorTimingsStandard_test") << "DetectorTimings::TriggerTime() => " << time;
94  }
95  else {
96  ++nErrors;
97  mf::LogProblem("DetectorTimingsStandard_test")
98  << "Trigger time expected to be " << expectedTime << " us in electronics time, but got "
99  << time << " instead";
100  }
101 
102  return nErrors;
103 } // testTriggerTime()
104 
105 //------------------------------------------------------------------------------
106 unsigned int
108 {
109  unsigned int nErrors = 0U;
110 
111  //
112  // trigger time
113  //
114  double const expectedTime = timings.clockData().BeamGateTime(); // us
115 
116  // `BeamGateTime()` returns a time in electronics time scale [us]
117  auto const time = timings.BeamGateTime();
118  static_assert(util::is_same_decay_v<decltype(time.quantity()), util::quantities::microsecond>);
119 
120  if (close_in_value(time.value(), expectedTime)) {
121  mf::LogVerbatim("DetectorTimingsStandard_test")
122  << "DetectorTimings::BeamGateTime() => " << time;
123  }
124  else {
125  ++nErrors;
126  mf::LogProblem("DetectorTimingsStandard_test")
127  << "Beam gate time expected to be " << expectedTime << " us in electronics time, but got "
128  << time << " instead";
129  }
130 
131  return nErrors;
132 } // testBeamGateTime()
133 
134 //------------------------------------------------------------------------------
135 unsigned int
137 {
138 
139  using namespace detinfo::timescales; // simulation_time, electronics_time, ...
141 
142  unsigned int nErrors = 0U;
143 
144  constexpr lar::util::RealComparisons cmp(1e-4);
145 
146  //
147  // start time
148  //
149 
150  // simulation time start in electronics time
151  double const expectedStartTime_us = timings.clockData().G4ToElecTime(0.0); // ns
152  microsecond const expectedStartTime{expectedStartTime_us};
153 
154  // `startTime()` returns a time in electronics time scale [us]
155  auto const startTime = timings.startTime<simulation_time>();
156  static_assert(
157  util::is_same_decay_v<decltype(startTime.quantity()), util::quantities::microsecond>);
158 
159  if (startTime == expectedStartTime) {
160  mf::LogVerbatim("DetectorTimingsStandard_test")
161  << "DetectorTimings::startTime<simulation_time>() => " << startTime;
162  }
163  else {
164  ++nErrors;
165  mf::LogProblem("DetectorTimingsStandard_test")
166  << "Simulation time expected to start at " << expectedStartTime
167  << " in electronics time, but got " << startTime << " instead";
168  }
169 
170  // electronics time start in simulation time
171  auto const elecStartTime = timings.startTime<electronics_time, simulation_time>();
172  static_assert(
173  util::is_same_decay_v<decltype(elecStartTime.quantity()), util::quantities::nanosecond>);
174 
175  if (elecStartTime == -expectedStartTime) {
176  mf::LogVerbatim("DetectorTimingsStandard_test")
177  << "DetectorTimings::startTime<electronics_time, simulation_time>() => " << elecStartTime;
178  }
179  else {
180  ++nErrors;
181  mf::LogProblem("DetectorTimingsStandard_test")
182  << "Electronics time expected to start at " << (-expectedStartTime)
183  << " in simulation time, but got " << elecStartTime << " instead";
184  }
185 
186  //
187  // time conversions
188  //
189 
190  // to electronics time:
191  double const inputTime_ns = 100.0;
192  double const expectedTime = timings.clockData().G4ToElecTime(inputTime_ns);
193 
194  simulation_time inputTime{inputTime_ns};
195  static_assert(
196  util::is_same_decay_v<decltype(inputTime.quantity()), util::quantities::nanosecond>);
197 
198  auto const time = timings.toElectronicsTime(inputTime);
199  static_assert(util::is_same_decay_v<decltype(time.quantity()), util::quantities::microsecond>);
200 
201  if (time.value() == expectedTime) {
202  mf::LogVerbatim("DetectorTimingsStandard_test")
203  << "DetectorTimings::toElectronicsTime<simulation_time>(" << inputTime << ") => " << time;
204  }
205  else {
206  ++nErrors;
207  mf::LogProblem("DetectorTimingsStandard_test")
208  << "A simulation time of " << inputTime << " is expected to be " << expectedTime
209  << " us in electronics time, but got " << time << " instead";
210  }
211 
212  // back to simulation time:
213 
214  auto const simulTime = timings.toSimulationTime(electronics_time{expectedTime});
215  static_assert(
216  util::is_same_decay_v<decltype(simulTime.quantity()), util::quantities::nanosecond>);
217 
218  if (simulTime.value() == inputTime_ns) {
219  mf::LogVerbatim("DetectorTimingsStandard_test")
220  << "DetectorTimings::toTimeScale<electronics_time>(" << expectedTime << ") => " << simulTime;
221  }
222  else {
223  ++nErrors;
224  mf::LogProblem("DetectorTimingsStandard_test")
225  << "An electronics time of " << expectedTime << " us is expected to be " << inputTime
226  << " in simulation time, but got " << simulTime << " instead";
227  }
228 
229  // to TPC electronics ticks:
230  double const expectedTPCtick = timings.clockData().TPCG4Time2Tick(inputTime_ns);
231 
232  auto const TPCtick = timings.toTick<TPCelectronics_tick_d>(inputTime);
233  if (cmp.equal(TPCtick.value(), expectedTPCtick)) {
234  mf::LogVerbatim("DetectorTimingsStandard_test")
235  << "DetectorTimings::toTick<TPCelectronics_tick_d>(" << inputTime << ") => " << TPCtick;
236  }
237  else {
238  ++nErrors;
239  mf::LogProblem("DetectorTimingsStandard_test")
240  << "A simulation time of " << inputTime << " is expected to be at " << expectedTPCtick
241  << " TPC electronics tick, but got " << TPCtick << " instead";
242  }
243 
244  // let's try some more complex transformations...
245 
246  // which simulation times is the trigger time plus 100 TPC ticks?
247  auto const trigTime = timings.TriggerTime();
248  electronics_time_ticks const tickOffset{100};
249  simulation_time const expectedSimulTick =
250  timings.toTimeScale<simulation_time>(trigTime) +
251  tickOffset.value() * timings.ClockPeriodFor<electronics_time>();
252  auto const tick = timings.toTick<electronics_tick>(trigTime) + tickOffset;
253  auto const simulTick = timings.toTimeScale<simulation_time>(tick);
254 
255  if (simulTick == expectedSimulTick) {
256  mf::LogVerbatim("DetectorTimingsStandard_test")
257  << "DetectorTimings::toTimeScale<simulation_time>(" << trigTime << " + " << tickOffset
258  << " = " << tick << ") => " << simulTick;
259  }
260  else {
261  ++nErrors;
262  mf::LogProblem("DetectorTimingsStandard_test")
263  << "An offset of " << tickOffset << " on trigger time (" << trigTime << ") is expected to be "
264  << expectedSimulTick << " in simulation time, but got " << simulTick << " instead";
265  }
266 
267  return nErrors;
268 } // testSimulationTimes()
269 
270 //------------------------------------------------------------------------------
271 unsigned int
273 {
274 
275  using namespace detinfo::timescales; // trigger_time, electronics_time
276 
277  unsigned int nErrors = 0U;
278 
279  //
280  // start time
281  //
282 
283  // trigger time start in electronics time
284  double const expectedStartTime = timings.clockData().TriggerTime(); // us
285 
286  // `startTime()` returns a time in electronics time scale [us]
287  auto const startTime = timings.startTime<trigger_time>();
288  static_assert(
289  util::is_same_decay_v<decltype(startTime.quantity()), util::quantities::microsecond>);
290 
291  if (startTime.value() == expectedStartTime) {
292  mf::LogVerbatim("DetectorTimingsStandard_test")
293  << "DetectorTimings::startTime<trigger_time>() => " << startTime;
294  }
295  else {
296  ++nErrors;
297  mf::LogProblem("DetectorTimingsStandard_test")
298  << "Trigger time expected to start at " << expectedStartTime
299  << " us in electronics time, but got " << startTime << " instead";
300  }
301 
302  // electronics time start in trigger time
303  auto const elecStartTime = timings.startTime<electronics_time, trigger_time>();
304  static_assert(
305  util::is_same_decay_v<decltype(elecStartTime.quantity()), util::quantities::microsecond>);
306 
307  if (elecStartTime.value() == -expectedStartTime) {
308  mf::LogVerbatim("DetectorTimingsStandard_test")
309  << "DetectorTimings::startTime<electronics_time, trigger_time>() => " << elecStartTime;
310  }
311  else {
312  ++nErrors;
313  mf::LogProblem("DetectorTimingsStandard_test")
314  << "Electronics time expected to start at " << (-expectedStartTime)
315  << " us in trigger time, but got " << elecStartTime << " instead";
316  }
317 
318  //
319  // time conversions
320  //
321 
322  // to electronics time:
323  double const inputTime_us = 100.0;
324  double const expectedTime = timings.clockData().TriggerTime() + inputTime_us;
325 
326  trigger_time inputTime{inputTime_us};
327  static_assert(
328  util::is_same_decay_v<decltype(inputTime.quantity()), util::quantities::microsecond>);
329 
330  auto const time = timings.toElectronicsTime(inputTime);
331  static_assert(util::is_same_decay_v<decltype(time.quantity()), util::quantities::microsecond>);
332 
333  if (time.value() == expectedTime) {
334  mf::LogVerbatim("DetectorTimingsStandard_test")
335  << "DetectorTimings::toElectronicsTime<trigger_time>(" << inputTime << ") => " << time;
336  }
337  else {
338  ++nErrors;
339  mf::LogProblem("DetectorTimingsStandard_test")
340  << "A trigger time of " << inputTime << " is expected to be " << expectedTime
341  << " us in electronics time, but got " << time << " instead";
342  }
343 
344  // back to trigger time:
345 
346  auto const trigTime = timings.toTriggerTime(electronics_time{expectedTime});
347  static_assert(
348  util::is_same_decay_v<decltype(trigTime.quantity()), util::quantities::microsecond>);
349 
350  if (trigTime.value() == inputTime_us) {
351  mf::LogVerbatim("DetectorTimingsStandard_test")
352  << "DetectorTimings::toTriggerTime<electronics_time>(" << expectedTime << ") => " << trigTime;
353  }
354  else {
355  ++nErrors;
356  mf::LogProblem("DetectorTimingsStandard_test")
357  << "An electronics time of " << expectedTime << " us is expected to be " << inputTime
358  << " in trigger time, but got " << trigTime << " instead";
359  }
360 
361  return nErrors;
362 } // testTriggerTimes()
363 
364 //------------------------------------------------------------------------------
365 unsigned int
367 {
368 
369  using namespace util::quantities::time_literals;
370  using namespace detinfo::timescales; // optical_time, optical_tick
371 
372  unsigned int nErrors = 0U;
373 
374  //
375  // clocks
376  //
377 
378  // frequency
379  double const expectedFrequency = timings.clockData().OpticalClock().Frequency(); // MHz
380 
381  auto const frequency = timings.OpticalClockFrequency();
382  static_assert(util::is_same_decay_v<decltype(frequency), util::quantities::megahertz>);
383 
384  if (frequency.value() == expectedFrequency) {
385  mf::LogVerbatim("DetectorTimingsStandard_test")
386  << "DetectorTimings::OpticalClockFrequency() => " << frequency;
387  }
388  else {
389  ++nErrors;
390  mf::LogProblem("DetectorTimingsStandard_test")
391  << "Optical clock frequency expected to be " << expectedFrequency << " MHz, but got "
392  << frequency << " instead";
393  }
394 
395  // period
396  double const expectedPeriod = timings.clockData().OpticalClock().TickPeriod(); // MHz
397 
398  auto const period = timings.OpticalClockPeriod();
399  static_assert(util::is_same_decay_v<decltype(period)::quantity_t, util::quantities::microsecond>);
400 
401  if (period.value() == expectedPeriod) {
402  mf::LogVerbatim("DetectorTimingsStandard_test")
403  << "DetectorTimings::OpticalClockPeriod() => " << period;
404  }
405  else {
406  ++nErrors;
407  mf::LogProblem("DetectorTimingsStandard_test")
408  << "Optical clock period expected to be " << expectedPeriod << " us, but got " << period
409  << " instead";
410  }
411 
412  if (std::abs(period.quantity() * frequency - 1.0) > 1e-4) {
413  ++nErrors;
414  mf::LogProblem("DetectorTimingsStandard_test")
415  << "Optical clock period (" << period << ") and frequency (" << frequency
416  << " should have been one the inverse of the other! (their product is "
417  << (period.quantity() * frequency) << ")";
418  }
419 
420  //
421  // start time
422  //
423 
424  // in electronics scale
425  // optical time has no defined start time, and DetectorTimings sets it to
426  // the same time as the start of the electronics time
427  auto const expectedStartTime = 0_us;
428 
429  auto const startTime = timings.startTime<optical_time>();
430  static_assert(
431  util::is_same_decay_v<decltype(startTime.quantity()), util::quantities::microsecond>);
432 
433  if (startTime == expectedStartTime) {
434  mf::LogVerbatim("DetectorTimingsStandard_test")
435  << "DetectorTimings::startTime<optical_time>() => " << startTime;
436  }
437  else {
438  ++nErrors;
439  mf::LogProblem("DetectorTimingsStandard_test")
440  << "Start of optical time scale is expected to be " << expectedStartTime
441  << " in electronics time, but got " << startTime << " instead";
442  }
443 
444  // in trigger scale
445  auto const expectedTrigStartTime = expectedStartTime - timings.detClocksUnits().TriggerTime();
446 
447  auto const trigStartTime = timings.startTime<optical_time, trigger_time>();
448  static_assert(
449  util::is_same_decay_v<decltype(trigStartTime.quantity()), util::quantities::microsecond>);
450 
451  if (trigStartTime == expectedTrigStartTime) {
452  mf::LogVerbatim("DetectorTimingsStandard_test")
453  << "DetectorTimings::startTime<optical_time, trigger_time>() => " << trigStartTime;
454  }
455  else {
456  ++nErrors;
457  mf::LogProblem("DetectorTimingsStandard_test")
458  << "Start of optical time scale is expected to be " << expectedTrigStartTime
459  << " in trigger time, but got " << trigStartTime << " instead";
460  }
461 
462  //
463  // time conversions
464  //
465  double const inputTick_count = 900.5;
466 
467  //
468  // to electronics time (real tick):
469  //
470  double const expectedTime_us = inputTick_count * timings.clockData().OpticalClock().TickPeriod();
471 
472  optical_tick_d inputTick_d{inputTick_count};
473  static_assert(util::is_same_decay_v<decltype(inputTick_d.quantity()), util::quantities::tick_d>);
474 
475  auto const time = timings.toElectronicsTime(inputTick_d);
476  static_assert(util::is_same_decay_v<decltype(time.quantity()), util::quantities::microsecond>);
477 
478  if (time.value() == expectedTime_us) {
479  mf::LogVerbatim("DetectorTimingsStandard_test")
480  << "DetectorTimings::toElectronicsTime<optical_tick_d>(" << inputTick_d << ") => " << time;
481  }
482  else {
483  ++nErrors;
484  mf::LogProblem("DetectorTimingsStandard_test")
485  << "Optical tick #" << inputTick_count << " is expected to be " << expectedTime_us
486  << " us in electronics time, but got " << time << " instead";
487  }
488 
489  // back to optical tick:
490  auto const tick = timings.toTick<optical_tick_d>(time);
491  static_assert(util::is_same_decay_v<decltype(tick.quantity()), util::quantities::tick_d>);
492 
493  if (tick == inputTick_d) {
494  mf::LogVerbatim("DetectorTimingsStandard_test")
495  << "DetectorTimings::toTick<optical_tick_d, "
497  << ") => " << tick;
498  }
499  else {
500  ++nErrors;
501  mf::LogProblem("DetectorTimingsStandard_test")
503  << " is expected to be optical tick " << inputTick_d << ", but got " << tick << " instead";
504  }
505 
506  // to trigger time (truncated tick):
507 
508  double const expectedTrigTime_us = expectedTime_us - timings.clockData().TriggerTime();
509  double const expectedTrigTime_truncated_us =
510  static_cast<int>(inputTick_count) * timings.clockData().OpticalClock().TickPeriod() -
511  timings.clockData().TriggerTime();
512 
513  auto const inputTick = optical_tick::castFrom(inputTick_count);
514  static_assert(util::is_same_decay_v<decltype(inputTick.quantity()), util::quantities::tick>);
515 
516  auto const trigTime = timings.toTriggerTime(inputTick);
517  static_assert(
518  util::is_same_decay_v<decltype(trigTime.quantity()), util::quantities::microsecond>);
519 
520  if (trigTime.value() == expectedTrigTime_truncated_us) {
521  mf::LogVerbatim("DetectorTimingsStandard_test")
522  << "DetectorTimings::toTriggerTime<optical_tick>(" << inputTick << ") => " << trigTime;
523  }
524  else {
525  ++nErrors;
526  mf::LogProblem("DetectorTimingsStandard_test")
527  << "Optical tick " << inputTick << " is expected to be " << expectedTrigTime_truncated_us
528  << " us in trigger time, but got " << trigTime << " instead";
529  }
530 
531  // back to optical tick:
532  auto const trigTick
533  = timings.toTick<optical_tick>(trigger_time{expectedTrigTime_us});
534  static_assert
535  (util::is_same_decay_v<decltype(trigTick.quantity()), util::quantities::tick>);
536 
537  if (trigTick == inputTick) {
538  mf::LogVerbatim("DetectorTimingsStandard_test")
539  << "DetectorTimings::toTick<optical_tick, trigger_time>(" << expectedTrigTime_us << ") => "
540  << trigTick;
541  }
542  else {
543  ++nErrors;
544  mf::LogProblem("DetectorTimingsStandard_test")
545  << "Trigger time " << expectedTrigTime_us << " us is expected to be optical tick "
546  << inputTick << ", but got " << trigTick << " instead";
547  }
548 
549  //
550  // to electronics tick
551  //
552 
553  auto const expectedElecTick = timings.toTick<electronics_tick>(time);
554 
555  auto const elecTick = timings.toTick<electronics_tick>(inputTick);
556  static_assert
557  (util::is_same_decay_v<decltype(elecTick.quantity()), util::quantities::tick>);
558 
559  if (elecTick == expectedElecTick) {
560  mf::LogVerbatim("DetectorTimingsStandard_test")
561  << "DetectorTimings::toTick<electronics_tick>(" << inputTick << ") => "
562  << elecTick;
563  }
564  else {
565  ++nErrors;
566  mf::LogProblem("DetectorTimingsStandard_test")
567  << "Optical tick #" << inputTick_count << " is expected to be "
568  << expectedElecTick << " (electronics tick), but got "
569  << elecTick << " instead";
570  }
571 
572  // back to optical tick:
573  optical_tick const expectedOptTick
574  = timings.toTick<optical_tick>(timings.toElectronicsTime(expectedElecTick));
575 
576  auto const tickFromElecTick = timings.toTick<optical_tick>(elecTick);
577  static_assert(
579  <decltype(tickFromElecTick.quantity()), util::quantities::tick>
580  );
581 
582  if (tickFromElecTick == expectedOptTick) {
583  mf::LogVerbatim("DetectorTimingsStandard_test")
584  << "DetectorTimings::toTick<optical_tick, "
586  << ">(" << elecTick << ") => " << tickFromElecTick;
587  }
588  else {
589  ++nErrors;
590  mf::LogProblem("DetectorTimingsStandard_test")
592  << " " << elecTick
593  << " is expected to be optical tick " << expectedOptTick
594  << ", but got " << tickFromElecTick << " instead";
595  }
596 
597  //
598  // interval to ticks
599  //
600 
601  double const inputInterval_us = 200.008;
602 
603  time_interval const inputInterval{inputInterval_us};
604  static_assert(
605  util::is_same_decay_v<decltype(inputInterval.quantity()), util::quantities::microsecond>);
606 
607  // real
608  double const expectedTicksD = inputInterval_us / timings.clockData().OpticalClock().TickPeriod();
609 
610  auto const ticks_d = timings.toTicks<optical_time_ticks_d>(inputInterval);
611  static_assert(util::is_same_decay_v<decltype(ticks_d.quantity()), util::quantities::tick_d>);
612 
613  if (ticks_d.value() == expectedTicksD) {
614  mf::LogVerbatim("DetectorTimingsStandard_test")
615  << "DetectorTimings::toTicks<optical_time_ticks_d>(" << inputInterval << ") => " << ticks_d;
616  }
617  else {
618  ++nErrors;
619  mf::LogProblem("DetectorTimingsStandard_test")
620  << "Time interval " << inputInterval << " is expected to last " << expectedTicksD
621  << " optical ticks, but got " << ticks_d << " instead";
622  }
623 
624  // integer
625  int const expectedTicks = static_cast<int>(expectedTicksD);
626 
627  auto const ticks = timings.toTicks<optical_time_ticks>(inputInterval);
628  static_assert(util::is_same_decay_v<decltype(ticks.quantity()), util::quantities::tick>);
629 
630  if (ticks.value() == expectedTicks) {
631  mf::LogVerbatim("DetectorTimingsStandard_test")
632  << "DetectorTimings::toTicks<optical_time_ticks>(" << inputInterval << ") => " << ticks;
633  }
634  else {
635  ++nErrors;
636  mf::LogProblem("DetectorTimingsStandard_test")
637  << "Time interval " << inputInterval << " is expected to last " << expectedTicks
638  << " optical integer ticks, but got " << ticks << " instead";
639  }
640 
641  return nErrors;
642 } // testOpticalClockTimings()
643 
644 //------------------------------------------------------------------------------
645 /** ****************************************************************************
646  * @brief Runs the test
647  * @param argc number of arguments in argv
648  * @param argv arguments to the function
649  * @return number of detected errors (0 on success)
650  * @throw cet::exception most of error situations throw
651  *
652  * The arguments in argv are:
653  * 0. name of the executable ("DetectorClocksStandard_test")
654  * 1. (mandatory) path to the FHiCL configuration file
655  * 2. FHiCL path to the configuration of the test
656  * (default: physics.analyzers.larptest)
657  * 3. FHiCL path to the configuration of DetectorClocks service
658  * (default: services.DetectorClocksService)
659  *
660  */
661 //------------------------------------------------------------------------------
662 int
663 main(int argc, char const** argv)
664 {
665 
667 
668  //
669  // parameter parsing
670  //
671  int iParam = 0;
672 
673  // first argument: configuration file (mandatory)
674  if (++iParam < argc)
675  config.SetConfigurationPath(argv[iParam]);
676  else {
677  std::cerr << "FHiCL configuration file path required as first argument!" << std::endl;
678  return 1;
679  }
680 
681  // second argument: path of the parameter set for geometry test configuration
682  // (optional; default does not have any tester)
683  if (++iParam < argc) config.SetMainTesterParameterSetPath(argv[iParam]);
684 
685  // third argument: path of the parameter set for DetectorClocks configuration
686  // (optional; default: "services.DetectorClocks" from the inherited object)
687  if (++iParam < argc) config.SetServiceParameterSetPath("DetectorClocksService", argv[iParam]);
688 
689  unsigned int nErrors = 0 /* Tester.Run() */;
690 
691  //
692  // testing environment setup
693  //
694  TestEnvironment TestEnv(config);
695 
696  // DetectorClocksStandard supports the simple set up; so we invoke it
697  TestEnv.SimpleProviderSetup<detinfo::DetectorClocksStandard>();
698 
699  //
700  // run the test algorithm
701  // (I leave it here for reference -- there is no test algorithm here)
702  //
703 
704  // 1. we initialize it from the configuration in the environment,
705  // MyTestAlgo Tester(TestEnv.TesterParameters());
706 
707  // 2. we set it up with the geometry from the environment
708  // Tester.Setup(*(TestEnv.Provider<detinfo::DetectorClocks>()));
709 
710  // 3. then we run it!
711  // Note that here we are querying the abstract DetectorClocks interface;
712  // this is the right way to go.
713  auto const* detClocks = TestEnv.Provider<detinfo::DetectorClocks>();
714 
715  using namespace detinfo::timescales; // electronics_time
716  detinfo::DetectorTimings timings(detClocks->DataForJob());
717 
718  mf::LogVerbatim("DetectorTimingsStandard_test")
719  << "Electronics clock: " << timings.ClockPeriodFor<electronics_time>() << ", "
720  << timings.ClockFrequencyFor<electronics_time>();
721 
722  nErrors += testTriggerTime(timings);
723  nErrors += testBeamGateTime(timings);
724  nErrors += testSimulationTimes(timings);
725  nErrors += testTriggerTimes(timings);
726  nErrors += testOpticalClockTimings(timings);
727 
728  // 4. And finally we cross fingers.
729  if (nErrors > 0) { mf::LogError("clocks_test") << nErrors << " errors detected!"; }
730 
731  return (nErrors > 0U)? 1: 0;
732 } // main()
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
DetectorClocksData DataForJob() const override
Returns a complete detinfo::DetectorClocksData object.
unsigned int testOpticalClockTimings(detinfo::DetectorTimings const &timings)
electronics_time BeamGateTime() const
Dimensioned variables representing frequency quantities.
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.
Basic C++ metaprogramming utilities.
constexpr auto is_same_decay_v
Whether T and U are the same type, after being applied std::decay.
Definition: MetaUtils.h:263
microsecond_as<> microsecond
Type of time stored in microseconds, in double precision.
Definition: spacetime.h:119
Provides simple real number checks.
Ticks toTicks(time_interval time) const
Returns the number of ticks corresponding to a time interval.
trigger_time toTriggerTime(FromTime time) const
Converts a time point into trigger time scale.
detinfo::DetectorClocksData const & clockData() const
Returns the detector clocks data.
double TPCG4Time2Tick(double const g4time) const
Given G4 time returns electronics clock count [tdc].
Class holding a configuration for a test environment.
tick_d ticks_d
Alias for common language habits.
Definition: electronics.h:90
A collection of traits for a time scale.
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
constexpr value_t value() const
Returns the value of the quantity.
Definition: quantities.h:609
unsigned int testBeamGateTime(detinfo::DetectorTimings const &timings)
Functions to help debugging by instrumenting code.
tick ticks
Alias for common language habits.
Definition: electronics.h:78
Class for approximate comparisons.
timescale_traits< OpticalTimeCategory >::tick_interval_d_t optical_time_ticks_d
constexpr double TickPeriod() const noexcept
A single tick period in microseconds.
Definition: ElecClock.h:352
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).
Interface to detinfo::DetectorClocks.
Helper functions for support of DetectorClocksService in LArSoft tests.
timescale_traits< TriggerTimeCategory >::time_point_t trigger_time
A point in time on the trigger time scale.
MaybeLogger_< ELseverityLevel::ELsev_error, true > LogProblem
T abs(T value)
int main(int argc, char const **argv)
Runs the test.
detinfo::DetectorClocksWithUnits const & detClocksUnits() const
Returns a DetectorClocksWithUnits object.
const double e
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.
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].
timescale_traits< SimulationTimeCategory >::time_point_t simulation_time
A point in time on the simulation time scale.
static Config * config
Definition: config.cpp:1054
const double a
A value measured in the specified unit.
Definition: quantities.h:566
simulation_time toSimulationTime(FromTime time) const
Converts a time point into simulation time scale.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
ElecClock const & OpticalClock() const noexcept
Borrow a const Optical clock with time set to Trigger time [us].
timescale_traits< OpticalTimeCategory >::time_point_t optical_time
A point in time on the optical detector electronics time scale.
unsigned int testSimulationTimes(detinfo::DetectorTimings const &timings)
An interval (duration, length, distance) between two quantity points.
Definition: intervals.h:114
unsigned int testTriggerTime(detinfo::DetectorTimings const &timings)
electronics_time TriggerTime() const
Literal constants for time quantities.
Definition: spacetime.h:175
double TriggerTime() const
Trigger electronics clock time in [us].
Class used for the conversion of times between different formats and references.
A test environment with some support for service providers.
void SetConfigurationPath(std::string path)
Sets the path to the configuration file.
testing::TesterEnvironment< testing::BasicEnvironmentConfiguration > TestEnvironment
timescale_traits< OpticalTimeCategory >::tick_t optical_tick
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.
Dimensioned variables representing space or time quantities.
A class exposing an upgraded interface of detinfo::DetectorClocksData.
Data types for detinfo::DetectorTimings.
Implementation of detinfo::DetectorClocks interface with fixed settings from configuration.
unsigned int testTriggerTimes(detinfo::DetectorTimings const &timings)
static bool * b
Definition: config.cpp:1043
constexpr double Frequency() const
Frequency in MHz.
Definition: ElecClock.h:191
timescale_traits< OpticalTimeCategory >::tick_d_t optical_tick_d
auto OpticalClockPeriod() const
Returns the duration of the optical clock period and tick.
microsecond TriggerTime() const
Equivalent to detinfo::DetectorClocksData::TriggerTime().
void SetServiceParameterSetPath(std::string service_name, std::string path)
Sets the FHiCL path for the configuration of a test algorithm.
void SetMainTesterParameterSetPath(std::string path)
Sets the FHiCL path for the configuration of the main test algorithm.
Namespace including different time scales as defined in LArSoft.
timescale_traits< ElectronicsTimeCategory >::time_point_t electronics_time
A point in time on the electronics time scale.
QTextStream & endl(QTextStream &s)
constexpr TimeScale startTime() const
Returns the start time of the specified time scale.
void StaticChecks()