Unable to set low tolerance for picking points on boundary, [Warning: Found no facets matching domain for boundary condition]

Dear Community

Please find below the code segment which solves the 2D axisymmetric conduction problem in a spherical annulus.

There is a parameter called “TOL” in the program which is used to pick out points on the boundary. I have seen examples where TOL values as low as 1e-14 have been used. However, for the current set of parameters shown in the code, the lowest I can go is TOL=1e-3, and the computed solution agrees well with the analytical result.

However, if I use TOL=1e-4, I get the message

*** Warning: Found no facets matching domain for boundary condition" ***

and the computed solution is not correct. Using a higher number of segments for the polygonal approximation of a circle (the “num_segments” parameter) results in the same behavior. Using a higher value of the “mesh_resolution” parameter also does not help, and at mesh_resolution=512, I get the following error,

UMFPACK V5.7.8 (Nov 9, 2018): ERROR: out of memory

along with the previous warning about no facets found.

Could you please guide me on this matter ? Specifically, what should I do in order to be able to set a lower TOL value? I am assuming that smaller the value of TOL, more accurately would the boundaries be picked out.

Thank You
Warm Regards

from dolfin import *
from mshr import *
import math
import numpy as np

Re = 5.
Ri = 1.

domain = Circle(Point(0., 0.), Re, num_segments) - Circle(Point(0., 0.), Ri, num_segments)
mesh_resolution = 64
mesh = generate_mesh(domain, mesh_resolution)
V = FunctionSpace(mesh, "CG", 2)

x = SpatialCoordinate(mesh)
r = Expression("sqrt(x[0]*x[0]+x[1]*x[1])", degree=2)
theta = Expression("atan2(x[1],x[0])", degree=2)

# Define boundary subdomains

TOL = 1e-3 
# TOL = 1e-4 or lower results in 
# "Warning: Found no facets matching domain for boundary condition"

u_inner = Expression('cos(theta)', degree=2, theta=theta)
def inside(x, on_boundary):
    return near(x[0]**2 + x[1]**2, Ri**2, TOL) and on_boundary
u_outer = Constant(0.0)
def outside(x, on_boundary):
    return near(x[0]**2 + x[1]**2, Re**2, TOL) and on_boundary

inner_circ = DirichletBC(V,u_inner,inside)
outer_circ = DirichletBC(V,u_outer,outside)
bcs = [inner_circ, outer_circ]

u = TrialFunction(V)
v = TestFunction(V)
a1 = (u.dx(0)*v.dx(0))+(u.dx(1)*v.dx(1))
a2 = (Constant(1.0)/(r*sin(theta)))*v*(u.dx(1))
a = (a1-a2)*dx
f = Constant(0.0)
L = f*v*dx

# Compute solution
u = Function(V)
solve(a == L, u, bcs)

For your current problem, where you have two external boundaries, namely the circle with radius Ri and the circle with radius Re, I would suggest the following approach:

r_mid = Ri + (Re - Ri) / 2

class Inside(SubDomain):
    def inside(self, x, on_boundary):
        return sqrt(x[0]**2 + x[1]**2) < r_mid  and on_boundary

class Outside(SubDomain):
    def inside(self, x, on_boundary):
        return sqrt(x[0]**2 + x[1]**2) > r_mid and on_boundary

sub_domains = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
Inside().mark(sub_domains, 1)
Outside().mark(sub_domains, 2)
File("facets.pvd") << sub_domains

inner_circ = DirichletBC(V, u_inner, sub_domains, 1)
outer_circ = DirichletBC(V, u_outer, sub_domains, 2)

as you can see by opening the file facets.pvd in Paraview, you observe that the boundaries are correctly marked, independent of the mesh size.

1 Like

Thank you very much, Dokken, for the prompt response. Your suggestion works perfectly, and I was able to follow the logic of the script.

Warm Regards