Version: SMASH-1.5
lattice.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2015-2018
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #ifndef SRC_INCLUDE_LATTICE_H_
11 #define SRC_INCLUDE_LATTICE_H_
12 
13 #include <array>
14 #include <cstring>
15 #include <functional>
16 #include <utility>
17 #include <vector>
18 
19 #include "forwarddeclarations.h"
20 #include "fourvector.h"
21 #include "logging.h"
22 #include "numerics.h"
23 
24 namespace smash {
25 
35 enum class LatticeUpdate {
36  AtOutput = 0,
37  EveryTimestep = 1,
39 };
40 
45 template <typename T>
47  public:
65  RectangularLattice(const std::array<double, 3>& l,
66  const std::array<int, 3>& n,
67  const std::array<double, 3>& orig, bool per,
68  const LatticeUpdate upd)
69  : lattice_sizes_(l),
70  n_cells_(n),
71  cell_sizes_{l[0] / n[0], l[1] / n[1], l[2] / n[2]},
72  origin_(orig),
73  periodic_(per),
74  when_update_(upd) {
75  lattice_.resize(n_cells_[0] * n_cells_[1] * n_cells_[2]);
76  const auto& log = logger<LogArea::Lattice>();
77  log.debug("Rectangular lattice created: sizes[fm] = (", lattice_sizes_[0],
78  ",", lattice_sizes_[1], ",", lattice_sizes_[2], "), dims = (",
79  n_cells_[0], ",", n_cells_[1], ",", n_cells_[2], "), origin = (",
80  origin_[0], ",", origin_[1], ",", origin_[2],
81  "), periodic: ", periodic_);
82  if (n_cells_[0] < 1 || n_cells_[1] < 1 || n_cells_[2] < 1 ||
83  lattice_sizes_[0] < 0.0 || lattice_sizes_[1] < 0.0 ||
84  lattice_sizes_[2] < 0.0) {
85  throw std::invalid_argument(
86  "Lattice sizes should be positive, "
87  "lattice dimensions should be > 0.");
88  }
89  }
90 
92  void reset() { std::fill(lattice_.begin(), lattice_.end(), T()); }
93 
102  inline bool out_of_bounds(int ix, int iy, int iz) const {
103  // clang-format off
104  return !periodic_ &&
105  (ix < 0 || ix >= n_cells_[0] ||
106  iy < 0 || iy >= n_cells_[1] ||
107  iz < 0 || iz >= n_cells_[2]);
108  // clang-format on
109  }
110 
119  inline ThreeVector cell_center(int ix, int iy, int iz) const {
120  return ThreeVector(origin_[0] + cell_sizes_[0] * (ix + 0.5),
121  origin_[1] + cell_sizes_[1] * (iy + 0.5),
122  origin_[2] + cell_sizes_[2] * (iz + 0.5));
123  }
124 
133  inline ThreeVector cell_center(int index) const {
134  const int ix = index % n_cells_[0];
135  index = index / n_cells_[0];
136  const int iy = index % n_cells_[1];
137  const int iz = index / n_cells_[1];
138  return cell_center(ix, iy, iz);
139  }
140 
142  const std::array<double, 3>& lattice_sizes() const { return lattice_sizes_; }
143 
145  const std::array<int, 3>& dimensions() const { return n_cells_; }
146 
148  const std::array<double, 3>& cell_sizes() const { return cell_sizes_; }
149 
151  const std::array<double, 3>& origin() const { return origin_; }
152 
154  bool periodic() const { return periodic_; }
155 
158 
160  using iterator = typename std::vector<T>::iterator;
162  using const_iterator = typename std::vector<T>::const_iterator;
164  iterator begin() { return lattice_.begin(); }
166  const_iterator begin() const { return lattice_.begin(); }
168  iterator end() { return lattice_.end(); }
170  const_iterator end() const { return lattice_.end(); }
172  T& operator[](std::size_t i) { return lattice_[i]; }
174  const T& operator[](std::size_t i) const { return lattice_[i]; }
176  std::size_t size() const { return lattice_.size(); }
177 
186  T& node(int ix, int iy, int iz) {
187  return periodic_
188  ? lattice_[positive_modulo(ix, n_cells_[0]) +
189  n_cells_[0] *
190  (positive_modulo(iy, n_cells_[1]) +
191  n_cells_[1] * positive_modulo(iz, n_cells_[2]))]
192  : lattice_[ix + n_cells_[0] * (iy + n_cells_[1] * iz)];
193  }
194 
209  bool value_at(const ThreeVector& r, T& value) {
210  const int ix = std::floor((r.x1() - origin_[0]) / cell_sizes_[0]);
211  const int iy = std::floor((r.x2() - origin_[1]) / cell_sizes_[1]);
212  const int iz = std::floor((r.x3() - origin_[2]) / cell_sizes_[2]);
213  if (out_of_bounds(ix, iy, iz)) {
214  value = T();
215  return false;
216  } else {
217  value = node(ix, iy, iz);
218  return true;
219  }
220  }
221 
232  template <typename F>
233  void iterate_sublattice(const std::array<int, 3>& lower_bounds,
234  const std::array<int, 3>& upper_bounds, F&& func) {
235  const auto& log = logger<LogArea::Lattice>();
236  log.debug("Iterating sublattice with lower bound index (", lower_bounds[0],
237  ",", lower_bounds[1], ",", lower_bounds[2],
238  "), upper bound index (", upper_bounds[0], ",", upper_bounds[1],
239  ",", upper_bounds[2], ")");
240 
241  if (periodic_) {
242  for (int iz = lower_bounds[2]; iz < upper_bounds[2]; iz++) {
243  const int z_offset = positive_modulo(iz, n_cells_[2]) * n_cells_[1];
244  for (int iy = lower_bounds[1]; iy < upper_bounds[1]; iy++) {
245  const int y_offset =
246  n_cells_[0] * (positive_modulo(iy, n_cells_[1]) + z_offset);
247  for (int ix = lower_bounds[0]; ix < upper_bounds[0]; ix++) {
248  const int index = positive_modulo(ix, n_cells_[0]) + y_offset;
249  func(lattice_[index], ix, iy, iz);
250  }
251  }
252  }
253  } else {
254  for (int iz = lower_bounds[2]; iz < upper_bounds[2]; iz++) {
255  const int z_offset = iz * n_cells_[1];
256  for (int iy = lower_bounds[1]; iy < upper_bounds[1]; iy++) {
257  const int y_offset = n_cells_[0] * (iy + z_offset);
258  for (int ix = lower_bounds[0]; ix < upper_bounds[0]; ix++) {
259  func(lattice_[ix + y_offset], ix, iy, iz);
260  }
261  }
262  }
263  }
264  }
265 
278  template <typename F>
279  void iterate_in_radius(const ThreeVector& point, const double r_cut,
280  F&& func) {
281  std::array<int, 3> l_bounds, u_bounds;
282 
283  /* Array holds value at the cell center: r_center = r_0 + (i+0.5)cell_size,
284  * where i is index in any direction. Therefore we want cells with condition
285  * (r-r_cut)*csize - 0.5 < i < (r+r_cut)*csize - 0.5, r = r_center - r_0 */
286  for (int i = 0; i < 3; i++) {
287  l_bounds[i] =
288  std::ceil((point[i] - origin_[i] - r_cut) / cell_sizes_[i] - 0.5);
289  u_bounds[i] =
290  std::ceil((point[i] - origin_[i] + r_cut) / cell_sizes_[i] - 0.5);
291  }
292 
293  if (!periodic_) {
294  for (int i = 0; i < 3; i++) {
295  if (l_bounds[i] < 0) {
296  l_bounds[i] = 0;
297  }
298  if (u_bounds[i] > n_cells_[i]) {
299  u_bounds[i] = n_cells_[i];
300  }
301  if (l_bounds[i] > n_cells_[i] || u_bounds[i] < 0) {
302  return;
303  }
304  }
305  }
306  iterate_sublattice(l_bounds, u_bounds, std::forward<F>(func));
307  }
308 
317  template <typename L>
318  bool identical_to_lattice(const L* lat) const {
319  return n_cells_[0] == lat->dimensions()[0] &&
320  n_cells_[1] == lat->dimensions()[1] &&
321  n_cells_[2] == lat->dimensions()[2] &&
322  std::abs(lattice_sizes_[0] - lat->lattice_sizes()[0]) <
323  really_small &&
324  std::abs(lattice_sizes_[1] - lat->lattice_sizes()[1]) <
325  really_small &&
326  std::abs(lattice_sizes_[2] - lat->lattice_sizes()[2]) <
327  really_small &&
328  std::abs(origin_[0] - lat->origin()[0]) < really_small &&
329  std::abs(origin_[1] - lat->origin()[1]) < really_small &&
330  std::abs(origin_[2] - lat->origin()[2]) < really_small &&
331  periodic_ == lat->periodic();
332  }
333 
334  protected:
336  std::vector<T> lattice_;
338  const std::array<double, 3> lattice_sizes_;
340  const std::array<int, 3> n_cells_;
342  const std::array<double, 3> cell_sizes_;
344  const std::array<double, 3> origin_;
346  const bool periodic_;
349 
350  private:
359  inline int positive_modulo(int i, int n) const {
360  /* (i % n + n) % n would be correct, but slow.
361  * Instead I rely on the fact that i should never go too far
362  * in negative region and replace i%n + n by i + 256 * n = i + (n << 8) */
363  // FIXME: This should use asserts, also checking for under- or overflows.
364  return (i + (n << 8)) % n;
365  }
366 };
367 
368 } // namespace smash
369 
370 #endif // SRC_INCLUDE_LATTICE_H_
The ThreeVector class represents a physical three-vector with the components .
Definition: threevector.h:30
double x3() const
Definition: threevector.h:163
bool periodic() const
Definition: lattice.h:154
constexpr double really_small
Numerical error tolerance.
Definition: constants.h:34
const_iterator begin() const
Definition: lattice.h:166
bool out_of_bounds(int ix, int iy, int iz) const
Checks if 3D index is out of lattice bounds.
Definition: lattice.h:102
T & node(int ix, int iy, int iz)
Take the value of a cell given its 3-D indices.
Definition: lattice.h:186
const std::array< int, 3 > & dimensions() const
Definition: lattice.h:145
double x1() const
Definition: threevector.h:155
int positive_modulo(int i, int n) const
Returns division modulo, which is always between 0 and n-1 in is not suitable, because it returns res...
Definition: lattice.h:359
const_iterator end() const
Definition: lattice.h:170
T & operator[](std::size_t i)
Definition: lattice.h:172
LatticeUpdate
Enumerator option for lattice updates.
Definition: lattice.h:35
std::vector< T > lattice_
The lattice itself, array containing physical quantities.
Definition: lattice.h:336
typename std::vector< smash::EnergyMomentumTensor >::iterator iterator
Iterator of lattice.
Definition: lattice.h:160
const LatticeUpdate when_update_
When the lattice should be recalculated.
Definition: lattice.h:348
const std::array< double, 3 > lattice_sizes_
Lattice sizes in x, y, z directions.
Definition: lattice.h:338
void iterate_in_radius(const ThreeVector &point, const double r_cut, F &&func)
Iterates only nodes, whose cell centers lie not further than r_cut in x, y, z directions from the giv...
Definition: lattice.h:279
Generic numerical functions.
LatticeUpdate when_update() const
Definition: lattice.h:157
const std::array< double, 3 > origin_
Coordinates of the left down nearer corner.
Definition: lattice.h:344
A container class to hold all the arrays on the lattice and access them.
Definition: lattice.h:46
typename std::vector< smash::EnergyMomentumTensor >::const_iterator const_iterator
Const interator of lattice.
Definition: lattice.h:162
bool identical_to_lattice(const L *lat) const
Checks if lattices of possibly different types have identical structure.
Definition: lattice.h:318
const bool periodic_
Whether the lattice is periodic.
Definition: lattice.h:346
void reset()
Sets all values on lattice to zeros.
Definition: lattice.h:92
RectangularLattice(const std::array< double, 3 > &l, const std::array< int, 3 > &n, const std::array< double, 3 > &orig, bool per, const LatticeUpdate upd)
Rectangular lattice constructor.
Definition: lattice.h:65
const std::array< double, 3 > & origin() const
Definition: lattice.h:151
const std::array< double, 3 > & cell_sizes() const
Definition: lattice.h:148
bool value_at(const ThreeVector &r, T &value)
Interpolates lattice quantity to coordinate r.
Definition: lattice.h:209
const std::array< double, 3 > cell_sizes_
Cell sizes in x, y, z directions.
Definition: lattice.h:342
const std::array< double, 3 > & lattice_sizes() const
Definition: lattice.h:142
ThreeVector cell_center(int ix, int iy, int iz) const
Find the coordinates of a given cell.
Definition: lattice.h:119
const T & operator[](std::size_t i) const
Definition: lattice.h:174
constexpr int n
Neutron.
ThreeVector cell_center(int index) const
Find the coordinate of cell center given the 1d index of the cell.
Definition: lattice.h:133
void iterate_sublattice(const std::array< int, 3 > &lower_bounds, const std::array< int, 3 > &upper_bounds, F &&func)
A sub-lattice iterator, which iterates in a 3D-structured manner and calls a function on every cell...
Definition: lattice.h:233
std::size_t size() const
Definition: lattice.h:176
double x2() const
Definition: threevector.h:159
Definition: action.h:24
const std::array< int, 3 > n_cells_
Number of cells in x,y,z directions.
Definition: lattice.h:340