Skip to content

Commit de997e8

Browse files
committed
introduce MixedMesh
1 parent 021589c commit de997e8

File tree

11 files changed

+574
-242
lines changed

11 files changed

+574
-242
lines changed

gem/gem.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
'IndexSum', 'ListTensor', 'Concatenate', 'Delta',
3434
'index_sum', 'partial_indexed', 'reshape', 'view',
3535
'indices', 'as_gem', 'FlexiblyIndexed',
36-
'Inverse', 'Solve', 'extract_type']
36+
'Inverse', 'Solve', 'extract_type', 'extract_variables']
3737

3838

3939
class NodeMeta(type):
@@ -1044,3 +1044,18 @@ def as_gem(expr):
10441044
def extract_type(expressions, klass):
10451045
"""Collects objects of type klass in expressions."""
10461046
return tuple(node for node in traversal(expressions) if isinstance(node, klass))
1047+
1048+
1049+
def extract_variables(expressions):
1050+
"""Collects variables in expressions."""
1051+
variables = set()
1052+
for node in traversal(expressions):
1053+
if isinstance(node, Variable):
1054+
variables.add(node)
1055+
elif isinstance(node, Indexed):
1056+
# Need to go deeper to find variables wrapped in 'VariableIndex's.
1057+
for idx in node.multiindex:
1058+
if isinstance(idx, VariableIndex):
1059+
v, = extract_variables((idx.expression, ))
1060+
variables.add(v)
1061+
return variables
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
from collections import defaultdict
2+
from tsfc import compile_form
3+
from ufl import (triangle, Mesh, MixedMesh, FunctionSpace, TestFunction, TrialFunction, Coefficient,
4+
Measure, SpatialCoordinate, inner, grad, curl, div, split, as_vector, )
5+
from ufl.pullback import identity_pullback, contravariant_piola
6+
from ufl.sobolevspace import H1, HDiv, L2
7+
from finat.ufl import FiniteElement, MixedElement, VectorElement
8+
from tsfc.ufl_utils import compute_form_data
9+
from tsfc import kernel_args
10+
11+
12+
def test_mixed_function_space_with_mixed_mesh_restrictions_base():
13+
cell = triangle
14+
gdim = 2
15+
elem0 = FiniteElement("Discontinuous Lagrange", cell, 2)
16+
elem1 = FiniteElement("Discontinuous Lagrange", cell, 3)
17+
elem = MixedElement([elem0, elem1])
18+
mesh0 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=100)
19+
mesh1 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=101)
20+
domain = MixedMesh(mesh0, mesh1)
21+
V = FunctionSpace(domain, elem)
22+
V0 = FunctionSpace(mesh0, elem0)
23+
V1 = FunctionSpace(mesh1, elem1)
24+
f = Coefficient(V, count=1000)
25+
f0, f1 = split(f)
26+
u0 = TrialFunction(V0)
27+
u1 = TrialFunction(V1)
28+
v0 = TestFunction(V0)
29+
v1 = TestFunction(V1)
30+
dx0 = Measure("dx", mesh0)
31+
dx1 = Measure("dx", mesh1)
32+
ds0 = Measure("ds", mesh0)
33+
ds1 = Measure("ds", mesh1)
34+
dS0 = Measure("dS", mesh0)
35+
dS1 = Measure("dS", mesh1)
36+
f0_split = Coefficient(V0)
37+
f1_split = Coefficient(V1)
38+
# a
39+
form = inner(grad(f1('|')), as_vector([1, 0])) * ds1(777)
40+
form_data = compute_form_data(form, do_split_coefficients={f: [f0_split, f1_split]})
41+
integral_data, = form_data.integral_data
42+
assert len(integral_data.domain_integral_type_map) == 1
43+
assert integral_data.domain_integral_type_map[mesh1] == "exterior_facet"
44+
# b
45+
form = inner(grad(f1('|')), grad(f1('|'))) * dS0(777)
46+
form_data = compute_form_data(form, do_split_coefficients={f: [f0_split, f1_split]})
47+
integral_data, = form_data.integral_data
48+
assert len(integral_data.domain_integral_type_map) == 2
49+
assert integral_data.domain_integral_type_map[mesh0] == "interior_facet"
50+
assert integral_data.domain_integral_type_map[mesh1] == "exterior_facet"
51+
# c
52+
form = div(f) * inner(grad(f1), grad(f1)) * inner(grad(u1), grad(v0)) * dx1
53+
form_data = compute_form_data(form, do_split_coefficients={f: [f0_split, f1_split]})
54+
integral_data, = form_data.integral_data
55+
assert len(integral_data.domain_integral_type_map) == 2
56+
assert integral_data.domain_integral_type_map[mesh0] == "cell"
57+
assert integral_data.domain_integral_type_map[mesh1] == "cell"
58+
59+
60+
def test_mixed_function_space_with_mixed_mesh_3_cg3_bdm3_dg2_dx1():
61+
cell = triangle
62+
gdim = 2
63+
elem0 = FiniteElement("Lagrange", cell, 3)
64+
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 3)
65+
elem2 = FiniteElement("Discontinuous Lagrange", cell, 2)
66+
elem = MixedElement([elem0, elem1, elem2])
67+
mesh0 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=100)
68+
mesh1 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=101)
69+
mesh2 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=102)
70+
domain = MixedMesh(mesh0, mesh1, mesh2)
71+
V = FunctionSpace(domain, elem)
72+
V0 = FunctionSpace(mesh0, elem0)
73+
V1 = FunctionSpace(mesh1, elem1)
74+
V2 = FunctionSpace(mesh2, elem2)
75+
f = Coefficient(V, count=1000)
76+
u0 = TrialFunction(V0)
77+
v1 = TestFunction(V1)
78+
f0, f1, f2 = split(f)
79+
f0_split = Coefficient(V0)
80+
f1_split = Coefficient(V1)
81+
f2_split = Coefficient(V2)
82+
x2 = SpatialCoordinate(mesh2)
83+
dx1 = Measure("dx", mesh1)
84+
form = inner(x2, x2) * f2 * inner(grad(u0), v1) * dx1(999)
85+
form_data = compute_form_data(form, do_split_coefficients={f: [f0_split, f1_split, f2_split]})
86+
integral_data, = form_data.integral_data
87+
assert len(integral_data.domain_integral_type_map) == 3
88+
assert integral_data.domain_integral_type_map[mesh0] == "cell"
89+
assert integral_data.domain_integral_type_map[mesh1] == "cell"
90+
assert integral_data.domain_integral_type_map[mesh2] == "cell"
91+
kernel, = compile_form(form)
92+
assert kernel.domain_number == 0
93+
assert kernel.integral_type == "cell"
94+
assert kernel.subdomain_id == (999, )
95+
assert kernel.active_domain_numbers.coordinates == (0, 1, 2)
96+
assert kernel.active_domain_numbers.cell_orientations == ()
97+
assert kernel.active_domain_numbers.cell_sizes == ()
98+
assert kernel.active_domain_numbers.exterior_facets == ()
99+
assert kernel.active_domain_numbers.interior_facets == ()
100+
assert kernel.coefficient_numbers == ((0, (2, )), )
101+
assert isinstance(kernel.arguments[0], kernel_args.OutputKernelArg)
102+
assert isinstance(kernel.arguments[1], kernel_args.CoordinatesKernelArg)
103+
assert isinstance(kernel.arguments[2], kernel_args.CoordinatesKernelArg)
104+
assert isinstance(kernel.arguments[3], kernel_args.CoordinatesKernelArg)
105+
assert isinstance(kernel.arguments[4], kernel_args.CoefficientKernelArg)
106+
assert kernel.arguments[0].loopy_arg.shape == (20, 10)
107+
assert kernel.arguments[1].loopy_arg.shape == (3 * gdim, )
108+
assert kernel.arguments[2].loopy_arg.shape == (3 * gdim, )
109+
assert kernel.arguments[3].loopy_arg.shape == (3 * gdim, )
110+
assert kernel.arguments[4].loopy_arg.shape == (6, )
111+
112+
113+
def test_mixed_function_space_with_mixed_mesh_restrictions_bdm3_dg2_dS0():
114+
cell = triangle
115+
gdim = 2
116+
elem0 = FiniteElement("Brezzi-Douglas-Marini", cell, 3)
117+
elem1 = FiniteElement("Discontinuous Lagrange", cell, 2)
118+
elem = MixedElement([elem0, elem1])
119+
mesh0 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=100)
120+
mesh1 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=101)
121+
domain = MixedMesh(mesh0, mesh1)
122+
V = FunctionSpace(domain, elem)
123+
V0 = FunctionSpace(mesh0, elem0)
124+
V1 = FunctionSpace(mesh1, elem1)
125+
f = Coefficient(V, count=1000)
126+
f0, f1 = split(f)
127+
f0_split = Coefficient(V0)
128+
f1_split = Coefficient(V1)
129+
u0 = TrialFunction(V0)
130+
u1 = TrialFunction(V1)
131+
v0 = TestFunction(V0)
132+
v1 = TestFunction(V1)
133+
dx0 = Measure("dx", mesh0)
134+
dx1 = Measure("dx", mesh1)
135+
ds0 = Measure("ds", mesh0)
136+
ds1 = Measure("ds", mesh1)
137+
dS0 = Measure("dS", mesh0)
138+
dS1 = Measure("dS", mesh1)
139+
form = inner(curl(f1('|')), curl(f1('|'))) * inner(grad(u1('|')), v0('+')) * dS0(777)
140+
form_data = compute_form_data(form, do_split_coefficients={f: [f0_split, f1_split]})
141+
integral_data, = form_data.integral_data
142+
assert len(integral_data.domain_integral_type_map) == 2
143+
assert integral_data.domain_integral_type_map[mesh0] == "interior_facet"
144+
assert integral_data.domain_integral_type_map[mesh1] == "exterior_facet"
145+
kernel, = compile_form(form)
146+
assert kernel.domain_number == 0
147+
assert kernel.integral_type == "interior_facet"
148+
assert kernel.subdomain_id == (777, )
149+
assert kernel.active_domain_numbers.coordinates == (0, 1)
150+
assert kernel.active_domain_numbers.cell_orientations == ()
151+
assert kernel.active_domain_numbers.cell_sizes == ()
152+
assert kernel.active_domain_numbers.exterior_facets == (1, )
153+
assert kernel.active_domain_numbers.interior_facets == (0, )
154+
assert kernel.coefficient_numbers == ((0, (1, )), )
155+
assert isinstance(kernel.arguments[0], kernel_args.OutputKernelArg)
156+
assert isinstance(kernel.arguments[1], kernel_args.CoordinatesKernelArg)
157+
assert isinstance(kernel.arguments[2], kernel_args.CoordinatesKernelArg)
158+
assert isinstance(kernel.arguments[3], kernel_args.CoefficientKernelArg)
159+
assert isinstance(kernel.arguments[4], kernel_args.ExteriorFacetKernelArg)
160+
assert isinstance(kernel.arguments[5], kernel_args.InteriorFacetKernelArg)
161+
assert kernel.arguments[0].loopy_arg.shape == (2 * 20, 6)
162+
assert kernel.arguments[1].loopy_arg.shape == (2 * (3 * gdim), )
163+
assert kernel.arguments[2].loopy_arg.shape == (3 * gdim, )
164+
assert kernel.arguments[3].loopy_arg.shape == (6, )
165+
assert kernel.arguments[4].loopy_arg.shape == (1, )
166+
assert kernel.arguments[5].loopy_arg.shape == (2, )
167+
168+
169+
def test_mixed_function_space_with_mixed_mesh_restrictions_dg2_dg3_ds1():
170+
cell = triangle
171+
gdim = 2
172+
elem0 = FiniteElement("Discontinuous Lagrange", cell, 2)
173+
elem1 = FiniteElement("Discontinuous Lagrange", cell, 3)
174+
elem = MixedElement([elem0, elem1])
175+
mesh0 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=100)
176+
mesh1 = Mesh(VectorElement("Lagrange", cell, 1), ufl_id=101)
177+
domain = MixedMesh(mesh0, mesh1)
178+
V = FunctionSpace(domain, elem)
179+
V0 = FunctionSpace(mesh0, elem0)
180+
V1 = FunctionSpace(mesh1, elem1)
181+
f = Coefficient(V, count=1000)
182+
f0_split = Coefficient(V0)
183+
f1_split = Coefficient(V1)
184+
f0, f1 = split(f)
185+
u0 = TrialFunction(V0)
186+
u1 = TrialFunction(V1)
187+
v0 = TestFunction(V0)
188+
v1 = TestFunction(V1)
189+
dx0 = Measure("dx", mesh0)
190+
dx1 = Measure("dx", mesh1)
191+
ds0 = Measure("ds", mesh0)
192+
ds1 = Measure("ds", mesh1)
193+
dS0 = Measure("dS", mesh0)
194+
dS1 = Measure("dS", mesh1)
195+
form = inner(grad(f1('|')), grad(f0('-'))) * inner(grad(u0('-')), grad(v1('|'))) * ds1(777)
196+
form_data = compute_form_data(form, do_split_coefficients={f: [f0_split, f1_split]})
197+
integral_data, = form_data.integral_data
198+
assert len(integral_data.domain_integral_type_map) == 2
199+
assert integral_data.domain_integral_type_map[mesh0] == "interior_facet"
200+
assert integral_data.domain_integral_type_map[mesh1] == "exterior_facet"
201+
kernel, = compile_form(form)
202+
assert kernel.domain_number == 0
203+
assert kernel.integral_type == "exterior_facet"
204+
assert kernel.subdomain_id == (777, )
205+
assert kernel.active_domain_numbers.coordinates == (0, 1)
206+
assert kernel.active_domain_numbers.cell_orientations == ()
207+
assert kernel.active_domain_numbers.cell_sizes == ()
208+
assert kernel.active_domain_numbers.exterior_facets == (0, )
209+
assert kernel.active_domain_numbers.interior_facets == (1, )
210+
assert kernel.coefficient_numbers == ((0, (0, 1)), )
211+
assert isinstance(kernel.arguments[0], kernel_args.OutputKernelArg)
212+
assert isinstance(kernel.arguments[1], kernel_args.CoordinatesKernelArg)
213+
assert isinstance(kernel.arguments[2], kernel_args.CoordinatesKernelArg)
214+
assert isinstance(kernel.arguments[3], kernel_args.CoefficientKernelArg)
215+
assert isinstance(kernel.arguments[4], kernel_args.CoefficientKernelArg)
216+
assert isinstance(kernel.arguments[5], kernel_args.ExteriorFacetKernelArg)
217+
assert isinstance(kernel.arguments[6], kernel_args.InteriorFacetKernelArg)
218+
assert kernel.arguments[0].loopy_arg.shape == (10, 2 * 6)
219+
assert kernel.arguments[1].loopy_arg.shape == (1 * (3 * gdim), )
220+
assert kernel.arguments[2].loopy_arg.shape == (2 * (3 * gdim), )
221+
assert kernel.arguments[3].loopy_arg.shape == (2 * 6, )
222+
assert kernel.arguments[4].loopy_arg.shape == (10, )
223+
assert kernel.arguments[5].loopy_arg.shape == (1, )
224+
assert kernel.arguments[6].loopy_arg.shape == (2, )

tests/test_tsfc_182.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from ufl import Coefficient, TestFunction, dx, inner, tetrahedron, Mesh, FunctionSpace
3+
from ufl import Coefficient, TestFunction, dx, inner, tetrahedron, Mesh, MixedMesh, FunctionSpace
44
from finat.ufl import FiniteElement, MixedElement, VectorElement
55

66
from tsfc import compile_form
@@ -20,7 +20,8 @@ def test_delta_elimination(mode):
2020

2121
element_chi_lambda = MixedElement(element_eps_p, element_lambda)
2222
domain = Mesh(VectorElement("Lagrange", tetrahedron, 1))
23-
space = FunctionSpace(domain, element_chi_lambda)
23+
domains = MixedMesh(domain, domain)
24+
space = FunctionSpace(domains, element_chi_lambda)
2425

2526
chi_lambda = Coefficient(space)
2627
delta_chi_lambda = TestFunction(space)

tests/test_tsfc_204.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from tsfc import compile_form
22
from ufl import (Coefficient, FacetNormal,
3-
FunctionSpace, Mesh, as_matrix,
3+
FunctionSpace, Mesh, MixedMesh, as_matrix,
44
dot, dS, ds, dx, facet, grad, inner, outer, split, triangle)
55
from finat.ufl import BrokenElement, FiniteElement, MixedElement, VectorElement
66

77

88
def test_physically_mapped_facet():
99
mesh = Mesh(VectorElement("P", triangle, 1))
10+
meshes = MixedMesh(mesh, mesh, mesh, mesh, mesh)
1011

1112
# set up variational problem
1213
U = FiniteElement("Morley", mesh.ufl_cell(), 2)
@@ -15,7 +16,7 @@ def test_physically_mapped_facet():
1516
Vv = VectorElement(BrokenElement(V))
1617
Qhat = VectorElement(BrokenElement(V[facet]))
1718
Vhat = VectorElement(V[facet])
18-
Z = FunctionSpace(mesh, MixedElement(U, Vv, Qhat, Vhat, R))
19+
Z = FunctionSpace(meshes, MixedElement(U, Vv, Qhat, Vhat, R))
1920

2021
z = Coefficient(Z)
2122
u, d, qhat, dhat, lam = split(z)

0 commit comments

Comments
 (0)