All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SpacePartition.h
Go to the documentation of this file.
1 /**
2  * @file SpacePartition.h
3  * @brief Class to organise data into a 3D grid
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date May 27, 2016
6  * @ingroup RemoveIsolatedSpacePoints
7  *
8  * This library provides:
9  *
10  * * SpacePartition: class to organise data in space into a 3D grid
11  * * CoordRange: simple coordinate range (interval) class
12  * * PositionExtractor: abstraction to extract a 3D position from an object
13  *
14  * This library contains only template classes and it is header only.
15  *
16  */
17 
18 #ifndef LAREXAMPLES_ALGORITHMS_REMOVEISOLATEDSPACEPOINTS_SPACEPARTITION_H
19 #define LAREXAMPLES_ALGORITHMS_REMOVEISOLATEDSPACEPOINTS_SPACEPARTITION_H
20 
21 // LArSoft libraries
23 
24 // C/C++ standard libraries
25 #include <cstddef> // std::ptrdiff_t
26 #include <cmath> // std::ceil()
27 #include <vector>
28 #include <array>
29 #include <string>
30 #include <stdexcept> // std::runtime_error
31 
32 
33 namespace lar {
34  namespace example {
35 
36  // BEGIN RemoveIsolatedSpacePoints group -----------------------------------
37  /// @ingroup RemoveIsolatedSpacePoints
38  /// @{
39  /**
40  * @brief Helper extractor for point coordinates
41  * @tparam Point type of point structure
42  *
43  * The mandatory interface is:
44  *
45  * - `static T x(Point const& point)`: return x coordinate of point
46  * - `static T y(Point const& point)`: return y coordinate of point
47  * - `static T z(Point const& point)`: return z coordinate of point
48  *
49  * The type T must be convertible to a number (typically a real one).
50  * Examples of specialisation:
51  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52  * struct SpaceTime_t {
53  * double x, y, z; ///< space coordinates
54  * double t; ///< time coordinate
55  * };
56  *
57  * namespace lar {
58  * namespace examples {
59  *
60  * template <>
61  * struct PositionExtractor<SpaceTime_t> {
62  *
63  * static double x(SpaceTime_t const& st) { return st.x; }
64  * static double y(SpaceTime_t const& st) { return st.y; }
65  * static double z(SpaceTime_t const& st) { return st.z; }
66  *
67  * };
68  *
69  * template <>
70  * struct PositionExtractor<SpaceTime_t const*> {
71  *
72  * static double x(SpaceTime_t const* st) { return st->x; }
73  * static double y(SpaceTime_t const* st) { return st->y; }
74  * static double z(SpaceTime_t const* st) { return st->z; }
75  *
76  * };
77  *
78  * }
79  * }
80  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81  * The argument of the function just needs to be something the template
82  * argument can be converted into: in the second example, the argument of
83  * `X` is not required to br exactly `SpaceTime_t const* const&`.
84  */
85  template <typename Point>
87 
88  namespace details {
89  template <typename Point>
90  struct PointTraits_t;
91 
92  /// type of Point coordinate
93  template <typename Point>
94  using ExtractCoordType_t
96 
97  } // namespace details
98 
99 
100  /// Range of coordinates
101  template <typename Coord>
102  struct CoordRange {
103  using Range_t = CoordRange<Coord>; ///< this type
104  using Coord_t = Coord; ///< data type for coordinate
105 
106  Coord_t lower; ///< lower boundary
107  Coord_t upper; ///< upper boundary
108 
109  /// Returns whether c is contained in the range (inclusve)
110  bool contains(Coord_t c) const;
111 
112  /// Returns whether the range is empty
113  bool empty() const;
114 
115  /// Returns whether the range is valid (empty is also valid)
116  bool valid() const;
117 
118  /// Returns the size of the range (no check)
119  Coord_t size() const;
120 
121  /// Returns the distance of the specified coordinate from the lower bound
122  Coord_t offset(Coord_t c) const { return c - lower; }
123 
124  /// Returns whether the specified range has the same limits as this
125  bool operator== (const Range_t& as) const;
126 
127  /// Returns whether the specified range has limits different than this
128  bool operator!= (const Range_t& than) const;
129 
130  }; // CoordRange<>
131 
132 
133  /// Range of coordinates
134  template <typename Coord>
135  struct CoordRangeCells: public CoordRange<Coord> {
137 
138  /// data type for coordinate
139  using Coord_t = typename Base_t::Coord_t;
140 
141  Coord_t cellSize; ///< size of a single cell
142 
143  /**
144  * @brief Constructor: assigns range and cell size
145  * @param low lower bound of the range
146  * @param high upper bound of the range
147  * @param cs size of each cell
148  */
150 
151  /**
152  * @brief Constructor: assigns range and cell size
153  * @param range lower and upper bound of the range
154  * @param cs size of each cell
155  */
156  CoordRangeCells(Base_t const& range, Coord_t cs);
157 
158 
159  /// Returns the index of the cell for coordinate c
160  std::ptrdiff_t findCell(Coord_t c) const;
161 
162  }; // CoordRangeCells<>
163 
164 
165  /**
166  * @brief A container of points sorted in cells
167  * @tparam PointIter type of iterator to the point
168  *
169  * This container arranges its elements into a 3D grid according to their
170  * position in space.
171  * The "position" is defined by the `PositionExtractor` class.
172  *
173  * The container stores a bit on information for each cell (it is not
174  * _sparse_), therefore its size can become large very quickly.
175  * Currently each (empty) cell in the grid uses
176  * `sizeof(std::vector<...>)`, that is 24, bytes.
177  *
178  * Currently, no facility is provided to find an element, although from a
179  * copy of the element, its position in the container can be computed with
180  * `pointIndex()`.
181  *
182  * For example, suppose you need to arrange points in a box of 6 x 8 x 4
183  * (arbitrary units) symmetric around the origin, each with 20 cells.
184  * This already makes a quite large container of 8000 elements.
185  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
186  * std::vector<std::array<double, 3U>> data;
187  * // fill the data points
188  *
189  * lar::examples::SpacePartition<double const*> partition(
190  * { -3.0, 3.0, 0.3 },
191  * { -4.0, 4.0, 0.4 },
192  * { -2.0, 2.0, 0.2 }
193  * );
194  *
195  * // populate the partition
196  * for (auto const& point: data) partition.fill(point.data());
197  *
198  * // find the cell for a reference point
199  * const double refPoint[] = { 0.5, 0.5, 0.5 };
200  * auto cellIndex = partition.pointIndex(refPoint);
201  *
202  * // do something with all the points in the same cell as the reference one
203  * for (double const* point: partition[cellIndex]) {
204  * // ...
205  * }
206  *
207  * // do something with all cells
208  * for (auto const& cell: partition) {
209  * // and process all points in each cell
210  * for (double const* point: cell) {
211  * // ...
212  * }
213  * }
214  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
215  * Note that in the example the stored data is direct pointers to the data
216  * in order to save space (the data is 3 doubles big, that is 24 bytes,
217  * while a pointer is usually only 8 bytes).
218  * The class `PositionExtractor` is specialized for `double const*` in this
219  * same library.
220  */
221  template <typename PointIter>
223  using Point_t = decltype(*(PointIter())); ///< type of the point
224  using Grid_t = ::util::GridContainer3D<PointIter>; ///< data container
225 
226  public:
227  /// type of point coordinate
229  using Range_t = CoordRangeCells<Coord_t>; ///< type of coordinate range
230 
231  /// type of index manager of the grid
232  using Indexer_t = typename Grid_t::Indexer_t;
233 
234  /// type of difference between cell indices
235  using CellIndexOffset_t = typename Indexer_t::CellIndexOffset_t;
236 
237  using CellIndex_t = typename Indexer_t::CellIndex_t; /// type of cell index
238 
239  /// type of cell identifier
240  using CellID_t = typename Indexer_t::CellID_t;
241 
242  /// type of cell
243  using Cell_t = typename Grid_t::Cell_t;
244 
245  /// Constructs the partition in a given volume with the given cell size
247  (Range_t rangeX, Range_t rangeY, Range_t rangeZ);
248 
249  /// Fills the partition with the points in the specified range
250  /// @throw std::runtime_error a point is outside the covered volume
251  void fill(PointIter begin, PointIter end);
252 
253  /// Returns the index pertaining the point (might be invalid!)
254  /// @throw std::runtime_error point is outside the covered volume
255  CellIndexOffset_t pointIndex(Point_t const& point) const;
256 
257  /// Returns the index manager of the grid
258  Indexer_t const& indexManager() const
259  { return data.indexManager(); }
260 
261  /// Returns whether there is a cell with the specified index (signed!)
262  bool has(CellIndexOffset_t ofs) const
263  { return data.has(ofs); }
264 
265  /// Returns the cell with the specified index
266  Cell_t const& operator[] (CellIndex_t index) const
267  { return data[index]; }
268 
269  /// Returns a constant iterator pointing to the first cell
270  typename Grid_t::const_iterator begin() const;
271 
272  /// Returns a constant iterator pointing after the last cell
273  typename Grid_t::const_iterator end() const;
274 
275  protected:
277 
278  Coord_t cellSize; ///< length of the side of each cubic cell
279 
280  Range_t xRange; ///< coordinates of the contained volume on x axis
281  Range_t yRange; ///< coordinates of the contained volume on z axis
282  Range_t zRange; ///< coordinates of the contained volume on z axis
283 
284  Grid_t data; ///< container of points
285 
286  }; // SpacePartition<>
287 
288 
289 
290  //--------------------------------------------------------------------------
291 
292  /// Implementation detail namespace (content is not documented)
293  namespace details {
294  /// Base for PositionExtractor on random-access containers
295  template <typename Cont, typename Data>
297  static Data x(Cont const& p) { return p[0]; }
298  static Data y(Cont const& p) { return p[1]; }
299  static Data z(Cont const& p) { return p[2]; }
300  }; // PositionExtractorFromArray<T*>
301 
302  template <typename Point>
303  auto extractPositionX(Point const& point)
304  { return PositionExtractor<Point>::x(point); }
305  template <typename Point>
306  auto extractPositionY(Point const& point)
307  { return PositionExtractor<Point>::y(point); }
308  template <typename Point>
309  auto extractPositionZ(Point const& point)
310  { return PositionExtractor<Point>::z(point); }
311 
312  template <typename Point>
313  struct PointTraits_t {
314  /// type of Point coordinate
315  using Coord_t = decltype(extractPositionX(std::decay_t<Point>()));
316  }; // ExtractCoordTypeHelper_t
317 
318  } // namespace details
319 
320  /// Specialisation of PositionExtractor for C array: { x, y, z }
321  template <typename T>
322  struct PositionExtractor<T*>:
324  {};
325 
326  /// Specialisation of PositionExtractor for C++ array: { x, y, z }
327  template <typename T>
328  struct PositionExtractor<std::array<T, 3U>>:
329  public details::PositionExtractorFromArray<std::array<T, 3U>, T>
330  {};
331 
332  /// Specialisation of PositionExtractor for C++ vector: { x, y, z }
333  /// (size is not checked!)
334  template <typename T>
336  public details::PositionExtractorFromArray<std::vector<T>, T>
337  {};
338 
339 
340  /// @}
341  // END RemoveIsolatedSpacePoints group -------------------------------------
342 
343  } // namespace example
344 } // namespace lar
345 
346 
347 //------------------------------------------------------------------------------
348 //--- lar::example::details
349 //---
350 namespace lar {
351  namespace example {
352  namespace details {
353 
354  /// Returns the dimensions of a grid diced with the specified size
355  template <typename Coord>
356  std::array<size_t, 3> diceVolume(
357  CoordRangeCells<Coord> const& rangeX,
358  CoordRangeCells<Coord> const& rangeY,
359  CoordRangeCells<Coord> const& rangeZ
360  )
361  {
362  return {{
363  size_t(std::ceil(rangeX.size() / rangeX.cellSize)),
364  size_t(std::ceil(rangeY.size() / rangeY.cellSize)),
365  size_t(std::ceil(rangeZ.size() / rangeZ.cellSize))
366  }};
367  } // diceVolume()
368 
369  } // namespace details
370  } // namespace example
371 } // namespace lar
372 
373 
374 //------------------------------------------------------------------------------
375 //--- template implementation
376 //------------------------------------------------------------------------------
377 //--- lar::example::CoordRange
378 //---
379 template <typename Coord>
381  { return (lower <= c) && (upper >= c); }
382 
383 template <typename Coord>
385  { return lower == upper; }
386 
387 
388 template <typename Coord>
390  { return lower <= upper; }
391 
392 template <typename Coord>
394  { return upper - lower; }
395 
396 template <typename Coord>
398  { return (upper == as.upper) && (lower == as.lower); }
399 
400 template <typename Coord>
402  { return (upper != than.upper) || (lower != than.lower); }
403 
404 
405 //------------------------------------------------------------------------------
406 //--- lar::example::CoordRange
407 //---
408 template <typename Coord>
411  : Base_t(low, high), cellSize(cs)
412  {}
413 
414 template <typename Coord>
416  (Base_t const& range, Coord_t cs)
417  : Base_t(range), cellSize(cs)
418  {}
419 
420 //------------------------------------------------------------------------------
421 template <typename Coord>
423  { return std::ptrdiff_t(Base_t::offset(c) / cellSize); }
424 
425 
426 //------------------------------------------------------------------------------
427 //--- lar::example::SpacePartition
428 //---
429 template <typename PointIter>
431  (Range_t rangeX, Range_t rangeY, Range_t rangeZ)
432  : xRange(rangeX)
433  , yRange(rangeY)
434  , zRange(rangeZ)
435  , data(details::diceVolume(xRange, yRange, zRange))
436 {
437  /*
438  std::cout << "Grid: "
439  << indexManager().sizeX() << " x "
440  << indexManager().sizeY() << " x " << indexManager().sizeZ()
441  << " (" << indexManager().size() << " cells)"
442  << "\n range X: " << xRange.lower << " -- " << xRange.upper << " [/" << xRange.cellSize << "]"
443  << "\n range Y: " << yRange.lower << " -- " << yRange.upper << " [/" << yRange.cellSize << "]"
444  << "\n range Z: " << zRange.lower << " -- " << zRange.upper << " [/" << zRange.cellSize << "]"
445  << std::endl;
446  */
447 } // lar::example::SpacePartition<>::SpacePartition
448 
449 
450 //--------------------------------------------------------------------------
451 template <typename PointIter>
453  (PointIter begin, PointIter end)
454 {
455 
456  PointIter it = begin;
457  while (it != end) {
458  // if the point is outside the volume, pointIndex will throw an exception
459  data.insert(pointIndex(*it), it);
460  ++it;
461  } // while
462 
463 } // lar::example::SpacePartition<>::fill()
464 
465 
466 //--------------------------------------------------------------------------
467 template <typename PointIter>
470 {
471  // compute the cell ID coordinates
472  Coord_t const x = details::extractPositionX(point);
473  CellDimIndex_t const xc = xRange.findCell(x);
474  if (!data.hasX(xc)) {
475  throw std::runtime_error
476  ("Point out of the volume (x = " + std::to_string(x) + ")");
477  }
478 
479  Coord_t const y = details::extractPositionY(point);
480  CellDimIndex_t const yc = yRange.findCell(y);
481  if (!data.hasY(yc)) {
482  throw std::runtime_error
483  ("Point out of the volume (y = " + std::to_string(y) + ")");
484  }
485 
486  Coord_t const z = details::extractPositionZ(point);
487  CellDimIndex_t const zc = zRange.findCell(z);
488  if (!data.hasZ(zc)) {
489  throw std::runtime_error
490  ("Point out of the volume (z = " + std::to_string(z) + ")");
491  }
492 
493  // return its index
494  return data.index(CellID_t{{ xc, yc, zc }});
495 
496 } // lar::example::SpacePartition<>::pointIndex()
497 
498 
499 //--------------------------------------------------------------------------
500 
501 #endif // LAREXAMPLES_ALGORITHMS_REMOVEISOLATEDSPACEPOINTS_SPACEPARTITION_H
A container of points sorted in cells.
process_name opflash particleana ie ie ie z
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
Grid_t::const_iterator end() const
Returns a constant iterator pointing after the last cell.
Range_t zRange
coordinates of the contained volume on z axis
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Definition: CORSIKAGen.fcl:7
Range_t yRange
coordinates of the contained volume on z axis
Coord_t size() const
Returns the size of the range (no check)
process_name opflash particleana ie x
Indexer_t const & indexManager() const
Returns the index manager of the grid.
Coord_t cellSize
length of the side of each cubic cell
std::vector< Datum_t > Cell_t
type of a single cell container
typename Cells_t::const_iterator const_iterator
type of iterator to all cells
pdgs p
Definition: selectors.fcl:22
CellIndexOffset_t pointIndex(Point_t const &point) const
Grid_t::const_iterator begin() const
Returns a constant iterator pointing to the first cell.
Range_t xRange
coordinates of the contained volume on x axis
typename details::PointTraits_t< Point >::Coord_t ExtractCoordType_t
type of Point coordinate
Helper extractor for point coordinates.
typename Grid_t::Indexer_t Indexer_t
type of index manager of the grid
Range of coordinates.
Coord_t cellSize
size of a single cell
bool contains(Coord_t c) const
Returns whether c is contained in the range (inclusve)
details::ExtractCoordType_t< Point_t > Coord_t
type of point coordinate
bool has(CellIndexOffset_t ofs) const
Returns whether there is a cell with the specified index (signed!)
standard_dbscan3dalg useful for diagnostics hits not in a line will not be clustered on on only for track like only for track like on on the smaller the less shower like tracks low
Coord_t upper
upper boundary
std::array< size_t, 3 > diceVolume(CoordRangeCells< Coord > const &rangeX, CoordRangeCells< Coord > const &rangeY, CoordRangeCells< Coord > const &rangeZ)
Returns the dimensions of a grid diced with the specified size.
Coord_t lower
lower boundary
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
auto extractPositionY(Point const &point)
bool operator!=(const Range_t &than) const
Returns whether the specified range has limits different than this.
SpacePartition(Range_t rangeX, Range_t rangeY, Range_t rangeZ)
Constructs the partition in a given volume with the given cell size.
bool valid() const
Returns whether the range is valid (empty is also valid)
then echo ***************************************echo array
Definition: find_fhicl.sh:28
process_name opflash particleana ie ie y
decltype(*(PointIter())) Point_t
type of the point
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:44
Coord_t offset(Coord_t c) const
Returns the distance of the specified coordinate from the lower bound.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
typename Indexer_t::CellIndexOffset_t CellIndexOffset_t
type of difference between cell indices
typename Grid_t::Cell_t Cell_t
type of cell
decltype(extractPositionX(std::decay_t< Point >())) Coord_t
type of Point coordinate
bool operator==(const Range_t &as) const
Returns whether the specified range has the same limits as this.
bool empty() const
Returns whether the range is empty.
Base for PositionExtractor on random-access containers.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
typename Indexer_t::CellDimIndex_t CellDimIndex_t
type of difference between indices
bool has(CellIndexOffset_t index) const
Returns whether the specified index is valid.
Grid_t data
container of points
std::string to_string(WindowPattern const &pattern)
CoordRange< Coord > Range_t
this type
auto extractPositionX(Point const &point)
typename Grid_t::CellDimIndex_t CellDimIndex_t
typename Indexer_t::CellID_t CellID_t
type of cell index
std::ptrdiff_t findCell(Coord_t c) const
Returns the index of the cell for coordinate c.
Containers with indices in 1, 2 and 3 dimensions.
Range of coordinates.
Indexer_t const & indexManager() const
Returns the index manager of the grid.
auto extractPositionZ(Point const &point)
CoordRangeCells(Coord_t low, Coord_t high, Coord_t cs)
Constructor: assigns range and cell size.
Coord_t Coord_t
data type for coordinate
Base class for a container of data arranged on a 3D-grid.
Cell_t const & operator[](CellIndex_t index) const
Returns the cell with the specified index.
void fill(PointIter begin, PointIter end)
typename Indexer_t::CellIndex_t CellIndex_t