Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update UFL element interface: move elements to FInAT #3166

Merged
merged 50 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b140c15
Set UFL branch
mscroggs Sep 26, 2023
7e820b2
tsfc branch
mscroggs Sep 26, 2023
40c39e9
use ufl.legacy
mscroggs Sep 26, 2023
ecdb138
ufl.legacy in tests
mscroggs Sep 26, 2023
0a3c489
update mathods that are now properties
mscroggs Sep 26, 2023
d1c459f
Add more .legacy
mscroggs Sep 26, 2023
a12a32f
fixes
mscroggs Sep 26, 2023
5c52519
not legacy
mscroggs Sep 26, 2023
c354ffc
Rename HDivElement -> HDiv and HCurlElement -> HCurl
mscroggs Sep 26, 2023
4248a51
replace as_domain
mscroggs Sep 26, 2023
7ebeb69
skip F401
mscroggs Sep 26, 2023
e110066
from ufl.legacy import *
mscroggs Sep 26, 2023
013b975
HDiv -> HDivElement
mscroggs Sep 26, 2023
ecf5e8b
fix
mscroggs Sep 26, 2023
4ad8cd6
team
mscroggs Sep 26, 2023
2fbd095
update AUTHORS.rst
mscroggs Sep 26, 2023
3da1330
adjust tolerance
mscroggs Sep 27, 2023
47afc7c
Merge branch 'master' into mscroggs/newfl-legacy
mscroggs Sep 27, 2023
4720901
increase tolerance very slightly
mscroggs Sep 27, 2023
891854e
investigate test that's failing on CI
mscroggs Sep 27, 2023
84c929d
no :
mscroggs Sep 27, 2023
7640458
more useful prints
mscroggs Sep 27, 2023
a8549e0
print more mesh info
mscroggs Sep 27, 2023
3fed974
remove parallel run of test
mscroggs Oct 13, 2023
62fc231
Merge branch 'master' into mscroggs/newfl-legacy
mscroggs Oct 13, 2023
07a273f
set ngsPETSc branch
mscroggs Oct 13, 2023
e55301b
move ufl.legacy to finat.ufl
mscroggs Oct 16, 2023
df8a463
flake
mscroggs Oct 16, 2023
877abef
ufl main
mscroggs Oct 16, 2023
9ab7293
flake
mscroggs Oct 16, 2023
6ee5673
finat branch
mscroggs Oct 16, 2023
0753498
Merge branch 'master' into mscroggs/newfl-legacy2
mscroggs Nov 2, 2023
9fbc5ed
remove ()
mscroggs Nov 2, 2023
9d19d61
Merge branch 'master' into mscroggs/newfl-legacy2
mscroggs Nov 8, 2023
9d1eb4f
Use ufl branch of fork
mscroggs Nov 8, 2023
250a5bf
remove debug prints
mscroggs Nov 8, 2023
e77a08e
change HDivElement back to HDiv
mscroggs Nov 8, 2023
e5eb2a1
add newline readme [to retrigger all CI runs]
mscroggs Nov 8, 2023
3b025ef
revert
mscroggs Nov 8, 2023
247fe16
add newline
mscroggs Nov 8, 2023
44381a3
Revert "add newline"
mscroggs Nov 8, 2023
8f6652c
Update tests/slate/test_mimetic.py
mscroggs Nov 8, 2023
3458c10
Update tests/regression/test_fs_caching.py
mscroggs Nov 8, 2023
03063e0
Update tests/regression/test_fs_caching.py
mscroggs Nov 8, 2023
3e470d0
Update tests/regression/test_fs_caching.py
mscroggs Nov 8, 2023
01266c1
set branches properly?
mscroggs Nov 15, 2023
af681f6
reset tolerance
mscroggs Nov 15, 2023
3dde501
Revert "reset tolerance"
mscroggs Nov 15, 2023
077fa11
use main ngspetsc branch
mscroggs Nov 15, 2023
775fce9
Apply suggestions from code review
JDBetteridge Nov 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ jobs:
python -m pip install \
pytest-cov pytest-timeout pytest-xdist pytest-timeout
python -m pip list

JDBetteridge marked this conversation as resolved.
Show resolved Hide resolved
- name: Test Firedrake
run: |
. ../firedrake_venv/bin/activate
Expand Down
2 changes: 2 additions & 0 deletions AUTHORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ Tomasz J. Salwa

Kaho Sato

Matthew Scroggs...............<https://mscroggs.co.uk>

Ben Sepanski..................<https://bensepanski.github.io>

Daniel R. Shapero.............<https://psc.apl.uw.edu/people/investigators/daniel-shapero/>
Expand Down
2 changes: 1 addition & 1 deletion demos/extruded_shallow_water/test_extrusion_lsw.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

horiz = FiniteElement("BDM", "triangle", 1)
vert = FiniteElement("DG", "interval", 0)
prod = HDiv(OuterProductElement(horiz, vert))
prod = HDivElement(OuterProductElement(horiz, vert))
W = FunctionSpace(mesh, prod)

X = FunctionSpace(mesh, "DG", 0, vfamily="DG", vdegree=0)
Expand Down
1 change: 1 addition & 0 deletions docs/source/team.ini
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ Francis P. Russell:
Thomas Roy:
Tomasz J. Salwa:
Kaho Sato:
Matthew Scroggs: https://mscroggs.co.uk
Ben Sepanski: https://bensepanski.github.io
Jemma Shipton:
Joseph G. Wallwork: https://www.imperial.ac.uk/people/j.wallwork16
Expand Down
1 change: 1 addition & 0 deletions firedrake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
pass
del ufl
from ufl import *
from finat.ufl import *
# Set up the cache directories before importing PyOP2.
firedrake_configuration.setup_cache_dirs()

Expand Down
2 changes: 1 addition & 1 deletion firedrake/adjoint_utils/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def _ad_dot(self, other, options=None):

@staticmethod
def _ad_assign_numpy(dst, src, offset):
l = dst.ufl_element().value_size()
l = dst.ufl_element().value_size
dst.assign(numpy.reshape(src[offset:offset + l], dst.ufl_shape), annotate=False)
offset += l
return dst, offset
Expand Down
7 changes: 4 additions & 3 deletions firedrake/assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from tsfc.finatinterface import create_element
from tsfc.ufl_utils import extract_firedrake_constants
import ufl
import finat.ufl
from firedrake import (extrusion_utils as eutils, matrix, parameters, solving,
tsfc_interface, utils)
from firedrake.adjoint_utils import annotate_assemble
Expand Down Expand Up @@ -1294,7 +1295,7 @@ def _as_global_kernel_arg_coefficient(_, self):

ufl_element = V.ufl_element()
if ufl_element.family() == "Real":
return op2.GlobalKernelArg((ufl_element.value_size(),))
return op2.GlobalKernelArg((ufl_element.value_size,))
else:
finat_element = create_element(ufl_element)
return self._make_dat_global_kernel_arg(finat_element, index)
Expand All @@ -1310,7 +1311,7 @@ def _as_global_kernel_arg_constant(_, self):
@_as_global_kernel_arg.register(kernel_args.CellSizesKernelArg)
def _as_global_kernel_arg_cell_sizes(_, self):
# this mirrors tsfc.kernel_interface.firedrake_loopy.KernelBuilder.set_cell_sizes
ufl_element = ufl.FiniteElement("P", self._mesh.ufl_cell(), 1)
ufl_element = finat.ufl.FiniteElement("P", self._mesh.ufl_cell(), 1)
finat_element = create_element(ufl_element)
return self._make_dat_global_kernel_arg(finat_element)

Expand All @@ -1337,7 +1338,7 @@ def _as_global_kernel_arg_cell_facet(_, self):
@_as_global_kernel_arg.register(kernel_args.CellOrientationsKernelArg)
def _as_global_kernel_arg_cell_orientations(_, self):
# this mirrors firedrake.mesh.MeshGeometry.init_cell_orientations
ufl_element = ufl.FiniteElement("DG", cell=self._form.ufl_domain().ufl_cell(), degree=0)
ufl_element = finat.ufl.FiniteElement("DG", cell=self._form.ufl_domain().ufl_cell(), degree=0)
finat_element = create_element(ufl_element)
return self._make_dat_global_kernel_arg(finat_element)

Expand Down
6 changes: 3 additions & 3 deletions firedrake/assign.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from pyadjoint.tape import annotate_tape
from pyop2.utils import cached_property
import pytools
import ufl
import finat.ufl
from ufl.algorithms import extract_coefficients
from ufl.constantvalue import as_ufl
from ufl.corealg.map_dag import map_expr_dag
Expand Down Expand Up @@ -155,9 +155,9 @@ def __init__(self, assignee, expression, subset=None):
raise ValueError("All functions in the expression must use the same "
"mesh as the assignee")

if (subset and type(assignee.ufl_element()) == ufl.MixedElement
if (subset and type(assignee.ufl_element()) == finat.ufl.MixedElement
and any(el.family() == "Real"
for el in assignee.ufl_element().sub_elements())):
for el in assignee.ufl_element().sub_elements)):
raise ValueError("Subset is not a valid argument for assigning to a mixed "
"element including a real element")

Expand Down
7 changes: 4 additions & 3 deletions firedrake/bcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import itertools

import ufl
from ufl import as_ufl, as_tensor, VectorElement
from ufl import as_ufl, as_tensor
from finat.ufl import VectorElement
import finat

import pyop2 as op2
Expand Down Expand Up @@ -329,12 +330,12 @@ def function_arg(self, g):
raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g)
self._function_arg = g
elif isinstance(g, ufl.classes.Zero):
if g.ufl_shape and g.ufl_shape != self.function_space().ufl_element().value_shape():
if g.ufl_shape and g.ufl_shape != self.function_space().ufl_element().value_shape:
raise ValueError(f"Provided boundary value {g} does not match shape of space")
# Special case. Scalar zero for direct Function.assign.
self._function_arg = g
elif isinstance(g, ufl.classes.Expr):
if g.ufl_shape != self.function_space().ufl_element().value_shape():
if g.ufl_shape != self.function_space().ufl_element().value_shape:
raise RuntimeError(f"Provided boundary value {g} does not match shape of space")
try:
self._function_arg = firedrake.Function(self.function_space())
Expand Down
29 changes: 15 additions & 14 deletions firedrake/checkpointing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import functools
import pickle
from petsc4py.PETSc import ViewerHDF5
import ufl
import finat.ufl
from pyop2 import op2
from pyop2.mpi import COMM_WORLD, internal_comm, decref, MPI
from firedrake.cython import hdf5interface as h5i
Expand Down Expand Up @@ -577,7 +577,7 @@ def save_mesh(self, mesh, distribution_name=None, permutation_name=None):
# Save tmesh.layers, which contains (start layer, stop layer)-tuple for each cell
# Conceptually, we project these integer pairs onto DG0 vector space of dim=2.
cell = base_tmesh.ufl_cell()
element = ufl.VectorElement("DP" if cell.is_simplex() else "DQ", cell, 0, dim=2)
element = finat.ufl.VectorElement("DP" if cell.is_simplex() else "DQ", cell, 0, dim=2)
layers_tV = impl.FunctionSpace(base_tmesh, element)
self._save_function_space_topology(layers_tV)
# Note that _cell_numbering coincides with DG0 section, so we can use tmesh.layers directly.
Expand Down Expand Up @@ -762,7 +762,7 @@ def _save_function_space_topology(self, tV):
path = self._path_to_dms(tmesh.name)
if dm_name not in self.require_group(path):
if element.family() == "Real":
assert not isinstance(element, (ufl.VectorElement, ufl.TensorElement))
assert not isinstance(element, (finat.ufl.VectorElement, finat.ufl.TensorElement))
else:
dm = self._get_dm_for_checkpointing(tV)
topology_dm = tmesh.topology_dm
Expand Down Expand Up @@ -845,7 +845,7 @@ def _save_function_topology(self, tf, idx=None):
tmesh = tV.mesh()
element = tV.ufl_element()
if element.family() == "Real":
assert not isinstance(element, (ufl.VectorElement, ufl.TensorElement))
assert not isinstance(element, (finat.ufl.VectorElement, finat.ufl.TensorElement))
dm_name = self._get_dm_name_for_checkpointing(tmesh, element)
path = self._path_to_vec(tmesh.name, dm_name, tf.name())
self.require_group(path)
Expand Down Expand Up @@ -894,7 +894,7 @@ def load_mesh(self, name=DEFAULT_MESH_NAME, reorder=None, distribution_parameter
variable_layers = self.get_attr(path, PREFIX_EXTRUDED + "_variable_layers")
if variable_layers:
cell = base_tmesh.ufl_cell()
element = ufl.VectorElement("DP" if cell.is_simplex() else "DQ", cell, 0, dim=2)
element = finat.ufl.VectorElement("DP" if cell.is_simplex() else "DQ", cell, 0, dim=2)
_ = self._load_function_space_topology(base_tmesh, element)
base_tmesh_key = self._generate_mesh_key_from_names(base_tmesh.name,
base_tmesh._distribution_name,
Expand Down Expand Up @@ -955,7 +955,7 @@ def load_mesh(self, name=DEFAULT_MESH_NAME, reorder=None, distribution_parameter
path = self._path_to_mesh_immersed(tmesh.name, name)
if path in self.h5pyfile:
cell = tmesh.ufl_cell()
element = ufl.FiniteElement("DP" if cell.is_simplex() else "DQ", cell, 0)
element = finat.ufl.FiniteElement("DP" if cell.is_simplex() else "DQ", cell, 0)
cell_orientations_tV = self._load_function_space_topology(tmesh, element)
tmesh_key = self._generate_mesh_key_from_names(tmesh.name,
tmesh._distribution_name,
Expand Down Expand Up @@ -1208,7 +1208,7 @@ def _load_function_topology(self, tmesh, element, tf_name, idx=None):
self.viewer.pushTimestepping()
self.viewer.setTimestep(idx)
if element.family() == "Real":
assert not isinstance(element, (ufl.VectorElement, ufl.TensorElement))
assert not isinstance(element, (finat.ufl.VectorElement, finat.ufl.TensorElement))
value = self.get_attr(path, "_".join([PREFIX, "value" if idx is None else "value_" + str(idx)]))
tf.dat.data.itemset(value)
else:
Expand Down Expand Up @@ -1247,10 +1247,10 @@ def _generate_function_space_name(self, V):
V_names = [PREFIX + "_function_space"]
for Vsub in V:
elem = Vsub.ufl_element()
if isinstance(elem, ufl.RestrictedElement):
if isinstance(elem, finat.ufl.RestrictedElement):
# RestrictedElement.shortstr() contains '<>|{}'.
elem_name = "RestrictedElement(%s,%s)" % (elem.sub_element().shortstr(), elem.restriction_domain())
elif isinstance(elem, ufl.EnrichedElement):
elif isinstance(elem, finat.ufl.EnrichedElement):
# EnrichedElement.shortstr() contains '<>+'.
elem_name = "EnrichedElement(%s)" % ",".join(e.shortstr() for e in elem._elements)
else:
Expand All @@ -1274,19 +1274,19 @@ def _get_shared_data_key_for_checkpointing(self, mesh, ufl_element):
real_tensorproduct = eutils.is_real_tensor_product_element(finat_element)
entity_dofs = finat_element.entity_dofs()
nodes_per_entity = tuple(mesh.make_dofs_per_plex_entity(entity_dofs))
if isinstance(ufl_element, ufl.TensorElement):
shape = ufl_element.reference_value_shape()
if isinstance(ufl_element, finat.ufl.TensorElement):
shape = ufl_element.reference_value_shape
block_size = np.product(shape)
elif isinstance(ufl_element, ufl.VectorElement):
shape = ufl_element.value_shape()[:1]
elif isinstance(ufl_element, finat.ufl.VectorElement):
shape = ufl_element.value_shape[:1]
block_size = np.product(shape)
else:
block_size = 1
return (nodes_per_entity, real_tensorproduct, block_size)

def _get_dm_for_checkpointing(self, tV):
sd_key = self._get_shared_data_key_for_checkpointing(tV.mesh(), tV.ufl_element())
if isinstance(tV.ufl_element(), (ufl.VectorElement, ufl.TensorElement)):
if isinstance(tV.ufl_element(), (finat.ufl.VectorElement, finat.ufl.TensorElement)):
nodes_per_entity, real_tensorproduct, block_size = sd_key
global_numbering = tV.mesh().create_section(nodes_per_entity, real_tensorproduct, block_size=block_size)
topology_dm = tV.mesh().topology_dm
Expand Down Expand Up @@ -1421,6 +1421,7 @@ def _load_ufl_element(self, path, name):
globals = {}
locals = {}
exec("from ufl import *", globals, locals)
exec("from finat.ufl import *", globals, locals)
return eval(self.get_attr(path, name + "_repr"), globals, locals)
else:
return self._unpickle(self.get_attr(path, name)) # backward compat.
Expand Down
13 changes: 9 additions & 4 deletions firedrake/constant.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numpy as np
import ufl
import finat.ufl

from tsfc.ufl_utils import TSFCConstantMixin
from pyop2 import op2
Expand Down Expand Up @@ -67,14 +68,18 @@ def __new__(cls, value, domain=None, name=None, count=None):

dat, rank, shape = _create_dat(op2.Global, value, domain._comm)

domain = ufl.as_domain(domain)
if not isinstance(domain, ufl.AbstractDomain):
cell = ufl.as_cell(domain)
coordinate_element = finat.ufl.VectorElement("Lagrange", cell, 1, gdim=cell.geometric_dimension)
domain = ufl.Mesh(coordinate_element)

cell = domain.ufl_cell()
if rank == 0:
element = ufl.FiniteElement("R", cell, 0)
element = finat.ufl.FiniteElement("R", cell, 0)
elif rank == 1:
element = ufl.VectorElement("R", cell, 0, shape[0])
element = finat.ufl.VectorElement("R", cell, 0, shape[0])
else:
element = ufl.TensorElement("R", cell, 0, shape=shape)
element = finat.ufl.TensorElement("R", cell, 0, shape=shape)

R = FunctionSpace(domain, element, name="firedrake.Constant")
return Function(R, val=dat).assign(value)
Expand Down
29 changes: 15 additions & 14 deletions firedrake/embedding.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
# -*- coding: utf-8 -*-
"""Module for utility functions for scalable HDF5 I/O."""
import finat.ufl
import ufl


def get_embedding_dg_element(element):
cell = element.cell()
cell = element.cell
degree = element.degree()
family = lambda c: "DG" if c.is_simplex() else "DQ"
if isinstance(cell, ufl.TensorProductCell):
if type(degree) is int:
scalar_element = ufl.FiniteElement("DQ", cell=cell, degree=degree)
scalar_element = finat.ufl.FiniteElement("DQ", cell=cell, degree=degree)
else:
scalar_element = ufl.TensorProductElement(*(ufl.FiniteElement(family(c), cell=c, degree=d)
for (c, d) in zip(cell.sub_cells(), degree)))
scalar_element = finat.ufl.TensorProductElement(*(finat.ufl.FiniteElement(family(c), cell=c, degree=d)
for (c, d) in zip(cell.sub_cells(), degree)))
else:
scalar_element = ufl.FiniteElement(family(cell), cell=cell, degree=degree)
shape = element.value_shape()
scalar_element = finat.ufl.FiniteElement(family(cell), cell=cell, degree=degree)
shape = element.value_shape
if len(shape) == 0:
DG = scalar_element
elif len(shape) == 1:
shape, = shape
DG = ufl.VectorElement(scalar_element, dim=shape)
DG = finat.ufl.VectorElement(scalar_element, dim=shape)
else:
if isinstance(element, ufl.TensorElement):
if isinstance(element, finat.ufl.TensorElement):
symmetry = element.symmetry()
else:
symmetry = None
DG = ufl.TensorElement(scalar_element, shape=shape, symmetry=symmetry)
DG = finat.ufl.TensorElement(scalar_element, shape=shape, symmetry=symmetry)
return DG


Expand All @@ -43,19 +44,19 @@ def get_embedding_element_for_checkpointing(element):

def get_embedding_method_for_checkpointing(element):
"""Return the method used to embed element in dg space."""
if isinstance(element, (ufl.HDivElement, ufl.HCurlElement, ufl.WithMapping)):
if isinstance(element, (finat.ufl.HDivElement, finat.ufl.HCurlElement, finat.ufl.WithMapping)):
return "project"
elif isinstance(element, (ufl.VectorElement, ufl.TensorElement)):
elem, = set(element.sub_elements())
elif isinstance(element, (finat.ufl.VectorElement, finat.ufl.TensorElement)):
elem, = set(element.sub_elements)
return get_embedding_method_for_checkpointing(elem)
elif element.family() in ['Lagrange', 'Discontinuous Lagrange',
'Nedelec 1st kind H(curl)', 'Raviart-Thomas',
'Nedelec 2nd kind H(curl)', 'Brezzi-Douglas-Marini',
'Q', 'DQ',
'S', 'DPC', 'Real']:
return "interpolate"
elif isinstance(element, ufl.TensorProductElement):
methods = [get_embedding_method_for_checkpointing(elem) for elem in element.sub_elements()]
elif isinstance(element, finat.ufl.TensorProductElement):
methods = [get_embedding_method_for_checkpointing(elem) for elem in element.sub_elements]
if any(method == "project" for method in methods):
return "project"
else:
Expand Down
2 changes: 1 addition & 1 deletion firedrake/extrusion_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def make_extruded_coords(extruded_topology, base_coords, ext_coords,
coordinates on the extruded cell (to write to), the fixed layer
height, and the current cell layer.
"""
_, vert_space = ext_coords.function_space().ufl_element().sub_elements()[0].sub_elements()
_, vert_space = ext_coords.function_space().ufl_element().sub_elements[0].sub_elements
if kernel is None and not (vert_space.degree() == 1
and vert_space.family() in ['Lagrange',
'Discontinuous Lagrange']):
Expand Down
2 changes: 1 addition & 1 deletion firedrake/formmanipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def argument(self, o):
else:
args += [Zero()
for j in numpy.ndindex(
V_is[i].ufl_element().value_shape())]
V_is[i].ufl_element().value_shape)]
return self._arg_cache.setdefault(o, as_vector(args))


Expand Down
Loading
Loading