Introduction
Grids are regular orthognal meshes. Similar to unstructured numerical meshes they provide indexing of mesh entites and express their adjacency. The difference, compared to the unstructured meshes, is that the adjacency of the mesh entities are not stored explicitly in the memory but the are computed on-the-fly. The interface of grids is as simillar as possible to the unstructured meshes but there are some differences. The main difference is that the mesh entities are given by their coordinates and orientation. The type and orientation of the entity is given by its basis and normals. Basis is a vector having one for axes, along which the entity has non-zero length, and zeros otherwise. Normals is a vector orthogonal to the basis vector, i.e. it has ones where basis vector has zeros and vice versa. The meaning of the normals vector is such that it is like a pack of all vectors of standart basis which are orthogonal to the grid entity. The following tables show all possible grid entities in 1D, 2D and 3D.
TODO: Bases and normals
Grid entities in 1D are as follows:
Entities in 1D | Basis | Normals | Unpacked normal vectors |
Cells | ( 1 ) | ( 0 ) | N/a |
Vertexes | ( 0 ) | ( 1 ) | ( 1 ) |
Grid entities in 2D are as follows:
Entities in 2D | Basis | Normals | Unpacked normal vectors |
Cells | ( 1, 1 ) | ( 0, 0 ) | N/A |
Faces along x- axis | ( 1, 0 ) | ( 0, 1 ) | ( 0, 1 ) |
Faces along y- axis | ( 0, 1 ) | ( 1, 0 ) | ( 1, 0 ) |
Vertexes | ( 0, 0 ) | ( 1, 1 ) | ( 1, 0 ), ( 0, 1 ) |
Grid entities in 3D are as follows:
Entities in 3D | Basis | Normals | Unpacked normal vectors |
Cells | ( 1, 1, 1 ) | ( 0, 0, 0 ) | N/A |
Faces along x- and y- axes | ( 1, 1, 0 ) | ( 0, 0, 1 ) | ( 0, 0, 1 ) |
Faces along x- and z- axes | ( 1, 0, 1 ) | ( 0, 1, 0 ) | ( 0, 1, 0 ) |
Faces along y- and z- axes | ( 0, 1, 1 ) | ( 1, 0, 0 ) | ( 1, 0, 0 ) |
Edges along x-axis | ( 1, 0, 0 ) | ( 0, 1, 1 ) | ( 0, 1, 0 ), ( 0, 0, 1 ) |
Edges along y-axis | ( 0, 1, 0 ) | ( 1, 0, 1 ) | ( 1, 0, 0 ), ( 0, 0, 1 ) |
Edges along z-axis | ( 0, 0, 1 ) | ( 1, 1, 0 ) | ( 1, 0, 0 ), ( 0, 1, 0 ) |
Vertexes | ( 0, 0, 0 ) | ( 1, 1, 1 ) | ( 1, 0, 0 ), ( 0, 1, 0 ), ( 0, 0, 1 ) |
The grid entity stores the vector with packed normals, tha basis vector is always computed on the fly. So whenever it possible, using the the normals vector is preferred for better performance.
Remark: The entity orientation given by the normals or basis vector should be encoded staticaly in the type of the entity. This would make the implementation of the grid entities more efficient. Such implementation, however, requires suppport of the generic lambda function by the compiler. Since the CUDA compiler nvcc
is not able to compile a code with the generic lambda functions we stay with current implementation which is not optimal. Therefore, in the future, the implementation of the grid entities may change.
The following figures show coordinates and indexing of the grid entities in 2D for demonstration. Indexing of cells looks as follows:
+-------+-------+-------+-------+-------+ +-------+-------+-------+-------+-------+
| (0,4) | (1,4) | (2,4) | (3,4) | (4,4) | | (20 ) | (21 ) | (22 ) | (23 ) | (24 ) |
+-------+-------+-------+-------+-------+ +-------+-------+-------+-------+-------+
| (0,3) | (1,3) | (2,3) | (3,3) | (4,3) | | (15 ) | (16 ) | (17 ) | (18 ) | (19 ) |
+-------+-------+-------+-------+-------+ +-------+-------+-------+-------+-------+
| (0,2) | (1,2) | (2,2) | (3,2) | (4,2) | | (10 ) | (11 ) | (12 ) | (13 ) | (14 ) |
+-------+-------+-------+-------+-------+ +-------+-------+-------+-------+-------+
| (0,1) | (1,1) | (2,1) | (3,1) | (4,1) | | ( 5 ) | ( 6 ) | ( 7 ) | ( 8 ) | ( 9 ) |
+-------+-------+-------+-------+-------+ +-------+-------+-------+-------+-------+
| (0,0) | (1,0) | (2,0) | (3,0) | (4,0) | | ( 0 ) | ( 1 ) | ( 2 ) | ( 3 ) | ( 4 ) |
+-------+-------+-------+-------+-------+ +-------+-------+-------+-------+-------+
Indexing of faces looks as:
+-(0,6)-+-(1,6)-+-(2,6)-+-(3,6)-+-(4,6)-+ +-( 30)-+-( 31)-+-( 32)-+-( 33)-+-( 34)-+
| | | | | | | | | | | |
(0,5) (1,5) (2,5) (3,5) (4,5) (5,5) ( 65) ( 66) ( 67) ( 68) ( 69) ( 70)
| | | | | | | | | | | |
+-(0,5)-+-(1,5)-+-(2,5)-+-(3,5)-+-(4,5)-+ +-( 25)-+-( 26)-+-( 27)-+-( 28)-+-( 29)-+
| | | | | | | | | | | |
(0,4) (1,4) (2,4) (3,4) (4,4) (5,4) ( 59) ( 60) ( 61) ( 62) ( 63) ( 64)
| | | | | | | | | | | |
+-(0,4)-+-(1,4)-+-(2,4)-+-(3,4)-+-(4,4)-+ +-( 20)-+-( 21)-+-( 22)-+-( 23)-+-( 24)-+
| | | | | | | | | | | |
(0,3) (1,3) (2,3) (3,3) (4,3) (5,3) ( 53) ( 54) ( 55) ( 56) ( 57) ( 58)
| | | | | | | | | | | |
+-(0,3)-+-(1,3)-+-(2,3)-+-(3,3)-+-(4,3)-+ +-( 15)-+-( 16)-+-( 17)-+-( 18)-+-( 19)-+
| | | | | | | | | | | |
(0,2) (1,2) (2,2) (3,2) (4,2) (5,2) ( 47) ( 48) ( 49) ( 50) ( 51) ( 52)
| | | | | | | | | | | |
+-(0,2)-+-(1,2)-+-(2,2)-+-(3,2)-+-(4,2)-+ +-( 10)-+-( 11)-+-( 12)-+-( 13)-+-( 14)-+
| | | | | | | | | | | |
(0,1) (1,1) (2,1) (3,1) (4,1) (5,1) ( 41) ( 42) ( 43) ( 44) ( 45) ( 46)
| | | | | | | | | | | |
+-(0,1)-+-(1,1)-+-(2,1)-+-(3,1)-+-(4,1)-+ +-( 5 )-+-( 6 )-+-( 7 )-+-( 8 )-+-( 9 )-+
| | | | | | | | | | | |
(0,0) (1,0) (2,0) (3,0) (4,0) (5,0) ( 35) ( 36) ( 37) ( 38) ( 39) ( 40)
| | | | | | | | | | | |
+-(0,0)-+-(1,0)-+-(2,0)-+-(3,0)-+-(4,0)-+ +-( 0 )-+-( 1 )-+-( 2 )-+-( 3 )-+-( 4 )-+
And indexing of vertexes looks as follows:
(0,5)--(1,5)--(2,5)--(3,5)--(4,5)--(5,5) ( 30)--( 31)--( 32)--( 33)--( 34)--( 35)
| | | | | | | | | | | |
(0,4)--(1,4)--(2,4)--(3,4)--(4,4)--(5,4) ( 24)--( 25)--( 26)--( 27)--( 28)--( 29)
| | | | | | | | | | | |
(0,3)--(1,3)--(2,3)--(3,3)--(4,3)--(5,3) ( 18)--( 19)--( 20)--( 21)--( 22)--( 23)
| | | | | | | | | | | |
(0,2)--(1,2)--(2,2)--(3,2)--(4,2)--(5,2) ( 12)--( 13)--( 14)--( 15)--( 16)--( 17)
| | | | | | | | | | | |
(0,1)--(1,1)--(2,1)--(3,1)--(4,1)--(5,1) ( 6)--( 7)--( 8)--( 9)--( 10)--( 11)
| | | | | | | | | | | |
(0,0)--(1,0)--(2,0)--(3,0)--(4,0)--(5,0) ( 0)--( 1)--( 2)--( 3)--( 4)--( 5)
Grid may have arbitrary dimension i.e. even higher than 3D. It is represented by the templated class TNL::Meshes::Grid which has the wollowing template parameters:
Dimension
is dimension of the grid. This can be any interger value greater than zero.
Real
is a precision of the arithmetics used by the grid. It is double
by default.
Device
is the device where the grid shall be allocated. Currently it can be either TNL::Devices::Host for CPU or TNL::Devices::Cuda for CUDA supporting GPUs. It is TNL::Devices::Host by default.
Index
is a type being used for indexing. It is int
by default.
Grid creation
The grid is defined by its dimension, domain covered by the grid and its resolution. The following example shows how to create a grid:
2#include <TNL/Meshes/Grid.h>
4int main(
int argc,
char* argv[] )
7 grid_1D.setDomain( {0.0}, {1.0} );
11 grid_2D.setDomain( {0.0, 0.0}, {1.0,2.0});
15 grid_3D.setDomain( {0.0, 0.0, 0.0}, {1.0, 2.0, 3.0} );
Orthogonal n-dimensional grid.
Definition Grid.h:33
Here we create set of grids with different dimension. For each grid we set different resolution along each axis (using the constructor of the grid) and different length along each axis (by calling method TNL::Meshes::Grid::setDomain).
The result looks as follows:
| Dimensions: [ 10 ] |
| Origin: [ 0 ] |
| Proportions: [ 1 ] |
| Space steps: [ 0.1 ] |
| Entities count with basis [ 0 ]: 11 |
| Entities count with basis [ 1 ]: 10 |
| Dimensions: [ 10, 20 ] |
| Origin: [ 0, 0 ] |
| Proportions: [ 1, 2 ] |
| Space steps: [ 0.1, 0.1 ] |
| Entities count with basis [ 0, 0 ]: 231 |
| Entities count with basis [ 1, 0 ]: 210 |
| Entities count with basis [ 0, 1 ]: 220 |
| Entities count with basis [ 1, 1 ]: 200 |
| Dimensions: [ 10, 20, 30 ] |
| Origin: [ 0, 0, 0 ] |
| Proportions: [ 1, 2, 3 ] |
| Space steps: [ 0.1, 0.1, 0.1 ] |
| Entities count with basis [ 0, 0, 0 ]: 7161 |
| Entities count with basis [ 1, 0, 0 ]: 6510 |
| Entities count with basis [ 0, 1, 0 ]: 6820 |
| Entities count with basis [ 0, 0, 1 ]: 6930 |
| Entities count with basis [ 1, 1, 0 ]: 6200 |
| Entities count with basis [ 1, 0, 1 ]: 6300 |
| Entities count with basis [ 0, 1, 1 ]: 6600 |
| Entities count with basis [ 1, 1, 1 ]: 6000 |
The following example shows creation of a grid independently on the grid dimension. The domain covered by the grid is \( [0,1]^d\) where \( d \) is the grid dimension. The resolution os the same along each axis. Tho code looks as follows:
2#include <TNL/Meshes/Grid.h>
4template<
int Dimension >
8 using CoordinatesType =
typename GridType::CoordinatesType;
10 CoordinatesType origin( 0.0 ), proportions( 1.0 );
11 grid.setDomain( origin, proportions );
16int main(
int argc,
char* argv[] )
The result looks as follows:
Creating grid with dimension equal one.
| Dimensions: [ 10 ] |
| Origin: [ 0 ] |
| Proportions: [ 1 ] |
| Space steps: [ 0.1 ] |
| Entities count with basis [ 0 ]: 11 |
| Entities count with basis [ 1 ]: 10 |
Creating grid with dimension equal two.
| Dimensions: [ 10, 10 ] |
| Origin: [ 0, 0 ] |
| Proportions: [ 1, 1 ] |
| Space steps: [ 0.1, 0.1 ] |
| Entities count with basis [ 0, 0 ]: 121 |
| Entities count with basis [ 1, 0 ]: 110 |
| Entities count with basis [ 0, 1 ]: 110 |
| Entities count with basis [ 1, 1 ]: 100 |
Creating grid with dimension equal three.
| Dimensions: [ 10, 10, 10 ] |
| Origin: [ 0, 0, 0 ] |
| Proportions: [ 1, 1, 1 ] |
| Space steps: [ 0.1, 0.1, 0.1 ] |
| Entities count with basis [ 0, 0, 0 ]: 1331 |
| Entities count with basis [ 1, 0, 0 ]: 1210 |
| Entities count with basis [ 0, 1, 0 ]: 1210 |
| Entities count with basis [ 0, 0, 1 ]: 1210 |
| Entities count with basis [ 1, 1, 0 ]: 1100 |
| Entities count with basis [ 1, 0, 1 ]: 1100 |
| Entities count with basis [ 0, 1, 1 ]: 1100 |
| Entities count with basis [ 1, 1, 1 ]: 1000 |
Creating grid with dimension equal four.
| Dimensions: [ 10, 10, 10, 10 ] |
| Origin: [ 0, 0, 0, 0 ] |
| Proportions: [ 1, 1, 1, 1 ] |
| Space steps: [ 0.1, 0.1, 0.1, 0.1 ] |
| Entities count with basis [ 0, 0, 0, 0 ]: 14641 |
| Entities count with basis [ 1, 0, 0, 0 ]: 13310 |
| Entities count with basis [ 0, 1, 0, 0 ]: 13310 |
| Entities count with basis [ 0, 0, 1, 0 ]: 13310 |
| Entities count with basis [ 0, 0, 0, 1 ]: 13310 |
| Entities count with basis [ 1, 1, 0, 0 ]: 12100 |
| Entities count with basis [ 1, 0, 1, 0 ]: 12100 |
| Entities count with basis [ 1, 0, 0, 1 ]: 12100 |
| Entities count with basis [ 0, 1, 1, 0 ]: 12100 |
| Entities count with basis [ 0, 1, 0, 1 ]: 12100 |
| Entities count with basis [ 0, 0, 1, 1 ]: 12100 |
| Entities count with basis [ 1, 1, 1, 0 ]: 11000 |
| Entities count with basis [ 1, 1, 0, 1 ]: 11000 |
| Entities count with basis [ 1, 0, 1, 1 ]: 11000 |
| Entities count with basis [ 0, 1, 1, 1 ]: 11000 |
| Entities count with basis [ 1, 1, 1, 1 ]: 10000 |
Traversing the grid
The grid does not store any data it only provides only indexing of the grid entities. The indexes then serve for accessing data stored in an array or vector. The grid entities may be traversed in parallel as we show in the following example:
3#include <TNL/Meshes/Grid.h>
4#include <TNL/Containers/Vector.h>
6template<
typename Device >
12 static constexpr int Dimension = 2;
13 const int grid_size = 5;
19 using CoordinatesType =
typename GridType::CoordinatesType;
20 using PointType =
typename GridType::PointType;
26 using GridCell =
typename GridType::Cell;
27 using GridFace =
typename GridType::Face;
28 using GridVertex =
typename GridType::Vertex;
33 GridType grid( grid_size );
34 PointType origin( 0.0 ), proportions( 1.0 );
35 grid.setDomain( origin, proportions );
40 VectorType cells( grid.template getEntitiesCount< Dimension >(), 0.0 );
41 VectorType faces( grid.template getEntitiesCount< Dimension - 1 >(), 0.0 );
42 VectorType vertexes( grid.template getEntitiesCount< 0 >(), 0.0 );
48 auto cells_view = cells.getView();
49 auto faces_view = faces.getView();
50 auto vertexes_view = vertexes.getView();
55 grid.template forAllEntities< Dimension >( [=]
__cuda_callable__ (
const GridCell& cell )
mutable {
56 cells_view[ cell.getIndex() ] = cell.getIndex();
63 for(
int i = grid_size-1; i>= 0; i-- ) {
64 for(
int j = 0; j < grid_size; j++ ) {
65 GridCell cell( grid, {j, i} );
66 auto idx = cell.getIndex();
76 grid.template forAllEntities< Dimension - 1 >( [=]
__cuda_callable__ (
const GridFace& face )
mutable {
77 const CoordinatesType normal = face.getNormals();
80 if( TNL::all(greaterEqual( face.getCoordinates() - normal, 0 )) ) {
81 auto neighbour = face.template getNeighbourEntity< Dimension >( -normal );
82 sum += cells_view[ neighbour.getIndex() ];
85 if( TNL::all(less( face.getCoordinates(), face.getGrid().getDimensions() )) ) {
86 auto neighbour = face.template getNeighbourEntity< Dimension >( { 0, 0 } );
87 sum += cells_view[ neighbour.getIndex() ];
90 faces_view[ face.getIndex() ] = sum /
count;
97 for(
int i = grid_size; i>= 0; i-- ) {
99 for(
int j = 0; j < grid_size; j++ ) {
100 GridFace face( grid, {j, i}, {0,1} );
101 auto idx = face.getIndex();
106 for(
int j = 0; j <= grid_size; j++ ) {
107 GridFace face( grid, {j, i - 1}, { 1,0 } );
108 auto idx = face.getIndex();
117 grid.template forAllEntities< 0 >( [=]
__cuda_callable__ (
const GridVertex& vertex )
mutable {
120 auto grid_dimensions = vertex.getGrid().getDimensions();
121 if( vertex.getCoordinates().x() > 0 && vertex.getCoordinates().y() > 0 ) {
122 auto neighbour = vertex.template getNeighbourEntity< Dimension >( { -1,-1 } );
123 sum += cells_view[ neighbour.getIndex() ];
126 if( vertex.getCoordinates().x() > 0 && vertex.getCoordinates().y() < grid_dimensions.y() ) {
127 auto neighbour = vertex.template getNeighbourEntity< Dimension >( { -1,0 } );
128 sum += cells_view[ neighbour.getIndex() ];
131 if( vertex.getCoordinates().x() < grid_dimensions.x() && vertex.getCoordinates().y() > 0 ) {
132 auto neighbour = vertex.template getNeighbourEntity< Dimension >( { 0,-1 } );
133 sum += cells_view[ neighbour.getIndex() ];
136 if( TNL::all(less( vertex.getCoordinates(), vertex.getGrid().getDimensions() )) ) {
137 auto neighbour = vertex.template getNeighbourEntity< Dimension >( {0,0} );
138 sum += cells_view[ neighbour.getIndex() ];
141 vertexes_view[ vertex.getIndex() ] = sum /
count;
148 for(
int i = grid_size; i>= 0; i-- ) {
149 for(
int j = 0; j <= grid_size; j++ ) {
150 GridVertex vertex( grid, {j, i} );
151 auto idx = vertex.getIndex();
158int main(
int argc,
char* argv[] )
161 traverseGrid< TNL::Devices::Host >();
165 traverseGrid< TNL::Devices::Cuda >();
#define __cuda_callable__
Definition CudaCallable.h:22
Vector extends Array with algebraic operations.
Definition Vector.h:39
In this example we start with writting an index of each cell into the cell. Next, we fill each face with average number computed from the neighbour cells and at the end, we do the same with vertices. We also write values stored in particular grid entities to the console.
The whoel example consits of the following steps:
- Setting dimension and resoltion of the grid (lines 12 and 13).
- We define necessary types which we will need later. It is the grid type (
GridType
on line 18), type for coordinates of the grid entities ( CoordinatesType
line 19), type for the real-world coordinates (PointType
on lines 20) and type of container for storing the values of particular grid entities (VectorType
on line 21).
- We defiene types of the following grid entities - cell (
GridCell
, line 26), face (GridFace
, line 27) and vertex (GridVertex
, line 28).
- We create an instance of the grid (lines 33-35). The resolution of the grid, which equals 5x5, is set by the grid constructor. The domain covered by the grid is given by points
origin
and proportions
(defined on the line 34) which are passed to the method TNL::Meshes::Grid::setDomain (line 35).
- Next we allocate vectors for storing of values in particular grid entities (lines 40-42). The number of grid entities are given by templated method TNL::Meshes::Grid::getEntitiesCount. The template parameter defines dimension of the grid entities the number of which we are asking for.
- In the next step, we prepare vector views (
cells_view
, faces_view
and vertexes_view
, lines 48-50) which we will need later in lambda functions.
- On the lines 55-57, we iterate over all grid cells using templated method TNL::Meshes::Grid::forAllEntities. The template parameter again says dimension of the grid entities we want to iterate over. The method takes one parameter which is a lambda function that is supposed to be evaluated for each cell. The lamda function receives one parameter, type of which is TNL::Meshes::GridEntity. This grid entity represents particular cells over which we iterate. The index of the cell is obtained by method TNL::Meshes::GridEntity::getIndex.
- Next we print the values of all cells. This must be done sequentially on the CPU and tehrefore we do not use parallal for (TNL::Meshes::Grid::forAllEntities) anymore. Now we iterate over all cells sequentialy row by row (for loops on lines 63 and 64). We create grid cell with given coordinates (line 65) and we ask for its global index (line 66) which we use for acces to the vector with cell values (
cell
). The result of this is a matrix of cell values printed on a console.
- On the lines (76-91), we iterate over all faces of the grid. Again we use the method TNL::Meshes::Grid::forAllEntities but now the template parameter telling the dimension of the entites is dimensions of the grid minus one (
Dimension-1
). The lambda function being performed for each face now gets one parameter which is a grid entity (TNL::Meshes::GridEntity) with dimensions equal to one. First of all we fetch the normal vector of the face (line 77) by calling a method TNL::Meshes::GridEntity::getNormals which in case of faces is realy a normal to the face (there is no more than one orthogonal normal to the face in the space having the same dimension as the grid). For horizontal faces, the normal is \(n_h=(0,1)\), and for vertical faces, the normal is \(n_v=(1,0)\). Note that if the resolution of the grid is \((N_x,N_y)\) then the number of horizontal faces along \(x\) and \(y\) axes is \((N_x,N_y+1)=(N_x,N_y)+n_h\) and the number of vertical faces along \(x\) and \(y\) axes is \((N_x+1,N_y)=(N_x,N_y)+n_v\). To compute the average number of values of the neighbour cells we need to get value from the cell in the direction opposite to the face normal. We first check if there is such a cell (if statement on the line 80) and if it is the case we fetch its global index (line 81), add its value to the sum
(line 82) and then we increase variable count
which is the number off values that contrtibuted to the average (line 83). Next we have to get value from the cell having the same coordinates as the face itself. We first check if there is such a cell (line 85) - note that the number of faces can be higher than the number of cells along the \(x\) axis for vertical faces and along \(y\) axis for horizontal faces. If there is such neighbour cell we fatch its index (line 86), add its value to variable sum
(line 87) and increase variable count
(line 88). Finally we compute the average value of the neighbout cells and store in the vector with values of faces at the position given by the global index of the current face (line 90).
- Next we print the values of the faces on the console. Line by line, we print first horizontal faces with row index equal five, followed by vertical faces with row index equal five, next horizontal faces with row index four and so on. As before, this must be done sequentially on the CPU so we do not use parallel for (TNL::Meshes::Grid::forAllEntities). So we iterate over all rows of the grid (line 97) and for each row we first print the horizontal faces (lines 99-103) and then the vertical ones (lines 106-110). Note that in both cases we create instance of grid face (lines 100 and 107) where the last parameter of the constructor defines the orientatio of the face -
{0,1}
is normal of horizontal faces (line 100) and {1,0}
is normal of vertical faces.
- Finally, we iterate over all vertexes and compute average value of all neghbouring cells. The vertexes have no orientation so we do not need to care the normals. We only check the number of neighbour cells based on the vertex coordinates. To iterate over all vertexes in parallel we use the method TNL::Meshes::Grid::forAllEntities with entity dimension set to zero (line 117). The lambda function, we perform on each vertex, provides us parameter
vertex
which represents the vertex that we currently operate on. We just fetch the coordinates of the vertex (line 120) and then we check what are the neighbour cells (if statements on lines 121, 126, 131 and 136). For each such a cell we add its value to variable sum
. Finaly we compute the average value and store it in the vertex (line 141).
- At the end we print values of all vertexes the same way as we did it with cells (lines 148-155).
The result looks as follows:
Traversing grid on CPU...
Values of cells ....
20 21 22 23 24
15 16 17 18 19
10 11 12 13 14
5 6 7 8 9
0 1 2 3 4
Values of faces ...
20 21 22 23 24
20 20.5 21.5 22.5 23.5 24
17.5 18.5 19.5 20.5 21.5
15 15.5 16.5 17.5 18.5 19
12.5 13.5 14.5 15.5 16.5
10 10.5 11.5 12.5 13.5 14
7.5 8.5 9.5 10.5 11.5
5 5.5 6.5 7.5 8.5 9
2.5 3.5 4.5 5.5 6.5
0 0.5 1.5 2.5 3.5 4
0 1 2 3 4
Values of vertexes ....
20 20.5 21.5 22.5 23.5 24
17.5 18 19 20 21 21.5
12.5 13 14 15 16 16.5
7.5 8 9 10 11 11.5
2.5 3 4 5 6 6.5
0 0.5 1.5 2.5 3.5 4
Traversing grid on CUDA GPU...
Values of cells ....
20 21 22 23 24
15 16 17 18 19
10 11 12 13 14
5 6 7 8 9
0 1 2 3 4
Values of faces ...
20 21 22 23 24
20 20.5 21.5 22.5 23.5 24
17.5 18.5 19.5 20.5 21.5
15 15.5 16.5 17.5 18.5 19
12.5 13.5 14.5 15.5 16.5
10 10.5 11.5 12.5 13.5 14
7.5 8.5 9.5 10.5 11.5
5 5.5 6.5 7.5 8.5 9
2.5 3.5 4.5 5.5 6.5
0 0.5 1.5 2.5 3.5 4
0 1 2 3 4
Values of vertexes ....
20 20.5 21.5 22.5 23.5 24
17.5 18 19 20 21 21.5
12.5 13 14 15 16 16.5
7.5 8 9 10 11 11.5
2.5 3 4 5 6 6.5
0 0.5 1.5 2.5 3.5 4
Writers
Writers help to export data linked with a grid to some of standart formats like VTK, VTI or Gnuplot. The following example shows the use of the grid writers:
3#include <TNL/Meshes/Grid.h>
4#include <TNL/Meshes/Writers/VTIWriter.h>
5#include <TNL/Meshes/Writers/VTKWriter.h>
6#include <TNL/Meshes/Writers/GnuplotWriter.h>
7#include <TNL/Containers/Vector.h>
9template<
typename Device >
15 static constexpr int Dimension = 2;
16 const int grid_size = 5;
22 using PointType =
typename GridType::PointType;
28 using GridCell =
typename GridType::Cell;
29 using GridVertex =
typename GridType::Vertex;
34 GridType grid( grid_size );
35 PointType origin( 0.0 ), proportions( 1.0 );
36 grid.setDomain( origin, proportions );
41 VectorType cells( grid.template getEntitiesCount< Dimension >(), 0.0 );
42 VectorType vertexes( grid.template getEntitiesCount< 0 >(), 0.0 );
48 auto cells_view = cells.getView();
49 auto vertexes_view = vertexes.getView();
54 grid.template forAllEntities< Dimension >( [=]
__cuda_callable__ (
const GridCell& cell )
mutable {
55 cells_view[ cell.getIndex() ] = cell.getIndex();
64 cells_file_vti.
open( cells_file_name_vti.getString(), std::ios::out );
66 cells_vti_writer.writeImageData( grid );
67 cells_vti_writer.writeCellData( cells,
"cell-values");
75 cells_file_vtk.
open( cells_file_name_vtk.getString(), std::ios::out );
77 cells_vtk_writer.writeEntities( grid );
78 cells_vtk_writer.writeCellData( cells,
"cell-values");
86 cells_file_gplt.
open( cells_file_name_gplt.getString(), std::ios::out );
88 cells_gplt_writer.writeEntities( grid );
89 cells_gplt_writer.writeCellData( grid, cells,
"cell-values");
94 grid.template forAllEntities< 0 >( [=]
__cuda_callable__ (
const GridVertex& vertex )
mutable {
97 auto grid_dimensions = vertex.getGrid().getDimensions();
98 if( vertex.getCoordinates().x() > 0 && vertex.getCoordinates().y() > 0 ) {
99 auto neighbour = vertex.template getNeighbourEntity< Dimension >( { -1,-1 } );
100 sum += cells_view[ neighbour.getIndex() ];
103 if( vertex.getCoordinates().x() > 0 && vertex.getCoordinates().y() < grid_dimensions.y() ) {
104 auto neighbour = vertex.template getNeighbourEntity< Dimension >( { -1,0 } );
105 sum += cells_view[ neighbour.getIndex() ];
108 if( vertex.getCoordinates().x() < grid_dimensions.x() && vertex.getCoordinates().y() > 0 ) {
109 auto neighbour = vertex.template getNeighbourEntity< Dimension >( { 0,-1 } );
110 sum += cells_view[ neighbour.getIndex() ];
113 if( TNL::all(less( vertex.getCoordinates(), vertex.getGrid().getDimensions() )) ) {
114 auto neighbour = vertex.template getNeighbourEntity< Dimension >( {0,0} );
115 sum += cells_view[ neighbour.getIndex() ];
118 vertexes_view[ vertex.getIndex() ] = sum /
count;
127 vertexes_file_vti.
open( vertexes_file_name_vti.getString(), std::ios::out );
129 vertexes_vti_writer.writeImageData( grid );
130 vertexes_vti_writer.writePointData( vertexes,
"vertexes-values" );
138 vertexes_file_vtk.
open( vertexes_file_name_vtk.getString(), std::ios::out );
140 vertexes_vtk_writer.writeEntities( grid );
141 vertexes_vtk_writer.writePointData( vertexes,
"vertexes-values" );
149 vertexes_file_gplt.
open( vertexes_file_name_gplt.getString(), std::ios::out );
151 vertexes_gplt_writer.writeEntities( grid );
152 vertexes_gplt_writer.writePointData( grid, vertexes,
"vertexes-values" );
155int main(
int argc,
char* argv[] )
158 writeGrid< TNL::Devices::Host >();
162 writeGrid< TNL::Devices::Cuda >();
Writer of data linked with meshes into Gnuplot format.
Definition GnuplotWriter.h:21
Writer of data linked with meshes into VTI format.
Definition VTIWriter.h:24
Writer of data linked with meshes into VTK format.
Definition VTKWriter.h:23
Class for managing strings.
Definition String.h:33
std::string getType()
Returns a human-readable string representation of given type.
Definition TypeInfo.h:75
It is a modification of the previous example. As before, we first set values linked with the grid cells and vertexes and then we write the into output files. The values linked with cells are exported to VTI format on the lines 63-69, to VTK format on the lines 74-80 and the Gnuplot format on lines. The writers have the same interface. They have constructors which require output stream as a parameter (TNL::Meshes::Writers::VTIWriter::VTIWriter, TNL::Meshes::Writers::VTKWriter::VTKWriter ). Next we call a method writeEntities
(TNL::Meshes::Writers::VTIWriter::writeEntities, TNL::Meshes::Writers::VTKWriter::writeEntities) which exports the grid entities to the file. In the case of the Gnuplot format, this method just writes simple header to the file and does not need to be called (the method is mainly for the compatibility with other writers). Finaly we may export data linked with the grid cells using a method writeCellData
(TNL::Meshes::Writers::VTIWriter::writeCellData, TNL::Meshes::Writers::VTKWriter::writeCellData).
In the same way, we can export data linked with vertexes (line 125-152).