Building a Cmesh by hand - DLR-AMR/t8code GitHub Wiki
Build Cmesh
In this tutorial we will learn how to create a user defined cmesh by hand.
This is suitable for small to medium sized cmeshes where you want to fully control all parameters.
For beginners we recommend to not follow this route but to read a cmesh from file using t8_cmesh_vtk_reader
(vor VTK files) or t8_cmesh_from_msh_file
(for Gmsh created .msh files).
You will find the code to this example in the tutorials/general/t8_tutorial_build_cmesh*
files and it creates the executables tutorials/general/t8_tutorial_build_cmesh
.
In the last tutorials we learned how to create a forest, adapt it, and how to store data. We also learned about algorithms for partitioning, balancing and creating a ghost layer. In all these previous tutorials predefined meshes were used. In this tutorial we learn how to define a user defined mesh in two- and three dimensions. In both examples we define and use different tree classes and join the different trees to create the domain. In order to be able to reflect the results, the meshes are stored in .vtu
files.
Steps of how to define a mesh
The cmesh defines the topology of a given domain and is the coarsest possible mesh.
1. Definition of all vertices
In a first step an array with all is defined. Independent of the fact if a mesh is defined two- or three dimensional, each point is defined by three coordinates. The vertices are ordered in a listing of points for each cell. Thus, there can be duplicates in the list.
double vertices[numberOfValues] = {
//point values for tree 1
x_1,y_1,z_1 //(x,y,z) of first point of tree 1
x_2,y_2,z_2 //(x,y,z) of second point of tree 1
.
.
.
x_n,y_n,z_n //(x,y,z) of nth point (last point) of tree 1
//point values for tree 2
x_1,y_1,z_1 //(x,y,z) of first point of tree 2
x_2,y_2,z_2 //(x,y,z) of second point of tree 2
.
.
.
x_m,y_m,z_m //(x,y,z) of nth point (last point) of tree 2
.
.
.
//point values for the last tree
x_1,y_1,z_1 //(x,y,z) of first point of the last tree
x_2,y_2,z_2 //(x,y,z) of second point of the last tree
.
.
.
x_o,y_o,z_o //(x,y,z) of nth point (last point) of the last tree
};
2. Initialization of the mesh
Before creating a mesh, it has, of course, to be initialized using t8_cmesh_init
.
3. Definition of the geometry
A cmesh can have different types of geometry which are set using the function t8_cmesh_register_geometry
. The use of curved meshes is described in the tutorial Feature Curved meshes. In this tutorial we will use meshes with a linear geometry.
4. Definition of the classes of the different trees
t8code
supports eight different basic tree shapes for the cmesh
, see also t8_eclass.h
:
element shape | description | Number of vertices |
---|---|---|
T8_ECLASS_VERTEX | 0D points | 1 |
T8_ECLASS_LINE | 1D lines | 2 |
T8_ECLASS_TRIANGLE | 2D triangles | 3 |
T8_ECLASS_QUAD | 2D quadrilaterals | 4 |
T8_ECLASS_TET | 3D tetrahedra | 4 |
T8_ECLASS_PYRAMID | 3D pyramids | 5 |
T8_ECLASS_PRISM | 3D prisms | 6 |
T8_ECLASS_HEX | 3D hexahedra | 8 |
Using the function t8_cmesh_set_tree_class
the tree class of each tree is set.
Parameter | Description |
---|---|
cmesh | The cmesh to be updated. |
tree_id | The global number of the tree. |
tree_class | The element class of this tree. |
Definition of the classes of the different trees - each tree is defined by one cell
//Class of the first tree
t8_cmesh_set_tree_class (cmesh, 0, T8_ECLASS_[TYPE]);
//Class of the second tree
t8_cmesh_set_tree_class (cmesh, 1, T8_ECLASS_[TYPE]);
.
.
.
//Class of the last tree
t8_cmesh_set_tree_class (cmesh, x, T8_ECLASS_[TYPE]);
5. Classification of the vertex coordinates for each tree
Vertex IDs for the two two-dimensional trees:
Each tree can assign coordinates to its vertices. This is done using t8_cmesh_set_tree_vertices
.
It is not allowed to call this function after t8_cmesh_commit
.
Parameter | Description |
---|---|
cmesh | The cmesh to be updated. |
tree_id | The global number of the tree. |
*vertices | Array of 3 * num_vertices doubles storing the vertex coordinates. Can be overwritten or deleted after the function call. |
num_vertices | Number of the vertices of the tree (i.e. 3 for a triangle tree, 4 for a quad tree, ...). |
// Set vertex coordinates of tree 0
t8_cmesh_set_tree_vertices (cmesh, 0, [pointerToVertexCoordinatesOfTreeZero], [numberOfVerticesTreeZero]);
// Set vertex coordinates of tree 1
t8_cmesh_set_tree_vertices (cmesh, 1, [pointerToVertexCoordinatesOfTreeOne] , [numberOfVerticesTreeOne]);
.
.
.
// Set vertex coordinates of tree x
t8_cmesh_set_tree_vertices (cmesh, x, [pointerToVertexCoordinatesOfTree(x)] , [numberOfVerticesTree(x)]);
After the cmesh was committed you can retrieve the coordinates by calling double *t8_cmesh_get_tree_vertices (t8_cmesh_t cmesh, t8_locidx_t ltreeid)
.
6. Definition of global vertex Ids
Since https://github.com/DLR-AMR/t8code/pull/960 (t8code version 4.0.0) it is possible to assign global vertex Ids to the tree vertices.
That is, if two trees are connected to each other via two of their vertices, this vertex becomes a single global vertex with a unique Id.
These Ids have to be set manually using t8_cmesh_set_global_vertices_of_tree
.
It is not allowed to call this function after t8_cmesh_commit
.
Parameter | Description |
---|---|
cmesh | The cmesh to be updated. |
tree | The gobale tree id of a tree in the cmesh |
global_tree_vertices | An array of num_vertices many integers specifying the global vertex Ids of the tree's local vertices. |
num_vertices | The number of (local) vertices of the tree (i.e. 3 for a triangle, 4 for a quad). |
// Set the global vertex Ids of tree 0
t8_cmesh_set_global_vertices_of_tree (cmesh, 0, [pointerToGlobalVertexIdsOfTreeZero], [numberOfVerticesTreeZero]);
// Set the global vertex Ids of tree 1
t8_cmesh_set_global_vertices_of_tree (cmesh, 1, [pointerToGlobalVertexIdsOfTreeOne], [numberOfVerticesTreeOne]);
...
After the cmesh is committed you can retrieve the global vertex Ids via t8_cmesh_get_global_vertices_of_tree
to get the global Ids of a single tree's vertices or via t8_cmesh_get_vertex_to_tree_list
(currently WIP and not yet available) to get for each global vertex Id a list of all (tree,vertex) pairs that are connected to it.
7. Definition of the face neighbors between the different trees
Edge IDs for the corresponding to the vertices can be seen in the previous figure (f_i).
In this step all connections (face neighbors) between the different trees are set using t8_cmesh_set_join
.
Parameter | Description |
---|---|
cmesh | The cmesh to be updated. |
tree1 | The tree id of the first of the two trees. |
tree2 | The tree id of the second of the two trees. |
face1 | The face number of the first tree. |
face2 | The face number of the second tree. |
orientation | Specify how face1 and face2 are oriented to each other |
The orientation is determined as follows. Let my_face and other_face be the two face numbers of the connecting trees.
We chose a main_face from them as follows: Either both trees have the same element class, then the face with the lower face number is the main_face o the trees belong to different classes in which case the face belonging to the tree with the lower class according to the ordering
triangle < square, hex < tet < prism < pyramid
,
is the main_face.
Then face corner 0 of the main_face connects to a face corner k in the other face. The face orientation is defined as the number k.
// List of all face neighboor connections
t8_cmesh_set_join (cmesh, [treeId1], [treeId2], [faceIdInTree1], [faceIdInTree2], [orientation]);
t8_cmesh_set_join (cmesh, [treeId1], [treeId2], [faceIdInTree1], [faceIdInTree2], [orientation]);
.
.
.
t8_cmesh_set_join (cmesh, [treeId1], [treeId2], [faceIdInTree1], [faceIdInTree2], [orientation]);
8. Commit the mesh
The last step of creating a user defined mesh is committing the mesh using t8_cmesh_commit
.
2D Example
In this two-dimensional example four triangles and two quads are used. We will look at the following example. In the left you can see the order of the vertices and in the right the edge IDs.
The vertices of the trees have the following coordinate:
tree | vertices |
---|---|
triangle 1 | {(0, 0, 0), (0.5, 0, 0), (0.5, 0.5, 0)} |
triangle 2 | {(0, 0, 0), (0.5, 0.5, 0), (0, 0.5, 0)} |
triangle 3 | {(0.5, 0.5, 0), (1, 0.5, 0), (1, 1, 0)} |
triangle 4 | {(0.5, 0.5, 0), (1, 1, 0), (0.5, 1, 0)} |
quad 1 | {(0.5, 0, 0), (1, 0, 0), (0.5, 0.5, 0), (1, 0.5, 0)} |
quad 2 | {(0, 0.5, 0), (0.5, 0.5, 0), (0, 1, 0), (0.5, 1, 0)} |
The tree class for the triangles is T8_ECLASS_TRIANGLE
and this for the quad is T8_ECLASS_QUAD
:
// definition of the tree classes (you need one classification for each tree)
t8_cmesh_set_tree_class (cmesh, [treeID], T8_ECLASS_TRIANGLE);
t8_cmesh_set_tree_class (cmesh, [treeID], T8_ECLASS_QUAD);
Each edge of the tree has an ID. The IDs for this example can be seen in the figure. For the direct neighbor information, the following trees are connected:
ID of first tree | ID of second tree | ID of face (first tree) | ID of face (second tree) |
---|---|---|---|
0 | 1 | 1 | 2 |
0 | 2 | 0 | 0 |
1 | 3 | 0 | 2 |
2 | 4 | 3 | 2 |
3 | 5 | 1 | 1 |
4 | 5 | 1 | 2 |
// definition of the face neighboors
t8_cmesh_set_join (cmesh, 0, 1, 1, 2, 0);
t8_cmesh_set_join (cmesh, 0, 2, 0, 0, 0);
t8_cmesh_set_join (cmesh, 1, 3, 0, 2, 1);
t8_cmesh_set_join (cmesh, 2, 4, 3, 2, 0);
t8_cmesh_set_join (cmesh, 3, 5, 1, 1, 0);
t8_cmesh_set_join (cmesh, 4, 5, 1, 2, 0);
As this cmesh has periodic boundaries, there are also the connections
ID of first tree | ID of second tree | ID of face of first tree | ID of face of second tree |
---|---|---|---|
0 | 3 | 2 | 3 |
1 | 2 | 1 | 1 |
2 | 5 | 2 | 0 |
3 | 4 | 0 | 0 |
// definition of the face neighboors for the periodic boundaries
t8_cmesh_set_join (cmesh, 0, 3, 2, 3, 0);
t8_cmesh_set_join (cmesh, 1, 2, 1, 1, 0);
t8_cmesh_set_join (cmesh, 2, 5, 2, 0, 1);
t8_cmesh_set_join (cmesh, 3, 4, 0, 0, 0);
3D Example
In this three dimensional example two tetrahedra, two prisms, one pyramid, and one hexahedron is used. We will look at the following example. In the left you can see the order of the vertices and in the right the edge IDs.
The vertices of the trees have the following coordinate:
tree | vertices |
---|---|
tetrahedron 1 | {(0.43, 0, 2), (0, 0, 1), (0.86, -0.5, 1), (0.86, 0.5, 1)} |
tetrahedron 2 | {(2.29, 0, 2), (1.86, -0.5, 1), (2.72, 0, 1), (1.86, 0.5, 1)} |
prism 1 | {(0, 0, 0), (0.86, -0.5, 0), (0.86, 0.5, 0), (0, 0, 1), (0.86, -0.5, 1), (0.86, 0.5, 1)} |
prism 2 | {(1.86, -0.5, 0), (2.72, 0, 0), (1.86, 0.5, 0), (1.86, -0.5, 1), (2.72, 0, 1), (1.86, 0.5, 1)} |
pyramid | {(0.86, 0.5, 0), (1.86, 0.5, 0), (0.86, -0.5, 0), (1.86, -0.5, 0), (1.36, 0, -0.5)} |
hexahedron | {(0.86, -0.5, 0), (1.86, -0.5, 0), (0.86, 0.5, 0), (1.86, 0.5, 0), (0.86, -0.5, 1), (1.86, -0.5, 1),(0.86, 0.5, 1), (1.86, 0.5, 1)} |
The tree class for the tetrahedra is T8_ECLASS_TET
, this for the prisms is T8_ECLASS_PRISM
, and this for the hexahedron is T8_ECLASS_HEX
:
// definition of the tree classes (you need one classification for each tree)
t8_cmesh_set_tree_class (cmesh, [treeID], T8_ECLASS_TET);
t8_cmesh_set_tree_class (cmesh, [treeID], T8_ECLASS_PRISM);
t8_cmesh_set_tree_class (cmesh, [treeID], T8_ECLASS_PYRAMID);
t8_cmesh_set_tree_class (cmesh, [treeID], T8_ECLASS_HEX);
As the mesh has no periodic boundaries, there are only direct neighbors. These are encoded by the face connections between the trees:
ID of first tree | ID of second tree | ID of face (first tree) | ID of face (second tree) |
---|---|---|---|
0 | 2 | 0 | 4 |
1 | 3 | 4 | 4 |
2 | 5 | 0 | 0 |
3 | 5 | 1 | 1 |
4 | 5 | 4 | 4 |
// definition of the face neighboors
t8_cmesh_set_join (cmesh, 0, 2, 0, 4, 0);
t8_cmesh_set_join (cmesh, 1, 3, 0, 4, 0);
t8_cmesh_set_join (cmesh, 2, 5, 0, 0, 0);
t8_cmesh_set_join (cmesh, 3, 5, 1, 1, 0);
t8_cmesh_set_join (cmesh, 4, 5, 4, 4, 2);