PointIsolationAlgStress_test.cc
Go to the documentation of this file.
1 /**
2  * @file PointIsolationAlgStress_test.cc
3  * @brief Stress test for PointIsolationAlg
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date May 27, 2016
6  * @see PointIsolationAlg.h
7  * @ingroup RemoveIsolatedSpacePoints
8  *
9  * Usage
10  * ======
11  *
12  * Runs a isolation removal algorithm on a set of points distributed in a cubic
13  * grid.
14  *
15  * Usage:
16  *
17  * PointIsolationAlg_test NumberOfPoints[+|-] IsolationRadius
18  *
19  * where NumberOfPoints is an approximation of the number of points to be
20  * generated on a grid and processed.
21  * Due to the strict geometric pattern, only perfect cubes are allowed as
22  * number of points. The perfect cube closest to NumberOfPoints be effectively
23  * used, unless "+" or "-" are specified, in which cases the next non-smaller
24  * or non-larger cube will be used, respectively.
25  * The points are places in a simple grid, with a distance of 1 (arbitrary unit)
26  * one from the next on each direction.
27  * The IsolationRadius parameter is measured in the same unit.
28  *
29  * On configuration failure, the test returns with exit code 1.
30  * On test failure, the test returns with exit code 2.
31  *
32  */
33 
34 // LArSoft libraries
36 
37 // C/C++ standard libraries
38 #include <cmath> // std::pow(), std::ceil(), std::floor()
39 #include <stdexcept> // std::logic_error
40 #include <chrono>
41 #include <sstream>
42 #include <iostream>
43 #include <array>
44 
45 
46 // BEGIN RemoveIsolatedSpacePoints group ---------------------------------------
47 /// @ingroup RemoveIsolatedSpacePoints
48 /// @{
49 //------------------------------------------------------------------------------
50 //--- Test code
51 //---
52 template <typename T> T cube(T side) { return side * side * side; }
53 
54 template <typename Point>
55 std::vector<Point> createPointsInCube(unsigned int pointsPerSide) {
56 
57  std::vector<Point> points;
58  points.reserve(cube(pointsPerSide));
59 
60  Point p;
61  for (unsigned int i = 0; i < pointsPerSide; ++i) {
62  p[0] = i;
63  for (unsigned int j = 0; j < pointsPerSide; ++j) {
64  p[1] = j;
65  for (unsigned int k = 0; k < pointsPerSide; ++k) {
66  p[2] = k;
67  points.push_back(p);
68  } // for k
69  } // for j
70  } // for i
71 
72  return points;
73 } // createPointsInCube()
74 
75 
76 //------------------------------------------------------------------------------
77 template <typename T>
80  std::ostream& out = std::cout
81 ) {
82  out << "PointIsolationAlg algorithm configuration:"
83  << "\n radius: " << std::sqrt(config.radius2)
84  << "\n bounding box:"
85  << "\n x: " << config.rangeX.lower << " -- " << config.rangeX.upper
86  << "\n y: " << config.rangeY.lower << " -- " << config.rangeY.upper
87  << "\n z: " << config.rangeZ.lower << " -- " << config.rangeZ.upper
88  << std::endl;
89 } // PrintConfiguration()
90 
91 
92 //------------------------------------------------------------------------------
93 template <typename T>
95  unsigned int pointsPerSide,
97 ) {
98 
99  using Coord_t = T;
100  using PointIsolationAlg_t = lar::example::PointIsolationAlg<Coord_t>;
101 
102  using Point_t = std::array<Coord_t, 3U>;
103 
104  //
105  // creation of the input points
106  //
107  auto start_init_time = std::chrono::high_resolution_clock::now();
108 
109  // create the points in a cube
110  std::vector<Point_t> points = createPointsInCube<Point_t>(pointsPerSide);
111 
112  auto stop_init_time = std::chrono::high_resolution_clock::now();
113  auto elapsed_init = std::chrono::duration_cast<std::chrono::duration<float>>
114  (stop_init_time - start_init_time); // seconds
115 
116  unsigned int const expected = (config.radius2 >= 1.)? points.size(): 0;
117  std::cout << "Processing " << points.size() << " points." << std::endl;
118 
119  //
120  // algorithm initialisation and execution
121  //
122  PointIsolationAlg_t::validateConfiguration(config);
123  PointIsolationAlg_t algo(config);
124  auto start_run_time = std::chrono::high_resolution_clock::now();
125  std::vector<size_t> result = algo.removeIsolatedPoints(points);
126  auto stop_run_time = std::chrono::high_resolution_clock::now();
127 
128  auto elapsed_run = std::chrono::duration_cast<std::chrono::duration<float>>
129  (stop_run_time - start_run_time); // seconds
130 
131  //
132  // report results on screen
133  //
134  PrintConfiguration<Coord_t>(config);
135  std::cout << "Found " << result.size() << "/" << points.size()
136  << " non-isolated points in " << (elapsed_run.count()*1000.) << " ms"
137  << " (" << (elapsed_init.count()*1000.) << " ms for initialization)"
138  << std::endl;
139 
140  if (result.size() != expected) {
141  throw std::logic_error(
142  "Expected " + std::to_string(expected) + " non-isolated points, found "
143  + std::to_string(points.size()) + "."
144  );
145  }
146 
147 } // StressTest()
148 
149 
150 //------------------------------------------------------------------------------
151 //--- main()
152 //---
153 int main(int argc, char** argv) {
154  using Coord_t = double;
155 
156  //
157  // argument parsing
158  //
159  if (argc != 3) {
160  std::cerr << "Usage: " << argv[0]
161  << " NumberOfPoints[+|-] IsolationRadius"
162  << std::endl;
163  return 1;
164  }
165 
166  std::istringstream sstr;
167 
168  enum RoundMode_t { rmNearest, rmCeil, rmFloor, rmDefault = rmNearest };
169 
170  unsigned int requestedPoints = 0;
171  RoundMode_t roundMode = rmDefault;
172  sstr.str(argv[1]);
173  sstr >> requestedPoints;
174  if (!sstr) {
175  std::cerr << "Error: expected number of points as first argument, got '"
176  << argv[1] << "' instead." << std::endl;
177  return 1;
178  }
179  char c;
180  sstr >> c;
181  if (sstr.eof()) roundMode = rmDefault;
182  else {
183  switch (c) {
184  case '+': roundMode = rmCeil; break;
185  case '-': roundMode = rmFloor; break;
186  default:
187  std::cerr << "Invalid round mode specification '" << c
188  << "' (must be '+', '-' or omitted)" << std::endl;
189  return 1;
190  } // switch round mode spec
191  } // if has round mode spec
192 
193  Coord_t radius;
194  sstr.clear();
195  sstr.str(argv[2]);
196  sstr >> radius;
197  if (!sstr) {
198  std::cerr << "Error: expected isolation radius as second argument, got '"
199  << argv[2] << "' instead." << std::endl;
200  return 1;
201  }
202 
203 
204  //
205  // prepare the configuration
206  //
207 
208  // decide on the points per side
209  double sideLength = std::pow(double(requestedPoints), 1./3.);
210  unsigned int pointsPerSide = (unsigned int) std::floor(sideLength);
211  switch (roundMode) {
212  case rmFloor: break;
213  case rmCeil: pointsPerSide = (unsigned int) std::ceil(sideLength); break;
214  case rmNearest: {
215  unsigned int const nFloorPoints = cube(pointsPerSide),
216  nCeilPoints = cube(pointsPerSide + 1);
217  if ((requestedPoints - nFloorPoints) >= (nCeilPoints - requestedPoints))
218  ++pointsPerSide;
219  break;
220  } // case rmNearest
221  } // switch roundMode
222  if (pointsPerSide < 1) pointsPerSide = 1; // sanity check
223 
224  // enclosing volume has a 0.5 margin
225  constexpr Coord_t margin = 0.5;
227  config.radius2 = cet::square(radius);
228  config.rangeX = { -margin, pointsPerSide - 1.0 + margin };
229  config.rangeY = config.rangeX;
230  config.rangeZ = config.rangeX;
231 
232  try {
233  StressTest<Coord_t>(pointsPerSide, config);
234  }
235  catch (std::logic_error const& e) {
236  std::cerr << "Test failure!\n" << e.what() << std::endl;
237  return 2;
238  }
239 
240  return 0;
241 } // main()
242 
243 /// @}
244 // END RemoveIsolatedSpacePoints group -----------------------------------------
245 
Algorithm to detect isolated space points.
static QCString result
const char expected[]
Definition: Exception_t.cc:22
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >> Point_t
constexpr T pow(T x)
Definition: pow.h:72
Coord_t radius2
square of isolation radius [cm^2]
Range_t rangeY
range in Y of the covered volume
enum geo::coordinates Coord_t
constexpr T square(T x)
Definition: pow.h:21
Range_t rangeX
range in X of the covered volume
Coord_t upper
upper boundary
Coord_t lower
lower boundary
const double e
static Config * config
Definition: config.cpp:1054
std::vector< Point > createPointsInCube(unsigned int pointsPerSide)
Type containing all configuration parameters of the algorithm.
p
Definition: test.py:223
void StressTest(unsigned int pointsPerSide, typename lar::example::PointIsolationAlg< T >::Configuration_t const &config)
Algorithm(s) dealing with point isolation in space.
Range_t rangeZ
range in Z of the covered volume
int main(int argc, char **argv)
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
void PrintConfiguration(typename lar::example::PointIsolationAlg< T >::Configuration_t const &config, std::ostream &out=std::cout)
QTextStream & endl(QTextStream &s)
T cube(T side)