In this section, commonly-used construct types whose use may require specific explainations or recommendations are described.
In many instance data such as mesh connectivity requires managing a variable number of entries per data element. This is for example the case of faces → vertices connectivity. The average number of vertices per face is usually quite low, but the maximum number may be significantly higher, so using an array with regular stride would be very inefficient for some data sets.
A common solution to this problem is to use indexed arrays, in which an array containing data is supplemented by a second array containing the start indexes of entries in the data array for each element.
In C and C++ code, the natural indexing is zero-based, but one-based indexing may also be used for some arrays as a vestige of prior Fortran code, or for arrays using global numbers.
The recommendations are the following:
Let us consider an array array_data
indexed by a zero-based array_index
array. The values of array_data
associated with element *ie*, are the values ranging from indexes *istart = ie* included to *iend = ie+1* excluded (past-the-end index).
The number of values associated with *ie* is determined by: array_index[i_e+1] - array_index[i_e]
, whether the index is zero-based or one-based.
For an indexed array of n elements, the size the index array should thus be equal to n+1 (and not n as would be the case for regular 1-d or strided arrays), and the total size of array_data
is equal to array_index[n]
for a zero-based index, or array_index[n] - array_index[0]
in general.
Readers familiar with Compressed Sparse Row or similar matrix or graph representations may already have noted the similarity with the indexed arrays described here. In the case of CSR matrix structures, 2 data arrays are often associated with 1 row index: one array definining the column indices, and a second one defining the associated values.
This is in reality no different than using an indexed array as described here to define a faces → vertices connectivity, and also associating data (for example coordinates) to vertices.
In code_saturne, matrix non-diagonal terms usually correspond to cell faces, and the CSR matrix representation is very similar to that of a cells → faces connectivity, except for the fact that a standard CSR representation uses only "unsigned" column ids, whereas face numbers may be signed in the matching mesh representation so as to convey orientation (an alternative solution would be to use a separate array for orientation, in which case the similarity to CSR would be complete).
We illustrate the use of an indexed array to define a faces → vertices connectivity for a simple surface mesh:
In this example we use 0-based (0 to n-1) numbering, as in most uses of indexed arrays in code_saturne.
For mesh connectivities (adjacencies) that may be used across several functions, the cs_adjacency_t structure allows storing an manipulation indexed arrays.
In C++ code using the .cpp
extension, the cs_dispatch_context
class may be used to run code defined as C++ lambda functions in parallel. The corresponding code can be written in a portable manner, but executed using different runtimes, such as OpenMP or CUDA.
Examples are provided in the source tree, in
tests/cs_dispatch_test.cpp
src/alge/cs_benchmark.cpp
Note that this class should not be called from code with the .cxx
extension, as when using CUDA, that code will ve compiled using a different compiler, and using the class in both cases may confuse those compiler's avoidance of duplicating C++ template code instanciation.