Theseus
Compressible flow solver
Loading...
Searching...
No Matches
Flow.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#include <cassert>
8#include <cmath>
9#include "GasModel.hpp"
10
11// This file contains helper routines that implement flow physics models
12// and methods. Helpers in this module need and use results from the gas
13// EOS and Transport models, but do not belong themselves in the EOS or
14// Transport constructs.
15//
16// NOTE: The main reason for existence of these helpers is to centralize
17// the routines which may need to be updated when adding new gas models
18// like LTE/NLTE. Some routines in this module may be invalid for other
19// gas types, but are central to how fluxes are computed.
20namespace Theseus {
21 namespace Flow {
22
23 MFEM_HOST_DEVICE
24 inline void RotateState(const StateLayout layout, const mfem::real_t *nor, Theseus::PointStateViewRW &S)
25 {
26 int dim = layout.dim;
27 if(dim == 1){
28 S.set_momentum(layout, 0, S.momentum(layout, 0)*nor[0]);
29 return;
30 }
31
32 mfem::real_t tan1[3];
33 mfem::real_t rhoV[3];
34 for(int idim = 0;idim < dim;idim++)
35 rhoV[idim] = S.momentum(layout, idim);
36 Theseus::Kernels::Normal(dim, nor, tan1);
37 mfem::real_t rho_u = Theseus::Kernels::Dot(dim, rhoV, nor);
38 mfem::real_t rho_v = Theseus::Kernels::Dot(dim, rhoV, tan1);
39
40 if (dim == 3)
41 {
42 mfem::real_t tan2[3];
43 Theseus::Kernels::Cross(dim, nor, tan1, tan2);
44 rhoV[2] = Theseus::Kernels::Dot(dim, rhoV, tan2);
45 }
46 rhoV[0] = rho_u;
47 rhoV[1] = rho_v;
48 for(int idim = 0;idim < dim;idim++){
49 S.set_momentum(layout, idim, rhoV[idim]);
50 }
51 }
52
53 // This routine takes as input a *face-oriented* state as input and returns
54 // p* for the 1D Riemann problem at the face.
55 template<typename StateView, typename GasModelT>
56 MFEM_HOST_DEVICE
57 inline mfem::real_t slipwall_pstar(const StateView &S, const GasModelT &gasModel)
58 {
59 const mfem::real_t rho = gasModel.density(S);
60 const mfem::real_t c = gasModel.sound_speed(S);
61 const mfem::real_t p = gasModel.pressure(S);
62 const mfem::real_t v = gasModel.velocity(S, 0);
63 const mfem::real_t gamma = gasModel.gamma(S);
64 const mfem::real_t gammaP1 = gamma + 1.;
65 const mfem::real_t gammaM1 = gamma - 1.;
66 const mfem::real_t gammaP1Inverse = 1.0/gammaP1;
67 const mfem::real_t gammaM1Inverse = 1.0/gammaM1;
68 if (v > 0.0){
69 return (p + 0.25*v*gammaP1*rho*
70 (v + std::sqrt(v*v + 8.0*gammaP1Inverse*p*(gammaM1*gammaP1Inverse+1.0)/rho)));
71 } else {
72 return p * std::pow(std::max(1.0 + 0.5*gammaM1*v/c, 0.0001), 2.0*gamma*gammaM1Inverse);
73 }
74 return 0.0;
75 }
76
77 // This interface uses the internal entropy state (Se), and the wall temp (Tw) to get a "wall beta"
78 // It *requires specialization* for any gas other than ideal single component gas
79 // Ideal Gas: beta = 1/(RTwall)
80 // Ideal Mixtures / LTE beta = 1/(Rmix*Twall), where Rmix is depending on the mixture Rmix(Y)
81 // NLTE: Potentially this will be OK, but EOS-dependent
82 template<typename StateView, typename GasModelT>
83 MFEM_HOST_DEVICE
84 inline mfem::real_t isothermal_wall_beta(const StateView &Se, mfem::real_t Tw, const GasModelT &gasModel)
85 {
86 // In gas models where R_gas is not constant (e.g. a mixture), we need to pass the *conserved*
87 // state to the gasModel.R_gas function. Since we only have ideal atm with fixed R_gas, I am
88 // skipping the unnecessary Entropy2Conservative conversion.
89 return (1.0 / (gasModel.R_gas(Se)*Tw));
90
91 // LTE Gas Model wants this one (because it uses dimensional entropy)
92 // return (1.0 / Tw);
93 }
94
96 mfem::real_t p0;
97 mfem::real_t T0;
98 };
99
101 mfem::real_t rho;
102 mfem::real_t v2;
103 mfem::real_t energy;
104 };
105
106 template<typename ConservedStateView, typename GasModelT>
107 MFEM_HOST_DEVICE
108 inline StaticKinematics isentropic_total_to_static(const ConservedStateView &S, const TotalConditions &Ct,
109 const GasModelT &gasModel)
110 {
111 StaticKinematics out{};
112 const mfem::real_t p = gasModel.pressure(S);
113 const mfem::real_t gamma = gasModel.gamma(S);
114 const mfem::real_t cp = gasModel.cp(S);
115 const mfem::real_t gm1 = gamma - 1.0;
116 const mfem::real_t expo = gm1 / gamma;
117
118 mfem::real_t v2 = 2.0*cp*Ct.T0*(1.0 - std::pow(p/Ct.p0, expo));
119 v2 = std::max(0.0, v2);
120 const mfem::real_t cpT = cp * Ct.T0 - 0.5*v2;
121 out.rho = (gamma / gm1)*p/cpT;
122 out.energy = p/gm1 + 0.5*v2*out.rho;
123 return out;
124 }
125
126 template<typename StateView, typename StateViewRW, typename GasModelT>
127 MFEM_HOST_DEVICE
128 inline void riemann_invariant_outer_state(const StateView &Si, const StateView &So, StateViewRW &S2, const mfem::real_t *n,
129 const GasModelT &gasModel)
130 {
131 const int dim = gasModel.dim();
132 const mfem::real_t rho_i = gasModel.density(Si);
133 const mfem::real_t rho_o = gasModel.density(So);
134 mfem::real_t Vn_i = gasModel.momentum(Si, 0)*n[0];
135 mfem::real_t Vn_o = gasModel.momentum(So, 0)*n[0];
136 if (dim > 1){
137 Vn_i += gasModel.momentum(Si, 1)*n[1];
138 Vn_o += gasModel.momentum(So, 1)*n[1];
139 }
140 if (dim > 2){
141 Vn_i += gasModel.momentum(Si, 2)*n[2];
142 Vn_o += gasModel.momentum(So, 2)*n[2];
143 }
144
145 Vn_i /= rho_i;
146 Vn_o /= rho_o;
147
148 const mfem::real_t p_i = gasModel.pressure(Si);
149 const mfem::real_t a_i = gasModel.sound_speed(Si);
150 const mfem::real_t p_o = gasModel.pressure(So);
151 const mfem::real_t a_o = gasModel.sound_speed(So);
152
153 const mfem::real_t gamma = gasModel.gamma(Si);
154 const mfem::real_t gm1 = gamma - 1.0;
155 const mfem::real_t gm1i = 1.0 / gm1;
156 const mfem::real_t gi = 1.0/gamma;
157
158 const bool ext_supersonic_n = (std::abs(Vn_o) >= a_o);
159
160 const mfem::real_t Rm =
161 (ext_supersonic_n && Vn_i >= 0.0)
162 ? (Vn_i - 2.0 * a_i * gm1i)
163 : (Vn_o - 2.0 * a_o * gm1i);
164 const mfem::real_t Rp =
165 (ext_supersonic_n && Vn_i < 0.0)
166 ? (Vn_o + 2.0 * a_o * gm1i)
167 : (Vn_i + 2.0 * a_i * gm1i);
168
169 const mfem::real_t Vn_b = 0.5 * (Rm + Rp);
170 const mfem::real_t a_b = 0.25*gm1*(Rp - Rm);
171
172 const mfem::real_t dVn_i = Vn_b - Vn_i;
173 const mfem::real_t dVn_o = Vn_b - Vn_o;
174
175 // Density from isentrope anchored on inflow/outflow side
176 const auto rho_from_ref = [&](mfem::real_t rho_ref, mfem::real_t p_ref) {
177 // rho_b = rho_ref * ( (a_b^2 * rho_ref)/(gamma*p_ref) )^(1/(gamma-1))
178 const mfem::real_t factor = (a_b*a_b) * rho_ref / (gamma * p_ref);
179 return rho_ref * std::pow(factor, gm1i);
180 };
181
182 const bool inflow = (Vn_i < 0.0);
183 const mfem::real_t rho_b = inflow ? rho_from_ref(rho_o, p_o) : rho_from_ref(rho_i, p_i);
184 S2.set_mass(gasModel.L, rho_b);
185 const mfem::real_t p_b = (a_b * a_b) * rho_b * gi;
186 mfem::real_t vb[3] = {0., 0., 0.};
187 mfem::real_t vb2 = 0.0;
188 const mfem::real_t dVn = inflow ? dVn_o : dVn_i;
189 for(int idim = 0;idim < dim;idim++){
190 const mfem::real_t base = inflow ? gasModel.velocity(So, idim) : gasModel.velocity(Si, idim);
191 vb[idim] = base + dVn*n[idim];
192 vb2 += (vb[idim]*vb[idim]);
193 S2.set_momentum(gasModel.L, idim, rho_b*vb[idim]);
194 }
195 S2.set_energy(gasModel.L, p_b * gm1i + 0.5 * rho_b * vb2);
196 }
197
198 template<typename PrimStateView, typename ConsStateView, typename GasModelT>
199 MFEM_HOST_DEVICE inline void PrimitiveToConserved(const PrimStateView &prim, ConsStateView &cons, const GasModelT &gasModel){
200 const mfem::real_t rho = prim.mass(gasModel.L);
201 const int dim = gasModel.dim();
202 // NOTE: This call *should* fail for gas models other than ideal single component
203 const mfem::real_t gamma = gasModel.gamma(prim);
204 mfem::real_t v2 = prim.velocity(gasModel.L, 0)*prim.velocity(gasModel.L, 0);
205 cons.set_mass(gasModel.L, rho);
206 cons.set_momentum(gasModel.L, 0, rho*prim.velocity(gasModel.L, 0));
207 if (dim > 1){
208 cons.set_momentum(gasModel.L, 1, rho*prim.velocity(gasModel.L, 1));
209 v2 += prim.velocity(gasModel.L, 1)*prim.velocity(gasModel.L, 1);
210 }
211 if (dim > 2){
212 cons.set_momentum(gasModel.L, 2, rho*prim.velocity(gasModel.L, 2));
213 v2 += prim.velocity(gasModel.L, 2)*prim.velocity(gasModel.L,2);
214 }
215 cons.set_energy(gasModel.L, prim.pressure(gasModel.L) / (gamma-1.) + 0.5 * rho * v2);
216 }
217 }
218}
MFEM_HOST_DEVICE mfem::real_t isothermal_wall_beta(const StateView &Se, mfem::real_t Tw, const GasModelT &gasModel)
Definition Flow.hpp:84
MFEM_HOST_DEVICE void riemann_invariant_outer_state(const StateView &Si, const StateView &So, StateViewRW &S2, const mfem::real_t *n, const GasModelT &gasModel)
Definition Flow.hpp:128
MFEM_HOST_DEVICE mfem::real_t slipwall_pstar(const StateView &S, const GasModelT &gasModel)
Definition Flow.hpp:57
MFEM_HOST_DEVICE StaticKinematics isentropic_total_to_static(const ConservedStateView &S, const TotalConditions &Ct, const GasModelT &gasModel)
Definition Flow.hpp:108
MFEM_HOST_DEVICE void PrimitiveToConserved(const PrimStateView &prim, ConsStateView &cons, const GasModelT &gasModel)
Definition Flow.hpp:199
MFEM_HOST_DEVICE void RotateState(const StateLayout layout, const mfem::real_t *nor, Theseus::PointStateViewRW &S)
Definition Flow.hpp:24
MFEM_HOST_DEVICE void Cross(const int dim, const mfem::real_t *vec1, const mfem::real_t *vec2, mfem::real_t *cross)
Definition theseus_kernels.hpp:91
MFEM_HOST_DEVICE void Normal(const int dim, const mfem::real_t *vec, mfem::real_t *nor)
Definition theseus_kernels.hpp:36
MFEM_HOST_DEVICE mfem::real_t Dot(const int dim, const mfem::real_t *vec1, const mfem::real_t *vec2)
Definition theseus_kernels.hpp:82
Definition AxisymmetricGeometry.hpp:15
Definition Flow.hpp:100
mfem::real_t rho
Definition Flow.hpp:101
mfem::real_t v2
Definition Flow.hpp:102
mfem::real_t energy
Definition Flow.hpp:103
Definition Flow.hpp:95
mfem::real_t p0
Definition Flow.hpp:96
mfem::real_t T0
Definition Flow.hpp:97
Definition GasState.hpp:218
MFEM_HOST_DEVICE void set_momentum(const StateLayout &L, int d, mfem::real_t val)
Definition GasState.hpp:252
MFEM_HOST_DEVICE mfem::real_t momentum(const StateLayout &L, int d) const
Definition GasState.hpp:245
Definition GasState.hpp:37
int dim
Definition GasState.hpp:38