From a93b1b319cf11e3c11f20e1e85a73e69794c802b Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Thu, 2 Oct 2025 16:23:59 +0100 Subject: [PATCH 1/5] Bump version number --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 310ae088..5e9567b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "firedrake-fiat" # TODO RELEASE -version = "2025.10.0.dev0" +version = "2025.10.1.dev0" dependencies = [ # TODO RELEASE "fenics-ufl @ git+https://github.com/FEniCS/ufl.git@release", From 7c4249cf83b7889c685dc68b3c5e9ede3d2f9c91 Mon Sep 17 00:00:00 2001 From: ksagiyam <46749170+ksagiyam@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:34:14 +0100 Subject: [PATCH 2/5] gem: disable making temporaries for VariableIndexs (#195) --- gem/scheduling.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gem/scheduling.py b/gem/scheduling.py index 41039a0e..7e361cd8 100644 --- a/gem/scheduling.py +++ b/gem/scheduling.py @@ -117,10 +117,6 @@ def handle(ops, push, decref, node): elif isinstance(node, gem.Zero): # should rarely happen assert not node.shape elif isinstance(node, (gem.Indexed, gem.FlexiblyIndexed)): - if node.indirect_children: - # Do not inline; - # Index expression can be involved if it contains VariableIndex. - ops.append(impero.Evaluate(node)) for child in itertools.chain(node.children, node.indirect_children): decref(child) elif isinstance(node, gem.IndexSum): From 763c49455767cebb83d754c517f4781a3cd81237 Mon Sep 17 00:00:00 2001 From: Pablo Brubeck Date: Thu, 30 Oct 2025 21:09:53 +0000 Subject: [PATCH 3/5] Lumped mass quadrature scheme (#197) * Lumped mass quadrature scheme --- finat/quadrature.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/finat/quadrature.py b/finat/quadrature.py index 0272313c..702b5d23 100644 --- a/finat/quadrature.py +++ b/finat/quadrature.py @@ -9,7 +9,8 @@ from FIAT.reference_element import LINE, QUADRILATERAL, TENSORPRODUCT from gem.utils import safe_repr -from finat.point_set import GaussLegendrePointSet, KMVPointSet, PointSet, TensorPointSet +from finat.point_set import (GaussLegendrePointSet, GaussLobattoLegendrePointSet, + KMVPointSet, PointSet, TensorPointSet) def make_quadrature(ref_el, degree, scheme="default"): @@ -43,7 +44,13 @@ def make_quadrature(ref_el, degree, scheme="default"): if degree < 0: raise ValueError("Need positive degree, not %d" % degree) - if ref_el.get_shape() == LINE and not ref_el.is_macrocell(): + if scheme.lower() in {"kmv", "lump"}: + fiat_rule = fiat_scheme(ref_el, degree, "KMV") + if ref_el.get_shape() == LINE: + point_set = GaussLobattoLegendrePointSet(fiat_rule.get_points()) + else: + point_set = KMVPointSet(fiat_rule.get_points()) + elif ref_el.get_shape() == LINE and not ref_el.is_macrocell(): # FIAT uses Gauss-Legendre line quadature, however, since we # symbolically label it as such, we wish not to risk attaching # the wrong label in case FIAT changes. So we explicitly ask @@ -53,10 +60,7 @@ def make_quadrature(ref_el, degree, scheme="default"): point_set = GaussLegendrePointSet(fiat_rule.get_points()) else: fiat_rule = fiat_scheme(ref_el, degree, scheme) - if scheme.lower() == "kmv": - point_set = KMVPointSet(fiat_rule.get_points()) - else: - point_set = PointSet(fiat_rule.get_points()) + point_set = PointSet(fiat_rule.get_points()) return QuadratureRule(point_set, fiat_rule.get_weights(), ref_el=ref_el, io_ornt_map_tuple=fiat_rule._intrinsic_orientation_permutation_map_tuple) From b50607a714807c32dca1f2e412ce20ff299ba79c Mon Sep 17 00:00:00 2001 From: Connor Ward Date: Tue, 11 Nov 2025 09:50:09 +0000 Subject: [PATCH 4/5] Bump version number --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5e9567b1..c92ba5c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "firedrake-fiat" # TODO RELEASE -version = "2025.10.1.dev0" +version = "2025.10.2.dev0" dependencies = [ # TODO RELEASE "fenics-ufl @ git+https://github.com/FEniCS/ufl.git@release", From 418c59944e01cc283e925a8d6bb352c6cf77ba81 Mon Sep 17 00:00:00 2001 From: Pablo Brubeck Date: Fri, 28 Nov 2025 09:16:54 +0000 Subject: [PATCH 5/5] BUG: fix KMV embedded degree (#199) * BUG: fix KMV embedded degree * test --- finat/ufl/elementlist.py | 11 ++++++++++- test/finat/test_create_finat_element.py | 11 +++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/finat/ufl/elementlist.py b/finat/ufl/elementlist.py index d9f7126e..ebfd4fa5 100644 --- a/finat/ufl/elementlist.py +++ b/finat/ufl/elementlist.py @@ -463,6 +463,15 @@ def canonical_element_description(family, cell, order, form_degree): raise ValueError(f"Invalid value rank {value_rank}.") embedded_degree = order - if any(bubble in family for bubble in ("Guzman-Neilan", "Bernardi-Raugel")): + if family == "Kong-Mulder-Veldhuizen": + if order == 1: + bump = 0 + elif tdim == 2 and order < 5: + bump = 1 + else: + bump = 2 + embedded_degree += bump + elif any(bubble in family for bubble in ("Guzman-Neilan", "Bernardi-Raugel")): embedded_degree = tdim + return family, short_name, order, reference_value_shape, sobolev_space, mapping, embedded_degree diff --git a/test/finat/test_create_finat_element.py b/test/finat/test_create_finat_element.py index fd0d798d..02eaac8b 100644 --- a/test/finat/test_create_finat_element.py +++ b/test/finat/test_create_finat_element.py @@ -124,6 +124,17 @@ def test_quadrilateral_variant_spectral_dq_l2(): assert isinstance(element.product.factors[1], finat.GaussLegendre) +@pytest.mark.parametrize("cell, degree", + [(ufl.triangle, p) for p in range(1, 7)] + + [(ufl.tetrahedron, p) for p in range(1, 4)]) +def test_kmv(cell, degree): + ufl_element = finat.ufl.FiniteElement('KMV', cell, degree) + finat_element = create_element(ufl_element) + assert ufl_element.degree() == degree + assert ufl_element.embedded_superdegree == finat_element.degree + assert (finat_element.degree > degree) or (degree == 1) + + def test_cache_hit(ufl_element): A = create_element(ufl_element) B = create_element(ufl_element)