This is a read only copy of the old FEniCS QA forum. Please visit the new QA forum to ask questions

How to apply BCs for sub domains?

0 votes

I am currently working on an implementation of PMLs in FEniCS to allow better simulation of scattering problems. PMLs are layers surrounding the region of interest (the inner domain) in which the scattered waves are absorbed so as to avoid reflections back into the inner domain.

Starting in 1D, i have tried creating an IntervalMesh and splitting it into an inner domain and a (surrounding) pml domain. Since the incoming field should only be present on the inner domain, the BCs are applied at the edge of the inner domain. Hence if the thickness of the pml layers (dpml) is nonzero, the inner domain boundaries will not coincide with the mesh boundaries. In this case, i get an all-zero solution. If dpml=0 i get the expected solution.

Below is a MWE. To get the all-zero solution, simply change dpml to a non-zero value.

from dolfin import *
import numpy as np

class LambdaDomain(SubDomain):
    def __init__(self, condition):
        self.condition = condition
        SubDomain.__init__(self)

    def inside(self, x, on_boundary):
        return self.condition(x, on_boundary)

wl = 500
lx = wl*2
nx = 1000
dpml = 0.0 * wl

# Create mesh.
lx_full = int(lx + 2.0 * dpml)
nx_full = int((lx_full / lx) * nx)
mesh = IntervalMesh(nx_full, 0.0, lx_full)
# Mark boundaries.
facet_function = FacetFunction('size_t', mesh)
LambdaDomain(lambda x, on: near(x[0], dpml, lx / nx) and x[0] >= dpml).mark(facet_function, 1)
# ds = Measure("ds")[facet_function]  # Original code
dS = Measure("dS")[facet_function]
# Mark domains.
cell_function = CellFunction('size_t', mesh)
LambdaDomain(lambda x, on: dpml <= x[0] <= lx + dpml).mark(cell_function, 1)
dx = Measure("dx")[cell_function]

# Define constants.
k0 = Constant(2 * np.pi / wl)
A0 = Constant(1.0)
# Create double valued space (real + imag).
V = FunctionSpace(mesh, 'CG', 2)
V2 = V * V
# Create test/trail functions (real + imag).
(u_r, u_i) = TrialFunction(V2)
(v_r, v_i) = TestFunction(V2)
# EQ: 1D scalar helmholtz.
a = k0 * k0 * (v_r * u_r + v_i * u_i) * dx(1) - \
    (inner(nabla_grad(u_r), nabla_grad(v_r)) + inner(nabla_grad(u_i), nabla_grad(v_i))) * dx(1)
# BC: Incoming plane wave from left.
# L = - 2 * v_r * Expression('-A0*(k0*sin(k0*x[0]))', k0=k0, A0=A0) * ds(1) + \
#     - 2 * v_i * Expression('-A0*(k0*cos(k0*x[0]))', k0=k0, A0=A0) * ds(1)  # Original code
L = - 2 * avg(v_r) * avg(Expression('-A0*(k0*sin(k0*x[0]))', k0=k0, A0=A0)) * dS(1) + \
    - 2 * avg(v_i) * avg(Expression('-A0*(k0*cos(k0*x[0]))', k0=k0, A0=A0)) * dS(1)
# Solve equations
A = assemble(a)
b = assemble(L)
p = Function(V2)
solve(A, p.vector(), b)
pr, pi = p.split(True)

# Plot stuff.
plot(facet_function)
plot(cell_function)
plot(pr)
interactive()

I guess i am applying the BCs wrong somehow. Can anyone point me in the right direction?

asked Feb 16, 2016 by emher FEniCS User (1,290 points)
edited Feb 16, 2016 by emher

1 Answer

+1 vote
 
Best answer

For setting "boundary conditions" like that, you need to use dS (interior facets) instead of ds (exterior facets). You also need to restrict your arguments, typically by using avg.

answered Feb 16, 2016 by Øyvind Evju FEniCS Expert (17,700 points)
selected Feb 16, 2016 by emher

You're absolutely correct. I have update my MWE with the necessary adjustments.

...