Skip to content

Commit 314f1e2

Browse files
authored
Merge pull request #78 from Project-SEA-Stack/refactor/hydro-system
Major Refactor: Modular Hydrodynamics Core (HydroForces) with HydroSystem Façade, and Chrono Coupling Layer
2 parents 2db832f + 82cdf3d commit 314f1e2

File tree

79 files changed

+5006
-5798
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+5006
-5798
lines changed

CMakeLists.txt

Lines changed: 211 additions & 191 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
<p align="center">
33
<img src="docs/assets/img/hydrochrono_banner.png" />
44
<br/>
5-
<a href="https://github.com/NREL/HydroChrono/releases"><img src="https://img.shields.io/badge/version-v0.3-blue.svg" /></a>
5+
<a href="https://github.com/NREL/HydroChrono/releases"><img src="https://img.shields.io/badge/version-v0.4-blue.svg" /></a>
66
<a href="#"><img src="https://img.shields.io/badge/status-Prototype-orange.svg" /></a>
77
</p>
88

9-
> ⚠️ HydroChrono is under active development (`v0.3` prototype). This early release focuses on a YAML‑driven CLI and portable HDF5 outputs so you can try the code and share feedback. Expect rapid iteration over the coming year (inc. more advanced PTO, control, mooring & hydrodynamics) — please get in touch if you have any issues or feature requests.
9+
> ⚠️ HydroChrono is under active development (`v0.4` prototype). This early release focuses on a YAML‑driven CLI and portable HDF5 outputs so you can try the code and share feedback. Expect rapid iteration over the coming year (inc. more advanced PTO, control, mooring & hydrodynamics) — please get in touch if you have any issues or feature requests.
1010
1111

1212
HydroChrono (Hydrodynamics for Project Chrono) is a hydrodynamics simulation toolkit built on [Project Chrono](https://projectchrono.org/). It is designed for simulating wave energy converters (WECs) and other complex ocean systems, and is **100% free and open‑source** end‑to‑end — no proprietary dependencies required. This repo ships a prototype, YAML‑driven CLI app for running simulations and exporting portable results.

app/run_hydrochrono.cpp

Lines changed: 55 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
* @brief CLI entrypoint for the HydroChrono YAML-based runner
44
*/
55

6-
#include <hydroc/hydrochrono_runner/run_hydrochrono_from_yaml.h>
6+
#include <hydroc/runner/run_from_yaml.h>
77
#include <hydroc/version.h>
88
#include "../src/utils/misc_options.h"
99
#include <hydroc/logging.h>
1010
#include <string>
1111
#include <filesystem>
12+
#include <iostream>
1213

1314
#ifdef _WIN32
1415
#include <windows.h>
@@ -75,15 +76,15 @@ struct CLIArgs {
7576
std::string sim_file;
7677
bool nogui = false;
7778
bool log = false;
78-
bool nobanner = false; // NEW: Disable banner display
79-
bool quiet = false; // NEW: Quiet mode (minimal output)
80-
bool debug = false; // NEW: Enable detailed simulation diagnostics
81-
bool trace = false; // NEW: Enable step-by-step simulation tracing
82-
std::string output_h5; // NEW: Export HDF5 results path
83-
bool h5_verbose = false; // NEW: HDF5 verbose diagnostics
84-
std::string h5_tag; // NEW: Optional tag appended to filename
85-
bool fail_fast = false; // NEW: Stop on first failure during sweep
86-
bool profile = false; // NEW: Enable runtime profiling summary
79+
bool nobanner = false; // Disable banner display
80+
bool quiet = false; // Quiet mode (minimal output)
81+
bool debug = false; // Enable detailed simulation diagnostics
82+
bool trace = false; // Enable step-by-step simulation tracing
83+
std::string output_h5; // Export HDF5 results path
84+
bool h5_verbose = false; // HDF5 verbose diagnostics
85+
std::string h5_tag; // Optional tag appended to filename
86+
bool fail_fast = false; // Stop on first failure during sweep
87+
bool profile = false; // Enable runtime profiling summary
8788
};
8889

8990
static CLIArgs ParseArguments(int argc, char* argv[]) {
@@ -164,51 +165,60 @@ int main(int argc, char* argv[]) {
164165
// Configure UTF-8 console output on Windows (must be first!)
165166
// ---------------------------------------------------------------------
166167
#ifdef _WIN32
167-
// Enable UTF-8 console output on Windows
168168
SetConsoleOutputCP(CP_UTF8);
169-
std::ios_base::sync_with_stdio(false);
170169
#endif
171170

172171
// Check for hidden options first (before any other processing)
173172
if (hydroc::misc::HandleHiddenOptions(argc, argv)) {
174173
return 0;
175174
}
176175

176+
// -------------------------------------------------------------------------
177+
// Initialize logging early so all CLI output uses the nice formatting
178+
// Wrapped in try/catch to report initialization failures clearly
179+
// -------------------------------------------------------------------------
180+
try {
181+
hydroc::LoggingConfig cfg;
182+
cfg.enable_cli_output = true;
183+
cfg.enable_file_output = false;
184+
cfg.console_level = hydroc::LogLevel::Info;
185+
cfg.file_level = hydroc::LogLevel::Info;
186+
(void)hydroc::Initialize(cfg); // Ignore return value; failures throw
187+
} catch (const std::exception& e) {
188+
std::cerr << "FATAL: Exception during logging initialization: " << e.what() << std::endl;
189+
return 1;
190+
} catch (...) {
191+
std::cerr << "FATAL: Unknown exception during logging initialization" << std::endl;
192+
return 1;
193+
}
194+
177195
// Check for help/version/info flags first (before requiring input directory)
178196
for (int i = 1; i < argc; i++) {
179197
std::string arg = argv[i];
180198
if (arg == "--help" || arg == "-h") {
181-
hydroc::LoggingConfig cfg;
182-
cfg.enable_cli_output = true;
183-
cfg.enable_file_output = false;
184-
cfg.console_level = hydroc::LogLevel::Info;
185-
cfg.file_level = hydroc::LogLevel::Info;
186-
hydroc::Initialize(cfg);
187199
PrintHelp(argv[0]);
188200
hydroc::Shutdown();
189201
return 0;
190202
} else if (arg == "--version" || arg == "-v") {
191-
hydroc::LoggingConfig cfg;
192-
cfg.enable_cli_output = true;
193-
cfg.enable_file_output = false;
194-
cfg.console_level = hydroc::LogLevel::Info;
195-
cfg.file_level = hydroc::LogLevel::Info;
196-
hydroc::Initialize(cfg);
197203
PrintVersion();
198204
hydroc::Shutdown();
199205
return 0;
200206
} else if (arg == "--info" || arg == "-i") {
201-
hydroc::LoggingConfig cfg;
202-
cfg.enable_cli_output = true;
203-
cfg.enable_file_output = false;
204-
cfg.console_level = hydroc::LogLevel::Info;
205-
cfg.file_level = hydroc::LogLevel::Info;
206-
hydroc::Initialize(cfg);
207207
PrintInfo();
208208
hydroc::Shutdown();
209209
return 0;
210210
}
211211
}
212+
213+
// Handle "no arguments" case
214+
if (argc == 1) {
215+
hydroc::cli::LogError("ERROR: Input directory or setup file is required");
216+
hydroc::cli::ShowEmptyLine();
217+
hydroc::cli::LogInfo(std::string("Usage: ") + argv[0] + " [options] <input_directory_or_setup_file>");
218+
hydroc::cli::LogInfo("Use --help for more information.");
219+
hydroc::Shutdown();
220+
return 1;
221+
}
212222

213223
// Parse command line arguments
214224
CLIArgs args = ParseArguments(argc, argv);
@@ -219,85 +229,61 @@ int main(int argc, char* argv[]) {
219229
hydroc::cli::ShowEmptyLine();
220230
hydroc::cli::LogInfo(std::string("Usage: ") + argv[0] + " [options] <input_directory_or_setup_file>");
221231
hydroc::cli::LogInfo("Use --help for more information.");
232+
hydroc::Shutdown();
222233
return 1;
223234
}
224235

225236
// Check if input is a setup file or directory
226237
std::filesystem::path input_path(args.input_directory);
227238
if (std::filesystem::exists(input_path)) {
228239
if (std::filesystem::is_regular_file(input_path)) {
229-
// Check if it's a setup file
230240
if (input_path.extension() == ".yaml") {
231241
const std::string filename = input_path.filename().string();
232242
const std::string suffix = ".setup.yaml";
233243
if (filename.length() >= suffix.length() &&
234244
filename.compare(filename.length() - suffix.length(), suffix.length(), suffix) == 0) {
235-
// Convert setup file path to directory path
236245
args.input_directory = input_path.parent_path().string();
237246
hydroc::cli::LogInfo(std::string("Loaded setup file: ") + input_path.string());
238247
} else {
239248
hydroc::cli::LogError("ERROR: File provided is not a valid .setup.yaml file");
240249
hydroc::cli::LogInfo(std::string(" Path: ") + args.input_directory);
241250
hydroc::cli::LogInfo(" Expected: Directory or any file ending in '.setup.yaml'");
251+
hydroc::Shutdown();
242252
return 1;
243253
}
244254
}
245255
} else if (!std::filesystem::is_directory(input_path)) {
246256
hydroc::cli::LogError("ERROR: Path is neither a directory nor a regular file");
247257
hydroc::cli::LogInfo(std::string(" Path: ") + args.input_directory);
258+
hydroc::Shutdown();
248259
return 1;
249260
}
250261
} else {
251262
hydroc::cli::LogError("ERROR: Input path does not exist");
252263
hydroc::cli::LogInfo(std::string(" Path: ") + args.input_directory);
264+
hydroc::Shutdown();
253265
return 1;
254266
}
255267

256-
// Note: Banner will be rendered by the YAML runner
268+
// Shutdown logging - the runner will reinitialize it
269+
hydroc::Shutdown();
257270

258271
// Prepare arguments for the YAML runner
259272
std::vector<std::string> runner_args;
260-
runner_args.push_back(argv[0]); // program name
261-
262-
// Add input directory
273+
runner_args.push_back(argv[0]);
263274
runner_args.push_back(args.input_directory);
264275

265-
// Add optional flags
266-
if (args.nogui) {
267-
runner_args.push_back("--nogui");
268-
}
269-
270-
// Add logging flag if requested
271-
if (args.log) {
272-
runner_args.push_back("--log");
273-
}
274-
275-
// Add new CLI options
276-
if (args.nobanner) {
277-
runner_args.push_back("--nobanner");
278-
}
279-
280-
if (args.quiet) {
281-
runner_args.push_back("--quiet");
282-
}
283-
284-
if (args.debug) {
285-
runner_args.push_back("--debug");
286-
}
287-
288-
if (args.trace) {
289-
runner_args.push_back("--trace");
290-
}
291-
292-
if (args.profile) {
293-
runner_args.push_back("--profile");
294-
}
295-
276+
if (args.nogui) runner_args.push_back("--nogui");
277+
if (args.log) runner_args.push_back("--log");
278+
if (args.nobanner) runner_args.push_back("--nobanner");
279+
if (args.quiet) runner_args.push_back("--quiet");
280+
if (args.debug) runner_args.push_back("--debug");
281+
if (args.trace) runner_args.push_back("--trace");
282+
if (args.profile) runner_args.push_back("--profile");
296283
if (!args.model_file.empty()) {
297284
runner_args.push_back("--model_file");
298285
runner_args.push_back(args.model_file);
299286
}
300-
301287
if (!args.sim_file.empty()) {
302288
runner_args.push_back("--sim_file");
303289
runner_args.push_back(args.sim_file);
@@ -306,9 +292,7 @@ int main(int argc, char* argv[]) {
306292
runner_args.push_back("--output-h5");
307293
runner_args.push_back(args.output_h5);
308294
}
309-
if (args.fail_fast) {
310-
runner_args.push_back("--fail-fast");
311-
}
295+
if (args.fail_fast) runner_args.push_back("--fail-fast");
312296

313297
// Convert to argc/argv format for the runner
314298
std::vector<char*> runner_argv;

0 commit comments

Comments
 (0)