Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into dolci/update_ufl
Browse files Browse the repository at this point in the history
  • Loading branch information
Ig-dolci committed Mar 6, 2025
2 parents dcad2e4 + 6d367f6 commit 4132de2
Show file tree
Hide file tree
Showing 25 changed files with 1,010 additions and 181 deletions.
56 changes: 28 additions & 28 deletions .github/workflows/tsfc-tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# This workflow will install tsfc and run its unit tests

name: tsfc integration
# This workflow will test the UFL branch against the latest Firedrake container
name: TSFC integration

on:
pull_request:
Expand All @@ -11,37 +10,38 @@ jobs:
tsfc-tests:
name: Run TSFC tests
runs-on: ubuntu-latest

container:
image: firedrakeproject/firedrake-vanilla-default:latest
# Github hosted runners require running as root user:
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#docker-container-filesystem
options: --user root
env:
CC: gcc-10
CXX: g++-10

# Since we are running as root we need to set PYTHONPATH to be able to find the installed
# packages
PYTHONPATH: /home/firedrake/firedrake:/home/firedrake/.local/lib/python3.12/site-packages
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.12
# Download UFL into a subdirectory not called 'ufl' to make sure
# that the package installs correctly. Otherwise 'import ufl' may
# work even if the installation failed because it is a subdirectory.
path: ufl-repo

- name: Uninstall existing UFL
run: |
python3 -m pip uninstall --break-system-packages -y ufl
- name: Create virtual environment
run: |
python3 -m venv venv-ufl
- name: Install UFL
run: |
pip3 install .
. venv-ufl/bin/activate
pip install ./ufl-repo
pip list
- name: Clone tsfc
uses: actions/checkout@v4
with:
path: ./tsfc
repository: firedrakeproject/tsfc
ref: master
- name: Install tsfc
- name: Run TSFC tests
run: |
cd tsfc
pip install -r requirements-ext.txt
pip install git+https://github.com/coneoproject/COFFEE.git#egg=coffee
pip install git+https://github.com/firedrakeproject/fiat.git#egg=fenics-fiat
pip install git+https://github.com/FInAT/FInAT.git#egg=finat
pip install git+https://github.com/firedrakeproject/loopy.git#egg=loopy
pip install .[ci]
pip install pytest
- name: Run tsfc unit tests
run: python3 -m pytest tsfc/tests
. venv-ufl/bin/activate
python -m pytest /home/firedrake/firedrake/tests/tsfc
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ Contributors:
| Corrado Maurini <[email protected]>
| Jack S. Hale <[email protected]>
| Tuomas Airaksinen <[email protected]>
| Nacime Bouziani <[email protected]>
| Reuben W. Hill <[email protected]>
| Cécile Daversin-Catty <[email protected]>
| Nacime Bouziani <[email protected]>
| Matthew Scroggs <[email protected]>
| Jørgen S. Dokken <[email protected]>
14 changes: 11 additions & 3 deletions test/test_classcoverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
Not,
Or,
PermutationSymbol,
RidgeJacobian,
RidgeJacobianDeterminant,
RidgeJacobianInverse,
SpatialCoordinate,
TensorConstant,
VectorConstant,
Expand Down Expand Up @@ -292,9 +295,14 @@ def testAll(self):
_test_object(g, (), ())
g = FacetJacobianInverse(domain)
_test_object(g, (dim - 1, dim), ())

g = FacetNormal(domain)
_test_object(g, (dim,), ())
g = RidgeJacobian(domain3D)
_test_object(g, (3, 1), ())
g = RidgeJacobianDeterminant(domain3D)
_test_object(g, (), ())
g = RidgeJacobianInverse(domain3D)
_test_object(g, (1, 3), ())
g = FacetNormal(domain3D)
_test_object(g, (3,), ())
# g = CellNormal(domain)
# _test_object(g, (dim,), ())

Expand Down
23 changes: 15 additions & 8 deletions test/test_external_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from ufl.algorithms.apply_derivatives import apply_derivatives
from ufl.core.external_operator import ExternalOperator
from ufl.finiteelement import FiniteElement
from ufl.form import BaseForm
from ufl.form import BaseForm, ZeroBaseForm
from ufl.pullback import identity_pullback
from ufl.sobolevspace import H1

Expand Down Expand Up @@ -205,10 +205,10 @@ def test_differentiation_procedure_action(V1, V2):
def test_extractions(domain_2d, V1):
from ufl.algorithms.analysis import (
extract_arguments,
extract_arguments_and_coefficients,
extract_base_form_operators,
extract_coefficients,
extract_constants,
extract_terminals_with_domain,
)

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

assert extract_coefficients(e) == [u]
assert extract_arguments(e) == [vstar_e]
assert extract_arguments_and_coefficients(e) == ([vstar_e], [u])
assert extract_terminals_with_domain(e) == ([vstar_e], [u], [])
assert extract_constants(e) == [c]
assert extract_base_form_operators(e) == [e]

F = e * dx

assert extract_coefficients(F) == [u]
assert extract_arguments(e) == [vstar_e]
assert extract_arguments_and_coefficients(e) == ([vstar_e], [u])
assert extract_terminals_with_domain(e) == ([vstar_e], [u], [])
assert extract_constants(F) == [c]
assert F.base_form_operators() == (e,)

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

assert extract_coefficients(e) == [u]
assert extract_arguments(e) == [vstar_e, u_hat]
assert extract_arguments_and_coefficients(e) == ([vstar_e, u_hat], [u])
assert extract_terminals_with_domain(e) == ([vstar_e, u_hat], [u], [])
assert extract_base_form_operators(e) == [e]

F = e * dx

assert extract_coefficients(F) == [u]
assert extract_arguments(e) == [vstar_e, u_hat]
assert extract_arguments_and_coefficients(e) == ([vstar_e, u_hat], [u])
assert extract_terminals_with_domain(e) == ([vstar_e, u_hat], [u], [])
assert F.base_form_operators() == (e,)

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

assert extract_coefficients(e2) == [u, w]
assert extract_arguments(e2) == [vstar_e2, u_hat]
assert extract_arguments_and_coefficients(e2) == ([vstar_e2, u_hat], [u, w])
assert extract_terminals_with_domain(e2) == ([vstar_e2, u_hat], [u, w], [])
assert extract_base_form_operators(e2) == [e, e2]

F = e2 * dx

assert extract_coefficients(e2) == [u, w]
assert extract_arguments(e2) == [vstar_e2, u_hat]
assert extract_arguments_and_coefficients(e2) == ([vstar_e2, u_hat], [u, w])
assert extract_terminals_with_domain(e2) == ([vstar_e2, u_hat], [u, w], [])
assert F.base_form_operators() == (e, e2)


Expand Down Expand Up @@ -516,3 +516,10 @@ def test_replace(V1):

dN_replaced = dN._ufl_expr_reconstruct_(u, argument_slots=(A, uhat))
assert G == dN_replaced


def test_ZeroDerivative(V1):
u = Coefficient(V1, count=1)
N = ExternalOperator(Coefficient(V1, count=0), function_space=V1)
dN1 = expand_derivatives(derivative(N, u))
assert isinstance(dN1, ZeroBaseForm)
8 changes: 4 additions & 4 deletions test/test_interpolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
from ufl.algorithms.ad import expand_derivatives
from ufl.algorithms.analysis import (
extract_arguments,
extract_arguments_and_coefficients,
extract_base_form_operators,
extract_coefficients,
extract_terminals_with_domain,
)
from ufl.algorithms.expand_indices import expand_indices
from ufl.core.interpolate import Interpolate
Expand Down Expand Up @@ -172,12 +172,12 @@ def test_extract_base_form_operators(V1, V2):
# -- Interpolate(u, V2) -- #
Iu = Interpolate(u, V2)
assert extract_arguments(Iu) == [vstar]
assert extract_arguments_and_coefficients(Iu) == ([vstar], [u])
assert extract_terminals_with_domain(Iu) == ([vstar], [u], [])

F = Iu * dx
# Form composition: Iu * dx <=> Action(v * dx, Iu(u; v*))
assert extract_arguments(F) == []
assert extract_arguments_and_coefficients(F) == ([], [u])
assert extract_terminals_with_domain(F) == ([], [u], [])

for e in [Iu, F]:
assert extract_coefficients(e) == [u]
Expand All @@ -186,7 +186,7 @@ def test_extract_base_form_operators(V1, V2):
# -- Interpolate(u, V2) -- #
Iv = Interpolate(uhat, V2)
assert extract_arguments(Iv) == [vstar, uhat]
assert extract_arguments_and_coefficients(Iv) == ([vstar, uhat], [])
assert extract_terminals_with_domain(Iv) == ([vstar, uhat], [], [])
assert extract_coefficients(Iv) == []
assert extract_base_form_operators(Iv) == [Iv]

Expand Down
4 changes: 4 additions & 0 deletions test/test_measures.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def test_construct_forms_from_default_measures():
ds = Measure("ds")
dS = Measure("dS")

dl = Measure("dr")

dP = Measure("dP")
# dV = Measure("dV")

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

assert dl.integral_type() == "ridge"

assert dP.integral_type() == "vertex"
# TODO: Change dP to dV:
# assert dP.integral_type() == "point"
Expand Down
104 changes: 104 additions & 0 deletions test/test_mixed_function_space_with_mesh_sequence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from ufl import (
CellVolume,
Coefficient,
FacetArea,
FacetNormal,
FunctionSpace,
Measure,
Mesh,
MeshSequence,
SpatialCoordinate,
TestFunction,
TrialFunction,
grad,
inner,
split,
triangle,
)
from ufl.algorithms import compute_form_data
from ufl.domain import extract_domains
from ufl.finiteelement import FiniteElement, MixedElement
from ufl.pullback import contravariant_piola, identity_pullback
from ufl.sobolevspace import H1, L2, HDiv


def test_mixed_function_space_with_mesh_sequence_basic():
cell = triangle
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
elem = MixedElement([elem0, elem1, elem2])
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
domain = MeshSequence([mesh0, mesh1, mesh2])
V = FunctionSpace(domain, elem)
u = TrialFunction(V)
v = TestFunction(V)
f = Coefficient(V, count=1000)
g = Coefficient(V, count=2000)
u0, u1, u2 = split(u)
v0, v1, v2 = split(v)
f0, f1, f2 = split(f)
g0, g1, g2 = split(g)
dx1 = Measure("dx", mesh1)
x = SpatialCoordinate(mesh1)
form = x[1] * f0 * inner(grad(u0), v1) * dx1(999)
fd = compute_form_data(
form,
do_apply_function_pullbacks=True,
do_apply_integral_scaling=True,
do_apply_geometry_lowering=True,
preserve_geometry_types=(CellVolume, FacetArea),
do_apply_restrictions=True,
do_estimate_degrees=True,
complex_mode=False,
)
(id0,) = fd.integral_data
assert fd.preprocessed_form.arguments() == (v, u)
assert fd.reduced_coefficients == [f]
assert form.coefficients()[fd.original_coefficient_positions[0]] is f
assert id0.domain is mesh1
assert id0.integral_type == "cell"
assert id0.subdomain_id == (999,)
assert fd.original_form.domain_numbering()[id0.domain] == 0
assert id0.integral_coefficients == set([f])
assert id0.enabled_coefficients == [True]


def test_mixed_function_space_with_mesh_sequence_signature():
cell = triangle
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
dx0 = Measure("dx", mesh0)
dx1 = Measure("dx", mesh1)
n0 = FacetNormal(mesh0)
n1 = FacetNormal(mesh1)
form_a = inner(n1, n1) * dx0(999)
form_b = inner(n0, n0) * dx1(999)
assert form_a.signature() == form_b.signature()
assert extract_domains(form_a) == (mesh0, mesh1)
assert extract_domains(form_b) == (mesh1, mesh0)


def test_mixed_function_space_with_mesh_sequence_hash():
cell = triangle
elem0 = FiniteElement("Lagrange", cell, 1, (), identity_pullback, H1)
elem1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1, (2,), contravariant_piola, HDiv)
elem2 = FiniteElement("Discontinuous Lagrange", cell, 0, (), identity_pullback, L2)
elem = MixedElement([elem0, elem1, elem2])
mesh0 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=100)
mesh1 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=101)
mesh2 = Mesh(FiniteElement("Lagrange", cell, 1, (2,), identity_pullback, H1), ufl_id=102)
domain = MeshSequence([mesh0, mesh1, mesh2])
domain_ = MeshSequence([mesh0, mesh1, mesh2])
V = FunctionSpace(domain, elem)
V_ = FunctionSpace(domain_, elem)
u = TrialFunction(V)
u_ = TrialFunction(V_)
assert hash(domain_) == hash(domain)
assert domain_ == domain
assert hash(V_) == hash(V)
assert V_ == V
assert hash(u_) == hash(u)
assert u_ == u
10 changes: 10 additions & 0 deletions test/test_piecewise_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
FacetJacobian,
FacetJacobianDeterminant,
FacetJacobianInverse,
RidgeJacobian,
RidgeJacobianDeterminant,
RidgeJacobianInverse,
)
from ufl.finiteelement import FiniteElement
from ufl.pullback import identity_pullback
Expand Down Expand Up @@ -284,6 +287,13 @@ def mappings_are_cellwise_constant(domain, test):
assert is_cellwise_constant(e) == test
e = FacetJacobianInverse(domain)
assert is_cellwise_constant(e) == test
if domain.topological_dimension() > 2:
e = RidgeJacobian(domain)
assert is_cellwise_constant(e) == test
e = RidgeJacobianDeterminant(domain)
assert is_cellwise_constant(e) == test
e = RidgeJacobianInverse(domain)
assert is_cellwise_constant(e) == test


def test_mappings_are_cellwise_constant_on_linear_affine_cells(affine_domains):
Expand Down
Loading

0 comments on commit 4132de2

Please sign in to comment.