Skip to content

Commit

Permalink
Add OMEGA data types (E3SM-Project#19)
Browse files Browse the repository at this point in the history
* 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
philipwjones authored and grnydawn committed Jun 23, 2023
1 parent 70f10a5 commit 00bf971
Show file tree
Hide file tree
Showing 5 changed files with 1,218 additions and 0 deletions.
52 changes: 52 additions & 0 deletions components/omega/doc/devGuide/DataTypes.md
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.

2 changes: 2 additions & 0 deletions components/omega/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ Development is taking place at https://github.com/E3SM-Project/Omega.
:maxdepth: 2
userGuide/QuickStart
userGuide/DataTypes
```

```{toctree}
:caption: Developer's guide
:maxdepth: 2
devGuide/QuickStart
devGuide/DataTypes
devGuide/CondaEnv
devGuide/Docs
devGuide/BuildDocs
Expand Down
14 changes: 14 additions & 0 deletions components/omega/doc/userGuide/DataTypes.md
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.

97 changes: 97 additions & 0 deletions components/omega/src/base/DataTypes.h
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
Loading

0 comments on commit 00bf971

Please sign in to comment.