pystencils.grids.protocols.IField#
- class pystencils.grids.protocols.IField(*args, **kwargs)#
Interface for algebraic fields to the pystencils code generator.
Algebraic fields in pystencils are functions
(1)#\[f: I \to \mathcal{D}\]from an index space \(I \subset \mathbb{Z}^{k}\) to some domain \(\mathcal{D}\). The dimensionality \(k\) is the field’s spatial rank (or just rank). In code generation, fields are backed by \(m\)-dimensional memory buffers (where \(m \ge k\)). The
IFieldprotocol defines the interface any algebraic field type must define to communicate its memory properties to the code generator.Each algebraic field type must provide the following information to the code generator:
its
name;its memory data type (
dtype);its buffer specification defining the required memory properties of the field’s underlying buffers;
its iteration limits defining the valid index space for a kernel’s spatial iteration.
Universal Buffer Model and Indexing Rules
At runtime, pystencils fields are backed by contiguous, linearized memory buffers. Between the algebraic front-end, the code generator, and any runtime system, the indexing semantics of these buffers are governed by the following universal buffer model (see also Fig. 1).
An m-dimensional buffer of element type
Tis a contiguous memory region of sizeB = allocShape[0] * ... * allocShape[m-1] * sizeof(T)
bytes.
The buffer’s memory is linearized according to the linearization strides
(strides[0], ..., strides[m- 1]).The buffer is split into an inner region and a padding region. The inner region has the format
shape[0], ..., shape[m- 1], and is embedded at an offset(offset[0], ..., offset[m- 1]).The buffer’s base pointer identifies the first entry of the inner region. The memory address of buffer element
(i[0], ..., i[m-1])is calculated as in Lst. 1:addr = base_ptr + strides[0] * i[0] + strides[1] * i[1] + ... + strides[m-1] * i[m-1]
This has a few consequences:
The first entry of the inner region always has buffer index
(0, ..., 0)The inner region is covered exactly by the indices
(0 : shape[0] - 1, 0 : shape[1] - 1, ..., 0 : shape[m- 1] - 1)The padding region is accessed by negative indices, and indices with
i[k] >= shape[k]
Fig. 1 Universal buffer model for pystencils fields. Properties modelled by
FieldBufferSpecare shown in bold; hidden properties are printed thin.#The universal buffer model is realized by the
IFieldprotocol viaget_buffer_spec. TheFieldBufferSpecinstance returned byget_buffer_specdefines the buffer’s data typeT; (the name of) its base pointer; as well as its inner region shape and its strides as constants or symbols. These properties are printed bold in Fig. 1. Base pointer and strides are used by the backend for index calculations (Lst. 1), while the shape may be used to define the iteration space.Field Access to Buffer Indices
The rules for how algebraic field accesses are translated into buffer indices, and how the buffer is split into inner and padding regions for a given field, depend on the field class.
TensorField, for instance, allows the presence of ghost layers which it maps into the padding region.NumPy Arrays as Buffers
NumPy and its sister libraries (CuPy, DPNP) are the prime runtime environments for pystencils, and their
ndarrayclasses the foremost implementation of field buffers. However,ndarraydoes not implement the universal buffer protocol, as it does not differentiate between the inner and padding regions.When creating an
ndarrayfor a given field, that array must have shape(allocShape[0], ..., allocShape[m-1]); but when passing it to a kernel, its base pointer must be extracted from the correct offset. These two aspects of array handling are realized by fields implementing the following protocols:CreateNdArray.create_ndarray: Gets the underlying array module and the required spatial shape; must create and return anndarrayof the given module to hold the data for the field. The spatial shape is the shape of the inner region of the field’s index space \(I\) (see (1)). For instance,TensorField.create_ndarray(xp, spatial_shape)will create an array of shape(spatial_shape[0] + 2 * ghost_layers, ...) + tensor_shapeto accomodate its ghost layers, while also setting up the array’s strides to match its memory layout.create_ndarrayis primarily used by thePatchDataclass to allocate its arrays.ViewNdArray.view_ndarray: Gets anndarrayinstance backing the field, and must return a view into the inner region of that array. For instance,TensorField.view_ndarray(arr)will returnarr[ghost_layers:-ghost_layers, ..., 0, ..., 0], cutting of its ghost layers in the spatial buffer dimensions.
- property dtype: PsType | DynamicType#
Data type of the field’s elements
- get_buffer_spec()#
Return the buffer specification defining the field’s memory properties
- Return type:
- get_iteration_limits()#
Return the iteration limits for kernels operating on this field
- Return type: