forked from E3SM-Project/Omega
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add OMEGA data types (E3SM-Project#19)
* add OMEGA data types and YAKL arrays - includes source header defining all supported OMEGA data types - includes user and developer documentation sections - includes a unit test that tests both the expected size of standard types and the creation of YAKL host and device arrays - doxygen comments have been added - minor changes were made after review and linter results
- Loading branch information
1 parent
70f10a5
commit 00bf971
Showing
5 changed files
with
1,218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
(omega-dev-data-types)= | ||
|
||
## Data Types and Precision | ||
|
||
OMEGA supports all standard data types and uses some additional defined | ||
types to guarantee a specific level of precision. In particular, we | ||
define I4, I8, R4 and R8 types for 4-byte (32-bit) and 8-byte (64-bit) | ||
integer and floating point variables. Note that these exist in the | ||
OMEGA namespace so use the scoped form OMEGA::I4, etc. | ||
In addition, we define a Real data type that is, by default, | ||
double precision (8 bytes/64-bit) but if the code is built with a | ||
`-DSINGLE_PRECISION` (see insert link to build system) preprocessor flag, | ||
the default Real becomes single precision (4-byte/32-bit). For floating | ||
point variables, developers should use this Real type instead of the | ||
specific R4 or R8 forms unless the specific form is required | ||
(eg converting to single precision before output or if a particular | ||
algorithm is known to require double precision). This allows us to | ||
easily convert all reals to single precision to explore performance or | ||
accuracy in single precision mode. | ||
|
||
## Arrays and YAKL | ||
|
||
The C++ language does not have native support for multi-dimensional | ||
arrays as part of the language standard, though there are a number | ||
of implementations as part of the Standard Template Library and | ||
elsewhere. OMEGA uses the [YAKL](https://github.com/mrnorman/YAKL) | ||
framework for defining and allocating arrays on both the CPU host and | ||
any accelerator device that may be present. Because the syntax for | ||
defining such arrays is somewhat long, we instead define a number of | ||
alias array types of the form `ArrayNDTT` where N is the dimension of | ||
the array and TT is the data type (I4, I8, R4, R8 or Real) corresponding | ||
to the types described above. The dimension refers to the number of | ||
ranks in the array and not the physical dimension. Although YAKL | ||
supports Fortran ordering, we will use C ordering for array indices. | ||
Within OMEGA the default location for an Array should be on the device | ||
with a similar type ArrayHostNDTT defined for arrays needed on the host. | ||
As an example, we can define and allocate a device and host array using: | ||
```c++ | ||
Array3dReal Temperature("Temperature",nTimeLevels, nCells, nVertLevels); | ||
ArrayHost3dReal TemperatureHost("Temperature",nTimeLevels, nCells, nVertLevels); | ||
``` | ||
Alternatively, you can use the copy functions to create a host copy | ||
from the device or vice versa. | ||
```c++ | ||
auto TemperatureHost = Temperature.createHostCopy(); | ||
``` | ||
Finally, the arrays can be deallocated explicity using the class | ||
deallocate method, eg `Temperature.deallocate();` or if they are local | ||
to a routine, they will be automatically deallocated when they fall out | ||
of scope on exit. More details on YAKL arrays are available in the YAKL | ||
documentation. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
(omega-user-data-types)= | ||
|
||
## Data Types and Precision | ||
|
||
OMEGA supports all standard data types and uses some specific defined | ||
types to guarantee a specific level of precision. There is only one | ||
user-configurable option for precision. When a specific floating point | ||
precision is not required, we use a Real data type that is, by default, | ||
double precision (8 bytes/64-bit) but if the code is built with a | ||
`-DSINGLE_PRECISION` (see insert link to build system) preprocessor flag, | ||
the default Real becomes single precision (4-byte/32-bit). Users are | ||
encouraged to use the default double precision unless exploring the | ||
performance or accuracy characteristics of single precision. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#ifndef OMEGA_DATA_TYPES_H | ||
#define OMEGA_DATA_TYPES_H | ||
//===-- base/DataTypes.h - data type and array definitions ------*- C++ -*-===// | ||
// | ||
/// \file | ||
/// \brief Defines standard data types and YAKL array aliases | ||
/// | ||
/// This header defines fixed-length data types to enforce levels of precision | ||
/// where needed. In addition, it supplies a generic real type that is double | ||
/// precision by default but can be switched throughout using a preprocessor | ||
/// definition SINGLE_PRECISION. Finally, all arrays in OMEGA are defined | ||
/// as YAKL arrays to enable allocation and kernel launching on accelerator | ||
/// devices. Because the YAKL definitions can be lengthy, this header defines | ||
/// useful aliases for up to 5D arrays in all supported types on either the | ||
/// host or device. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "YAKL.h" | ||
#include <cstdint> | ||
|
||
namespace OMEGA { | ||
|
||
// Standard integer and floating point types | ||
using I4 = std::int32_t; ///< alias for 32-bit integer | ||
using I8 = std::int64_t; ///< alias for 64-bit integer | ||
using R4 = float; ///< alias for 32-bit (single prec) real | ||
using R8 = double; ///< alias for 64-bit (double prec) real | ||
|
||
/// generic real 64-bit (default) or 32-bit (if -DSINGLE_PRECISION used) | ||
#ifdef SINGLE_PRECISION | ||
using Real = float; | ||
#else | ||
using Real = double; | ||
#endif | ||
|
||
// Aliases for YAKL arrays - by default, all arrays are on the device and | ||
// use C-ordering. | ||
/// Aliases for YAKL device arrays of various dimensions and types | ||
using Array1DI4 = yakl::Array<I4, 1, yakl::memDevice, yakl::styleC>; | ||
using Array1DI8 = yakl::Array<I8, 1, yakl::memDevice, yakl::styleC>; | ||
using Array1DR4 = yakl::Array<R4, 1, yakl::memDevice, yakl::styleC>; | ||
using Array1DR8 = yakl::Array<R8, 1, yakl::memDevice, yakl::styleC>; | ||
using Array1DReal = yakl::Array<Real, 1, yakl::memDevice, yakl::styleC>; | ||
using Array2DI4 = yakl::Array<I4, 2, yakl::memDevice, yakl::styleC>; | ||
using Array2DI8 = yakl::Array<I8, 2, yakl::memDevice, yakl::styleC>; | ||
using Array2DR4 = yakl::Array<R4, 2, yakl::memDevice, yakl::styleC>; | ||
using Array2DR8 = yakl::Array<R8, 2, yakl::memDevice, yakl::styleC>; | ||
using Array2DReal = yakl::Array<Real, 2, yakl::memDevice, yakl::styleC>; | ||
using Array3DI4 = yakl::Array<I4, 3, yakl::memDevice, yakl::styleC>; | ||
using Array3DI8 = yakl::Array<I8, 3, yakl::memDevice, yakl::styleC>; | ||
using Array3DR4 = yakl::Array<R4, 3, yakl::memDevice, yakl::styleC>; | ||
using Array3DR8 = yakl::Array<R8, 3, yakl::memDevice, yakl::styleC>; | ||
using Array3DReal = yakl::Array<Real, 3, yakl::memDevice, yakl::styleC>; | ||
using Array4DI4 = yakl::Array<I4, 4, yakl::memDevice, yakl::styleC>; | ||
using Array4DI8 = yakl::Array<I8, 4, yakl::memDevice, yakl::styleC>; | ||
using Array4DR4 = yakl::Array<R4, 4, yakl::memDevice, yakl::styleC>; | ||
using Array4DR8 = yakl::Array<R8, 4, yakl::memDevice, yakl::styleC>; | ||
using Array4DReal = yakl::Array<Real, 4, yakl::memDevice, yakl::styleC>; | ||
using Array5DI4 = yakl::Array<I4, 5, yakl::memDevice, yakl::styleC>; | ||
using Array5DI8 = yakl::Array<I8, 5, yakl::memDevice, yakl::styleC>; | ||
using Array5DR4 = yakl::Array<R4, 5, yakl::memDevice, yakl::styleC>; | ||
using Array5DR8 = yakl::Array<R8, 5, yakl::memDevice, yakl::styleC>; | ||
using Array5DReal = yakl::Array<Real, 5, yakl::memDevice, yakl::styleC>; | ||
|
||
// Also need similar aliases for arrays on the host | ||
/// Aliases for YAKL host arrays of various dimensions and types | ||
using ArrayHost1DI4 = yakl::Array<I4, 1, yakl::memHost, yakl::styleC>; | ||
using ArrayHost1DI8 = yakl::Array<I8, 1, yakl::memHost, yakl::styleC>; | ||
using ArrayHost1DR4 = yakl::Array<R4, 1, yakl::memHost, yakl::styleC>; | ||
using ArrayHost1DR8 = yakl::Array<R8, 1, yakl::memHost, yakl::styleC>; | ||
using ArrayHost1DReal = yakl::Array<Real, 1, yakl::memHost, yakl::styleC>; | ||
using ArrayHost2DI4 = yakl::Array<I4, 2, yakl::memHost, yakl::styleC>; | ||
using ArrayHost2DI8 = yakl::Array<I8, 2, yakl::memHost, yakl::styleC>; | ||
using ArrayHost2DR4 = yakl::Array<R4, 2, yakl::memHost, yakl::styleC>; | ||
using ArrayHost2DR8 = yakl::Array<R8, 2, yakl::memHost, yakl::styleC>; | ||
using ArrayHost2DReal = yakl::Array<Real, 2, yakl::memHost, yakl::styleC>; | ||
using ArrayHost3DI4 = yakl::Array<I4, 3, yakl::memHost, yakl::styleC>; | ||
using ArrayHost3DI8 = yakl::Array<I8, 3, yakl::memHost, yakl::styleC>; | ||
using ArrayHost3DR4 = yakl::Array<R4, 3, yakl::memHost, yakl::styleC>; | ||
using ArrayHost3DR8 = yakl::Array<R8, 3, yakl::memHost, yakl::styleC>; | ||
using ArrayHost3DReal = yakl::Array<Real, 3, yakl::memHost, yakl::styleC>; | ||
using ArrayHost4DI4 = yakl::Array<I4, 4, yakl::memHost, yakl::styleC>; | ||
using ArrayHost4DI8 = yakl::Array<I8, 4, yakl::memHost, yakl::styleC>; | ||
using ArrayHost4DR4 = yakl::Array<R4, 4, yakl::memHost, yakl::styleC>; | ||
using ArrayHost4DR8 = yakl::Array<R8, 4, yakl::memHost, yakl::styleC>; | ||
using ArrayHost4DReal = yakl::Array<Real, 4, yakl::memHost, yakl::styleC>; | ||
using ArrayHost5DI4 = yakl::Array<I4, 5, yakl::memHost, yakl::styleC>; | ||
using ArrayHost5DI8 = yakl::Array<I8, 5, yakl::memHost, yakl::styleC>; | ||
using ArrayHost5DR4 = yakl::Array<R4, 5, yakl::memHost, yakl::styleC>; | ||
using ArrayHost5DR8 = yakl::Array<R8, 5, yakl::memHost, yakl::styleC>; | ||
using ArrayHost5DReal = yakl::Array<Real, 5, yakl::memHost, yakl::styleC>; | ||
|
||
} // end namespace OMEGA | ||
|
||
//===----------------------------------------------------------------------===// | ||
#endif |
Oops, something went wrong.