Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion include/rvegen/postprocess/gmsh_geo_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,13 @@ class gmsh_geo_writer final : public post_process_base<T> {
: value_type{0}},
_element_order{handler.contains("element_order")
? handler.template get<int>("element_order")
: 0} {}
: 0},
_algorithm{handler.contains("algorithm")
? handler.template get<int>("algorithm")
: 0},
_recombine_quads{handler.contains("recombine_quads")
? handler.template get<bool>("recombine_quads")
: false} {}

[[nodiscard]] static parameter_controller_t parameters() {
parameter_controller_t s;
Expand All @@ -92,6 +98,11 @@ class gmsh_geo_writer final : public post_process_base<T> {
s.template insert<int>("element_order")
.template add<numsim_core::description_label<"if > 0, emits Mesh.ElementOrder = <value> in the .geo header — 1 for linear elements (gmsh default), 2 for quadratic (better accuracy on elliptic FE problems). Default 0 = no directive emitted.">>()
.template add<numsim_core::range<0, 5>>();
s.template insert<int>("algorithm")
.template add<numsim_core::description_label<"if > 0, emits Mesh.Algorithm = <value> in the .geo header — gmsh 2D meshing algorithm choice (1=MeshAdapt, 2=Auto, 3=Initial only, 5=Delaunay, 6=Frontal-Delaunay, 7=BAMG, 8=Frontal-Delaunay for quads, 9=Packing of parallelograms). Default 0 = no directive emitted (gmsh defaults to 6/Frontal-Delaunay).">>()
.template add<numsim_core::range<0, 10>>();
s.template insert<bool>("recombine_quads")
.template add<numsim_core::description_label<"if true, emits Mesh.RecombineAll = 1 in the header — gmsh recombines the triangular mesh into quadrilateral / hexahedral elements. Useful for FE-RVE workflows that need structured-style elements. Default false.">>();
return s;
}

Expand Down Expand Up @@ -124,6 +135,23 @@ class gmsh_geo_writer final : public post_process_base<T> {
void set_element_order(int order) noexcept { _element_order = order; }
[[nodiscard]] int element_order() const noexcept { return _element_order; }

// Gmsh 2D meshing-algorithm choice. 0 (default) → no directive
// emitted, gmsh uses Frontal-Delaunay (algorithm 6). Other useful
// values: 8 (Frontal-Delaunay-for-quads, pairs well with
// recombine_quads), 9 (Packing of Parallelograms). See gmsh manual
// §7.4.1 for the full list.
void set_algorithm(int algorithm) noexcept { _algorithm = algorithm; }
[[nodiscard]] int algorithm() const noexcept { return _algorithm; }

// Recombine triangle meshes into quadrilateral elements (or tet
// meshes into hexahedra for 3D). Useful for FE-RVE workflows that
// need structured-style element shapes — e.g. some FFT solvers
// expect quad/hex meshes.
void set_recombine_quads(bool recombine) noexcept {
_recombine_quads = recombine;
}
[[nodiscard]] bool recombine_quads() const noexcept { return _recombine_quads; }

[[nodiscard]] std::string const& output_path() const noexcept {
return _output_path;
}
Expand Down Expand Up @@ -228,6 +256,12 @@ class gmsh_geo_writer final : public post_process_base<T> {
if (_element_order > 0) {
out << "Mesh.ElementOrder = " << _element_order << ";\n";
}
if (_algorithm > 0) {
out << "Mesh.Algorithm = " << _algorithm << ";\n";
}
if (_recombine_quads) {
out << "Mesh.RecombineAll = 1;\n";
}
out << "\n";
}

Expand Down Expand Up @@ -417,6 +451,8 @@ class gmsh_geo_writer final : public post_process_base<T> {
value_type _char_length_min{0};
value_type _char_length_max{0};
int _element_order{0};
int _algorithm{0};
bool _recombine_quads{false};
};

} // namespace rvegen
35 changes: 35 additions & 0 deletions tests/extra_types_smoke.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,38 @@ void test_gmsh_geo_writer_omits_element_order_when_default() {
REQUIRE(out.str().find("Mesh.ElementOrder") == std::string::npos);
}

void test_gmsh_geo_writer_emits_algorithm_when_set() {
rvegen::gmsh_geo_writer<double>::shape_vector shapes;
shapes.emplace_back(std::make_unique<rvegen::circle<double>>(0.5, 0.5, 0.1));
rvegen::gmsh_geo_writer<double> writer{};
writer.set_algorithm(8); // Frontal-Delaunay-for-quads
std::stringstream out;
writer.write(out, shapes, {1.0, 1.0, 0.0});
REQUIRE(out.str().find("Mesh.Algorithm = 8;") != std::string::npos);
}

void test_gmsh_geo_writer_emits_recombine_when_set() {
rvegen::gmsh_geo_writer<double>::shape_vector shapes;
shapes.emplace_back(std::make_unique<rvegen::circle<double>>(0.5, 0.5, 0.1));
rvegen::gmsh_geo_writer<double> writer{};
writer.set_recombine_quads(true);
std::stringstream out;
writer.write(out, shapes, {1.0, 1.0, 0.0});
REQUIRE(out.str().find("Mesh.RecombineAll = 1;") != std::string::npos);
}

void test_gmsh_geo_writer_omits_algorithm_and_recombine_when_default() {
// Default ctor → neither directive should appear.
rvegen::gmsh_geo_writer<double>::shape_vector shapes;
shapes.emplace_back(std::make_unique<rvegen::circle<double>>(0.5, 0.5, 0.1));
rvegen::gmsh_geo_writer<double> writer{};
std::stringstream out;
writer.write(out, shapes, {1.0, 1.0, 0.0});
const auto txt = out.str();
REQUIRE(txt.find("Mesh.Algorithm") == std::string::npos);
REQUIRE(txt.find("Mesh.RecombineAll") == std::string::npos);
}

void test_gmsh_geo_writer_keeps_placeholders_when_mesh_size_default() {
// Default ctor leaves the mesh-size knobs at 0 → commented
// placeholders remain. Back-compat for callers that haven't
Expand Down Expand Up @@ -3577,6 +3609,9 @@ int main() {
test_gmsh_geo_writer_emits_mesh_size_directives_when_set();
test_gmsh_geo_writer_emits_element_order_when_set();
test_gmsh_geo_writer_omits_element_order_when_default();
test_gmsh_geo_writer_emits_algorithm_when_set();
test_gmsh_geo_writer_emits_recombine_when_set();
test_gmsh_geo_writer_omits_algorithm_and_recombine_when_default();
test_gmsh_geo_writer_keeps_placeholders_when_mesh_size_default();
test_voronoi_to_shapes_helper_returns_shape_vector();
test_svg_writer_emits_polygon_element_for_convex_polygon();
Expand Down
Loading