2D Triangulations
These examples can be loaded into Julia (Revise.jl recommended)
These examples return either a SimplexGridBuilder
struct which can be turned into a grid by calling simplexgrid
(builder), or just an ExtendableGrid with default simplex grid data.
The control flags for Triangle are created based on default options provided by this module which try to ensure "good" grids for FEM and FVM computations. These are documented in SimplexGridFactory.default_options
Occasional options!
statements in the examples overwrite these defaults.
This test code is released under the license conditions of Triangulate.jl
using SimplexGridFactory
using ExtendableGrids
using LinearAlgebra
using Triangulate
Domain triangulation
Here we just describe a domain as a polygon and mesh it.
function triangulation_of_domain()
builder = SimplexGridBuilder(; Generator = Triangulate)
p1 = point!(builder, 0, 0)
p2 = point!(builder, 1, 0)
p3 = point!(builder, 1, 2)
p4 = point!(builder, 0, 1)
p5 = point!(builder, -1, 2)
facet!(builder, p1, p2)
facet!(builder, p2, p3)
facet!(builder, p3, p4)
facet!(builder, p4, p5)
facet!(builder, p5, p1)
builder
end
Triangulation with size control and boundary markers
The previous example was a little bit bland. We miss:
- size control for the triangles
- differently marking of boundary parts
function nicer_triangulation_of_domain()
builder = SimplexGridBuilder(; Generator = Triangulate)
p1 = point!(builder, 0, 0)
p2 = point!(builder, 1, 0)
p3 = point!(builder, 1, 2)
p4 = point!(builder, 0, 1)
p5 = point!(builder, -1, 2)
facetregion!(builder, 1)
facet!(builder, p1, p2)
facet!(builder, p2, p3)
facetregion!(builder, 2)
facet!(builder, p3, p4)
facet!(builder, p4, p5)
facetregion!(builder, 3)
facet!(builder, p5, p1)
options!(builder; maxvolume = 0.01)
builder
end
Triangulation with subregions
Here we create different subregions and apply the maxvolume constraint to the subregions
function triangulation_of_domain_with_subregions()
builder = SimplexGridBuilder(; Generator = Triangulate)
p1 = point!(builder, 0, 0)
p2 = point!(builder, 1, 0)
p3 = point!(builder, 1, 2)
p4 = point!(builder, 0, 1)
p5 = point!(builder, -1, 2)
facetregion!(builder, 1)
facet!(builder, p1, p2)
facet!(builder, p2, p3)
facetregion!(builder, 2)
facet!(builder, p3, p4)
facet!(builder, p4, p5)
facetregion!(builder, 3)
facet!(builder, p5, p1)
facetregion!(builder, 4)
facet!(builder, p1, p4)
cellregion!(builder, 2)
maxvolume!(builder, 0.1)
regionpoint!(builder, -0.1, 0.5)
cellregion!(builder, 3)
maxvolume!(builder, 0.01)
regionpoint!(builder, 0.2, 0.2)
builder
end
Direct specification of input arrays
Of course we can specify the input for Triangle directly. The aim of SimplexBuilder is to avoid the tedious and error prone counting connected with this approach.
function direct_square(Generator = Triangulate)
simplexgrid(Generator;
points = [0 0; 0 1; 1 1; 1 0]',
bfaces = [1 2; 2 3; 3 4; 4 1]',
bfaceregions = [1, 2, 3, 4],
regionpoints = [0.5 0.5;]',
regionnumbers = [1],
regionvolumes = [0.01])
end
Local refinement
We can interface to Triangle's unsuitable mechanism
function square_localref()
builder = SimplexGridBuilder(; Generator = Triangulate)
cellregion!(builder, 1)
maxvolume!(builder, 0.01)
regionpoint!(builder, 0.5, 0.5)
p1 = point!(builder, 0, 0)
p2 = point!(builder, 1, 0)
p3 = point!(builder, 1, 1)
p4 = point!(builder, 0, 1)
facetregion!(builder, 1)
facet!(builder, p1, p2)
facetregion!(builder, 2)
facet!(builder, p2, p3)
facetregion!(builder, 3)
facet!(builder, p3, p4)
facetregion!(builder, 4)
facet!(builder, p4, p1)
refinement_center = [0.5, 0.5]
function unsuitable(x1, y1, x2, y2, x3, y3, area)
bary = [(x1 + x2 + x3) / 3, (y2 + y2 + y3) / 3]
dist = norm(bary - refinement_center)
if area > 0.01 * dist
return 1
else
return 0
end
end
options!(builder; unsuitable = unsuitable)
builder
end
Domain with holes
We can generate domains with holes. This at once shall demonstrate how the chosen API approach eases bookeeping of features added to the geometry description
function swiss_cheese_2d()
function circlehole!(builder, center, radius; n = 20)
points = [point!(builder, center[1] + radius * sin(t), center[2] + radius * cos(t)) for t in range(0, 2π; length = n)]
for i = 1:(n - 1)
facet!(builder, points[i], points[i + 1])
end
facet!(builder, points[end], points[1])
holepoint!(builder, center)
end
builder = SimplexGridBuilder(; Generator = Triangulate)
cellregion!(builder, 1)
maxvolume!(builder, 0.1)
regionpoint!(builder, 0.1, 0.1)
p1 = point!(builder, 0, 0)
p2 = point!(builder, 10, 0)
p3 = point!(builder, 10, 10)
p4 = point!(builder, 0, 10)
facetregion!(builder, 1)
facet!(builder, p1, p2)
facet!(builder, p2, p3)
facet!(builder, p3, p4)
facet!(builder, p4, p1)
holes = [8.0 4.0;
1.0 2.0;
8.0 9.0;
3.0 4.0;
4.0 6.0;
7.0 9.0;
4.0 7.0;
7.0 5.0;
2.0 1.0;
4.0 1.0;
4.0 8.0;
2.0 8.0;
3.0 6.0;
4.0 9.0;
9.0 1.0;
9.0 1.0;
6.0 9.0;
8.0 9.0;
3.0 5.0;
1.0 4.0]'
radii = [0.15, 0.15, 0.1, 0.35, 0.2, 0.3, 0.1, 0.4, 0.1, 0.4, 0.4, 0.15, 0.2, 0.2, 0.2, 0.35, 0.15, 0.25, 0.15, 0.25]
for i = 1:length(radii)
facetregion!(builder, i + 1)
circlehole!(builder, holes[:, i], radii[i])
end
builder
end
Remeshing another grid
The bregions!
method allows to use another grid as geometry description
function remesh_2d()
b = SimplexGridBuilder(; Generator = Triangulate)
X=0:0.1:1
grid1 = simplexgrid(X, X)
bregions!(b,grid1)
simplexgrid(b,maxvolume=0.01)
end
Glueing in another grid
The bregions!
method allows to extract parts of the geometry description from an already existing grid.
function glue_2d()
b = SimplexGridBuilder(; Generator = Triangulate)
h = 0.25
X = 0:h:10
Y = 0:h:4
grid1 = simplexgrid(X, Y)
bfacemask!(grid1, [0, 2], [10, 2], 7)
cellmask!(grid1, [0, 0], [10, 2], 2)
xmin = -2
x0min = 0
x0max = 10
xmax = 12
y0min = 0
ymin = -2
y0max = 4
ymax = 6
facetregion!(b, 8)
facet!(b, (xmin, ymin), (xmax, ymin))
facet!(b, (xmax, ymin), (xmax, 2))
facet!(b, (xmax, 2), (xmax, ymax))
facet!(b, (xmin, ymax), (xmax, ymax))
facet!(b, (xmin, ymin), (xmin, 2))
facet!(b, (xmin, 2), (xmin, ymax))
facetregion!(b, 7)
facet!(b, (x0min, 2), (xmin, 2))
facet!(b, (x0max, 2), (xmax, 2))
cellregion!(b, 1)
regionpoint!(b, 5, 5)
cellregion!(b, 2)
regionpoint!(b, 5, -1)
holepoint!(b, 5, 2)
bregions!(b, grid1, 1:6)
grid2 = simplexgrid(b; maxvolume = 0.6)
grid2 = glue(grid1, grid2)
end
Plot generation
using GridVisualize
function generateplots(picdir; Plotter = nothing)
if isdefined(Plotter, :Makie)
size = (600, 300)
Plotter.activate!(; type = "png", visible = false)
p = builderplot(triangulation_of_domain(); Plotter, size)
Plotter.save(joinpath(picdir, "triangulation_of_domain.png"),p)
p = builderplot(nicer_triangulation_of_domain(); Plotter, size)
Plotter.save(joinpath(picdir, "nicer_triangulation_of_domain.png"),p)
p = builderplot(triangulation_of_domain_with_subregions(); Plotter, size)
Plotter.save(joinpath(picdir, "triangulation_of_domain_with_subregions.png"),p)
p = builderplot(square_localref(); Plotter, size)
Plotter.save(joinpath(picdir, "square_localref.png"),p)
p = gridplot(direct_square(); Plotter, size)
Plotter.save(joinpath(picdir, "direct_square.png"),p)
p = builderplot(swiss_cheese_2d(); Plotter, size)
Plotter.save(joinpath(picdir, "swiss_cheese_2d.png"),p)
p = gridplot(remesh_2d(); Plotter, size)
Plotter.save(joinpath(picdir, "remesh_2d.png"),p)
p = gridplot(glue_2d(); Plotter, size)
Plotter.save(joinpath(picdir, "glue_2d.png"),p)
end
end
This page was generated using Literate.jl.