Skip to content

Commit 6ac9b9d

Browse files
committed
handle restrictions on MeshSequence
1 parent 6a67124 commit 6ac9b9d

6 files changed

+816
-40
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import pytest
2+
3+
from ufl import (
4+
CellVolume,
5+
Coefficient,
6+
FacetArea,
7+
FacetNormal,
8+
FunctionSpace,
9+
Measure,
10+
Mesh,
11+
MeshSequence,
12+
SpatialCoordinate,
13+
TestFunction,
14+
TrialFunction,
15+
div,
16+
grad,
17+
inner,
18+
split,
19+
triangle,
20+
)
21+
from ufl.algorithms import compute_form_data
22+
from ufl.domain import extract_domains
23+
from ufl.finiteelement import FiniteElement, MixedElement
24+
from ufl.pullback import contravariant_piola, identity_pullback
25+
from ufl.sobolevspace import H1, L2, HDiv
26+
27+
28+
def test_mixed_function_space_with_mixed_mesh_cell():
29+
cell = triangle
30+
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
31+
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
32+
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
33+
elem = MixedElement([elem0, elem1, elem2])
34+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
35+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
36+
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
37+
domain = MeshSequence([mesh0, mesh1, mesh2])
38+
V = FunctionSpace(domain, elem)
39+
V0 = FunctionSpace(mesh0, elem0)
40+
V1 = FunctionSpace(mesh1, elem1)
41+
u1 = TrialFunction(V1)
42+
v0 = TestFunction(V0)
43+
f = Coefficient(V, count=1000)
44+
g = Coefficient(V, count=2000)
45+
f0, f1, f2 = split(f)
46+
g0, g1, g2 = split(g)
47+
dx2 = Measure("dx", mesh2)
48+
x1 = SpatialCoordinate(mesh1)
49+
# Assemble (0, 1)-block.
50+
form = x1[1] * f0 * div(g1) * inner(u1, grad(v0)) * dx2(999)
51+
fd = compute_form_data(
52+
form,
53+
do_apply_function_pullbacks=True,
54+
do_apply_integral_scaling=True,
55+
do_apply_geometry_lowering=True,
56+
preserve_geometry_types=(CellVolume, FacetArea),
57+
do_apply_restrictions=True,
58+
do_estimate_degrees=True,
59+
do_split_coefficients=(f, g),
60+
do_assume_single_integral_type=False,
61+
complex_mode=False,
62+
)
63+
(id0,) = fd.integral_data
64+
assert fd.preprocessed_form.arguments() == (v0, u1)
65+
assert fd.reduced_coefficients == [f, g]
66+
assert form.coefficients()[fd.original_coefficient_positions[0]] is f
67+
assert form.coefficients()[fd.original_coefficient_positions[1]] is g
68+
assert id0.domain_integral_type_map[mesh0] == "cell"
69+
assert id0.domain_integral_type_map[mesh1] == "cell"
70+
assert id0.domain_integral_type_map[mesh2] == "cell"
71+
assert id0.domain is mesh2
72+
assert id0.integral_type == "cell"
73+
assert id0.subdomain_id == (999,)
74+
assert fd.original_form.domain_numbering()[id0.domain] == 0
75+
assert id0.integral_coefficients == set([f, g])
76+
assert id0.enabled_coefficients == [True, True]
77+
78+
79+
def test_mixed_function_space_with_mixed_mesh_facet():
80+
cell = triangle
81+
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
82+
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
83+
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
84+
elem = MixedElement([elem0, elem1, elem2])
85+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
86+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
87+
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
88+
domain = MeshSequence([mesh0, mesh1, mesh2])
89+
V = FunctionSpace(domain, elem)
90+
V1 = FunctionSpace(mesh1, elem1)
91+
V2 = FunctionSpace(mesh2, elem2)
92+
u1 = TrialFunction(V1)
93+
v2 = TestFunction(V2)
94+
f = Coefficient(V, count=1000)
95+
g = Coefficient(V, count=2000)
96+
f0, f1, f2 = split(f)
97+
g0, g1, g2 = split(g)
98+
dS1 = Measure("dS", mesh1)
99+
ds2 = Measure("ds", mesh2)
100+
x2 = SpatialCoordinate(mesh2)
101+
# Assemble (2, 1)-block.
102+
form = inner(x2, g1("+")) * g2 * inner(u1("-"), grad(v2)) * dS1(999) + f0("-") * div(
103+
f1
104+
) * inner(div(u1), v2) * ds2(777)
105+
fd = compute_form_data(
106+
form,
107+
do_apply_function_pullbacks=True,
108+
do_apply_integral_scaling=True,
109+
do_apply_geometry_lowering=True,
110+
preserve_geometry_types=(CellVolume, FacetArea),
111+
do_apply_restrictions=True,
112+
do_estimate_degrees=True,
113+
do_split_coefficients=(f, g),
114+
do_assume_single_integral_type=False,
115+
complex_mode=False,
116+
)
117+
(
118+
id0,
119+
id1,
120+
) = fd.integral_data
121+
assert fd.preprocessed_form.arguments() == (v2, u1)
122+
assert fd.reduced_coefficients == [f, g]
123+
assert form.coefficients()[fd.original_coefficient_positions[0]] is f
124+
assert form.coefficients()[fd.original_coefficient_positions[1]] is g
125+
assert id0.domain_integral_type_map[mesh1] == "interior_facet"
126+
assert id0.domain_integral_type_map[mesh2] == "exterior_facet"
127+
assert id0.domain is mesh1
128+
assert id0.integral_type == "interior_facet"
129+
assert id0.subdomain_id == (999,)
130+
assert fd.original_form.domain_numbering()[id0.domain] == 0
131+
assert id0.integral_coefficients == set([g])
132+
assert id0.enabled_coefficients == [False, True]
133+
assert id1.domain_integral_type_map[mesh0] == "interior_facet"
134+
assert id1.domain_integral_type_map[mesh1] == "exterior_facet"
135+
assert id1.domain_integral_type_map[mesh2] == "exterior_facet"
136+
assert id1.domain is mesh2
137+
assert id1.integral_type == "exterior_facet"
138+
assert id1.subdomain_id == (777,)
139+
assert fd.original_form.domain_numbering()[id1.domain] == 1
140+
assert id1.integral_coefficients == set([f])
141+
assert id1.enabled_coefficients == [True, False]
142+
143+
144+
def test_mixed_function_space_with_mixed_mesh_raise():
145+
cell = triangle
146+
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
147+
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
148+
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
149+
elem = MixedElement([elem0, elem1, elem2])
150+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
151+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
152+
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
153+
domain = MeshSequence([mesh0, mesh1, mesh2])
154+
V = FunctionSpace(domain, elem)
155+
f = Coefficient(V, count=1000)
156+
g = Coefficient(V, count=2000)
157+
_, f1, _ = split(f)
158+
_, g1, _ = split(g)
159+
dS1 = Measure("dS", mesh1)
160+
# Make sure that all mixed functions are split when applying default restrictions.
161+
form = div(g1("+")) * div(f1("-")) * dS1
162+
with pytest.raises(RuntimeError) as e_info:
163+
_ = compute_form_data(
164+
form,
165+
do_apply_function_pullbacks=True,
166+
do_apply_integral_scaling=True,
167+
do_apply_geometry_lowering=True,
168+
preserve_geometry_types=(CellVolume, FacetArea),
169+
do_apply_restrictions=True,
170+
do_estimate_degrees=True,
171+
do_split_coefficients=(f,),
172+
do_assume_single_integral_type=False,
173+
complex_mode=False,
174+
)
175+
assert e_info.match("Not expecting a terminal object on a mixed mesh at this stage")
176+
# Make sure that g1 is restricted as f1.
177+
form = div(g1) * div(f1("-")) * dS1
178+
with pytest.raises(ValueError) as e_info:
179+
_ = compute_form_data(
180+
form,
181+
do_apply_function_pullbacks=True,
182+
do_apply_integral_scaling=True,
183+
do_apply_geometry_lowering=True,
184+
preserve_geometry_types=(CellVolume, FacetArea),
185+
do_apply_restrictions=True,
186+
do_estimate_degrees=True,
187+
do_split_coefficients=(f, g),
188+
do_assume_single_integral_type=False,
189+
complex_mode=False,
190+
)
191+
assert e_info.match("Discontinuous type Coefficient must be restricted.")
192+
193+
194+
def test_mixed_function_space_with_mixed_mesh_signature():
195+
cell = triangle
196+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
197+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
198+
dx0 = Measure("dx", mesh0)
199+
dx1 = Measure("dx", mesh1)
200+
n0 = FacetNormal(mesh0)
201+
n1 = FacetNormal(mesh1)
202+
form_a = inner(n1, n1) * dx0(999)
203+
form_b = inner(n0, n0) * dx1(999)
204+
assert form_a.signature() == form_b.signature()
205+
assert extract_domains(form_a) == (mesh0, mesh1)
206+
assert extract_domains(form_b) == (mesh1, mesh0)

0 commit comments

Comments
 (0)