Interpolating Functions on higher order elements

Hello everyone,

Except some little projects with Fenics in my past I still trying to learn and work with FENCIS, whenever I can. Currently I tried to understand higher-order elements in FENICS better and found it at best confusing.
To illustrate my point I have developed this small WORKING example:

from mpi4py import MPI
from dolfinx.mesh import CellType, create_unit_square
from dolfinx.fem import functionspace, Function
from dolfinx.io import XDMFFile
from basix.ufl import element
import numpy as np

element_type = "Lagrange"
element_dof = 1 # <-- This is what I will change later

mesh = create_unit_square(MPI.COMM_WORLD, 96, 96, CellType.triangle)
elem = element(element_type, mesh.basix_cell(), element_dof)
V = functionspace(mesh, elem)

u = Function(V)

# Zero u
u.x.array[:] = 0.0

# Interpolate some random function
u.interpolate(lambda x: 0.63 + 0.02 * (0.5 - np.random.rand(x.shape[1])))
u.x.scatter_forward()


from pathlib import Path

output = Path("/home/fenics/shared/") #  this is important for jupyter notebooks

# Output file
file = XDMFFile(MPI.COMM_WORLD, str(output /f "test-{element_dof}.xdmf"), "w")
file.write_mesh(mesh)
file.write_function(u, 0)
file.close()

From my little understanding changing element_dof to something other then 1 (i.e. 2, 3, etc) should work with the same code, because more “interpolation points” are added, BUT doing so results in the following error:

RuntimeError                              Traceback (most recent call last)
/fenics_tests.ipynb Cell 10 line 3
     29 file = XDMFFile(MPI.COMM_WORLD, str(output / f "test-{element_dof}.xdmf"), "w")
     30 file.write_mesh(mesh)
---> 31 file.write_function(u, 0)
     32 file.close()

File /usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/io/utils.py:235, in XDMFFile.write_function(self, u, t, mesh_xpath)
    219 def write_function(self, u: Function, t: float = 0.0, mesh_xpath="/Xdmf/Domain/Grid[@GridType='Uniform'][1]"):
    220     """Write function to file for a given time.
    221 
    222     Note:
ref='/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/io/utils.py:0'>0</a>;32m   (...)
    233 
    234     """
--> 235     super().write_function(getattr(u, "_cpp_object", u), t, mesh_xpath)

RuntimeError: Degree of output Function must be same as mesh degree. Maybe the Function needs to be interpolated?

I studied issues like:

But still do I not know what to change.
Besides a workaround in code, which is degree independent, it would by nice to get an understanding how FENICS handles higher-order elements so I can better understand why this problem occur.
I would also appreciate if someone could show my how to debug such an issue, because debugging FENICS related issues, still seems like a mystery to me.

Thanks for your time!

The error message states that the degree of the function space does not match the mesh degree. The mesh degree is the order of the Lagrange space used to represent a single cell in the mesh geometry.

This representation is used to map points to and from the reference element.

The XDMF file format only supports first or second order Lagrange elements, where the degree has to be equal to the order of the mesh geometry.

Thus for straight edged triangles, tetrahedra, quadrilatrals or hexahedrons) the XDMFFile can only store first order Lagrange finite elements. This means that you have to interpolate the higher order function into a lower order space.

In legacy FEniCS this was done implicitly under the hood (causing confusion and misinterpretations of results).
If you use the VTKFile or VTXWriter (recommended) to write out abritrary order Lagrange or DG finite element functions to file. The reason that I stress the finite element family is that Paraview/VTK does not support more exotic finite elements such as RT or N1curl, and thus one have to interpolate into an appropriate Lagrange/DG space.

2 Likes

If I understood you correctly, this is not so much a problem in FENICSx, as it is more a problem with the limitations of the file format.
So if switching to another file format hould be fine (as long as I use “Lagrange” as the element_type).
Replacing:

with:

with VTXWriter(mesh.comm, output / f"test_u-{element_dof}.bp", u) as vtx_u:
    vtx_u.write(0)

Runs with out the RuntimeError, but when I try to open it in Paraview it crashes with the following message:

Qt: Session management error: Could not open network socket
/usr/include/c++/12.2.0/bits/stl_vector.h:1123: std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::operator[](size_type) [with _Tp = int; _Alloc = std::allocator<int>; reference = int&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.

Loguru caught a signal: SIGABRT
Stack trace:
51      0x560758b254e5 paraview(+0xa4e5) [0x560758b254e5]
50      0x7ff80942964b __libc_start_main + 139
49      0x7ff80942958a /usr/lib/x86_64-linux-gnu/libc.so.6(+0x2958a) [0x7ff80942958a]
48      0x560758b252b3 paraview(+0xa2b3) [0x560758b252b3]
47      0x7ff8072d5976 QCoreApplication::exec() + 150
46      0x7ff8072cd80b QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 299
45      0x7ff807326ae6 QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 102
44      0x7ff7f771e4a3 g_main_context_iteration + 51
43      0x7ff7f7777028 /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(+0xb0028) [0x7ff7f7777028]
42      0x7ff7f7720d71 g_main_context_dispatch + 673
41      0x7ff7a4d1992a /usr/lib/x86_64-linux-gnu/libQt5XcbQpa.so.5(+0x6b92a) [0x7ff7a4d1992a]
40      0x7ff80772a0bc QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 172
39      0x7ff8077571bd QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 2061
38      0x7ff8072ced98 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 280
37      0x7ff807f7affe QApplicationPrivate::notify_helper(QObject*, QEvent*) + 126
36      0x7ff807fd9100 /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5(+0x1d9100) [0x7ff807fd9100]
35      0x7ff807fd60b9 /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5(+0x1d60b9) [0x7ff807fd60b9]
34      0x7ff807f8169e QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool, bool) + 446
33      0x7ff8072ced98 QCoreApplication::notifyInternal2(QObject*, QEvent*) + 280
32      0x7ff807f83592 QApplication::notify(QObject*, QEvent*) + 5058
31      0x7ff807f7affe QApplicationPrivate::notify_helper(QObject*, QEvent*) + 126
30      0x7ff807fbce28 QWidget::event(QEvent*) + 424
29      0x7ff808104e74 /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5(+0x304e74) [0x7ff808104e74]
28      0x7ff8080fd052 /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5(+0x2fd052) [0x7ff8080fd052]
27      0x7ff807f773db QAction::activate(QAction::ActionEvent) + 171
26      0x7ff807f747b2 QAction::triggered(bool) + 66
25      0x7ff8073062cc /usr/lib/x86_64-linux-gnu/libQt5Core.so.5(+0x3062cc) [0x7ff8073062cc]
24      0x7ff809109c0d /app/bin/../lib/libpqApplicationComponents-pv5.11.so.1(+0x109c0d) [0x7ff809109c0d]
23      0x7ff8091b25b1 pqLoadDataReaction::loadData() + 49
22      0x7ff8091b2169 pqLoadDataReaction::loadData(QSet<QPair<QString, QString> > const&) + 5769
21      0x7ff8091af5d2 pqLoadDataReaction::loadFilesForSupportedTypes(QList<QStringList>) + 1362
20      0x7ff8091aeaee pqLoadDataReaction::loadData(QStringList const&, QString const&, QString const&, pqServer*) + 1710
19      0x7ff8091ade9e pqLoadDataReaction::loadData(QList<QStringList> const&, QString const&, QString const&, pqServer*) + 2030
18      0x7ff8091acf96 pqLoadDataReaction::DetermineFileReader(QString const&, pqServer*, vtkSMReaderFactory*, QPair<QString, QString>&) + 166
17      0x7ff806e0c85c vtkSMReaderFactory::GetReaders(char const*, vtkSMSession*) + 316
16      0x7ff806e0b59d vtkSMReaderFactory::vtkInternals::vtkValue::CanReadFile(char const*, bool, std::vector<std::string> const&, vtkSMSession*, bool) + 333
15      0x7ff806e0a1d8 vtkSMReaderFactory::CanReadFile(char const*, vtkSMProxy*) + 280
14      0x7ff806deb7a1 vtkSMProxy::UpdateVTKObjects() + 49
13      0x7ff806e4e2a1 vtkSMSourceProxy::CreateVTKObjects() + 33
12      0x7ff806dec0b3 vtkSMProxy::CreateVTKObjects() + 1347
11      0x7ff806ced87a vtkPVSessionBase::PushState(paraview_protobuf::Message*) + 42
10      0x7ff806d17f8d vtkSIProxy::Push(paraview_protobuf::Message*) + 61
9       0x7ff806d16ec8 vtkSIProxy::InitializeAndCreateVTKObjects(paraview_protobuf::Message*) + 3480
8       0x7ff806d2e2f0 vtkSISourceProxy::ReadXMLAttributes(vtkPVXMLElement*) + 32
7       0x7ff806d14ac7 vtkSIProxy::ReadXMLAttributes(vtkPVXMLElement*) + 855
6       0x7ff806d18d12 vtkSIProxy::ReadXMLProperty(vtkPVXMLElement*) + 418
5       0x7ff806d3057f vtkSIStringVectorProperty::ReadXMLAttributes(vtkSIProxy*, vtkPVXMLElement*) + 2303
4       0x7ff7f98e1f9d /usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0xe1f9d) [0x7ff7f98e1f9d]
3       0x7ff8094287fc abort + 215
2       0x7ff80943f04e raise + 30
1       0x7ff809491204 /usr/lib/x86_64-linux-gnu/libc.so.6(+0x91204) [0x7ff809491204]
0       0x7ff80943f100 /usr/lib/x86_64-linux-gnu/libc.so.6(+0x3f100) [0x7ff80943f100]
(  35.464s) [paraview        ]                       :0     FATL| Signal: SIGABRT

Is this a problem with ParaView, or is my implementation just wrong?

but why does it crash, then when I change

to

?
(I mean second order is supported, right?)

What version of Paraview are you using and how did you install it?

You need a relatively new version of Paraview and it needs to be installed with ADIOS2 support.
You should use the VTX reader when opening the file.

if you could run the command-line tool bpls -a -l name_of_bp_file.bp as well and post the output here.

I installed the flathub package flatpak run org.paraview.ParaView --version returns paraview version 5.11.2. According to this post it does not seem to enable ADIOS 2 specificly. So is my only option to build paraview from skretch?

You could download one of the binaries:

Thank you very much!
Using VTXWriter and the new ParaView-Binary solved the problem!