bluemesh2d 0.1.1.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bluemesh2d/_version.py +24 -0
- bluemesh2d/aabb_tree/findball.py +121 -0
- bluemesh2d/aabb_tree/findtria.py +299 -0
- bluemesh2d/aabb_tree/maketree.py +147 -0
- bluemesh2d/aabb_tree/mapvert.py +72 -0
- bluemesh2d/aabb_tree/queryset.py +83 -0
- bluemesh2d/aabb_tree/scantree.py +124 -0
- bluemesh2d/dependencies.py +83 -0
- bluemesh2d/feedback.py +142 -0
- bluemesh2d/geom_util/boundary_util.py +216 -0
- bluemesh2d/geom_util/getiso.py +194 -0
- bluemesh2d/geom_util/poly_util.py +795 -0
- bluemesh2d/geom_util/proj_util.py +250 -0
- bluemesh2d/geomesh_util/border_util.py +283 -0
- bluemesh2d/geomesh_util/depth_field.py +333 -0
- bluemesh2d/geomesh_util/grd_util.py +1000 -0
- bluemesh2d/geomesh_util/interpolation_mesh.py +318 -0
- bluemesh2d/geomesh_util/merge_circumcenters.py +268 -0
- bluemesh2d/geomesh_util/water_polygon.py +406 -0
- bluemesh2d/hfun_util/build_hfun.py +589 -0
- bluemesh2d/hfun_util/hfun_dispersion.py +96 -0
- bluemesh2d/hfun_util/lfshfn.py +110 -0
- bluemesh2d/hfun_util/limhfn.py +65 -0
- bluemesh2d/hfun_util/make_constant_hfun.py +32 -0
- bluemesh2d/hfun_util/make_depth_hfun.py +51 -0
- bluemesh2d/hfun_util/smooth_and_precomput.py +188 -0
- bluemesh2d/hfun_util/trihfn.py +84 -0
- bluemesh2d/hjac_util/limgrad.py +105 -0
- bluemesh2d/mesh_ball/cdtbal1.py +38 -0
- bluemesh2d/mesh_ball/cdtbal2.py +104 -0
- bluemesh2d/mesh_ball/inv_2x2.py +61 -0
- bluemesh2d/mesh_ball/inv_3x3.py +72 -0
- bluemesh2d/mesh_ball/pwrbal2.py +134 -0
- bluemesh2d/mesh_ball/tribal2.py +27 -0
- bluemesh2d/mesh_cost/relhfn.py +62 -0
- bluemesh2d/mesh_cost/triang.py +59 -0
- bluemesh2d/mesh_cost/triarea.py +51 -0
- bluemesh2d/mesh_cost/trideg.py +44 -0
- bluemesh2d/mesh_cost/triscr.py +43 -0
- bluemesh2d/mesh_file/bnd_util.py +664 -0
- bluemesh2d/mesh_file/loadmsh.py +165 -0
- bluemesh2d/mesh_file/ugrid.py +308 -0
- bluemesh2d/mesh_util/cfmtri.py +118 -0
- bluemesh2d/mesh_util/deltri.py +131 -0
- bluemesh2d/mesh_util/idxtri.py +53 -0
- bluemesh2d/mesh_util/isfeat.py +90 -0
- bluemesh2d/mesh_util/minlen.py +46 -0
- bluemesh2d/mesh_util/setset.py +49 -0
- bluemesh2d/mesh_util/tricon.py +90 -0
- bluemesh2d/mesh_util/tridiv.py +187 -0
- bluemesh2d/meshgen.py +202 -0
- bluemesh2d/ortho_merge/constants.py +27 -0
- bluemesh2d/ortho_merge/geometry.py +64 -0
- bluemesh2d/ortho_merge/ortho_merge_iter.py +812 -0
- bluemesh2d/ortho_merge/orthogonalize.py +2989 -0
- bluemesh2d/pipeline.py +277 -0
- bluemesh2d/poly_data/airfoil.msh +958 -0
- bluemesh2d/poly_data/channel.msh +212 -0
- bluemesh2d/poly_data/islands.msh +13819 -0
- bluemesh2d/poly_data/lake.msh +612 -0
- bluemesh2d/poly_data/river.msh +690 -0
- bluemesh2d/poly_test/inpoly.py +105 -0
- bluemesh2d/poly_test/inpoly_mat.py +104 -0
- bluemesh2d/refine.py +972 -0
- bluemesh2d/smood.py +623 -0
- bluemesh2d/smooth.py +522 -0
- bluemesh2d/tricost.py +426 -0
- bluemesh2d/tridemo.py +723 -0
- bluemesh2d/triread.py +53 -0
- bluemesh2d-0.1.1.dev0.dist-info/METADATA +139 -0
- bluemesh2d-0.1.1.dev0.dist-info/RECORD +74 -0
- bluemesh2d-0.1.1.dev0.dist-info/WHEEL +5 -0
- bluemesh2d-0.1.1.dev0.dist-info/licenses/LICENSE +674 -0
- bluemesh2d-0.1.1.dev0.dist-info/top_level.txt +1 -0
bluemesh2d/tridemo.py
ADDED
|
@@ -0,0 +1,723 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import matplotlib.pyplot as plt
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from bluemesh2d.hfun_util.trihfn import trihfn
|
|
8
|
+
from bluemesh2d.hfun_util.lfshfn import lfshfn
|
|
9
|
+
from bluemesh2d.mesh_util.tridiv import tridiv
|
|
10
|
+
from bluemesh2d.mesh_util.idxtri import idxtri
|
|
11
|
+
from bluemesh2d.smooth import smooth
|
|
12
|
+
from bluemesh2d.refine import refine
|
|
13
|
+
from bluemesh2d.triread import triread
|
|
14
|
+
from bluemesh2d.tricost import tricost
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def tridemo(demo):
|
|
18
|
+
"""Run a MESH2D-style 2D triangulation demo by index.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
demo : int
|
|
23
|
+
Demo index (0–10).
|
|
24
|
+
|
|
25
|
+
Notes
|
|
26
|
+
-----
|
|
27
|
+
Available demos:
|
|
28
|
+
|
|
29
|
+
- 0 : Square with a central square hole (basic PSLG and size constraints).
|
|
30
|
+
- 1 : Effect of the radius–edge threshold ``rho2`` on mesh density/quality.
|
|
31
|
+
- 2 : Compare Delaunay-refinement vs. Frontal-Delaunay ``kind``.
|
|
32
|
+
- 3 : User-defined mesh-size constraints (airfoil, ``lfshfn`` / ``trihfn``).
|
|
33
|
+
- 4 : Hill-climbing smoothing and quality histograms.
|
|
34
|
+
- 5 : Multi-part geometry definitions.
|
|
35
|
+
- 6 : Geometries with internal edge constraints.
|
|
36
|
+
- 7 : Quadtree-style refinement via :func:`~bluemesh2d.mesh_util.tridiv.tridiv`.
|
|
37
|
+
- 8 : Custom mesh-size function (``hfun8``).
|
|
38
|
+
- 9 : Large-scale mesh refinement and optimization (islands).
|
|
39
|
+
- 10 : Medium-scale mesh refinement and optimization (river).
|
|
40
|
+
|
|
41
|
+
References
|
|
42
|
+
----------
|
|
43
|
+
Translation of the MESH2D function ``TRIDEMO``.
|
|
44
|
+
Original MATLAB source: https://github.com/dengwirda/mesh2d
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
if demo == 0:
|
|
48
|
+
demo0()
|
|
49
|
+
elif demo == 1:
|
|
50
|
+
demo1()
|
|
51
|
+
elif demo == 2:
|
|
52
|
+
demo2()
|
|
53
|
+
elif demo == 3:
|
|
54
|
+
demo3()
|
|
55
|
+
elif demo == 4:
|
|
56
|
+
demo4()
|
|
57
|
+
elif demo == 5:
|
|
58
|
+
demo5()
|
|
59
|
+
elif demo == 6:
|
|
60
|
+
demo6()
|
|
61
|
+
elif demo == 7:
|
|
62
|
+
demo7()
|
|
63
|
+
elif demo == 8:
|
|
64
|
+
demo8()
|
|
65
|
+
elif demo == 9:
|
|
66
|
+
demo9()
|
|
67
|
+
elif demo == 10:
|
|
68
|
+
demo10()
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError("tridemo:invalidSelection - Invalid selection!")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def demo0():
|
|
74
|
+
"""Mesh a square domain with a central square hole."""
|
|
75
|
+
|
|
76
|
+
print(
|
|
77
|
+
" A very simple example to start with -- construct a mesh for \n"
|
|
78
|
+
" a simple square domain with a square hole cut from its cen- \n"
|
|
79
|
+
" tre. The geometry is specified as a Planar Straight-Line \n"
|
|
80
|
+
" Graph (PSLG) -- a list of xy coordinates, or 'nodes', and a \n"
|
|
81
|
+
" list of straight-line connections between nodes, or 'edges'.\n"
|
|
82
|
+
" The refine routine is used to build a triangulation of the \n"
|
|
83
|
+
" domain that: (a) conforms to the geometry, and (b) contains \n"
|
|
84
|
+
" only 'nicely' shaped triangles. In the second panel, a mesh \n"
|
|
85
|
+
" that additionally satisfies 'mesh-size' constrains is cons- \n"
|
|
86
|
+
" structed -- "
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
node = np.array(
|
|
90
|
+
[ # list of xy "node" coordinates
|
|
91
|
+
[0, 0], # outer square
|
|
92
|
+
[9, 0],
|
|
93
|
+
[9, 9],
|
|
94
|
+
[0, 9],
|
|
95
|
+
[4, 4], # inner square
|
|
96
|
+
[5, 4],
|
|
97
|
+
[5, 5],
|
|
98
|
+
[4, 5],
|
|
99
|
+
]
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
edge = (
|
|
103
|
+
np.array(
|
|
104
|
+
[ # list of "edges" between nodes
|
|
105
|
+
[1, 2], # outer square
|
|
106
|
+
[2, 3],
|
|
107
|
+
[3, 4],
|
|
108
|
+
[4, 1],
|
|
109
|
+
[5, 6], # inner square
|
|
110
|
+
[6, 7],
|
|
111
|
+
[7, 8],
|
|
112
|
+
[8, 5],
|
|
113
|
+
]
|
|
114
|
+
)
|
|
115
|
+
- 1
|
|
116
|
+
)
|
|
117
|
+
opts = {}
|
|
118
|
+
vert, etri, tria, tnum = refine(node, edge, [], opts)
|
|
119
|
+
|
|
120
|
+
plt.figure()
|
|
121
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
122
|
+
plt.gca().set_aspect("equal")
|
|
123
|
+
plt.axis("off")
|
|
124
|
+
|
|
125
|
+
hfun = 0.5 # uniform "target" edge-lengths
|
|
126
|
+
vert, etri, tria, tnum = refine(node, edge, [], opts, hfun)
|
|
127
|
+
|
|
128
|
+
plt.figure()
|
|
129
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
130
|
+
plt.gca().set_aspect("equal")
|
|
131
|
+
plt.axis("off")
|
|
132
|
+
|
|
133
|
+
plt.draw()
|
|
134
|
+
plt.show()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def demo1():
|
|
138
|
+
"""Demonstrate the effect of ``rho2`` on mesh density and quality."""
|
|
139
|
+
|
|
140
|
+
filepath = os.path.dirname(os.path.abspath(__file__))
|
|
141
|
+
meshfile = os.path.join(filepath, "poly_data", "lake.msh")
|
|
142
|
+
|
|
143
|
+
node, edge, _, _ = triread(meshfile)
|
|
144
|
+
|
|
145
|
+
print(
|
|
146
|
+
" The refine routine can be used to build guaranteed-quality \n"
|
|
147
|
+
" Delaunay triangulations for general polygonal geometries in \n"
|
|
148
|
+
" the two-dimensional plane. The 'quality' of elements in the \n"
|
|
149
|
+
" triangulation can be controlled using the 'radius-edge' bo- \n"
|
|
150
|
+
" und RHO2. \n"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
print("\n")
|
|
154
|
+
print(
|
|
155
|
+
" Setting large values for RHO2, (RHO2 = 1.50 here) generates \n"
|
|
156
|
+
" sparse triangulations with poor worst-case angle bounds. \n"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
opts = {"kind": "delaunay", "rho2": 1.50}
|
|
160
|
+
|
|
161
|
+
vert, etri, tria, tnum = refine(node, edge, [], opts)
|
|
162
|
+
|
|
163
|
+
plt.figure()
|
|
164
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
165
|
+
plt.gca().set_aspect("equal")
|
|
166
|
+
plt.axis("off")
|
|
167
|
+
|
|
168
|
+
plt.title(f"TRIA-MESH: RHO2<=+1.50, |TRIA|={tria.shape[0]}")
|
|
169
|
+
|
|
170
|
+
print(
|
|
171
|
+
" Setting small values for RHO2, (RHO2 = 1.00 here) generates \n"
|
|
172
|
+
" dense triangulations with good worst-case angle bounds. \n"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
opts = {"kind": "delaunay", "rho2": 1.00}
|
|
176
|
+
|
|
177
|
+
vert, etri, tria, tnum = refine(node, edge, [], opts)
|
|
178
|
+
|
|
179
|
+
plt.figure()
|
|
180
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
181
|
+
plt.gca().set_aspect("equal")
|
|
182
|
+
plt.axis("off")
|
|
183
|
+
|
|
184
|
+
plt.title(f"TRIA-MESH: RHO2<=+1.00, |TRIA|={tria.shape[0]}")
|
|
185
|
+
|
|
186
|
+
plt.draw()
|
|
187
|
+
plt.show()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def demo2():
|
|
191
|
+
"""Compare Delaunay-refinement and Frontal-Delaunay ``kind`` options."""
|
|
192
|
+
|
|
193
|
+
filepath = os.path.dirname(os.path.abspath(__file__))
|
|
194
|
+
meshfile = os.path.join(filepath, "poly_data", "lake.msh")
|
|
195
|
+
|
|
196
|
+
node, edge, _, _ = triread(meshfile)
|
|
197
|
+
|
|
198
|
+
print(
|
|
199
|
+
" The refine routine supports two Delaunay-based refinement \n"
|
|
200
|
+
" algorithms: a 'standard' Delaunay-refinement type approach, \n"
|
|
201
|
+
" and a 'Frontal-Delaunay' technique. For problems constrain- \n"
|
|
202
|
+
" ed by element 'quality' alone, the Frontal-Delaunay approa- \n"
|
|
203
|
+
" ch typically produces significantly sparser meshes. In both \n"
|
|
204
|
+
" cases, the same worst-case element quality bounds are sati- \n"
|
|
205
|
+
" sfied in a guaranteed manner. \n"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
opts = {"kind": "delaunay", "rho2": 1.00}
|
|
209
|
+
|
|
210
|
+
vert, etri, tria, tnum = refine(node, edge, [], opts)
|
|
211
|
+
|
|
212
|
+
plt.figure()
|
|
213
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
214
|
+
plt.gca().set_aspect("equal")
|
|
215
|
+
plt.axis("off")
|
|
216
|
+
|
|
217
|
+
plt.title(f"TRIA-MESH: KIND=DELAUNAY, |TRIA|={tria.shape[0]}")
|
|
218
|
+
|
|
219
|
+
opts = {"kind": "delfront", "rho2": 1.00}
|
|
220
|
+
|
|
221
|
+
vert, etri, tria, tnum = refine(node, edge, [], opts)
|
|
222
|
+
|
|
223
|
+
plt.figure()
|
|
224
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
225
|
+
plt.gca().set_aspect("equal")
|
|
226
|
+
plt.axis("off")
|
|
227
|
+
|
|
228
|
+
plt.title(f"TRIA-MESH: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
229
|
+
|
|
230
|
+
plt.draw()
|
|
231
|
+
plt.show()
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def demo3():
|
|
235
|
+
"""Demonstrate user-defined mesh-size constraints on an airfoil geometry."""
|
|
236
|
+
|
|
237
|
+
# équivalent de mfilename('fullpath')
|
|
238
|
+
filepath = os.path.dirname(os.path.abspath(__file__))
|
|
239
|
+
meshfile = os.path.join(filepath, "poly_data", "airfoil.msh")
|
|
240
|
+
|
|
241
|
+
node, edge, _, _ = triread(meshfile)
|
|
242
|
+
|
|
243
|
+
print(
|
|
244
|
+
" Additionally, the refine routine supports size-driven ref- \n"
|
|
245
|
+
" inement, producing meshes that satisfy constraints on elem- \n"
|
|
246
|
+
" ent edge-lengths. The lfshfn routine can be used to create \n"
|
|
247
|
+
" mesh-size functions based on an estimate of the 'local-fea- \n"
|
|
248
|
+
" ture-size' associated with a polygonal domain. The Frontal- \n"
|
|
249
|
+
" Delaunay refinement algorithm discussed in DEMO-2 is espec- \n"
|
|
250
|
+
" ially good at generating high-quality triangulations in the \n"
|
|
251
|
+
" presence of mesh-size constraints. \n"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
olfs = {"dhdx": 0.15}
|
|
255
|
+
|
|
256
|
+
vlfs, tlfs, hlfs = lfshfn(node, edge, [], olfs)
|
|
257
|
+
slfs = idxtri(vlfs, tlfs)
|
|
258
|
+
|
|
259
|
+
facecolors = np.mean(hlfs[tlfs[:, 0:3]], axis=1)
|
|
260
|
+
plt.figure()
|
|
261
|
+
plt.tripcolor(
|
|
262
|
+
vlfs[:, 0],
|
|
263
|
+
vlfs[:, 1],
|
|
264
|
+
tlfs[:, 0:3],
|
|
265
|
+
facecolors=facecolors,
|
|
266
|
+
shading="flat",
|
|
267
|
+
cmap="viridis",
|
|
268
|
+
)
|
|
269
|
+
plt.gca().set_aspect("equal")
|
|
270
|
+
plt.axis("off")
|
|
271
|
+
plt.title(f"MESH-SIZE: KIND=DELAUNAY, |TRIA|={tlfs.shape[0]}")
|
|
272
|
+
|
|
273
|
+
hfun = trihfn
|
|
274
|
+
|
|
275
|
+
vert, etri, tria, tnum = refine(node, edge, [], {}, hfun, vlfs, tlfs, slfs, hlfs)
|
|
276
|
+
|
|
277
|
+
plt.figure()
|
|
278
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
279
|
+
plt.gca().set_aspect("equal")
|
|
280
|
+
plt.axis("off")
|
|
281
|
+
|
|
282
|
+
plt.title(f"TRIA-MESH: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
283
|
+
|
|
284
|
+
plt.draw()
|
|
285
|
+
plt.show()
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def demo4():
|
|
289
|
+
"""Demonstrate hill-climbing smoothing and quality histograms."""
|
|
290
|
+
|
|
291
|
+
# Équivalent MATLAB mfilename / fileparts
|
|
292
|
+
filepath = os.path.dirname(os.path.abspath(__file__))
|
|
293
|
+
meshfile = os.path.join(filepath, "poly_data", "airfoil.msh")
|
|
294
|
+
|
|
295
|
+
node, edge, _, _ = triread(meshfile)
|
|
296
|
+
|
|
297
|
+
print(
|
|
298
|
+
" The smooth routine provides iterative mesh 'smoothing' ca- \n"
|
|
299
|
+
" pabilities, seeking to improve triangulation quality by ad- \n"
|
|
300
|
+
" justing the vertex positions and mesh topology. Specifical- \n"
|
|
301
|
+
" ly, a 'hill-climbing' type optimisation is implemented, gu- \n"
|
|
302
|
+
" aranteeing that mesh-quality is improved monotonically. The \n"
|
|
303
|
+
" DRAWSCR routine provides detailed analysis of triangulation \n"
|
|
304
|
+
" quality, plotting histograms of various quality metrics. \n"
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
olfs = {"dhdx": 0.15}
|
|
308
|
+
|
|
309
|
+
vlfs, tlfs, hlfs = lfshfn(node, edge, [], olfs)
|
|
310
|
+
slfs = idxtri(vlfs, tlfs)
|
|
311
|
+
|
|
312
|
+
hfun = trihfn
|
|
313
|
+
|
|
314
|
+
vert, etri, tria, tnum = refine(node, edge, [], {}, hfun, vlfs, tlfs, slfs, hlfs)
|
|
315
|
+
|
|
316
|
+
plt.figure()
|
|
317
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
318
|
+
plt.gca().set_aspect("equal")
|
|
319
|
+
plt.axis("off")
|
|
320
|
+
|
|
321
|
+
plt.title(f"MESH-REF.: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
322
|
+
|
|
323
|
+
vnew, enew, tnew, tnum = smooth(vert, etri, tria, tnum)
|
|
324
|
+
|
|
325
|
+
plt.figure()
|
|
326
|
+
plt.triplot(vnew[:, 0], vnew[:, 1], tnew[:, 0:3], color=[0.2, 0.2, 0.2])
|
|
327
|
+
plt.gca().set_aspect("equal")
|
|
328
|
+
plt.axis("off")
|
|
329
|
+
|
|
330
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tnew.shape[0]}")
|
|
331
|
+
|
|
332
|
+
hvrt = trihfn(vert, vlfs, tlfs, slfs, hlfs)
|
|
333
|
+
hnew = trihfn(vnew, vlfs, tlfs, slfs, hlfs)
|
|
334
|
+
|
|
335
|
+
tricost(vert, etri, tria, tnum, hvrt)
|
|
336
|
+
tricost(vnew, enew, tnew, tnum, hnew)
|
|
337
|
+
|
|
338
|
+
plt.show()
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def demo5():
|
|
342
|
+
"""Mesh a multi-part geometry with conforming triangulation."""
|
|
343
|
+
|
|
344
|
+
print(
|
|
345
|
+
"Both refine and smooth routines support multi-part geometry\n"
|
|
346
|
+
"definitions, generating conforming triangulations that respect\n"
|
|
347
|
+
"internal and external constraints.\n"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
nod1 = np.array([[-1.0, -1.0], [1.0, -1.0], [1.0, 1.0], [-1.0, 1.0]])
|
|
352
|
+
|
|
353
|
+
edg1 = np.array([[0, 1], [1, 2], [2, 3], [3, 0]], dtype=int)
|
|
354
|
+
tag1 = np.zeros((edg1.shape[0], 1), dtype=int)
|
|
355
|
+
|
|
356
|
+
nod2 = np.array([[0.1, 0.0], [0.8, 0.0], [0.8, 0.8], [0.1, 0.8]])
|
|
357
|
+
|
|
358
|
+
edg2 = np.array([[0, 1], [1, 2], [2, 3], [3, 0]], dtype=int)
|
|
359
|
+
tag2 = np.ones((edg2.shape[0], 1), dtype=int)
|
|
360
|
+
|
|
361
|
+
# Circle geometry
|
|
362
|
+
adel = 2.0 * np.pi / 64.0
|
|
363
|
+
amin = 0.0
|
|
364
|
+
amax = 2.0 * np.pi - adel
|
|
365
|
+
|
|
366
|
+
ang = np.arange(amin, amax + adel / 2, adel)
|
|
367
|
+
xcir = 0.33 * np.cos(ang) - 0.33
|
|
368
|
+
ycir = 0.33 * np.sin(ang) - 0.25
|
|
369
|
+
ncir = np.column_stack((xcir, ycir))
|
|
370
|
+
|
|
371
|
+
numc = ncir.shape[0]
|
|
372
|
+
ecir = np.column_stack((np.arange(numc - 1), np.arange(1, numc)))
|
|
373
|
+
ecir = np.vstack((ecir, [numc - 1, 0]))
|
|
374
|
+
tagc = np.full((ecir.shape[0], 1), 2, dtype=int)
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
# offset inner square indices
|
|
378
|
+
edg2 = edg2 + nod1.shape[0]
|
|
379
|
+
edge = np.vstack((np.hstack((edg1, tag1)), np.hstack((edg2, tag2))))
|
|
380
|
+
node = np.vstack((nod1, nod2))
|
|
381
|
+
|
|
382
|
+
# offset circle indices
|
|
383
|
+
ecir = ecir + node.shape[0]
|
|
384
|
+
edge = np.vstack((edge, np.hstack((ecir, tagc))))
|
|
385
|
+
node = np.vstack((node, ncir))
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
edge_tag = edge[:, 2].astype(int)
|
|
389
|
+
part = [
|
|
390
|
+
np.where((edge_tag == 0) | (edge_tag == 1) | (edge_tag == 2))[0],
|
|
391
|
+
np.where(edge_tag == 1)[0],
|
|
392
|
+
np.where(edge_tag == 2)[0],
|
|
393
|
+
]
|
|
394
|
+
|
|
395
|
+
edge = edge[:, :2].astype(int)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
hmax = 0.045
|
|
399
|
+
vlfs, tlfs, hlfs = lfshfn(node, edge, part)
|
|
400
|
+
hlfs = np.minimum(hmax, hlfs)
|
|
401
|
+
slfs = idxtri(vlfs, tlfs)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
hfun = trihfn
|
|
405
|
+
|
|
406
|
+
vert, etri, tria, tnum = refine(node, edge, part, {}, hfun, vlfs, tlfs, slfs, hlfs)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
vert, etri, tria, tnum = smooth(vert, etri, tria, tnum)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
plt.figure()
|
|
413
|
+
for k, color in zip([1, 2, 3], [[0, 0, 0], [0.1, 0.1, 0.1], [0.2, 0.2, 0.2]]):
|
|
414
|
+
mask = tnum == k
|
|
415
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[mask, :], color=color, linewidth=0.2)
|
|
416
|
+
plt.axis("equal")
|
|
417
|
+
plt.axis("off")
|
|
418
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
419
|
+
|
|
420
|
+
plt.figure()
|
|
421
|
+
tpc = plt.tripcolor(vlfs[:, 0], vlfs[:, 1], tlfs, hlfs, shading="flat")
|
|
422
|
+
plt.colorbar(tpc, label="h")
|
|
423
|
+
plt.axis("equal")
|
|
424
|
+
plt.axis("off")
|
|
425
|
+
plt.title(f"MESH-SIZE: KIND=DELAUNAY, |TRIA|={tlfs.shape[0]}")
|
|
426
|
+
|
|
427
|
+
tricost(vert, etri, tria, tnum)
|
|
428
|
+
|
|
429
|
+
plt.show()
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def demo6():
|
|
433
|
+
"""Mesh a domain with internal edge constraints."""
|
|
434
|
+
|
|
435
|
+
print(
|
|
436
|
+
" Both the refine and smooth routines also support geometr- \n"
|
|
437
|
+
" ies containing 'internal' constraints. \n"
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
node = np.array(
|
|
441
|
+
[
|
|
442
|
+
[-1.0, -1.0],
|
|
443
|
+
[1.0, -1.0],
|
|
444
|
+
[1.0, 1.0],
|
|
445
|
+
[-1.0, 1.0],
|
|
446
|
+
[0.0, 0.0],
|
|
447
|
+
[0.2, 0.7],
|
|
448
|
+
[0.6, 0.2],
|
|
449
|
+
[0.4, 0.8],
|
|
450
|
+
[0.0, 0.5],
|
|
451
|
+
[-0.7, 0.3],
|
|
452
|
+
[-0.1, 0.1],
|
|
453
|
+
[-0.6, 0.5],
|
|
454
|
+
[-0.9, -0.8],
|
|
455
|
+
[-0.6, -0.7],
|
|
456
|
+
[-0.3, -0.6],
|
|
457
|
+
[0.0, -0.5],
|
|
458
|
+
[0.3, -0.4],
|
|
459
|
+
[-0.3, 0.4],
|
|
460
|
+
[-0.1, 0.3],
|
|
461
|
+
]
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
edge = np.array(
|
|
465
|
+
[
|
|
466
|
+
[0, 1],
|
|
467
|
+
[1, 2],
|
|
468
|
+
[2, 3],
|
|
469
|
+
[3, 0],
|
|
470
|
+
[4, 5],
|
|
471
|
+
[4, 6],
|
|
472
|
+
[4, 7],
|
|
473
|
+
[4, 8],
|
|
474
|
+
[4, 9],
|
|
475
|
+
[4, 10],
|
|
476
|
+
[4, 11],
|
|
477
|
+
[4, 12],
|
|
478
|
+
[4, 13],
|
|
479
|
+
[4, 14],
|
|
480
|
+
[4, 15],
|
|
481
|
+
[4, 16],
|
|
482
|
+
[4, 17],
|
|
483
|
+
[4, 18],
|
|
484
|
+
]
|
|
485
|
+
)
|
|
486
|
+
"""
|
|
487
|
+
the geometry must be split into its "exterior" and "int-
|
|
488
|
+
erior" components using the optional PART argument. Each
|
|
489
|
+
PART{I} specified should define the "exterior" boundary
|
|
490
|
+
of a polygonal region. "Interior" constraints should not
|
|
491
|
+
be referenced by any polygon in PART -- they are imposed
|
|
492
|
+
as isolated edge constraints.
|
|
493
|
+
"""
|
|
494
|
+
part = [np.array([0, 1, 2, 3])]
|
|
495
|
+
|
|
496
|
+
hmax = 0.175
|
|
497
|
+
|
|
498
|
+
opts = {"kind": "delaunay"}
|
|
499
|
+
|
|
500
|
+
vert, etri, tria, tnum = refine(node, edge, part, opts, hmax)
|
|
501
|
+
|
|
502
|
+
vert, etri, tria, tnum = smooth(vert, etri, tria, tnum)
|
|
503
|
+
|
|
504
|
+
plt.figure()
|
|
505
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, :3], color="k", linewidth=0.2)
|
|
506
|
+
for e in edge:
|
|
507
|
+
plt.plot(node[e, 0], node[e, 1], "k", linewidth=1)
|
|
508
|
+
|
|
509
|
+
plt.gca().set_aspect("equal")
|
|
510
|
+
plt.axis("off")
|
|
511
|
+
plt.title(f"MESH-OPT.: KIND=DELAUNAY, |TRIA|={tria.shape[0]}")
|
|
512
|
+
|
|
513
|
+
tricost(vert, etri, tria, tnum)
|
|
514
|
+
|
|
515
|
+
plt.show()
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def demo7():
|
|
519
|
+
"""Demonstrate quadtree-style refinement via :func:`~bluemesh2d.mesh_util.tridiv.tridiv`."""
|
|
520
|
+
|
|
521
|
+
filename = __file__
|
|
522
|
+
filepath = "/".join(filename.split("/")[:-1])
|
|
523
|
+
meshfile = f"{filepath}/poly_data/channel.msh"
|
|
524
|
+
|
|
525
|
+
node, edge, _, _ = triread(meshfile)
|
|
526
|
+
|
|
527
|
+
print(
|
|
528
|
+
" The tridiv routine can also be used to refine existing tr- \n"
|
|
529
|
+
" angulations. Each triangle is split into four new sub-tria- \n"
|
|
530
|
+
" ngles, such that element shape is preserved. Combining the \n"
|
|
531
|
+
" tridiv and smooth routines allows for hierarchies of high \n"
|
|
532
|
+
" quality triangulations to be generated. \n"
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
vlfs, tlfs, hlfs = lfshfn(node, edge)
|
|
536
|
+
slfs = idxtri(vlfs, tlfs)
|
|
537
|
+
|
|
538
|
+
pmax = np.max(node, axis=0)
|
|
539
|
+
pmin = np.min(node, axis=0)
|
|
540
|
+
|
|
541
|
+
hmax = np.mean(pmax - pmin) / 17.0
|
|
542
|
+
hlfs = np.minimum(hmax, hlfs)
|
|
543
|
+
|
|
544
|
+
hfun = trihfn
|
|
545
|
+
|
|
546
|
+
vert, etri, tria, tnum = refine(node, edge, [], {}, hfun, vlfs, tlfs, slfs, hlfs)
|
|
547
|
+
|
|
548
|
+
vert, etri, tria, tnum = smooth(vert, etri, tria, tnum)
|
|
549
|
+
vnew, enew, tnew, tnum = tridiv(vert, etri, tria, tnum)
|
|
550
|
+
vnew, enew, tnew, tnum = smooth(vnew, enew, tnew, tnum)
|
|
551
|
+
|
|
552
|
+
plt.figure()
|
|
553
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, :3], color="k")
|
|
554
|
+
|
|
555
|
+
plt.gca().set_aspect("equal")
|
|
556
|
+
plt.axis("off")
|
|
557
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
558
|
+
|
|
559
|
+
plt.figure()
|
|
560
|
+
plt.triplot(vnew[:, 0], vnew[:, 1], tnew[:, :3], color="k")
|
|
561
|
+
|
|
562
|
+
plt.gca().set_aspect("equal")
|
|
563
|
+
plt.axis("off")
|
|
564
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tnew.shape[0]}")
|
|
565
|
+
|
|
566
|
+
tricost(vert, etri, tria, tnum)
|
|
567
|
+
tricost(vnew, enew, tnew, tnum)
|
|
568
|
+
|
|
569
|
+
plt.show()
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
def demo8():
|
|
573
|
+
"""Demonstrate a custom Gaussian mesh-size function."""
|
|
574
|
+
|
|
575
|
+
node = np.array([[-1.0, -1.0], [3.0, -1.0], [3.0, 1.0], [-1.0, 1.0]])
|
|
576
|
+
edge = np.array([[0, 1], [1, 2], [2, 3], [3, 0]])
|
|
577
|
+
|
|
578
|
+
adel = 2.0 * np.pi / 64.0
|
|
579
|
+
amin = 0.0 * np.pi
|
|
580
|
+
amax = 2.0 * np.pi - adel
|
|
581
|
+
|
|
582
|
+
angles = np.arange(amin, amax + adel, adel)
|
|
583
|
+
xcir = 0.20 * np.cos(angles)
|
|
584
|
+
ycir = 0.20 * np.sin(angles)
|
|
585
|
+
ncir = np.column_stack([xcir, ycir])
|
|
586
|
+
numc = ncir.shape[0]
|
|
587
|
+
|
|
588
|
+
ecir = np.zeros((numc, 2), dtype=int)
|
|
589
|
+
ecir[:, 0] = np.arange(numc)
|
|
590
|
+
ecir[:, 1] = np.roll(ecir[:, 0], -1)
|
|
591
|
+
|
|
592
|
+
ecir = ecir + node.shape[0]
|
|
593
|
+
edge = np.vstack([edge, ecir])
|
|
594
|
+
node = np.vstack([node, ncir])
|
|
595
|
+
|
|
596
|
+
hfun = hfun8
|
|
597
|
+
|
|
598
|
+
vert, etri, tria, tnum = refine(node, edge, [], {}, hfun)
|
|
599
|
+
|
|
600
|
+
vert, etri, tria, tnum = smooth(vert, etri, tria, tnum)
|
|
601
|
+
|
|
602
|
+
plt.figure()
|
|
603
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, :3], color="k")
|
|
604
|
+
|
|
605
|
+
plt.gca().set_aspect("equal")
|
|
606
|
+
plt.axis("off")
|
|
607
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
608
|
+
|
|
609
|
+
plt.figure()
|
|
610
|
+
facecolors = np.mean(hfun8(vert)[tria[:, :3]], axis=1)
|
|
611
|
+
plt.tripcolor(
|
|
612
|
+
vert[:, 0],
|
|
613
|
+
vert[:, 1],
|
|
614
|
+
tria[:, :3],
|
|
615
|
+
facecolors=facecolors,
|
|
616
|
+
edgecolors="none",
|
|
617
|
+
cmap="viridis",
|
|
618
|
+
)
|
|
619
|
+
plt.gca().set_aspect("equal")
|
|
620
|
+
plt.axis("off")
|
|
621
|
+
plt.title("MESH-SIZE function.")
|
|
622
|
+
|
|
623
|
+
hvrt = hfun(vert)
|
|
624
|
+
tricost(vert, etri, tria, tnum, hvrt)
|
|
625
|
+
|
|
626
|
+
plt.show()
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def hfun8(test):
|
|
630
|
+
"""Return a Gaussian mesh-size field for demo 8.
|
|
631
|
+
|
|
632
|
+
Parameters
|
|
633
|
+
----------
|
|
634
|
+
test : ndarray of shape (N, 2)
|
|
635
|
+
Evaluation coordinates.
|
|
636
|
+
|
|
637
|
+
Returns
|
|
638
|
+
-------
|
|
639
|
+
hfun : ndarray of shape (N,)
|
|
640
|
+
Mesh-size values at ``test``.
|
|
641
|
+
"""
|
|
642
|
+
hmax = 0.05
|
|
643
|
+
hmin = 0.01
|
|
644
|
+
|
|
645
|
+
xmid = 0.0
|
|
646
|
+
ymid = 0.0
|
|
647
|
+
|
|
648
|
+
hcir = np.exp(-0.5 * (test[:, 0] - xmid) ** 2 - 2.0 * (test[:, 1] - ymid) ** 2)
|
|
649
|
+
|
|
650
|
+
hfun = hmax - (hmax - hmin) * hcir
|
|
651
|
+
|
|
652
|
+
return hfun
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
def demo9():
|
|
656
|
+
"""Run large-scale mesh refinement and optimization on the islands geometry."""
|
|
657
|
+
|
|
658
|
+
filename = __file__ # current file path
|
|
659
|
+
filepath = "/".join(filename.split("/")[:-1])
|
|
660
|
+
meshfile = f"{filepath}/poly_data/islands.msh"
|
|
661
|
+
|
|
662
|
+
# Load input mesh geometry
|
|
663
|
+
node, edge, _, _ = triread(meshfile)
|
|
664
|
+
|
|
665
|
+
vlfs, tlfs, hlfs = lfshfn(node, edge)
|
|
666
|
+
slfs = idxtri(vlfs, tlfs)
|
|
667
|
+
|
|
668
|
+
hfun = trihfn
|
|
669
|
+
vert, etri, tria, tnum = refine(node, edge, [], {}, hfun, vlfs, tlfs, slfs, hlfs)
|
|
670
|
+
|
|
671
|
+
vert, etri, tria, tnum = smooth(vert, etri, tria, tnum)
|
|
672
|
+
|
|
673
|
+
plt.figure()
|
|
674
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, :3], color="k")
|
|
675
|
+
plt.gca().set_aspect("equal")
|
|
676
|
+
plt.axis("off")
|
|
677
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
678
|
+
|
|
679
|
+
tricost(vert, etri, tria, tnum)
|
|
680
|
+
|
|
681
|
+
plt.show()
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
def demo10():
|
|
685
|
+
"""Run medium-scale mesh refinement and optimization on the river geometry."""
|
|
686
|
+
|
|
687
|
+
filename = __file__
|
|
688
|
+
filepath = "/".join(filename.split("/")[:-1])
|
|
689
|
+
meshfile = f"{filepath}/poly_data/river.msh"
|
|
690
|
+
|
|
691
|
+
node, edge, _, _ = triread(meshfile)
|
|
692
|
+
|
|
693
|
+
vlfs, tlfs, hlfs = lfshfn(node, edge)
|
|
694
|
+
slfs = idxtri(vlfs, tlfs)
|
|
695
|
+
|
|
696
|
+
hfun = trihfn
|
|
697
|
+
vert, etri, tria, tnum = refine(node, edge, [], {}, hfun, vlfs, tlfs, slfs, hlfs)
|
|
698
|
+
|
|
699
|
+
vert, etri, tria, tnum = smooth(vert, etri, tria, tnum)
|
|
700
|
+
|
|
701
|
+
plt.figure()
|
|
702
|
+
plt.triplot(vert[:, 0], vert[:, 1], tria[:, :3], color="k")
|
|
703
|
+
plt.gca().set_aspect("equal")
|
|
704
|
+
plt.axis("off")
|
|
705
|
+
plt.title(f"MESH-OPT.: KIND=DELFRONT, |TRIA|={tria.shape[0]}")
|
|
706
|
+
|
|
707
|
+
tricost(vert, etri, tria, tnum)
|
|
708
|
+
|
|
709
|
+
plt.show()
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
if __name__ == "__main__":
|
|
713
|
+
if len(sys.argv) < 2:
|
|
714
|
+
print("Usage: python -m examples.tridemo <demo_number>")
|
|
715
|
+
sys.exit(1)
|
|
716
|
+
|
|
717
|
+
try:
|
|
718
|
+
demo_number = int(sys.argv[1])
|
|
719
|
+
except ValueError:
|
|
720
|
+
print("Error: <demo_number> must be an integer.")
|
|
721
|
+
sys.exit(1)
|
|
722
|
+
|
|
723
|
+
tridemo(demo_number)
|