FEniCS / dolfinx

Next generation FEniCS problem solving environment
https://fenicsproject.org
GNU Lesser General Public License v3.0
776 stars 181 forks source link

Clarity requested: Confusing namespaces `functionspace` is a module in `ufl` but a function in `fem` #3325

Closed marc-git closed 1 month ago

marc-git commented 3 months ago

Describe new/missing feature

The change from FunctionSpace to functionspace will surely have its justification but it seems to me that one of the main talking points about switching to FEniCSx was for the clarity of the namespaces and the deduplication effort, and that seems to be a little lost. I'll try to be as constructive as I can.

The function dolfinx.fem.functionspace now returns a dolfinx.fem.FunctionSpace. Before, one used to initialise the instance with the initialiser. Why is the functionspace constructor now being encouraged (e.g. in the tutorials)? Can some words be added to the comments in the source code? In the examples, I typically see the basix.ufl.element being called through a tuple. Are you sure this is the best way for tutorial users to become familiar with using the library?

The module ufl.functionspace goes back to 2016 and has the introduction """Types for representing function spaces.""", but this seems to be a placeholder for function space types. Why do UFL and FEM need a thing called functionspace that are two different types of things, serving two different purposes, but with the same name?

How does a user know from a philosophical point of view, whether the thing she/he is looking for is in ufl or in fem? It seems function spaces live in fem but Vector Elements live in ufl. From the titles I would have probably expected the opposite.

I very much like the fenics(x) package(s) and try to encourage my students to learn it. I hope my motivation for the posted feature is clear.

Suggested user interface

No response

francesco-ballarin commented 3 months ago

functionspace is lower case because it is a function, while FunctionSpace is upper case because it is a class.

Vector Elements live in ufl

Not anymore, since 0.8.0, you'd have to use basix.ufl.

jhale commented 3 months ago

A few comments:

UFL contains only symbolic finite element concepts. Is is up to downstream libraries like DOLFINx or Firedrake to extend these objects and attach heavy data e.g. dofmaps. This is why we have two objects named similarly.

The only thing most 'regular' users need from ufl are the free functions, e.g. sin, grad etc. along with measures dx or ds. Everything else can be found in DOLFINx and Basix.

marc-git commented 3 months ago

I still think it isn't as clear as one would have intended or maybe I am using the code incorrectly.

You now have basix.ufl.element which you give to dolfinx.fem.functionspace' to get adolfinx.fem.FunctionSpace', from which you can get a dolfinx.fem.Function.

On the other hand, if I use a ufl.derivative I give it a ufl.form built from a dolfinx.fem.Function. I differentiate with respect to a dolfinx.fem.Function in the direction of a ufl.TestFunction.

Am I really supposed to use a ufl.TrialFunction for my problem variables? It isn't clear from the tutorials when to use which one or why they both exist.

jhale commented 3 months ago

I still think it isn't as clear as one would have intended or maybe I am using the code incorrectly.

Conceptually not a lot has changed here since the first batch of FEniCS papers.

Multiple similar or even identically named concepts exist within the DOLFINx/UFL/Basix (previously FIAT) namespaces.

This is because UFL is a symbolic language for writing variational forms. While it has meshes, elements and function spaces, they are abstract/light concepts that libraries like Python DOLFINx (and Python Basix) and Firedrake must extend, usually via inheritance, with an actual implementation.

Because of this inheritance pattern these concrete or heavy extensions can then be passed back and used with other abstract or light UFL methods or objects.

I would add that this use of Python inheritance is used very little in the C++ interface to DOLFINx. In DOLFINx C++ you must write purely symbolic forms in Python with UFL, generate C code with FFCx and then use DOLFINx C++ interface to create heavy objects in three very distinct steps.

We have a PR coming through soon which will (optionally) allow our users to use the Python interface in a way that is conceptually similar to the C++ interface. You may find this appealing if there is too much magic going on in our Python interface.

jhale commented 3 months ago

Already merged infact. Our nightly docker image will have this if you want to try it.

https://github.com/FEniCS/dolfinx/pull/3263

jorgensd commented 3 months ago

Already merged infact. Our nightly docker image will have this if you want to try it.

3263

An improved/generalized version of this feature is proposed in: https://github.com/FEniCS/dolfinx/pull/3262