Skip to content

Commit c1b0ead

Browse files
committed
Deploying to main from @ meshpro/dmsh-dev@be5a161 🚀
0 parents  commit c1b0ead

22 files changed

+350
-0
lines changed

.github/workflows/ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: ci
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
lint:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Check out repo
16+
uses: actions/checkout@v2
17+
- name: Set up Python
18+
uses: actions/setup-python@v2
19+
- name: Run pre-commit
20+
uses: pre-commit/[email protected]
21+
22+
build:
23+
runs-on: ubuntu-latest
24+
strategy:
25+
matrix:
26+
python-version: ["3.7", "3.8", "3.9", "3.10"]
27+
steps:
28+
- uses: actions/setup-python@v2
29+
with:
30+
python-version: ${{ matrix.python-version }}
31+
- uses: actions/checkout@v2
32+
- name: Test with tox
33+
run: |
34+
pip install tox
35+
tox -- --cov dmsh --cov-report xml --cov-report term
36+
- uses: codecov/codecov-action@v1
37+
if: ${{ matrix.python-version == '3.9' }}

README.md

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
<p align="center">
2+
<a href="https://github.com/nschloe/dmsh"><img alt="dmsh" src="https://raw.githubusercontent.com/meshpro/dmsh/main/logo/logo-with-text.svg" width="50%"></a>
3+
<p align="center">The worst mesh generator you'll ever use.</p>
4+
</p>
5+
6+
[![PyPi Version](https://img.shields.io/pypi/v/dmsh.svg?style=flat-square)](https://pypi.org/project/dmsh/)
7+
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/dmsh.svg?style=flat-square)](https://pypi.org/project/dmsh/)
8+
[![GitHub stars](https://img.shields.io/github/stars/nschloe/dmsh.svg?style=flat-square&logo=github&label=Stars&logoColor=white)](https://github.com/nschloe/dmsh)
9+
[![PyPi downloads](https://img.shields.io/pypi/dm/dmsh.svg?style=flat-square)](https://pypistats.org/packages/dmsh)
10+
11+
[![Discord](https://img.shields.io/static/v1?logo=discord&label=chat&message=on%20discord&color=7289da&style=flat-square)](https://discord.gg/PBCCvwHqpv)
12+
13+
Inspired by [distmesh](http://persson.berkeley.edu/distmesh/), dmsh can be slow,
14+
requires a lot of memory, and isn't terribly robust either.
15+
16+
On the plus side,
17+
18+
- it's got a user-friendly interface,
19+
- is pure Python (and hence easily installable on any system), and
20+
- it produces pretty high-quality meshes.
21+
22+
Combined with [optimesh](https://github.com/nschloe/optimesh), dmsh produces the
23+
highest-quality 2D meshes in the west.
24+
25+
### Examples
26+
27+
#### Primitives
28+
29+
| <img alt="circle" src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/circle.svg" width="100%"> | <img alt="circle" src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/rectangle.svg" width="100%"> | <img alt="circle" src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/polygon.svg" width="100%"> |
30+
| :--------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------: |
31+
32+
```python
33+
import dmsh
34+
import meshio
35+
import optimesh
36+
37+
geo = dmsh.Circle([0.0, 0.0], 1.0)
38+
X, cells = dmsh.generate(geo, 0.1)
39+
40+
# optionally optimize the mesh
41+
X, cells = optimesh.optimize_points_cells(X, cells, "CVT (full)", 1.0e-10, 100)
42+
43+
# visualize the mesh
44+
dmsh.show(X, cells, geo)
45+
46+
# and write it to a file
47+
meshio.Mesh(X, {"triangle": cells}).write("circle.vtk")
48+
```
49+
50+
```python
51+
import dmsh
52+
53+
geo = dmsh.Rectangle(-1.0, +2.0, -1.0, +1.0)
54+
X, cells = dmsh.generate(geo, 0.1)
55+
```
56+
57+
```python
58+
import dmsh
59+
60+
geo = dmsh.Polygon(
61+
[
62+
[0.0, 0.0],
63+
[1.1, 0.0],
64+
[1.2, 0.5],
65+
[0.7, 0.6],
66+
[2.0, 1.0],
67+
[1.0, 2.0],
68+
[0.5, 1.5],
69+
]
70+
)
71+
X, cells = dmsh.generate(geo, 0.1)
72+
```
73+
74+
#### Combinations
75+
76+
##### Difference
77+
78+
| <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/moon.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/pacman.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/rectangle-hole-refinement.svg" width="100%"> |
79+
| :-----------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------: |
80+
81+
```python
82+
import dmsh
83+
84+
geo = dmsh.Circle([-0.5, 0.0], 1.0) - dmsh.Circle([+0.5, 0.0], 1.0)
85+
X, cells = dmsh.generate(geo, 0.1)
86+
```
87+
88+
```python
89+
import dmsh
90+
91+
geo = dmsh.Circle([0.0, 0.0], 1.0) - dmsh.Polygon([[0.0, 0.0], [1.5, 0.4], [1.5, -0.4]])
92+
X, cells = dmsh.generate(geo, 0.1, tol=1.0e-10)
93+
```
94+
95+
The following example uses a nonconstant edge length; it depends on the distance to the
96+
circle `c`.
97+
98+
```python
99+
import dmsh
100+
import numpy as np
101+
102+
r = dmsh.Rectangle(-1.0, +1.0, -1.0, +1.0)
103+
c = dmsh.Circle([0.0, 0.0], 0.3)
104+
geo = r - c
105+
106+
X, cells = dmsh.generate(geo, lambda pts: np.abs(c.dist(pts)) / 5 + 0.05, tol=1.0e-10)
107+
```
108+
109+
##### Union
110+
111+
| <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/union-circles.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/union-rectangles.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/union-three-circles.svg" width="100%"> |
112+
| :--------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------: |
113+
114+
```python
115+
import dmsh
116+
117+
geo = dmsh.Circle([-0.5, 0.0], 1.0) + dmsh.Circle([+0.5, 0.0], 1.0)
118+
X, cells = dmsh.generate(geo, 0.15)
119+
```
120+
121+
```python
122+
import dmsh
123+
124+
geo = dmsh.Rectangle(-1.0, +0.5, -1.0, +0.5) + dmsh.Rectangle(-0.5, +1.0, -0.5, +1.0)
125+
X, cells = dmsh.generate(geo, 0.15)
126+
```
127+
128+
```python
129+
import dmsh
130+
import numpy as np
131+
132+
angles = np.pi * np.array([3.0 / 6.0, 7.0 / 6.0, 11.0 / 6.0])
133+
geo = dmsh.Union(
134+
[
135+
dmsh.Circle([np.cos(angles[0]), np.sin(angles[0])], 1.0),
136+
dmsh.Circle([np.cos(angles[1]), np.sin(angles[1])], 1.0),
137+
dmsh.Circle([np.cos(angles[2]), np.sin(angles[2])], 1.0),
138+
]
139+
)
140+
X, cells = dmsh.generate(geo, 0.15)
141+
```
142+
143+
#### Intersection
144+
145+
| <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/intersection-circles.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/intersection-three-circles.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/intersection-circle-halfspace.svg" width="100%"> |
146+
| :---------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------: |
147+
148+
```python
149+
import dmsh
150+
151+
geo = dmsh.Circle([0.0, -0.5], 1.0) & dmsh.Circle([0.0, +0.5], 1.0)
152+
X, cells = dmsh.generate(geo, 0.1, tol=1.0e-10)
153+
```
154+
155+
```python
156+
import dmsh
157+
import numpy as np
158+
159+
angles = np.pi * np.array([3.0 / 6.0, 7.0 / 6.0, 11.0 / 6.0])
160+
geo = dmsh.Intersection(
161+
[
162+
dmsh.Circle([np.cos(angles[0]), np.sin(angles[0])], 1.5),
163+
dmsh.Circle([np.cos(angles[1]), np.sin(angles[1])], 1.5),
164+
dmsh.Circle([np.cos(angles[2]), np.sin(angles[2])], 1.5),
165+
]
166+
)
167+
X, cells = dmsh.generate(geo, 0.1, tol=1.0e-10)
168+
```
169+
170+
The following uses the `HalfSpace` primtive for cutting off a circle.
171+
172+
```python
173+
import dmsh
174+
175+
geo = dmsh.HalfSpace([1.0, 1.0]) & dmsh.Circle([0.0, 0.0], 1.0)
176+
X, cells = dmsh.generate(geo, 0.1)
177+
```
178+
179+
### Rotation, translation, scaling
180+
181+
| <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/rotation.svg" width="100%"> | <img src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/scaling.svg" width="100%"> |
182+
| :---------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------: |
183+
184+
```python
185+
import dmsh
186+
import numpy as np
187+
188+
geo = dmsh.Rotation(dmsh.Rectangle(-1.0, +2.0, -1.0, +1.0), 0.1 * np.pi)
189+
X, cells = dmsh.generate(geo, 0.1, tol=1.0e-10)
190+
```
191+
192+
```python
193+
import dmsh
194+
195+
geo = dmsh.Rectangle(-1.0, +2.0, -1.0, +1.0) + [1.0, 1.0]
196+
X, cells = dmsh.generate(geo, 0.1)
197+
```
198+
199+
```python
200+
import dmsh
201+
202+
geo = dmsh.Rectangle(-1.0, +2.0, -1.0, +1.0) * 2.0
203+
X, cells = dmsh.generate(geo, 0.1, tol=1.0e-5)
204+
```
205+
206+
### Local refinement
207+
208+
<img alt="local-refinement" src="https://raw.githubusercontent.com/meshpro/dmsh/main/plots/local-refinement.svg" width="30%">
209+
210+
All objects can be used to refine the mesh according to the distance to the object;
211+
e.g. a `Path`:
212+
213+
```python
214+
import dmsh
215+
216+
geo = dmsh.Rectangle(0.0, 1.0, 0.0, 1.0)
217+
218+
p1 = dmsh.Path([[0.4, 0.6], [0.6, 0.4]])
219+
220+
221+
def target_edge_length(x):
222+
return 0.03 + 0.1 * p1.dist(x)
223+
224+
225+
X, cells = dmsh.generate(geo, target_edge_length, tol=1.0e-10)
226+
```
227+
228+
### Custom shapes
229+
230+
It is also possible to define your own geometry. Simply create a class derived from
231+
`dmsh.Geometry` that contains a `dist` method and a method to project points onto the
232+
boundary.
233+
234+
```python
235+
import dmsh
236+
import numpy as np
237+
238+
239+
class MyDisk(dmsh.Geometry):
240+
def __init__(self):
241+
self.r = 1.0
242+
self.x0 = [0.0, 0.0]
243+
bounding_box = [-1.0, 1.0, -1.0, 1.0]
244+
feature_points = np.array([[], []]).T
245+
super().__init__(bounding_box, feature_points)
246+
247+
def dist(self, x):
248+
assert x.shape[0] == 2
249+
y = (x.T - self.x0).T
250+
return np.sqrt(np.einsum("i...,i...->...", y, y)) - self.r
251+
252+
def boundary_step(self, x):
253+
# project onto the circle
254+
y = (x.T - self.x0).T
255+
r = np.sqrt(np.einsum("ij,ij->j", y, y))
256+
return ((y / r * self.r).T + self.x0).T
257+
258+
259+
geo = MyDisk()
260+
X, cells = dmsh.generate(geo, 0.1)
261+
```
262+
263+
### Debugging
264+
265+
| ![level-set-poly](https://raw.githubusercontent.com/meshpro/dmsh/main/plots/levelset-polygon.png) | ![level-set-rect-hole](https://raw.githubusercontent.com/meshpro/dmsh/main/plots/levelset-rect-hole.png) |
266+
| :-----------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------: |
267+
268+
dmsh is rather fragile, but sometimes the break-downs are due to an incorrectly defined
269+
geometry. Use
270+
271+
```
272+
geo.show()
273+
```
274+
275+
to inspect the level set function of your domain. (It must be negative inside the
276+
domain and positive outside. The 0-level set forms the domain boundary.)
277+
278+
### Installation
279+
280+
dmsh is [available from the Python Package
281+
Index](https://pypi.org/project/dmsh/), so simply type
282+
283+
```
284+
pip install dmsh
285+
```
286+
287+
to install.
288+
289+
### Testing
290+
291+
To run the dmsh unit tests, check out this repository and type
292+
293+
```
294+
tox
295+
```

logo/logo-with-text.svg

Lines changed: 1 addition & 0 deletions
Loading

plots/circle.svg

Lines changed: 1 addition & 0 deletions
Loading

plots/gmsh-quality.svg

Lines changed: 1 addition & 0 deletions
Loading

plots/gmsh-speed.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)