Problem when combining test and trial functions from different spaces

Hi all,

I am trying to solve a set of equations that involve velocity, pressure and temperature.
The finite element spaces that I am using for the different variables are the following:

Finite element spaces

import ufl
v_cg2 = ufl.VectorElement(“CG”, mesh.ufl_cell(), 2)
p_cg1 = ufl.FiniteElement(“CG”, mesh.ufl_cell(), 1)
T_cg2 = ufl.FiniteElement(“CG”, mesh.ufl_cell(), 2)
V = dolfinx.FunctionSpace(mesh, v_cg2) # Velocity function space
Q = dolfinx.FunctionSpace(mesh, p_cg1) # Pressure function space
W = dolfinx.FunctionSpace(mesh, T_cg2) # Temperature function space

Trial and test functions

u = ufl.TrialFunction(V) # Velocity (trial)
v = ufl.TestFunction(V) # Velocity (test)
p = ufl.TrialFunction(Q) # Pressure (trial)
q = ufl.TestFunction(Q) # Pressure (test)
T = ufl.TrialFunction(W) # Temperature (trial)
w = ufl.TestFunction(W) # Temperature (test)

The problem is that the equations are coupled, so I need to solve them simultaneously. However, I am getting errors when I try to build the bilinear form, since I need to combine test and trial functions from different element spaces.
For example, I need to compute the following term:

L1 = inner(q,(gamma*p-T))*dx
A = dolfinx.fem.assemble_matrix(L1)
A.assemble()

which gives me the following error:

Found different Arguments with same number and part.
Did you combine test or trial functions from different spaces?
The Arguments found are:
v_1
v_0
v_1
ERROR:UFL:Found different Arguments with same number and part.
Did you combine test or trial functions from different spaces?
The Arguments found are:
v_1
v_0
v_1
Traceback (most recent call last):
File “/root/dolfinX/Test.py”, line 110, in
A = dolfinx.fem.assemble_matrix(L1)
File “/usr/lib/python3.9/functools.py”, line 877, in wrapper
return dispatch(args[0].__class__)(*args, **kw)
File “/usr/local/dolfinx-real/lib/python3.8/dist-packages/dolfinx/fem/assemble.py”, line 283, in assemble_matrix
A = cpp.fem.create_matrix(_create_cpp_form(a))
File “/usr/local/dolfinx-real/lib/python3.8/dist-packages/dolfinx/fem/assemble.py”, line 35, in create_cpp_form
return Form(form).cpp_object
File “/usr/local/dolfinx-real/lib/python3.8/dist-packages/dolfinx/fem/form.py”, line 56, in __init

self._ufc_form, module, self._code = jit.ffcx_jit(
File “/usr/local/dolfinx-real/lib/python3.8/dist-packages/dolfinx/jit.py”, line 54, in mpi_jit
return local_jit(*args, **kwargs)
File “/usr/local/dolfinx-real/lib/python3.8/dist-packages/dolfinx/jit.py”, line 204, in ffcx_jit
r = ffcx.codegeneration.jit.compile_forms([ufl_object], parameters=p_ffcx, **p_jit)
File “/usr/local/lib/python3.9/dist-packages/ffcx/codegeneration/jit.py”, line 145, in compile_forms
ffcx.naming.compute_signature(forms, _compute_parameter_signature(p)
File “/usr/local/lib/python3.9/dist-packages/ffcx/naming.py”, line 24, in compute_signature
object_signature += ufl_object.signature()
File “/usr/local/lib/python3.9/dist-packages/ufl/form.py”, line 243, in signature
self._compute_signature()
File “/usr/local/lib/python3.9/dist-packages/ufl/form.py”, line 487, in _compute_signature
self._compute_renumbering())
File “/usr/local/lib/python3.9/dist-packages/ufl/form.py”, line 460, in _compute_renumbering
cn = self.coefficient_numbering()
File “/usr/local/lib/python3.9/dist-packages/ufl/form.py”, line 234, in coefficient_numbering
self._analyze_form_arguments()
File “/usr/local/lib/python3.9/dist-packages/ufl/form.py”, line 447, in _analyze_form_arguments
arguments, coefficients = extract_arguments_and_coefficients(self)
File “/usr/local/lib/python3.9/dist-packages/ufl/algorithms/analysis.py”, line 127, in extract_arguments_and_coefficients
error(msg)
File “/usr/local/lib/python3.9/dist-packages/ufl/log.py”, line 158, in error
raise self._exception_type(self._format_raw(*message))
ufl.log.UFLException: Found different Arguments with same number and part.
Did you combine test or trial functions from different spaces?
The Arguments found are:
v_1
v_0
v_1

What I understand then is that I cannot combine test and trial functions from different spaces. Therefore, I defined a mixed finite element space to try to fix this error:

Mixed finite element space

import ufl
v_cg2 = ufl.VectorElement(“CG”, mesh.ufl_cell(), 2)
p_cg1 = ufl.FiniteElement(“CG”, mesh.ufl_cell(), 1)
T_cg2 = ufl.FiniteElement(“CG”, mesh.ufl_cell(), 2)
mel = ufl.MixedElement([v_cg2, p_cg1, T_cg2])
Y = dolfinx.FunctionSpace(mesh, mel) # Mixed function space

and redefined the trial and test functions as follows:

Trial and test functions

u = ufl.TrialFunction(Y) # Velocity (trial)
v = ufl.TestFunction(Y) # Velocity (test)
p = ufl.TrialFunction(Y) # Pressure (trial)
q = ufl.TestFunction(Y) # Pressure (test)
T = ufl.TrialFunction(Y) # Temperature (trial)
w = ufl.TestFunction(Y) # Temperature (test)

This approach fixes the previous error, but now I am getting another one when I try to compute another term:

L2 = inner(w,div(u))*dx
A = dolfinx.fem.assemble_matrix(L2)
A.assemble()

The error now is:

Shapes do not match: <Argument id=140363992421472> and <Div id=140364133793920>.
ERROR:UFL:Shapes do not match: <Argument id=140363992421472> and <Div id=140364133793920>.
Traceback (most recent call last):
File “/root/dolfinX/Test.py”, line 105, in <module>
L2 = inner(w,div(u))*dx
File “/usr/local/lib/python3.9/dist-packages/ufl/operators.py”, line 158, in inner
return Inner(a, b)
File “/usr/local/lib/python3.9/dist-packages/ufl/tensoralgebra.py”, line 147, in __new__
error(“Shapes do not match: %s and %s.” % (ufl_err_str(a), ufl_err_str(b)))
File “/usr/local/lib/python3.9/dist-packages/ufl/log.py”, line 158, in error
raise self._exception_type(self._format_raw(*message))
ufl.log.UFLException: Shapes do not match: <Argument id=140363992421472> and <Div id=140364133793920>.

This means that the shape of w is different from the shape of div(u), which is understandable since now w and u belong to the same mixed space W (and when taking the divergence of u, the space changes).

Consequently, my question would be how can I combine test and trial functions that belong to different spaces to build the bilinear form. Does anybody have any idea?

My minimal example is:

# Import
from mpi4py import MPI
rank = MPI.COMM_WORLD.rank
import dolfinx
from ufl import Identity, div, dot, ds, dx, inner, lhs, nabla_grad, rhs, sym, Dn, grad

‘’’ Generation of geometry and mesh ‘’’
# Domain dimensions
L = 3
H = 0.5
gdim = 3

# Initialise meshing process
import gmsh
gmsh.initialize()

# Geometry
if rank == 0:
gmsh.model.add(“TVA Channel 3D”)
fluid = gmsh.model.occ.addBox(0, 0, 0, L, H, H)
gmsh.model.occ.synchronize()

# Generate mesh
if rank == 0:
gmsh.model.mesh.generate(gdim)
gmsh.write(“meshTVAchannel.msh”)

# Domain marker
fluid_marker = 1
if rank == 0:
volumes = gmsh.model.getEntities(dim=gdim)
gmsh.model.addPhysicalGroup(volumes[0][0], [volumes[0][1]], fluid_marker)
gmsh.model.setPhysicalName(volumes[0][0], fluid_marker, “Fluid”)

# Boundary markers
import numpy as np
inlet_marker, outlet_marker, wall_marker = 2, 3, 4
inflow, outflow, walls = [], [], []
if rank == 0:
boundaries = gmsh.model.getBoundary(volumes)
for boundary in boundaries:
center_of_mass = gmsh.model.occ.getCenterOfMass(boundary[0], boundary[1])
if np.allclose(center_of_mass, [0, H/2, 0]):
inflow.append(boundary[1])
elif np.allclose(center_of_mass, [L, H/2, 0]):
outflow.append(boundary[1])
else:
walls.append(boundary[1])
gmsh.model.addPhysicalGroup(1, walls, wall_marker)
gmsh.model.setPhysicalName(1, wall_marker, “Walls”)
gmsh.model.addPhysicalGroup(1, inflow, inlet_marker)
gmsh.model.setPhysicalName(1, inlet_marker, “Inlet”)
gmsh.model.addPhysicalGroup(1, outflow, outlet_marker)
gmsh.model.setPhysicalName(1, outlet_marker, “Outlet”)

# Import mesh to dolfinX
from gmsh_helpers import gmsh_model_to_mesh
mesh, facet_tags = gmsh_model_to_mesh(gmsh.model, cell_data=True, facet_data=False, gdim=3)

‘’’ Generation of finite element spaces ‘’’
# Finite element spaces
import ufl
v_cg2 = ufl.VectorElement(“CG”, mesh.ufl_cell(), 2)
p_cg1 = ufl.FiniteElement(“CG”, mesh.ufl_cell(), 1)
T_cg2 = ufl.FiniteElement(“CG”, mesh.ufl_cell(), 2)
mel = ufl.MixedElement([v_cg2, p_cg1, T_cg2])
V = dolfinx.FunctionSpace(mesh, v_cg2)
Q = dolfinx.FunctionSpace(mesh, p_cg1)
W = dolfinx.FunctionSpace(mesh, T_cg2)
Y = dolfinx.FunctionSpace(mesh, mel)

# Trial and test functions
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
p = ufl.TrialFunction(Q)
q = ufl.TestFunction(Q)
T = ufl.TrialFunction(W)
w = ufl.TestFunction(W)
# # Trial and test functions
# u = ufl.TrialFunction(Y)
# v = ufl.TestFunction(Y)
# p = ufl.TrialFunction(Y)
# q = ufl.TestFunction(Y)
# T = ufl.TrialFunction(Y)
# w = ufl.TestFunction(Y)

# Numerical parameters
gamma = 1.017

‘’’’ Left-hand side ‘’’
# First component
L1 = inner(q,(gamma*p-T))*dx

# Second component
L2 = inner(w,div(u))*dx

L = L1 + L2

A = dolfinx.fem.assemble_matrix(L)
A.assemble()

Thank you very much in advance!

Please make sure that your code is properly formatted (indentation preserved) using 3x` encapsulation, and make sure to remove all code not needed for reproducibility.

Sorry, I did not paste the code in the correct format. Please find below a minimal example for the first error and a minimal example for the second error.

Minimal example for first error

# Import
import dolfinx
from ufl import Identity, div, dot, ds, dx, inner, lhs, nabla_grad, rhs, sym, Dn, grad

# Domain dimensions
L = 3
H = 0.5
gdim = 3

# Initialise meshing process
import gmsh
gmsh.initialize()

# Geometry
fluid = gmsh.model.occ.addBox(0, 0, 0, L, H, H)
gmsh.model.occ.synchronize()

# Generate mesh
gmsh.model.mesh.generate(gdim)

# Domain marker
fluid_marker = 1
volumes = gmsh.model.getEntities(dim=gdim)
gmsh.model.addPhysicalGroup(volumes[0][0], [volumes[0][1]], fluid_marker)
gmsh.model.setPhysicalName(volumes[0][0], fluid_marker, 'Fluid')

# Import mesh to dolfinX
from gmsh_helpers import gmsh_model_to_mesh
mesh, facet_tags = gmsh_model_to_mesh(gmsh.model, cell_data=True, facet_data=False, gdim=3)

# Finite element spaces
import ufl
v_cg2 = ufl.VectorElement('CG', mesh.ufl_cell(), 2)
p_cg1 = ufl.FiniteElement('CG', mesh.ufl_cell(), 1)
T_cg2 = ufl.FiniteElement('CG', mesh.ufl_cell(), 2)
mel = ufl.MixedElement([v_cg2, p_cg1, T_cg2])
V = dolfinx.FunctionSpace(mesh, v_cg2)
Q = dolfinx.FunctionSpace(mesh, p_cg1)
W = dolfinx.FunctionSpace(mesh, T_cg2)
Y = dolfinx.FunctionSpace(mesh, mel)

# Trial and test functions
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
p = ufl.TrialFunction(Q)
q = ufl.TestFunction(Q)
T = ufl.TrialFunction(W)
w = ufl.TestFunction(W)

# Numerical parameters
gamma = 1.017

# First component
L1 = inner(q,(gamma*p-T))*dx

# Assemble bilinear form
A = dolfinx.fem.assemble_matrix(L1)
A.assemble()

Minimal example for the second error

# Import
import dolfinx
from ufl import Identity, div, dot, ds, dx, inner, lhs, nabla_grad, rhs, sym, Dn, grad

# Domain dimensions
L = 3
H = 0.5
gdim = 3

# Initialise meshing process
import gmsh
gmsh.initialize()

# Geometry
fluid = gmsh.model.occ.addBox(0, 0, 0, L, H, H)
gmsh.model.occ.synchronize()

# Generate mesh
gmsh.model.mesh.generate(gdim)

# Domain marker
fluid_marker = 1
volumes = gmsh.model.getEntities(dim=gdim)
gmsh.model.addPhysicalGroup(volumes[0][0], [volumes[0][1]], fluid_marker)
gmsh.model.setPhysicalName(volumes[0][0], fluid_marker, 'Fluid')

# Import mesh to dolfinX
from gmsh_helpers import gmsh_model_to_mesh
mesh, facet_tags = gmsh_model_to_mesh(gmsh.model, cell_data=True, facet_data=False, gdim=3)

# Finite element spaces
import ufl
v_cg2 = ufl.VectorElement('CG', mesh.ufl_cell(), 2)
p_cg1 = ufl.FiniteElement('CG', mesh.ufl_cell(), 1)
T_cg2 = ufl.FiniteElement('CG', mesh.ufl_cell(), 2)
mel = ufl.MixedElement([v_cg2, p_cg1, T_cg2])
V = dolfinx.FunctionSpace(mesh, v_cg2)
Q = dolfinx.FunctionSpace(mesh, p_cg1)
W = dolfinx.FunctionSpace(mesh, T_cg2)
Y = dolfinx.FunctionSpace(mesh, mel)

# Trial and test functions
u = ufl.TrialFunction(Y)
v = ufl.TestFunction(Y)
p = ufl.TrialFunction(Y)
q = ufl.TestFunction(Y)
T = ufl.TrialFunction(Y)
w = ufl.TestFunction(Y)

# Numerical parameters
gamma = 1.017

# Second component
L2 = inner(w,div(u))*dx

# Assemble bilinear form
A = dolfinx.fem.assemble_matrix(L2)
A.assemble()

You need to split the trial function from the mixed space for each component, which can either be done by

y = ufl.TrialFunction(Y)
u, p, T = ufl.split(y)

or use ufl.TrialFunctions, as shown below:

# Import
import dolfinx
from ufl import  div, dx, inner, FiniteElement, VectorElement, TrialFunctions, TestFunctions, MixedElement
from mpi4py import MPI
mesh = dolfinx.UnitCubeMesh(MPI.COMM_WORLD, 10, 10, 10)
v_cg2 = VectorElement('CG', mesh.ufl_cell(), 2)
p_cg1 = FiniteElement('CG', mesh.ufl_cell(), 1)
T_cg2 = FiniteElement('CG', mesh.ufl_cell(), 2)
mel = MixedElement([v_cg2, p_cg1, T_cg2])
V = dolfinx.FunctionSpace(mesh, v_cg2)
Q = dolfinx.FunctionSpace(mesh, p_cg1)
W = dolfinx.FunctionSpace(mesh, T_cg2)
Y = dolfinx.FunctionSpace(mesh, mel)

# Trial and test functions
u, p, T = TrialFunctions(Y)
v, q, w = TestFunctions(Y)

# Numerical parameters
gamma = 1.017

# Second component
L2 = inner(w,div(u))*dx

# Assemble bilinear form
A = dolfinx.fem.assemble_matrix(L2)
A.assemble()
1 Like

Thank you very much! It’s working now.