Mallard 0.8.0
Unstructured, GPU accelerated, high-order finite volume CFD solver
Mallard website
Loading...
Searching...
No Matches
gradient.h
Go to the documentation of this file.
1
12#ifndef GRADIENT_H
13#define GRADIENT_H
14
15#include <Kokkos_Core.hpp>
16
17#include "common.h"
18#include "boundary.h"
19#include "mesh.h"
20
25struct LSQSystem {
26 rtype M[N_DIM * (N_DIM + 1) / 2] = {};
28
30 void add(const rtype * dx, const rtype * W_i, const rtype * W_j) {
31 const rtype w = 1.0_r / dot<N_DIM>(dx, dx);
32 if constexpr (N_DIM == 2) {
33 M[0] += w * dx[0] * dx[0];
34 M[1] += w * dx[0] * dx[1];
35 M[2] += w * dx[1] * dx[1];
37 const rtype dW = W_j[i] - W_i[i];
38 b[i][0] += w * dx[0] * dW;
39 b[i][1] += w * dx[1] * dW;
40 }
41 } else {
42 uint8_t k = 0;
43 for (uint8_t r = 0; r < N_DIM; r++) {
44 for (uint8_t c = r; c < N_DIM; c++) M[k++] += w * dx[r] * dx[c];
45 }
47 const rtype dW = W_j[i] - W_i[i];
48 for (uint8_t d = 0; d < N_DIM; d++) b[i][d] += w * dx[d] * dW;
49 }
50 }
51 }
52
58 if constexpr (N_DIM == 2) {
59 const rtype inv_det = 1.0_r / (M[0] * M[2] - M[1] * M[1]);
61 g[i][0] = inv_det * ( M[2] * b[i][0] - M[1] * b[i][1]);
62 g[i][1] = inv_det * (-M[1] * b[i][0] + M[0] * b[i][1]);
63 }
64 } else {
65 const rtype A[9] = {M[0], M[1], M[2],
66 M[1], M[3], M[4],
67 M[2], M[4], M[5]};
68 rtype A_inv[9];
71 gemv<3>(A_inv, b[i], g[i]);
72 }
73 }
74 }
75};
76
86 Kokkos::View<uint32_t *> offsets_faces_of_cell;
87 Kokkos::View<uint32_t *> faces_of_cell;
88 Kokkos::View<int32_t *[2]> cells_of_face;
89 Kokkos::View<rtype *[N_DIM]> cell_coords;
90 Kokkos::View<rtype *[N_DIM]> face_coords;
91 Kokkos::View<rtype *[N_DIM]> face_normals;
92 Kokkos::View<rtype *[N_DIM]> shifts;
93 Kokkos::View<uint8_t *> face_shift;
95 Kokkos::View<rtype *[N_CONSERVATIVE]> W;
96 Kokkos::View<rtype *[N_CONSERVATIVE][N_DIM]> gradients;
97
106 bool one_sided(const uint32_t i_face) const {
107 return cells_of_face(i_face, 1) < 0 && boundaries.bcs(boundaries.face_bc(i_face)).is_characteristic();
108 }
109
115 const rtype * W_i, rtype * dx, rtype * W_j) const {
116 const int32_t c0 = cells_of_face(i_face, 0);
117 const int32_t c1 = cells_of_face(i_face, 1);
118 if (c1 >= 0) {
119 // Across a periodic face, cell 1 sits at its centroid plus the shift
120 const uint8_t s = face_shift(i_face);
121 if (c0 == static_cast<int32_t>(i_cell)) {
122 FOR_I_DIM dx[i] = (cell_coords(c1, i) + shifts(s, i)) - cell_coords(i_cell, i);
123 } else {
124 FOR_I_DIM dx[i] = (cell_coords(c0, i) - shifts(s, i)) - cell_coords(i_cell, i);
125 }
126 const int32_t j = (c0 == static_cast<int32_t>(i_cell)) ? c1 : c0;
128 } else {
129 rtype n[N_DIM];
132 unit<N_DIM>(n_vec, n);
133 rtype d = 0.0;
134 FOR_I_DIM d += (face_coords(i_face, i) - cell_coords(i_cell, i)) * n[i];
136 if (bc.type == BoundaryType::DIRICHLET || bc.type == BoundaryType::UPT ||
137 bc.type == BoundaryType::FARFIELD) {
138 // A prescribed state is the value at the face centroid
141 } else {
142 FOR_I_DIM dx[i] = 2.0_r * d * n[i];
143 boundaries.ghost_W_at(i_face, W_i, n, 2.0_r * d, W_j);
144 }
146 // Ghost temperature consistent with the prescribed heat flux into the
147 // fluid: q = kappa dT/dn with n pointing out of the domain
148 const rtype R = boundaries.R;
149 const rtype T_i = W_i[N_DIM + 1] / (W_i[0] * R);
151 const rtype T_g = Kokkos::fmax(T_i + 2.0_r * d * bc.data[N_DIM + 1] / kappa, 0.1_r * T_i);
152 W_j[0] = W_i[N_DIM + 1] / (R * T_g);
153 }
154 }
155 }
156
158 void operator()(const uint32_t i_cell) const {
165 lsq.add(dx, W_i, W_j);
166 }
168 lsq.solve(g);
169 FOR_I_CONSERVATIVE for (uint8_t d = 0; d < N_DIM; d++) gradients(i_cell, i, d) = g[i][d];
170 }
171};
172
178template <uint8_t N, typename T>
180bool cholesky(const T A[N][N], T L[N][N]) {
181 for (uint8_t p = 0; p < N; p++) {
182 for (uint8_t q = 0; q <= p; q++) {
183 T s = A[q][p];
184 for (uint8_t k = 0; k < q; k++) s -= L[p][k] * L[q][k];
185 if (q < p) {
186 L[p][q] = s / L[q][q];
187 } else if (s > T(1.0e-10) * A[p][p]) {
188 L[p][p] = Kokkos::sqrt(s);
189 } else {
190 return false;
191 }
192 }
193 }
194 return true;
195}
196
200template <uint8_t N, typename T>
202void cholesky_solve(const T L[N][N], T * x) {
203 for (uint8_t p = 0; p < N; p++) {
204 for (uint8_t k = 0; k < p; k++) x[p] -= L[p][k] * x[k];
205 x[p] /= L[p][p];
206 }
207 for (int p = N - 1; p >= 0; p--) {
208 for (int k = p + 1; k < N; k++) x[p] -= L[k][p] * x[k];
209 x[p] /= L[p][p];
210 }
211}
212
218 Kokkos::View<rtype *[N_DIM]> cells;
219 Kokkos::View<rtype *[N_DIM]> faces;
220};
221
235 Kokkos::View<uint32_t *> offsets_cells_of_cell;
236 Kokkos::View<uint32_t *> cells_of_cell;
237 Kokkos::View<uint8_t *> cells_of_cell_shift;
239 bool quadratic = true;
240 // Axisymmetric runs: r-weighted second moments of the cells (Mesh::cell_covariance),
241 // so that the quadratic fits the cells' averages rather than point values
242 Kokkos::View<rtype *[3]> covariance;
243
244 static constexpr uint8_t NB = N_DIM + N_DIM * (N_DIM + 1) / 2; // Linear and quadratic monomials
245
250 template <typename F>
252 void for_each_point(const uint32_t i_cell, F && f) const {
254 rtype dx[N_DIM];
255 const uint8_t s = cells_of_cell_shift(k);
257 f(dx, false, k);
258 }
259 // The ghost positions do not depend on the states
261 FOR_I_CONSERVATIVE W_i[i] = 1.0;
264 if (faces.cells_of_face(i_face, 1) >= 0 || faces.one_sided(i_face)) continue;
265 rtype dx[N_DIM];
267 f(dx, true, k);
268 }
269 }
270
276 void compute_weights(const uint32_t i_cell) const {
277 double A[NB][NB] = {}, M[N_DIM][N_DIM] = {};
278 double scale = 0.0; // Inverse length that keeps the monomials of order one
279 uint16_t n_points = 0;
280 // The mean of (x - x_i)_a (x - x_i)_b over neighbor point k, minus that over cell i
281 auto moment_offset = [&](bool is_face, uint32_t k, uint8_t m) {
282 if constexpr (N_DIM == 2) {
283 if (covariance.extent(0) == 0) return 0.0;
284 const double C_i = double(covariance(i_cell, m));
285 if (!is_face) return double(covariance(cells_of_cell(k), m)) - C_i;
286 const uint32_t f = faces.faces_of_cell(k);
288 // A prescribed state is a point value at the face; other ghosts mirror cell i
289 if (type == BoundaryType::DIRICHLET || type == BoundaryType::UPT || type == BoundaryType::FARFIELD) {
290 return -C_i;
291 }
292 double n[2] = {double(faces.face_normals(f, 0)), double(faces.face_normals(f, 1))};
293 const double len = Kokkos::sqrt(n[0] * n[0] + n[1] * n[1]);
294 n[0] /= len;
295 n[1] /= len;
296 const double R[2][2] = {{1.0 - 2.0 * n[0] * n[0], -2.0 * n[0] * n[1]},
297 {-2.0 * n[0] * n[1], 1.0 - 2.0 * n[1] * n[1]}};
298 const double C[2][2] = {{C_i, double(covariance(i_cell, 1))},
300 const uint8_t a = (m == 2) ? 1 : 0, b = (m == 0) ? 0 : 1;
301 double mirrored = 0.0;
302 for (uint8_t p = 0; p < 2; p++) {
303 for (uint8_t q = 0; q < 2; q++) mirrored += R[a][p] * C[p][q] * R[b][q];
304 }
305 return mirrored - double(covariance(i_cell, m));
306 } else {
307 (void)is_face;
308 (void)k;
309 (void)m;
310 return 0.0;
311 }
312 };
313 auto monomials = [&](const double * dx, double * phi, bool is_face, uint32_t k) {
314 FOR_I_DIM phi[i] = dx[i] * scale;
315 uint8_t m = N_DIM;
316 for (uint8_t r = 0; r < N_DIM; r++) {
317 for (uint8_t c = r; c < N_DIM; c++) {
318 phi[m] = phi[r] * phi[c];
319 if (covariance.extent(0) > 0) phi[m] += moment_offset(is_face, k, m - N_DIM) * scale * scale;
320 m++;
321 }
322 }
323 };
324 auto widen = [](const rtype * dx_r, double * dx) {
325 FOR_I_DIM dx[i] = double(dx_r[i]);
326 double d2 = 0.0;
327 FOR_I_DIM d2 += dx[i] * dx[i];
328 return 1.0 / d2;
329 };
330 for_each_point(i_cell, [&](const rtype * dx_r, bool is_face, uint32_t k) {
331 double dx[N_DIM];
332 const double w = widen(dx_r, dx);
333 if (n_points++ == 0) scale = Kokkos::sqrt(w);
334 double phi[NB];
335 monomials(dx, phi, is_face, k);
336 for (uint8_t p = 0; p < NB; p++) {
337 for (uint8_t q = p; q < NB; q++) A[p][q] += w * phi[p] * phi[q];
338 }
339 for (uint8_t p = 0; p < N_DIM; p++) {
340 for (uint8_t q = p; q < N_DIM; q++) M[p][q] += w * dx[p] * dx[q];
341 }
342 });
343 double L[NB][NB], L_lin[N_DIM][N_DIM];
344 const bool fit_quadratic = quadratic && n_points >= NB && cholesky<NB>(A, L);
346 for_each_point(i_cell, [&](const rtype * dx_r, bool is_face, uint32_t k) {
347 double dx[N_DIM];
348 const double w = widen(dx_r, dx);
349 double c[N_DIM];
350 if (fit_quadratic) {
351 double phi[NB];
352 monomials(dx, phi, is_face, k);
354 FOR_I_DIM c[i] = w * scale * phi[i];
355 } else {
356 FOR_I_DIM c[i] = w * dx[i];
358 }
359 FOR_I_DIM (is_face ? weights.faces(k, i) : weights.cells(k, i)) = static_cast<rtype>(c[i]);
360 });
361 }
362
364 void operator()(const uint32_t i_cell) const {
369 const uint32_t j = cells_of_cell(k);
371 const rtype dW = faces.W(j, i) - W_i[i];
372 for (uint8_t d = 0; d < N_DIM; d++) g[i][d] += weights.cells(k, d) * dW;
373 }
374 }
377 if (faces.cells_of_face(i_face, 1) >= 0 || faces.one_sided(i_face)) continue;
381 const rtype dW = W_j[i] - W_i[i];
382 for (uint8_t d = 0; d < N_DIM; d++) g[i][d] += weights.faces(k, d) * dW;
383 }
384 }
385 FOR_I_CONSERVATIVE for (uint8_t d = 0; d < N_DIM; d++) faces.gradients(i_cell, i, d) = g[i][d];
386 }
387};
388
392inline LSQGradientFunctor make_gradient(const Mesh & mesh, const BoundaryData & boundaries,
393 Kokkos::View<rtype *[N_CONSERVATIVE]> W,
394 Kokkos::View<rtype *[N_CONSERVATIVE][N_DIM]> gradients) {
396 mesh.face_coords, mesh.face_normals, mesh.shifts, mesh.face_shift,
397 boundaries, W, gradients};
398}
399
406 bool quadratic = true) {
408 {Kokkos::View<rtype *[N_DIM]>("vertex_gradient_weights_cells", mesh.cells_of_cell.extent(0)),
409 Kokkos::View<rtype *[N_DIM]>("vertex_gradient_weights_faces", faces.faces_of_cell.extent(0))},
410 quadratic, quadratic ? mesh.cell_covariance : Kokkos::View<rtype *[3]>()};
411 Kokkos::parallel_for("vertex_gradient_weights", mesh.n_cells,
412 KOKKOS_LAMBDA(const uint32_t i_cell) { functor.compute_weights(i_cell); });
413 return functor;
414}
415
416#endif // GRADIENT_H
Boundary conditions.
BoundaryType
Definition boundary.h:25
Definition mesh.h:111
Kokkos::View< uint8_t * > cells_of_cell_shift
Definition mesh.h:469
Kokkos::View< uint32_t * > offsets_cells_of_cell
Definition mesh.h:463
Kokkos::View< rtype *[N_DIM]> cell_coords
Definition mesh.h:450
Kokkos::View< uint8_t * > face_shift
Definition mesh.h:468
Kokkos::View< rtype *[N_DIM]> face_normals
Definition mesh.h:453
Kokkos::View< uint32_t * > cells_of_cell
Definition mesh.h:462
Kokkos::View< uint32_t * > offsets_faces_of_cell
Definition mesh.h:458
uint32_t n_cells
Definition mesh.h:418
Kokkos::View< uint32_t * > faces_of_cell
Definition mesh.h:457
Kokkos::View< rtype *[3]> cell_covariance
Definition mesh.h:447
Kokkos::View< int32_t *[2]> cells_of_face
Definition mesh.h:461
Kokkos::View< rtype *[N_DIM]> shifts
Definition mesh.h:467
Kokkos::View< rtype *[N_DIM]> face_coords
Definition mesh.h:454
Common header file.
KOKKOS_INLINE_FUNCTION void gemv< 3 >(const rtype *A, const rtype *x, rtype *y)
Definition common_math.h:245
KOKKOS_INLINE_FUNCTION rtype dot(const rtype *a, const rtype *b)
Compute the dot product of two arrays.
Definition common_math.h:32
KOKKOS_INLINE_FUNCTION void invert_matrix< 3 >(const rtype *A, rtype *A_inv)
Definition common_math.h:191
float rtype
Definition common_typedef.h:39
#define N_DIM
Definition common_typedef.h:28
#define FOR_I_CONSERVATIVE
Definition common_typedef.h:33
#define N_CONSERVATIVE
Definition common_typedef.h:29
#define FOR_I_DIM
Definition common_typedef.h:32
KOKKOS_INLINE_FUNCTION bool cholesky(const T A[N][N], T L[N][N])
Cholesky factorization A = L L^T of a symmetric positive definite matrix given by its upper triangle....
Definition gradient.h:180
LSQVertexGradientFunctor make_vertex_gradient(const LSQGradientFunctor &faces, const Mesh &mesh, bool quadratic=true)
LSQVertexGradientFunctor over the given gradient functor's mesh, boundaries, states and gradients,...
Definition gradient.h:405
KOKKOS_INLINE_FUNCTION void cholesky_solve(const T L[N][N], T *x)
Solve L L^T x = b in place.
Definition gradient.h:202
LSQGradientFunctor make_gradient(const Mesh &mesh, const BoundaryData &boundaries, Kokkos::View< rtype *[N_CONSERVATIVE]> W, Kokkos::View< rtype *[N_CONSERVATIVE][N_DIM]> gradients)
LSQGradientFunctor of the states W into gradients over a mesh.
Definition gradient.h:392
Mesh class declaration.
Device-copyable boundary condition.
Definition boundary.h:97
Device-side lookup from faces to boundary conditions.
Definition boundary.h:229
Kokkos::View< int32_t * > face_bc
Definition boundary.h:230
bool viscous
Definition boundary.h:252
KOKKOS_INLINE_FUNCTION void ghost_W(const uint32_t i_face, const rtype *W_i, const rtype *n, rtype *W_g) const
Ghost state for boundary face i_face.
Definition boundary.h:471
KOKKOS_INLINE_FUNCTION void ghost_W_at(const uint32_t i_face, const rtype *W_i, const rtype *n, const rtype dist, rtype *W_g) const
Ghost state for a point a distance dist outside boundary face i_face (the mirror image of an interior...
Definition boundary.h:458
Kokkos::View< BoundaryCondition * > bcs
Definition boundary.h:249
Euler gas
Definition boundary.h:253
rtype R
Definition boundary.h:251
KOKKOS_INLINE_FUNCTION rtype conductivity(const rtype mu) const
Thermal conductivity for dynamic viscosity mu.
Definition physics.h:108
KOKKOS_INLINE_FUNCTION rtype viscosity(const rtype T) const
Dynamic viscosity at temperature T.
Definition physics.h:91
Weighted least-squares gradient of W = [rho, u, p] over face neighbors, with boundary ghost states pl...
Definition gradient.h:85
KOKKOS_INLINE_FUNCTION void neighbor(const uint32_t i_cell, const uint32_t i_face, const rtype *W_i, rtype *dx, rtype *W_j) const
Offset to and state of the neighbor across face i_face.
Definition gradient.h:114
Kokkos::View< uint32_t * > offsets_faces_of_cell
Definition gradient.h:86
Kokkos::View< uint32_t * > faces_of_cell
Definition gradient.h:87
BoundaryData boundaries
Definition gradient.h:94
Kokkos::View< int32_t *[2]> cells_of_face
Definition gradient.h:88
Kokkos::View< rtype *[N_DIM]> face_coords
Definition gradient.h:90
Kokkos::View< rtype *[N_DIM]> face_normals
Definition gradient.h:91
Kokkos::View< rtype *[N_CONSERVATIVE][N_DIM]> gradients
Definition gradient.h:96
Kokkos::View< rtype *[N_DIM]> cell_coords
Definition gradient.h:89
Kokkos::View< rtype *[N_CONSERVATIVE]> W
Definition gradient.h:95
KOKKOS_INLINE_FUNCTION void operator()(const uint32_t i_cell) const
Definition gradient.h:158
Kokkos::View< uint8_t * > face_shift
Definition gradient.h:93
KOKKOS_INLINE_FUNCTION bool one_sided(const uint32_t i_face) const
Whether vertex-neighbor gradients leave out the ghost of face i_face: the zero-gradient ghost of a ch...
Definition gradient.h:106
Kokkos::View< rtype *[N_DIM]> shifts
Definition gradient.h:92
Inverse-distance-squared weighted least-squares normal equations M g = b, with M stored as its upper ...
Definition gradient.h:25
KOKKOS_INLINE_FUNCTION void add(const rtype *dx, const rtype *W_i, const rtype *W_j)
Definition gradient.h:30
rtype M[N_DIM *(N_DIM+1)/2]
Definition gradient.h:26
KOKKOS_INLINE_FUNCTION void solve(rtype g[N_CONSERVATIVE][N_DIM]) const
Solve for the gradient of every variable: g[i][d] = d W_i / d x_d.
Definition gradient.h:57
rtype b[N_CONSERVATIVE][N_DIM]
Definition gradient.h:27
Gradient over all vertex neighbors plus the boundary ghost states of the cell's own boundary faces,...
Definition gradient.h:233
Kokkos::View< uint32_t * > offsets_cells_of_cell
Definition gradient.h:235
static constexpr uint8_t NB
Definition gradient.h:244
bool quadratic
Definition gradient.h:239
KOKKOS_INLINE_FUNCTION void for_each_point(const uint32_t i_cell, F &&f) const
Offset of every stencil point of cell i_cell, passed to f(offset, is_face, index into cells_of_cell o...
Definition gradient.h:252
Kokkos::View< uint32_t * > cells_of_cell
Definition gradient.h:236
KOKKOS_INLINE_FUNCTION void operator()(const uint32_t i_cell) const
Definition gradient.h:364
LSQGradientFunctor faces
Definition gradient.h:234
KOKKOS_INLINE_FUNCTION void compute_weights(const uint32_t i_cell) const
Compute the weights of cell i_cell, in double: the normal equations of the quadratic fit are too ill ...
Definition gradient.h:276
VertexGradientWeights weights
Definition gradient.h:238
Kokkos::View< rtype *[3]> covariance
Definition gradient.h:242
Kokkos::View< uint8_t * > cells_of_cell_shift
Definition gradient.h:237
Weights of LSQVertexGradientFunctor, aligned with cells_of_cell and faces_of_cell (zero for interior ...
Definition gradient.h:217
Kokkos::View< rtype *[N_DIM]> cells
Definition gradient.h:218
Kokkos::View< rtype *[N_DIM]> faces
Definition gradient.h:219
CellSetup< ExecSpace > c
Definition teno_setup.cpp:1810
uint8_t r
Definition teno_setup.cpp:687
Geometry< Space > g
Definition teno_setup.cpp:678
SlotArray< double, Space > A
Definition teno_setup.cpp:478
Lane< rtype > scale
Definition teno_setup.cpp:531