core 1.5.0
Shared MPI block decomposition, asynchronous ghost-layer exchange, SDF geometry, load balancing (header-only C++20)
Loading...
Searching...
No Matches
domain.hpp
Go to the documentation of this file.
1// core — the physical domain: the box a method solves in, and the uniform grid that resolves it.
2//
3// This is the one place in the suite that says what "the domain" is, so that flow, pnm, the AMR
4// octree, voro and the coupling drivers all describe the same world the same way. It implements
5// the `Domain` concept of suite/docs/INTERFACES.md §1 (`dim()`, `length()`, `origin()`,
6// `periodic(axis)`), and `UniformGrid` adds the Eulerian `resolution()`.
7//
8// Units are the caller's, and consistent (suite/docs/CONVENTIONS.md §7): the domain carries no unit
9// system and no dimension checking. Spacing is derived, never given:
10//
11// spacing[a] = length[a] / cells[a]
12//
13// Per-axis spacings may differ (anisotropic cells); the consumers that only support isotropic cells
14// today assert `isIsotropic()` themselves rather than this header forbidding it.
15//
16// Conventions honoured here: axis order is x-fastest, cell (i,j,k) spans
17// [origin + i*h, origin + (i+1)*h) per axis, so its centre is at origin + (i+0.5)*h. A face centre
18// on axis `a` at index i is at origin[a] + i*h[a] in that axis and cell-centred in the others —
19// the staggered MAC convention flow uses.
20//
21// Header-only, C++17-clean (so it can be pulled into device translation units).
22#ifndef PECLET_CORE_DOMAIN_HPP
23#define PECLET_CORE_DOMAIN_HPP
24
25#include <cmath>
26#include <cstddef>
27
29
30namespace peclet::core {
31
33template <int Dim = 3>
34struct Box {
37 std::array<bool, Dim> periodic{};
38
39 static constexpr int dim() { return Dim; }
40
42 Vec<Dim> upper() const {
43 Vec<Dim> u{};
44 for (int a = 0; a < Dim; ++a)
45 u[a] = origin[a] + length[a];
46 return u;
47 }
48
49 Vec<Dim> centre() const {
50 Vec<Dim> c{};
51 for (int a = 0; a < Dim; ++a)
52 c[a] = origin[a] + 0.5 * length[a];
53 return c;
54 }
55
56 Real volume() const {
57 Real v = 1.0;
58 for (int a = 0; a < Dim; ++a)
59 v *= length[a];
60 return v;
61 }
62
64 bool contains(const Vec<Dim>& p) const {
65 for (int a = 0; a < Dim; ++a) {
66 if (!(p[a] >= origin[a] && p[a] < origin[a] + length[a]))
67 return false;
68 }
69 return true;
70 }
71
73 Vec<Dim> wrap(const Vec<Dim>& p) const {
74 Vec<Dim> q = p;
75 for (int a = 0; a < Dim; ++a) {
76 if (!periodic[a] || !(length[a] > 0.0))
77 continue;
78 Real t = (q[a] - origin[a]) / length[a];
79 t -= std::floor(t);
80 // std::floor can return t == 1 for tiny negative inputs after rounding; clamp to [0,1).
81 if (!(t < 1.0))
82 t = 0.0;
83 q[a] = origin[a] + t * length[a];
84 }
85 return q;
86 }
87
89 Vec<Dim> minImage(const Vec<Dim>& a_, const Vec<Dim>& b) const {
90 Vec<Dim> d{};
91 for (int a = 0; a < Dim; ++a) {
92 d[a] = b[a] - a_[a];
93 if (!periodic[a] || !(length[a] > 0.0))
94 continue;
95 d[a] -= length[a] * std::round(d[a] / length[a]);
96 }
97 return d;
98 }
99};
100
106template <int Dim = 3>
110
111 UniformGrid() = default;
112 UniformGrid(const IVec<Dim>& c, const Box<Dim>& b) : box(b), cells(c) {}
113
115 static UniformGrid cellUnits(const IVec<Dim>& c, const std::array<bool, Dim>& per = {}) {
116 Box<Dim> b{};
117 for (int a = 0; a < Dim; ++a) {
118 b.origin[a] = 0.0;
119 b.length[a] = static_cast<Real>(c[a]);
120 }
121 b.periodic = per;
122 return UniformGrid(c, b);
123 }
124
125 // --- Domain concept ---
126 static constexpr int dim() { return Dim; }
127 const Vec<Dim>& length() const { return box.length; }
128 const Vec<Dim>& origin() const { return box.origin; }
129 bool periodic(int axis) const { return box.periodic[axis]; }
130 const IVec<Dim>& resolution() const { return cells; }
131
135 Vec<Dim> h{};
136 for (int a = 0; a < Dim; ++a)
137 h[a] = (cells[a] > 0) ? box.length[a] / static_cast<Real>(cells[a]) : 0.0;
138 return h;
139 }
140
142 Real minSpacing() const {
143 const Vec<Dim> h = spacing();
144 Real m = h[0];
145 for (int a = 1; a < Dim; ++a)
146 m = (h[a] < m) ? h[a] : m;
147 return m;
148 }
149
151 bool isIsotropic(Real tol = 1e-12) const {
152 const Vec<Dim> h = spacing();
153 for (int a = 1; a < Dim; ++a) {
154 const Real d = std::fabs(h[a] - h[0]);
155 const Real s = std::fabs(h[0]) > 0.0 ? std::fabs(h[0]) : 1.0;
156 if (d > tol * s)
157 return false;
158 }
159 return true;
160 }
161
162 Index numCells() const {
163 Index n = 1;
164 for (int a = 0; a < Dim; ++a)
165 n *= cells[a];
166 return n;
167 }
168
169 Real cellVolume() const {
170 const Vec<Dim> h = spacing();
171 Real v = 1.0;
172 for (int a = 0; a < Dim; ++a)
173 v *= h[a];
174 return v;
175 }
176
178 Vec<Dim> cellCentre(const IVec<Dim>& idx) const {
179 const Vec<Dim> h = spacing();
180 Vec<Dim> p{};
181 for (int a = 0; a < Dim; ++a)
182 p[a] = box.origin[a] + (static_cast<Real>(idx[a]) + 0.5) * h[a];
183 return p;
184 }
185
188 Vec<Dim> faceCentre(int axis, const IVec<Dim>& idx) const {
189 const Vec<Dim> h = spacing();
190 Vec<Dim> p{};
191 for (int a = 0; a < Dim; ++a) {
192 const Real off = (a == axis) ? 0.0 : 0.5;
193 p[a] = box.origin[a] + (static_cast<Real>(idx[a]) + off) * h[a];
194 }
195 return p;
196 }
197
199 Vec<Dim> nodePosition(const IVec<Dim>& idx) const {
200 const Vec<Dim> h = spacing();
201 Vec<Dim> p{};
202 for (int a = 0; a < Dim; ++a)
203 p[a] = box.origin[a] + static_cast<Real>(idx[a]) * h[a];
204 return p;
205 }
206
209 Vec<Dim> indexOf(const Vec<Dim>& p) const {
210 const Vec<Dim> h = spacing();
211 Vec<Dim> xi{};
212 for (int a = 0; a < Dim; ++a)
213 xi[a] = (h[a] > 0.0) ? (p[a] - box.origin[a]) / h[a] : 0.0;
214 return xi;
215 }
216
219 const Vec<Dim> h = spacing();
220 Vec<Dim> p{};
221 for (int a = 0; a < Dim; ++a)
222 p[a] = box.origin[a] + xi[a] * h[a];
223 return p;
224 }
225
227 IVec<Dim> cellOf(const Vec<Dim>& p) const {
228 const Vec<Dim> xi = indexOf(p);
229 IVec<Dim> idx{};
230 for (int a = 0; a < Dim; ++a)
231 idx[a] = static_cast<Index>(std::floor(xi[a]));
232 return idx;
233 }
234
235 bool contains(const Vec<Dim>& p) const { return box.contains(p); }
236 Vec<Dim> wrap(const Vec<Dim>& p) const { return box.wrap(p); }
237 Vec<Dim> minImage(const Vec<Dim>& a, const Vec<Dim>& b) const { return box.minImage(a, b); }
238};
239
240} // namespace peclet::core
241
242#endif // PECLET_CORE_DOMAIN_HPP
Kokkos::View< T *, MemSpace > View
1D device array.
Definition view.hpp:26
double Real
Default host floating type. Device kernels may use float; conversions happen at the boundary.
Definition types.hpp:18
std::int64_t Index
Signed index type for grids and particles (supersedes block_decomposer's long int IndxT).
Definition types.hpp:15
A physical, axis-aligned box with per-axis periodicity. Continuous — no cells.
Definition domain.hpp:34
Vec< Dim > minImage(const Vec< Dim > &a_, const Vec< Dim > &b) const
Minimum-image separation b - a, shortened across the periodic axes.
Definition domain.hpp:89
Real volume() const
Definition domain.hpp:56
Vec< Dim > upper() const
Upper corner: origin + length.
Definition domain.hpp:42
Vec< Dim > wrap(const Vec< Dim > &p) const
Fold a point into the box along the periodic axes; non-periodic axes are left untouched.
Definition domain.hpp:73
static constexpr int dim()
Definition domain.hpp:39
Vec< Dim > origin
lower corner
Definition domain.hpp:35
std::array< bool, Dim > periodic
per-axis periodicity
Definition domain.hpp:37
Vec< Dim > centre() const
Definition domain.hpp:49
bool contains(const Vec< Dim > &p) const
Is the point inside [origin, origin+length) on every axis?
Definition domain.hpp:64
Vec< Dim > length
extent per axis (> 0)
Definition domain.hpp:36
A box resolved by a regular cell grid.
Definition domain.hpp:107
Real cellVolume() const
Definition domain.hpp:169
bool periodic(int axis) const
Definition domain.hpp:129
IVec< Dim > cellOf(const Vec< Dim > &p) const
Index of the cell containing p (floor of the continuous index). No bounds check.
Definition domain.hpp:227
Vec< Dim > physicalOf(const Vec< Dim > &xi) const
Physical point of a continuous index coordinate: p = origin + xi * h. Inverse of indexOf.
Definition domain.hpp:218
bool isIsotropic(Real tol=1e-12) const
True when every axis has the same cell size to within tol relative.
Definition domain.hpp:151
static UniformGrid cellUnits(const IVec< Dim > &c, const std::array< bool, Dim > &per={})
The historical cell-unit grid: extent == cells, origin 0, spacing exactly 1.
Definition domain.hpp:115
Vec< Dim > nodePosition(const IVec< Dim > &idx) const
Physical position of grid node idx (cell corner): origin + idx * h.
Definition domain.hpp:199
static constexpr int dim()
Definition domain.hpp:126
Real minSpacing() const
The smallest cell size — the reference length the solvers non-dimensionalise with.
Definition domain.hpp:142
const Vec< Dim > & length() const
Definition domain.hpp:127
UniformGrid(const IVec< Dim > &c, const Box< Dim > &b)
Definition domain.hpp:112
Vec< Dim > cellCentre(const IVec< Dim > &idx) const
Physical centre of cell idx: origin + (idx + 1/2) * h.
Definition domain.hpp:178
Index numCells() const
Definition domain.hpp:162
Vec< Dim > faceCentre(int axis, const IVec< Dim > &idx) const
Physical centre of the axis-normal face at index idx (MAC staggering): the face coordinate is on the ...
Definition domain.hpp:188
bool contains(const Vec< Dim > &p) const
Definition domain.hpp:235
Vec< Dim > indexOf(const Vec< Dim > &p) const
Continuous index coordinate of a physical point: xi = (p - origin) / h.
Definition domain.hpp:209
Vec< Dim > wrap(const Vec< Dim > &p) const
Definition domain.hpp:236
const Vec< Dim > & origin() const
Definition domain.hpp:128
const IVec< Dim > & resolution() const
Definition domain.hpp:130
Vec< Dim > minImage(const Vec< Dim > &a, const Vec< Dim > &b) const
Definition domain.hpp:237
Vec< Dim > spacing() const
Cell size per axis: length / cells.
Definition domain.hpp:134