OpDetWaveform.h
Go to the documentation of this file.
1 /**
2  * @file lardataalg/Dumpers/RawData/OpDetWaveform.h
3  * @brief Utilities to dump `raw::OpDetWaveform` objects on screen.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date March 8th, 2017
6  *
7  * Currently this is a header-only library.
8  *
9  */
10 
11 #ifndef LARDATAALG_DUMPERS_RAWDATA_OPDETWAVEFORM_H
12 #define LARDATAALG_DUMPERS_RAWDATA_OPDETWAVEFORM_H
13 
14 
15 // LArSoft includes
17 #include "lardataalg/Utilities/StatCollector.h" // lar::util::MinMaxCollector
19 
20 // C//C++ standard libraries
21 #include <vector>
22 #include <algorithm> // std::min()
23 #include <ios> // std::fixed
24 #include <iomanip> // std::setprecision(), std::setw()
25 #include <utility> // std::forward(), std::swap()
26 
27 
28 namespace dump::raw {
29 
30  using namespace ::raw;
31 
32  /**
33  * @brief Prints the content of optical detector waveforms on screen.
34  *
35  * Example of usage:
36  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
37  * dump::raw::OpDetWaveformDumper dump;
38  * dump.setIndent(" ");
39  *
40  * for (raw::OpDetWaveform const& waveform: waveforms)
41  * dump(mf::LogVerbatim("dumper"), waveform);
42  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43  *
44  */
46  public:
47 
48  /// Base functor for printing time according to tick number.
49  struct TimeLabelMaker {
50 
51  virtual ~TimeLabelMaker() = default;
52 
53  /// Returns the label to be written for the specified `tick` number.
54  virtual std::string label
55  (raw::OpDetWaveform const& waveform, unsigned int tick) const = 0;
56 
57  /// Length of padded label. For best results, it should be a constant.
58  virtual unsigned int labelWidth
59  (raw::OpDetWaveform const& waveform, unsigned int tick) const
60  { return 10U; }
61 
62  }; // struct TimeLabelMaker
63 
64 
65  /// Time label: tick number relative to the waveform.
66  struct TickLabelMaker: public TimeLabelMaker {
67 
68  /// Returns the label to be written for the specified `tick` number.
69  virtual std::string label
70  (raw::OpDetWaveform const&, unsigned int tick) const override
71  { return std::to_string(tick); }
72 
73  /// Length of padded label. For best results, it should be a constant.
74  virtual unsigned int labelWidth
75  (raw::OpDetWaveform const& waveform, unsigned int) const override
76  { return digitsOf(waveform.size()); }
77 
78  }; // struct TickLabelMaker
79 
80 
81  /**
82  * @brief Constructor: sets waveform dump parameters.
83  * @param pedestal (default: `0`) the pedestal to be automatically added to
84  * all digits
85  * @param digitsPerLine (default: `0`) how many ADC digits to print per
86  * line; `0` disables the digit printing completely
87  *
88  * Note that no indentation is set. If some is desired, set it with
89  * `setIndent()` after construction.
90  */
92  (raw::ADC_Count_t pedestal = 0, unsigned int digitsPerLine = 0U)
93  : fPedestal(pedestal), fDigitsPerLine(digitsPerLine)
94  {}
95 
96  /**
97  * @brief Chooses which time label maker to use.
98  * @param timeLabelMaker a pointer to the external time label maker
99  *
100  * A time label maker is an object derived from `TimeLabelMaker` which can
101  * convert a waveform and tick into a string representing that tick within
102  * the waveform. If never specified or if `nullptr`, no time label will be
103  * printed at all.
104  */
105  void setTimeLabelMaker(TimeLabelMaker const* timeLabelMaker)
106  { fTimeLabelMaker = timeLabelMaker; }
107 
108 
109  /**
110  * @brief Dumps the content of a waveform into the specified output stream.
111  * @tparam Stream type of stream to dump data into
112  * @param stream stream to dump data into
113  * @param waveform the object to be dumped
114  *
115  * Indentation is regulated via base class methods (see `setIndent()`).
116  */
117  template <typename Stream>
118  void dump(Stream&& stream, raw::OpDetWaveform const& waveform);
119 
120  /// An alias of `dump()`.
121  template <typename Stream>
122  void operator()(Stream&& stream, raw::OpDetWaveform const& waveform)
123  { dump(stream, waveform); }
124 
125 
126  /// Pads the specified string to the right, truncating its right if needed.
127  static std::string padRight
128  (std::string const& s, unsigned int width, std::string padding = " ");
129 
130  /// Pads the specified string to the right, truncating its right if needed.
131  static unsigned int digitsOf(unsigned int n);
132 
133  private:
134 
135  raw::ADC_Count_t fPedestal; ///< ADC pedestal (subtracted from readings).
136  unsigned int fDigitsPerLine; ///< ADC readings per line in the output.
137 
138  /// The functor to be used to extract the time label.
139  TimeLabelMaker const* fTimeLabelMaker = nullptr;
140 
141  }; // class OpDetWaveformDumper
142 
143 } // namespace dump::raw
144 
145 
146 // -----------------------------------------------------------------------------
147 // --- Template implementation
148 // -----------------------------------------------------------------------------
149 template <typename Stream>
151  (Stream&& stream, raw::OpDetWaveform const& waveform)
152 {
153  static std::string const headerSep = " | ";
154 
155  auto const& data = waveform;
156  using Count_t = raw::ADC_Count_t;
157 
158  auto out = indenter(std::forward<Stream>(stream));
159 
160  // print a header for the raw digits
161  out.start()
162  << "on channel #" << waveform.ChannelNumber() << " (time stamp: "
163  << waveform.TimeStamp() << "): " << data.size() << " time ticks";
164 
165  // print the content of the channel
166  if (fDigitsPerLine == 0) return;
167 
168  // save and change indentation
169  saveIndentSettings().set(indent() + " ");
170 
171  unsigned int repeat_count = 0U; // additional lines like the last one
172  unsigned int index = 0U;
173  unsigned int firstLineTick = 0U;
174 
175  // local function for printing and resetting the repeat count
176  auto flushRepeatCount
177  = [this, &out, &waveform, &firstLineTick](unsigned int& count)
178  -> decltype(auto)
179  {
180  if (count > 0) {
181  out.newline();
182  if (fTimeLabelMaker) {
183  out
184  << padRight("", fTimeLabelMaker->labelWidth(waveform, firstLineTick))
185  << headerSep
186  ;
187  }
188  out << " [ ... repeated " << count << " more times ]";
189  count = 0;
190  }
191  return out;
192  };
193 
194  std::vector<Count_t> DigitBuffer(fDigitsPerLine), LastBuffer;
195 
197  out.newline()
198  << "content of the channel (" << fDigitsPerLine << " ticks per line):";
199  auto iTick = data.cbegin(), tend = data.cend(); // const iterators
200  while (iTick != tend) {
201  // the next line will show at most fDigitsPerLine ticks
202  unsigned int line_size
203  = std::min(fDigitsPerLine, (unsigned int) data.size() - index);
204  if (line_size == 0) break; // no more ticks
205 
206  // fill the new buffer (iTick will move forward)
207  DigitBuffer.resize(line_size);
208  auto iBuf = DigitBuffer.begin(), bend = DigitBuffer.end();
209  while ((iBuf != bend) && (iTick != tend))
210  Extrema.add(*(iBuf++) = *(iTick++) - fPedestal);
211  firstLineTick = index;
212  index += line_size;
213 
214  // if the new buffer is the same as the old one, just mark it
215  if (DigitBuffer == LastBuffer) {
216  repeat_count += 1;
217  continue;
218  }
219 
220  // if there are previous repeats, write that on screen
221  // before the new, different line
222  flushRepeatCount(repeat_count);
223 
224  // dump the new line of ticks
225  out.newline();
226  if (fTimeLabelMaker) {
227  out << padRight(
228  fTimeLabelMaker->label(waveform, firstLineTick),
229  fTimeLabelMaker->labelWidth(waveform, firstLineTick)
230  )
231  << headerSep
232  ;
233  }
234  for (auto digit: DigitBuffer)
235  out << " " << std::setw(4) << digit;
236 
237 
238  // quick way to assign DigitBuffer to LastBuffer
239  // (we don't care we lose the former)
240  std::swap(LastBuffer, DigitBuffer);
241 
242  } // while
243  flushRepeatCount(repeat_count);
244  if (Extrema.min() != Extrema.max()) {
245  out.newline()
246  << " range of " << data.size()
247  << " samples: [" << Extrema.min() << ";" << Extrema.max() << "] (span: "
248  << (Extrema.max() - Extrema.min());
249  if (fPedestal != 0) {
250  out << ", absolute: ["
251  << (Extrema.min() + fPedestal) << ";"
252  << (Extrema.max() + fPedestal) << "]";
253  }
254  out << ")";
255  }
256 
258 
259 } // dump::raw::OpDetWaveformDumper::dump()
260 
261 
262 //----------------------------------------------------------------------------
264  (std::string const& s, unsigned int width, std::string padding /* = " " */)
265 {
266 
267  if (s.length() > width) { // too long already?
268  // truncate on the right
269  return { s, 0U, width }; // { string, start index, character count }
270  }
271 
272  std::string padded;
273  padded.reserve(width);
274 
275  // this is how many full padding strings we need to prepend
276  unsigned int nPadding
277  = (s.length() >= width)? 0U: (width - s.length()) / padding.length();
278 
279  // if there is need for some more partial padding beyond that:
280  if (nPadding * padding.length() + s.length() < width) {
281  // immediately prepend from the rightmost part of the padding string
282  padded.append(
283  padding.end() - (width - (nPadding * padding.length() + s.length())),
284  padding.end()
285  );
286  }
287 
288  // add the rest of the padding and the string, and then we are done
289  while (nPadding-- > 0) padded += padding;
290  padded += s;
291 
292  assert(padded.length() == width);
293 
294  return padded;
295 } // dump::raw::OpDetWaveformDumper::padRight()
296 
297 
298 //----------------------------------------------------------------------------
299 unsigned int dump::raw::OpDetWaveformDumper::digitsOf(unsigned int n) {
300  unsigned int digits = 1U;
301  while (n >= 10) {
302  ++digits;
303  n /= 10;
304  }
305  return digits;
306 } // dump::raw::OpDetWaveformDumper::digitsOf()
307 
308 
309 //----------------------------------------------------------------------------
310 
311 
312 #endif // LARDATAALG_DUMPERS_RAWDATA_OPDETWAVEFORM_H
Data_t max() const
Returns the accumulated maximum, or a very small number if no values.
This_t & add(Data_t value)
Include a single value in the statistics.
Channel_t ChannelNumber() const
Definition: OpDetWaveform.h:65
OpDetWaveformDumper(raw::ADC_Count_t pedestal=0, unsigned int digitsPerLine=0U)
Constructor: sets waveform dump parameters.
Definition: OpDetWaveform.h:92
void dump(Stream &&stream, raw::OpDetWaveform const &waveform)
Dumps the content of a waveform into the specified output stream.
TimeStamp_t TimeStamp() const
Definition: OpDetWaveform.h:66
void operator()(Stream &&stream, raw::OpDetWaveform const &waveform)
An alias of dump().
std::string string
Definition: nybbler.cc:12
IndentSettings & restoreIndentSettings()
Restores and returns the last saved settings.
Definition: DumperBase.h:220
void set(std::string const &newIndent, std::string const &newFirstIndent)
Definition: DumperBase.h:45
Raw data description.
static std::string padRight(std::string const &s, unsigned int width, std::string padding=" ")
Pads the specified string to the right, truncating its right if needed.
virtual unsigned int labelWidth(raw::OpDetWaveform const &waveform, unsigned int tick) const
Length of padded label. For best results, it should be a constant.
Definition: OpDetWaveform.h:59
Classes gathering simple statistics.
Keeps track of the minimum and maximum value we observed.
TimeLabelMaker const * fTimeLabelMaker
The functor to be used to extract the time label.
Data_t min() const
Returns the accumulated minimum, or a very large number if no values.
void swap(Handle< T > &a, Handle< T > &b)
std::void_t< T > n
Base functor for printing time according to tick number.
Definition: OpDetWaveform.h:49
std::string const & indent() const
Returns the indentation string currently configured for all lines.
Definition: DumperBase.h:96
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
decltype(auto) indenter(Stream &&out) const
Returns an Indenter object tied to this dumper and out stream.
Definition: DumperBase.h:202
void setTimeLabelMaker(TimeLabelMaker const *timeLabelMaker)
Chooses which time label maker to use.
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
raw::ADC_Count_t fPedestal
ADC pedestal (subtracted from readings).
Prints the content of optical detector waveforms on screen.
Definition: OpDetWaveform.h:45
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
IndentSettings & saveIndentSettings()
Stacks a copy of the current settings, and returns the "new" ones.
Definition: DumperBase.h:212
virtual std::string label(raw::OpDetWaveform const &waveform, unsigned int tick) const =0
Returns the label to be written for the specified tick number.
Base class for data dumpers.
Definition: DumperBase.h:39
unsigned int fDigitsPerLine
ADC readings per line in the output.
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
Helper base class for implementing data product dump algorithms.
static QCString * s
Definition: config.cpp:1042
short ADC_Count_t
Definition: OpDetWaveform.h:21
static unsigned int digitsOf(unsigned int n)
Pads the specified string to the right, truncating its right if needed.
Time label: tick number relative to the waveform.
Definition: OpDetWaveform.h:66