Bug fixed in Version 12.0
I would like to calculate the volume of ElementMesh
made of HexahedronElement
. Even though "MeshOrder"
is 1, elements can have "curved" faces (nodes of the same face are not co-planar). This is a MWE with one element.
Needs["NDSolve`FEM`"]
mesh = ToElementMesh[
"Coordinates" -> {{0,0,0},{1,0,0},{1,1,0},{0,1,0},{0,0,0.5},{1,0,1},{1,1,1},{0,1,1}},
"MeshElements" -> {HexahedronElement[{{1, 2, 3, 4, 5, 6, 7, 8}}]}
];
mesh["Wireframe"["MeshElementStyle" -> FaceForm[LightBlue],ImageSize -> 200]]
I have found 4 different methods and each gives me a different answer. The most straightforward is to use the "MeshElementMeasure"
method of ElementMesh
object.
Total@Flatten@mesh["MeshElementMeasure"]
(* 0.916667 *)
I converted the hexahedron to 5 tetrahedra and called the same method on them (function is defined bellow).
Total@Flatten[HexToTetrahedron[mesh]["MeshElementMeasure"]]
(* 0.833333 *)
Then my own implementation of Gauss integration of Jacobian determinant over element (function is defined below).
MeshElementVolume[mesh["Coordinates"], HexahedronElement, 1]
(* 0.875 *)
And finally NIntegrate
which also works on ElementMesh
objects.
NIntegrate[1., {x, y, z} ∈ mesh]
(* 0.876271 *)
What is "the most" correct way to calculate this volume? I know there are some assumptions involved on how to treat the curved face, but surely there must some common way to do this?
Definitions of functions used above:
HexToTetrahedron::type="ElementMesh should contain only hexadedral elements.";
HexToTetrahedron[mesh_ElementMesh]:=Module[{
nodes,origElms,tetConnect,restructure,newElms
},
origElms=mesh["MeshElements"];
If[Head@First[origElms]=!=HexahedronElement,Message[HexToTetrahedron::type];Return[$Failed]];
tetConnect={{4, 1, 2, 5},{7, 5, 2, 6},{4, 2, 3, 7},{4, 5, 2, 7},{4, 5, 7, 8}};
restructure=Function[{hexNodes},Part[hexNodes,#]&/@tetConnect];
newElms=TetrahedronElement[
Flatten[restructure/@First@ElementIncidents[origElms],1]
];
ToElementMesh[
"Coordinates"->mesh["Coordinates"],
"MeshElements"->{newElms}
]
]
(* Works for one element only. *)
MeshElementVolume[nodes_List,type_,meshOrder_]:=Block[{
igCrds=ElementIntegrationPoints[type,meshOrder],
igWgts=ElementIntegrationWeights[type,meshOrder],
shapeDerivative=ElementShapeFunctionDerivative[type,meshOrder],
jacobian,r,s,t
},
jacobian=Function[{r,s,t},Det[(shapeDerivative@@{r,s,t}).nodes]];
(jacobian@@@igCrds).igWgts
]
MeshRegion[{{0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 0, 0.5}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1}}, Hexahedron[{{1, 2, 3, 4, 5, 6, 7, 8}}]]
Sorry about that. $\endgroup$ToElementMesh[Cuboid[{-1, -1, -1}, {1, 1, 1}], MaxCellMeasure -> {"Volume" -> 0.005}, "MeshElementType" -> TetrahedronElement];
$\endgroup$