Giter Site home page Giter Site logo

fenics / ufl Goto Github PK

View Code? Open in Web Editor NEW
88.0 88.0 65.0 5.63 MB

UFL - Unified Form Language

Home Page: https://fenicsproject.org

License: GNU Lesser General Public License v3.0

Python 100.00%
domain-specific-language fenicsx finite-element-method finite-element-software partial-differential-equations python variational-method

ufl's People

Contributors

anderslogg avatar aslakbergersen avatar blechta avatar cdaversin avatar celdred avatar chrisrichardson avatar dham avatar florianwechsung avatar garth-wells avatar gmarkall avatar igorbaratta avatar ivanyashchuk avatar jhale avatar johannesring avatar jorgensd avatar kent-and avatar kynan avatar lzlarryli avatar massimiliano-leoni avatar meg-simula avatar michalhabera avatar miklos1 avatar mscroggs avatar nbouziani avatar nicholasbarton avatar pbrubeck avatar snicholasbarton avatar thomasgibson avatar vidartf avatar wence- avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ufl's Issues

DAG visitor overhaul

The MultiFunction based map_dag visitors in UFL provide a caching (and hence efficient) API for implementing post-order visits of a UFL DAG. The core function is map_expr_dags (the relevant part is here https://github.com/FEniCS/ufl/blob/master/ufl/corealg/map_dag.py#L64).

Most of the transformations in the UFL pipeline are bottom up (post-order) and so are well-served by this infrastructure. Some, however, are pre-order (or at least partially pre-order). Examples include the restriction propagation (which hand-codes a post-order visit of a restricted subtree https://github.com/FEniCS/ufl/blob/master/ufl/algorithms/apply_restrictions.py#L36)

This can lead to unintended performance bugs where one, by necessity, hand-codes the DAG recursion to get a pre-order visit. This will blow up the perceived size of the DAG, the avoidance of which was one of the major motiviating factors for the ReuseTransformer -> MultiFunction + map_expr_dag transition.

Unfortunately, providing a caching pre-order visit requires that the visitor object sees the cache (the post-order visit cache can be managed completely from the outside). In the latter case the MultiFunction does not implement its own recursion and instead is used for type-based method dispatch on the first argument.

In tsfc, this issue is solved by having a more general visitor implementation (https://github.com/firedrakeproject/tsfc/blob/master/gem/node.py#L187). One writes singledispatch recursive functions that take the cache-manager as a parameter. Recursion is done by __call__ing this parameter on children as necessary.

Here's an example from tsfc using this pattern to manage abs-simplification (from https://github.com/firedrakeproject/tsfc/blob/master/tsfc/ufl_utils.py#L250)

@singledispatch
def _simplify_abs(o, self, in_abs):
    """Single-dispatch function to simplify absolute values.

    :arg o: UFL node
    :arg self: Callback handler for recursion
    :arg in_abs: Is ``o`` inside an absolute value?

    When ``in_abs`` we must return a non-negative value, potentially
    by wrapping the returned node with ``Abs``.
    """
    raise AssertionError("UFL node expected, not %s" % type(o))

@_simplify_abs.register(Expr)
def _simplify_abs_expr(o, self, in_abs):
    # General case, only wrap the outer expression (if necessary)
    operands = [self(op, False) for op in o.ufl_operands]
    result = ufl_reuse_if_untouched(o, *operands)
    if in_abs:
        result = Abs(result)
    return result

...

@_simplify_abs.register(Abs)
def _simplify_abs_abs(o, self, in_abs):
    return self(o.ufl_operands[0], True)

def simplify_abs(expression):
    """Simplify absolute values in a UFL expression.  Its primary
    purpose is to "neutralise" CellOrientation nodes that are
    surrounded by absolute values and thus not at all necessary."""
    mapper = MemoizerArg(_simplify_abs)
    return mapper(expression, False)

The MemoizerArg manages the caching and recursion, the visitor just needs to implement appropriate handlers for all of the nodes (and recurse where necessary).

This supports caching in both pre- and post-order traversal because the dispatch functions see the memoizer object.

We could implement something like this for UFL, I think one can probably provide backwards-compat to the existing MultiFunction setup.

Any other better suggestions? The current functional interface of map_expr_dag precludes stashing the callbacks on the MultiFunction object easily.

Group integrals by metadata

Currently UFL groups integrals by domain, integral_type, subdomain_id into IntegralData objects.
The form compiler then uses this to generate different kernels.

However, forms with different metadata are grouped, and in FFCx, this can potentially produce an error (see: #Issue 394).

Ideally, we would like to have one kernel by metadata (and possibly a quadrature rule per kernel).
Our proposal is to modify build_integral_data, to group integrals by metadata.

@wence- Any thoughts on that? Would it be ok for tsfc?

Replace `pkg_resources` with `importlib.metadata`

Built-in functionality to use with Python>=3.8, ref:
https://docs.python.org/3/library/importlib.metadata.html

Context
Python 3.7 EOL is happening in 2 months: https://endoflife.date/python
and the usage of pkg_resources with ufl causes a lot of deprecation warnings:

 python3 -Wd -c "import pkg_resources"    
/usr/local/lib/python3.10/dist-packages/pkg_resources/__init__.py:121: DeprecationWarning: pkg_resources is deprecated as an API
  warnings.warn("pkg_resources is deprecated as an API", DeprecationWarning)
/usr/local/lib/python3.10/dist-packages/pkg_resources/__init__.py:2870: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('mpl_toolkits')`.
Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages
  declare_namespace(pkg)
/usr/local/lib/python3.10/dist-packages/pkg_resources/__init__.py:2870: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('sphinxcontrib')`.
Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages
  declare_namespace(pkg)

As Legacy DOLFIN does not support main branch of UFL, this is safe from a DOLFIN perspective, as DOLFINx, requires Python>=3.8 (https://github.com/FEniCS/dolfinx/blob/main/python/setup.py).
As far as I can tell, Firedrake still supports Python 3.7.

How to compute differential of a complex form?

Hello UFL users and developers,

This post is taken from the fenics forum with an adapted minimal working example.

I'm trying to use a fenics code to reproduce the results of this paper as part of a validation process.

This is a fluid mechanics paper that involves a specific decomposition : q(x,r,theta,t)=q_0(x,r)+epsilon q_1(x,r)e^(imtheta+(sigma+i omega)t) Going from the Navier-Stokes equations Nd_tq+M(q)=0 and obtaining a base flow q_0 from M(q_0)=0, this allows for computation of the perturbations as a generalised eigenvalue problem dM/dq(q_0)q_1=(sigma+i omega)Nq_1

The nonlinear operator M is well--known in the case of the Navier Stokes equations but in this decomposition it is complex (q_1 is complex as well). The core of the problem is computing dM/dq.

I've read here that the UFL can handle complex values. The code below is an attempt to leverage automatic differentiation to obtain dM/dq(q_0)

from ufl import *
from ufl.classes import TestFunction, TrialFunction
from ufl.algorithms.compute_form_data import compute_form_data

# Physical parameters
m=-1
Re=200
cell = triangle
FE_vector=VectorElement("Lagrange",cell,2,3)
FE_scalar=FiniteElement("Lagrange",cell,1)
FE_TH = MixedElement([FE_vector,FE_scalar])
# Test and trial functions
test = TestFunction(FE_TH)
trial = TrialFunction(FE_TH)
# Initial conditions
q = Coefficient(FE_TH)

# Gradient with x[0] is x, x[1] is r, x[2] is theta
def grad(v,m):
	return as_tensor([[v[0].dx(0), v[0].dx(1), m*1j*v[0]],
				 	  [v[1].dx(0), v[1].dx(1), m*1j*v[1]-v[2]],
					  [v[2].dx(0), v[2].dx(1), m*1j*v[2]+v[1]]])

def div(v,m): return v[0].dx(0) + v[1].dx(1) + m*1j*v[2]

# Navier Stokes variational form
def NS_form(m):
    u,p=split(q)
    test_u,test_m=split(test)

    #mass (variational formulation)
    M = div(u,m)*test_m*dx
    #set_trace()
    #momentum (different test functions and IBP)
    M += 	    dot(grad(u,m)*u,	test_u)   *dx # Convection
    M += 1/Re*inner(grad(u,m), grad(test_u,m))*dx # Diffusion
    M -= 	    dot(p, 			div(test_u,m))*dx # Pressure
    return M

pert_form=compute_form_data(NS_form(m),complex_mode=True)

With my installation, UFL bundled into dolfin 2019.1.0 installed using docker I obtain the resulting traceback :

Traceback (most recent call last):
  File "MWE_ufl.py", line 46, in <module>
    pert_form=compute_form_data(NS_form(m),complex_mode=True)
  File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/compute_form_data.py", line 418, in compute_form_data
    check_form_arity(preprocessed_form, self.original_form.arguments(), complex_mode)  # Currently testing how fast this is
  File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/check_arities.py", line 177, in check_form_arity
    check_integrand_arity(itg.integrand(), arguments, complex_mode)
  File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/check_arities.py", line 159, in check_integrand_arity
    arg_tuples = map_expr_dag(rules, expr, compress=False)
  File "/usr/local/lib/python3.6/dist-packages/ufl/corealg/map_dag.py", line 37, in map_expr_dag
    result, = map_expr_dags(function, [expression], compress=compress)
  File "/usr/local/lib/python3.6/dist-packages/ufl/corealg/map_dag.py", line 86, in map_expr_dags
    r = handlers[v._ufl_typecode_](v, *[vcache[u] for u in v.ufl_operands])
  File "/usr/local/lib/python3.6/dist-packages/ufl/algorithms/check_arities.py", line 48, in sum
    raise ArityMismatch("Adding expressions with non-matching form arguments {0} vs {1}.".format(_afmt(a), _afmt(b)))
ufl.algorithms.check_arities.ArityMismatch: Adding expressions with non-matching form arguments ('v_0',) vs ('conj(v_0)',).

I would be grateful on any insight as to why this error arises, how to go around it, or more generally how to handle complex values in UFL (I've found few examples) and how to solve my problem.

Remove depcreacted way of defining Coefficients, Arguments etc.

The code consists of several deprecated ways of defining coefficients, arguments etc (used in old ufl files).
For instance:

DG jump operator gives the wrong result for a vector-valued equation

The standard Discontinuous Galerkin formulation of the scalar Poisson equation

$$ -\Delta u = 1 $$

has terms like

$$\sum_{e \in \mathcal{E}} \int_e [v] \{\nabla u\} $$

which in UFL is expressed as

inner(jump(v, n), avg(grad(u))) * dS

and all is well.

For the case in which the equation is vector valued, however, $u$ is now a vector and so $\nabla u$ is a second-order tensor, while $[v]$ will be either a scalar or a vector depending on whether jump(v, n) or jump(v) is used, so the inner product is not well-defined any more.

The (one?) correct DG formulation for the vector Poisson equation uses the term

$$\sum_{e \in \mathcal{E}} \int_e [v]_\otimes : \{\nabla u\} $$

where

$$[v]_\otimes = v^+ \otimes n^+ + v^- \otimes n^-.$$

I tried implementing this with

inner(jump(outer(v, n)), avg(grad(u))) * dS

but, with the current UFL implementation,

ufl/ufl/operators.py

Lines 441 to 452 in 64c846a

def jump(v, n=None):
"UFL operator: Take the jump of *v* across a facet."
v = as_ufl(v)
is_constant = len(extract_domains(v)) > 0
if is_constant:
if n is None:
return v('+') - v('-')
r = len(v.ufl_shape)
if r == 0:
return v('+') * n('+') + v('-') * n('-')
else:
return dot(v('+'), n('+')) + dot(v('-'), n('-'))

this returns [notice the wrong "-" instead of a "+"]
$$v^+ \otimes n^+ - v^- \otimes n^-.$$

CoordinateDerivative and Conj do not compose correctly.

suppose in a complex valued inverse problem we have:

x = SpatialCoordinate(mesh)
functional = f(x)*dx

where f(x) is some UFL expression which might be a function of x. Now, the adjoint will need to compute:

conj(derivative(functional, mesh)

Which is currently an error since CoordinateDerivative must be the outermost operator on any expression. If we push the conj inside the derivative then this is also an error because then the conjugate is not applied to the det(J) which results from integral scaling. In combination with the CoordinateDerivative this causes unconjugated test functions, which is an error.

Answers on a postcard please.

H1curl matrix element get bigger and bigger

Hi all, I found the maximum element value of the assemble matrix of inner(curl(u), curl(v))*dx increases with the mesh size, while inner(u, v)*dx does not. Is it normal?

from fenics import *

mesh = UnitSquareMesh(40, 40)
V = FunctionSpace(mesh, "N1curl", 1)

u = TrialFunction(V)
v = TestFunction(V)
a = inner(curl(u), curl(v)) * dx
A = assemble(a)

A.array().max()

UFL deprecated function used in UFL code

Running ufl tests highlights the issue:

python3 -m pytest -xvs test/
====================================================================================================== test session starts ======================================================================================================
platform linux -- Python 3.8.10, pytest-7.1.3, pluggy-1.0.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: ...
plugins: forked-1.4.0, xdist-2.5.0
collected 561 items                                                                                                                                                                                                             

test/test_algorithms.py::test_extract_arguments_vs_fixture PASSED
test/test_algorithms.py::test_extract_coefficients_vs_fixture PASSED
test/test_algorithms.py::test_extract_elements_and_extract_unique_elements PASSED
test/test_algorithms.py::test_pre_and_post_traversal PASSED
test/test_algorithms.py::test_expand_indices Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_algorithms.py::test_adjoint PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/Constant.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/ConvectionJacobi.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/ConvectionJacobi2.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/ConvectionVector.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/Elasticity.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/EnergyNorm.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/Equation.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/ExplicitConvection.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/FEEC.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/FunctionOperators.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/H1norm.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/HarmonicMap.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/HarmonicMap2.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/Heat.py] PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/HornSchunck.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED
test/test_analyse_demos.py::test_demo_files[/home/ia397/Projects/fenics/ufl/demo/HyperElasticity.py] Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
Expr.ufl_domain() is deprecated, please use extract_unique_domain(expr) instead.
PASSED

 

uflx and legacy dolfin/ffc support

ufl 2022.1.0 got released, bringing in modernization of the API. That's great, except some projects will still be using old dolfin.

For instance, the dolfin demos include demo/documented/poisson/cpp/Poisson.ufl, which uses FiniteElement. That's been removed from ufl 2022.1.0 (there is FiniteElementBase instead), and so running old ffc fails:

$ ffc -l dolfin -s -O -r auto Poisson.ufl
Traceback (most recent call last):
  File "/build/dolfin/cmake/scripts/generate-form-files.py", line 90, in <module>
    ret = ffc.main(args)
  File "/usr/lib/python3/dist-packages/ffc/main.py", line 215, in main
    resultcode = _compile_files(args, parameters, enable_profile)
  File "/usr/lib/python3/dist-packages/ffc/main.py", line 248, in _compile_files
    ufd = load_ufl_file(filename)
  File "/usr/lib/python3/dist-packages/ufl/algorithms/formfiles.py", line 181, in load_ufl_file
    namespace = execute_ufl_code(uflcode)
  File "/usr/lib/python3/dist-packages/ufl/algorithms/formfiles.py", line 82, in execute_ufl_code
    exec(uflcode, namespace)
  File "<string>", line 24, in <module>
NameError: name 'FiniteElement' is not defined

(this is after patching old ffc with its own copy of cellname2facetname).

I think that means it's not feasible to keep patching ffc (and dolfin) to keep up with latest ufl. Should ufl be renamed as uflx at this point, as was done for the ffcโ†’ffcx transition?

Error when using a coefficient derivative map of a vector coefficient w.r.t. a scalar

Taking the derivative of a form containing a vector coefficient w.r.t. a scalar coefficient and supplying a coefficient derivative map results in an error, e.g.:

test.py:

from ufl import (triangle, FiniteElement, VectorElement, TestFunction, Coefficient, inner, dx, derivative)
  
V = FiniteElement("Lagrange", triangle, 1)
VV = VectorElement("Lagrange", triangle, 1)

dv = TestFunction(V)

df = Coefficient(VV)
g = Coefficient(VV)
f = Coefficient(VV)
u = Coefficient(V)
cd = {f: df}

integrand = inner(f, g)

F = integrand*dx
J = derivative(F, u, dv, cd)

forms = [F, J]

ffcx test.py results in:

ufl.log.UFLException: Component and shape length don't match.

I have a fix that's working for my usage case that I'll put in a PR for comment.

Refactor FiniteElementBase

I've created this issue to take note of things we'd like to do to the FiniteElementBase class now that we're working on moving element definitions into Basix/finat

  • Remove __init__ and instead have abstractmethods and abstractpropertys
  • Change the abstractmethods to abstractpropertys
  • remove family, degree and quad_scheme from the base class
  • Add type hints (particularly in abstract classes)
  • Reconstruct method needs to be made to work with subclasses
  • symmetry method needs thinking about
  • __add__ and __mul__ need removing from base class
  • component functions need looking at

Should `VectorElement` and `TensorElement` be subclasses of `MixedElement`?

Changes required to support vertex cells led to questions about the design decision of having VectorElement and TensorElement be subclasses of MixedElement.

Originally posted by @wence- in #30 :

I would advocate keeping MixedElement only for a "bag of unrelated elements" and create new Vector/TensorElement classes that rank-augment an existing FiniteElement object. One could then go one step further and just make VectorElement a functional constructor for a TensorElement.

Make tests pass flake8

Currently, the test directory is included in flake8's excludes. This should be removed and the tests should be made to pass flake8

`preprocessed_form` contains global derivatives of the Jacobian

The following code

import ufl

coord_element = ufl.VectorElement("Lagrange", ufl.quadrilateral, 1)
mesh = ufl.Mesh(coord_element)
element = ufl.FiniteElement("RTCF", ufl.quadrilateral, 1)
V = ufl.FunctionSpace(mesh, element)
v = ufl.TrialFunction(V)
form = ufl.inner(1, ufl.div(v)) * ufl.dx

form_data = ufl.algorithms.compute_form_data(
    form,
    do_apply_function_pullbacks=True,
    do_apply_integral_scaling=True,
    do_apply_geometry_lowering=True,
    preserve_geometry_types=(ufl.classes.Jacobian,),
    do_apply_restrictions=True,
    do_append_everywhere_integrals=False)

print(form_data.preprocessed_form)

produces an output containing grad(J) instead of transforming the Jacobian derivatives to reference_grad(J). Is this the desired behaviour? Should these global derivatives not have been transformed to reference derivatives after preprocessing? I discovered this whilst investigating FEniCS/ffcx#373.

Delete or update .mailmap

The git mailmap has not been updated since 2016, and should either be updated or deleted.
Any preferences?

Remove deprecated way of modifying Measure

Legacy code with should be removed in favor of using the measure initializer

  • ufl/ufl/measure.py

    Lines 286 to 297 in a7426bd

    def __getitem__(self, data):
    """This operator supports legacy syntax in python dolfin programs.
    The old documentation reads: Return a new Measure for same
    integration type with an attached context for interpreting
    domain ids. By default this new Measure integrates over
    everywhere, but it can be restricted with a domain id as
    usual. Example: dx = dx[boundaries]; L = f*v*dx + g*v+dx(1).
    """
    deprecate("Notation dx[meshfunction] is deprecated. Please use dx(subdomain_data=meshfunction) instead.")
    return self(subdomain_data=data)

Error in online documentation

The docstrings of ufl.operators.dot does not match the actual documentation of the function,
i.e.

UFL operator: Take the dot product of a and b. The complex conjugate of the second argument is taken.
and

"UFL operator: Take the dot product of a and b. This won't take the complex conjugate of the second argument."

Form compiler has to compute `CellVolume`

Is there any specific reason for the following code:

@memoized_handler
def cell_volume(self, o):
if self._preserve_types[o._ufl_typecode_]:
return o
domain = o.ufl_domain()
if not domain.is_piecewise_linear_simplex_domain():
# Don't lower for non-affine cells, instead leave it to
# form compiler
warnings.warn("Only know how to compute the cell volume of an affine cell.")
return o
r = self.jacobian_determinant(JacobianDeterminant(domain))
r0 = ReferenceCellVolume(domain)
return abs(r * r0)

To me, it seems like this should work for both affine and non-affine cells. I tested this locally with DOLFINx (by commenting out the if clause, with the following code:

import gmsh
import numpy as np
import ufl
from dolfinx import fem, io
from mpi4py import MPI

# Generate a mesh with non-affine cells
gdim = 2
mesh_comm = MPI.COMM_WORLD
model_rank = 0
if mesh_comm.rank == model_rank:
    gmsh.initialize()
    rectangle = gmsh.model.occ.addRectangle(0, 0, 0, 1, 1, tag=1)
    obstacle = gmsh.model.occ.addDisk(0.5, 0.5, 0, 0.3, 0.3)
    fluid = gmsh.model.occ.cut([(gdim, rectangle)], [(gdim, obstacle)])
    gmsh.model.occ.synchronize()
    volumes = gmsh.model.getEntities(dim=gdim)
    gmsh.model.addPhysicalGroup(volumes[0][0], [volumes[0][1]], 1)
    gmsh.option.setNumber("Mesh.Algorithm", 8)
    gmsh.option.setNumber("Mesh.RecombinationAlgorithm", 2)
    gmsh.option.setNumber("Mesh.RecombineAll", 1)
    gmsh.option.setNumber("Mesh.SubdivisionAlgorithm", 1)
    gmsh.model.mesh.generate(gdim)
domain, _, _ = io.gmshio.model_to_mesh(
    gmsh.model, mesh_comm, model_rank, gdim=gdim)
gmsh.finalize()


Ve = fem.FunctionSpace(domain, ("DG", 0))
elmVol_ufl = ufl.CellVolume(domain)
elmVol_expr = fem.Expression(elmVol_ufl, Ve.element.interpolation_points())
elmVol = fem.Function(Ve, name="Element Volume (expression)")
elmVol.interpolate(elmVol_expr)

q_degree = 3
vol2 = fem.Function(Ve)
fem.petsc.assemble_vector(vol2.vector, fem.form(
    1*ufl.TestFunction(Ve)*ufl.dx(metadata={"quadrature_degree": q_degree})))
vol2.x.scatter_forward()
print(vol2.x.array - elmVol.x.array)
assert np.allclose(vol2.x.array, elmVol.x.array)
vol2.name = "ElementVolume (assembly)"

with io.XDMFFile(domain.comm, "cell_vol.xdmf", "w") as xdmf:
    xdmf.write_mesh(domain)
    xdmf.write_function(elmVol)
    xdmf.write_function(vol2)

Yielding
cellvolume

Remove `*` overload in `FiniteElementBase` for creating `MixedElement`

Concerns: https://github.com/FEniCS/ufl/blob/main/ufl/finiteelement/finiteelementbase.py#L199

This is cute for two spaces but is confusing and a bit useless for three or more spaces, see e.g. this recent thread on Slack:

https://fenicsproject.slack.com/archives/C1AFSEWKU/p1622793170035800

I would be in favour of removing/deprecating this code path and perhaps the + overload as well

https://github.com/FEniCS/ufl/blob/main/ufl/finiteelement/finiteelementbase.py#L192

ufl sphinx docs do not build

Do the docs (doc/sphinx) for ufl need to be updated? I suspect they're configured to an old version of sphinx. requirements.txt declares sphinx==1.7.0, but the sphinx version available to me at the moment is 3.4.3.

When I run make html from doc/sphinx, it fails with No module named 'sphinx.apidoc',

$ make html
sphinx-build -b html -d build/doctrees   source build/html
Running Sphinx v3.4.3
making output directory... done
WARNING: html_static_path entry '_static' does not exist

Extension error:
Handler <function run_apidoc at 0x7f8e5e7a80d0> for event 'builder-inited' threw an exception (exception: No module named 'sphinx.apidoc')
make: *** [Makefile:55: html] Error 2

doc/sphinx/source/conf.py uses (l.298)

    from sphinx.apidoc import main

I guess sphinx.apidoc must have appeared in sphinx 1.7.0, and is no longer available. sphinxcontrib.apidoc is available on my system, but substituting sphinx.apidoc for sphinxcontrib.apidoc is not the solution (exception: cannot import name 'main' from 'sphinxcontrib.apidoc')

Lazy Replace

It would be very useful to have a lazy version of replace, which only gets applied when the expression tree is traversed.

Example:
Say I have an expression expr which contains a ufl.ConstantValue named c as a parameter. If I want to have the derivative of expr wrt. c I can do so by creating a ufl.Coefficient named f and doing:

ufl.replace(expr, {c: f})
ufl.derivative(expr, f)

However this traverses the expression tree twice.

(This issue would also be fixed by implementing derivative wrt. ufl.ConstantValue, but there are more examples where this is desirable). This came up as a discussion point when reviewing a recent Firedrake PR. Tagging @dham .

Issue with complex-valued expressions

The below code gives the error ufl.log.UFLException: Unexpected complex value in real expression. Should it be expected to work?

import ufl
cell = ufl.triangle
x = ufl.SpatialCoordinate(cell)
f = x[0] + x[0] * 1j
# f = ufl.Constant(x[0] + x[0] * 1j)  # this works
# f = ufl.real(f)  # this doesn't work either
ufl.algorithms.remove_complex_nodes.remove_complex_nodes(f)

Decide on consistent naming for Base/Abstract classes

Currently, the base class for finite element is called FiniteElementBase while the base class for cells is called AbstractCell.

We should decide on a consistent naming for base classes. I'm in favour of the ObjectNameBase but am open to better opinions.

BUG Report

This report is for class PermutationSymbol(ConstantValue) in ufl/ufl/constantvalue.py, in line 387:

self.ufl_shape = (dim,) * dim

Consider a second order and 3d PermutationSymbol, current code gives

self.ufl_shape = (dim,) * dim = (3, 3, 3),

which should be (3,3), actually.

So, this line should be changed to as in class Identity(ConstantValue):

self.ufl_shape = (dim, dim)

Don't skip E741

flake8's E741 is for ambiguous variable names. Instead of skipping this, we should rename variables to better names.

VectorElement constructor drops quadrature rule when `family` is a `FiniteElement`

When constructing a VectorElement based from a scalar FiniteElement, the quadrature scheme of that element is dropped.
This is not the case for TensorElement, although one would expect the same behavior for both types.
The reason lies in the call to FiniteElementBase.__init__ in line 298 of ufl/finiteelement/mixedelement.py, which sets quad_scheme to None if it is not given explicitly. This call is not present in the constructor of TensorElement.

ufl 2023.1 breaks old dolfin

The change of API in ufl 2023.1 (2023.1.1.post0) breaks old dolfin.

It also breaks old ffc. ufl.log.WARNING was removed in ufl 2023 and is used by ffc. But ffc can be easily patched to treat any instance of WARNING as either INFO or ERROR.

dolfin cannot be so easily patched. The problem is not only ufl.log.WARNING. For instance demo_poisson.py gives

$ python3 demo_poisson.py 
Calling FFC just-in-time (JIT) compiler, this may take some time.
Calling FFC just-in-time (JIT) compiler, this may take some time.
Calling FFC just-in-time (JIT) compiler, this may take some time.
Calling FFC just-in-time (JIT) compiler, this may take some time.
Calling FFC just-in-time (JIT) compiler, this may take some time.
Traceback (most recent call last):
  File "/projects/fenics/build/tests/dolfin/demo-python/documented/poisson/demo_poisson.py", line 170, in <module>
    solve(a == L, u, bc)
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/fem/solving.py", line 233, in solve
    _solve_varproblem(*args, **kwargs)
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/fem/solving.py", line 268, in _solve_varproblem
    problem = LinearVariationalProblem(eq.lhs, eq.rhs, u, bcs,
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/fem/problem.py", line 58, in __init__
    L = Form(L, form_compiler_parameters=form_compiler_parameters)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/fem/form.py", line 82, in __init__
    self.set_cell_domains(subdomains)
TypeError: set_cell_domains(): incompatible function arguments. The following argument types are supported:
    1. (self: dolfin.cpp.fem.Form, arg0: dolfin.cpp.mesh.MeshFunctionSizet) -> None

Invoked with: <dolfin.fem.form.Form object at 0x7f67280289b0>, [None]

Should ufl be patched (as version 2023.2, say) to restore support for old dolfin?

Or should the new namespace be changed from ufl to uflx ? This was done previously when ffc was changed to ffcx

`ufl.split` incompatible with `ufl.as_vector`

I found a useful case that is not correctly handled by ufl.split.

Consider the simple code snapshot below. Both broken_case and working_case return a vector-like expression, however ufl.split is unable to correctly extract the list of components for the broken case.

import dolfin as dl
import ufl

def broken_case():
    print("Construct a vector using as_vector")
    a = dl.Constant(1.)
    b = dl.Constant(2.)
    return ufl.as_vector( (a,b) )

def working_case():
    print("Construct a vector constant")
    return dl.Constant( (1., 2.) )

v = working_case()
print( ufl.split(v) )

v = broken_case()
print( ufl.split(v) )

which produces the output.

Construct a vector constant
(Indexed(Coefficient(FunctionSpace(None, VectorElement(FiniteElement('Real', None, 0), dim=2)), 0), MultiIndex((FixedIndex(0),))), Indexed(Coefficient(FunctionSpace(None, VectorElement(FiniteElement('Real', None, 0), dim=2)), 0), MultiIndex((FixedIndex(1),))))

Construct a vector using as_vector
Don't know how to split [f_1, f_2].
Traceback (most recent call last):
  File "my_tesst.py", line 18, in <module>
    print( ufl.split(v) )
  File "/Users/uvilla/anaconda3/envs/fenics-2019.1/lib/python3.7/site-packages/ufl/split_functions.py", line 61, in split
    error("Don't know how to split %s." % (v,))
  File "/Users/uvilla/anaconda3/envs/fenics-2019.1/lib/python3.7/site-packages/ufl/log.py", line 172, in error
    raise self._exception_type(self._format_raw(*message))
ufl.log.UFLException: Don't know how to split [f_1, f_2].

On the other hand:

v = broken_case()
a,b= v

produces the desired effect.

Then, my question is: Would make sense to replace this error line with return v?

TypeError: unsupported operand type(s) for *: 'Conj' and 'Form'

Hi i have met a very basic bug, or at least a strange behaviour, involving ufl

Here is a very minimal code showing the issue:

from dolfin import *

mesh = RectangleMesh(Point(0., 0.), Point(1, 1), 1, 1, "crossed")
V = VectorFunctionSpace(mesh, 'CG', degree=2)
u_ = TestFunction(V)
x = SpatialCoordinate(mesh)

Working

first_form = inner(Constant((1,1)), u_) * x[0] * dx
print("First form", first_form)

Not working

dx1 = x[0] * dx
second_form = inner(Constant((1,1)), u_) * dx1
print("Second form", second_form)

No operation is defined between the Conj operator and a ufl-form even though one could expect these two syntax to be equivalent

Remove support for `.ufl` files

For largely historical reasons, UFL supports loading and executing .ufl files. This hides from the user that they can can exploit the full features of a Python program, and prevents the mixing of UFL and form compiler features in a single program, e.g. UFL and specifics of FFCx cannot be synthesised in the generation process.

This change should have no impact on Python libraries that use UFL. It should only impact static libraries that pre-compile code from .ufl input.

RT function cannot interpolate

Hello everyone, I have a vector function to be interpolated into the RT space and do it like this f.interpolate(lambda x: (g1(x), g2(x)) without luck.

External ufl types.

When adding an UFL type using the @ufl_type decorator this seems to lead to errors in, for example, the Transformer class from ufl.algorithms. Example, somewhere in some external (to ufl) code:

import ufl
from ufl.core.ufl_type import ufl_type
@ufl_type(is_scalar=True)
class BoundaryId(ufl.geometry.GeometricFacetQuantity):
    """UFL boundary id: can be used in a conditional to fix the desired boundary id."""
    __slots__ = ()
    name = "facetid"

This leads to an index error in

h, visit_children_first = self._handlers[o._ufl_typecode_]
It can be fixed by adding the new class manually to all_ufl_classes:

from ufl.classes import all_ufl_classes
all_ufl_classes.add(BoundaryId)

However, this can cause problems when other Python modules using UFL are included before these two lines, because it can mess up the index order in all_ufl_classes. So the result is, that all other modules using UFL should be included after this statement.

So the question is: What is the correct way of adding external UFL types (besides using @ufl_type)? Or is this a bug and the modification of the UFL internal lists and sets should be done inside the @ufl_type functions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.