Array wrappers
The PencilArrays
module defines types for handling MPI-distributed data.
The most important types are:
PencilArray
: array wrapper including MPI decomposition information. Takes local indices starting at 1, regardless of the location of each MPI process on the global topology.GlobalPencilArray
:PencilArray
wrapper that takes global indices, which generally don't start at 1. See also Global views.
Construction
An uninitialised PencilArray
can be constructed from a Pencil
instance as
pencil = Pencil(#= ... =#)
A = PencilArray{Float64}(undef, pencil)
parent(A) # returns the Array wrapped by `A`
This allocates a new Array
with the local dimensions and data type associated to the Pencil
.
One can also construct a PencilArray
wrapper from an existing AbstractArray
, whose dimensions must be compatible with the Pencil
configuration. For instance, the following works:
dims = size_local(pencil, MemoryOrder()) # dimensions must be in memory order!
data = zeros(dims)
A = PencilArray(pencil, data)
Note that data
does not need to be a Array
, but can be any subtype of AbstractArray
.
It is also possible to construct higher dimensional arrays, as in:
data = zeros(dims..., 3, 2)
A = PencilArray(pencil, data)
This will construct a PencilArray
where the rightmost dimensions (called extra dimensions in the PencilArrays API) will never be split among MPI processes.
Dimension permutations
Unlike the wrapped AbstractArray
, the PencilArray
wrapper takes indices in logical order. For instance, if the underlying permutation of the Pencil
is (2, 3, 1)
, then A[i, j, k]
points to the same value as parent(A)[j, k, i]
.
Global views
PencilArray
s are accessed using local indices that start at 1, regardless of the location of the subdomain associated to the local process on the global grid. Sometimes it may be more convenient to use global indices describing the position of the local process in the domain. For this, the global_view
function is provided that generates an OffsetArray
wrapper taking global indices.
For more details, see for instance the gradient example in the PencilFFTs docs.
Regular PencilArray
s have more functionality than global view wrappers. This includes broadcasting, which is currently not supported for global views. In general it should be preferred to work with PencilArray
s.
Types
PencilArrays.PencilArray
— TypePencilArray(pencil::Pencil, data::AbstractArray{T,N})
Create array wrapper with pencil decomposition information.
The array dimensions and element type must be consistent with those of the given pencil.
If the Pencil
has an associated index permutation, then data
must have its dimensions permuted accordingly (in memory order).
Unlike data
, the resulting PencilArray
should be accessed with unpermuted indices (in logical order).
Example
Suppose pencil
has local dimensions (10, 20, 30)
before permutation, and has an asociated permutation (2, 3, 1)
. Then:
data = zeros(20, 30, 10) # parent array (with dimensions in memory order)
u = PencilArray(pencil, data) # wrapper with dimensions (10, 20, 30)
@assert size_local(u) === (10, 20, 30)
u[15, 25, 5] # BoundsError (15 > 10 and 25 > 20)
u[5, 15, 25] # correct
parent(u)[15, 25, 5] # correct
The data array can have one or more extra dimensions to the right (slow indices), which are not affected by index permutations.
Example
dims = (20, 30, 10)
PencilArray(pencil, zeros(dims...)) # works (scalar)
PencilArray(pencil, zeros(dims..., 3)) # works (3-component vector)
PencilArray(pencil, zeros(dims..., 4, 3)) # works (4×3 tensor)
PencilArray(pencil, zeros(3, dims...)) # fails
PencilArray{T}(undef, pencil::Pencil, [extra_dims...])
Allocate an uninitialised PencilArray
that can hold data in the local pencil.
Extra dimensions, for instance representing vector components, can be specified. These dimensions are added to the rightmost (slowest) indices of the resulting array.
Example
Suppose pencil
has local dimensions (20, 10, 30)
. Then:
PencilArray{Float64}(undef, pencil) # array dimensions are (20, 10, 30)
PencilArray{Float64}(undef, pencil, 4, 3) # array dimensions are (20, 10, 30, 4, 3)
More examples:
julia> pen = Pencil((20, 10, 12), MPI.COMM_WORLD);
julia> u = PencilArray{Float64}(undef, pen);
julia> summary(u)
"20×10×12 PencilArray{Float64, 3}(::Pencil{3, 2, NoPermutation, Array})"
julia> PencilArray{Float64}(undef, pen, 4, 3) |> summary
"20×10×12×4×3 PencilArray{Float64, 5}(::Pencil{3, 2, NoPermutation, Array})"
PencilArrays.GlobalPencilArray
— TypeGlobalPencilArray{T,N} <: AbstractArray{T,N}
Alias for an OffsetArray
wrapping a PencilArray
.
Unlike PencilArray
s, GlobalPencilArray
s take global indices, which in general don't start at 1 for a given MPI process.
The global_view
function should be used to create a GlobalPencilArray
from a PencilArray
.
PencilArrays.PencilArrayCollection
— TypePencilArrayCollection
UnionAll
type describing a collection of PencilArray
s.
Such a collection can be a tuple or an array of PencilArray
s.
Collections are by assumption homogeneous: each array has the same properties, and in particular, is associated to the same Pencil
configuration.
For convenience, certain operations defined for PencilArray
are also defined for PencilArrayCollection
, and return the same value as for a single PencilArray
. Some examples are pencil
, range_local
and get_comm
.
Also note that functions from Base
, such as size
, ndims
and eltype
, are not overloaded for PencilArrayCollection
, since they already have a definition for tuples and arrays (and redefining them would be type piracy...).
PencilArrays.AbstractManyPencilArray
— TypeAbstractManyPencilArray{N,M}
Abstract type specifying a container holding M
different PencilArray
views to the same underlying.
All views share the same dimensionality N
. In principle, their element types can be different.
A concrete implementation, ManyPencilArray
, is proposed in which all arrays have the same element type T
.
PencilArrays.ManyPencilArray
— TypeManyPencilArray{T,N,M} <: AbstractManyPencilArray{N,M}
Container holding M
different PencilArray
views to the same underlying data buffer. All views share the same element type T
and dimensionality N
.
This can be used to perform in-place data transpositions with transpose!
.
ManyPencilArray{T}(undef, pencils...; extra_dims=())
Create a ManyPencilArray
container that can hold data of type T
associated to all the given Pencil
s.
The optional extra_dims
argument is the same as for PencilArray
.
Methods
PencilArray
PencilArrays.extra_dims
— Methodextra_dims(x::PencilArray)
extra_dims(x::PencilArrayCollection)
Return tuple with size of "extra" dimensions of PencilArray
.
PencilArrays.Pencils.MPITopologies.get_comm
— Methodget_comm(x::PencilArray)
get_comm(x::PencilArrayCollection)
Get MPI communicator associated to a pencil-distributed array.
PencilArrays.Permutations.permutation
— Functionpermutation(::Type{<:PencilArray})
permutation(x::PencilArray)
permutation(x::PencilArrayCollection)
Get index permutation associated to the given PencilArray
.
Returns NoPermutation()
if there is no associated permutation.
PencilArrays.global_view
— Methodglobal_view(x::PencilArray)
Create an OffsetArray
of a PencilArray
that takes global indices in logical order.
PencilArrays.ndims_extra
— Methodndims_extra(::Type{<:PencilArray})
ndims_extra(x::PencilArray)
ndims_extra(x::PencilArrayCollection)
Number of "extra" dimensions associated to PencilArray
.
These are the dimensions that are not associated to the domain geometry. For instance, they may correspond to vector or tensor components.
These dimensions correspond to the rightmost indices of the array.
The total number of dimensions of a PencilArray
is given by:
ndims(x) == ndims_space(x) + ndims_extra(x)
PencilArrays.ndims_space
— Methodndims_space(x::PencilArray)
ndims_space(x::PencilArrayCollection)
Number of dimensions associated to the domain geometry.
These dimensions correspond to the leftmost indices of the array.
The total number of dimensions of a PencilArray
is given by:
ndims(x) == ndims_space(x) + ndims_extra(x)
Base.parent
— Methodparent(x::PencilArray)
Return array wrapped by a PencilArray
.
PencilArrays.pencil
— Methodpencil(x::PencilArray)
Return decomposition configuration associated to a PencilArray
.
Base.pointer
— Methodpointer(x::PencilArray)
Return pointer to the start of the underlying data.
Use with caution: this may not make a lot of sense if the underlying data is not contiguous or strided (e.g. if the PencilArray
is wrapping a non-strided SubArray
).
PencilArrays.Pencils.range_local
— Methodrange_local(x::PencilArray, [order = LogicalOrder()])
range_local(x::PencilArrayCollection, [order = LogicalOrder()])
Local data range held by the PencilArray
.
By default the dimensions are returned in logical order.
PencilArrays.Pencils.range_remote
— Methodrange_remote(x::PencilArray, coords, [order = LogicalOrder()])
range_remote(x::PencilArrayCollection, coords, [order = LogicalOrder()])
Get data range held by the PencilArray
in a given MPI process.
The location of the MPI process in the topology is determined by the coords
argument, which can be given as a linear or Cartesian index.
See range_remote(::Pencil, ...)
variant for details.
Base.similar
— Methodsimilar(x::PencilArray, [element_type=eltype(x)], [dims]) -> PencilArray
Returns a PencilArray
similar to x
.
In particular, the new array shares the same parallel decomposition (the same Pencil
) than x
. This means that the dimensions of the new array must be the same as those of x
. Note that the optional dims
argument is allowed for the sole reason of making things work nicely with other packages (such as StructArrays.jl), but things will fail if dims ≠ size(x)
.
Examples
julia> pen = Pencil((20, 10, 12), MPI.COMM_WORLD);
julia> u = PencilArray{Float64}(undef, pen);
julia> similar(u) |> summary
"20×10×12 PencilArray{Float64, 3}(::Pencil{3, 2, NoPermutation, Array})"
julia> similar(u, size(u)) |> summary
"20×10×12 PencilArray{Float64, 3}(::Pencil{3, 2, NoPermutation, Array})"
julia> similar(u, ComplexF32) |> summary
"20×10×12 PencilArray{ComplexF32, 3}(::Pencil{3, 2, NoPermutation, Array})"
julia> similar(u, (4, 3, 8))
ERROR: DimensionMismatch: cannot construct a similar PencilArray with different size
julia> similar(u, (4, 3)) |> summary
ERROR: DimensionMismatch: cannot construct a similar PencilArray with different size
julia> similar(u, ComplexF32) |> summary
"20×10×12 PencilArray{ComplexF32, 3}(::Pencil{3, 2, NoPermutation, Array})"
julia> similar(u, ComplexF32, (4, 3))
ERROR: DimensionMismatch: cannot construct a similar PencilArray with different size
similar(x::PencilArray, [element_type = eltype(x)], p::Pencil)
Create a PencilArray
with the decomposition described by the given Pencil
.
This variant may be used to create a PencilArray
that has a different decomposition than the input PencilArray
.
Examples
julia> pen_u = Pencil((20, 10, 12), (2, 3), MPI.COMM_WORLD);
julia> u = PencilArray{Float64}(undef, pen_u);
julia> pen_v = Pencil(pen_u; decomp_dims = (1, 3), permute = Permutation(2, 3, 1))
Decomposition of 3D data
Data dimensions: (20, 10, 12)
Decomposed dimensions: (1, 3)
Data permutation: Permutation(2, 3, 1)
Array type: Array
julia> v = similar(u, pen_v);
julia> summary(v)
"20×10×12 PencilArray{Float64, 3}(::Pencil{3, 2, Permutation{(2, 3, 1), 3}, Array})"
julia> pencil(v) === pen_v
true
julia> vint = similar(u, Int, pen_v);
julia> summary(vint)
"20×10×12 PencilArray{Int64, 3}(::Pencil{3, 2, Permutation{(2, 3, 1), 3}, Array})"
julia> pencil(vint) === pen_v
true
similar(p::Pencil, [A = typeof_array(p)], [dims = size_global(p)])
Returns a Pencil
decomposition with global dimensions dims
and with underlying array type A
.
Typically, A
should be something like Array
or CuArray
(see Pencil
for details).
Base.length
— Methodlength(A::AbstractManyPencilArray)
Returns the number of PencilArray
s wrapped by A
.
length(x::PencilArray)
Get the local number of elements stored in the PencilArray
.
Equivalent to length_local(x)
.
PencilArrays.Pencils.length_local
— Methodlength_local(x::PencilArray)
Get linear length of the local data held by a PencilArray
.
PencilArrays.Pencils.length_global
— Methodlength_global(x::PencilArray)
Get linear length of the global data held by a PencilArray
.
Base.size
— Methodsize(x::PencilArray)
Return the local dimensions of a PencilArray
in logical order.
Defined as size_local(x, LogicalOrder())
.
PencilArrays.Pencils.size_local
— Methodsize_local(x::PencilArray, [order = LogicalOrder()])
size_local(x::PencilArrayCollection, [order = LogicalOrder()])
Local dimensions of the data held by the PencilArray
.
See also size_local(::Pencil)
.
PencilArrays.Pencils.size_global
— Methodsize_global(x::PencilArray, [order = LogicalOrder()])
size_global(x::PencilArrayCollection, [order = LogicalOrder()])
Global dimensions associated to the given array.
By default, the logical dimensions of the dataset are returned.
If order = LogicalOrder()
, this is the same as size(x)
.
See also size_global(::Pencil)
.
PencilArrays.sizeof_global
— Methodsizeof_global(x::PencilArray)
sizeof_global(x::PencilArrayCollection)
Global size of array in bytes.
PencilArrays.Pencils.topology
— Methodtopology(x::PencilArray)
topology(x::PencilArrayCollection)
Get MPITopology
associated to a PencilArray
.
PencilArrays.Pencils.typeof_array
— Functiontypeof_array(x::Pencil)
typeof_array(x::PencilArray)
typeof_array(x::AbstractArray)
Get the type of array (without the element type) so it can be used as a constructor.
PencilArrays.typeof_ptr
— Functiontypeof_ptr(x::AbstractArray)
typeof_ptr(x::PencilArray)
Get the type of pointer to the underlying array of a PencilArray
or AbstractArray
.
ManyPencilArray
Base.first
— Methodfirst(A::AbstractManyPencilArray)
Returns the first PencilArray
wrapped by A
.
Base.getindex
— Methodgetindex(A::AbstractManyPencilArray, ::Val{i})
getindex(A::AbstractManyPencilArray, i::Integer)
Returns the i-th PencilArray
wrapped by A
.
If possible, the Val{i}
form should be preferred, as it ensures that the full type of the returned PencilArray
is known by the compiler.
See also first(::AbstractManyPencilArray)
, last(::AbstractManyPencilArray)
.
Example
A = ManyPencilArray(pencil1, pencil2, pencil3)
# Get the PencilArray associated to `pencil2`.
u2 = A[2]
u2 = A[Val(2)]
Base.last
— Methodlast(A::AbstractManyPencilArray)
Returns the last PencilArray
wrapped by A
.
Base.length
— Methodlength(A::AbstractManyPencilArray)
Returns the number of PencilArray
s wrapped by A
.
Core.Tuple
— MethodTuple(A::AbstractManyPencilArray) -> (u1, u2, …)
Returns the PencilArray
s wrapped by A
.
This can be useful for iterating over all the wrapped arrays.
Index
Core.Tuple
PencilArrays.AbstractManyPencilArray
PencilArrays.GlobalPencilArray
PencilArrays.ManyPencilArray
PencilArrays.PencilArray
PencilArrays.PencilArrayCollection
Base.first
Base.getindex
Base.last
Base.length
Base.length
Base.parent
Base.pointer
Base.similar
Base.size
PencilArrays.Pencils.MPITopologies.get_comm
PencilArrays.Pencils.length_global
PencilArrays.Pencils.length_local
PencilArrays.Pencils.range_local
PencilArrays.Pencils.range_remote
PencilArrays.Pencils.size_global
PencilArrays.Pencils.size_local
PencilArrays.Pencils.topology
PencilArrays.Pencils.typeof_array
PencilArrays.Permutations.permutation
PencilArrays.extra_dims
PencilArrays.global_view
PencilArrays.ndims_extra
PencilArrays.ndims_space
PencilArrays.pencil
PencilArrays.sizeof_global
PencilArrays.typeof_ptr