Theseus
Compressible flow solver
Loading...
Searching...
No Matches
NavierStokesFlux.hpp
Go to the documentation of this file.
1// Copyright (c) 2025-2026 Board of Trustees of the University of Illinois
2//
3// This file is part of Theseus.
4//
5// SPDX-License-Identifier: BSD-3-Clause
6#pragma once
7
8#include "mfem.hpp"
10#include "GasModel.hpp"
11
12namespace Theseus
13{
14 namespace NavierStokesFlux
15 {
16 template<typename GasT>
17 MFEM_HOST_DEVICE inline static mfem::real_t
18 MaximumNormalWaveSpeed(const GasT &gas,
19 const mfem::real_t *state1,
20 const mfem::real_t *state2,
21 const mfem::real_t *direction)
22 {
23 PointStateView S1{state1};
24 PointStateView S2{state2};
25 mfem::real_t velocity_dot_direction1 = 0.0;
26 mfem::real_t velocity_dot_direction2 = 0.0;
27 mfem::real_t direction_norm_squared = 0.0;
28 for (int d = 0; d < gas.dim(); ++d)
29 {
30 velocity_dot_direction1 += gas.velocity(S1, d) * direction[d];
31 velocity_dot_direction2 += gas.velocity(S2, d) * direction[d];
32 direction_norm_squared += direction[d] * direction[d];
33 }
34 const mfem::real_t direction_norm =
35 Kernels::rsqrt(direction_norm_squared);
36 return Kernels::rmax(
37 Kernels::rabs(velocity_dot_direction1)
38 + gas.sound_speed(S1) * direction_norm,
39 Kernels::rabs(velocity_dot_direction2)
40 + gas.sound_speed(S2) * direction_norm);
41 }
42
43 // Inviscid / Euler Flux
44 template<typename GasT>
45 MFEM_HOST_DEVICE inline static void
46 ComputeInviscidFluxKernel(const GasT &gas,
47 const mfem::real_t *state,
48 mfem::real_t inv_flux[Theseus::MAXEQ][Theseus::MAXDIM])
49 {
50 PointStateView S{state};
51
52 // 1. Get states
53 const int dim = gas.dim();
54 const mfem::real_t density = gas.density(S);
55 const mfem::real_t spec_vol = 1.0/density;
56 mfem::real_t momentum[Theseus::MAXDIM] = {0.,0.,0.};
57 for(int idim = 0;idim < dim;idim++){
58 momentum[idim] = gas.momentum(S, idim);
59 }
60
61 const mfem::real_t energy = gas.energy(S);
62 const mfem::real_t pressure = gas.pressure(S);
63 const mfem::real_t ke = gas.kinetic_energy_density(S);
64 const int eq_mass = gas.L.eq_mass;
65 const int eq_mom0 = gas.L.eq_mom0;
66 const int eq_ener = gas.L.eq_energy;
67 const int eq_spec = gas.L.eq_scalar0;
68
69 const mfem::real_t H = (energy + pressure)*spec_vol;
70 // 2. Compute Flux
71 for (int d = 0; d < dim; d++)
72 {
73 inv_flux[eq_mass][d] = momentum[d];
74 for (int i = 0; i < dim; i++)
75 {
76 // ρuuᵀ
77 inv_flux[eq_mom0+i][d] = momentum[i]*momentum[d]*spec_vol;
78 }
79 // (ρuuᵀ) + p
80 inv_flux[eq_mom0+d][d] += pressure;
81 inv_flux[eq_ener][d] = momentum[d]*H;
82 for(int s = 0;s < gas.L.num_scalars;s++){
83 inv_flux[eq_spec+s][d] = gas.scalar(S, s) * momentum[d] * spec_vol;
84 }
85 }
86 // 3. Compute maximum characteristic speed
87 // const mfem::real_t sound = gas.sound_speed(S);
88 // fluid speed |u|
89 // const mfem::real_t speed = Theseus::Kernels::rsqrt(2.0 * ke / density);
90 // max characteristic speed = fluid speed + sound speed
91 // return speed + sound;
92 }
93
94 template<typename GasT>
95 MFEM_HOST_DEVICE inline
96 static void ComputeViscousFluxKernel(const GasT &gas,
97 const mfem::real_t *state,
98 const mfem::real_t *dprim_x,
99 const mfem::real_t *dprim_y,
100 const mfem::real_t *dprim_z,
101 mfem::real_t visc_flux[Theseus::MAXEQ][Theseus::MAXDIM],
102 bool axisymmetric = false,
103 mfem::real_t radius = 0.0,
104 mfem::real_t *azimuthal_stress = nullptr)
105 {
106
107 // TODO: Update for scalar transport
108 const int dim = gas.dim();
109 // Zero the flux to start
110 for(int q = 0;q < Theseus::MAXEQ;q++){
111 for(int idir = 0;idir < dim;idir++){
112 visc_flux[q][idir] = 0.0;
113 }
114 }
115
116 PointStateView S{state};
117
118 // Access some physical constants
119 const mfem::real_t mu = gas.viscosity(S);
120 const mfem::real_t kappa = gas.thermal_conductivity(S);
121 const mfem::real_t mu_bulk = gas.bulk_viscosity(S);
122
123 // State structure constants
124 const int eq_mass = gas.L.eq_mass;
125 const int eq_mom0 = gas.L.eq_mom0;
126 const int eq_ener = gas.L.eq_energy;
127 const int nscalar = gas.L.num_scalars;
128
129 // Make & populate gradient containers
130 mfem::real_t grad_rho[Theseus::MAXDIM] = {0.0, 0.0, 0.0};
131 mfem::real_t grad_p[Theseus::MAXDIM] = {0.0, 0.0, 0.0};
132 mfem::real_t grad_t[Theseus::MAXDIM] = {0.0, 0.0, 0.0};
133 mfem::real_t grad_vel[Theseus::MAXDIM][Theseus::MAXDIM] = {{0.0}};
134
135 grad_rho[0] = dprim_x[eq_mass];
136 grad_vel[0][0] = dprim_x[eq_mom0];
137 grad_p[0] = dprim_x[eq_ener];
138 if(dim > 1){
139 grad_rho[1] = dprim_y[eq_mass];
140 grad_vel[0][1] = dprim_y[eq_mom0];
141 grad_vel[1][0] = dprim_x[eq_mom0+1];
142 grad_vel[1][1] = dprim_y[eq_mom0+1];
143 grad_p[1] = dprim_y[eq_ener];
144 if(dim > 2){
145 grad_rho[2] = dprim_z[eq_mass];
146 grad_vel[0][2] = dprim_z[eq_mom0];
147 grad_vel[1][2] = dprim_z[eq_mom0+1];
148 grad_vel[2][0] = dprim_x[eq_mom0+2];
149 grad_vel[2][1] = dprim_y[eq_mom0+2];
150 grad_vel[2][2] = dprim_z[eq_mom0+2];
151 grad_p[2] = dprim_z[eq_ener];
152 }
153 }
154
155 gas.grad_temperature(S, grad_rho, grad_p, grad_t);
156 mfem::real_t vel[Theseus::MAXDIM] = {0.0, 0.0, 0.0};
157 mfem::real_t div_vel = 0.0;
158 for(int i = 0;i < dim;i++){
159 vel[i] = gas.velocity(S, i);
160 div_vel += grad_vel[i][i];
161 }
162 mfem::real_t radial_rate = 0.0;
163 if (axisymmetric)
164 {
166 //radial_rate = radius > AxisymmetricGeometry::radius_tolerance ?
167 // vel[radial] / radius : grad_vel[radial][radial];
169 {
170 radial_rate = vel[radial] / radius;
171 }
172 else
173 {
174 radial_rate = grad_vel[radial][radial];
175 // Axis parity requires u_r=0. Use the regular trace in the
176 // viscous energy flux even if the weak axis BC leaves a small
177 // nonzero radial momentum at the boundary node.
178 vel[radial] = 0.0;
179 }
180 div_vel += radial_rate;
181 }
182
183 if (azimuthal_stress)
184 {
185 *azimuthal_stress = 0.0;
186 if (axisymmetric)
187 {
188 *azimuthal_stress = mu *
189 (2.0 * radial_rate - mu_bulk * div_vel);
190 }
191 }
192
193 // Build momentum/energy viscous fluxes by physical direction.
194 // Output convention:
195 // flux_eq_dir[eq][dir]
196 //
197 // Mass row eq=0 remains zero.
198 for (int dir = 0; dir < dim; ++dir)
199 {
200 // viscous stress tensor components tau[mom,dir]
201 for (int mom = 0; mom < dim; ++mom)
202 {
203 mfem::real_t tau = 0.0;
204
205 if (mom == dir)
206 {
207 // Perserve legacy tau exactly
208 tau = mu * (2.0 * grad_vel[mom][dir] - mu_bulk * div_vel);
209 }
210 else
211 {
212 tau = mu * (grad_vel[mom][dir] + grad_vel[dir][mom]);
213 }
214
215 visc_flux[eq_mom0 + mom][dir] = tau;
216 }
217 mfem::real_t eflux = kappa * grad_t[dir];
218 for(int mom = 0;mom < dim;mom++)
219 {
220 eflux += vel[mom] * visc_flux[eq_mom0 + mom][dir];
221 }
222 visc_flux[eq_ener][dir] = eflux;
223 }
224 }
225
226 template<typename GasT>
227 MFEM_HOST_DEVICE inline
228 static void compute_ref_viscous_flux(const GasT &gas,
229 const int dim,
230 const int neq,
231 const mfem::real_t *state,
232 const mfem::real_t *dqx,
233 const mfem::real_t *dqy,
234 const mfem::real_t *dqz,
235 const mfem::real_t *adj_row,
236 mfem::real_t *f_ref,
237 bool axisymmetric = false,
238 mfem::real_t radius = 0.0)
239 {
240 mfem::real_t flux_phys[Theseus::MAXEQ][Theseus::MAXDIM] = {{0.}};
241
242 // Grab the physical flux
243 ComputeViscousFluxKernel(gas, state, dqx, dqy, dqz, flux_phys,
244 axisymmetric, radius);
245
246 for (int q = 0; q < neq; ++q)
247 {
248 f_ref[q] = 0.0;
249 for (int j = 0; j < dim; ++j)
250 f_ref[q] += adj_row[j] * flux_phys[q][j];
251 }
252 }
253
254 };
255
256}
MFEM_HOST_DEVICE mfem::real_t rsqrt(mfem::real_t x)
Definition theseus_kernels.hpp:19
MFEM_HOST_DEVICE mfem::real_t rmax(mfem::real_t a, mfem::real_t b)
Definition theseus_kernels.hpp:17
MFEM_HOST_DEVICE mfem::real_t rabs(mfem::real_t x)
Definition theseus_kernels.hpp:22
Definition AxisymmetricGeometry.hpp:15
constexpr const int MAXDIM
Definition theseus_kernels.hpp:14
constexpr const int MAXEQ
Definition theseus_kernels.hpp:13
static constexpr mfem::real_t radius_tolerance
Definition AxisymmetricGeometry.hpp:22
static constexpr int radial_coordinate
Definition AxisymmetricGeometry.hpp:20
Definition GasState.hpp:127
MFEM_HOST_DEVICE mfem::real_t momentum(const StateLayout &L, int d) const
Definition GasState.hpp:147
MFEM_HOST_DEVICE mfem::real_t velocity(const StateLayout &L, int d) const
Definition GasState.hpp:169