Skip to content
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
6573217
First draft of expanding set size to match when unioning
indiamai Aug 19, 2024
dc5188a
Change condition of extension
indiamai Aug 19, 2024
c75efef
Adapt new coeff construction for vec sets
indiamai Aug 20, 2024
dfd1347
select larger of degrees
indiamai Aug 21, 2024
21f1bf1
Add orthonormal requirement
indiamai Aug 28, 2024
3eb0d1a
merge master
indiamai Nov 18, 2024
2c21e27
Merge master
indiamai Dec 9, 2024
2b45bd5
Move finat commits from old branch
indiamai Dec 9, 2024
9b05688
Lint
indiamai Dec 9, 2024
3a7bb5b
Merge master
indiamai Jan 6, 2025
8d1a074
Refactor to deal with single source of truth
indiamai Jan 6, 2025
b72cd61
Refactoring
indiamai Jan 6, 2025
a89d057
Renaming fuse project (#125)
indiamai Jan 10, 2025
ac81474
Address Pablo's comments
indiamai Jan 11, 2025
9420a6d
Lint
indiamai Jan 11, 2025
be81de3
Remove final references to India Def
indiamai Jan 11, 2025
2e3ed6c
Add test, small change to spatial dimension management
indiamai Jan 13, 2025
0b593e5
remove fuse dependency
indiamai Jan 15, 2025
263dad1
Modify code to use np.pad
indiamai Jan 16, 2025
ad63ee0
Add extension of coefficients to allow union of polysets with differe…
indiamai Jan 16, 2025
3a5b073
Small changes to allow different topologies
indiamai Jan 17, 2025
8d52e22
remove orthonormal as seems to be no longer necessary
indiamai Jan 22, 2025
8eaa60c
Remove further orthonormals
indiamai Jan 23, 2025
d3b31cb
Merge branch 'indiamai/extend_coeffs' into indiamai/integrate_fuse
indiamai Jan 23, 2025
b5e41fe
Merge branch 'master' into indiamai/integrate_fuse
indiamai Jan 26, 2025
f31fd72
Update UFL rep of fuse element to cover both regular fuse and tensor …
indiamai Feb 10, 2025
a91c7a2
tensor prod infrastructure
indiamai Feb 17, 2025
2bc3161
convert things to generic as_Cell and add flattening infra for fuse
indiamai Feb 20, 2025
4953241
Add generic hypercube class
indiamai Feb 21, 2025
e8aaa56
Change type to allow comparision of subclasses of tensor product cell…
indiamai Feb 26, 2025
a726c98
Add function that moves any cell to a simplex. Modify DPC to use
indiamai Mar 13, 2025
7d5ef1c
Integrate hypercube changes to fuse (#137)
indiamai Mar 21, 2025
9e2f7c0
Merge branch 'master' into indiamai/integrate_fuse
indiamai Apr 30, 2025
2f8a74d
Merge branch 'master' into indiamai/integrate_fuse
indiamai Apr 30, 2025
8771342
First stab at a rewrite of connectivity to respect non UFC ordering
indiamai May 5, 2025
2373db4
refactor, simplify
indiamai May 6, 2025
3482800
remove print
indiamai May 7, 2025
ef6c59c
modify to use hasse diagram for fuse sub entities
indiamai May 16, 2025
df581a7
remove print
indiamai May 16, 2025
dde1c05
add the ablity to pass facet orientation to facet quadrature rule
indiamai May 23, 2025
f04175e
Merge branch 'master' into indiamai/integrate_fuse
indiamai Jun 12, 2025
ab73328
add clearer error
indiamai Jun 12, 2025
85cef62
Merge branch 'main' into indiamai/integrate_fuse
indiamai Sep 25, 2025
e665761
Move fuse as_cell dependence out of UFL and into final.ufl (#184)
indiamai Oct 1, 2025
53bc284
Merge branch 'main' into indiamai/integrate_fuse
indiamai Oct 30, 2025
a4a887c
Merge branch 'main' into indiamai/integrate_fuse
indiamai Oct 30, 2025
4633e7f
Merge branch 'main' into indiamai/integrate_fuse
indiamai Dec 3, 2025
720e2fa
use ufl sobolev spaces
indiamai Mar 11, 2026
63e381f
remove to_ufl
indiamai Mar 31, 2026
e645ce7
changes to allow custom fuse transforms
indiamai May 15, 2026
99a5a31
change degree access
indiamai Jun 11, 2026
0858daf
add triple to enriched
indiamai Jun 15, 2026
34e1301
Merge branch 'main' into indiamai/integrate_fuse
indiamai Jun 18, 2026
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
8 changes: 4 additions & 4 deletions FIAT/nedelec.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def NedelecSpace2D(ref_el, degree):
raise Exception("NedelecSpace2D requires 2d reference element")

k = degree - 1
vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, (sd,))
vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, (sd,), scale="orthonormal")

dimPkp1 = expansions.polynomial_dimension(ref_el, k + 1)
dimPk = expansions.polynomial_dimension(ref_el, k)
Expand All @@ -32,7 +32,7 @@ def NedelecSpace2D(ref_el, degree):
for i in range(sd))))
vec_Pk_from_Pkp1 = vec_Pkp1.take(vec_Pk_indices)

Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1)
Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, scale="orthonormal")
PkH = Pkp1.take(list(range(dimPkm1, dimPk)))

Q = create_quadrature(ref_el, 2 * (k + 1))
Expand All @@ -43,8 +43,8 @@ def NedelecSpace2D(ref_el, degree):

CrossX = numpy.dot(numpy.array([[0.0, 1.0], [-1.0, 0.0]]), Qpts.T)
PkHCrossX_at_Qpts = PkH_at_Qpts[:, None, :] * CrossX[None, :, :]
PkHCrossX_coeffs = numpy.dot(numpy.multiply(PkHCrossX_at_Qpts, Qwts), Pkp1_at_Qpts.T)

PkHCrossX_coeffs = numpy.dot(numpy.multiply(PkHCrossX_at_Qpts, Qwts),
Pkp1_at_Qpts.T)
PkHcrossX = polynomial_set.PolynomialSet(ref_el,
k + 1,
k + 1,
Expand Down
42 changes: 39 additions & 3 deletions FIAT/polynomial_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,51 @@ def polynomial_set_union_normalized(A, B):
not contain any of the same members of the set, as we construct a
span via SVD.
"""
new_coeffs = numpy.concatenate((A.coeffs, B.coeffs), axis=0)
assert A.get_reference_element() == B.get_reference_element()
new_coeffs = construct_new_coeffs(A.get_reference_element(), A, B)

deg = max(A.get_degree(), B.get_degree())
em_deg = max(A.get_embedded_degree(), B.get_embedded_degree())
coeffs = spanning_basis(new_coeffs)
return PolynomialSet(A.get_reference_element(),
A.get_degree(),
A.get_embedded_degree(),
deg,
em_deg,
A.get_expansion_set(),
coeffs)


def construct_new_coeffs(ref_el, A, B):
# Constructs new coefficients for the set union of A and B
# If A and B do not have the same degree the smaller one
# is extended to match the larger

sd = ref_el.get_spatial_dimension()
if A.get_embedded_degree() != B.get_embedded_degree():

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to check also for the continuity of the expansion sets. We throw a ValueError if they are different. This logic would only work for discontinuous expansion sets, and break if the expansion set continuity is "C1".

Suggested change
if A.get_embedded_degree() != B.get_embedded_degree():
if A.get_embedded_degree() != B.get_embedded_degree() and continuity is None:

higher = A if A.degree > B.degree else B
lower = B if A.degree > B.degree else A

try:
sd = lower.get_shape()[0]
except IndexError:
sd = 1

embedded_coeffs = []
diff = higher.coeffs.shape[-1] - lower.coeffs.shape[-1]
for coeff in lower.coeffs:
if sd > 1:
new_coeff = []
for row in coeff:
new_coeff.append(numpy.append(row, [0 for i in range(diff)]))
embedded_coeffs.append(new_coeff)
else:
embedded_coeffs.append(numpy.append(coeff, [0 for i in range(diff)]))
embedded_coeffs = numpy.array(embedded_coeffs)
new_coeffs = numpy.array(list(embedded_coeffs) + list(higher.coeffs))
else:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this case works if A and B have the same continuity and degree.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess then this function still needs to handle the case where A and B are not discontinuous but don't have the same degree. I haven't encountered this yet but will add it as a note in the function.

new_coeffs = numpy.array(list(A.coeffs) + list(B.coeffs))
Comment thread
indiamai marked this conversation as resolved.
Outdated
return new_coeffs


class ONSymTensorPolynomialSet(PolynomialSet):
"""Constructs an orthonormal basis for symmetric-tensor-valued
polynomials on a reference element.
Expand Down
6 changes: 3 additions & 3 deletions FIAT/raviart_thomas.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def RTSpace(ref_el, degree):
sd = ref_el.get_spatial_dimension()

k = degree - 1
vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, (sd,))
vec_Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, (sd,), scale="orthonormal")

dimPkp1 = expansions.polynomial_dimension(ref_el, k + 1)
dimPk = expansions.polynomial_dimension(ref_el, k)
Expand All @@ -30,7 +30,7 @@ def RTSpace(ref_el, degree):
for i in range(sd))))
vec_Pk_from_Pkp1 = vec_Pkp1.take(vec_Pk_indices)

Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1)
Pkp1 = polynomial_set.ONPolynomialSet(ref_el, k + 1, scale="orthonormal")
PkH = Pkp1.take(list(range(dimPkm1, dimPk)))

Q = create_quadrature(ref_el, 2 * (k + 1))
Expand All @@ -39,12 +39,12 @@ def RTSpace(ref_el, degree):
# have to work on this through "tabulate" interface
# first, tabulate PkH at quadrature points
PkH_at_Qpts = PkH.tabulate(Qpts)[(0,) * sd]

Pkp1_at_Qpts = Pkp1.tabulate(Qpts)[(0,) * sd]

x = Qpts.T
PkHx_at_Qpts = PkH_at_Qpts[:, None, :] * x[None, :, :]
PkHx_coeffs = numpy.dot(numpy.multiply(PkHx_at_Qpts, Qwts), Pkp1_at_Qpts.T)

PkHx = polynomial_set.PolynomialSet(ref_el,
k,
k + 1,
Expand Down
3 changes: 2 additions & 1 deletion finat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
KongMulderVeldhuizen, Lagrange, Real, Serendipity, # noqa: F401
TrimmedSerendipityCurl, TrimmedSerendipityDiv, # noqa: F401
TrimmedSerendipityEdge, TrimmedSerendipityFace, # noqa: F401
Nedelec, NedelecSecondKind, RaviartThomas, Regge) # noqa: F401
Nedelec, NedelecSecondKind, RaviartThomas, Regge, # noqa: F401
IndiaDefElement) # noqa: F401

from .argyris import Argyris # noqa: F401
from .aw import ArnoldWinther, ArnoldWintherNC # noqa: F401
Expand Down
8 changes: 8 additions & 0 deletions finat/element_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import finat
import finat.ufl
from fuse.cells import CellComplexToUFL as FuseCell
import ufl

from FIAT import ufc_cell
Expand Down Expand Up @@ -112,6 +113,8 @@ def as_fiat_cell(cell):
:arg cell: the :class:`ufl.Cell` to convert."""
if not isinstance(cell, ufl.AbstractCell):
raise ValueError("Expecting a UFL Cell")
if isinstance(cell, FuseCell):
return cell.to_fiat()
return ufc_cell(cell)


Expand Down Expand Up @@ -302,6 +305,11 @@ def convert_restrictedelement(element, **kwargs):
return finat.RestrictedElement(finat_elem, element.restriction_domain()), deps


@convert.register(finat.ufl.FuseElement)
def convert_india_def(element, **kwargs):
return finat.fiat_elements.IndiaDefElement(element.triple), set()


hexahedron_tpc = ufl.TensorProductCell(ufl.interval, ufl.interval, ufl.interval)
quadrilateral_tpc = ufl.TensorProductCell(ufl.interval, ufl.interval)
_cache = weakref.WeakKeyDictionary()
Expand Down
5 changes: 5 additions & 0 deletions finat/fiat_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,8 @@ def __init__(self, cell, degree, variant=None):
class NedelecSecondKind(VectorFiatElement):
def __init__(self, cell, degree, variant=None):
super().__init__(FIAT.NedelecSecondKind(cell, degree, variant=variant))


class IndiaDefElement(FiatElement):
def __init__(self, triple):
super(IndiaDefElement, self).__init__(triple.to_fiat())
1 change: 1 addition & 0 deletions finat/ufl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
from finat.ufl.mixedelement import MixedElement, TensorElement, VectorElement # noqa: F401
from finat.ufl.restrictedelement import RestrictedElement # noqa: F401
from finat.ufl.tensorproductelement import TensorProductElement # noqa: F401
from finat.ufl.fuseelement import FuseElement # noqa: F401
45 changes: 45 additions & 0 deletions finat/ufl/fuseelement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Element."""
# -*- coding: utf-8 -*-
# Copyright (C) 2025 India Marsden
#
# SPDX-License-Identifier: LGPL-3.0-or-later

from finat.ufl.finiteelementbase import FiniteElementBase


class FuseElement(FiniteElementBase):
"""
A finite element defined using FUSE.

TODO: Need to deal with cases where value shape and reference value shape are different
"""

def __init__(self, triple, cell=None):
self.triple = triple
if not cell:
cell = self.triple.cell.to_ufl()

# this isn't really correct
degree = self.triple.spaces[0].degree()
super(FuseElement, self).__init__("IT", cell, degree, None, triple.get_value_shape())

def __repr__(self):
return "FiniteElement(%s, %s, (%s, %s, %s), %s)" % (
repr(self.triple.DOFGenerator), repr(self.triple.cell), repr(self.triple.spaces[0]), repr(self.triple.spaces[1]), repr(self.triple.spaces[2]), "X")

def __str__(self):
return "<Fuse%sElem on %s>" % (self.triple.spaces[0], self.triple.cell)

def mapping(self):
if str(self.sobolev_space) == "HCurl":
return "covariant Piola"
elif str(self.sobolev_space) == "HDiv":
return "contravariant Piola"
else:
return "identity"

def sobolev_space(self):
return self.triple.spaces[1]

def reconstruct(self, family=None, cell=None, degree=None, quad_scheme=None, variant=None):
return FuseElement(self.triple, cell=cell)
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies = [
"symengine",
"sympy",
"fenics-ufl @ git+https://github.com/firedrakeproject/ufl.git",
"fuse-element @ git+https://github.com/indiamai/fuse.git",
]
requires-python = ">=3.10"
authors = [
Expand Down