# Distinguish between inner and outer boundary in MeshRegion

For example, this is a 2D MeshRegion with one (or more) holes in it:

mr = DiscretizeRegion@RegionDifference[
Rectangle[{-1, -1}, {1, 1}],
Disk[{0, 0}, 0.5]
]


I would like to identify outer boundary (MeshCells) and inner boundary of a hole. I can get indices of all boundary MeshCells, but cannot distinguish between them. How can I do that?

HighlightMesh[mr, MeshCellIndex[mr, {1, "Boundary"}]]


Ultimately I will convert this MeshRegion to ElementMesh and assign different integer markers to LineElements on the boundary.

• What is the reason you start with a MeshRegion in the first place? Jan 9, 2019 at 8:01
• @user21 There is no particular reason, I just couldn't think of a better solution. Actually the input and output for this procedure will always be ElementMesh. Jan 9, 2019 at 8:04

You can use ConnectedMeshComponents as follows:

cmc = ConnectedMeshComponents[DiscretizeGraphics[MeshPrimitives[mr, {1, "Boundary"}]]];

Show[mr,  Epilog -> Thread[{Thickness[.01], {Red, Blue},  MeshPrimitives[#, 1] & /@ cmc}]]


You can convert your MeshRegion to a boundary element mesh with auto generated markers by:

Needs["NDSolveFEM"]
bmesh = ToBoundaryMesh[RegionBoundary[mr]];
bmesh["Wireframe"["MeshElementStyle" -> "BoundaryGrouping"]]


The fact that the rectangle has also been split is desirable for FEM. You can look at the markers generated.

bmesh["BoundaryElementMarkerUnion"]
{1, 2, 3, 4, 5}


Here is a mesh that has an outer boundary, an inner boundary and a material boundary:

Needs["NDSolveFEM"]
\[CapitalOmega] =
ImplicitRegion[(x - 1/2)^2 + (y - 1/2)^2 >= (1/
2)^2 && (x + 1/2)^2 + (y + 1/2)^2 >= (1/2)^2, {{x, -2,
2}, {y, -2, 2}}];
(mesh = ToElementMesh[\[CapitalOmega],
"RegionHoles" -> {{-1/2, -1/2}},
"RegionMarker" -> {{{1/2, 1/2}, 2}, {{1/2, -1/2}, 1}},
"MaxBoundaryCellMeasure" -> 0.125])["Wireframe"]


You can then extract the boundary element marker union; these markers are auto generated.

groups = mesh["BoundaryElementMarkerUnion"]
{1, 2, 3, 4, 5, 6}


Some colors for the markers:

temp = Most[Range[0, 1, 1/(Length[groups])]];
colors = ColorData["BrightBands"][#] & /@ temp


mesh["Wireframe"["MeshElement" -> "BoundaryElements",
"MeshElementStyle" -> (Directive[#] & /@ colors)]]


To further work with this you could use MeshElementSplitByMarker:

mesbm = Flatten[
MeshElementSplitByMarker[
MeshOrderAlteration[mesh, 1]["BoundaryElements"]]];


and extract one of the components:

Graphics[GraphicsComplex[mesh["Coordinates"],
Line[ElementIncidents[mesbm[[6]]]]]]


This selection works by looking at normals and grouping them with some threshold. There are a few examples in the ElementMesh ref page in the Scope section under "BoundaryNormals".

Another approach is to use the "VertexBoundaryConnectivity" in conjunction with StronglyConnectedComponents.

bmesh = ToBoundaryMesh[mesh];
belems = bmesh["BoundaryElements"];

bincidents = Join @@ ElementIncidents[belems];
S = bmesh["VertexBoundaryConnectivity"];
S = Transpose[S].S;
components = SparseArrayStronglyConnectedComponents[S];
pls = Map[Line[DeveloperToPackedArray /@ (Part[bincidents, #])] &,
components]
Graphics[GraphicsComplex[bmesh["Coordinates"], pls]]


• Thanks. I think that StronglyConnectedComponents method is suitable for me, since my ElementMesh objects may come without distinct markers of "BoundaryElements", because they could be imported from elsewhere. Jan 9, 2019 at 9:57
• @Pinti, I think they should have boundary markers even if they are imported. If not, could you please send me such an example to look at it? Thanks. Jan 9, 2019 at 11:48
• Very useful! Which version did you use? In MMA 11.0 on Windows, the third line of your reply (bmesh["Wireframe"["MeshElementStyle" -> "BoundaryGrouping"]]) throws an error: BoundaryGrouping is not a Graphics primitive or directive. Jul 2, 2019 at 12:05
• Reproduced on another 11.0 Windows machine. Works fine in 11.3. Jul 2, 2019 at 12:13