21#define DOCTEST_CONFIG_IMPLEMENT
35static constexpr real GOLDEN_NOT_ACQUIRED = 1e300;
40static std::string projectRoot()
42 std::string f(__FILE__);
43 for (
int i = 0; i < 4; i++)
45 auto pos = f.rfind(
'/');
46 if (pos == std::string::npos)
48 if (pos != std::string::npos)
60template <EulerModel model>
61static std::string writeTempConfig(
const std::string &caseJsonPath,
const std::string &tag,
62 const nlohmann::ordered_json &overrides = {})
64 auto tmpDir = std::filesystem::temp_directory_path() /
"dndsr_euler_test";
65 std::filesystem::create_directories(tmpDir);
66 std::string defaultPath = (tmpDir / (tag +
"_default.json")).string();
67 std::string
cfgPath = (tmpDir / (tag +
".json")).string();
72 solverTmp.ConfigureFromJson(defaultPath,
false);
74 MPI::Barrier(g_mpi.
comm);
77 auto fDefault = std::ifstream(defaultPath);
79 auto j = nlohmann::ordered_json::parse(fDefault,
nullptr,
true,
true);
82 auto fCase = std::ifstream(caseJsonPath);
84 auto jCase = nlohmann::ordered_json::parse(fCase,
nullptr,
true,
true);
88 j.merge_patch(overrides);
91 std::string meshRel = j[
"dataIOControl"][
"meshFile"];
92 std::filesystem::path meshAbs = std::filesystem::weakly_canonical(
93 std::filesystem::path(caseJsonPath).parent_path() / meshRel);
94 j[
"dataIOControl"][
"meshFile"] = meshAbs.string();
97 j[
"outputControl"][
"nDataOutC"] = 1000000;
98 j[
"outputControl"][
"nDataOut"] = 1000000;
99 j[
"outputControl"][
"nDataOutCInternal"] = 1000000;
100 j[
"outputControl"][
"nDataOutInternal"] = 1000000;
101 j[
"outputControl"][
"dataOutAtInit"] =
false;
102 j[
"timeMarchControl"][
"nTimeStep"] = 1;
107 auto fOut = std::ofstream(
cfgPath);
109 fOut << std::setw(4) << j;
112 MPI::Barrier(g_mpi.
comm);
121template <EulerModel model>
126 constexpr int nVarsFixed = TEval::nVarsFixed;
127 constexpr int gDim = TEval::gDim;
128 int nVars = getNVars(model);
131 TSolver solver(g_mpi);
132 solver.ConfigureFromJson(
cfgPath,
true);
133 solver.ReadMeshAndInitialize();
135 auto &eval = solver.getEval();
136 auto &u = solver.getU();
137 auto &uRec = solver.getURec();
138 auto &uRecNew = solver.getURecNew();
139 auto vfv = solver.getVFV();
140 auto mesh = solver.getMesh();
141 auto &config = solver.getConfiguration();
142 auto &JSource = solver.getJSource();
143 auto &betaPP = solver.getBetaPP();
150 vfv->BuildUDof(rhs, nVars);
151 vfv->BuildUDof(xinc, nVars);
152 vfv->BuildUDof(xincNew, nVars);
153 vfv->BuildUDof(dTau, 1);
154 vfv->BuildUDof(alphaPP_tmp, 1);
158 config.eulerSettings.useScalarJacobian ? 0 : 1,
162 eval.InitializeUDOF(u);
163 u.trans.startPersistentPull();
164 u.trans.waitPersistentPull();
167 real CFL = config.implicitCFLControl.CFL;
168 real curDtMin = 1e100;
170 eval.FixUMaxFilter(u);
171 u.trans.startPersistentPull();
172 u.trans.waitPersistentPull();
174 eval.EvaluateDt(dTau, u, uRec, CFL, curDtMin, 1e100,
175 config.implicitCFLControl.useLocalDt, 0.0);
183 eval.EvaluateRHS(rhs, JSource, u, uRec, uRec,
184 betaPP, alphaPP_tmp,
false, 0.0);
185 rhs.
trans.startPersistentPull();
186 rhs.
trans.waitPersistentPull();
189 Eigen::VectorXd resNorm(nVars);
190 eval.EvaluateNorm(resNorm, rhs, 1,
true);
194 std::cout <<
" RHS L1 norms:";
195 for (
int i = 0; i < nVars; i++)
196 std::cout <<
" " << std::scientific << std::setprecision(10) << resNorm(i);
197 std::cout << std::endl;
204 real alphaDiag = 1.0;
206 eval.LUSGSMatrixInit(JD, JSource, dTau, dt, alphaDiag, u, uRec, 0, 0.0);
210 eval.UpdateLUSGSForward(alphaDiag, 0.0, rhs, u, xinc, JD, xincNew);
211 eval.UpdateLUSGSBackward(alphaDiag, 0.0, rhs, u, xinc, JD, xincNew);
212 xincNew.
trans.startPersistentPull();
213 xincNew.
trans.waitPersistentPull();
217 Eigen::VectorXd incNorm(nVars);
218 eval.EvaluateNorm(incNorm, xinc, 2,
false);
219 real incL2 = incNorm.norm();
222 std::cout <<
" Inc L2 norm: " << std::scientific << std::setprecision(10) << incL2 << std::endl;
224 return {resNorm(0), resNorm(nVars > 4 ? 4 : nVars - 1), incL2};
231TEST_CASE(
"EulerEvaluator pipeline: IV (NS, P1, 2D)")
233 std::string root = projectRoot();
235 root +
"/cases/euler/euler_config_IV.json",
"iv_test",
236 {{
"vfvSettings", {{
"maxOrder", 1}, {
"intOrder", 3}}},
237 {
"dataIOControl", {{
"meshDirectBisect", 0},
238 {
"meshFile", root +
"/data/mesh/IV10_10.cgns"}}}});
241 std::cout <<
"=== IV (NS, P1) ===" << std::endl;
243 auto [rhsDensity, rhsEnergy, incL2] = runOneNewtonStep<NS>(
cfgPath);
255 std::cout <<
" golden candidates: rhsDensity=" << std::scientific
256 << std::setprecision(10) << rhsDensity
257 <<
" incL2=" << incL2 << std::endl;
267TEST_CASE(
"EulerEvaluator pipeline: NACA0012 (NS_SA, P1)")
269 std::string root = projectRoot();
270 std::string
cfgPath = writeTempConfig<NS_SA>(
271 root +
"/cases/eulerSA/eulerSA_config.json",
"naca_test",
272 {{
"vfvSettings", {{
"maxOrder", 1}, {
"intOrder", 3}}},
273 {
"restartState", {{
"iStep", 0}, {
"iStepInternal", 0}}},
274 {
"dataIOControl", {{
"meshFile", root +
"/data/mesh/NACA0012_H2.cgns"}}}});
277 std::cout <<
"=== NACA0012 (NS_SA, P1) ===" << std::endl;
279 auto [rhsDensity, rhsEnergy, incL2] = runOneNewtonStep<NS_SA>(
cfgPath);
281 CHECK(std::isfinite(rhsDensity));
282 CHECK(std::isfinite(rhsEnergy));
283 CHECK(std::isfinite(incL2));
284 CHECK(rhsDensity > 0);
290 std::cout <<
" golden candidates: rhsDensity=" << std::scientific
291 << std::setprecision(10) << rhsDensity
292 <<
" incL2=" << incL2 << std::endl;
302TEST_CASE(
"EulerEvaluator pipeline: Box (NS_3D, P1)")
304 std::string root = projectRoot();
305 std::string
cfgPath = writeTempConfig<NS_3D>(
306 root +
"/cases/euler3D/euler3D_config_Box.json",
"box3d_test",
307 {{
"vfvSettings", {{
"maxOrder", 1}, {
"intOrder", 3}, {
"cacheDiffBase",
false}}},
308 {
"dataIOControl", {{
"meshFile", root +
"/data/mesh/Uniform32_3D_Periodic.cgns"}}}});
311 std::cout <<
"=== Box (NS_3D, P1) ===" << std::endl;
313 auto [rhsDensity, rhsEnergy, incL2] = runOneNewtonStep<NS_3D>(
cfgPath);
315 CHECK(std::isfinite(rhsDensity));
316 CHECK(std::isfinite(rhsEnergy));
317 CHECK(std::isfinite(incL2));
318 CHECK(rhsDensity > 0);
324 std::cout <<
" golden candidates: rhsDensity=" << std::scientific
325 << std::setprecision(10) << rhsDensity
326 <<
" incL2=" << incL2 << std::endl;
337 MPI_Init(&argc, &argv);
340 doctest::Context ctx;
341 ctx.applyCommandLine(argc, argv);
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Top-level solver orchestrator for compressible Navier-Stokes / Euler simulations.
MPI-parallel distributed array of per-cell Degrees-of-Freedom (conservative variable vectors).
void setConstant(real R)
Set all DOF entries to a uniform scalar value.
Core finite-volume evaluator for compressible Navier-Stokes / Euler equations.
Top-level solver orchestrator for compressible Navier-Stokes / Euler equations.
Per-cell diagonal or block-diagonal Jacobian storage for implicit time stepping.
void SetModeAndInit(int mode, int nVarsC, ArrayDOFV< nVarsFixed > &mock)
Select the storage mode and allocate arrays matching mock's layout.
the host side operators are provided as implemented
double real
Canonical floating-point scalar used throughout DNDSR (double precision).
TTrans trans
Ghost-communication engine bound to father and son.
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
int rank
This rank's 0-based index within comm (-1 until initialised).
MPI_Comm comm
The underlying MPI communicator handle.
void setWorld()
Initialise the object to MPI_COMM_WORLD. Requires MPI_Init to have run.
std::array< real, 3 > runOneNewtonStep(const std::string &cfgPath)
CHECK(std::isfinite(rhsDensity))
TEST_CASE("3D: VFV P2 HQM error < P1 on sinCos3D")