I deformed a mesh by appending a deformation array to the mesh with mesh.geometry.x[:, d] += deformation_array.x.array[:]
, where d
is the dimension of mesh to be moved. I got the correct result with a serial run. The result was wrong with parallel runs but the visualization was correct.
To brief the problem: I have two non-matching meshes in a FSI problem. Every time I need to interpolate the fields from the background (bigger) domain to the foreground (smaller) domain and then form the deformation array. In the following code, serial run returns the expected result 1, but it gives 1.30419921875 with
mpirun -n 4 python parallel_area.py
The doflinx version is 0.6.0.
MWE:
# parallel_area.py
# Test to measure area of mesh after deformation in parallel
from mpi4py import MPI
from dolfinx import fem, io, mesh
from ufl import dx
# Dimension of the problem
ndims = 2
# Foreground mesh and function space
mesh_square = mesh.create_unit_square(MPI.COMM_WORLD, 32, 32)
mesh_square.geometry.x[:, :2] -= 0.5 # move center to (0, 0) with size (-0.5, -0.5) -> (0.5, 0.5)
V_square = fem.VectorFunctionSpace(mesh_square, ("Lagrange", 1))
Q_square = fem.FunctionSpace(mesh_square, ("Lagrange", 1))
# Background mesh and function space
mesh_background = mesh.create_unit_square(MPI.COMM_WORLD, 64, 64)
mesh_background.geometry.x[:, :2] -= 0.5 # move center to (0, 0)
mesh_background.geometry.x[:, :2] *= 2 # double the size: (-1, -1) -> (1, 1)
V_background = fem.VectorFunctionSpace(mesh_background, ("Lagrange", 1))
Q_background = fem.FunctionSpace(mesh_background, ("Lagrange", 1))
# Original area
one = fem.Function(Q_square)
one.x.array[:] = 1
f = one*dx
area0 = MPI.COMM_WORLD.allreduce(fem.assemble_scalar(fem.form(one*dx)), op = MPI.SUM)
print("Original area:", area0) # always returns 1 as expected
with io.XDMFFile(MPI.COMM_WORLD, "original_area.xdmf", "w") as file:
file.write_mesh(mesh_square)
## Deformation occurs
# Define background fields
u_background = fem.Function(V_background)
u_background.sub(0).interpolate(lambda x: x[1]) # like a shear flow
# Interpolate to foreground fields
u_square = fem.Function(V_square)
for d in range(ndims):
u_square.sub(d).interpolate(u_background.sub(d))
# Deform the foreground mesh
dt = 1 # an coefficient which mimics the one in the real problem
for d in range(ndims):
mesh_square.geometry.x[:, d] += u_square.sub(d).collapse().x.array[:] * dt
# Compute new area
one = fem.Function(Q_square)
one.x.array[:] = 1
f = one*dx
area1 = MPI.COMM_WORLD.allreduce(fem.assemble_scalar(fem.form(one*dx)), op = MPI.SUM)
with io.XDMFFile(MPI.COMM_WORLD, "changed_area.xdmf", "w") as file:
file.write_mesh(mesh_square)
print("Changed area:", area1) # mpirun -n 1: 1; -n 2: 1; -n 3: 1.45068359375; -n 4: 1.30419921875