DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
SingleBlockApp.hpp
Go to the documentation of this file.
1/** @file SingleBlockApp.hpp
2 * @brief Main entry-point template for single-block Euler/Navier-Stokes solver executables.
3 *
4 * Provides getSingleBlockAppName() for mapping EulerModel enum values to
5 * executable names, and the RunSingleBlockConsoleApp() template that wires up
6 * CLI argument parsing (argparse), JSON configuration loading with optional
7 * key/value overrides, JSON Schema emission, and the solve pipeline
8 * (mesh read → initialization → implicit time integration).
9 */
10#pragma once
11
12#include <argparse.hpp>
13
14#include "EulerSolver.hpp"
15
16namespace DNDS::Euler
17{
18 /**
19 * @brief Map an EulerModel enum value to its corresponding executable name string.
20 *
21 * Used to derive default configuration file paths and to set the program name
22 * shown in --help output.
23 *
24 * @param model Compile-time or runtime EulerModel variant.
25 * @return Null-terminated C string with the executable name (e.g. "euler",
26 * "eulerSA", "euler3D"). Returns "_error_app_name_" for unrecognized models.
27 */
28 constexpr static inline const char *getSingleBlockAppName(const EulerModel model)
29 {
30 if (model == NS)
31 return "euler";
32 else if (model == NS_SA)
33 return "eulerSA";
34 else if (model == NS_2D)
35 return "euler2D";
36 else if (model == NS_3D)
37 return "euler3D";
38 else if (model == NS_SA_3D)
39 return "eulerSA3D";
40 else if (model == NS_2EQ)
41 return "euler2EQ";
42 else if (model == NS_2EQ_3D)
43 return "euler2EQ3D";
44 else if (model == NS_EX)
45 return "eulerEX";
46 else if (model == NS_EX_3D)
47 return "eulerEX3D";
48 return "_error_app_name_";
49 }
50
51 /**
52 * @brief Main entry point for single-block solver console applications.
53 *
54 * This function template is instantiated for each EulerModel variant and
55 * serves as the complete `main()` implementation for that solver executable.
56 *
57 * **Execution flow:**
58 * 1. Initialize MPI and build default/user configuration file paths.
59 * 2. Parse command-line arguments via argparse:
60 * - Positional `config` — path to the user JSON configuration file.
61 * - Positional `field_n_variables` (extended models with DynamicSize only).
62 * - `-k`/`--overwrite_key` and `-v`/`--overwrite_value` — repeated pairs
63 * for ad-hoc JSON config overrides.
64 * - `--debug` — attach-debugger mode (MPI hold).
65 * - `--emit-schema` — print the full JSON Schema for this solver's
66 * configuration and exit.
67 * 3. In `--emit-schema` mode: instantiate a default EulerSolver, emit the
68 * schema produced by DNDS_DECLARE_CONFIG, and return.
69 * 4. In normal mode: construct an EulerSolver, load the default config then
70 * the user config (with key/value overrides), call
71 * ReadMeshAndInitialize(), and RunImplicitEuler().
72 *
73 * @tparam model Compile-time EulerModel selecting the equation set / dimension.
74 * @param argc Argument count forwarded from main().
75 * @param argv Argument vector forwarded from main().
76 * @return 0 on success (abnormal paths call std::abort()).
77 */
78 template <EulerModel model>
79 int RunSingleBlockConsoleApp(int argc, char *argv[])
80 {
81 using namespace std::literals;
82 MPIInfo mpi;
83 mpi.setWorld();
84
85 std::string defaultConfJson = "../cases/"s + getSingleBlockAppName(model) + "_default_config.json"s;
86 std::string confJson = "../cases/"s + getSingleBlockAppName(model) + "_config.json";
87 std::vector<std::string> overwriteKeys, overwriteValues;
88
89 argparse::ArgumentParser mainParser(getSingleBlockAppName(model), DNDS_VERSION_STRING);
90 std::string read_configPath;
91 if (getnVarsFixed(model) == DynamicSize)
92 mainParser.add_argument("field_n_variables").default_value<int>(5).scan<'i', int>();
93 mainParser.add_argument("config").default_value("");
94 mainParser.add_argument("-k", "--overwrite_key")
95 .help("keys to the json entries to overwrite")
96 .append()
97 .default_value<std::vector<std::string>>({});
98 mainParser.add_argument("-v", "--overwrite_value")
99 .help("values to the json entries to overwrite")
100 .append()
101 .default_value<std::vector<std::string>>({});
102 mainParser.add_argument("--debug").flag().default_value(false);
103 mainParser.add_argument("--emit-schema")
104 .help("Print JSON Schema for this solver's configuration and exit")
105 .flag()
106 .default_value(false);
107
110
111 try
112 {
113 mainParser.parse_args(argc, argv);
114 if (mainParser.get<bool>("--debug"))
115 {
116 Debug::isDebugging = true;
118 }
119 read_configPath = mainParser.get("config");
120 if (!read_configPath.empty())
121 {
122 confJson = read_configPath;
123 std::filesystem::path p(read_configPath);
124 if (p.is_relative())
125 p = "." / p; // so that not using a wrong path if using a file in cwd
126 defaultConfJson = getStringForcePath(p.parent_path()) + "/"s + getSingleBlockAppName(model) + "_default_config.json"s;
127 }
128 overwriteKeys = mainParser.get<std::vector<std::string>>("--overwrite_key");
129 overwriteValues = mainParser.get<std::vector<std::string>>("--overwrite_value");
130 if (overwriteKeys.size() != overwriteValues.size())
131 throw std::runtime_error("overwrite keys and values not matching");
132 }
133 catch (const std::exception &err)
134 {
135 std::cerr << err.what() << std::endl;
136 std::cerr << mainParser;
137 std::abort();
138 }
139
140 // ---- --emit-schema: print JSON Schema and exit (no MPI, no mesh) ----
141 if (mainParser.get<bool>("--emit-schema"))
142 {
143 int nVars = getnVarsFixed(model);
144 if (nVars == DynamicSize)
145 nVars = mainParser.get<int>("field_n_variables");
146
147 // Build a default-initialized solver to get the full default config JSON.
148 // Then emit a basic JSON Schema inferred from the defaults, enriched with
149 // metadata from any sections that have been migrated to DNDS_PARAM.
150 Euler::EulerSolver<model> solver(mpi, nVars);
151
152 // Write defaults to generate the full default config
153 std::string schemaDefaultFile = "/tmp/dnds_schema_defaults_" + std::to_string(mpi.rank) + ".json";
154 solver.ConfigureFromJson(schemaDefaultFile, false);
155
156 // Build schema: Configuration is fully registered via DNDS_DECLARE_CONFIG,
157 // so emitSchema() produces the complete recursive schema.
158 if (mpi.rank == 0)
159 {
160 using TConfig = typename Euler::EulerSolver<model>::Configuration;
161 nlohmann::ordered_json schema = TConfig::schema(
162 std::string("DNDSR ") + getSingleBlockAppName(model) + " configuration");
163 schema["$schema"] = "http://json-schema.org/draft-07/schema#";
164 schema["title"] = schema["description"];
165 std::cout << schema.dump(4) << std::endl;
166 std::filesystem::remove(schemaDefaultFile);
167 }
168 MPI::Barrier(mpi.comm);
169 if (mpi.rank != 0)
170 std::filesystem::remove(schemaDefaultFile);
171 return 0;
172 }
173
174 try
175 {
176 int nVars = getnVarsFixed(model);
177 if (nVars == DynamicSize)
178 nVars = mainParser.get<int>("field_n_variables");
179 if (mpi.rank == 0)
180 log() << "Current MPI thread level: " << MPI::GetMPIThreadLevel() << std::endl;
182 Euler::EulerSolver<model> solver(mpi, nVars);
183 if (mpi.rank == 0)
184 {
185 log() << "Reading configuration from " << confJson << std::endl;
186 log() << "Using default configuration from " << defaultConfJson << std::endl;
187 }
188 solver.ConfigureFromJson(defaultConfJson, false);
189 solver.ConfigureFromJson(defaultConfJson, true, confJson, overwriteKeys, overwriteValues);
190 solver.ReadMeshAndInitialize();
191 solver.RunImplicitEuler();
192 }
193 catch (const std::exception &e)
194 {
195 std::cerr << "DNDS top-level exception: " << e.what() << std::endl;
196 std::abort();
197 }
198 catch (...)
199 {
200 std::cerr << "Unknown exception" << std::endl;
201 std::abort();
202 }
203 return 0;
204 }
205
206}
Top-level solver orchestrator for compressible Navier-Stokes / Euler simulations.
#define DNDS_VERSION_STRING
Fallback when the build system did not inject the version string.
Definition Macros.hpp:72
Top-level solver orchestrator for compressible Navier-Stokes / Euler equations.
void RunImplicitEuler()
Run the main implicit time-marching loop.
void ReadMeshAndInitialize()
Read the mesh and initialize the full solver pipeline.
void ConfigureFromJson(const std::string &jsonName, bool read=false, const std::string &jsonMergeName="", const std::vector< std::string > &overwriteKeys={}, const std::vector< std::string > &overwriteValues={})
Load or write solver configuration from/to a JSON file.
static CommStrategy & Instance()
Access the process-wide singleton.
Definition MPI.cpp:415
ArrayCommType GetArrayStrategy()
Current array-pack strategy.
Definition MPI.cpp:421
void MPIDebugHold(const MPIInfo &mpi)
If isDebugging is set, block every rank in a busy-wait loop so the user can attach a debugger and ins...
Definition MPI.cpp:59
bool isDebugging
Flag consulted by MPIDebugHold and assert_false_info_mpi.
Definition MPI.cpp:90
int RunSingleBlockConsoleApp(int argc, char *argv[])
Main entry point for single-block solver console applications.
EulerModel
Enumerates the available compressible flow solver model configurations.
Definition Euler.hpp:875
@ NS_2EQ_3D
NS + 2-equation RANS, 3D geometry (7 vars).
Definition Euler.hpp:882
@ NS_SA_3D
NS + Spalart-Allmaras, 3D geometry (6 vars).
Definition Euler.hpp:880
@ NS
Navier-Stokes, 2D geometry, 3D physics (5 vars).
Definition Euler.hpp:876
@ NS_EX_3D
Extended NS, 3D geometry, dynamic nVars (Eigen::Dynamic).
Definition Euler.hpp:884
@ NS_SA
NS + Spalart-Allmaras, 2D geometry (6 vars).
Definition Euler.hpp:877
@ NS_2EQ
NS + 2-equation RANS, 2D geometry (7 vars).
Definition Euler.hpp:881
@ NS_3D
Navier-Stokes, 3D geometry, 3D physics (5 vars).
Definition Euler.hpp:879
@ NS_EX
Extended NS, 2D geometry, dynamic nVars (Eigen::Dynamic).
Definition Euler.hpp:883
@ NS_2D
NS with 2D physics (2 velocity components, 4 vars). The only model with dim=2.
Definition Euler.hpp:878
MPI_int Barrier(MPI_Comm comm)
Wrapper over MPI_Barrier.
Definition MPI.cpp:248
int GetMPIThreadLevel()
Return the MPI thread-support level the current process was initialised with.
Definition MPI.hpp:474
void RegisterSignalHandler()
Install SEGV / ABRT handlers that print a backtrace via DNDS_signal_handler.
Definition Defines.hpp:55
DNDS_CONSTANT const rowsize DynamicSize
Template parameter flag: "row width is set at runtime but uniform".
Definition Defines.hpp:277
std::string getStringForcePath(const std::filesystem::path::string_type &v)
Portable conversion of a platform-native path string to std::string.
Definition Defines.hpp:630
std::ostream & log()
Return the current DNDSR log stream (either std::cout or the installed file).
Definition Defines.cpp:49
std::string GetSetVersionName(const std::string &ver)
Read/set the build version string accessible from code.
Definition Defines.cpp:172
Complete solver configuration, serializable to/from JSON.
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Definition MPI.hpp:215
real err