Skip to content

Commit b8483c3

Browse files
authored
Merge pull request #61 from firedrakeproject/dolci/update_ufl
Update ufl
2 parents dcad2e4 + 4132de2 commit b8483c3

25 files changed

Lines changed: 1010 additions & 181 deletions

.github/workflows/tsfc-tests.yml

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
# This workflow will install tsfc and run its unit tests
2-
3-
name: tsfc integration
1+
# This workflow will test the UFL branch against the latest Firedrake container
2+
name: TSFC integration
43

54
on:
65
pull_request:
@@ -11,37 +10,38 @@ jobs:
1110
tsfc-tests:
1211
name: Run TSFC tests
1312
runs-on: ubuntu-latest
14-
13+
container:
14+
image: firedrakeproject/firedrake-vanilla-default:latest
15+
# Github hosted runners require running as root user:
16+
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem
17+
options: --user root
1518
env:
16-
CC: gcc-10
17-
CXX: g++-10
18-
19+
# Since we are running as root we need to set PYTHONPATH to be able to find the installed
20+
# packages
21+
PYTHONPATH: /home/firedrake/firedrake:/home/firedrake/.local/lib/python3.12/site-packages
1922
steps:
2023
- uses: actions/checkout@v4
21-
- name: Set up Python
22-
uses: actions/setup-python@v5
2324
with:
24-
python-version: 3.12
25+
# Download UFL into a subdirectory not called 'ufl' to make sure
26+
# that the package installs correctly. Otherwise 'import ufl' may
27+
# work even if the installation failed because it is a subdirectory.
28+
path: ufl-repo
29+
30+
- name: Uninstall existing UFL
31+
run: |
32+
python3 -m pip uninstall --break-system-packages -y ufl
33+
34+
- name: Create virtual environment
35+
run: |
36+
python3 -m venv venv-ufl
2537
2638
- name: Install UFL
2739
run: |
28-
pip3 install .
40+
. venv-ufl/bin/activate
41+
pip install ./ufl-repo
42+
pip list
2943
30-
- name: Clone tsfc
31-
uses: actions/checkout@v4
32-
with:
33-
path: ./tsfc
34-
repository: firedrakeproject/tsfc
35-
ref: master
36-
- name: Install tsfc
44+
- name: Run TSFC tests
3745
run: |
38-
cd tsfc
39-
pip install -r requirements-ext.txt
40-
pip install git+https://github.com/coneoproject/COFFEE.git#egg=coffee
41-
pip install git+https://github.com/firedrakeproject/fiat.git#egg=fenics-fiat
42-
pip install git+https://github.com/FInAT/FInAT.git#egg=finat
43-
pip install git+https://github.com/firedrakeproject/loopy.git#egg=loopy
44-
pip install .[ci]
45-
pip install pytest
46-
- name: Run tsfc unit tests
47-
run: python3 -m pytest tsfc/tests
46+
. venv-ufl/bin/activate
47+
python -m pytest /home/firedrake/firedrake/tests/tsfc

AUTHORS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ Contributors:
2828
| Corrado Maurini <corrado.maurini@upmc.fr>
2929
| Jack S. Hale <mail@jackhale.co.uk>
3030
| Tuomas Airaksinen <tuomas.airaksinen@gmail.com>
31-
| Nacime Bouziani <nacime.bouziani@gmail.com>
3231
| Reuben W. Hill <reuben.hill10@imperial.ac.uk>
32+
| Cécile Daversin-Catty <cecile@simula.no>
3333
| Nacime Bouziani <n.bouziani18@imperial.ac.uk>
3434
| Matthew Scroggs <matthew.scroggs.14@ucl.ac.uk>
35+
| Jørgen S. Dokken <dokken@simula.no>

test/test_classcoverage.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
Not,
2525
Or,
2626
PermutationSymbol,
27+
RidgeJacobian,
28+
RidgeJacobianDeterminant,
29+
RidgeJacobianInverse,
2730
SpatialCoordinate,
2831
TensorConstant,
2932
VectorConstant,
@@ -292,9 +295,14 @@ def testAll(self):
292295
_test_object(g, (), ())
293296
g = FacetJacobianInverse(domain)
294297
_test_object(g, (dim - 1, dim), ())
295-
296-
g = FacetNormal(domain)
297-
_test_object(g, (dim,), ())
298+
g = RidgeJacobian(domain3D)
299+
_test_object(g, (3, 1), ())
300+
g = RidgeJacobianDeterminant(domain3D)
301+
_test_object(g, (), ())
302+
g = RidgeJacobianInverse(domain3D)
303+
_test_object(g, (1, 3), ())
304+
g = FacetNormal(domain3D)
305+
_test_object(g, (3,), ())
298306
# g = CellNormal(domain)
299307
# _test_object(g, (dim,), ())
300308

test/test_external_operator.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from ufl.algorithms.apply_derivatives import apply_derivatives
3232
from ufl.core.external_operator import ExternalOperator
3333
from ufl.finiteelement import FiniteElement
34-
from ufl.form import BaseForm
34+
from ufl.form import BaseForm, ZeroBaseForm
3535
from ufl.pullback import identity_pullback
3636
from ufl.sobolevspace import H1
3737

@@ -205,10 +205,10 @@ def test_differentiation_procedure_action(V1, V2):
205205
def test_extractions(domain_2d, V1):
206206
from ufl.algorithms.analysis import (
207207
extract_arguments,
208-
extract_arguments_and_coefficients,
209208
extract_base_form_operators,
210209
extract_coefficients,
211210
extract_constants,
211+
extract_terminals_with_domain,
212212
)
213213

214214
u = Coefficient(V1)
@@ -219,15 +219,15 @@ def test_extractions(domain_2d, V1):
219219

220220
assert extract_coefficients(e) == [u]
221221
assert extract_arguments(e) == [vstar_e]
222-
assert extract_arguments_and_coefficients(e) == ([vstar_e], [u])
222+
assert extract_terminals_with_domain(e) == ([vstar_e], [u], [])
223223
assert extract_constants(e) == [c]
224224
assert extract_base_form_operators(e) == [e]
225225

226226
F = e * dx
227227

228228
assert extract_coefficients(F) == [u]
229229
assert extract_arguments(e) == [vstar_e]
230-
assert extract_arguments_and_coefficients(e) == ([vstar_e], [u])
230+
assert extract_terminals_with_domain(e) == ([vstar_e], [u], [])
231231
assert extract_constants(F) == [c]
232232
assert F.base_form_operators() == (e,)
233233

@@ -236,14 +236,14 @@ def test_extractions(domain_2d, V1):
236236

237237
assert extract_coefficients(e) == [u]
238238
assert extract_arguments(e) == [vstar_e, u_hat]
239-
assert extract_arguments_and_coefficients(e) == ([vstar_e, u_hat], [u])
239+
assert extract_terminals_with_domain(e) == ([vstar_e, u_hat], [u], [])
240240
assert extract_base_form_operators(e) == [e]
241241

242242
F = e * dx
243243

244244
assert extract_coefficients(F) == [u]
245245
assert extract_arguments(e) == [vstar_e, u_hat]
246-
assert extract_arguments_and_coefficients(e) == ([vstar_e, u_hat], [u])
246+
assert extract_terminals_with_domain(e) == ([vstar_e, u_hat], [u], [])
247247
assert F.base_form_operators() == (e,)
248248

249249
w = Coefficient(V1)
@@ -252,14 +252,14 @@ def test_extractions(domain_2d, V1):
252252

253253
assert extract_coefficients(e2) == [u, w]
254254
assert extract_arguments(e2) == [vstar_e2, u_hat]
255-
assert extract_arguments_and_coefficients(e2) == ([vstar_e2, u_hat], [u, w])
255+
assert extract_terminals_with_domain(e2) == ([vstar_e2, u_hat], [u, w], [])
256256
assert extract_base_form_operators(e2) == [e, e2]
257257

258258
F = e2 * dx
259259

260260
assert extract_coefficients(e2) == [u, w]
261261
assert extract_arguments(e2) == [vstar_e2, u_hat]
262-
assert extract_arguments_and_coefficients(e2) == ([vstar_e2, u_hat], [u, w])
262+
assert extract_terminals_with_domain(e2) == ([vstar_e2, u_hat], [u, w], [])
263263
assert F.base_form_operators() == (e, e2)
264264

265265

@@ -516,3 +516,10 @@ def test_replace(V1):
516516

517517
dN_replaced = dN._ufl_expr_reconstruct_(u, argument_slots=(A, uhat))
518518
assert G == dN_replaced
519+
520+
521+
def test_ZeroDerivative(V1):
522+
u = Coefficient(V1, count=1)
523+
N = ExternalOperator(Coefficient(V1, count=0), function_space=V1)
524+
dN1 = expand_derivatives(derivative(N, u))
525+
assert isinstance(dN1, ZeroBaseForm)

test/test_interpolate.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
from ufl.algorithms.ad import expand_derivatives
2828
from ufl.algorithms.analysis import (
2929
extract_arguments,
30-
extract_arguments_and_coefficients,
3130
extract_base_form_operators,
3231
extract_coefficients,
32+
extract_terminals_with_domain,
3333
)
3434
from ufl.algorithms.expand_indices import expand_indices
3535
from ufl.core.interpolate import Interpolate
@@ -172,12 +172,12 @@ def test_extract_base_form_operators(V1, V2):
172172
# -- Interpolate(u, V2) -- #
173173
Iu = Interpolate(u, V2)
174174
assert extract_arguments(Iu) == [vstar]
175-
assert extract_arguments_and_coefficients(Iu) == ([vstar], [u])
175+
assert extract_terminals_with_domain(Iu) == ([vstar], [u], [])
176176

177177
F = Iu * dx
178178
# Form composition: Iu * dx <=> Action(v * dx, Iu(u; v*))
179179
assert extract_arguments(F) == []
180-
assert extract_arguments_and_coefficients(F) == ([], [u])
180+
assert extract_terminals_with_domain(F) == ([], [u], [])
181181

182182
for e in [Iu, F]:
183183
assert extract_coefficients(e) == [u]
@@ -186,7 +186,7 @@ def test_extract_base_form_operators(V1, V2):
186186
# -- Interpolate(u, V2) -- #
187187
Iv = Interpolate(uhat, V2)
188188
assert extract_arguments(Iv) == [vstar, uhat]
189-
assert extract_arguments_and_coefficients(Iv) == ([vstar, uhat], [])
189+
assert extract_terminals_with_domain(Iv) == ([vstar, uhat], [], [])
190190
assert extract_coefficients(Iv) == []
191191
assert extract_base_form_operators(Iv) == [Iv]
192192

test/test_measures.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def test_construct_forms_from_default_measures():
1616
ds = Measure("ds")
1717
dS = Measure("dS")
1818

19+
dl = Measure("dr")
20+
1921
dP = Measure("dP")
2022
# dV = Measure("dV")
2123

@@ -37,6 +39,8 @@ def test_construct_forms_from_default_measures():
3739
assert ds.integral_type() == "exterior_facet"
3840
assert dS.integral_type() == "interior_facet"
3941

42+
assert dl.integral_type() == "ridge"
43+
4044
assert dP.integral_type() == "vertex"
4145
# TODO: Change dP to dV:
4246
# assert dP.integral_type() == "point"
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from ufl import (
2+
CellVolume,
3+
Coefficient,
4+
FacetArea,
5+
FacetNormal,
6+
FunctionSpace,
7+
Measure,
8+
Mesh,
9+
MeshSequence,
10+
SpatialCoordinate,
11+
TestFunction,
12+
TrialFunction,
13+
grad,
14+
inner,
15+
split,
16+
triangle,
17+
)
18+
from ufl.algorithms import compute_form_data
19+
from ufl.domain import extract_domains
20+
from ufl.finiteelement import FiniteElement, MixedElement
21+
from ufl.pullback import contravariant_piola, identity_pullback
22+
from ufl.sobolevspace import H1, L2, HDiv
23+
24+
25+
def test_mixed_function_space_with_mesh_sequence_basic():
26+
cell = triangle
27+
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
28+
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
29+
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
30+
elem = MixedElement([elem0, elem1, elem2])
31+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
32+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
33+
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
34+
domain = MeshSequence([mesh0, mesh1, mesh2])
35+
V = FunctionSpace(domain, elem)
36+
u = TrialFunction(V)
37+
v = TestFunction(V)
38+
f = Coefficient(V, count=1000)
39+
g = Coefficient(V, count=2000)
40+
u0, u1, u2 = split(u)
41+
v0, v1, v2 = split(v)
42+
f0, f1, f2 = split(f)
43+
g0, g1, g2 = split(g)
44+
dx1 = Measure("dx", mesh1)
45+
x = SpatialCoordinate(mesh1)
46+
form = x[1] * f0 * inner(grad(u0), v1) * dx1(999)
47+
fd = compute_form_data(
48+
form,
49+
do_apply_function_pullbacks=True,
50+
do_apply_integral_scaling=True,
51+
do_apply_geometry_lowering=True,
52+
preserve_geometry_types=(CellVolume, FacetArea),
53+
do_apply_restrictions=True,
54+
do_estimate_degrees=True,
55+
complex_mode=False,
56+
)
57+
(id0,) = fd.integral_data
58+
assert fd.preprocessed_form.arguments() == (v, u)
59+
assert fd.reduced_coefficients == [f]
60+
assert form.coefficients()[fd.original_coefficient_positions[0]] is f
61+
assert id0.domain is mesh1
62+
assert id0.integral_type == "cell"
63+
assert id0.subdomain_id == (999,)
64+
assert fd.original_form.domain_numbering()[id0.domain] == 0
65+
assert id0.integral_coefficients == set([f])
66+
assert id0.enabled_coefficients == [True]
67+
68+
69+
def test_mixed_function_space_with_mesh_sequence_signature():
70+
cell = triangle
71+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
72+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
73+
dx0 = Measure("dx", mesh0)
74+
dx1 = Measure("dx", mesh1)
75+
n0 = FacetNormal(mesh0)
76+
n1 = FacetNormal(mesh1)
77+
form_a = inner(n1, n1) * dx0(999)
78+
form_b = inner(n0, n0) * dx1(999)
79+
assert form_a.signature() == form_b.signature()
80+
assert extract_domains(form_a) == (mesh0, mesh1)
81+
assert extract_domains(form_b) == (mesh1, mesh0)
82+
83+
84+
def test_mixed_function_space_with_mesh_sequence_hash():
85+
cell = triangle
86+
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
87+
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
88+
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
89+
elem = MixedElement([elem0, elem1, elem2])
90+
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
91+
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
92+
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
93+
domain = MeshSequence([mesh0, mesh1, mesh2])
94+
domain_ = MeshSequence([mesh0, mesh1, mesh2])
95+
V = FunctionSpace(domain, elem)
96+
V_ = FunctionSpace(domain_, elem)
97+
u = TrialFunction(V)
98+
u_ = TrialFunction(V_)
99+
assert hash(domain_) == hash(domain)
100+
assert domain_ == domain
101+
assert hash(V_) == hash(V)
102+
assert V_ == V
103+
assert hash(u_) == hash(u)
104+
assert u_ == u

test/test_piecewise_checks.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
FacetJacobian,
3333
FacetJacobianDeterminant,
3434
FacetJacobianInverse,
35+
RidgeJacobian,
36+
RidgeJacobianDeterminant,
37+
RidgeJacobianInverse,
3538
)
3639
from ufl.finiteelement import FiniteElement
3740
from ufl.pullback import identity_pullback
@@ -284,6 +287,13 @@ def mappings_are_cellwise_constant(domain, test):
284287
assert is_cellwise_constant(e) == test
285288
e = FacetJacobianInverse(domain)
286289
assert is_cellwise_constant(e) == test
290+
if domain.topological_dimension() > 2:
291+
e = RidgeJacobian(domain)
292+
assert is_cellwise_constant(e) == test
293+
e = RidgeJacobianDeterminant(domain)
294+
assert is_cellwise_constant(e) == test
295+
e = RidgeJacobianInverse(domain)
296+
assert is_cellwise_constant(e) == test
287297

288298

289299
def test_mappings_are_cellwise_constant_on_linear_affine_cells(affine_domains):

0 commit comments

Comments
 (0)