How to correctly assign values to mixed elements in FEniCS-X?

Hi all, I want to assign values to the mixed elements in FEniCSX. Since there are not too many tutorials about mixed elements FEniCSX, I do it according to the tutorials of FEniCS, but the results seem to be incorrect.

Here is my minimal working example:

import dolfinx
import numpy as np
from mpi4py import MPI
from dolfinx.cpp.mesh import CellType
import ufl

mesh = dolfinx.RectangleMesh(MPI.COMM_WORLD, [np.array([0, 0, 0]), np.array([2, 2, 0])], \
    [1, 2], CellType.quadrilateral)
v_el = ufl.VectorElement("CG", mesh.ufl_cell(), 1)
s_el = ufl.FiniteElement("CG", mesh.ufl_cell(), 1)
mixed_el = ufl.MixedElement([v_el, s_el]) # mixed element
VP = dolfinx.FunctionSpace(mesh, mixed_el) # mixed function space
q = dolfinx.Function(VP)
u, v = ufl.split(q) # trial functions
(w, y) = ufl.TestFunctions(VP) # test functions

# we assign arbitrary values to u and v as solutions
NNode = mesh.geometry.x.shape[0] # number of nodes
u0, v0  = q.split()
with u0.vector.localForm() as u0_loc:
    u0_loc.setValues((np.arange(2*NNode)).tolist(), np.arange(2*NNode).tolist())
with v0.vector.localForm() as v0_loc:
    v0_loc.setValues((2*NNode+np.arange(NNode)).tolist(), np.arange(NNode).tolist())
print(u0.compute_point_values().round(2))
print(v0.compute_point_values().round(2))

This code will give us the wrong result:

[[-0.  1.]
 [ 2.  3.]
 [ 4.  5.]
 [ 6.  7.]
 [ 0.  1.]
 [ 2.  3.]]
[[ 8.]
 [ 9.]
 [10.]
 [11.]
 [ 4.]
 [ 5.]]

If we use the simple elements

V = dolfinx.VectorFunctionSpace(mesh, ("CG", 1))
S = dolfinx.FunctionSpace(mesh, ("CG", 1))
u  = dolfinx.Function(V)
v  = dolfinx.Function(S)

NNode = mesh.geometry.x.shape[0] # number of nodes
with u.vector.localForm() as u_loc:
    u_loc.setValues(np.arange(2*NNode).tolist(), np.arange(2*NNode).tolist())
with v.vector.localForm() as v_loc:
    v_loc.setValues(np.arange(NNode).tolist(), np.arange(NNode).tolist())
print(u.compute_point_values().round(2))
print(v.compute_point_values().round(2))

we can obtain the correct results:

[[-0.  1.]
 [ 2.  3.]
 [ 4.  5.]
 [ 6.  7.]
 [ 8.  9.]
 [10. 11.]]
[[-0.]
 [ 1.]
 [ 2.]
 [ 3.]
 [ 4.]
 [ 5.]]

If we reduce the element size,

mesh = dolfinx.RectangleMesh(MPI.COMM_WORLD, [np.array([0, 0, 0]), np.array([2, 2, 0])], \
    [1, 1], CellType.quadrilateral)

We can obtain the same results from simple and mixed elements now:

[[0. 1.]
 [2. 3.]
 [4. 5.]
 [6. 7.]]
[[0.]
 [1.]
 [2.]
 [3.]]

So could anyone please tell me how to correctly assign values to mixed elements in FEniCS-X?
Thanks!

1 Like

Actually this is a follow-up question of the post Solve the nonlinear coupled-field problem with FEniCSX - FEniCS Project. I am not sure if I illustrated my question clearly, and I would like to restate my question:

We have one mixed element mixed_el containing two simple elements v_el and s_el. I want to assign values 0-11 to function u0 corresponding to the element v_el, and values 0-5 to the function v0 corresponding to the element s_el. So how can I realize it?

Thanks!

Consider the following:

import dolfinx
from mpi4py import MPI
import dolfinx.io
import ufl
import numpy as np

mesh = dolfinx.UnitSquareMesh(MPI.COMM_WORLD, 10, 10)
el = ufl.FiniteElement("CG", mesh.ufl_cell(), 1)
mel = ufl.MixedElement([el, el])
V = dolfinx.FunctionSpace(mesh, mel)
num_subs = V.num_sub_spaces()
spaces = []
maps = []
for i in range(num_subs):
    space_i, map_i = V.sub(i).collapse(collapsed_dofs=True)
    spaces.append(space_i)
    maps.append(map_i)


u = dolfinx.Function(V)
u0 = dolfinx.Function(spaces[0])
u1 = dolfinx.Function(spaces[1])

u0.vector.array[:] = np.arange(len(maps[0]))
u1.vector.array[:] = np.arange(len(maps[1]))
u.vector.array[maps[0]] = u0.vector.array
u.vector.array[maps[1]] = u1.vector.array

with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "splitted_space.xdmf", "w") as xdmf:
    xdmf.write_mesh(mesh)
    xdmf.write_function(u.sub(0))
    xdmf.write_function(u.sub(1))
4 Likes

Thanks @Yingqi_Jia for this post and @dokken for the solution - It is also very useful for me.

I am working with complex geometries, so I need to run my code in parallel. However, when I try to run in parallel (using MPI) the solution that @dokken proposes, I get an error saying that:

could not broadcast input array from shape (46,) into shape (33,)

Therefore, I was wondering if it is possible to use this approach for parallel computing or if I need to think on a different solution for this problem.

Thank you very much in advance.

@JLorenteMacias Consider the following up to date example:

import dolfinx
from mpi4py import MPI
import dolfinx.io
import ufl
import numpy as np

mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 10, 10)
el = ufl.FiniteElement("CG", mesh.ufl_cell(), 1)
mel = ufl.MixedElement([el, el])
V = dolfinx.fem.FunctionSpace(mesh, mel)
num_subs = V.num_sub_spaces
spaces = []
maps = []
for i in range(num_subs):
    space_i, map_i = V.sub(i).collapse()
    spaces.append(space_i)
    maps.append(map_i)


u = dolfinx.fem.Function(V)
u0 = dolfinx.fem.Function(spaces[0])
u1 = dolfinx.fem.Function(spaces[1])
u0.x.array[:] = np.arange(len(maps[0]))
u1.x.array[:] = np.arange(len(maps[1]))[::-1]
u.x.array[maps[0]] = u0.x.array
u.x.array[maps[1]] = u1.x.array
u.x.scatter_forward()
with dolfinx.io.XDMFFile(MPI.COMM_WORLD, "splitted_space.xdmf", "w") as xdmf:
    xdmf.write_mesh(mesh)
    xdmf.write_function(u.sub(0))
    xdmf.write_function(u.sub(1))
6 Likes

Thank you very much!