Mallard 0.8.0
Unstructured, GPU accelerated, high-order finite volume CFD solver
Mallard website
Loading...
Searching...
No Matches
boundary.h
Go to the documentation of this file.
1
12#ifndef BOUNDARY_H
13#define BOUNDARY_H
14
15#include <string>
16#include <unordered_map>
17#include <vector>
18
19#include <Kokkos_Core.hpp>
20#include <toml.hpp>
21
22#include "common.h"
23#include "physics.h"
24
40
41static const std::unordered_map<std::string, BoundaryType> BOUNDARY_TYPES = {
42 {"symmetry", BoundaryType::SYMMETRY},
43 {"extrapolation", BoundaryType::EXTRAPOLATION},
44 {"wall_adiabatic", BoundaryType::WALL_ADIABATIC},
45 {"wall_isothermal", BoundaryType::WALL_ISOTHERMAL},
46 {"wall_heat_flux", BoundaryType::WALL_HEAT_FLUX},
47 {"upt", BoundaryType::UPT},
48 {"p_out", BoundaryType::P_OUT},
49 {"p_out_average", BoundaryType::P_OUT_AVERAGE},
50 {"dirichlet", BoundaryType::DIRICHLET},
51 {"farfield", BoundaryType::FARFIELD},
52 {"nscbc_outlet", BoundaryType::NSCBC_OUTLET},
53 {"nscbc_inlet", BoundaryType::NSCBC_INLET}
54};
55
56static const std::unordered_map<BoundaryType, std::string> BOUNDARY_NAMES = {
57 {BoundaryType::SYMMETRY, "symmetry"},
58 {BoundaryType::EXTRAPOLATION, "extrapolation"},
59 {BoundaryType::WALL_ADIABATIC, "wall_adiabatic"},
60 {BoundaryType::WALL_ISOTHERMAL, "wall_isothermal"},
61 {BoundaryType::WALL_HEAT_FLUX, "wall_heat_flux"},
62 {BoundaryType::UPT, "upt"},
63 {BoundaryType::P_OUT, "p_out"},
64 {BoundaryType::P_OUT_AVERAGE, "p_out_average"},
65 {BoundaryType::DIRICHLET, "dirichlet"},
66 {BoundaryType::FARFIELD, "farfield"},
67 {BoundaryType::NSCBC_OUTLET, "nscbc_outlet"},
68 {BoundaryType::NSCBC_INLET, "nscbc_inlet"},
69 {BoundaryType::PARTITION, "partition"}
70};
71
99 enum Relax : uint8_t {
100 ACOUSTIC = 0, // sigma / L of the incoming acoustic wave
101 TEMPERATURE, // NSCBC_INLET: sigma_T / L, negative to impose T exactly
102 TANGENTIAL, // NSCBC_INLET: sigma_t / L, negative to impose the tangential velocity exactly
103 BETA, // transverse relaxation in [0, 1], negative for the local Mach number
104 T_TARGET, // NSCBC_INLET: target temperature
105 N_RELAX
106 };
107
109 rtype data[N_DIM + 2] = {};
111
112 KOKKOS_INLINE_FUNCTION
117
118 KOKKOS_INLINE_FUNCTION
122
124 KOKKOS_INLINE_FUNCTION
125 bool is_transmissive() const {
127 }
128
132 static BoundaryCondition from_input(const toml::value & input, const Euler & physics);
133
143 KOKKOS_INLINE_FUNCTION
144 void ghost_W(const rtype * W_i, const rtype * n, const rtype gamma, const rtype R,
145 const bool viscous, rtype * W_g) const {
146 constexpr uint8_t E = N_DIM + 1;
147 for (uint8_t i = 0; i < N_DIM + 2; i++) W_g[i] = W_i[i];
148 const rtype u_n = dot<N_DIM>(W_i + 1, n);
149 switch (type) {
154 break;
158 if (viscous) {
159 FOR_I_DIM W_g[1 + i] = 2.0_r * data[1 + i] - W_i[1 + i];
161 const rtype T_i = W_i[E] / (W_i[0] * R);
162 const rtype T_g = Kokkos::fmax(2.0_r * data[0] - T_i, 0.1_r * data[0]);
163 W_g[0] = W_i[E] / (R * T_g);
164 }
165 break;
166 }
167 [[fallthrough]];
169 FOR_I_DIM W_g[1 + i] = W_i[1 + i] - 2.0_r * u_n * n[i];
170 break;
172 for (uint8_t i = 0; i < N_DIM + 2; i++) W_g[i] = data[i];
173 break;
175 // Handled per face by BoundaryData
176 break;
178 // Characteristic far field: the outgoing Riemann invariant comes from
179 // the interior, the incoming one from the free stream, and entropy and
180 // tangential velocity from the upwind side
181 const rtype a_i = Kokkos::sqrt(gamma * W_i[E] / W_i[0]);
182 const rtype a_inf = Kokkos::sqrt(gamma * data[E] / data[0]);
183 const rtype u_n_inf = dot<N_DIM>(data + 1, n);
184 if (Kokkos::fabs(u_n) >= a_i) {
185 if (u_n < 0.0_r) {
186 for (uint8_t i = 0; i < N_DIM + 2; i++) W_g[i] = data[i];
187 }
188 break;
189 }
190 const rtype r_out = u_n + 2.0_r * a_i / (gamma - 1.0_r);
191 const rtype r_in = u_n_inf - 2.0_r * a_inf / (gamma - 1.0_r);
192 const rtype u_n_b = 0.5_r * (r_out + r_in);
193 const rtype a_b = 0.25_r * (gamma - 1.0_r) * (r_out - r_in);
194 const rtype * W_up = (u_n_b < 0.0_r) ? data : W_i;
195 const rtype u_n_up = (u_n_b < 0.0_r) ? u_n_inf : u_n;
196 const rtype entropy = W_up[E] / Kokkos::pow(W_up[0], gamma);
197 W_g[0] = Kokkos::pow(a_b * a_b / (gamma * entropy), 1.0_r / (gamma - 1.0_r));
198 FOR_I_DIM W_g[1 + i] = W_up[1 + i] + (u_n_b - u_n_up) * n[i];
199 W_g[E] = W_g[0] * a_b * a_b / gamma;
200 break;
201 }
202 case BoundaryType::P_OUT: {
203 const rtype a = Kokkos::sqrt(gamma * W_i[E] / W_i[0]);
204 if (u_n < a) {
205 // Subsonic: impose pressure, keep temperature
206 W_g[0] = W_i[0] * data[E] / W_i[E];
207 W_g[E] = data[E];
208 }
209 break;
210 }
212 const rtype a = Kokkos::sqrt(gamma * W_i[E] / W_i[0]);
213 if (u_n < a) {
214 // Subsonic: shift the local pressure so the boundary average
215 // matches the target, keeping temperature
216 const rtype p_g = Kokkos::fmax(W_i[E] + data[0], 1e-3_r * W_i[E]);
217 W_g[0] = W_i[0] * p_g / W_i[E];
218 W_g[E] = p_g;
219 }
220 break;
221 }
222 }
223 }
224};
225
230 Kokkos::View<int32_t *> face_bc; // Index into bcs, -1 for interior faces
231 Kokkos::View<int32_t *> face_image; // Transmissive faces: interior image cell, else -1
232 Kokkos::View<int32_t *> face_image_face; // Face of the image cell matching the translated face, else -1
233 Kokkos::View<uint8_t *> face_image_side; // Side of face_image_face belonging to the image cell
234 Kokkos::View<uint8_t *> face_image_flip; // 2D: whether the image face runs opposite to the boundary face
235 Kokkos::View<uint8_t **> face_image_quad; // 3D: quadrature point of the image face matching each point
236 Kokkos::View<int32_t *> face_state_index; // Dirichlet faces: index into face_state, else -1
237 Kokkos::View<rtype *[N_DIM + 2]> face_state; // Exterior W of Dirichlet faces
238 Kokkos::View<int32_t *> face_char; // Characteristic faces: index into char_*, else -1
239 Kokkos::View<uint32_t *> char_faces; // Characteristic faces
240 Kokkos::View<rtype *> char_depth; // Twice the distance from the boundary cell's centroid to the face
241 Kokkos::View<rtype *[3]> char_transverse; // [u_t . grad p, rho div_t u_t, rho u_t . grad u_n] on the face
242 Kokkos::View<rtype *[2]> char_state; // [p, u_n] of the face, whose p - rho c u_n is the incoming acoustic wave
243 Kokkos::View<rtype *[N_DIM]> char_target; // Inlets: target velocity of the face at the current stage
244 Kokkos::View<rtype *[N_DIM]> char_target_next; // Inlets: target velocity at the end of the step, for d(w-)/dt
245 Kokkos::View<uint32_t *> char_offsets; // CSR of char_neighbors
246 Kokkos::View<uint32_t *> char_neighbors; // Characteristic faces of the same orientation sharing an edge (3D) or node (2D)
247 Kokkos::View<rtype *[N_DIM]> char_neighbor_dx; // Center of each neighbor relative to the face, across periodic seams too
248 Kokkos::View<uint8_t *> char_edge; // Faces sharing a node with a boundary face that is not characteristic (a wall)
249 Kokkos::View<BoundaryCondition *> bcs;
251 rtype R = 1.0;
252 bool viscous = false;
255 // Gas mixtures: per condition, the mass fractions and [gamma, e0] of a
256 // prescribed state (UPT); empty for a single gas
257 Kokkos::View<rtype **, Kokkos::LayoutRight> bc_Y;
258 Kokkos::View<rtype *[2]> bc_thermo;
259
270 template <typename T_W, typename T_F, typename T_FT, typename T_CT>
272 void exterior_mixture(const uint32_t i_face, const uint8_t i_quad, const uint8_t n_quad, const rtype * W_i,
273 const rtype * th_i, const rtype * n, const T_W & W_cells, const T_F & face_solution,
274 const T_FT & face_thermo, const T_CT & cell_thermo, rtype * W_g, rtype * th_g) const {
275 const int32_t i_bc = face_bc(i_face);
276 const BoundaryCondition & bc = bcs(i_bc);
277 const bool characteristic = bc.is_characteristic();
278 // Characteristic faces start from the transmissive state
279 rtype W_e[N_DIM + 2], th_e[2];
280 rtype * W_t = characteristic ? W_e : W_g;
281 rtype * th_t = characteristic ? th_e : th_g;
284 if (image_face >= 0) {
285 uint8_t q;
286 if constexpr (N_DIM == 2) {
287 q = static_cast<uint8_t>(face_image_flip(i_face) ? n_quad - 1 - i_quad : i_quad);
288 } else {
290 }
291 const uint8_t side = face_image_side(i_face);
292 for (uint8_t i = 0; i < N_DIM + 2; i++) W_t[i] = face_solution(image_face, q, side, i);
293 th_t[0] = face_thermo(image_face, q, side, 0);
294 th_t[1] = face_thermo(image_face, q, side, 1);
295 } else if (image >= 0) {
296 for (uint8_t i = 0; i < N_DIM + 2; i++) W_t[i] = W_cells(image, i);
297 th_t[0] = cell_thermo(image, 0);
298 th_t[1] = cell_thermo(image, 1);
299 } else {
300 bc.ghost_W(W_i, n, th_i[0], R, viscous, W_t);
301 if (bc.type == BoundaryType::UPT) {
302 th_t[0] = bc_thermo(i_bc, 0);
303 th_t[1] = bc_thermo(i_bc, 1);
304 } else {
305 th_t[0] = th_i[0];
306 th_t[1] = th_i[1];
307 }
308 }
309 if (!characteristic) return;
313 th_g[0] = bc_thermo(i_bc, 0);
314 th_g[1] = bc_thermo(i_bc, 1);
315 } else {
316 th_g[0] = th_src[0];
317 th_g[1] = th_src[1];
318 }
319 }
320
333 template <typename T_W, typename T_F>
335 void exterior_W(const uint32_t i_face, const uint8_t i_quad, const uint8_t n_quad,
336 const rtype * W_i, const rtype * n, const T_W & W_cells, const T_F & face_solution,
337 rtype * W_g) const {
338 if (bcs(face_bc(i_face)).is_characteristic()) {
339 rtype W_e[N_DIM + 2];
340 transmissive_W(i_face, i_quad, n_quad, W_i, n, W_cells, face_solution, W_e);
342 return;
343 }
344 transmissive_W(i_face, i_quad, n_quad, W_i, n, W_cells, face_solution, W_g);
345 }
346
348 template <typename T_W, typename T_F>
350 void transmissive_W(const uint32_t i_face, const uint8_t i_quad, const uint8_t n_quad,
351 const rtype * W_i, const rtype * n, const T_W & W_cells, const T_F & face_solution,
352 rtype * W_g) const {
355 if (image_face >= 0) {
356 uint8_t q;
357 if constexpr (N_DIM == 2) {
358 q = static_cast<uint8_t>(face_image_flip(i_face) ? n_quad - 1 - i_quad : i_quad);
359 } else {
361 }
362 for (uint8_t i = 0; i < N_DIM + 2; i++) {
363 W_g[i] = face_solution(image_face, q, face_image_side(i_face), i);
364 }
365 } else if (image >= 0) {
366 for (uint8_t i = 0; i < N_DIM + 2; i++) W_g[i] = W_cells(image, i);
367 } else {
368 ghost_W(i_face, W_i, n, W_g);
369 }
370 }
371
374
389 GhostEntropy characteristic_W(const uint32_t i_face, const rtype * W_l, const rtype * W_e, const rtype * n,
390 const rtype gamma_l, rtype * W_g) const {
391 using Relax = BoundaryCondition::Relax;
392 constexpr uint8_t E = N_DIM + 1;
394 const int32_t k = face_char(i_face);
395 const bool inlet = bc.type == BoundaryType::NSCBC_INLET;
396 const rtype rho = W_l[0], p = W_l[E];
397 const rtype c2 = gamma_l * p / rho;
398 const rtype c = Kokkos::sqrt(c2);
399 const rtype u_n = dot<N_DIM>(W_l + 1, n);
400 if (u_n >= c) {
401 for (uint8_t i = 0; i < N_DIM + 2; i++) W_g[i] = W_l[i];
403 }
404 if (inlet && u_n <= -c) {
405 W_g[0] = bc.data[0];
406 FOR_I_DIM W_g[1 + i] = char_target(k, i);
407 W_g[E] = bc.data[E];
409 }
410 const rtype Z = rho * c;
411 const rtype u_n_e = dot<N_DIM>(W_e + 1, n);
412 const rtype w_out = p + Z * u_n;
413 // Pressure and velocity are continuous at contacts, p - rho c u_n is not
414 const rtype w_in = char_state(k, 0) - Z * char_state(k, 1);
415 const rtype p_g = Kokkos::fmax(0.5_r * (w_out + w_in), 1e-3_r * p);
416 const rtype u_n_g = 0.5_r * (w_out - w_in) / Z;
417 W_g[E] = p_g;
418 if (u_n >= 0.0_r) {
419 // Entropy and tangential velocity leave with the flow
420 W_g[0] = rho * Kokkos::pow(p_g / p, 1.0_r / gamma_l);
421 FOR_I_DIM W_g[1 + i] = W_l[1 + i] + (u_n_g - u_n) * n[i];
423 }
424 if (!inlet) {
425 W_g[0] = W_e[0] * Kokkos::pow(p_g / W_e[E], 1.0_r / gamma_l);
426 FOR_I_DIM W_g[1 + i] = W_e[1 + i] + (u_n_g - u_n_e) * n[i];
428 }
429 // Inflow: temperature and tangential velocity relax toward the target, at the target's gas constant
430 const rtype T_t = bc.relax[Relax::T_TARGET];
431 const rtype R_t = bc.data[E] / (bc.data[0] * T_t);
432 const rtype hc_u = char_depth(k) * c / (-u_n);
433 const rtype a_T = (bc.relax[Relax::TEMPERATURE] < 0.0_r)
434 ? 1.0_r : Kokkos::fmin(1.0_r, hc_u * bc.relax[Relax::TEMPERATURE]);
435 const rtype a_t = (bc.relax[Relax::TANGENTIAL] < 0.0_r)
436 ? 1.0_r : Kokkos::fmin(1.0_r, hc_u * bc.relax[Relax::TANGENTIAL]);
437 const rtype T_e = W_e[E] / (W_e[0] * R_t);
438 const rtype T_g = T_e + a_T * (T_t - T_e);
441 const rtype u_n_t = dot<N_DIM>(u_target, n);
442 FOR_I_DIM {
443 const rtype u_t_e = W_e[1 + i] - u_n_e * n[i];
444 const rtype u_t_t = u_target[i] - u_n_t * n[i];
445 W_g[1 + i] = u_t_e + a_t * (u_t_t - u_t_e) + u_n_g * n[i];
446 }
447 W_g[0] = p_g / (R_t * T_g);
449 }
450
458 void ghost_W_at(const uint32_t i_face, const rtype * W_i, const rtype * n, const rtype dist,
459 rtype * W_g) const {
460 ghost_W(i_face, W_i, n, W_g);
462 if (bc.is_wall() || bc.type == BoundaryType::SYMMETRY) {
463 W_g[N_DIM + 1] += W_i[0] * dot<N_DIM>(gravity, n) * dist;
464 }
465 }
466
471 void ghost_W(const uint32_t i_face, const rtype * W_i, const rtype * n, rtype * W_g) const {
473 if (k >= 0) {
474 for (uint8_t i = 0; i < N_DIM + 2; i++) W_g[i] = face_state(k, i);
475 return;
476 }
477 bcs(face_bc(i_face)).ghost_W(W_i, n, gamma, R, viscous, W_g);
478 }
479};
480
481class Mesh;
482
495 const std::vector<int32_t> & h_face_bc,
496 const std::vector<BoundaryCondition> & h_bcs,
497 rtype gamma, rtype R = 1.0, bool viscous = false,
498 const Euler & gas = Euler());
499
500#endif // BOUNDARY_H
BoundaryData make_boundary_data(const Mesh &mesh, const std::vector< int32_t > &h_face_bc, const std::vector< BoundaryCondition > &h_bcs, rtype gamma, rtype R=1.0, bool viscous=false, const Euler &gas=Euler())
Build BoundaryData (face -> condition map and transmissive image cells) on the host and copy it to th...
Definition boundary.cpp:180
BoundaryType
Definition boundary.h:25
Definition mesh.h:111
Common header file.
KOKKOS_INLINE_FUNCTION rtype dot(const rtype *a, const rtype *b)
Compute the dot product of two arrays.
Definition common_math.h:32
float rtype
Definition common_typedef.h:39
#define N_DIM
Definition common_typedef.h:28
#define FOR_I_DIM
Definition common_typedef.h:32
Physics model declaration.
Device-copyable boundary condition.
Definition boundary.h:97
BoundaryType type
Definition boundary.h:108
rtype relax[N_RELAX]
Definition boundary.h:110
Relax
Entries of relax: relaxation rates over the sound speed are sigma / L (1/length).
Definition boundary.h:99
@ BETA
Definition boundary.h:103
@ ACOUSTIC
Definition boundary.h:100
@ TANGENTIAL
Definition boundary.h:102
@ T_TARGET
Definition boundary.h:104
@ N_RELAX
Definition boundary.h:105
@ TEMPERATURE
Definition boundary.h:101
static BoundaryCondition from_input(const toml::value &input, const Euler &physics)
Parse a [[boundaries]] table entry.
Definition boundary.cpp:27
KOKKOS_INLINE_FUNCTION bool is_characteristic() const
Definition boundary.h:119
KOKKOS_INLINE_FUNCTION void ghost_W(const rtype *W_i, const rtype *n, const rtype gamma, const rtype R, const bool viscous, rtype *W_g) const
Ghost state W_g = [rho, u, p] given the interior state W_i.
Definition boundary.h:144
rtype data[N_DIM+2]
Definition boundary.h:109
KOKKOS_INLINE_FUNCTION bool is_transmissive() const
Whether the exterior state is transmissive away from the Riemann solver (image faces).
Definition boundary.h:125
KOKKOS_INLINE_FUNCTION bool is_wall() const
Definition boundary.h:113
Device-side lookup from faces to boundary conditions.
Definition boundary.h:229
KOKKOS_INLINE_FUNCTION void exterior_mixture(const uint32_t i_face, const uint8_t i_quad, const uint8_t n_quad, const rtype *W_i, const rtype *th_i, const rtype *n, const T_W &W_cells, const T_F &face_solution, const T_FT &face_thermo, const T_CT &cell_thermo, rtype *W_g, rtype *th_g) const
Exterior state of a gas mixture on boundary face i_face: W as in exterior_W (with the interior gamma ...
Definition boundary.h:272
Kokkos::View< rtype *[N_DIM]> char_target
Definition boundary.h:243
Kokkos::View< uint8_t ** > face_image_quad
Definition boundary.h:235
Kokkos::View< int32_t * > face_bc
Definition boundary.h:230
rtype gravity[N_DIM]
Definition boundary.h:254
Kokkos::View< rtype *[3]> char_transverse
Definition boundary.h:241
Kokkos::View< rtype * > char_depth
Definition boundary.h:240
Kokkos::View< int32_t * > face_image
Definition boundary.h:231
KOKKOS_INLINE_FUNCTION void transmissive_W(const uint32_t i_face, const uint8_t i_quad, const uint8_t n_quad, const rtype *W_i, const rtype *n, const T_W &W_cells, const T_F &face_solution, rtype *W_g) const
Exterior state of exterior_W before the characteristic treatment.
Definition boundary.h:350
Kokkos::View< rtype *[N_DIM]> char_target_next
Definition boundary.h:244
KOKKOS_INLINE_FUNCTION GhostEntropy characteristic_W(const uint32_t i_face, const rtype *W_l, const rtype *W_e, const rtype *n, const rtype gamma_l, rtype *W_g) const
Characteristic (NSCBC) exterior state of boundary face i_face for the Riemann solver (docs/design/nsc...
Definition boundary.h:389
Kokkos::View< rtype *[2]> char_state
Definition boundary.h:242
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::View< uint32_t * > char_faces
Definition boundary.h:239
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< uint8_t * > char_edge
Definition boundary.h:248
Kokkos::View< rtype **, Kokkos::LayoutRight > bc_Y
Definition boundary.h:257
Kokkos::View< rtype *[N_DIM]> char_neighbor_dx
Definition boundary.h:247
Kokkos::View< BoundaryCondition * > bcs
Definition boundary.h:249
Kokkos::View< uint8_t * > face_image_side
Definition boundary.h:233
KOKKOS_INLINE_FUNCTION void exterior_W(const uint32_t i_face, const uint8_t i_quad, const uint8_t n_quad, const rtype *W_i, const rtype *n, const T_W &W_cells, const T_F &face_solution, rtype *W_g) const
Exterior state seen by the Riemann solver on boundary face i_face.
Definition boundary.h:335
Kokkos::View< int32_t * > face_image_face
Definition boundary.h:232
Kokkos::View< rtype *[N_DIM+2]> face_state
Definition boundary.h:237
Kokkos::View< uint8_t * > face_image_flip
Definition boundary.h:234
Euler gas
Definition boundary.h:253
rtype gamma
Definition boundary.h:250
Kokkos::View< uint32_t * > char_offsets
Definition boundary.h:245
Kokkos::View< uint32_t * > char_neighbors
Definition boundary.h:246
rtype R
Definition boundary.h:251
Kokkos::View< rtype *[2]> bc_thermo
Definition boundary.h:258
Kokkos::View< int32_t * > face_char
Definition boundary.h:238
Kokkos::View< int32_t * > face_state_index
Definition boundary.h:236
GhostEntropy
Where the entropy of a characteristic ghost state comes from.
Definition boundary.h:373
Calorically perfect gas, inviscid (Euler) or viscous and heat conducting (Navier-Stokes,...
Definition physics.h:54
CellSetup< ExecSpace > c
Definition teno_setup.cpp:1810