feat(stroid): improved CLI & fixed gcc bug
stroid now installs properly, has an improved CLI for outputting more formats, and can compile on clang and gcc
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -75,6 +75,7 @@ subprojects/libcomposition/
|
||||
subprojects/GridFire/
|
||||
subprojects/tomlplusplus-*/
|
||||
subprojects/CLI11-*/
|
||||
subprojects/magic_enum-*/
|
||||
|
||||
|
||||
qhull.wrap
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
config_p = subproject('libconfig',
|
||||
default_options:[
|
||||
'default_library=static',
|
||||
'pkg_config=' + get_option('pkg_config').to_string(),
|
||||
'build_tests=' + get_option('build_tests').to_string(),
|
||||
'build_examples=false'
|
||||
|
||||
1
build-config/magic_enum/meson.build
Normal file
1
build-config/magic_enum/meson.build
Normal file
@@ -0,0 +1 @@
|
||||
magic_enum_dep = dependency('magic_enum', required : true)
|
||||
@@ -1,3 +1,4 @@
|
||||
subdir('mfem')
|
||||
subdir('libconfig')
|
||||
subdir('CLI11')
|
||||
subdir('magic_enum')
|
||||
@@ -24,4 +24,6 @@ configure_file(
|
||||
input : 'stroid.h.in',
|
||||
output : 'stroid.h',
|
||||
configuration : config ,
|
||||
install: true,
|
||||
install_dir: get_option('includedir') / 'stroid'
|
||||
)
|
||||
|
||||
@@ -27,3 +27,8 @@ stroid_dep = declare_dependency(
|
||||
include_directories: stroid_include_files,
|
||||
dependencies: dependencies
|
||||
)
|
||||
|
||||
install_subdir(
|
||||
'include/stroid',
|
||||
install_dir: get_option('includedir') / 'stroid'
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
[wrap-git]
|
||||
url = https://github.com/4D-STAR/libconfig.git
|
||||
revision = v2.0.3
|
||||
revision = v2.0.4
|
||||
depth = 1
|
||||
10
subprojects/magic_enum.wrap
Normal file
10
subprojects/magic_enum.wrap
Normal file
@@ -0,0 +1,10 @@
|
||||
[wrap-file]
|
||||
directory = magic_enum-0.9.7
|
||||
source_url = https://github.com/Neargye/magic_enum/archive/refs/tags/v0.9.7.tar.gz
|
||||
source_filename = magic_enum-v0.9.7.tar.gz
|
||||
source_hash = b403d3dad4ef542fdc3024fa37d3a6cedb4ad33c72e31b6d9bab89dcaf69edf7
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/magic_enum_0.9.7-1/magic_enum-v0.9.7.tar.gz
|
||||
wrapdb_version = 0.9.7-1
|
||||
|
||||
[provide]
|
||||
magic_enum = magic_enum_dep
|
||||
@@ -1 +1 @@
|
||||
executable('stroid', 'stroid.cpp', dependencies: [stroid_dep, cli11_dep], install: true)
|
||||
executable('stroid', 'stroid.cpp', dependencies: [stroid_dep, cli11_dep, magic_enum_dep], install: true)
|
||||
|
||||
226
tools/stroid.cpp
226
tools/stroid.cpp
@@ -1,84 +1,200 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "mfem.hpp"
|
||||
|
||||
#include "stroid/config/config.h"
|
||||
#include "stroid/IO/mesh.h"
|
||||
#include "stroid/topology/curvilinear.h"
|
||||
#include "stroid/topology/topology.h"
|
||||
|
||||
#include "stroid/stroid.h"
|
||||
|
||||
#include "fourdst/config/config.h"
|
||||
|
||||
#include "CLI/CLI.hpp"
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <algorithm>
|
||||
#include <print>
|
||||
|
||||
enum INFO_MODE {
|
||||
VERSION,
|
||||
DEFAULT_CONFIG
|
||||
// ReSharper disable once CppUnusedIncludeDirective
|
||||
#include "mfem.hpp"
|
||||
#include "stroid/stroid.h"
|
||||
#include "fourdst/config/config.h"
|
||||
#include "CLI/CLI.hpp"
|
||||
#include "magic_enum/magic_enum.hpp"
|
||||
|
||||
bool validate_filename_extension(const std::string& filename, const std::string& expected_ext) {
|
||||
const auto pos = filename.rfind('.');
|
||||
if (pos == std::string::npos) return false;
|
||||
return filename.substr(pos + 1) == expected_ext;
|
||||
}
|
||||
|
||||
enum class MESH_FORMATS : int {
|
||||
VTK,
|
||||
VTU,
|
||||
MFEM,
|
||||
NETGEN,
|
||||
INFO,
|
||||
PARAVIEW
|
||||
};
|
||||
|
||||
struct OUTPUT_CONFIG {
|
||||
struct VTK_SETTINGS {
|
||||
int ref = 0;
|
||||
int field_data = 0;
|
||||
} vtk;
|
||||
|
||||
struct VTU_SETTINGS {
|
||||
int ref = 1;
|
||||
mfem::VTKFormat format = mfem::VTKFormat::ASCII;
|
||||
bool high_order_output = true;
|
||||
int compression_level = 0;
|
||||
bool bdr_elements = false;
|
||||
} vtu;
|
||||
|
||||
struct MFEM_SETTINGS {
|
||||
std::string comments = "Generated by stroid";
|
||||
} mfem;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
fourdst::config::Config<stroid::config::MeshConfig> cfg;
|
||||
OUTPUT_CONFIG out_cfg;
|
||||
MESH_FORMATS selected_format = MESH_FORMATS::VTU; // Default fallback
|
||||
|
||||
CLI::App app{"stroid - A tool for generating multi-block meshes for stellar modeling"};
|
||||
auto* generate = app.add_subcommand("generate", "Generate a multi-block mesh for stellar modeling");
|
||||
auto* info = app.add_subcommand("info", "Access information about the program stroid");
|
||||
|
||||
app.footer(
|
||||
"\nEXAMPLES:\n"
|
||||
" -> stroid generate -c config.toml -o star_mesh.vtu vtu\n"
|
||||
" -> stroid generate --config config.toml --view --no-save\n"
|
||||
" -> stroid info --version\n"
|
||||
" -> stroid info --default\n"
|
||||
);
|
||||
|
||||
auto* generate = app.add_subcommand("generate", "Generate a multi-block mesh");
|
||||
auto* info = app.add_subcommand("info", "Access information about stroid");
|
||||
|
||||
std::optional<std::string> config_filename;
|
||||
std::string output_filename;
|
||||
bool view_mesh;
|
||||
bool no_save;
|
||||
std::optional<std::string> glvis_host;
|
||||
std::optional<int> glvis_port;
|
||||
std::string output_filename = "stroid";
|
||||
bool view_mesh = false;
|
||||
bool no_save = false;
|
||||
std::string glvis_host = "localhost";
|
||||
int glvis_port = 19916;
|
||||
|
||||
generate->add_option("-c,--config", config_filename, "Path to configuration file")->check(CLI::ExistingFile);
|
||||
generate->add_flag("-v,--view", view_mesh, "View the generated mesh using GLVis");
|
||||
generate->add_flag("-n,--nosave", no_save, "Do not save the generated mesh to a file");
|
||||
generate->add_option("--glvis-host", glvis_host, "GLVis server host (default: localhost)")->default_val("localhost");
|
||||
generate->add_option("--glvis-port", glvis_port, "GLVis server port (default: 19916)")->default_val(19916);
|
||||
generate->add_option("-o,--output", output_filename, "Output filename for the generated mesh")->default_val("stroid");
|
||||
generate->add_flag("-n,--no-save", no_save, "Do not save the generated mesh to a file");
|
||||
generate->add_option("--glvis-host", glvis_host, "GLVis server host")->capture_default_str();
|
||||
generate->add_option("--glvis-port", glvis_port, "GLVis server port")->capture_default_str();
|
||||
generate->add_option("-o,--output", output_filename, "Output filename base")->capture_default_str();
|
||||
|
||||
for (auto [value, name_view] : magic_enum::enum_entries<MESH_FORMATS>()) {
|
||||
std::string name{name_view};
|
||||
std::ranges::transform(name, name.begin(), ::tolower);
|
||||
|
||||
auto* sub = generate->add_subcommand(name, "Output as " + name);
|
||||
|
||||
switch (value) {
|
||||
case MESH_FORMATS::VTK:
|
||||
sub->add_option("--ref", out_cfg.vtk.ref, "Refinement level");
|
||||
sub->add_option("--field-data", out_cfg.vtk.field_data, "Field data flag");
|
||||
break;
|
||||
case MESH_FORMATS::VTU:
|
||||
sub->add_option("--ref", out_cfg.vtu.ref, "Refinement level");
|
||||
sub->add_option("--compression", out_cfg.vtu.compression_level, "Compression level (0-9)");
|
||||
sub->add_flag("--high-order", out_cfg.vtu.high_order_output, "High order output");
|
||||
break;
|
||||
case MESH_FORMATS::MFEM:
|
||||
sub->add_option("--comments", out_cfg.mfem.comments, "Header comments");
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
sub->callback([&selected_format, value]() {
|
||||
selected_format = value;
|
||||
});
|
||||
}
|
||||
|
||||
// generate->require_subcommand(1);
|
||||
|
||||
info->add_flag_callback("-v,--version", []() {
|
||||
std::println("Stroid Version {}", stroid::version::toString());
|
||||
return 0;
|
||||
}, "Display stroid version information");
|
||||
|
||||
info->add_flag_callback("-d,--default", [&cfg]() {
|
||||
cfg.save("default.toml");
|
||||
}, "Save the default configuration to a file default.toml");
|
||||
std::println("Default configuration saved to default.toml");
|
||||
}, "Save the default configuration to default.toml");
|
||||
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch (const CLI::ParseError &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
CLI11_PARSE(app, argc, argv);
|
||||
|
||||
// Ensure that if view is requested, host and port are set
|
||||
if (view_mesh) {
|
||||
if (!glvis_host.has_value()) {
|
||||
glvis_host = "localhost";
|
||||
if (*generate) {
|
||||
if (config_filename.has_value()) {
|
||||
cfg.load(config_filename.value());
|
||||
}
|
||||
if (!glvis_port.has_value()) {
|
||||
glvis_port = 19916;
|
||||
|
||||
const std::unique_ptr<mfem::Mesh> mesh = stroid::topology::BuildSkeleton(cfg);
|
||||
stroid::topology::Finalize(*mesh, cfg);
|
||||
stroid::topology::PromoteToHighOrder(*mesh, cfg);
|
||||
stroid::topology::ProjectMesh(*mesh, cfg);
|
||||
|
||||
if (!no_save) {
|
||||
const std::string& final_path = output_filename;
|
||||
|
||||
switch (selected_format) {
|
||||
case MESH_FORMATS::MFEM: {
|
||||
if (!validate_filename_extension(final_path, "mesh")) {
|
||||
std::cerr << "WARNING! Saving to MFEM format without the standard '.mesh' extension. File will be called " << final_path << std::endl;
|
||||
}
|
||||
std::ofstream ofs(final_path);
|
||||
mesh->Print(ofs);
|
||||
break;
|
||||
}
|
||||
case MESH_FORMATS::VTU: {
|
||||
if (!validate_filename_extension(final_path, "vtu")) {
|
||||
std::cerr << "WARNING! Saving to VTU format without the standard '.vtu' extension. File will be called " << final_path << std::endl;
|
||||
}
|
||||
std::ofstream ofs(final_path);
|
||||
mesh->PrintVTU(ofs,
|
||||
out_cfg.vtu.ref,
|
||||
out_cfg.vtu.format,
|
||||
out_cfg.vtu.high_order_output,
|
||||
out_cfg.vtu.compression_level,
|
||||
out_cfg.vtu.bdr_elements);
|
||||
break;
|
||||
}
|
||||
case MESH_FORMATS::VTK: {
|
||||
if (!validate_filename_extension(final_path, "vtk")) {
|
||||
std::cerr << "WARNING! Saving to VTK format without the standard '.vtk' extension. File will be called " << final_path << std::endl;
|
||||
}
|
||||
std::ofstream ofs(final_path);
|
||||
mesh->PrintVTK(ofs, out_cfg.vtk.ref, out_cfg.vtk.field_data);
|
||||
break;
|
||||
}
|
||||
case MESH_FORMATS::NETGEN: {
|
||||
if (!validate_filename_extension(final_path, "nmesh")) {
|
||||
std::cerr << "WARNING! Saving to Netgen format without the standard '.nmesh' extension. File will be called " << final_path << std::endl;
|
||||
}
|
||||
std::ofstream ofs(final_path);
|
||||
mesh->PrintXG(ofs);
|
||||
break;
|
||||
}
|
||||
case MESH_FORMATS::INFO: {
|
||||
mesh->PrintCharacteristics();
|
||||
}
|
||||
case MESH_FORMATS::PARAVIEW: {
|
||||
stroid::IO::SaveVTU(*mesh, final_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (view_mesh) {
|
||||
stroid::IO::ViewMesh(*mesh,
|
||||
"Spheroidal Mesh - Colored by Element ID",
|
||||
stroid::IO::VISUALIZATION_MODE::ELEMENT_ID,
|
||||
glvis_host,
|
||||
glvis_port);
|
||||
}
|
||||
} else if (!*info) {
|
||||
std::println("Usage: {} [generate|info] --help", argv[0]);
|
||||
}
|
||||
|
||||
// If config filename is provided, load configuration from file
|
||||
if (config_filename.has_value()) {
|
||||
cfg.load(config_filename.value());
|
||||
}
|
||||
|
||||
|
||||
const std::unique_ptr<mfem::Mesh> mesh = stroid::topology::BuildSkeleton(cfg);
|
||||
stroid::topology::Finalize(*mesh, cfg);
|
||||
stroid::topology::PromoteToHighOrder(*mesh, cfg);
|
||||
stroid::topology::ProjectMesh(*mesh, cfg);
|
||||
|
||||
|
||||
if (!output_filename.empty() && !no_save) {
|
||||
stroid::IO::SaveVTU(*mesh, output_filename);
|
||||
}
|
||||
|
||||
if (view_mesh) {
|
||||
stroid::IO::ViewMesh(*mesh, "Spheroidal Mesh - Colored by Element ID", stroid::IO::VISUALIZATION_MODE::ELEMENT_ID, glvis_host.value(), glvis_port.value());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user