From 104122cd0402b1fa95f89c0672d55a6e48081cbc Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Tue, 24 Jun 2025 15:24:26 +0200 Subject: [PATCH 1/4] Fix forwanding of minangle to TetGen; set 10 to be the default We need an additional "/" after the "q" flag, as stated in 10.20347/WIAS.TECHREPORT.13 chapter 4.2.3. The previous default of "20" produces impractical results, so adjest the default to 10. --- src/options.jl | 13 +++++++++---- src/simplexgridbuilder.jl | 4 +++- src/tetgen.jl | 2 +- src/triangle.jl | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/options.jl b/src/options.jl index fb8a7b4..44af50a 100644 --- a/src/options.jl +++ b/src/options.jl @@ -9,7 +9,8 @@ keyword arguments available to the methods of the package and are listed in the | PLC | true | -p | -p | Triangulate/tetraheralize PLSG/PLC | | refine | false | -r | -r | Refines a previously generated mesh. | | quality | true | -q | -q | Quality mesh generation | -| minangle | 20 | | | Minimum angle for quality | +| minangle | 2D: 20 | | | Minimum angle for quality | +| | 3D: 10 | | | | | volumecontrol | true | -a | -a | Maximum area constraint | | maxvolume | Inf | | | Value of area/volume constraint if less than Inf | | attributes | true | -A | -A | Regional attribute to each simplex. | @@ -39,11 +40,11 @@ The `unsuitable` parameter should be a function, see [`triunsuitable!`](https://juliageometry.github.io/TetGen.jl/stable/#TetGen.triunsuitable!-Tuple{Function}) . """ -default_options() = Dict{Symbol, Any}( +default_options(mesher) = Dict{Symbol, Any}( :PLC => true, :refine => false, :quality => true, - :minangle => 20, + :minangle => mesher == :triangle ? 20 : 10, :volumecontrol => true, :maxvolume => Inf, :attributes => true, @@ -83,7 +84,11 @@ function makeflags(options, mesher) options[:refine] ? flags *= "r" : nothing if options[:quality] minangle = Float64(options[:minangle]) - flags *= @sprintf("q%.2f", minangle) + if mesher == :tetgen + flags *= @sprintf("q/%.2f", minangle) + else + flags *= @sprintf("q%.2f", minangle) + end end if options[:volumecontrol] flags *= "a" diff --git a/src/simplexgridbuilder.jl b/src/simplexgridbuilder.jl index 873fa09..8e611d8 100644 --- a/src/simplexgridbuilder.jl +++ b/src/simplexgridbuilder.jl @@ -49,8 +49,10 @@ function SimplexGridBuilder(; Generator = nothing, tol = 1.0e-12, checkexisting if istetgen(Generator) dim = 3 + mesher = :tetgen elseif istriangulate(Generator) dim = 2 + mesher = :triangle else throw(ArgumentError("Wrong Generator: SimplexGridBuilder needs Generator=TetGen or Generator=Triangulate as argument")) end @@ -66,7 +68,7 @@ function SimplexGridBuilder(; Generator = nothing, tol = 1.0e-12, checkexisting builder.regionpoints = ElasticArray{Cdouble}(undef, dim, 0) builder.regionvolumes = [] builder.regionnumbers = [] - builder.options = default_options() + builder.options = default_options(mesher) builder.checkexisting = checkexisting builder._savedpoint = 0 return builder diff --git a/src/tetgen.jl b/src/tetgen.jl index 271a613..92ca1e8 100644 --- a/src/tetgen.jl +++ b/src/tetgen.jl @@ -7,7 +7,7 @@ See [`default_options`](@ref) for available `kwargs`. """ function ExtendableGrids.simplexgrid(::Type{TetGenType}, TetGen, input; kwargs...) - opts = blendoptions!(default_options(); kwargs...) + opts = blendoptions!(default_options(:tetgen); kwargs...) flags = makeflags(opts, :tetgen) diff --git a/src/triangle.jl b/src/triangle.jl index d9ae5c4..2bd037b 100644 --- a/src/triangle.jl +++ b/src/triangle.jl @@ -6,7 +6,7 @@ Create Grid from Triangle input data. See [`default_options`](@ref) for available `kwargs`. """ function ExtendableGrids.simplexgrid(::Type{TriangulateType}, Triangulate, input; kwargs...) - opts = blendoptions!(default_options(); kwargs...) + opts = blendoptions!(default_options(:triangle); kwargs...) flags = makeflags(opts, :triangle) From 0ec0c1edd5e28e38551a468137db7ac7aa8adb13 Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Tue, 24 Jun 2025 15:27:27 +0200 Subject: [PATCH 2/4] Bump version; add changelog entry --- CHANGELOG.md | 5 +++++ Project.toml | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c52bd1..e86a733 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changes +## v2.6.0 June 24, 2025 + +- Fixed `minangle` parameter forwarding to TetGen +- New default value `minangle = 10` for `TetGen`, leave default value `20` for `Triangle` + ## v2.5.0 June 24, 2025 - Allow for Triangulate v3 - Re-implemented builderplot based on GridVisualize.plot_triangulateio diff --git a/Project.toml b/Project.toml index c90b7ed..b4d49e8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "SimplexGridFactory" uuid = "57bfcd06-606e-45d6-baf4-4ba06da0efd5" -authors = ["Juergen Fuhrmann "] -version = "2.5.0" +authors = ["Juergen Fuhrmann ", "Patrick Jaap "] +version = "2.6.0" [deps] DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" From 2a56716eeeedd0830f4f90f2d8eaf10cfe1afa82 Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Tue, 24 Jun 2025 16:09:13 +0200 Subject: [PATCH 3/4] use TetGen's minangle default; add radius_edge_ratio flag --- CHANGELOG.md | 3 ++- src/options.jl | 49 +++++++++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e86a733..313c50a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ ## v2.6.0 June 24, 2025 - Fixed `minangle` parameter forwarding to TetGen -- New default value `minangle = 10` for `TetGen`, leave default value `20` for `Triangle` +- New default value `minangle = 0` for `TetGen`, leave default value `20` for `Triangle` +- New flag `radius_edge_ratio` for `TetGen` ## v2.5.0 June 24, 2025 - Allow for Triangulate v3 diff --git a/src/options.jl b/src/options.jl index 44af50a..2294074 100644 --- a/src/options.jl +++ b/src/options.jl @@ -4,26 +4,27 @@ Create dictionary of mesh generation options with default values. These at once keyword arguments available to the methods of the package and are listed in the following table: -| keyword | default | 2D | 3D | Explanation | -|:---------------|:-------:|:---:|:---:|:-----------------------------------------------------------| -| PLC | true | -p | -p | Triangulate/tetraheralize PLSG/PLC | -| refine | false | -r | -r | Refines a previously generated mesh. | -| quality | true | -q | -q | Quality mesh generation | -| minangle | 2D: 20 | | | Minimum angle for quality | -| | 3D: 10 | | | | -| volumecontrol | true | -a | -a | Maximum area constraint | -| maxvolume | Inf | | | Value of area/volume constraint if less than Inf | -| attributes | true | -A | -A | Regional attribute to each simplex. | -| confdelaunay | true | -D | | Ensure that all circumcenter lie within the domain. | -| nosteiner | false | -Y | -Y | Prohibits insertion of Steiner points on the mesh boundary | -| quiet | true | -Q | -Q | Suppress all output unless an error occurs. | -| verbose | false | -V | -V | Give detailed information. | -| debugfacets | true | | -d | Detects self-intersections of facets of the PLC. | -| check | false | -C | -C | Checks the consistency of the final mesh. | -| optlevel | 1 | | -O | Specifies the level of mesh optimization. | -| unsuitable | nothing | | | Unsuitable function | -| addflags | "" | | | Additional flags | -| flags | nothing | | | Set flags, overwrite all other options | +| keyword | default | 2D | 3D | Explanation | +|:------------------|:-------:|:---:|:---:|:-----------------------------------------------------------| +| PLC | true | -p | -p | Triangulate/tetraheralize PLSG/PLC | +| refine | false | -r | -r | Refines a previously generated mesh. | +| quality | true | -q | -q | Quality mesh generation | +| minangle | 2D: 20 | | | Minimum angle for quality | +| | 3D: 0 | | | | +| radius_edge_ratio | 2.0 | | | (3D only) Minimum radius/edge ratio for quality | +| volumecontrol | true | -a | -a | Maximum area constraint | +| maxvolume | Inf | | | Value of area/volume constraint if less than Inf | +| attributes | true | -A | -A | Regional attribute to each simplex. | +| confdelaunay | true | -D | | Ensure that all circumcenter lie within the domain. | +| nosteiner | false | -Y | -Y | Prohibits insertion of Steiner points on the mesh boundary | +| quiet | true | -Q | -Q | Suppress all output unless an error occurs. | +| verbose | false | -V | -V | Give detailed information. | +| debugfacets | true | | -d | Detects self-intersections of facets of the PLC. | +| check | false | -C | -C | Checks the consistency of the final mesh. | +| optlevel | 1 | | -O | Specifies the level of mesh optimization. | +| unsuitable | nothing | | | Unsuitable function | +| addflags | "" | | | Additional flags | +| flags | nothing | | | Set flags, overwrite all other options | For mesh generation, these are turned into mesh generator control flags. This process can be completely @@ -44,7 +45,8 @@ default_options(mesher) = Dict{Symbol, Any}( :PLC => true, :refine => false, :quality => true, - :minangle => mesher == :triangle ? 20 : 10, + :minangle => mesher == :triangle ? 20 : 0, + :radius_edge_ratio => 2.0, :volumecontrol => true, :maxvolume => Inf, :attributes => true, @@ -83,12 +85,15 @@ function makeflags(options, mesher) options[:PLC] ? flags *= "p" : nothing options[:refine] ? flags *= "r" : nothing if options[:quality] + radius_edge_ratio = Float64(options[:radius_edge_ratio]) minangle = Float64(options[:minangle]) if mesher == :tetgen - flags *= @sprintf("q/%.2f", minangle) + flags *= @sprintf("q%.2f", radius_edge_ratio) + flags *= @sprintf("/%.2f", minangle) else flags *= @sprintf("q%.2f", minangle) end + end if options[:volumecontrol] flags *= "a" From 042a6af1908f180c7b94fce29baf1dcb6b99fe3c Mon Sep 17 00:00:00 2001 From: Patrick Jaap Date: Tue, 24 Jun 2025 16:41:34 +0200 Subject: [PATCH 4/4] Adapt test values --- test/runtests.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index d923825..26a43b2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -224,7 +224,7 @@ end @test testgrid(test_simplecube(; flags = "pAaqQD"), (109, 286, 198)) @test testgrid(test_simplecube(; maxvolume = 0.05), (50, 68, 96)) - @test testgrid(test_simplecube(; unsuitable = test_tetunsuitable), (223, 971, 198)) + @test testgrid(test_simplecube(; unsuitable = test_tetunsuitable), (242, 1095, 198)) end @testset "SimplexGridBuilder 3d" begin @@ -264,7 +264,7 @@ end end @test SimplexGridFactory.tetgenio(test_buildercube0()) isa RawTetGenIO - @test testgrid(test_buildercube(; unsuitable = test_tetunsuitable), (223, 971, 198)) + @test testgrid(test_buildercube(; unsuitable = test_tetunsuitable), (242, 1095, 198)) end @testset "examples2d.jl" begin @@ -284,7 +284,7 @@ end; @test testgrid(tetrahedralization_of_cube(), (718, 2456, 1094)) @test testgrid(tet_cube_with_primitives(), (5658, 27324, 6888)) @test testgrid(glue_3d(), (29832, 173202, 13200)) - @test testgrid(stl_3d(), (4740, 13605, 9464)) + @test testgrid(stl_3d(), (5979, 20640, 9818)) end; # @testset " PlutoGridFactory.jl" begin @@ -382,7 +382,7 @@ end; end @test testgrid(prim2d(), (106, 179, 50)) @test testgrid(prim2d_lineto(), (24, 30, 16)) - @test testgrid(prim3d(), (423, 1787, 822)) + @test testgrid(prim3d(), (591, 2872, 822)) @test testgrid(prim3d_moveto(), (207, 564, 368)) end