Hi there,
I try to model simple 1D diffusion problem with Robin BC using Dokken’s tutorial using DOLFINX v0.9.0 with conda. The Dirichlet and Neumann BCs are all OK but Robin BC does not agree with the analytical solution within the domain although it satisfies the values at the boundaries.
Here is the MWE:
from dolfinx.fem import functionspace
from dolfinx.fem import (Constant, Function, functionspace, assemble_scalar,
dirichletbc, form, locate_dofs_topological)
from ufl import TrialFunction, TestFunction, inner, ds, lhs, rhs, dx, Measure, grad
import numpy as np
from dolfinx.fem.petsc import LinearProblem
from dolfinx import default_scalar_type
from dolfinx.mesh import meshtags, locate_entities, create_interval
from mpi4py import MPI
# Geometrical parameters
N = 10
L_total = 1.0
mesh = create_interval(MPI.COMM_WORLD, N, [0.0, L_total])
mesh.topology.create_connectivity(mesh.topology.dim - 1, mesh.topology.dim)
boundaries = [(1, lambda x: np.isclose(x[0], 0)),
(2, lambda x: np.isclose(x[0], L_total))]
facet_indices, facet_markers = [], []
fdim = mesh.topology.dim - 1
for (marker, locator) in boundaries:
facets = locate_entities(mesh, fdim, locator)
facet_indices.append(facets)
facet_markers.append(np.full(len(facets), marker))
facet_indices = np.array(np.hstack(facet_indices), dtype=np.int32)
facet_markers = np.array(np.hstack(facet_markers), dtype=np.int32)
sorted_facets = np.argsort(facet_indices)
facet_tags = meshtags(mesh, fdim, facet_indices[sorted_facets], facet_markers[sorted_facets])
# Define the boundary conditions
u_left = 1.0
D_ij = 1.0 # diffusion coefficient
r_k = -1 # mass transfer coefficient
r = Constant(mesh, default_scalar_type(-D_ij*r_k))
s = 0.3 # concentration outside the surface
degree = 1
V = functionspace(mesh, ("Lagrange", degree))
u, v = TrialFunction(V), TestFunction(V)
f = Constant(mesh, default_scalar_type(0))
F = D_ij * inner(grad(u), grad(v)) * dx - inner(f, v) * dx
ds = Measure("ds", domain=mesh, subdomain_data=facet_tags)
class BoundaryCondition():
def __init__(self, type, marker, values):
self._type = type
if type == "Dirichlet":
u_D = Function(V)
u_D.x.array[:]=values
facets = facet_tags.find(marker)
dofs = locate_dofs_topological(V, fdim, facets)
self._bc = dirichletbc(u_D, dofs)
elif type == "Neumann":
self._bc = inner(values, v) * ds(marker)
elif type == "Robin":
self._bc = values[0] * inner(u-values[1], v)* ds(marker)
else:
raise TypeError("Unknown boundary condition: {0:s}".format(type))
@property
def bc(self):
return self._bc
@property
def type(self):
return self._type
boundary_conditions = [
BoundaryCondition("Dirichlet", 1, u_left),
BoundaryCondition("Robin", 2, (r, s)),
]
bcs = []
for condition in boundary_conditions:
if condition.type == "Dirichlet":
bcs.append(condition.bc)
else:
F += condition.bc
# Solve linear variational problem
a = lhs(F)
L = rhs(F)
problem = LinearProblem(a, L, bcs=bcs, petsc_options={"ksp_type": "preonly", "pc_type": "lu"})
c_numeric = problem.solve()
x_numeric = np.linspace(0, L_total, len(c_numeric.x.array))
# Analytical solution
x_analytical = np.linspace(0, L_total, N+1)
c_analytical = (-r_k*s*x_analytical + u_left)/(1-r_k*x_analytical)
import matplotlib.pyplot as plt
plt.plot(x_numeric, c_numeric.x.array, "s-r", label="FEM")
plt.plot(x_analytical, c_analytical, label="trivial")
plt.xlabel("x")
plt.ylabel("concentration (%)")
plt.legend()
plt.show()
giving:
I would be grateful if you can enlighten me.