raw_test.cc
Go to the documentation of this file.
1 /**
2  * @file raw_test.cc
3  * @brief Tests the raw data compression routines
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date 20140716
6  * @version 1.0
7  *
8  * This test covers only no compression and Huffman compression.
9  * If compresses a data set, uncompresses it back and checks that the result
10  * is the same as the original one.
11  * As such, it does not support lossy compression (like zero suppression).
12  *
13  * See http://www.boost.org/libs/test for the Boost test library home page.
14  *
15  * Timing:
16  * version 1.0 takes less than 3" on a 3 GHz machine
17  */
18 
19 // C/C++ standard libraries
20 #include <cmath> // std::sqrt()
21 #include <limits> // std::numeric_limits<>
22 #include <random> // std::default_random_engine, ...
23 #include <string>
24 #include <map>
25 #include <iostream>
26 
27 // Boost libraries
28 /*
29  * Boost Magic: define the name of the module;
30  * and do that before the inclusion of Boost unit test headers
31  * because it will change what they provide.
32  * Among the those, there is a main() function and some wrapping catching
33  * unhandled exceptions and considering them test failures, and probably more.
34  * This also makes fairly complicate to receive parameters from the command line
35  * (for example, a random seed).
36  */
37 #define BOOST_TEST_MODULE ( raw_test )
38 #include "boost/test/unit_test.hpp"
39 
40 // LArSoft libraries
42 #include "larcoreobj/SimpleTypesAndConstants/RawTypes.h" // raw::Compress_t
43 #include "lardataobj/RawData/raw.h"
44 
45 
46 /// The seed for the default random engine
47 constexpr unsigned int RandomSeed = 12345;
48 
49 
50 //------------------------------------------------------------------------------
51 //--- Input data creation
52 //
53 // Here are some classes to produce input data for the tests.
54 // All the classes, derived from DataCreatorBase, need to override the create()
55 // method to provide their data.
56 // The base class provides by default a random engine (from C++ STL)
57 // with a fixed seed.
58 //
59 
60 /// Interface of an object creating data to be tested on
62  public:
63  typedef std::vector<short> InputData_t;
64 
65  /// Random engine shared by all the data creators
66  static std::default_random_engine random_engine;
67 
68  /// Constructor: just assigns a name to this data set
69  DataCreatorBase(std::string new_name): test_name(new_name) {}
70 
71  /// Returns the name of this set
72  std::string name() const { return test_name; }
73 
74  /// Virtual destructor
75  virtual ~DataCreatorBase() {}
76 
77  /// Creates and returns the data sample; pure virtual
78  virtual InputData_t create(size_t size) = 0;
79 
80  private:
81  std::string test_name; ///< internal storage for test name
82 }; // class DataCreatorBase
83 
84 // Initialized with a hard-coded seed
85 std::default_random_engine DataCreatorBase::random_engine(RandomSeed);
86 
87 
88 
89 /// Data creator: uniformly random data, specified range plus offset (pedestal)
91  public:
92  float baseline; ///< pedestal
93  float width; ///< (half)width of the uniform distribution
94 
95  /// Constructor: assigns data set name and noise parameters
97  (std::string name, float RMS, float pedestal = 0.):
98  DataCreatorBase(name),
99  baseline(pedestal), width(RMS * std::sqrt(12.))
100  {}
101 
102  /// Creates and returns the data sample
103  virtual InputData_t create(size_t size) override
104  {
105  std::uniform_real_distribution<float> noise
106  (baseline - width, baseline + width);
107  InputData_t data(size);
108  for (auto& item: data)
109  item = InputData_t::size_type(noise(random_engine));
110  return data;
111  } // create()
112 
113 }; // class UniformNoiseCreator
114 
115 
116 /// Data creator: Gaussian random data
118  public:
119  float mean; ///< mean of the noise Gaussian (pedestal)
120  float stdev; ///< standard deviation of the noise Gaussian (RMS)
121 
122  /// Constructor: assigns data set name and noise parameters
124  (std::string name, float sigma, float mu = 0.):
125  DataCreatorBase(name),
126  mean(mu), stdev(sigma)
127  {}
128 
129  /// Creates and returns the data sample
130  virtual InputData_t create(size_t size) override
131  {
132  std::normal_distribution<float> noise(mean, stdev);
133  InputData_t data(size);
134  for (auto& item: data)
135  item = InputData_t::size_type(noise(random_engine));
136  return data;
137  } // create()
138 
139 }; // class GaussianNoiseCreator
140 
141 
142 /// Data creator: sine wave data
144  public:
145  float period; ///< period of the wave [ticks]
146  float amplitude; ///< amplitude of the wave [ADC counts]
147 
148  /// Constructor: assigns data set name and noise parameters
150  (std::string name, float new_period, float new_amplitude):
151  DataCreatorBase(name),
152  period(new_period), amplitude(new_amplitude)
153  {}
154 
155  /// Creates and returns the data sample
156  virtual InputData_t create(size_t size) override
157  {
158  // for c2: constexpr variable 'two_pi' must be initialized by a constant expression
159  //constexpr float two_pi = float(2. * std::acos(-1.));
160  constexpr float two_pi = 2.0F * util::pi<float>();
162  data.reserve(size);
163  for (size_t i = 0; i < size; ++i)
164  data.push_back(amplitude * std::sin(i / period * two_pi));
165  return data;
166  } // create()
167 
168 }; // class SineWaveCreator
169 
170 
171 /// Data creator: uniformly random data, full range
173  public:
174 
175  /// Creates and returns the data sample
176  virtual InputData_t create(size_t size) override
177  {
178  std::uniform_int_distribution<short> uniform(
181  );
182  InputData_t data(size);
183  for (auto& item: data)
184  item = InputData_t::value_type(uniform(random_engine));
185  return data;
186  } // create()
187 
188 }; // class RandomDataCreator
189 
190 
191 //------------------------------------------------------------------------------
192 //--- Test code
193 //
194 // The tests are going to be repetitive: do almost the same thing in slightly
195 // different ways over and over.
196 // For that reason we have a data generator with a generic interface, and also
197 // the following functions to perform tests repeatedly.
198 //
199 
200 /**
201  * @brief Tests a data set with a given compression
202  * @param id string representing the test (short descriptive text)
203  * @param data data set (a vector of short integers)
204  * @param mode compression mode to be tested
205  * @see RunDataCompressionTests
206  *
207  * The test consists in compressing and uncompressing back data.
208  * The test fails if the uncompressed data does not match the original one.
209  *
210  * This is actually a single step of the full test implemented in
211  * RunDataCompressionTests.
212  */
214  (std::string id, const std::vector<short>& data, raw::Compress_t mode)
215 {
216  // working a copy of the original data:
217  std::vector<short> buffer(data);
218 
219  // compress
220  raw::Compress(buffer, mode);
221  std::cout << id << ": compressed data size: " << buffer.size() << std::endl;
222 
223  // decompress (on an already allocated buffer)
224  std::vector<short> data_again(data.size());
225  raw::Uncompress(buffer, data_again, mode);
226 
227  // Boost provides facilities to compare data and print if it does not match:
228  BOOST_TEST(data_again.size() == data.size());
229 
230  BOOST_CHECK_EQUAL_COLLECTIONS
231  (data.begin(), data.end(), data_again.begin(), data_again.end());
232 
233 } // RunDataCompressionTest()
234 
235 
236 /**
237  * @brief Runs data compression tests with selected compression modes
238  * @param pDataCreator an object to create the input data set
239  * @see RunDataCompressionTest()
240  *
241  * This function hard-codes some sets of parameters for the tests:
242  * the same test in RunDataCompressionTest() is repeated with different data
243  * size and different compression modes.
244  * This comprises the full test.
245  */
247 
248  // the compression modes we are going to use, with a human-readable label
249  std::map<raw::Compress_t, std::string> CompressionModes;
250  CompressionModes[raw::kNone] = "uncompressed";
251  CompressionModes[raw::kHuffman] = "Huffman";
252 // CompressionModes[raw::kZeroSuppression] = "zero suppression";
253 // CompressionModes[raw::kZeroHuffman] = "zero suppression plus Huffman";
254 // CompressionModes[raw::kDynamicDec] = "dynamic";
255 
256  // the data sizes we are going to try, with a human-confusing label
257  std::map<size_t, std::string> DataSizes;
258  DataSizes[64] = "small size";
259  DataSizes[9600] = "medium size";
260  DataSizes[1048576] = "large size";
261 
262  for (const auto size_info: DataSizes) {
263  // create the original data:
264  const std::vector<short> data(pDataCreator->create(size_info.first));
265 
266  // test the same data with different compression algorithms:
267  for (const auto test_info: CompressionModes) {
268  // a "nice" label to make output vaguely meaningful...
269  std::string test_id = pDataCreator->name()
270  + " (" + size_info.second + " " + test_info.second + ")";
271 
272  // ... and run the test
273  RunDataCompressionTest(test_id, data, test_info.first);
274  } // for compression modes
275  } // for data sizes
276 
277  // that's it; Boost keeps records of successes and failures
278 } // RunDataCompressionTests()
279 
280 
281 //------------------------------------------------------------------------------
282 //--- registration of tests
283 //
284 // Boost needs now to know which tests we want to run.
285 // We run many RunDataCompressionTests() tests with different input data.
286 // Tests are "automatically" registered, hence the BOOST_AUTO_TEST_CASE()
287 // macro name. The argument is the name of the test; each step will have a
288 // number of checks and it will fail if any of them does.
289 //
290 
292  UniformNoiseCreator InputData("null input data", 0.);
293  RunDataCompressionTests(&InputData);
294 }
295 
296 BOOST_AUTO_TEST_CASE(ConstantData) {
297  UniformNoiseCreator InputData("constant input data", 0., 41.);
298  RunDataCompressionTests(&InputData);
299 }
300 
301 BOOST_AUTO_TEST_CASE(SmallUniformNoiseData) {
302  UniformNoiseCreator InputData("uniform small noise", 5.);
303  RunDataCompressionTests(&InputData);
304 }
305 
306 BOOST_AUTO_TEST_CASE(SmallUniformNoiseOffsetData) {
307  UniformNoiseCreator InputData("uniform small noise and offset", 5., 123.2);
308  RunDataCompressionTests(&InputData);
309 }
310 
311 BOOST_AUTO_TEST_CASE(LargeUniformNoiseData) {
312  UniformNoiseCreator InputData("uniform large noise", 40.);
313  RunDataCompressionTests(&InputData);
314 }
315 
316 BOOST_AUTO_TEST_CASE(SmallGaussianNoiseOffsetData) {
317  GaussianNoiseCreator InputData("Gaussian small noise and offset", 5., 123.2);
318  RunDataCompressionTests(&InputData);
319 }
320 
321 BOOST_AUTO_TEST_CASE(LargeGaussianNoiseData) {
322  GaussianNoiseCreator InputData("Gaussian large noise and offset", 40., 194.);
323  RunDataCompressionTests(&InputData);
324 }
325 
326 BOOST_AUTO_TEST_CASE(VeryLowFrequencySineWaveData) {
327  SineWaveCreator InputData("Very low frequency pure sine wave", 1024., 50.);
328  RunDataCompressionTests(&InputData);
329 }
330 
331 BOOST_AUTO_TEST_CASE(LowFrequencySineWaveData) {
332  SineWaveCreator InputData("Low frequency pure sine wave", 128., 100.);
333  RunDataCompressionTests(&InputData);
334 }
335 
336 BOOST_AUTO_TEST_CASE(HighFrequencySineWaveData) {
337  SineWaveCreator InputData("High frequency pure sine wave", 16., 100.);
338  RunDataCompressionTests(&InputData);
339 }
Huffman Encoding.
Definition: RawTypes.h:10
virtual InputData_t create(size_t size)=0
Creates and returns the data sample; pure virtual.
def stdev(lst)
Definition: HandyFuncs.py:269
enum raw::_compress Compress_t
float stdev
standard deviation of the noise Gaussian (RMS)
Definition: raw_test.cc:120
static std::default_random_engine random_engine
Random engine shared by all the data creators.
Definition: raw_test.cc:66
void RunDataCompressionTests(DataCreatorBase *pDataCreator)
Runs data compression tests with selected compression modes.
Definition: raw_test.cc:246
Data creator: uniformly random data, full range.
Definition: raw_test.cc:172
std::string string
Definition: nybbler.cc:12
std::string test_name
internal storage for test name
Definition: raw_test.cc:81
virtual InputData_t create(size_t size) override
Creates and returns the data sample.
Definition: raw_test.cc:103
Interface of an object creating data to be tested on.
Definition: raw_test.cc:61
float baseline
pedestal
Definition: raw_test.cc:92
void RunDataCompressionTest(std::string id, const std::vector< short > &data, raw::Compress_t mode)
Tests a data set with a given compression.
Definition: raw_test.cc:214
no compression
Definition: RawTypes.h:9
virtual ~DataCreatorBase()
Virtual destructor.
Definition: raw_test.cc:75
std::string name() const
Returns the name of this set.
Definition: raw_test.cc:72
virtual InputData_t create(size_t size) override
Creates and returns the data sample.
Definition: raw_test.cc:156
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
DataCreatorBase(std::string new_name)
Constructor: just assigns a name to this data set.
Definition: raw_test.cc:69
virtual InputData_t create(size_t size) override
Creates and returns the data sample.
Definition: raw_test.cc:176
Data creator: Gaussian random data.
Definition: raw_test.cc:117
static int max(int a, int b)
float period
period of the wave [ticks]
Definition: raw_test.cc:145
float width
(half)width of the uniform distribution
Definition: raw_test.cc:93
virtual InputData_t create(size_t size) override
Creates and returns the data sample.
Definition: raw_test.cc:130
float amplitude
amplitude of the wave [ADC counts]
Definition: raw_test.cc:146
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
Definition: raw.cxx:19
constexpr unsigned int RandomSeed
The seed for the default random engine.
Definition: raw_test.cc:47
dictionary test_info
Definition: test.py:453
Data creator: uniformly random data, specified range plus offset (pedestal)
Definition: raw_test.cc:90
BOOST_AUTO_TEST_CASE(NullData)
Definition: raw_test.cc:291
Collection of Physical constants used in LArSoft.
void Uncompress(const std::vector< short > &adc, std::vector< short > &uncompressed, raw::Compress_t compress)
Uncompresses a raw data buffer.
Definition: raw.cxx:776
std::vector< short > InputData_t
Definition: raw_test.cc:63
Data creator: sine wave data.
Definition: raw_test.cc:143
float mean
mean of the noise Gaussian (pedestal)
Definition: raw_test.cc:119
double mean(sqlite3 *db, std::string const &table_name, std::string const &column_name)
Definition: statistics.cc:16
QTextStream & endl(QTextStream &s)