3
$\begingroup$

I want to mesh a cube and what I use is ToElementMesh[Cuboid[ {-1, -1, -1}, {1, 1, 1}]]. This creates a regular grid of the cube.

Is there a way to specify that it has to use triangles and that the density should be larger in the middle of the cube compared to the corners?

$\endgroup$
  • 1
    $\begingroup$ Use the options "MeshElementType" and "MeshRefinementFunction". $\endgroup$ – Rahul Feb 4 '15 at 13:28
  • $\begingroup$ @Rahul Is there a way to use triangles and make the boundaries identical such that I can use periodic boundary conditions? $\endgroup$ – BillyJean Feb 4 '15 at 13:46
3
$\begingroup$

I don't know of a built-in way to get a periodic boundary.

New answer

Another way: One potential drawback is that the tetrahedra are aligned with a regular grid. But if the main goal was to increase the fineness of the mesh near the center, then this is a way to do that.

First create a hexahedral mesh of an appropriate fineness along the boundary. Then refine it to a tetrahedral mesh, with a MeshRefinementFunction that prevents refinement at the boundary (other than the initial decomposition of the cubes into tetrahedra). Opposite boundaries seem to be divided in the same way, but one ought to check because I know of no guarantee of this. As in the original answer one can inspect hexmesh to determine the appropriate cut-off Max[Abs[vertices]] < 0.6 for the MeshRefinementFunction.

hexmesh = ToElementMesh[Cuboid[{-1, -1, -1}, {1, 1, 1}],
                        MaxCellMeasure -> {"Volume" -> 0.05}];
tetmesh = ToElementMesh[
  ToBoundaryMesh[
   "Coordinates" -> hexmesh["Coordinates"],
   "BoundaryElements" -> hexmesh["BoundaryElements"]],
  MeshElementType -> TetrahedronElement,
  MaxCellMeasure -> {"Volume" -> 0.05},
  MeshRefinementFunction -> 
   Function[{vertices, vol}, 
    vol > 0.0002 + 0.001 Max[Abs[vertices]] && Max[Abs[vertices]] < 0.6]]
(*
  ElementMesh[{{-1., 1.}, {-1., 1.}, {-1., 1.}},
   {TetrahedronElement["<" 5643 ">"]}]
*)

tetmesh["Wireframe"]
tetmesh["Wireframe"["MeshElement" -> "MeshElements", Boxed -> False]]

Mathematica graphics

Mathematica graphics

Original answer

Here's a way to construct one. You have to be careful in converting the boundary to a full mesh, since ToElementMesh will subdivide the boundary. This method does not seem to be foolproof, but you can get boundary meshes of varying densities, so it seems workable.

The idea is to create a mesh on a square. Then make six copies of the meshed square in 3-space to form the boundary of the solid cube. Next, mesh the cube so that the boundary stays in tact using MaxCellMeasure -> {"Volume" -> Infinity} and a MeshRefinementFunction that does not allow refinement near the boundary.

Needs["NDSolve`FEM`"];

base = ToElementMesh[Cuboid[{-1, -1}, {1, 1}], 
   MaxCellMeasure -> {"Area" -> 0.01}, 
   MeshElementType -> TriangleElement];
coordsL = PadRight[base["Coordinates"], {Automatic, 3}, -1];
coordsR = PadRight[base["Coordinates"], {Automatic, 3}, 1];
bcoords = 
  Join @@ NestList[RotateLeft[#, {0, 1}] &, Join[coordsL, coordsR], 2];
belem = {TriangleElement[
    Join @@ Table[
      base["MeshElements"][[1, 1]] + i*Length[coordsL], {i, 0, 5}]
    ]};

bmesh = ToBoundaryMesh[
   "Coordinates" -> bcoords,
   "BoundaryElements" -> belem];

We can visually inspect a side of the cube to see how to construct the MeshRefinementFunction.

Show[base["Wireframe"], Frame -> True]

Mathematica graphics

We can also inspect the volumes of the elements to gauge appropriate cut-offs for the MeshRefinementFunction.

Sort[Flatten[ElementMeshElementMeasure[emesh]]] // Short[#1, 5] &
(*
 {0.0000301671, 0.0000397688, 0.0000411234, <<13847>>, 0.00349643, 0.00360805, 0.00393156}
*)

emesh = ToElementMesh[bmesh,
  MaxCellMeasure -> {"Volume" -> Infinity},
  MeshRefinementFunction -> 
   Function[{vertices, vol}, 
    vol > 0.00002 + 0.0015 Max[Abs[vertices]] && Max[Abs[vertices]] < 0.8]]
(*
  ElementMesh[{{-1., 1.}, {-1., 1.}, {-1., 1.}},
   {TetrahedronElement["<" 13853 ">"]}]
*)

We can check the results. The boundary of emesh agrees with the constructed bmesh.

bmesh["Wireframe"]
emesh["Wireframe"]

Sort /@ Cases[Normal@bmesh["Wireframe"], Polygon[p_] :> p, Infinity];
Sort /@ Cases[Normal@emesh["Wireframe"], Polygon[p_] :> p, Infinity];
% === %%
(*  True  *)

emesh["Wireframe"["MeshElement" -> "MeshElements", Boxed -> False]]

Mathematica graphics

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.