Hello all,
We are currently trying to solve a coupled PDE with 4 degrees of freedom (3 displacement and 1 pressure) preferably with a MixedElement approach.
Right now we have several issues with the code (the snippet omits the definition of the weak forms but it should be clear anyway):
- after definition of the MixedElement we can’t access the underlying Functions for u and lambda (pressure). [Line 58 and following]
- definition of the boundary conditions seems to be way to complex for such an easy problem setup (especially for all the single components of u). [Line 68 - 135]
- the PDE contains the time derivative of the displacement. For the approximation we try to incorporate a simple backwards differentiation scheme based on the currently known solution of u. However, this approach does not work well with the MixedElement formulation (due to the fact that we cannot extract the underlying functions of the MixedElement) [Line 141 - 147]
import numpy as np
from mpi4py import MPI
from petsc4py import PETSc
import ufl
from dolfinx import mesh, fem, plot, io, nls
# ---------------------------------------------------------------------------- #
# Parameters #
# ---------------------------------------------------------------------------- #
L, W, H = 1, 1, 1
mesh_size = 0.2
# Simulation parameter
dt = 0.1
# Elasticity parameters
E = 1e7
nu = 0.3
# Environmental influences
b = [0, 0, 0]
# 3D box with hexahedron cells
n_elements = [max(int(x / mesh_size), 1) for x in [L, W, H]]
domain = mesh.create_box(
comm=MPI.COMM_WORLD,
points=[np.array([0, 0, 0]), np.array([L, W, H])],
n=n_elements,
cell_type=mesh.CellType.hexahedron,
)
# ---------------------------------------------------------------------------- #
# FiniteElements #
# ---------------------------------------------------------------------------- #
# u = displacement (dim=3)
# lm = pressure (dim=1)
element_u = ufl.VectorElement(
family="Lagrange",
cell=domain.ufl_cell(),
degree=2,
)
element_lm = ufl.FiniteElement(
family="Lagrange",
cell=domain.ufl_cell(),
degree=1,
)
element = ufl.MixedElement(element_u, element_lm)
V = fem.FunctionSpace(domain, element)
# The trial/test functions get defined on the (mixed) function space
dudlm = ufl.TestFunction(V)
du, dlm = ufl.split(dudlm)
ulm = fem.Function(V)
(u, lm) = ufl.split(ulm)
print(type(lm)) # ufl.indexed.Indexed <<<< why no Function
print(type(u)) # ufl.tensors.ListTensor <<<< from split?
# we use dx as the measure on the domain volume and ds on the boundary
dx = ufl.dx
ds = ufl.ds
# ---------------------------------------------------------------------------- #
# Boundary Conditions #
# ---------------------------------------------------------------------------- #
# is there an easier way for the definition of the BCs in mixed elements?
def clamped_boundary(x, axis, offset):
return np.isclose(x[axis], offset)
clamp_u = lambda x: clamped_boundary(x, 2, 0)
clamp_lm_left = lambda x: clamped_boundary(x, 0, 0)
clamp_lm_right = lambda x: clamped_boundary(x, 0, L)
facet_dim = domain.topology.dim - 1
# get the mesh entities, where the clamped boundary shall be applied
boundary_facets_u = mesh.locate_entities_boundary(
domain,
facet_dim,
clamp_u,
)
boundary_facets_lm_left = mesh.locate_entities_boundary(
domain,
facet_dim,
clamp_lm_left,
)
boundary_facets_lm_right = mesh.locate_entities_boundary(
domain,
facet_dim,
clamp_lm_right,
)
# get the topological (element) dofs that correspond to the clamped boundary
topological_dofs_x = fem.locate_dofs_topological(
V.sub(0).sub(0),
facet_dim,
boundary_facets_u,
)
topological_dofs_y = fem.locate_dofs_topological(
V.sub(0).sub(1),
facet_dim,
boundary_facets_u,
)
topological_dofs_z = fem.locate_dofs_topological(
V.sub(0).sub(2),
facet_dim,
boundary_facets_u,
)
topological_dofs_lm_left = fem.locate_dofs_topological(
V.sub(1),
facet_dim,
boundary_facets_lm_left,
)
topological_dofs_lm_right = fem.locate_dofs_topological(
V.sub(1),
facet_dim,
boundary_facets_lm_right,
)
u_D = PETSc.ScalarType(0.0)
bcx = fem.dirichletbc(u_D, topological_dofs_x, V.sub(0).sub(0))
bcy = fem.dirichletbc(u_D, topological_dofs_y, V.sub(0).sub(1))
bcz = fem.dirichletbc(u_D, topological_dofs_z, V.sub(0).sub(2))
bclml = fem.dirichletbc(PETSc.ScalarType(0), topological_dofs_lm_left, V.sub(1))
bclmr = fem.dirichletbc(PETSc.ScalarType(50), topological_dofs_lm_right, V.sub(1))
bcs = [bcx, bcy, bcz, bclml, bclmr]
# ---------------------------------------------------------------------------- #
# Definition of a time differentiation method #
# ---------------------------------------------------------------------------- #
# required: du/dt
u_prev = fem.Function(V.sub(0))
u_prev.interpolate(lambda x: np.zeros_like(x[:3])) # initialize with 0
u_dot = (u - u_prev) / dt
# print(u_dot.x.array) # <<< does not work. Is there an alternative?
# ---------------------------------------------------------------------------- #
# Define Weak Form #
# ---------------------------------------------------------------------------- #
F = get_weak_form() # (dummy)
# ---------------------------------------------------------------------------- #
# Solve #
# ---------------------------------------------------------------------------- #
problem = fem.petsc.NonlinearProblem(F, ulm, bcs=bcs)
solver = nls.petsc.NewtonSolver(MPI.COMM_WORLD, problem)
# ... some more options
for i in range(1):
uh = solver.solve(ulm)
u_prev.x.array[:] = u.x.array[:] # <<< does not work either (u is ListTensor)
Any input is highly appreciated.
Thanks in advance and all the best