All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DiscretePhotoelectronPulse.h
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.h
3  * @brief Sampling of a photoelectron pulse.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date March 17, 2020
6  * @see `icaruscode/PMT/Algorithms/DiscretePhotoelectronPulse.cxx`
7  *
8  */
9 
10 #ifndef ICARUSCODE_PMT_ALGORITHMS_DISCRETEPHOTOELECTRONPULSE_H
11 #define ICARUSCODE_PMT_ALGORITHMS_DISCRETEPHOTOELECTRONPULSE_H
12 
13 
14 // // ICARUS libraries
17 
18 // LArSoft libraries
19 #include "lardataalg/Utilities/quantities/spacetime.h" // nanosecond
20 #include "lardataalg/Utilities/quantities/frequency.h" // gigahertz
21 #include "lardataalg/Utilities/quantities/electronics.h" // tick, counts_f
22 
23 // guidelines library
24 #include "gsl/gsl_util" // gsl::index
25 
26 // C++ standard library
27 #include <string>
28 #include <utility> // std::forward()
29 #include <type_traits> // std::is_same_v, std::decay_t
30 #include <cstdlib> // std::size_t
31 
32 
33 
34 // -----------------------------------------------------------------------------
35 namespace icarus::opdet {
36 
37  using namespace util::quantities::electronics_literals;
38 
39  class DiscretePhotoelectronPulse;
40 
41 } // namespace icarus::opdet
42 
43 
44 // -----------------------------------------------------------------------------
45 /**
46  * @brief Precomputed digitized shape of a given function.
47  *
48  * Multiple samplings ("subsamples") are performed with sub-tick offsets.
49  *
50  * The sampled function is of type
51  * `PhotoelectronPulseFunction<util::quantities::nanosecond>` (polymorphic
52  * implementations are supported).
53  *
54  * A reference to the sampled function is kept available, so that function needs
55  * to be valid for the lifetime of this object.
56  *
57  */
59  public:
62 
63  /// Type of shape (times are in nanoseconds).
66 
67  private:
68  static_assert(
69  std::is_same_v<std::decay_t<PulseFunction_t::Time>, nanoseconds>,
70  "The type of single response function does not take nanoseconds."
71  );
72 
73  /// Internal discretized representation of the sampled pulse shape.
75 
76  public:
79 
80  using SubsampleIndex_t = gsl::index; ///< Type of index of subsample.
81 
82  /// Type of subsample data (a sampling of the full range).
84 
85  static_assert(!std::is_same<Time_t, Tick_t>(),
86  "Time and tick must be different types!");
87 
88  /**
89  * @brief Constructor: samples the pulse.
90  * @param pulseShape the shape to be pulsed; times in nanoseconds
91  * @param samplingFreq frequency of samples [gigahertz]
92  * @param nSubsamples (default: `1`) the number of samples within a tick
93  * @param samplingThreshold (default: 10^-6^) pulse shape ends when its
94  * value is below this threshold
95  *
96  * Samples start from time 0, which is the time of the start of the first
97  * tick. This time is expected to be the arrival time of the photoelectron.
98  *
99  * The length of the sampling is determined by the sampling threshold:
100  * at the first tick after the peak time where the shape function is below
101  * threshold, the sampling ends (that tick under threshold itself is also
102  * discarded).
103  *
104  * The ownership of `pulseShape` is acquired by this object.
105  */
107  PulseFunction_t const& pulseShape,
108  gigahertz samplingFreq,
109  unsigned int nSubsamples = 1U,
110  ADCcount samplingThreshold = 1e-6_ADCf
111  );
112 
113  /// Returns the length of the sampled pulse in ticks.
114  std::size_t pulseLength() const { return fSampledShape.size(); }
115 
116  /// Evaluates the shape at the specified time.
117  ADCcount operator() (Time_t time) const { return shape()(time); }
118 
119  // --- BEGIN -- Access to subsamples ---------------------------------------
120  /**
121  * @name Access to subsamples.
122  *
123  * A subsample is represented by a forward-iterable object. For example:
124  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
125  * using namespace util::quantities::time_literals;
126  * auto const& subsample = dpp.subsampleFor(5_ns);
127  * for (auto sample: subsample) // ...
128  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129  *
130  * @note Direct iterator access is currently not implemented because the
131  * underlying implementation of the subsample object (`gsl::span`)
132  * does not support "borrowing" the data. See the note in
133  * `util::SampledFunction` for more details. The issue should be
134  * solved with C++20.
135  */
136  /// @{
137 
138  /// Returns the subsample specified by index `i`, undefined if invalid.
139  decltype(auto) subsample(SubsampleIndex_t i) const
140  { return fSampledShape.subsample(i); }
141 
142  /// Returns the index of the subsample whose tick left limit is closest to
143  /// `time` (see `util::SampledFunction::closestSubsampleIndex()`).
144  decltype(auto) subsampleFor(Time_t time) const
145  { return subsample(fSampledShape.closestSubsampleIndex(time)); }
146 
147  SubsampleIndex_t nSubsamples() const { return fSampledShape.nSubsamples(); }
148 
149  /// @}
150  // --- END -- Access to subsamples -----------------------------------------
151 
152  // --- BEGIN -- Functional shape -------------------------------------------
153  /// @name Functional shape
154  /// @{
155  /// Returns the function which was sampled.
156  PulseFunction_t const& shape() const { return fShape; }
157 
158  /// Returns the peak amplitude in ADC counts.
159  ADCcount peakAmplitude() const { return shape().peakAmplitude(); }
160 
161  /// Returns the time at the peak from the beginning of sampling.
162  nanoseconds peakTime() const { return shape().peakTime(); }
163 
164  /// Returns the sampling frequency (same units as entered).
165  gigahertz samplingFrequency() const { return fSamplingFreq; }
166 
167  /// Returns the sampling period (inverse of frequency).
168  nanoseconds samplingPeriod() const { return 1.0 / samplingFrequency(); }
169 
170  /// Returns the duration of the waveform in time units.
171  /// @see `pulseLength()`
172  nanoseconds duration() const { return pulseLength() * samplingPeriod(); }
173 
174  /// @}
175  // --- END -- Functional shape ---------------------------------------------
176 
177 
178  // @{
179  /**
180  * @brief Prints on stream the parameters of this shape.
181  * @tparam Stream type of stream to write into
182  * @param out the stream to write into
183  * @param indent indentation string, prepended to all lines except first
184  * @param firstIndent indentation string prepended to the first line
185  */
186  template <typename Stream>
187  void dump(Stream&& out,
188  std::string const& indent, std::string const& firstIndent
189  ) const;
190  template <typename Stream>
191  void dump(Stream&& out, std::string const& indent = "") const
192  { dump(std::forward<Stream>(out), indent, indent); }
193  // @}
194 
195  /**
196  * @brief Checks that the waveform tails not sampled are negligible.
197  * @param limit threshold below which the waveform is considered negligible
198  * @param outputCat _(default: empty)_ message facility output category
199  * to use for messages
200  * @return whether the two tails are negligible
201  *
202  * If `outputCat` is empty (default) no message is printed.
203  * Otherwise, in case of failure a message is sent to message facility
204  * (under category `outputCat`) describing the failure(s).
205  */
206  bool checkRange(ADCcount limit, std::string const& outputCat) const;
207 
208  private:
209 
210  /// Analytical shape of the pules.
212  gigahertz fSamplingFreq; ///< Sampling frequency.
213 
214  /// Pulse shape, discretized.
216 
217 
218  /// Builds the sampling cache.
219  static SampledFunction_t sampleShape(
220  PulseFunction_t const& pulseShape,
221  gigahertz samplingFreq, unsigned int nSubsamples,
222  ADCcount threshold
223  );
224 
225 }; // class DiscretePhotoelectronPulse<>
226 
227 
228 // -----------------------------------------------------------------------------
229 
230 
231 //-----------------------------------------------------------------------------
232 //--- template implementation
233 //-----------------------------------------------------------------------------
234 // -----------------------------------------------------------------------------
235 // --- icarus::opdet::DiscretePhotoelectronPulse
236 // -----------------------------------------------------------------------------
238  PulseFunction_t const& pulseShape,
239  gigahertz samplingFreq, unsigned int nSubsamples, /* = 1U */
240  ADCcount samplingThreshold /* = 1e-3_ADCf */
241  )
242  : fShape(pulseShape)
243  , fSamplingFreq(samplingFreq)
244  , fSampledShape
245  (sampleShape(shape(), fSamplingFreq, nSubsamples, samplingThreshold))
246  {}
247 
248 
249 //-----------------------------------------------------------------------------
250 template <typename Stream>
252  std::string const& indent, std::string const& firstIndent
253  ) const
254 {
255  out << firstIndent << "Sampled pulse waveform " << pulseLength()
256  << " samples long (" << duration()
257  << " long, sampled at " << samplingFrequency()
258  << ");"
259  << "\n" << shape().toString(indent + " ", indent);
260  fSampledShape.dump(out, indent + " ", indent);
261 } // icarus::opdet::DiscretePhotoelectronPulse::dump()
262 
263 
264 //-----------------------------------------------------------------------------
265 
266 
267 #endif // ICARUSCODE_PMT_ALGORITHMS_DISCRETEPHOTOELECTRONPULSE_H
268 
Dimensioned variables representing frequency quantities.
PulseFunction_t const & fShape
Analytical shape of the pules.
std::size_t pulseLength() const
Returns the length of the sampled pulse in ticks.
void dump(Stream &&out, std::string const &indent, std::string const &firstIndent) const
Prints on stream the parameters of this shape.
ADCcount peakAmplitude() const
Returns the peak amplitude in ADC counts.
gsl::index SubsampleIndex_t
Type of index of subsample.
gigahertz samplingFrequency() const
Returns the sampling frequency (same units as entered).
Precomputed digitized shape of a given function.
Abstract interface of shape of a pulse from one photoelectron.
gigahertz_as<> gigahertz
Type of frequency stored in gigahertz, in double precision.
Definition: frequency.h:111
SampledFunction_t fSampledShape
Pulse shape, discretized.
A value measured in the specified unit.
Definition: quantities.h:566
DiscretePhotoelectronPulse(PulseFunction_t const &pulseShape, gigahertz samplingFreq, unsigned int nSubsamples=1U, ADCcount samplingThreshold=1e-6_ADCf)
Constructor: samples the pulse.
Class for a function with precomputed values.
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
Interface for a function describing a pulse from a photoelectron.
Dimensioned variables related to electronics.
nanoseconds samplingPeriod() const
Returns the sampling period (inverse of frequency).
void dump(Stream &&out, std::string const &indent="") const
Dimensioned variables representing space or time quantities.
nanosecond_as<> nanosecond
Type of time stored in nanoseconds, in double precision.
Definition: spacetime.h:136
SampledFunction_t::SubsampleData_t Subsample_t
Type of subsample data (a sampling of the full range).
do i e
nanoseconds peakTime() const
Returns the time at the peak from the beginning of sampling.
gsl::span< Y_t const > SubsampleData_t
Span of subsample data. Can be forward iterated.
bnb BNB Stream
nanosecond nanoseconds
Alias for common language habits.
Definition: spacetime.h:139