Working with grids
PencilArrays.jl includes functionality for conveniently working with the coordinates associated to a multidimensional domain. For this, the localgrid
function can be used to construct an object describing the grid coordinates associated to the local MPI process. This object can be used to easily and efficiently perform operations that depend on the local coordinates.
Creating local grids
As an example, say we are performing a 3D simulation on a rectilinear grid, so that the coordinates of a grid point are given by $\bm{x}_{ijk} = (x_i, y_j, z_k)$ where x
, y
and z
are separate one-dimensional arrays. For instance:
Nx, Ny, Nz = 65, 17, 21
xs = range(0, 1; length = Nx)
ys = range(-1, 1; length = Ny)
zs = range(0, 2; length = Nz)
Before continuing, let's create a domain decomposition configuration:
using MPI
using PencilArrays
MPI.Init()
comm = MPI.COMM_WORLD
pen = Pencil((Nx, Ny, Nz), comm)
Decomposition of 3D data
Data dimensions: (65, 17, 21)
Decomposed dimensions: (2, 3)
Data permutation: NoPermutation()
Array type: Array
Now, we can extract the local grid associated to the local MPI process:
grid = localgrid(pen, (xs, ys, zs))
LocalRectilinearGrid{3} with coordinates:
(1) 0.0:0.015625:1.0
(2) -1.0:0.125:1.0
(3) 0.0:0.1:2.0
Note that this example was run on a single MPI process, which makes things somewhat less interesting, but the same applies to more processes. With more than one process, the local grid is a subset of the global grid defined by the coordinates (xs, ys, zs)
.
Using local grids
The grid
object just created can be used to operate with PencilArray
s. In particular, say we want to initialise a PencilArray
to a function that depends on the domain coordinates, $u(x, y, z) = x + 2y + z^2$. This can be easily done using the broadcasting syntax (here we use the @.
macro for convenience):
u = PencilArray{Float64}(undef, pen) # construct PencilArray first
@. u = grid.x + 2 * grid.y + grid.z^2
Here, grid.x
, grid.y
and grid.z
are a convenient way of extracting the three components of the grid. Alternatively, one can use the syntax grid[1]
, grid[2]
, etc..., which is in particularly useful when working in dimensions higher than 3.
Note that one could do the same as above using indexing instead of broadcasting:
for I ∈ eachindex(grid)
x, y, z = grid[I]
u[I] = x + 2y + z^2
end
Library
PencilArrays.LocalGrids.AbstractLocalGrid
— TypeAbstractLocalGrid{N, Perm <: AbstractPermutation}
Abstract type specifying the local portion of an N
-dimensional grid.
PencilArrays.LocalGrids.LocalRectilinearGrid
— TypeLocalRectilinearGrid{N, Perm} <: AbstractLocalGrid{N, Perm}
Defines the local portion of a rectilinear grid in N
dimensions.
A rectilinear grid is represented by a set of orthogonal coordinates (x, y, z, ...)
.
PencilArrays.LocalGrids.localgrid
— Functionlocalgrid(x::PencilArray, args...)
Equivalent of localgrid(pencil(x), args...)
.
localgrid((xs, ys, ...), perm = NoPermutation()) -> LocalRectilinearGrid
Create a LocalRectilinearGrid
from a set of orthogonal coordinates (xs, ys, ...)
, where each element is an AbstractVector
.
Optionally, one can pass a static permutation (as in Permutation(2, 1, 3)
) to change the order in which the coordinates are iterated.
localgrid(p::Pencil, (x_global, y_global, ...)) -> LocalRectilinearGrid
localgrid(u::PencilArray, (x_global, y_global, ...)) -> LocalRectilinearGrid
Create a LocalRectilinearGrid
from a decomposition configuration and from a set of orthogonal global coordinates (x_global, y_global, ...)
.
In this case, each *_global
is an AbstractVector
describing the coordinates along one dimension of the global grid.
PencilArrays.LocalGrids.components
— FunctionLocalGrids.components(g::LocalRectilinearGrid) -> (xs, ys, zs, ...)
Get coordinates associated to the current MPI process.