ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
BoxGeometry.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2026 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
24
25#include <utils/Vector.hpp>
26
27#include <bitset>
28#include <cassert>
29#include <cmath>
30#include <limits>
31#include <stdexcept>
32#include <utility>
33
34#if defined(__GNUG__) or defined(__clang__)
35#define ESPRESSO_ATTR_ALWAYS_INLINE [[gnu::always_inline]]
36#else
37#define ESPRESSO_ATTR_ALWAYS_INLINE
38#endif
39
40namespace detail {
41/**
42 * @brief Get the minimum-image distance between two coordinates.
43 * @param a Coordinate of the terminal point.
44 * @param b Coordinate of the initial point.
45 * @param box_length Box length.
46 * @param box_length_inv Inverse box length
47 * @param box_length_half Half box length
48 * @param periodic Box periodicity.
49 * @return Shortest distance from @p b to @p a across periodic images,
50 * i.e. <tt>a - b</tt>. Can be negative.
51 */
52template <typename T>
53T get_mi_coord(T a, T b, T box_length, T box_length_inv, T box_length_half,
54 bool periodic) {
55 auto const dx = a - b;
56
57 if (periodic && (std::abs(dx) > box_length_half)) {
58 return dx - std::round(dx * box_length_inv) * box_length;
59 }
60
61 return dx;
62}
63
64/**
65 * @brief Get the minimum-image distance between two coordinates.
66 * @param a Coordinate of the terminal point.
67 * @param b Coordinate of the initial point.
68 * @param box_length Box length.
69 * @param periodic Box periodicity.
70 * @return Shortest distance from @p b to @p a across periodic images,
71 * i.e. <tt>a - b</tt>. Can be negative.
72 */
73template <typename T> T get_mi_coord(T a, T b, T box_length, bool periodic) {
74 return get_mi_coord(a, b, box_length, 1. / box_length, 0.5 * box_length,
75 periodic);
76}
77
78/** @brief Calculate image box shift vector.
79 * @param image_box image box offset
80 * @param box box length
81 * @return Image box coordinates.
82 */
83inline auto image_shift(Utils::Vector3i const &image_box,
84 Utils::Vector3d const &box) {
85 return hadamard_product(image_box, box);
86}
87
88/** @brief Unfold particle coordinates to image box.
89 * @param pos coordinate to unfold
90 * @param image_box image box offset
91 * @param box box length
92 * @return Unfolded coordinates.
93 */
94inline auto unfolded_position(Utils::Vector3d const &pos,
95 Utils::Vector3i const &image_box,
96 Utils::Vector3d const &box) {
97 return pos + image_shift(image_box, box);
98}
99} // namespace detail
100
101enum class BoxType { CUBOID = 0, LEES_EDWARDS = 1 };
102
104public:
106 set_length(Utils::Vector3d{1., 1., 1.});
107 set_periodic(0u, true);
108 set_periodic(1u, true);
109 set_periodic(2u, true);
111 }
113 m_type = rhs.type();
114 set_length(rhs.length());
115 set_periodic(0u, rhs.periodic(0u));
116 set_periodic(1u, rhs.periodic(1u));
117 set_periodic(2u, rhs.periodic(2u));
118 m_lees_edwards_bc = rhs.m_lees_edwards_bc;
119 }
120
121private:
122 BoxType m_type = BoxType::CUBOID;
123 /** Flags for all three dimensions whether pbc are applied (default). */
124 std::bitset<3> m_periodic = 0b111;
125 /** Side lengths of the box */
126 Utils::Vector3d m_length = {1., 1., 1.};
127 /** Inverse side lengths of the box */
128 Utils::Vector3d m_length_inv = {1., 1., 1.};
129 /** Half side lengths of the box */
130 Utils::Vector3d m_length_half = {0.5, 0.5, 0.5};
131
132 /** Lees-Edwards boundary conditions */
133 LeesEdwardsBC m_lees_edwards_bc;
134
135public:
136 /**
137 * @brief Set periodicity for direction
138 *
139 * @param coord The coordinate to set the periodicity for.
140 * @param val True if this direction should be periodic.
141 */
142 void set_periodic(unsigned coord, bool val) { m_periodic.set(coord, val); }
143
144 /**
145 * @brief Check periodicity in direction.
146 *
147 * @param coord Direction to check
148 * @return true iff periodic in direction.
149 */
150 constexpr bool periodic(unsigned coord) const {
151 assert(coord <= 2u);
152 return m_periodic[coord];
153 }
154
155 /**
156 * @brief Box length
157 * @return Return vector of side-lengths of the box.
158 */
159 Utils::Vector3d const &length() const { return m_length; }
160
161 /**
162 * @brief Inverse box length
163 * @return Return vector of inverse side-lengths of the box.
164 */
165 Utils::Vector3d const &length_inv() const { return m_length_inv; }
166
167 /**
168 * @brief Half box length
169 * @return Return vector of half side-lengths of the box.
170 */
171 Utils::Vector3d const &length_half() const { return m_length_half; }
172
173 /**
174 * @brief Set box side lengths.
175 * @param box_l Length that should be set.
176 */
179 m_length = box_l;
180 m_length_inv = {1. / box_l[0], 1. / box_l[1], 1. / box_l[2]};
181 m_length_half = 0.5 * box_l;
182 }
183
184 /**
185 * @brief Box volume
186 * @return Return the volume of the box.
187 */
188 double volume() const { return Utils::product(m_length); }
189
190 /**
191 * @brief Get the minimum-image distance between two coordinates.
192 * @param a Coordinate of the terminal point.
193 * @param b Coordinate of the initial point.
194 * @param coord Direction
195 * @return Shortest distance from @p b to @p a across periodic images,
196 * i.e. <tt>a - b</tt>. Can be negative.
197 */
198 template <typename T> T inline get_mi_coord(T a, T b, unsigned coord) const {
199 assert(coord <= 2u);
200
201 return detail::get_mi_coord(a, b, m_length[coord], m_length_inv[coord],
202 m_length_half[coord], m_periodic[coord]);
203 }
204
205 /**
206 * @brief Get the minimum-image vector between two coordinates.
207 *
208 * @tparam T Floating point type.
209 *
210 * @param a Coordinate of the terminal point.
211 * @param b Coordinate of the initial point.
212 * @return Vector from @p b to @p a that minimizes the distance across
213 * periodic images, i.e. <tt>a - b</tt>.
214 */
215 template <typename T>
218 if (type() == BoxType::LEES_EDWARDS) {
219 auto const shear_plane_normal = lees_edwards_bc().shear_plane_normal;
220 auto a_tmp = a;
221 auto b_tmp = b;
222 a_tmp[shear_plane_normal] = Algorithm::periodic_fold(
223 a_tmp[shear_plane_normal], m_length[shear_plane_normal]);
224 b_tmp[shear_plane_normal] = Algorithm::periodic_fold(
225 b_tmp[shear_plane_normal], m_length[shear_plane_normal]);
226 return lees_edwards_bc().distance(a_tmp - b_tmp, m_length, m_length_half,
227 m_length_inv, m_periodic);
228 }
230 return {get_mi_coord(a[0], b[0], 0u), get_mi_coord(a[1], b[1], 1u),
231 get_mi_coord(a[2], b[2], 2u)};
232 }
233
234 /**
235 * @brief Get the minimum-image vector between two coordinates.
236 *
237 * @tparam T Floating point type.
238 *
239 * @param a0 x element of the terminal point.
240 * @param a1 y element of the terminal point.
241 * @param a2 z element of the terminal point.
242 * @param b0 x element of the initial point.
243 * @param b1 y element of the initial point.
244 * @param b2 z element of the initial point.
245 * @return Vector from @p b to @p a that minimizes the distance across
246 * periodic images, i.e. <tt>a - b</tt>.
247 */
248 template <typename T>
250 get_mi_vector(T const &a0, T const &a1, T const &a2, T const &b0, T const &b1,
251 T const &b2) const {
252 if (type() == BoxType::LEES_EDWARDS) {
253 auto const shear_plane_normal = lees_edwards_bc().shear_plane_normal;
254 auto a_tmp = Utils::Vector3<T>{a0, a1, a2};
255 auto b_tmp = Utils::Vector3<T>{b0, b1, b2};
256 a_tmp[shear_plane_normal] = Algorithm::periodic_fold(
257 a_tmp[shear_plane_normal], m_length[shear_plane_normal]);
258 b_tmp[shear_plane_normal] = Algorithm::periodic_fold(
259 b_tmp[shear_plane_normal], m_length[shear_plane_normal]);
260 return lees_edwards_bc().distance(a_tmp - b_tmp, m_length, m_length_half,
261 m_length_inv, m_periodic);
262 }
264 return {get_mi_coord(a0, b0, 0u), get_mi_coord(a1, b1, 1u),
265 get_mi_coord(a2, b2, 2u)};
266 }
267
268 BoxType type() const { return m_type; }
269 void set_type(BoxType type) { m_type = type; }
270
271 LeesEdwardsBC const &lees_edwards_bc() const { return m_lees_edwards_bc; }
272 void set_lees_edwards_bc(LeesEdwardsBC bc) { m_lees_edwards_bc = bc; }
273
274 /**
275 * @brief Update the Lees-Edwards parameters of the box geometry
276 * for the current simulation time.
277 */
278 void lees_edwards_update(double pos_offset, double shear_velocity) {
280 m_lees_edwards_bc.pos_offset = pos_offset;
281 m_lees_edwards_bc.shear_velocity = shear_velocity;
282 }
283
284 /** Calculate the velocity difference including the Lees-Edwards velocity */
286 Utils::Vector3d const &y,
287 Utils::Vector3d const &u,
288 Utils::Vector3d const &v) const {
289 auto ret = u - v;
290 if (type() == BoxType::LEES_EDWARDS) {
291 auto const &le = m_lees_edwards_bc;
292 auto const shear_plane_normal = le.shear_plane_normal;
293 auto const shear_direction = le.shear_direction;
294 auto const dy = x[shear_plane_normal] - y[shear_plane_normal];
295 if (std::fabs(dy) > length_half()[shear_plane_normal]) {
296 ret[shear_direction] -= std::copysign(le.shear_velocity, dy);
297 }
298 }
299 return ret;
300 }
301
302 /** @brief Fold coordinates to primary simulation box in-place.
303 * Lees-Edwards offset is ignored.
304 * @param[in,out] pos coordinates to fold
305 * @param[in,out] image_box image box offset
306 */
307 void fold_position(Utils::Vector3d &pos, Utils::Vector3i &image_box) const {
308 for (auto i = 0u; i < 3u; i++) {
309 if (m_periodic[i]) {
310 auto const result =
311 Algorithm::periodic_fold(pos[i], image_box[i], m_length[i]);
312 if (result.second == std::numeric_limits<int>::min() or
313 result.second == std::numeric_limits<int>::max()) {
314 throw std::runtime_error(
315 "Overflow in the image box count while folding a particle "
316 "coordinate into the primary simulation box. Maybe a particle "
317 "experienced a huge force.");
318 }
319 std::tie(pos[i], image_box[i]) = result;
320 }
321 }
322 }
323
324 /**
325 * @brief Calculate coordinates folded to primary simulation box.
326 * @param[in] pos coordinates to fold
327 * @return Folded coordinates.
328 */
329 auto folded_position(Utils::Vector3d const &pos) const {
330 auto pos_folded = pos;
331 for (auto i = 0u; i < 3u; i++) {
332 if (m_periodic[i]) {
333 pos_folded[i] = Algorithm::periodic_fold(pos[i], m_length[i]);
334 }
335 }
336
337 return pos_folded;
338 }
339
340 /**
341 * @brief Calculate image box of coordinates folded to primary simulation box.
342 * @param[in] pos coordinates
343 * @param[in] image_box image box to fold
344 * @return Folded image box.
345 */
347 Utils::Vector3i const &image_box) const {
348 auto image_box_folded = image_box;
349 for (auto i = 0u; i < 3u; i++) {
350 if (m_periodic[i]) {
352 Algorithm::periodic_fold(pos[i], image_box[i], m_length[i]).second;
353 }
354 }
355
356 return image_box_folded;
357 }
358
359 /** @brief Calculate image box shift vector */
360 auto image_shift(Utils::Vector3i const &image_box) const {
361 return detail::image_shift(image_box, m_length);
362 }
363
364 /** @brief Unfold particle coordinates to image box. */
366 Utils::Vector3i const &image_box) const {
367 return detail::unfolded_position(pos, image_box, m_length);
368 }
369};
BoxType
@ LEES_EDWARDS
#define ESPRESSO_ATTR_ALWAYS_INLINE
static int coord(std::string const &s)
Vector implementation and trait types for boost qvm interoperability.
auto unfolded_position(Utils::Vector3d const &pos, Utils::Vector3i const &image_box) const
Unfold particle coordinates to image box.
T get_mi_coord(T a, T b, unsigned coord) const
Get the minimum-image distance between two coordinates.
ESPRESSO_ATTR_ALWAYS_INLINE Utils::Vector3< T > get_mi_vector(Utils::Vector3< T > const &a, Utils::Vector3< T > const &b) const
Get the minimum-image vector between two coordinates.
void lees_edwards_update(double pos_offset, double shear_velocity)
Update the Lees-Edwards parameters of the box geometry for the current simulation time.
auto folded_position(Utils::Vector3d const &pos) const
Calculate coordinates folded to primary simulation box.
Utils::Vector3d const & length() const
Box length.
LeesEdwardsBC const & lees_edwards_bc() const
BoxGeometry(BoxGeometry const &rhs)
constexpr bool periodic(unsigned coord) const
Check periodicity in direction.
double volume() const
Box volume.
BoxType type() const
auto image_shift(Utils::Vector3i const &image_box) const
Calculate image box shift vector.
Utils::Vector3d const & length_half() const
Half box length.
Utils::Vector3d const & length_inv() const
Inverse box length.
void set_periodic(unsigned coord, bool val)
Set periodicity for direction.
void set_length(Utils::Vector3d const &box_l)
Set box side lengths.
auto folded_image_box(Utils::Vector3d const &pos, Utils::Vector3i const &image_box) const
Calculate image box of coordinates folded to primary simulation box.
void set_lees_edwards_bc(LeesEdwardsBC bc)
void fold_position(Utils::Vector3d &pos, Utils::Vector3i &image_box) const
Fold coordinates to primary simulation box in-place.
Utils::Vector3d velocity_difference(Utils::Vector3d const &x, Utils::Vector3d const &y, Utils::Vector3d const &u, Utils::Vector3d const &v) const
Calculate the velocity difference including the Lees-Edwards velocity.
void set_type(BoxType type)
ESPRESSO_ATTR_ALWAYS_INLINE Utils::Vector3< T > get_mi_vector(T const &a0, T const &a1, T const &a2, T const &b0, T const &b1, T const &b2) const
Get the minimum-image vector between two coordinates.
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value) noexcept
Create a vector that has all entries set to the same value.
Definition Vector.hpp:131
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
auto periodic_fold(std::floating_point auto x, std::integral auto i, std::floating_point auto l)
Fold value into primary interval.
T product(Vector< T, N > const &v)
Definition Vector.hpp:372
unsigned int shear_plane_normal
Utils::Vector3d distance(Utils::Vector3d const &d, Utils::Vector3d const &l, Utils::Vector3d const &, Utils::Vector3d const &l_inv, std::bitset< 3 > const periodic) const