SpatialOps
Basics of field creation

Goal of this example

This example will show how to create a field in SpatialOps

Key Concepts

  1. A SpatialField is comprised of a few things:

    • A MemoryWindow object describes the logical layout of the field in memory. Among other things, a window contains a description of the domain size.
    • A BoundaryCellInfo object describes the behavior of a field at a boundary. For face fields on structured meshes, the (+) face on the side of the domain has an extra storage location. We will explore this more later.
    • A GhostData object describes the number of ghost cells on each face of the domain. These ghost cells are used to exchange data between patches on different nodes and for stencil calculations. We will explore this more later.
    • A pointer to the raw block of memory for the field and its StorageMode (ExternalStorage or InternalStorage) This can either be supplied (for externally managed memory) or it will be created internally. For internally created fields, the supplied memory block will be ignored and can be NULL.
    • The location of the field (CPU, GPU, etc.). Fields can be created on a CPU, GPU, etc. and moved between these devices. In fact, a field can be on multiple devices at once.

    For now, don't worry about these details - they will be covered in more detail in later examples.

  2. A SpatialField is strongly typed. There are several supported field types defined for fields associated with structured meshes listed here. This will also be explored more in later examples.
  3. The SpatialFieldStore can be used to quickly build fields. It returns SpatFldPtr objects that have pointer semantics and are reference-counted.

Example Code

examples/field_creation.cpp

#include <spatialops/structured/FVStaggered.h> // everything required to build fields on structured meshes
using namespace SpatialOps;
// If we are compiling with GPU CUDA support, create fields on the device.
// Otherwise, create them on the host.
#ifdef ENABLE_CUDA
# define LOCATION GPU_INDEX
#else
# define LOCATION CPU_INDEX
#endif
int main()
{
// SVolField = Scalar Volume Field (non-staggered, cell-centered field)
typedef SVolField FieldT;
//----------------------------------------------------------------------------
// Use default values to create objects required to build a field:
// Ghost cells are needed by some applications and operations
// In general, set ghost cells to zero, unless they are needed:
const GhostData nghost(0);
// Determine if we have physical boundaries present on each right/positive (+) face.
const bool bcx=true, bcy=true, bcz=true;
const IntVec bc(bcx,bcy,bcz);
const BoundaryCellInfo bcInfo = BoundaryCellInfo::build<FieldT>( bc, bc );
// Define the size of the field (nx,ny,nz)
const IntVec fieldDim( 10, 9, 8 );
// Construct a memory window (logical extents of a field) from dimensions,
// ghost cell data, and boundary cell information
const MemoryWindow window( get_window_with_ghost( fieldDim, nghost, bcInfo ) );
//----------------------------------------------------------------------------
// Create a field from scratch
// parameters:
// window : logical extents for the field
// bcInfo : boundary cell information for the field
// nghost : ghost cell data for the field
// NULL : externally allocated memory (not needed here; hence, NULL)
// InternalStorage : internally manage memory (could also be ExternalStorage)
// LOCATION : CPU or GPU memory
FieldT f( window, bcInfo, nghost, NULL, InternalStorage, LOCATION );
//----------------------------------------------------------------------------
// Create a field from a prototype using the "SpatialFieldStore." SpatFldPtr has
// regular pointer semantics but is a reference-counted pointer.
SpatFldPtr<FieldT> f2 = SpatialFieldStore::get<FieldT>(f); // field with same layout as "f"
return 0;
}