I have a two phase system for ALE-FSI problem. I extract a submesh from parent mesh to make immersed solid. In every step, the parent mesh is moved by appending a displacement function Delta_x
as
_mesh.geometry.x[:, :tdim] += Delta_x.x.array.reshape((-1, tdim))
The submesh is also needed to be updated accordingly. Here I create a displacement function Delta_x_s
on the submesh, and Delta_x_s
is interpolated from Delta_x
as suggested by the following.
I have tried the aforementioned step by either matching meshes or non-matching meshes interpolation, but the submesh is wrongly updated as the attached figure shows. I sense that it is due to the DOF-vertex relation is mismatched on submesh.
MWE with DOLFINx v0.9.0:
import os
os.environ['OMP_NUM_THREADS'] = '1'
from dolfinx import io, fem, mesh
from mpi4py import MPI
import numpy as np
import ufl
from dolfinx.fem.petsc import LinearProblem
comm = MPI.COMM_WORLD
prefix = "output"
mesh_order = 1
_mesh = mesh.create_unit_square(comm, 16, 16)
tdim = 2
fdim = tdim - 1
_mesh.geometry.x[:, :tdim] -= 0.5
_mesh.geometry.x[:, :tdim] *= 2
# Create mesh and functions
V = fem.functionspace(_mesh, ("Lagrange", mesh_order, (tdim,)))
DG0 = fem.functionspace(_mesh, ("DG", 0))
mask = fem.Function(DG0)
Omega_s = mesh.locate_entities(_mesh, tdim, lambda x: np.logical_and(np.abs(x[0]) < 0.25 + 1e-5,
np.abs(x[1]) < 0.25 + 1e-5))
_mesh.topology.create_connectivity(tdim, tdim)
_mesh.topology.create_connectivity(fdim, tdim)
dofs = fem.locate_dofs_topological(DG0, tdim, Omega_s)
mask.x.array[dofs] = 1
disp = fem.Function(V)
wall_function = fem.Function(V)
Delta_x = fem.Function(V)
u = ufl.TrialFunction(V)
v = ufl.TestFunction(V)
# Create submesh
submesh, solid_cell_map, _, _ = mesh.create_submesh(_mesh, tdim, Omega_s)
V_s = fem.functionspace(submesh, ("Lagrange", mesh_order, (tdim, )))
Delta_x_s = fem.Function(V_s)
boundary_facets = mesh.exterior_facet_indices(_mesh.topology)
bc_solid = fem.dirichletbc(disp, fem.locate_dofs_topological(V, tdim, Omega_s))
bc_wall = fem.dirichletbc(wall_function, fem.locate_dofs_topological(V, fdim, boundary_facets))
bcs = [bc_solid, bc_wall]
N = 20
delta_alpha = - np.pi / 4 / N
x = ufl.SpatialCoordinate(_mesh)
center = ufl.as_vector([0.0, 0.0])
cos = ufl.cos(delta_alpha)
sin = ufl.sin(delta_alpha)
R = ufl.as_matrix([[cos, -sin], # rotation matrix
[sin, cos]])
I = ufl.Identity(tdim)
# Weak form for ALE mapping
a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx
L = ufl.inner(fem.Constant(_mesh, [0.] * tdim), v) * ufl.dx
# Visualize initial result
with io.XDMFFile(MPI.COMM_WORLD, f"{prefix}/mesh_0.xdmf", "w") as file:
file.write_mesh(_mesh)
file.write_function(mask, 0)
with io.XDMFFile(MPI.COMM_WORLD, f"{prefix}/submesh_0.xdmf", "w") as file:
file.write_mesh(submesh)
file.write_function(Delta_x, 0)
# Time iterate
for step in range(N):
# Set up boundary conditions
expr = fem.Expression((R - I) * (x - center), V.element.interpolation_points())
disp.interpolate(expr)
disp.x.scatter_forward()
# Solve ALE mapping
if comm.rank == 0:
print(f"Step {step + 1} / {N}", flush=True)
problem = LinearProblem(a, L, bcs = bcs, u = Delta_x,
petsc_options={"ksp_type": "preonly", "pc_type": "lu",
"pc_factor_mat_solver_type": "mumps"})
problem.solve()
Delta_x.x.scatter_forward()
_mesh.geometry.x[:, :tdim] += Delta_x.x.array.reshape((-1, tdim))
# Move submesh by interpolating displacement
# 1. Matching mesh interpolation
Delta_x_s.x.array[:] = 0.0
Delta_x_s.interpolate(Delta_x,
cells0 = solid_cell_map,
cells1 = np.arange(len(solid_cell_map)))
Delta_x_s.x.scatter_forward()
submesh.geometry.x[:, :tdim] += Delta_x_s.x.array.reshape((-1, tdim))
# 2. Non-matching mesh interpolation
"""
dest_mesh_cell_map = V_s.mesh.topology.index_map(tdim)
num_cells_on_proc = dest_mesh_cell_map.size_local + dest_mesh_cell_map.num_ghosts
cells = np.arange(num_cells_on_proc, dtype = np.int32)
interpolation_data = fem.create_interpolation_data(V_s, V, cells, padding=1e-8)
Delta_x_s.interpolate_nonmatching(Delta_x, cells, interpolation_data=interpolation_data)
submesh.geometry.x[:, :tdim] += Delta_x_s.x.array.reshape((-1, tdim))
"""
with io.XDMFFile(MPI.COMM_WORLD, f"{prefix}/mesh_{step + 1}.xdmf", "w") as file:
file.write_mesh(_mesh)
file.write_function(mask, step + 1)
with io.XDMFFile(MPI.COMM_WORLD, f"{prefix}/submesh_{step + 1}.xdmf", "w") as file:
file.write_mesh(submesh)
file.write_function(Delta_x_s, step + 1)