ddfem 1.0.0__py3-none-any.whl → 1.0.1__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.
- ddfem/__init__.py +4 -0
- ddfem/boundary.py +12 -3
- ddfem/examples/__init__.py +0 -0
- ddfem/examples/advection_diffusion.py +74 -0
- ddfem/examples/beam.py +147 -0
- ddfem/examples/cahn_hilliard.py +67 -0
- ddfem/examples/chemical_reaction.py +88 -0
- ddfem/examples/constant.py +46 -0
- ddfem/examples/five_circle_flat.py +197 -0
- ddfem/examples/forchheimer.py +48 -0
- ddfem/examples/hyperelasticity.py +88 -0
- ddfem/examples/linear_elasticity.py +45 -0
- ddfem/examples/plaplace.py +29 -0
- ddfem/examples/single_circle.py +135 -0
- ddfem/examples/triple_circle.py +217 -0
- ddfem/examples/triple_circle_beam.py +208 -0
- ddfem/geometry/__init__.py +3 -3
- ddfem/geometry/arc.py +10 -8
- ddfem/geometry/ball.py +24 -0
- ddfem/geometry/box.py +7 -8
- ddfem/geometry/domain.py +16 -4
- ddfem/geometry/domain_dune.py +16 -0
- ddfem/geometry/helpers.py +19 -12
- ddfem/geometry/pie.py +7 -7
- ddfem/geometry/plane.py +20 -0
- ddfem/geometry/primitive_base.py +129 -70
- ddfem/geometry/vesica.py +7 -6
- ddfem/model2ufl.py +10 -4
- ddfem/transformers/DDM1.py +10 -68
- ddfem/transformers/Fitted.py +22 -12
- ddfem/transformers/Mix0.py +10 -64
- ddfem/transformers/NNS.py +11 -72
- ddfem/transformers/NS.py +14 -79
- ddfem/transformers/__init__.py +1 -0
- ddfem/transformers/transformer_base.py +102 -15
- {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/METADATA +2 -6
- ddfem-1.0.1.dist-info/RECORD +41 -0
- ddfem/base_model.py +0 -200
- ddfem/geometry/circle.py +0 -39
- ddfem-1.0.0.dist-info/RECORD +0 -27
- {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/WHEEL +0 -0
- {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {ddfem-1.0.0.dist-info → ddfem-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
from dune.ufl import Constant
|
2
|
+
from ufl import as_vector, div, exp, grad, inner, sqrt
|
3
|
+
|
4
|
+
from ddfem.boundary import BndFlux_v, BndValue
|
5
|
+
|
6
|
+
|
7
|
+
def fhModel(inverted):
|
8
|
+
class Model:
|
9
|
+
dimRange = 1
|
10
|
+
outFactor_i = Constant(1, "outFactor")
|
11
|
+
|
12
|
+
def initial(x):
|
13
|
+
return 1 / 2 * (x[0] ** 2 + x[1] ** 2) - 1 / 3 * (x[0] ** 3 - x[1] ** 3) + 1
|
14
|
+
|
15
|
+
def exact(t, x):
|
16
|
+
return as_vector([exp(-2 * t) * (Model.initial(x) - 1) + 1])
|
17
|
+
|
18
|
+
def K(U, DU):
|
19
|
+
# DU = exp(-2 * t) * (x[0] - x[0]^2, x[1] + x[1]^2)
|
20
|
+
return 2 / (1 + sqrt(1 + 4 * sqrt(inner(DU, DU))))
|
21
|
+
|
22
|
+
def F_v(t, x, U, DU):
|
23
|
+
return Model.K(U, DU) * DU
|
24
|
+
|
25
|
+
def S_i(t, x, U, DU):
|
26
|
+
return -div(
|
27
|
+
Model.F_v(t, x, Model.exact(t, x), grad(Model.exact(t, x)))
|
28
|
+
) + as_vector([-2 * exp(-2 * t) * (Model.initial(x) - 1)])
|
29
|
+
|
30
|
+
valD = BndValue(lambda t, x, U: Model.exact(t, x))
|
31
|
+
|
32
|
+
valN = BndFlux_v(
|
33
|
+
lambda t, x, U, DU, n: Model.F_v(
|
34
|
+
t, x, Model.exact(t, x), grad(Model.exact(t, x))
|
35
|
+
)
|
36
|
+
* n
|
37
|
+
)
|
38
|
+
|
39
|
+
boundary = {
|
40
|
+
"sides": valD,
|
41
|
+
"ends": valN,
|
42
|
+
}
|
43
|
+
|
44
|
+
if inverted:
|
45
|
+
for i in range(1, 5):
|
46
|
+
boundary[i] = valD
|
47
|
+
|
48
|
+
return Model
|
@@ -0,0 +1,88 @@
|
|
1
|
+
from dune.ufl import Constant
|
2
|
+
from ufl import (
|
3
|
+
Identity,
|
4
|
+
as_vector,
|
5
|
+
conditional,
|
6
|
+
det,
|
7
|
+
diff,
|
8
|
+
div,
|
9
|
+
dot,
|
10
|
+
grad,
|
11
|
+
ln,
|
12
|
+
nabla_div,
|
13
|
+
nabla_grad,
|
14
|
+
outer,
|
15
|
+
replace,
|
16
|
+
sym,
|
17
|
+
tr,
|
18
|
+
variable,
|
19
|
+
zero,
|
20
|
+
)
|
21
|
+
from ufl.algorithms.ad import expand_derivatives
|
22
|
+
|
23
|
+
from ddfem.boundary import BndFlux_v, BndValue
|
24
|
+
|
25
|
+
|
26
|
+
def hyModel():
|
27
|
+
# https://jsdokken.com/dolfinx-tutorial/chapter2/hyperelasticity.html
|
28
|
+
class Model:
|
29
|
+
dimRange = 2
|
30
|
+
rho = Constant(1000, name="density") # kg/m3
|
31
|
+
g = Constant(9.8, name="gravity") # m/s2
|
32
|
+
|
33
|
+
body = Constant([0.0, -rho * g], "body") # N/m3
|
34
|
+
vd = Constant([0, 0], "fixedboundary")
|
35
|
+
T = Constant([0, 0], "traction") # Pa
|
36
|
+
|
37
|
+
outFactor_i = Constant(1, "outFactor")
|
38
|
+
|
39
|
+
# Elasticity parameters
|
40
|
+
# https://www.efunda.com/formulae/solid_mechanics/mat_mechanics/calc_elastic_constants.cfm
|
41
|
+
E = 1e7 # Young modulus ; Pa
|
42
|
+
nu = 0.4 # Poisson ratio ;
|
43
|
+
lamb = Constant(E * nu / ((1 + nu) * (1 - 2 * nu)), name="Lame_1") # Pa
|
44
|
+
mu = Constant(E / (2 * (1 + nu)), name="Lame_2") # i.e. Shear modulus ; Pa
|
45
|
+
|
46
|
+
def P(U, DU):
|
47
|
+
I = Identity(Model.dimRange)
|
48
|
+
# Stress
|
49
|
+
# Hyper-elasticity, (compressible neo-Hookean model)
|
50
|
+
F = variable(I + grad(U)) # Deformation gradient
|
51
|
+
C = F.T * F # Right Cauchy-Green tensor
|
52
|
+
J = det(F)
|
53
|
+
Ic = tr(C) # First Invariant
|
54
|
+
mu = Model.mu
|
55
|
+
lamb = Model.lamb
|
56
|
+
psi = (mu / 2) * (Ic - 3) - mu * ln(J) + (lamb / 2) * (ln(J)) ** 2
|
57
|
+
|
58
|
+
p = diff(psi, F)
|
59
|
+
p = expand_derivatives(p)
|
60
|
+
p = replace(p, {F: I + DU})
|
61
|
+
# p = replace(p, {F: I + grad(U)})
|
62
|
+
|
63
|
+
# Linear-elasticity
|
64
|
+
# p = lamb * tr(sym(DU)) * I + 2 * mu * sym(DU)
|
65
|
+
|
66
|
+
return p
|
67
|
+
|
68
|
+
def F_v(t, x, U, DU):
|
69
|
+
return Model.P(U, DU)
|
70
|
+
|
71
|
+
def S_i(t, x, U, DU):
|
72
|
+
return Model.body
|
73
|
+
|
74
|
+
valD = lambda t, x, U: Model.vd
|
75
|
+
|
76
|
+
valN = lambda t, x, U, DU, n: Model.T
|
77
|
+
|
78
|
+
boundary = {
|
79
|
+
"left": BndValue(valD),
|
80
|
+
"other": BndFlux_v(valN),
|
81
|
+
}
|
82
|
+
# boundary = {
|
83
|
+
# "left": BndValue(valD),
|
84
|
+
# "right": BndFlux_v(valN),
|
85
|
+
# "bulk": BndFlux_v(valN),
|
86
|
+
# }
|
87
|
+
|
88
|
+
return Model
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from dune.ufl import Constant
|
2
|
+
from ufl import Identity, as_vector, div, grad, sym, tr, zero
|
3
|
+
|
4
|
+
from ddfem.boundary import BndFlux_v, BndValue
|
5
|
+
|
6
|
+
|
7
|
+
def leModel():
|
8
|
+
class Model:
|
9
|
+
dimRange = 2
|
10
|
+
lamb = Constant(0.1, name="Lame_1")
|
11
|
+
mu = Constant(1, name="Lame_2")
|
12
|
+
rho = Constant(1 / 1000, name="density")
|
13
|
+
g = Constant(9.8, name="gravity")
|
14
|
+
|
15
|
+
outFactor_i = Constant(1, "outFactor")
|
16
|
+
|
17
|
+
vd = Constant([0, 0], "stationary")
|
18
|
+
vn = Constant([0, 0], "traction")
|
19
|
+
|
20
|
+
I = Identity(dimRange)
|
21
|
+
|
22
|
+
def sigma(U, DU):
|
23
|
+
return Model.lamb * tr(sym(DU)) * Model.I + 2 * Model.mu * sym(DU)
|
24
|
+
|
25
|
+
def F_v(t, x, U, DU):
|
26
|
+
return Model.sigma(U, DU)
|
27
|
+
|
28
|
+
def S_i(t, x, U, DU):
|
29
|
+
return as_vector([0.0, -Model.rho * Model.g])
|
30
|
+
|
31
|
+
valD = lambda t, x, U: Model.vd
|
32
|
+
|
33
|
+
valN = lambda t, x, U, DU, n: Model.vn
|
34
|
+
|
35
|
+
# boundary = {
|
36
|
+
# "left": BndValue(valD),
|
37
|
+
# "other": BndFlux_v(valN),
|
38
|
+
# }
|
39
|
+
boundary = {
|
40
|
+
"left": BndValue(valD),
|
41
|
+
"right": BndFlux_v(valN),
|
42
|
+
"bulk": BndFlux_v(valN),
|
43
|
+
}
|
44
|
+
|
45
|
+
return Model
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from dune.ufl import Constant
|
2
|
+
from ufl import grad, inner
|
3
|
+
|
4
|
+
from ddfem.boundary import BndValue
|
5
|
+
|
6
|
+
|
7
|
+
def pModel(power):
|
8
|
+
class Model:
|
9
|
+
dimRange = 1
|
10
|
+
ep = Constant(1e-5, name="ep")
|
11
|
+
f = Constant([1], name="f")
|
12
|
+
g = Constant([0], name="g")
|
13
|
+
p = Constant(power, name="p") # p for p-Laplacian
|
14
|
+
assert p.value > 1 and p.value < 2**16
|
15
|
+
outFactor_i = Constant(1, "outFactor")
|
16
|
+
|
17
|
+
def K(u):
|
18
|
+
return (Model.ep**2 + inner(grad(u), grad(u))) ** ((Model.p - 2) / 2)
|
19
|
+
|
20
|
+
def F_v(t, x, U, DU):
|
21
|
+
return Model.K(U) * DU
|
22
|
+
|
23
|
+
def S_i(t, x, U, DU):
|
24
|
+
return Model.f - U
|
25
|
+
|
26
|
+
bc = BndValue(g)
|
27
|
+
boundary = {1: bc, 2: bc, 3: bc, 4: bc, "full": bc}
|
28
|
+
|
29
|
+
return Model
|
@@ -0,0 +1,135 @@
|
|
1
|
+
import numpy as np
|
2
|
+
try:
|
3
|
+
import pygmsh
|
4
|
+
except ImportError:
|
5
|
+
pygmsh = None
|
6
|
+
|
7
|
+
try:
|
8
|
+
import dune
|
9
|
+
except ImportError:
|
10
|
+
print("""
|
11
|
+
Example code requires dune to run. To install run
|
12
|
+
pip install dune-fem
|
13
|
+
""")
|
14
|
+
|
15
|
+
from ddfem import geometry as gm
|
16
|
+
from ddfem.geometry.domain_dune import DomainDune
|
17
|
+
|
18
|
+
from dune.alugrid import aluConformGrid as leafGridView
|
19
|
+
from dune.fem.view import adaptiveLeafGridView
|
20
|
+
from dune.grid import cartesianDomain
|
21
|
+
from dune.ufl import Constant, Space
|
22
|
+
|
23
|
+
from ufl import SpatialCoordinate, sqrt
|
24
|
+
|
25
|
+
def getDomain(initialRefine, version, inverted, adaptLevels=0, epsFactor=4.5):
|
26
|
+
|
27
|
+
shiftx, shifty = sqrt(2) * 1e-6, sqrt(3) * 1e-6
|
28
|
+
domain_range = [[-0.5 + shiftx, -0.5 + shifty], [0.5 + shiftx, 0.5 + shifty]]
|
29
|
+
initial_gridsize = [75 * 2**initialRefine] * 2
|
30
|
+
h = sqrt(
|
31
|
+
((domain_range[1][0] - domain_range[0][0]) / initial_gridsize[0]) ** 2
|
32
|
+
+ ((domain_range[1][1] - domain_range[0][1]) / initial_gridsize[1]) ** 2
|
33
|
+
)
|
34
|
+
epsilon = Constant(epsFactor * h * 0.5 ** (adaptLevels / 2), "epsilon")
|
35
|
+
|
36
|
+
print(f"h={h * 0.5 ** (adaptLevels / 2)}, epsilon={epsilon.value}")
|
37
|
+
|
38
|
+
circles = [
|
39
|
+
[0.3, [0.15, 0.15], "b1"],
|
40
|
+
[0.3, [-0.15, -0.15], "b2"],
|
41
|
+
[0.4, [0, 0], "b3"],
|
42
|
+
]
|
43
|
+
|
44
|
+
b = [gm.Ball(c[0], c[1], epsilon=epsilon, name=c[2]) for c in circles]
|
45
|
+
sdfs = [b[0] | b[1], b[2]]
|
46
|
+
sdfs[0].name = "sides"
|
47
|
+
sdfs[1].name = "ends"
|
48
|
+
omega = b[2] # sdfs[0] & sdfs[1]
|
49
|
+
if inverted:
|
50
|
+
omega = omega.invert()
|
51
|
+
omega.name = "full"
|
52
|
+
|
53
|
+
x = SpatialCoordinate(Space(2))
|
54
|
+
sdf = omega(x)
|
55
|
+
|
56
|
+
def spacing(x, y):
|
57
|
+
r_min = 2*epsilon.value
|
58
|
+
r_max = 32 * epsilon.value
|
59
|
+
dist = np.abs(sdf((x, y)))
|
60
|
+
if dist <= r_min:
|
61
|
+
return geom.characteristic_length_min
|
62
|
+
elif dist >= r_max:
|
63
|
+
return geom.characteristic_length_max
|
64
|
+
else:
|
65
|
+
# Linear
|
66
|
+
m = (geom.characteristic_length_max - geom.characteristic_length_min) / (
|
67
|
+
r_max - r_min
|
68
|
+
)
|
69
|
+
return m * (dist - r_min) + geom.characteristic_length_min
|
70
|
+
|
71
|
+
if version == "cartesian":
|
72
|
+
domain = cartesianDomain(*domain_range, initial_gridsize)
|
73
|
+
|
74
|
+
elif version == "fitted":
|
75
|
+
if pygmsh is None:
|
76
|
+
raise AttributeError("'fitted' requires install pygmsh")
|
77
|
+
with pygmsh.occ.Geometry() as geom:
|
78
|
+
geom.characteristic_length_max = h
|
79
|
+
geom.characteristic_length_min = h
|
80
|
+
|
81
|
+
disks = geom.add_disk([circles[2][1][0], circles[2][1][1], 0.0], circles[2][0])
|
82
|
+
# [geom.add_disk([c[1][0], c[1][1], 0.0], c[0]) for c in circles]
|
83
|
+
|
84
|
+
# ds = geom.boolean_union([disks[0], disks[1]])
|
85
|
+
shape = disks # geom.boolean_intersection([ds, disks[2]])
|
86
|
+
if inverted:
|
87
|
+
rectangle = geom.add_rectangle(
|
88
|
+
[domain_range[0][0], domain_range[0][1], 0.0],
|
89
|
+
domain_range[1][0] - domain_range[0][0],
|
90
|
+
domain_range[1][1] - domain_range[0][1],
|
91
|
+
)
|
92
|
+
geom.boolean_difference(rectangle, shape)
|
93
|
+
|
94
|
+
geom.set_mesh_size_callback(
|
95
|
+
lambda dim, tag, x, y, z, lc: spacing(x, y),
|
96
|
+
ignore_other_mesh_sizes=True,
|
97
|
+
)
|
98
|
+
mesh = geom.generate_mesh()
|
99
|
+
points, cells = mesh.points, mesh.cells_dict
|
100
|
+
domain = {
|
101
|
+
"vertices": points[:, :2].astype(float),
|
102
|
+
"simplices": cells["triangle"].astype(int),
|
103
|
+
}
|
104
|
+
|
105
|
+
elif version == "adaptive":
|
106
|
+
if pygmsh is None:
|
107
|
+
raise AttributeError("'adaptive' requires install pygmsh")
|
108
|
+
with pygmsh.occ.Geometry() as geom:
|
109
|
+
geom.characteristic_length_max = h
|
110
|
+
geom.characteristic_length_min = h
|
111
|
+
|
112
|
+
geom.add_rectangle(
|
113
|
+
[domain_range[0][0], domain_range[0][1], 0.0],
|
114
|
+
domain_range[1][0] - domain_range[0][0],
|
115
|
+
domain_range[1][1] - domain_range[0][1],
|
116
|
+
)
|
117
|
+
|
118
|
+
geom.set_mesh_size_callback(
|
119
|
+
lambda dim, tag, x, y, z, lc: spacing(x, y),
|
120
|
+
ignore_other_mesh_sizes=True,
|
121
|
+
)
|
122
|
+
mesh = geom.generate_mesh()
|
123
|
+
points, cells = mesh.points, mesh.cells_dict
|
124
|
+
domain = {
|
125
|
+
"vertices": points[:, :2].astype(float),
|
126
|
+
"simplices": cells["triangle"].astype(int),
|
127
|
+
}
|
128
|
+
|
129
|
+
gridView = adaptiveLeafGridView(leafGridView(domain))
|
130
|
+
|
131
|
+
domain = DomainDune(omega, x, gridView)
|
132
|
+
domain.adapt(level=adaptLevels)
|
133
|
+
gridView.plot()
|
134
|
+
|
135
|
+
return gridView, domain
|
@@ -0,0 +1,217 @@
|
|
1
|
+
import numpy as np
|
2
|
+
|
3
|
+
try:
|
4
|
+
import pygmsh
|
5
|
+
except ImportError:
|
6
|
+
pygmsh = None
|
7
|
+
|
8
|
+
try:
|
9
|
+
import dune
|
10
|
+
except ImportError:
|
11
|
+
print(
|
12
|
+
"""
|
13
|
+
Example code requires dune to run. To install run
|
14
|
+
pip install dune-fem
|
15
|
+
"""
|
16
|
+
)
|
17
|
+
|
18
|
+
from dune.alugrid import aluConformGrid as leafGridView
|
19
|
+
from dune.fem import adapt, mark, markNeighbors
|
20
|
+
from dune.fem.function import gridFunction
|
21
|
+
from dune.fem.space import lagrange
|
22
|
+
from dune.fem.view import adaptiveLeafGridView
|
23
|
+
from dune.grid import cartesianDomain
|
24
|
+
from dune.ufl import Constant, Space
|
25
|
+
from ufl import SpatialCoordinate, sqrt
|
26
|
+
|
27
|
+
from ddfem import geometry as gm
|
28
|
+
from ddfem.geometry.domain_dune import DomainDune
|
29
|
+
|
30
|
+
|
31
|
+
def getDomain(
|
32
|
+
initialRefine, version, inverted, adaptLevels=0, epsFactor=4.5, smoothing=None
|
33
|
+
):
|
34
|
+
|
35
|
+
gm.SDF.smoothing = smoothing
|
36
|
+
shiftx, shifty = sqrt(2) * 1e-6, sqrt(3) * 1e-6
|
37
|
+
domain_range = [[-0.5 + shiftx, -0.5 + shifty], [0.5 + shiftx, 0.5 + shifty]]
|
38
|
+
initial_gridsize = [100 * 2**initialRefine] * 2
|
39
|
+
h = sqrt(
|
40
|
+
((domain_range[1][0] - domain_range[0][0]) / initial_gridsize[0]) ** 2
|
41
|
+
+ ((domain_range[1][1] - domain_range[0][1]) / initial_gridsize[1]) ** 2
|
42
|
+
)
|
43
|
+
|
44
|
+
def get_eps(h):
|
45
|
+
return Constant(epsFactor * h * 0.5 ** (adaptLevels / 2), "epsilon")
|
46
|
+
|
47
|
+
balls = [
|
48
|
+
[0.3, [0.15, 0.15], "b1"],
|
49
|
+
[0.3, [-0.15, -0.15], "b2"],
|
50
|
+
[0.4, [0, 0], "b3"],
|
51
|
+
]
|
52
|
+
|
53
|
+
b = [gm.Ball(c[0], c[1], name=c[2]) for c in balls]
|
54
|
+
sdfs = [b[0] | b[1], b[2]]
|
55
|
+
sdfs[0].name = "sides"
|
56
|
+
sdfs[1].name = "ends"
|
57
|
+
omega = sdfs[0] & sdfs[1]
|
58
|
+
if inverted:
|
59
|
+
omega = omega.invert()
|
60
|
+
omega.name = "full"
|
61
|
+
|
62
|
+
h_max = h * 3
|
63
|
+
h_min = h / 2
|
64
|
+
radius = 5
|
65
|
+
|
66
|
+
x = SpatialCoordinate(Space(2))
|
67
|
+
sdf = omega(x)
|
68
|
+
|
69
|
+
def spacing(x, y, epsilon):
|
70
|
+
r_min = epsilon.value
|
71
|
+
r_max = radius * epsilon.value
|
72
|
+
dist = np.abs(sdf((x, y)))
|
73
|
+
if dist <= r_min:
|
74
|
+
return geom.characteristic_length_min
|
75
|
+
elif dist >= r_max:
|
76
|
+
return geom.characteristic_length_max
|
77
|
+
else:
|
78
|
+
# Linear
|
79
|
+
m = (geom.characteristic_length_max - geom.characteristic_length_min) / (
|
80
|
+
r_max - r_min
|
81
|
+
)
|
82
|
+
return m * (dist - r_min) + geom.characteristic_length_min
|
83
|
+
|
84
|
+
if version == "cartesian":
|
85
|
+
domain = cartesianDomain(*domain_range, initial_gridsize)
|
86
|
+
epsilon = get_eps(h)
|
87
|
+
|
88
|
+
elif version == "fitted":
|
89
|
+
if pygmsh is None:
|
90
|
+
raise AttributeError("'fitted' requires install pygmsh")
|
91
|
+
with pygmsh.occ.Geometry() as geom:
|
92
|
+
geom.characteristic_length_max = h_max
|
93
|
+
geom.characteristic_length_min = h_min
|
94
|
+
epsilon = get_eps(h_min)
|
95
|
+
|
96
|
+
disks = [geom.add_disk([c[1][0], c[1][1], 0.0], c[0]) for c in balls]
|
97
|
+
|
98
|
+
ds = geom.boolean_union([disks[0], disks[1]])
|
99
|
+
shape = geom.boolean_intersection([ds, disks[2]])
|
100
|
+
if inverted:
|
101
|
+
rectangle = geom.add_rectangle(
|
102
|
+
[domain_range[0][0], domain_range[0][1], 0.0],
|
103
|
+
domain_range[1][0] - domain_range[0][0],
|
104
|
+
domain_range[1][1] - domain_range[0][1],
|
105
|
+
)
|
106
|
+
geom.boolean_difference(rectangle, shape)
|
107
|
+
|
108
|
+
geom.set_mesh_size_callback(
|
109
|
+
lambda dim, tag, x, y, z, lc: spacing(x, y, epsilon),
|
110
|
+
ignore_other_mesh_sizes=True,
|
111
|
+
)
|
112
|
+
mesh = geom.generate_mesh()
|
113
|
+
points, cells = mesh.points, mesh.cells_dict
|
114
|
+
domain = {
|
115
|
+
"vertices": points[:, :2].astype(float),
|
116
|
+
"simplices": cells["triangle"].astype(int),
|
117
|
+
}
|
118
|
+
|
119
|
+
elif version == "dune_adaptive":
|
120
|
+
gridsize = [int(j * h / h_max) for j in initial_gridsize]
|
121
|
+
domain = cartesianDomain(*domain_range, gridsize)
|
122
|
+
|
123
|
+
elif version == "gmsh_adaptive":
|
124
|
+
if pygmsh is None:
|
125
|
+
raise AttributeError("'gmsh_adaptive' requires install pygmsh")
|
126
|
+
with pygmsh.occ.Geometry() as geom:
|
127
|
+
geom.characteristic_length_max = h_max
|
128
|
+
geom.characteristic_length_min = h_min
|
129
|
+
epsilon = get_eps(h_min)
|
130
|
+
|
131
|
+
geom.add_rectangle(
|
132
|
+
[domain_range[0][0], domain_range[0][1], 0.0],
|
133
|
+
domain_range[1][0] - domain_range[0][0],
|
134
|
+
domain_range[1][1] - domain_range[0][1],
|
135
|
+
)
|
136
|
+
|
137
|
+
geom.set_mesh_size_callback(
|
138
|
+
lambda dim, tag, x, y, z, lc: spacing(x, y, epsilon),
|
139
|
+
ignore_other_mesh_sizes=True,
|
140
|
+
)
|
141
|
+
mesh = geom.generate_mesh()
|
142
|
+
points, cells = mesh.points, mesh.cells_dict
|
143
|
+
domain = {
|
144
|
+
"vertices": points[:, :2].astype(float),
|
145
|
+
"simplices": cells["triangle"].astype(int),
|
146
|
+
}
|
147
|
+
|
148
|
+
elif version == "gmsh_embedded":
|
149
|
+
if pygmsh is None:
|
150
|
+
raise AttributeError("'fitted' requires install pygmsh")
|
151
|
+
with pygmsh.occ.Geometry() as geom:
|
152
|
+
geom.characteristic_length_max = h_max
|
153
|
+
geom.characteristic_length_min = h_min
|
154
|
+
epsilon = get_eps(h_min)
|
155
|
+
|
156
|
+
disks = [geom.add_disk([c[1][0], c[1][1], 0.0], c[0]) for c in balls]
|
157
|
+
|
158
|
+
ds = geom.boolean_union([disks[0], disks[1]])
|
159
|
+
shape = geom.boolean_intersection([ds, disks[2]])
|
160
|
+
rectangle = geom.add_rectangle(
|
161
|
+
[domain_range[0][0], domain_range[0][1], 0.0],
|
162
|
+
domain_range[1][0] - domain_range[0][0],
|
163
|
+
domain_range[1][1] - domain_range[0][1],
|
164
|
+
)
|
165
|
+
|
166
|
+
geom.boolean_fragments(rectangle, shape)
|
167
|
+
|
168
|
+
geom.set_mesh_size_callback(
|
169
|
+
lambda dim, tag, x, y, z, lc: spacing(x, y, epsilon),
|
170
|
+
ignore_other_mesh_sizes=True,
|
171
|
+
)
|
172
|
+
mesh = geom.generate_mesh()
|
173
|
+
points, cells = mesh.points, mesh.cells_dict
|
174
|
+
domain = {
|
175
|
+
"vertices": points[:, :2].astype(float),
|
176
|
+
"simplices": cells["triangle"].astype(int),
|
177
|
+
}
|
178
|
+
|
179
|
+
else:
|
180
|
+
raise ValueError("invalid mesh type")
|
181
|
+
|
182
|
+
gridView = adaptiveLeafGridView(leafGridView(domain))
|
183
|
+
|
184
|
+
if version == "dune_adaptive":
|
185
|
+
omega.epsilon = get_eps(h_min)
|
186
|
+
omega.epsilon.value *= radius
|
187
|
+
epsilon_value = omega.epsilon.value
|
188
|
+
|
189
|
+
marker = mark
|
190
|
+
|
191
|
+
refinements = int(2 * np.log2(h_max / h_min))
|
192
|
+
|
193
|
+
region = gridFunction(
|
194
|
+
omega.phi(x) * (1 - omega.phi(x)), gridView=gridView
|
195
|
+
) # interface
|
196
|
+
|
197
|
+
for j in range(1, refinements + 1):
|
198
|
+
|
199
|
+
omega.epsilon.value = epsilon_value * j / refinements
|
200
|
+
marker(region, 0.00247262315663, maxLevel=refinements) # 1 epsilon
|
201
|
+
|
202
|
+
adapt(gridView.hierarchicalGrid)
|
203
|
+
|
204
|
+
h_min = h_max * 0.5 ** (j / 2)
|
205
|
+
epsilon = get_eps(h_min)
|
206
|
+
|
207
|
+
omega.propagate_epsilon(epsilon)
|
208
|
+
domain = omega
|
209
|
+
|
210
|
+
domain = DomainDune(omega, x, gridView)
|
211
|
+
domain.adapt(level=adaptLevels)
|
212
|
+
|
213
|
+
print(
|
214
|
+
f"h_max={h_max}, h_min={h_min * 0.5 ** (adaptLevels / 2)}, epsilon={epsilon.value}"
|
215
|
+
)
|
216
|
+
|
217
|
+
return gridView, domain
|