Skip to content

Commit

Permalink
Merge branch 'main' into jhale/bump-version
Browse files Browse the repository at this point in the history
  • Loading branch information
garth-wells authored May 23, 2023
2 parents 5ab8021 + e3c6cdd commit 850e6fc
Show file tree
Hide file tree
Showing 27 changed files with 100 additions and 111 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/fenicsx-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ jobs:
container: fenicsproject/test-env:nightly-openmpi

env:
CC: clang
CXX: clang++

PETSC_ARCH: linux-gnu-complex-32
OMPI_ALLOW_RUN_AS_ROOT: 1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pythonapp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ['3.7', '3.8', '3.9', '3.10']
python-version: ['3.8', '3.9', '3.10', '3.11']

steps:
- uses: actions/checkout@v3
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/tsfc-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@ jobs:
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
8 changes: 3 additions & 5 deletions doc/sphinx/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.

import sys
import os
import shlex
import pkg_resources
import datetime
import importlib.metadata

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
Expand Down Expand Up @@ -58,7 +55,8 @@
this_year = datetime.date.today().year
copyright = u'%s, FEniCS Project' % this_year
author = u'FEniCS Project'
version = pkg_resources.get_distribution("fenics-ufl").version

version = importlib.metadata.version("fenics-ufl")
release = version

# The language for content autogenerated by Sphinx. Refer to documentation
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[build-system]
requires = ["setuptools>=58", "wheel"]
requires = ["setuptools>=62", "wheel"]

build-backend = "setuptools.build_meta"
6 changes: 3 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ classifiers =
Operating System :: MacOS :: MacOS X
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Topic :: Scientific/Engineering :: Mathematics
Topic :: Software Development :: Libraries :: Python Modules

[options]
packages = find:
include_package_data = True
zip_safe = False
python_requires = >= 3.7
python_requires = >= 3.8
setup_requires =
setuptools >= 58
setuptools >= 62
wheel
install_requires =
numpy
Expand Down
16 changes: 0 additions & 16 deletions setup.py

This file was deleted.

4 changes: 4 additions & 0 deletions test/test_split.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def test_split(self):
assert (d+d,) == Coefficient(v2).ufl_shape
assert (2*d*d,) == Coefficient(m2).ufl_shape

# Split simple element
t = TestFunction(f)
assert split(t) == (t,)

# Split twice on nested mixed elements gets
# the innermost scalar subcomponents
t = TestFunction(f*v)
Expand Down
5 changes: 5 additions & 0 deletions test/test_str.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,8 @@ def test_str_list_matrix_with_zero():

# FIXME: Add more tests for tensors collapsing
# partly or completely into Zero!


def test_str_element():
elem = FiniteElement("Q", quadrilateral, 1)
assert str(elem) == "<Q1 on a quadrilateral>"
4 changes: 2 additions & 2 deletions ufl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@
# Modified by Massimiliano Leoni, 2016
# Modified by Cecile Daversin-Catty, 2018

import pkg_resources
import importlib.metadata

__version__ = pkg_resources.get_distribution("fenics-ufl").version
__version__ = importlib.metadata.version("fenics-ufl")

# README
# Imports here should be what the user sees when doing "from ufl import *",
Expand Down
11 changes: 5 additions & 6 deletions ufl/algorithms/apply_derivatives.py
Original file line number Diff line number Diff line change
Expand Up @@ -1268,12 +1268,11 @@ def coefficient_derivative(self, o):

def coordinate_derivative(self, o, f, w, v, cd):
from ufl.algorithms import extract_unique_elements
spaces = set(c.family() for c in extract_unique_elements(o))
unsupported_spaces = {"Argyris", "Bell", "Hermite", "Morley"}
if spaces & unsupported_spaces:
raise NotImplementedError(
"CoordinateDerivative is not supported for elements of type {spaces & unsupported_spaces}. "
"This is because their pullback is not implemented in UFL.")
for space in extract_unique_elements(o):
if space.mapping() == "custom":
raise NotImplementedError(
"CoordinateDerivative is not supported for elements with custom pull back.")

_, w, v, cd = o.ufl_operands
rules = CoordinateDerivativeRuleset(w, v, cd)
key = (CoordinateDerivativeRuleset, w, v, cd)
Expand Down
4 changes: 2 additions & 2 deletions ufl/algorithms/apply_function_pullbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def apply_known_single_pullback(r, element):
domain = extract_unique_domain(r)
if mapping == "physical":
return r
elif mapping == "identity":
elif mapping == "identity" or mapping == "custom":
return r
elif mapping == "contravariant Piola":
J = Jacobian(domain)
Expand Down Expand Up @@ -122,7 +122,7 @@ def apply_single_function_pullbacks(r, element):
if mapping in {"physical", "identity",
"contravariant Piola", "covariant Piola",
"double contravariant Piola", "double covariant Piola",
"L2 Piola"}:
"L2 Piola", "custom"}:
# Base case in recursion through elements. If the element
# advertises a mapping we know how to handle, do that
# directly.
Expand Down
4 changes: 1 addition & 3 deletions ufl/algorithms/apply_restrictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,10 @@ def coefficient(self, o):
def facet_normal(self, o):
D = extract_unique_domain(o)
e = D.ufl_coordinate_element()
f = e.family()
d = e.degree()
gd = D.geometric_dimension()
td = D.topological_dimension()

if f == "Lagrange" and d == 1 and gd == td:
if e._is_linear() and gd == td:
# For meshes with a continuous linear non-manifold
# coordinate field, the facet normal from side - points in
# the opposite direction of the one from side +. We must
Expand Down
2 changes: 1 addition & 1 deletion ufl/algorithms/change_to_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def ndarray(shape):
# covariant_hcurl_mapping = JinvT * PullbackOf(o)
ec, = ec
emapping = K[:, ec] # Column of K is row of K.T
elif mapping == "identity":
elif mapping == "identity" or mapping == "custom":
emapping = None
else:
raise ValueError(f"Unknown mapping: {mapping}")
Expand Down
2 changes: 0 additions & 2 deletions ufl/algorithms/compute_form_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@ def _compute_form_data_elements(self, arguments, coefficients, domains):
def _check_elements(form_data):
for element in chain(form_data.unique_elements,
form_data.unique_sub_elements):
if element.family() is None:
raise ValueError(f"Found element with undefined family: {element}")
if element.cell() is None:
raise ValueError(f"Found element with undefined cell: {element}")

Expand Down
2 changes: 1 addition & 1 deletion ufl/algorithms/elementtransformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def tear(element):
def _increase_degree(element, degree_rise):
if isinstance(element, (FiniteElement, VectorElement, TensorElement)):
# Can't increase degree for reals
if element.family() == "Real":
if element._is_globally_constant():
return element
return element.reconstruct(degree=(element.degree() + degree_rise))
elif isinstance(element, MixedElement):
Expand Down
2 changes: 1 addition & 1 deletion ufl/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def is_globally_constant(expr):
continue
elif isinstance(e, FormArgument):
# Accept only Real valued Arguments and Coefficients
if e.ufl_element().family() == "Real":
if e.ufl_element()._is_globally_constant():
continue
else:
return False
Expand Down
2 changes: 1 addition & 1 deletion ufl/core/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@

from ufl.core.ufl_type import UFLType, update_ufl_type_attributes


# --- The base object for all UFL expression tree nodes ---


class Expr(object, metaclass=UFLType):
"""Base class for all UFL expression types.
Expand Down
8 changes: 4 additions & 4 deletions ufl/finiteelement/elementlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,21 +106,21 @@ def show_elements():
(1, None), simplices[1:]) # "RTF" (2d), "N1F" (3d)

# Elements not in the periodic table
register_element("Argyris", "ARG", 0, H2, "identity", (5, 5), ("triangle",))
register_element("Bell", "BELL", 0, H2, "identity", (5, 5), ("triangle",))
register_element("Argyris", "ARG", 0, H2, "custom", (5, 5), ("triangle",))
register_element("Bell", "BELL", 0, H2, "custom", (5, 5), ("triangle",))
register_element("Brezzi-Douglas-Fortin-Marini", "BDFM", 1, HDiv,
"contravariant Piola", (1, None), simplices[1:])
register_element("Crouzeix-Raviart", "CR", 0, L2, "identity", (1, 1),
simplices[1:])
# TODO: Implement generic Tear operator for elements instead of this:
register_element("Discontinuous Raviart-Thomas", "DRT", 1, L2,
"contravariant Piola", (1, None), simplices[1:])
register_element("Hermite", "HER", 0, H1, "identity", (3, 3), simplices)
register_element("Hermite", "HER", 0, H1, "custom", (3, 3), simplices)
register_element("Kong-Mulder-Veldhuizen", "KMV", 0, H1, "identity", (1, None),
simplices[1:])
register_element("Mardal-Tai-Winther", "MTW", 1, H1, "contravariant Piola", (3, 3),
("triangle",))
register_element("Morley", "MOR", 0, H2, "identity", (2, 2), ("triangle",))
register_element("Morley", "MOR", 0, H2, "custom", (2, 2), ("triangle",))

# Special elements
register_element("Boundary Quadrature", "BQ", 0, L2, "identity", (0, None),
Expand Down
8 changes: 7 additions & 1 deletion ufl/finiteelement/finiteelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def __init__(self,
# simplify base though.
self._sobolev_space = sobolev_space
self._mapping = mapping
self._short_name = short_name
self._short_name = short_name or family
self._variant = variant

# Finite elements on quadrilaterals and hexahedrons have an IrreducibleInt as degree
Expand Down Expand Up @@ -189,6 +189,12 @@ def __repr__(self):
"""Format as string for evaluation as Python object."""
return self._repr

def _is_globally_constant(self):
return self.family() == "Real"

def _is_linear(self):
return self.family() == "Lagrange" and self.degree() == 1

def mapping(self):
"""Return the mapping type for this element ."""
return self._mapping
Expand Down
15 changes: 12 additions & 3 deletions ufl/finiteelement/finiteelementbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ class FiniteElementBase(ABC):
def __init__(self, family, cell, degree, quad_scheme, value_shape,
reference_value_shape):
"""Initialize basic finite element data."""
if not isinstance(family, str):
raise ValueError("Invalid family type.")
if not (degree is None or isinstance(degree, (int, tuple))):
raise ValueError("Invalid degree type.")
if not isinstance(value_shape, tuple):
Expand Down Expand Up @@ -62,6 +60,17 @@ def mapping(self):
"""Return the mapping type for this element."""
pass

def _is_globally_constant(self):
"""Check if the element is a global constant.
For Real elements, this should return True.
"""
return False

def _is_linear(self):
"""Check if the element is Lagrange degree 1."""
return False

def _ufl_hash_data_(self):
return repr(self)

Expand Down Expand Up @@ -109,7 +118,7 @@ def cell(self):
def is_cellwise_constant(self, component=None):
"""Return whether the basis functions of this
element is spatially constant over each cell."""
return self.family() == "Real" or self.degree() == 0
return self._is_globally_constant() or self.degree() == 0

def value_shape(self):
"Return the shape of the value space on the global domain."
Expand Down
3 changes: 3 additions & 0 deletions ufl/finiteelement/mixedelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ def __init__(self, *elements, **kwargs):
def __repr__(self):
return "MixedElement(" + ", ".join(repr(e) for e in self._sub_elements) + ")"

def _is_linear(self):
return all(i._is_linear() for i in self._sub_elements)

def reconstruct_from_elements(self, *elements):
"Reconstruct a mixed element from new subelements."
if all(a == b for (a, b) in zip(elements, self._sub_elements)):
Expand Down
3 changes: 3 additions & 0 deletions ufl/finiteelement/restrictedelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ def is_cellwise_constant(self):
"""
return self._element.is_cellwise_constant()

def _is_linear(self):
return self._element._is_linear()

def sub_element(self):
"Return the element which is restricted."
return self._element
Expand Down
4 changes: 1 addition & 3 deletions ufl/finiteelement/tensorproductelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ def __init__(self, *elements, **kwargs):
self._cell = cell

def __repr__(self):
return "TensorProductElement(" + ", ".join(
repr(e) for e in self._sub_elements
) + f", {repr(self._cell)})"
return "TensorProductElement(" + ", ".join(repr(e) for e in self._sub_elements) + f", cell={repr(self._cell)})"

def mapping(self):
if all(e.mapping() == "identity" for e in self._sub_elements):
Expand Down
Loading

0 comments on commit 850e6fc

Please sign in to comment.