18#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
31static constexpr real g_gamma = 1.4;
32static constexpr real GOLDEN_NOT_ACQUIRED = 1e300;
37 Eigen::Vector<real, 5> U;
38 real E = p / (g_gamma - 1.0) + 0.5 * rho * (u * u +
v *
v + w * w);
39 U << rho, rho * u, rho *
v, rho * w, E;
44static Eigen::Vector<real, 5> exactNormalFlux(
45 const Eigen::Vector<real, 5> &U,
const Eigen::Vector3d &
n)
47 Eigen::Vector3d
velo = U.segment<3>(1) / U(0);
50 real p = (g_gamma - 1.0) * (U(4) - 0.5 * U(0) * vSqr);
52 Eigen::Vector<real, 5> F;
54 F.segment<3>(1) = U.segment<3>(1) * vn + p *
n;
60static auto noDump = []() {};
65static Eigen::Vector<real, 5> callDispatcher(
67 const Eigen::Vector<real, 5> &UL,
68 const Eigen::Vector<real, 5> &UR,
69 const Eigen::Vector3d &
n)
71 Eigen::Vector3d
vg = Eigen::Vector3d::Zero();
72 Eigen::Vector<real, 5> F;
74 real lam0, lam123, lam4;
75 InviscidFlux_IdealGas_Dispatcher<3>(
76 rsType, UL, UR, UL, UR,
vg,
n, g_gamma, F,
77 0.0, 0.0, 0.0, noDump, lam0, lam123, lam4);
85TEST_CASE(
"Roe consistency: identical states give exact flux")
87 auto U = prim2cons(1.225, 100.0, -50.0, 25.0, 101325.0);
88 Eigen::Vector3d
n(0.6, -0.8, 0.0);
91 auto Fexact = exactNormalFlux(U,
n);
92 auto F = callDispatcher(
Roe, U, U,
n);
94 for (
int i = 0; i < 5; i++)
97 CHECK(F(i) == doctest::Approx(
Fexact(i)).epsilon(1e-10));
101TEST_CASE(
"HLLC consistency: identical states give exact flux")
103 auto U = prim2cons(1.225, 100.0, -50.0, 25.0, 101325.0);
104 Eigen::Vector3d
n(0.0, 1.0, 0.0);
106 auto Fexact = exactNormalFlux(U,
n);
107 auto F = callDispatcher(
HLLC, U, U,
n);
109 for (
int i = 0; i < 5; i++)
112 CHECK(F(i) == doctest::Approx(
Fexact(i)).epsilon(1e-10));
116TEST_CASE(
"HLLEP consistency: identical states give exact flux")
118 auto U = prim2cons(1.225, 100.0, -50.0, 25.0, 101325.0);
119 Eigen::Vector3d
n(0.0, 0.0, 1.0);
121 auto Fexact = exactNormalFlux(U,
n);
122 auto F = callDispatcher(
HLLEP, U, U,
n);
124 for (
int i = 0; i < 5; i++)
127 CHECK(F(i) == doctest::Approx(
Fexact(i)).epsilon(1e-10));
131TEST_CASE(
"Roe variants M1-M8 consistency (M2,M9 not implemented)")
133 auto U = prim2cons(1.0, 50.0, 0.0, 0.0, 100000.0);
134 Eigen::Vector3d
n(1.0, 0.0, 0.0);
141 auto F = callDispatcher(rs, U, U,
n);
142 for (
int i = 0; i < 5; i++)
145 CHECK(F(i) == doctest::Approx(
Fexact(i)).epsilon(1e-8));
156 auto UL = prim2cons(1.0, 100.0, 0.0, 0.0, 100000.0);
157 auto UR = prim2cons(0.125, 0.0, 0.0, 0.0, 10000.0);
158 Eigen::Vector3d
n(1.0, 0.0, 0.0);
160 auto F1 = callDispatcher(
Roe, UL, UR,
n);
161 auto F2 = callDispatcher(
Roe, UR, UL, -
n);
163 for (
int i = 0; i < 5; i++)
166 CHECK(F1(i) == doctest::Approx(-F2(i)).epsilon(1e-10));
170TEST_CASE(
"HLLC symmetry: F(UL,UR,n) = -F(UR,UL,-n)")
172 auto UL = prim2cons(1.0, 100.0, 0.0, 0.0, 100000.0);
173 auto UR = prim2cons(0.125, 0.0, 0.0, 0.0, 10000.0);
174 Eigen::Vector3d
n(1.0, 0.0, 0.0);
176 auto F1 = callDispatcher(
HLLC, UL, UR,
n);
177 auto F2 = callDispatcher(
HLLC, UR, UL, -
n);
179 for (
int i = 0; i < 5; i++)
182 CHECK(F1(i) == doctest::Approx(-F2(i)).epsilon(1e-10));
199static auto g_sodUL = prim2cons(1.0, 0.0, 0.0, 0.0, 1.0);
200static auto g_sodUR = prim2cons(0.125, 0.0, 0.0, 0.0, 0.1);
201static const Eigen::Vector3d g_sodN = Eigen::Vector3d(1.0, 0.0, 0.0);
205 {0.0, 0.0, 0.0, 0.0, 0.0}},
207 {0.0, 0.0, 0.0, 0.0, 0.0}},
209 {0.0, 0.0, 0.0, 0.0, 0.0}},
214 for (
auto &tc : g_sodTests)
218 auto F = callDispatcher(tc.rsType, g_sodUL, g_sodUR, g_sodN);
220 std::cout <<
"[Sod/" << tc.name <<
"] F = " << std::scientific
221 << std::setprecision(10);
222 for (
int i = 0; i < 5; i++)
223 std::cout << F(i) <<
" ";
224 std::cout << std::endl;
226 for (
int i = 0; i < 5; i++)
229 CHECK_FALSE(std::isnan(F(i)));
230 CHECK_FALSE(std::isinf(F(i)));
234 CHECK(F(0) >= -1e-10);
253static const auto g_goldenUL = prim2cons(1.225, 100.0, -50.0, 25.0, 101325.0);
254static const auto g_goldenUR = prim2cons(0.8, 200.0, 0.0, 0.0, 80000.0);
255static const Eigen::Vector3d g_goldenN = Eigen::Vector3d(0.6, 0.8, 0.0).normalized();
259 {8.1162345145e+01, 5.8813861917e+04, 5.8759839011e+04,
260 5.9539454795e+02, 2.7251925995e+07}},
262 {9.3486183606e+01, 5.5647501399e+04, 5.7057534871e+04,
263 2.3371545902e+03, 2.5454872499e+07}},
265 {9.2861523292e+01, 5.1385111929e+04, 6.2875774679e+04,
266 5.7376094955e+03, 2.6719441912e+07}},
269TEST_CASE(
"Golden flux values for mixed-state test vector")
271 for (
auto &tc : g_goldenTests)
275 auto F = callDispatcher(tc.rsType, g_goldenUL, g_goldenUR, g_goldenN);
277 std::cout <<
"[Golden/" << tc.name <<
"] F =";
278 for (
int i = 0; i < 5; i++)
279 std::cout <<
" " << std::scientific << std::setprecision(10) << F(i);
280 std::cout << std::endl;
282 for (
int i = 0; i < 5; i++)
285 CHECK_FALSE(std::isnan(F(i)));
286 if (tc.golden[i] < GOLDEN_NOT_ACQUIRED)
287 CHECK(F(i) == doctest::Approx(tc.golden[i]).epsilon(1e-8));
297TEST_CASE(
"All solvers: quiescent gas produces same flux (p-only)")
299 auto U = prim2cons(1.0, 0.0, 0.0, 0.0, 1.0);
300 Eigen::Vector3d
n(1.0, 0.0, 0.0);
301 auto Fexact = exactNormalFlux(U,
n);
306 auto F = callDispatcher(rs, U, U,
n);
307 for (
int i = 0; i < 5; i++)
310 CHECK(F(i) == doctest::Approx(
Fexact(i)).epsilon(1e-12));
319TEST_CASE(
"Roe eigenvalue output: lam0 < lam123 < lam4 for subsonic")
321 auto UL = prim2cons(1.0, 50.0, 0.0, 0.0, 100000.0);
322 auto UR = prim2cons(1.1, 55.0, 0.0, 0.0, 105000.0);
323 Eigen::Vector3d
n(1, 0, 0),
vg(0, 0, 0);
325 Eigen::Vector<real, 5> F;
326 real lam0, lam123, lam4;
327 InviscidFlux_IdealGas_Dispatcher<3>(
328 Roe, UL, UR, UL, UR,
vg,
n, g_gamma, F,
329 0.0, 0.0, 0.0, noDump, lam0, lam123, lam4);
335 CHECK(lam4 >= lam123);
344 auto U = prim2cons(2.0, 100.0, 200.0, 300.0, 200000.0);
345 Eigen::Vector3d
n(1.0, 1.0, 1.0);
348 auto Fexact = exactNormalFlux(U,
n);
349 auto F = callDispatcher(
Roe, U, U,
n);
351 for (
int i = 0; i < 5; i++)
354 CHECK(F(i) == doctest::Approx(
Fexact(i)).epsilon(1e-8));
Ideal-gas Riemann solvers, flux functions, and thermodynamic utilities for the compressible Euler / N...
RiemannSolverType
Selects the approximate Riemann solver and its entropy-fix variant.
the host side operators are provided as implemented
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
Eigen::Matrix< real, 5, 1 > v
Eigen::Vector3d vg(0, 0, 0)
Eigen::Vector3d n(1.0, 0.0, 0.0)
TEST_CASE("Roe symmetry: F(UL,UR,n) = -F(UR,UL,-n)")