Virtual Testbed
Ship dynamics simulator for extreme conditions
core/grid.hh
1 #ifndef VTESTBED_CORE_GRID_HH
2 #define VTESTBED_CORE_GRID_HH
3 
4 #include <cmath>
5 #include <ostream>
6 #include <stdexcept>
7 
8 #include <vtestbed/base/blitz.hh>
9 #include <vtestbed/base/bstream.hh>
10 #include <vtestbed/base/for_loop.hh>
11 
12 namespace vtb {
13 
14  namespace core {
15 
24  template <class T, int N>
25  class Grid {
26 
27  public:
28  typedef blitz::TinyVector<T,N> vec;
29  typedef blitz::TinyVector<int,N> int_n;
30 
31  private:
32  vec _lbound{T{0}};
33  vec _ubound{T{0}};
34  int_n _begin_index{blitz::const_vector<int,N>(0)};
35  int_n _end_index{blitz::const_vector<int,N>(0)};
36 
37  public:
38 
39  Grid() = default;
40  ~Grid() = default;
41  Grid(const Grid&) = default;
42  Grid& operator=(const Grid&) = default;
43  Grid(Grid&&) = default;
44  Grid& operator=(Grid&&) = default;
45 
46  template <class X>
47  inline explicit
48  Grid(const Grid<X,N>& rhs) {
49  this->_lbound = rhs.lbound();
50  this->_ubound = rhs.ubound();
51  this->_begin_index = rhs.begin();
52  this->_end_index = rhs.end();
53  }
54 
55  inline
56  Grid(
57  const vec& lbound,
58  const vec& ubound,
59  const int_n& begin_index,
60  const int_n& end_index
61  ):
62  _lbound(lbound),
63  _ubound(ubound),
64  _begin_index(begin_index),
65  _end_index(end_index) {
66  #if defined(VTB_DEBUG)
67  for (int i=0; i<N; ++i) {
68  if (this->begin(i) > this->end(i)) {
70  "vtb::core::Grid: bad begin/end index"
71  );
72  }
73  }
74  #endif
75  }
76 
77  inline
78  Grid(const vec& lbound, const vec& ubound, const int_n& shape):
79  Grid(lbound, ubound, blitz::const_vector<int, N>(0), shape) {}
80 
81  inline
82  Grid(const vec& ubound, const int_n& shape):
83  Grid(
84  blitz::const_vector<T,N>(T{0}),
85  ubound,
86  blitz::const_vector<int,N>(0),
87  shape
88  ) {}
89 
90  inline explicit
91  Grid(const int_n& shape):
92  Grid(vec{shape-1}, shape) {}
93 
94  template <class ... Tail>
95  inline explicit
96  Grid(const Grid<T,1>& head, const Tail& ... tail) {
97  const Grid<T,1>* grids[N] = {&head, &(tail)...};
98  for (int i=0; i<N; ++i) {
99  this->_lbound(i) = grids[i]->lbound(0);
100  this->_ubound(i) = grids[i]->ubound(0);
101  this->_begin_index(i) = grids[i]->begin(0);
102  this->_end_index(i) = grids[i]->end(0);
103  }
104  }
105 
107  inline const int_n
108  shape() const noexcept {
109  return this->end() - this->begin();
110  }
111 
113  inline int
114  extent(int i) const noexcept {
115  return this->end(i) - this->begin(i);
116  }
117 
119  inline const int_n&
120  begin() const noexcept {
121  return this->_begin_index;
122  }
123 
125  inline int_n&
126  begin() noexcept {
127  return this->_begin_index;
128  }
129 
131  inline int
132  begin(int i) const noexcept {
133  return this->_begin_index(i);
134  }
135 
137  inline int&
138  begin(int i) noexcept {
139  return this->_begin_index(i);
140  }
141 
143  inline const int_n&
144  end() const noexcept {
145  return this->_end_index;
146  }
147 
149  inline int_n&
150  end() noexcept {
151  return this->_end_index;
152  }
153 
155  inline int&
156  end(int i) noexcept {
157  return this->_end_index(i);
158  }
159 
161  inline int
162  end(int i) const noexcept {
163  return this->_end_index(i);
164  }
165 
167  inline const vec&
168  lbound() const noexcept {
169  return this->_lbound;
170  }
171 
173  inline vec&
174  lbound() noexcept {
175  return this->_lbound;
176  }
177 
178  inline T
179  lbound(int i) const noexcept {
180  return this->_lbound(i);
181  }
182 
183  inline T&
184  lbound(int i) noexcept {
185  return this->_lbound(i);
186  }
187 
189  inline const vec&
190  ubound() const noexcept {
191  return this->_ubound;
192  }
193 
195  inline vec&
196  ubound() noexcept {
197  return this->_ubound;
198  }
199 
200  inline T
201  ubound(int i) const noexcept {
202  return this->_ubound(i);
203  }
204 
205  inline T&
206  ubound(int i) noexcept {
207  return this->_ubound(i);
208  }
209 
211  inline int
212  num_patches(int i) const {
213  return std::max(this->extent(i)-1, 1);
214  }
215 
217  inline const int_n
218  num_patches() const {
219  return blitz::max(this->shape()-1, 1);
220  }
221 
223  inline const vec
224  size() const noexcept {
225  return this->ubound() - this->lbound();
226  }
227 
229  inline const T
230  length(int i) const noexcept {
231  return this->ubound(i) - this->lbound(i);
232  }
233 
235  inline size_t num_elements() const { return product(shape()); }
236 
238  inline const T
239  delta(int i) const {
240  const int npatches = this->num_patches(i);
241  return npatches == 0 ? T(0) : (this->length(i) / npatches);
242  }
243 
245  inline vec
246  delta() const {
247  using blitz::where;
248  const auto& npatches = this->num_patches();
249  return where(npatches == 0, T(0), this->size() / npatches);
250  }
251 
253  inline const vec
254  operator()(const int_n& i) const noexcept {
255  return this->lbound() + this->delta()*(i - this->begin());
256  }
257 
259  inline const vec
260  operator()(const int_n& i, const vec& delta) const noexcept {
261  return this->lbound() + delta*(i - this->begin());
262  }
263 
264  inline const T
265  operator()(const int i, const int dim) const noexcept {
266  return this->lbound(dim) +
267  this->delta(dim)*(i - this->begin(dim));
268  }
269 
270  inline const vec
271  index(const vec& x) const noexcept {
272  using blitz::where;
273  const auto& npatches = this->num_patches();
274  return this->begin() + where(
275  npatches == 0,
276  T(0),
277  (x - this->lbound()) / this->delta()
278  );
279  }
280 
281  inline const T
282  index(T x, const int dim) const noexcept {
283  const int npatches = this->num_patches(dim);
284  return this->begin(dim) +
285  (npatches == 0 ? T(0)
286  : ((x - this->lbound(dim)) / this->delta(dim)));
287  }
288 
289  inline Grid<T,N>
290  operator()(const blitz::RectDomain<N>& domain) const {
291  Grid<T,N> result;
292  for (int i=0; i<N; ++i) {
293  auto start = domain.lbound(i);
294  auto end = domain.ubound(i);
295  result._begin_index[i] = start;
296  result._end_index[i] = end+1;
297  result._lbound[i] = (*this)(start, i);
298  result._ubound[i] = (*this)(end, i);
299  }
300  return result;
301  }
302 
303  template <class ... Tail>
304  inline Grid<T,N>
305  operator()(const blitz::Range& head, const Tail& ... tail) const {
306  const blitz::Range* ranges[N] = {&head, &(tail)...};
307  Grid<T,N> result;
308  for (int i=0; i<N; ++i) {
309  const auto& r = *ranges[i];
310  auto start = r.first(this->_begin_index[i]);
311  auto end = r.last(this->_end_index[i]-1);
312  result._begin_index[i] = start;
313  result._end_index[i] = end+1;
314  result._lbound[i] = (*this)(start, i);
315  result._ubound[i] = (*this)(end, i);
316  }
317  return result;
318  }
319 
320  template <class ... Tail>
321  inline auto
322  select(int head, Tail ... tail) const -> Grid<T,sizeof...(tail)+1> {
323  const int dimensions[] = {head, tail...};
324  Grid<T,sizeof...(tail)+1> result;
325  for (size_t i=0; i<sizeof...(tail)+1; ++i) {
326  const auto dim = dimensions[i];
327  if (dim >= N) { throw std::invalid_argument("bad dimension"); }
328  result.begin(i) = this->_begin_index[dim],
329  result.end(i) = this->_end_index[dim],
330  result.lbound(i) = this->_lbound[dim],
331  result.ubound(i) = this->_ubound[dim];
332  }
333  return result;
334  }
335 
336  inline void compact() { end() -= begin(); begin() = 0; }
337 
338  inline void
339  clear() noexcept {
340  this->_lbound = T(0);
341  this->_ubound = T(0);
342  this->_begin_index = 0;
343  this->_end_index = 1;
344  }
345 
346  inline bool
347  within_bounds(T x, int dim) const noexcept {
348  return !(x < this->_lbound(dim) || x > this->_ubound(dim));
349  }
350 
351  inline bool
352  contains(const vec& x) const noexcept {
353  return !blitz::any(x < this->lbound() || x > this->ubound());
354  }
355 
356  template <class ... Args>
357  inline bool
358  contains(const vec& x , const Args& ... tail) const noexcept {
359  return this->contains(x) && contains(tail...);
360  }
361 
362  inline bool
363  near(const Grid& rhs, T eps) {
364  using blitz::all;
365  using blitz::near;
366  return
367  all(rhs.begin() == this->begin()) &&
368  all(rhs.end() == this->end()) &&
369  near(rhs.lbound(), this->lbound(), eps) &&
370  near(rhs.ubound(), this->ubound(), eps);
371  }
372 
373  inline bool
374  empty() const {
375  using blitz::any;
376  return any(lbound() > ubound()) || any(shape() <= 1);
377  }
378 
379  inline friend bstream&
380  operator<<(bstream& out, const Grid& rhs) {
381  out << rhs._lbound;
382  out << rhs._ubound;
383  out << rhs._begin_index;
384  out << rhs._end_index;
385  return out;
386  }
387 
388  inline friend bstream&
389  operator>>(bstream& in, Grid& rhs) {
390  in >> rhs._lbound;
391  in >> rhs._ubound;
392  in >> rhs._begin_index;
393  in >> rhs._end_index;
394  return in;
395  }
396 
397  friend std::ostream&
398  operator<<(std::ostream& out, const Grid& rhs) {
399  return out
400  << "from" << ' ' << rhs._lbound << ' '
401  << "to" << ' ' << rhs._ubound << ' '
402  << "start" << ' ' << rhs._begin_index << ' '
403  << "end" << ' ' << rhs._end_index;
404  }
405 
406  };
407 
408  template <class T>
409  blitz::Array<T,1>
410  generate(const Grid<T,1>& grid);
411 
412  template <class T, int N>
413  inline blitz::TinyVector<T,N>
414  clamp(const blitz::TinyVector<T,N> x, const Grid<T,N>& grid) {
415  using blitz::min;
416  using blitz::max;
417  return max(grid.lbound(), min(grid.ubound(), x));
418  }
419 
420  template <class T, int N, class Function>
421  inline void
422  generate(
423  const Grid<T,N>& grid,
424  blitz::Array<T,N>& result,
425  Function func
426  ) {
427  #if defined(VTB_DEBUG)
428  if (!all(result.shape() <= grid.end())) {
429  throw std::invalid_argument(
430  "vtb::core::generate: bad result shape"
431  );
432  }
433  #endif
434  const auto delta{grid.delta()};
435  parallel_for_loop<N>(
436  grid.begin(),
437  grid.end(),
438  [&](const blitz::TinyVector<int,N>& idx) {
439  result(idx) = func(grid(idx, delta));
440  }
441  );
442  }
443 
444  template <class T, int N, class Function>
445  inline blitz::Array<T,N>
446  generate(
447  const Grid<T,N>& grid,
448  Function func
449  ) {
450  blitz::Array<T,N> result(grid.shape());
451  generate<T,N,Function>(grid, result, func);
452  return result;
453  }
454 
455  }
456 
457 }
458 
459 #endif // vim:filetype=cpp
const T length(int i) const noexcept
The size of the region for dimension i.
Definition: core/grid.hh:230
int extent(int i) const noexcept
The number of points for dimension i.
Definition: core/grid.hh:114
T generate(T... args)
int num_patches(int i) const
The number of patches (intervals) for dimension i.
Definition: core/grid.hh:212
const int_n & end() const noexcept
End indices (exclusive).
Definition: core/grid.hh:144
size_t num_elements() const
Total number of grid points.
Definition: core/grid.hh:235
const vec & lbound() const noexcept
Lower bound of the region.
Definition: core/grid.hh:168
T min(T... args)
const int_n shape() const noexcept
The number of points for all dimensions.
Definition: core/grid.hh:108
const vec size() const noexcept
The size of the region.
Definition: core/grid.hh:224
const T delta(int i) const
The size of the patch (interval) for dimension i.
Definition: core/grid.hh:239
A region defined by start and end index and lower and upper bound for each dimension.
Definition: core/grid.hh:25
int & end(int i) noexcept
End index for dimension i (exclusive).
Definition: core/grid.hh:156
int end(int i) const noexcept
End index for dimension i (exclusive).
Definition: core/grid.hh:162
const int_n & begin() const noexcept
Start indices (inclusive).
Definition: core/grid.hh:120
T max(T... args)
Main namespace.
Definition: convert.hh:9
const vec operator()(const int_n &i) const noexcept
Point inside the region specified by index i.
Definition: core/grid.hh:254
int & begin(int i) noexcept
Start index for dimension i (inclusive).
Definition: core/grid.hh:138
vec delta() const
The size of the patch (interval) for all dimensions.
Definition: core/grid.hh:246
int_n & end() noexcept
End indices (exclusive).
Definition: core/grid.hh:150
vec & lbound() noexcept
Lower bound of the region.
Definition: core/grid.hh:174
const vec & ubound() const noexcept
Upper bound of the region.
Definition: core/grid.hh:190
const int_n num_patches() const
The number of patches (intervals) for all dimensions.
Definition: core/grid.hh:218
int begin(int i) const noexcept
Start index for dimension i (inclusive).
Definition: core/grid.hh:132
int_n & begin() noexcept
Start indices (inclusive).
Definition: core/grid.hh:126
vec & ubound() noexcept
Upper bound of the region.
Definition: core/grid.hh:196
const vec operator()(const int_n &i, const vec &delta) const noexcept
Point inside the region specified by index i and delta.
Definition: core/grid.hh:260