From c4190b12057e8bcd9c30895d3f349ddade853f9b Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Wed, 18 Mar 2026 15:56:12 +0000 Subject: [PATCH 1/5] Fixes for Real x extruded following https://github.com/firedrakeproject/fiat/pull/237 --- tests/firedrake/vertexonly/test_interpolation_from_parent.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/firedrake/vertexonly/test_interpolation_from_parent.py b/tests/firedrake/vertexonly/test_interpolation_from_parent.py index 81dce16f4c..02b99d96b7 100644 --- a/tests/firedrake/vertexonly/test_interpolation_from_parent.py +++ b/tests/firedrake/vertexonly/test_interpolation_from_parent.py @@ -310,11 +310,6 @@ def test_scalar_real_interpolation(parentmesh, vertexcoords): vm = VertexOnlyMesh(parentmesh, vertexcoords, missing_points_behaviour="ignore") W = FunctionSpace(vm, "DG", 0) V = FunctionSpace(parentmesh, "Real", 0) - # Remove below when interpolating constant onto Real works for extruded - if type(parentmesh.topology) is mesh.ExtrudedMeshTopology: - with pytest.raises(ValueError): - assemble(interpolate(Constant(1), V)) - return v = assemble(interpolate(Constant(1), V)) w_v = assemble(interpolate(v, W)) assert np.allclose(w_v.dat.data_ro, 1.) From 312f99c268419ec06321dc4396719816f9667a4c Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Wed, 18 Mar 2026 15:57:40 +0000 Subject: [PATCH 2/5] branch pointer! --- .github/workflows/core.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 36744599f9..eb8f06c5b9 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -210,6 +210,9 @@ jobs: --extra-index-url https://download.pytorch.org/whl/cpu \ "$(echo ./firedrake-repo/dist/firedrake-*.tar.gz)[ci]" + : # UNDO ME + pip install git+https://github.com/firedrakeproject/fiat.git@connorjward/handle-real -v --no-deps --ignore-installed + firedrake-clean pip list From bda00db4a128d66b4bfd20f8ab1e089107a89a83 Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Thu, 19 Mar 2026 15:07:09 +0000 Subject: [PATCH 3/5] Don't special case Real so much --- tsfc/fem.py | 5 ----- tsfc/kernel_interface/common.py | 10 +--------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/tsfc/fem.py b/tsfc/fem.py index f4613cf8a3..943089052e 100644 --- a/tsfc/fem.py +++ b/tsfc/fem.py @@ -743,11 +743,6 @@ def translate_constant_value(terminal, mt, ctx): def translate_coefficient(terminal, mt, ctx): domain = extract_unique_domain(terminal) vec = ctx.coefficient(terminal, mt.restriction) - - if terminal.ufl_element().family() == 'Real': - assert mt.local_derivatives == 0 - return vec - element = ctx.create_element(terminal.ufl_element(), restriction=mt.restriction) # Collect FInAT tabulation for all entities diff --git a/tsfc/kernel_interface/common.py b/tsfc/kernel_interface/common.py index 4b48b0ca3f..aed238c64f 100644 --- a/tsfc/kernel_interface/common.py +++ b/tsfc/kernel_interface/common.py @@ -58,9 +58,7 @@ def coefficient(self, ufl_coefficient, restriction): kernel_arg = self.coefficient_map[ufl_coefficient] domain = extract_unique_domain(ufl_coefficient) assert self._domain_integral_type_map[domain] is not None - if ufl_coefficient.ufl_element().family() == 'Real': - return kernel_arg - elif not self._domain_integral_type_map[domain].startswith("interior_facet"): + if not self._domain_integral_type_map[domain].startswith("interior_facet"): return kernel_arg else: return kernel_arg[{'+': 0, '-': 1}[restriction]] @@ -495,12 +493,6 @@ def prepare_coefficient(coefficient, name, domain_integral_type_map): GEM expression referring to the Coefficient values. """ - if coefficient.ufl_element().family() == 'Real': - # Constant - value_size = coefficient.ufl_function_space().value_size - expression = gem.reshape(gem.Variable(name, (value_size,)), - coefficient.ufl_shape) - return expression finat_element = create_element(coefficient.ufl_element()) shape = finat_element.index_shape size = numpy.prod(shape, dtype=int) From ecd89b0ead09965b279b33106ee3aa7285b09a8b Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Fri, 20 Mar 2026 10:26:15 +0000 Subject: [PATCH 4/5] fixup --- firedrake/functionspace.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/firedrake/functionspace.py b/firedrake/functionspace.py index d073930804..316c16d608 100644 --- a/firedrake/functionspace.py +++ b/firedrake/functionspace.py @@ -55,6 +55,9 @@ def make_scalar_element(mesh, family, degree, vfamily, vdegree, variant, quad_sc if isinstance(family, finat.ufl.FiniteElementBase): return family.reconstruct(cell=cell) + if family in {"R", "Real"} and degree is None: + degree = 0 + if isinstance(cell, ufl.TensorProductCell) \ and vfamily is not None and vdegree is not None: la = finat.ufl.FiniteElement(family, From 687a1d1c6bb00f030de54baf6d6b0c5372686d83 Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Tue, 24 Mar 2026 09:07:11 +0000 Subject: [PATCH 5/5] Remove R degree hack --- firedrake/functionspace.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/firedrake/functionspace.py b/firedrake/functionspace.py index 316c16d608..c8134e774c 100644 --- a/firedrake/functionspace.py +++ b/firedrake/functionspace.py @@ -31,7 +31,8 @@ def make_scalar_element(mesh, family, degree, vfamily, vdegree, variant, quad_sc family : The finite element family. degree : - The degree of the finite element. + The degree of the finite element. If unspecified this will default + to the lowest degree available for the given family. vfamily : The finite element in the vertical dimension (extruded meshes only). @@ -55,9 +56,6 @@ def make_scalar_element(mesh, family, degree, vfamily, vdegree, variant, quad_sc if isinstance(family, finat.ufl.FiniteElementBase): return family.reconstruct(cell=cell) - if family in {"R", "Real"} and degree is None: - degree = 0 - if isinstance(cell, ufl.TensorProductCell) \ and vfamily is not None and vdegree is not None: la = finat.ufl.FiniteElement(family, @@ -89,7 +87,8 @@ def FunctionSpace(mesh, family, degree=None, name=None, family : The finite element family. degree : - The degree of the finite element. + The degree of the finite element. If unspecified this will default + to the lowest degree available for the given family. name: An optional name for the function space. vfamily : @@ -128,7 +127,8 @@ def DualSpace(mesh, family, degree=None, name=None, family : The finite element family. degree : - The degree of the finite element. + The degree of the finite element. If unspecified this will default + to the lowest degree available for the given family. name : An optional name for the function space. vfamily: @@ -167,7 +167,8 @@ def VectorFunctionSpace(mesh, family, degree=None, dim=None, name=None, family : The finite element family. degree : - The degree of the finite element. + The degree of the finite element. If unspecified this will default + to the lowest degree available for the given family. dim : An optional number of degrees of freedom per function space node (defaults to the geometric dimension of the mesh). @@ -219,7 +220,8 @@ def TensorFunctionSpace(mesh, family, degree=None, shape=None, family : The finite element family. degree : - The degree of the finite element. + The degree of the finite element. If unspecified this will default + to the lowest degree available for the given family. shape : An optional shape for the tensor-valued degrees of freedom at each function space node (defaults to a square tensor using the