How to assign Element marker at boundary edges
Here is an approach using built-in functions:
reg = DiscretizeRegion[Disk[{0, 0}, 0.5], MeshCellHighlight -> {{2, All} -> White}]
Now, we obtain the outer points:
int = MeshCellIndex[reg, {0, "Interior"}][[All,2]] (* interior points *)
ext = Complement[MeshCellIndex[reg, 0][[All,2]], int] (* exterior points *)
Finally, we set the properties of the region (interior and exterior points) using PropertyValue
and MeshCellLabel
:
PropertyValue[{reg, {0, ext}}, MeshCellLabel] =
Style[#, Bold, Darker @ Red, 8] & /@ Range @ Length @ ext;
PropertyValue[{reg, {0, int}}, MeshCellLabel] =
Style[#, Bold, Darker @ Blue, 8] & /@ Table[0, Length @ int];
Let's visualize:
reg
Note that this is still very much a region and you can compute various properties as usual:
Area @ reg
0.782472
Since this question has a FEM tag, I assume that the mesh is for applying boundary conditions to a PDE. If that is the case, then the solution suggested by @RunnyKine can be improved.
What you are looking for are the "PointMarkerFunction"
and the "BoundaryMarkerFunction"
. Now, it is important to understand that markers can be applied to points for DirichletConditions
via PointElements
, to edges/surfaces for NeumannValues via BoundaryElements
and to region components via MeshElements
for PDE coefficients. Once markers are in a mesh these are independent from each other. That means a NeumannValue
that looks for a ElementMaker
does not care about markers in point or mesh elements only about markers in boundary elements. So if you ask for markers in edges that will ever only be useful for NeumannValues
.
To get your requested marker in the mesh you can use a small function
Needs["NDSolve`FEM`"]
boundaryMarkerFunction =
Compile[{{boundaryElementCoords, _Real,
3}, {pointMarkres, _Integer, 2}},
Range[Length[boundaryElementCoords]]];
This is going to return a marker for every boundary element. To create the mesh use:
mesh = ToElementMesh[Disk[{0, 0}, 0.5],
"BoundaryMarkerFunction" ->
boundaryMarkerFunction
(*Optional for better visualization of this example *)
"MaxCellMeasure" -> 0.1,
"MaxBoundaryCellMeasure" -> 0.2,
PrecisionGoal -> 10^-3
];
This then gives
Show[mesh[
"Wireframe"["MeshElement" -> "BoundaryElements",
"MeshElementMarkerStyle" -> Red]]
, mesh["Wireframe"["MeshElement" -> "MeshElements",
"MeshElementMarkerStyle" -> Blue]]
]
There are a few things to note: First, the default mesh element marker is 0, so there was no need to set anything. If you want a different marker then 0, you can use "RegionMarker"\[Rule]{{{0,0},1}}
to specify a 1 marker.
Next, if you look at the PointElement
markers you'll see:
Show[mesh[
"Wireframe"["MeshElement" -> "PointElements",
"MeshElementMarkerStyle" -> Magenta]]
, mesh["Wireframe"]
]
So, the makers there have been derived from the edge markers specified. You can overwrite that by specifying a PointMarkerFunction
. There are a few examples in the FEM documentation of ToElementMesh in the options sections and in the ElementMesh generation tutorial.
Why should you use ToElementMesh
for that? To main reasons: First the FEM code will not understand the labels specified for the mesh region (that could be made to work) but secondly, the mesh is much more accurate:
(* MeshRegion *)
\[Pi] (1/2)^2 - 0.782472
0.0029261633974483336`
(* ElementMesh *)
\[Pi] (1/2)^2 - Total[Join @@ mesh["MeshElementMeasure"]]
0.0000174314511414142`
So, even for such a coarse FEM ElementMesh
, the accuracy of the area is much better because it's a second order mesh and the MeshRegion
is first order only. If you do FEM then I'd recommend to use ToElementMesh