Hello all,
I've been experimenting with the Poisson equation with a discontinuous coefficient, like in this example from the tutorial and the multiple subdomain demo.
There seem to be several ways to define the coefficients, and I wonder what the difference might be.
The method described in the demo is via subdomains.
Example:
from dolfin import *
import mshr
# Define Dirichlet boundary (x = 0 or x = 1)
class BoundaryLeft(SubDomain):
def inside(self, x, on_boundary):
return x[1] < DOLFIN_EPS and on_boundary
class BoundaryRight(SubDomain):
def inside(self, x, on_boundary):
return x[1] > 1 - DOLFIN_EPS and on_boundary
class Omega0(SubDomain):
def inside(self, x, on_boundary):
return True if x[1] <= 0.5 else False
class Omega1(SubDomain):
def inside(self, x, on_boundary):
return True if x[1] >= 0.5 else False
domain = mshr.Rectangle(Point(0., 0.), Point(1., 1.))
mesh = mshr.generate_mesh(domain, 32)
V = FunctionSpace(mesh, "CG", 1)
domains = CellFunction("size_t", mesh)
domains.set_all(0)
subdomain0 = Omega0()
subdomain0.mark(domains, 0)
subdomain1 = Omega1()
subdomain1.mark(domains, 1)
dx = Measure('dx', domain=mesh, subdomain_data=domains)
left = BoundaryLeft()
right = BoundaryRight()
bcs = [DirichletBC(V, 0., left),
DirichletBC(V, 1., right)]
k0 = Constant(1.5)
k1 = Constant(50.)
f = Constant(0.)
# Exact solution
u_ex = Expression("x[1] <= 0.5 ? 2*x[1]*k1/(k0+k1) : \
((2*x[1]-1)*k0+k1)/(k0+k1)", k0=float(k0), k1=float(k1))
# Define variational problem
u = TrialFunction(V)
v = TestFunction(V)
L = f*v*dx
a = inner(k0*grad(u), grad(v))*dx(0) + inner(k1*grad(u), grad(v))*dx(1)
u1 = Function(V)
solve(a == L, u1, bcs)
print("Err = %.3e" % errornorm(u_ex, u1))
Another method I consider is by interpolating an expression onto a DG-0 space, instead of using subdomains:
dx = Measure('dx')
kf = Expression("x[1]<=0.5 ? k0 : k1", k0=k0, k1=k1)
V0 = FunctionSpace(mesh, "DG", 0)
ki = interpolate(kf, V0)
u = TrialFunction(V)
v = TestFunction(V)
a = inner(ki*grad(u), grad(v))*dx
u2 = Function(V)
solve(a == L, u2, bcs)
print("Err = %.3e" % errornorm(u_ex, u2))
On the "unstructured" mesh, the error of the second method appears to be generally smaller than with the first one. With UnitSquareMesh(32, 32)
the problem is solved exactly and in both cases the error is exactly the same and near machine precision; but this is not the case I'm interested in.
Apart from the general advantages that subdomains may have for complex externally created meshs over expressions, what is the recommended way? What is the technical difference?
Thank you for your help!
David