All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SampledFunction_test.cc
Go to the documentation of this file.
1 /**
2  * @file SampledFunction_test.cc
3  * @brief Unit test for `util::SampledFunction`.
4  * @date February 14, 2020
5  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
6  * @see `icarusalg/Utilities/SampledFunction.h
7  */
8 
9 // Boost libraries
10 #define BOOST_TEST_MODULE SampledFunction
11 #include <boost/test/unit_test.hpp>
12 namespace tt = boost::test_tools;
13 
14 // ICARUS libraries
16 
17 // LArSoft libraries
19 
20 
21 //------------------------------------------------------------------------------
22 template <typename T, typename U>
23 constexpr T constexpr_floor(U num) {
24 
25  // goes to closest smaller positive integer or larger negative integer
26  T const inum = static_cast<T>(num);
27  if (num == static_cast<float>(inum)) return inum;
28 
29  return (num > U{ 0 })? inum: inum - T{ 1 };
30 } // constexpr_floor()
31 
32 static_assert(constexpr_floor<int>(0) == 0);
33 
34 static_assert(constexpr_floor<int>(-2.00) == -2);
35 static_assert(constexpr_floor<int>(-1.75) == -2);
36 static_assert(constexpr_floor<int>(-1.50) == -2);
37 static_assert(constexpr_floor<int>(-1.25) == -2);
38 static_assert(constexpr_floor<int>(-1.00) == -1);
39 static_assert(constexpr_floor<int>(-0.75) == -1);
40 static_assert(constexpr_floor<int>(-0.50) == -1);
41 static_assert(constexpr_floor<int>(-0.00) == +0);
42 static_assert(constexpr_floor<int>(+0.00) == +0);
43 static_assert(constexpr_floor<int>(+0.50) == +0);
44 static_assert(constexpr_floor<int>(+0.75) == +0);
45 static_assert(constexpr_floor<int>(+1.00) == +1);
46 static_assert(constexpr_floor<int>(+1.25) == +1);
47 static_assert(constexpr_floor<int>(+1.50) == +1);
48 static_assert(constexpr_floor<int>(+1.75) == +1);
49 static_assert(constexpr_floor<int>(+2.00) == +2);
50 
51 //------------------------------------------------------------------------------
52 void IdentityTest() {
53 
54  auto identity = [](double x){ return x; };
55 
56  // [ -2.0 , 6.0 ] with step size 0.5 and 4 subsamples (0.125 substep size)
57  constexpr gsl::index nSamples = 16;
58  constexpr gsl::index nSubsamples = 4;
59  constexpr double min = -2.0;
60  constexpr double max = min + static_cast<double>(nSamples / 2);
61  constexpr double range = max - min;
62  constexpr double step = range / nSamples;
63  constexpr double substep = step / nSubsamples;
64 
65 
66  BOOST_TEST_MESSAGE("Test settings:"
67  << "\nRange: " << min << " -- " << max << " (range: " << range << ")"
68  << "\nSamples: " << nSamples << " (size: " << step << ")"
69  << "\nSubsamples: " << nSubsamples << " (size: " << substep << ")"
70  );
71 
72  // function with 10 samples, sampled 4 times
73  util::SampledFunction<> sampled { identity, min, max, nSamples, nSubsamples };
74 
75  //
76  // Query
77  //
78  auto const close = tt::tolerance(1.e-6);
79  BOOST_TEST(sampled.size() == nSamples);
80  BOOST_TEST(sampled.nSubsamples() == nSubsamples);
81  BOOST_TEST(sampled.lower() == min);
82  BOOST_TEST(sampled.upper() == max);
83  BOOST_TEST(sampled.rangeSize() == max - min, close);
84  BOOST_TEST(sampled.stepSize() == step, close);
85  BOOST_TEST(sampled.substepSize() == substep, close);
86 
87  for (auto const iSub: util::counter(nSubsamples)) BOOST_TEST_CONTEXT("Subsample: " << iSub)
88  {
89 
90  double const subsampleStart = min + iSub * substep;
91 
92  auto const& subSample = sampled.subsample(iSub);
93  BOOST_TEST_MESSAGE
94  ("Subsample #" << iSub << ": " << subSample.size() << " samples");
95  auto itSample = subSample.begin();
96 
97  for (auto const iSample: util::counter(-nSamples, 2*nSamples+1)) BOOST_TEST_CONTEXT("Sample: " << iSample)
98  {
99  bool const bInRange = (iSample >= 0) && (iSample < nSamples);
100 
101  double const expected_x
102  = static_cast<double>(subsampleStart + iSample * step);
103  double const expected_value = identity(expected_x); // I wonder how much
104 
105  if (bInRange) {
106  BOOST_TEST(sampled.value(iSample, iSub) == expected_value);
107  BOOST_TEST(*itSample == expected_value);
108  BOOST_TEST_MESSAGE("[" << iSample << "] " << *itSample);
109  ++itSample;
110  }
111 
112  // check lookup from within the substep
113  for (double const shift: { 0.0, 0.25, 0.50, 0.75 }) BOOST_TEST_CONTEXT("Shift: " << shift) {
114  double const expected_x_in_the_middle = expected_x + shift * substep;
115 
116  gsl::index const stepIndex
117  = sampled.stepIndex(expected_x_in_the_middle, iSub);
118 
119  BOOST_TEST(sampled.isValidStepIndex(stepIndex) == bInRange);
120  BOOST_TEST(stepIndex == iSample);
121 
122  BOOST_TEST
123  (sampled.closestSubsampleIndex(expected_x_in_the_middle) == iSub);
124 
125  } // for shift
126 
127  } // for all samples in the subsample
128 
129  BOOST_TEST((itSample == subSample.end()), "itSample != subSample.end()");
130 
131  BOOST_TEST(!sampled.isValidStepIndex
132  (sampled.stepIndex(subsampleStart + max - min, iSub))
133  );
134 
135  } // for all subsamples
136 
137 } // void IdentityTest()
138 
139 
140 //------------------------------------------------------------------------------
142 
143  auto identity = [](double x){ return x; };
144 
145  // the following checks work for a monotonic function;
146  // the value at x = stopAt should not be included in the function range.
147 
148  constexpr gsl::index nSubsamples = 4;
149  constexpr double min = -2.0;
150  constexpr double atLeast = +1.0;
151  constexpr double stopBefore = +8.2; // deliberately avoid border effects
152  constexpr double step = 0.5;
153  constexpr double substep = step / nSubsamples;
154 
155  // this stop function does *not* include the stop value in the range
156  // when that value would be the right limit of the range; for that to
157  // be included, (y > stopValue) should be used.
158  constexpr double stopValue = identity(stopBefore);
159  auto const stopIf
160  = [](double, double y){ return (y < 0) || (y >= stopValue); };
161 
162  // function with 10 samples, sampled 4 times
163  util::SampledFunction sampled
164  { identity, min, step, stopIf, nSubsamples, atLeast };
165 
166  constexpr gsl::index expected_nSamples
167  = constexpr_floor<gsl::index>((stopBefore - min) / step);
168  constexpr gsl::index expected_max = min + step * expected_nSamples;
169  constexpr gsl::index expected_range = expected_max - min;
170 
171  //
172  // Query
173  //
174  BOOST_TEST(sampled.nSubsamples() == nSubsamples);
175  BOOST_TEST(sampled.lower() == min);
176  BOOST_TEST(sampled.stepSize() == step, close);
177  BOOST_TEST(sampled.substepSize() == substep, close);
178 
179  BOOST_TEST(sampled.upper() == expected_max, close);
180  BOOST_TEST_REQUIRE(sampled.size() == expected_nSamples);
181  BOOST_TEST(sampled.rangeSize() == expected_range, close);
182 
183 
184  auto const nSamples = sampled.size();
185 
186  for (auto const iSub: util::counter(nSubsamples)) BOOST_TEST_CONTEXT("Subsample: " << iSub)
187  {
188 
189  double const subsampleStart = min + iSub * substep;
190 
191  auto const& subSample = sampled.subsample(iSub);
192  BOOST_TEST_MESSAGE
193  ("Subsample #" << iSub << ": " << subSample.size() << " samples");
194  auto itSample = subSample.begin();
195 
196  for (auto const iSample: util::counter(-nSamples, 2*nSamples+1)) BOOST_TEST_CONTEXT("Sample: " << iSample)
197  {
198  bool const bInRange = (iSample >= 0) && (iSample < nSamples);
199 
200  double const expected_x
201  = static_cast<double>(subsampleStart + iSample * step);
202  double const expected_value = identity(expected_x); // I wonder how much
203 
204  if (bInRange) {
205  BOOST_TEST(sampled.value(iSample, iSub) == expected_value);
206  BOOST_TEST(*itSample == expected_value);
207  BOOST_TEST_MESSAGE("[" << iSample << "] " << *itSample);
208  ++itSample;
209  }
210 
211  } // for all samples in the subsample
212 
213  BOOST_TEST((itSample == subSample.end()), "itSample != subSample.end()");
214 
215  BOOST_TEST(!sampled.isValidStepIndex
216  (sampled.stepIndex(subsampleStart + expected_max - min, iSub))
217  );
218 
219  } // for all subsamples
220 
221 } // void ExtendedRangeTest()
222 
223 
224 //------------------------------------------------------------------------------
225 //--- The tests
226 //---
227 BOOST_AUTO_TEST_CASE( TestCase ) {
228 
229  IdentityTest();
231 
232 } // BOOST_AUTO_TEST_CASE( TestCase )
233 
BOOST_AUTO_TEST_CASE(AllTests)
process_name opflash particleana ie x
auto const tolerance
void ExtendedRangeTest()
constexpr T constexpr_floor(U num)
shift
Definition: fcl_checks.sh:26
void IdentityTest()
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:285
process_name opflash particleana ie ie y
Class for a function with precomputed values.
Test of util::counter and support utilities.
do i e
print OUTPUT<< EOF;< setup name="Default"version="1.0">< worldref="volWorld"/></setup ></gdml > EOF close(OUTPUT)
Precomputed discrete sampling of a given function.