Picking boundaries for a semi-circular domain

Hi @rkailash,

The issue here is the way mshr treats circles: not as circles, but as N-sided polygons (N-gons). You have specified num_segments = 500, which means that your mesh is of a 500-gon. mshr places vertices at the endpoints of each boundary segment, and at the midpoint. The vertex at the midpoint is not located on the circle. (In fact, it is displaced inwards in the radial direction by a distance of R(1-\cos{(\pi/N)}). This is why, in your original post, tol = 1e-3 worked but tol = 1e-4 did not. (Consider that for Re = 5 and num_segments = 500, R(1-\cos{(\pi/N)}) = 9.8\cdot 10^{-5}, very close to your tol.)

One way to fix this issue is to use Gmsh rather than mshr to generate your mesh. Gmsh treats circles as circles, not as N-gons, so all vertices on the boundary will be located on the circle, not displaced inwardly as in the mshr-generated mesh. If you take this appoach, your original functions

def inside(x, on_boundary):
    return near(x[0]**2 + x[1]**2, Ri**2, TOL) and on_boundary

def outside(x, on_boundary):
    return near(x[0]**2 + x[1]**2, Re**2, TOL) and on_boundary

should correctly identify the boundary nodes, even for very small values of TOL.

If you wish to continue using mshr, first consider that this statement from your original post is not strictly true:

The accuracy of picking out the boundaries is binary: the boundaries are correctly picked out, or they are not. The optimal value of tol is the largest value that is sufficiently small to exclude any internal facets. Choosing tol to be any smaller than this value will not have any effect on whether internal facets are picked, but it will make it more likely that external facets will be erroneously excluded. Using the expression that I have provided above, you could start with the following, and see if tol is sufficiently small to exclude all internal facets:

def inside(x, on_boundary):
    tol = 1.5*Ri * (1 - np.cos(np.pi / num_segments))
    return near(x[0]**2 + x[1]**2, Ri**2, tol) and on_boundary

def outside(x, on_boundary):
    tol = 1.5*Re * (1 - np.cos(np.pi / num_segments))
    return near(x[0]**2 + x[1]**2, Re**2, tol) and on_boundary