Response to Answer below.
Original Question:
I am trying to refine a 3D mesh in a certain region. This seems relevant but does not work for me. I start by making the region which consists of a box with an internal plate attached to one side.
Needs["NDSolve`FEM`"];
a = 1;
b = 0.5;
L = 0.2 + 0.0302;
d = 1;
tk = 0.01;
pts = {{L, -tk, 0}, {L, tk, 0}, {-L, tk, 0}, {-L, -tk, 0}, {L, -tk,
d}, {L, tk, d}, {-L, tk, d}, {-L, -tk, d}};
pts1 = {{a, -a, -b}, {a, a, -b}, {-a, a, -b}, {-a, -a, -b}, {a, -a,
d}, {a, a, d}, {-a, a, d}, {-a, -a, d}};
allpts = Join[pts, pts1];
hex = {{1, 2, 3, 4}, {1, 5, 6, 2}, {2, 6, 7, 3}, {7, 8, 4, 3}, {5, 1,
4, 8}};
hex1 = {{12, 9, 10, 11}, {9, 13, 14, 10}, {14, 15, 11, 10}, {15, 16,
12, 11}, {16, 13, 9, 12}};
hex2 = {{16, 8, 5, 13}, {13, 5, 6, 14}, {6, 7, 15, 14}, {16, 15, 7,
8}};
\[ScriptCapitalR] =
BoundaryMeshRegion[
allpts, {Polygon[hex], Polygon[hex1], Polygon[hex2]},
MeshCellStyle -> Opacity[0.3]];
HighlightMesh[\[ScriptCapitalR], Labeled[0, "Index"]]
This looks satisfactory so I continue to make a boundary mesh and a full mesh
bmesh = ToBoundaryMesh[\[ScriptCapitalR],
"BoundaryMeshGenerator" -> "Continuation"];
mesh = ToElementMesh[bmesh]
(* ElementMesh[{{-1., 1.}, {-1., 1.}, {-0.5, 1.}}, {TetrahedronElement[ "<" 16873 ">"]}] *)
I notice I get 16873 elements. The wire frame looks reasonable and I also plot within the outside box to inspect my plate.
m1 = mesh["Wireframe"]
Graphics3D[m1[[1]], Axes -> True,
PlotRange -> {All, {-0.5, 0.5}, All}]
I can improve my mesh by setting MaxCellMeasure
mesh = ToElementMesh[bmesh, MaxCellMeasure -> 0.0001]
m2 = mesh["Wireframe"]
Graphics3D[m2[[1]], Axes -> True,
PlotRange -> {All, {-0.5, 0.5}, All}]
(* ElementMesh[{{-1., 1.}, {-1., 1.}, {-0.5, 1.}}, {TetrahedronElement[ "<" 114246 ">"]}]*)
I now have 114246 elements. I only need the small elements around the plate so I attempt to make a mesh refinement function
ClearAll[mrf];
mrf = Function[{vert, vol},
Block[{y},
y = Min[Abs[vert[[All, 2]]]];
y < 0.2 && vol > 0.005
]
];
When I apply this option it seems to get ignored and I get back my first attempt with 16873 elements.
mesh = ToElementMesh[bmesh, MeshRefinementFunction -> mrf]
(* ElementMesh[{{-1., 1.}, {-1., 1.}, {-0.5, 1.}}, {TetrahedronElement[ "<" 16873 ">"]}]*)
How do I refine in a local region? Thanks for any enlightenment.
Edit in response to answer
User21 (always very helpful; thank you) has given a very useful answer but has not quite got me to where I wish to be.
Using MaxCellMeasure -> Infinity does give a refined mesh in some locations but not as much as I was expecting. Thus using this code
ClearAll[mrf];
mrf[{vert_, vol_}] := Module[{y},
y = Min[Abs[vert[[All, 2]]]];
y < 0.4 && vol > 0.00001
];
mesh = ToElementMesh[bmesh, MaxCellMeasure -> Infinity,
MeshRefinementFunction -> mrf]
m3 = mesh["Wireframe"]
Graphics3D[m3[[1]], Axes -> True, PlotRange -> {All, {-0.5, 0.5}, All}]
Graphics3D[{Point[mesh[[1]]]},
AspectRatio -> Automatic, Axes -> True
]
I have added a visualization of the elements by plotting their end points. Looking at the boundary mesh on the plate it is approximately the same as the first attempt using default values. It is not as good at the second case where I refined everywhere. Where I refined everywhere the boundary mesh was improved as needed. For my MeshRefinementFunction I don't seem to have changed the boundary mesh much. Do I have to do a boundary refinement function as well?
Addition using the update from user21.
User21 used the centre of each tet rather than the node nearest the plate. This seems to make a better job. In an extension to this update I have generated a mesh refinement function that just refines the volume around the plate. I have also defined a value for the mesh outside this volume so that the elements are not too small elsewhere. Thus
ClearAll[cf];
cf = With[{tk = tk, d = d, L = L},
Compile[{{c, _Real, 2}, {a, _Real, 0}},
Block[{com},
com = Total[c]/4;
If[
- 5 tk <= com[[2]] <= 5 tk &&
-L - 5 tk < com[[1]] <= L + 5 tk &&
-5 tk < com[[3]] &&
a > 0.00001, True, False]
]
]
];
mesh = ToElementMesh[bmesh, MaxCellMeasure -> 0.0005,
MeshRefinementFunction -> cf]
mesh = ToElementMesh[bmesh, MaxCellMeasure -> 0.0005,
MeshRefinementFunction -> cf]
mesh["Wireframe"[Axes -> True, PlotRange -> {All, {-0.5, 0.5}, All}]]
Graphics3D[{Point[mesh[[1]]]},
AspectRatio -> Automatic, Axes -> True
]
This gives me what I need. Thanks