feat(stroid): added command line and tests
This commit is contained in:
@@ -3,14 +3,42 @@
|
||||
#include "mfem.hpp"
|
||||
|
||||
namespace stroid::IO {
|
||||
/**
|
||||
* @brief Visualization modes for GLVis display.
|
||||
*/
|
||||
enum class VISUALIZATION_MODE : uint8_t {
|
||||
/** @brief No attribute visualization (default rendering). */
|
||||
NONE,
|
||||
/** @brief Color elements by their element attribute/ID. */
|
||||
ELEMENT_ID,
|
||||
/** @brief Color boundary-adjacent elements by boundary attribute/ID. */
|
||||
BOUNDARY_ELEMENT_ID
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Save a mesh to MFEM's native `.mesh` format.
|
||||
* @param mesh Mesh to serialize.
|
||||
* @param filename Output path (including extension).
|
||||
*/
|
||||
void SaveMesh(const mfem::Mesh& mesh, const std::string& filename);
|
||||
/**
|
||||
* @brief Save a mesh as a ParaView VTU dataset.
|
||||
* @param mesh Mesh to export.
|
||||
* @param exportName Output base name (ParaView will add extensions).
|
||||
*/
|
||||
void SaveVTU(mfem::Mesh& mesh, const std::string& exportName);
|
||||
void ViewMesh(mfem::Mesh &mesh, const std::string& title, VISUALIZATION_MODE mode);
|
||||
/**
|
||||
* @brief Stream a mesh to a running GLVis server for interactive viewing.
|
||||
* @param mesh Mesh to display.
|
||||
* @param title Window title shown in GLVis.
|
||||
* @param mode Attribute visualization mode.
|
||||
* @param vishost GLVis server host.
|
||||
* @param visport GLVis server port.
|
||||
*/
|
||||
void ViewMesh(mfem::Mesh &mesh, const std::string& title, VISUALIZATION_MODE mode, const std::string &vishost, int visport);
|
||||
/**
|
||||
* @brief Visualize boundary face valence (1=surface, 2=internal).
|
||||
* @param mesh Mesh whose boundary faces are inspected.
|
||||
*/
|
||||
void VisualizeFaceValence(mfem::Mesh& mesh);
|
||||
}
|
||||
@@ -1,18 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
namespace stroid::config {
|
||||
/**
|
||||
* @brief Configuration parameters for stroid mesh generation.
|
||||
*
|
||||
* These values are typically loaded via
|
||||
* `fourdst::config::Config<stroid::config::MeshConfig>` from a TOML file.
|
||||
* The README shows the expected TOML layout under the `[main]` table.
|
||||
* Unspecified keys use the defaults defined here.
|
||||
*/
|
||||
struct MeshConfig {
|
||||
int refinement_levels = 3;
|
||||
int order = 2;
|
||||
/**
|
||||
* @brief Number of uniform refinement passes applied after topology creation.
|
||||
* @toml [main].refinement_levels
|
||||
*/
|
||||
int refinement_levels = 4;
|
||||
/**
|
||||
* @brief Polynomial order for high-order elements.
|
||||
* @toml [main].order
|
||||
*/
|
||||
int order = 3;
|
||||
/**
|
||||
* @brief Whether to include an external domain extending to `r_infinity`.
|
||||
* @details Currently this flag does not affect mesh generation.
|
||||
* @toml [main].include_external_domain
|
||||
*/
|
||||
bool include_external_domain = false;
|
||||
|
||||
double r_core = 2.5;
|
||||
/**
|
||||
* @brief Radius of the stellar core region.
|
||||
* @toml [main].r_core
|
||||
*/
|
||||
double r_core = 1.5;
|
||||
/**
|
||||
* @brief Radius of the stellar surface.
|
||||
* @toml [main].r_star
|
||||
*/
|
||||
double r_star = 5.0;
|
||||
/**
|
||||
* @brief Flattening factor for spheroidal shaping (0 = spherical, >0 = oblate).
|
||||
* @toml [main].flattening
|
||||
*/
|
||||
double flattening = 0;
|
||||
|
||||
/**
|
||||
* @brief Outer radius of the external domain when enabled.
|
||||
* @toml [main].r_infinity
|
||||
*/
|
||||
double r_infinity = 6.0;
|
||||
|
||||
/**
|
||||
* @brief Radius inside which transformations are skipped to avoid singularities.
|
||||
* @toml [main].r_instability
|
||||
*/
|
||||
double r_instability = 1e-14;
|
||||
/**
|
||||
* @brief Controls the smoothness/steepness of the core-to-envelope transition.
|
||||
* @toml [main].core_steepness
|
||||
*/
|
||||
double core_steepness = 1.0;
|
||||
};
|
||||
}
|
||||
|
||||
27
src/include/stroid/meson.build
Normal file
27
src/include/stroid/meson.build
Normal file
@@ -0,0 +1,27 @@
|
||||
python_exe = import('python').find_installation('python3')
|
||||
|
||||
version_parser = '''
|
||||
import sys, re
|
||||
ver = sys.argv[1]
|
||||
if ver.startswith("v"): ver = ver[1:]
|
||||
m = re.match(r"^(\d+)\.(\d+)\.(\d+)(.*)$", ver)
|
||||
if m:
|
||||
print(f"{m.group(1)};{m.group(2)};{m.group(3)};{m.group(4)}")
|
||||
else:
|
||||
print("0;0;0;unknown")
|
||||
'''
|
||||
|
||||
ver_res = run_command(python_exe, '-c', version_parser, meson.project_version(), check: true)
|
||||
ver_parts = ver_res.stdout().strip().split(';')
|
||||
|
||||
config = configuration_data()
|
||||
config.set('STROID_VERSION_MAJOR', ver_parts[0])
|
||||
config.set('STROID_VERSION_MINOR', ver_parts[1])
|
||||
config.set('STROID_VERSION_PATCH', ver_parts[2])
|
||||
config.set('STROID_VERSION_TAG', ver_parts[3])
|
||||
|
||||
configure_file(
|
||||
input : 'stroid.h.in',
|
||||
output : 'stroid.h',
|
||||
configuration : config ,
|
||||
)
|
||||
110
src/include/stroid/stroid.h.in
Normal file
110
src/include/stroid/stroid.h.in
Normal file
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include "stroid/config/config.h"
|
||||
#include "stroid/topology/topology.h"
|
||||
#include "stroid/topology/mapping.h"
|
||||
#include "stroid/topology/curvilinear.h"
|
||||
#include "stroid/utils/mesh_utils.h"
|
||||
#include "stroid/IO/mesh.h"
|
||||
|
||||
/**
|
||||
* @namespace stroid
|
||||
* @brief Public API surface for the stroid mesh generation library.
|
||||
*
|
||||
* This namespace aggregates configuration, topology construction, mapping, and
|
||||
* mesh utilities for building curvilinear multi-block meshes.
|
||||
*
|
||||
* @par Example: build a mesh programmatically
|
||||
* @code
|
||||
* #include <memory>
|
||||
* #include "mfem.hpp"
|
||||
* #include "fourdst/config/config.h"
|
||||
* #include "stroid/stroid.h"
|
||||
*
|
||||
* int main() {
|
||||
* fourdst::config::Config<stroid::config::MeshConfig> cfg;
|
||||
* auto mesh = stroid::topology::BuildSkeleton(cfg);
|
||||
* stroid::topology::Finalize(*mesh, cfg);
|
||||
* stroid::topology::PromoteToHighOrder(*mesh, cfg);
|
||||
* stroid::topology::ProjectMesh(*mesh, cfg);
|
||||
* stroid::IO::SaveVTU(*mesh, "stroid");
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @par Example: tweak config then visualize
|
||||
* @code
|
||||
* fourdst::config::Config<stroid::config::MeshConfig> cfg;
|
||||
* cfg->order = 4;
|
||||
* cfg->flattening = 0.1;
|
||||
* auto mesh = stroid::topology::BuildSkeleton(cfg);
|
||||
* stroid::topology::Finalize(*mesh, cfg);
|
||||
* stroid::topology::PromoteToHighOrder(*mesh, cfg);
|
||||
* stroid::topology::ProjectMesh(*mesh, cfg);
|
||||
* stroid::IO::ViewMesh(*mesh, "Stroid Mesh", stroid::IO::VISUALIZATION_MODE::ELEMENT_ID, "localhost", 19916);
|
||||
* @endcode
|
||||
*/
|
||||
namespace stroid {
|
||||
/**
|
||||
* @brief Version helpers for the stroid library.
|
||||
*/
|
||||
struct version {
|
||||
static constexpr int major = @STROID_VERSION_MAJOR@;
|
||||
static constexpr int minor = @STROID_VERSION_MINOR@;
|
||||
static constexpr int patch = @STROID_VERSION_PATCH@;
|
||||
static constexpr const char* tag = "@STROID_VERSION_TAG@";
|
||||
|
||||
static std::string toString() {
|
||||
std::string versionStr = std::to_string(major) + "." +
|
||||
std::to_string(minor) + "." +
|
||||
std::to_string(patch);
|
||||
if (std::string(tag) != "") {
|
||||
versionStr += "-" + std::string(tag);
|
||||
}
|
||||
return versionStr;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const version&) {
|
||||
os << toString();
|
||||
return os;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @namespace std
|
||||
* @brief Standard library extensions used by stroid.
|
||||
*
|
||||
* Provides a `std::formatter` specialization for `stroid::version` so it can
|
||||
* be used with `std::format` and related APIs.
|
||||
*/
|
||||
// Overload format struct
|
||||
template <>
|
||||
struct std::formatter<stroid::version> : std::formatter<std::string> {
|
||||
auto format(const stroid::version& v, auto& ctx) {
|
||||
return std::formatter<std::string>::format(stroid::version::toString(), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @namespace stroid::config
|
||||
* @brief Configuration types and defaults for mesh generation.
|
||||
*/
|
||||
namespace stroid::config {}
|
||||
|
||||
/**
|
||||
* @namespace stroid::topology
|
||||
* @brief Topology construction and curvilinear mapping utilities.
|
||||
*/
|
||||
namespace stroid::topology {}
|
||||
|
||||
/**
|
||||
* @namespace stroid::IO
|
||||
* @brief Mesh serialization and visualization helpers.
|
||||
*/
|
||||
namespace stroid::IO {}
|
||||
|
||||
/**
|
||||
* @namespace stroid::utils
|
||||
* @brief Mesh inspection and validation utilities.
|
||||
*/
|
||||
namespace stroid::utils {}
|
||||
@@ -5,6 +5,17 @@
|
||||
#include "fourdst/config/config.h"
|
||||
|
||||
namespace stroid::topology {
|
||||
/**
|
||||
* @brief Promote a mesh to high-order by attaching an H1 nodal finite element space.
|
||||
* @param mesh Mesh to update in-place.
|
||||
* @param config Mesh configuration (uses `order`).
|
||||
*/
|
||||
void PromoteToHighOrder(mfem::Mesh& mesh, const fourdst::config::Config<config::MeshConfig> &config);
|
||||
/**
|
||||
* @brief Project high-order mesh nodes using the configured curvilinear mapping.
|
||||
* @details Requires nodes to be present (call PromoteToHighOrder first).
|
||||
* @param mesh Mesh to update in-place.
|
||||
* @param config Mesh configuration (uses radii, flattening, and mapping parameters).
|
||||
*/
|
||||
void ProjectMesh(mfem::Mesh& mesh, const fourdst::config::Config<config::MeshConfig> &config);
|
||||
}
|
||||
@@ -5,11 +5,31 @@
|
||||
#include "fourdst/config/config.h"
|
||||
|
||||
namespace stroid::topology {
|
||||
/**
|
||||
* @brief Apply an equiangular (gnomonic) projection to a point on a cube.
|
||||
* @param pos Position vector updated in-place.
|
||||
*/
|
||||
void ApplyEquiangular(mfem::Vector& pos);
|
||||
|
||||
/**
|
||||
* @brief Apply spheroidal flattening along the Z axis.
|
||||
* @param pos Position vector updated in-place.
|
||||
* @param config Mesh configuration (uses `flattening`).
|
||||
*/
|
||||
void ApplySpheroidal(mfem::Vector& pos, const fourdst::config::Config<config::MeshConfig> &config);
|
||||
|
||||
/**
|
||||
* @brief Apply Kelvin transform outside the stellar radius.
|
||||
* @param pos Position vector updated in-place.
|
||||
* @param config Mesh configuration (uses `r_star` and `r_infinity`).
|
||||
*/
|
||||
void ApplyKelvin(mfem::Vector& pos, const fourdst::config::Config<config::MeshConfig> &config);
|
||||
|
||||
/**
|
||||
* @brief Map a point from the initial block topology to the curvilinear domain.
|
||||
* @param pos Position vector updated in-place.
|
||||
* @param config Mesh configuration (uses radii, flattening, instability radius, and core steepness).
|
||||
* @param attribute_id Element attribute ID (currently unused).
|
||||
*/
|
||||
void TransformPoint(mfem::Vector& pos, const fourdst::config::Config<config::MeshConfig> &config, int attribute_id);
|
||||
}
|
||||
@@ -6,6 +6,16 @@
|
||||
#include <memory>
|
||||
|
||||
namespace stroid::topology {
|
||||
/**
|
||||
* @brief Build the initial multi-block mesh topology for the star model.
|
||||
* @param config Mesh configuration (uses radii and domain flags).
|
||||
* @return Newly allocated mesh skeleton (not yet refined or curved).
|
||||
*/
|
||||
std::unique_ptr<mfem::Mesh> BuildSkeleton(const fourdst::config::Config<config::MeshConfig> & config);
|
||||
/**
|
||||
* @brief Finalize topology, validate orientation, and apply uniform refinement.
|
||||
* @param mesh Mesh to finalize in-place.
|
||||
* @param config Mesh configuration (uses `refinement_levels`).
|
||||
*/
|
||||
void Finalize(mfem::Mesh& mesh, const fourdst::config::Config<config::MeshConfig> &config);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,16 @@
|
||||
#include "mfem.hpp"
|
||||
|
||||
namespace stroid::utils {
|
||||
/**
|
||||
* @brief Mark elements with negative Jacobian determinant.
|
||||
* @details Elements detected as flipped are assigned attribute 999.
|
||||
* @param mesh Mesh to scan and update in-place.
|
||||
*/
|
||||
void MarkFlippedElements(mfem::Mesh& mesh);
|
||||
/**
|
||||
* @brief Mark boundary elements whose outward normal orientation is flipped.
|
||||
* @details Boundary elements detected as flipped are assigned attribute 500.
|
||||
* @param mesh Mesh to scan and update in-place.
|
||||
*/
|
||||
void MarkFlippedBoundaryElements(mfem::Mesh& mesh);
|
||||
}
|
||||
@@ -17,14 +17,13 @@ namespace stroid::IO {
|
||||
|
||||
void SaveVTU(mfem::Mesh &mesh, const std::string &exportName) {
|
||||
mfem::ParaViewDataCollection pd(exportName, &mesh);
|
||||
pd.SetDataFormat(mfem::VTKFormat::BINARY);
|
||||
pd.SetHighOrderOutput(true);
|
||||
pd.Save();
|
||||
}
|
||||
|
||||
void ViewMesh(mfem::Mesh &mesh, const std::string& title, const VISUALIZATION_MODE mode) {
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
mfem::socketstream sol_sock(vishost, visport);
|
||||
void ViewMesh(mfem::Mesh &mesh, const std::string& title, const VISUALIZATION_MODE mode, const std::string &vishost, int visport) {
|
||||
mfem::socketstream sol_sock(vishost.c_str(), visport);
|
||||
if (!sol_sock.is_open()) {
|
||||
std::cerr << "Unable to connect to GLVis server at "
|
||||
<< vishost << ':' << visport << std::endl;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
dependencies = [
|
||||
mfem_dep,
|
||||
config_dep
|
||||
config_dep,
|
||||
]
|
||||
|
||||
subdir('include/stroid')
|
||||
|
||||
stroid_include_files = include_directories('include')
|
||||
stroid_sources = files(
|
||||
'lib/topology/curvilinear.cpp',
|
||||
@@ -13,7 +15,7 @@ stroid_sources = files(
|
||||
)
|
||||
|
||||
stroid_lib = static_library(
|
||||
'stroid',
|
||||
'libstroid',
|
||||
stroid_sources,
|
||||
include_directories: stroid_include_files,
|
||||
dependencies: dependencies,
|
||||
|
||||
Reference in New Issue
Block a user