Data grids
The output of many quantum chemistry packages are datasets defined on a spatial grid in real or reciprocal space. Theoretical tools may want to perform mathematical operations on this data, but operating on bare arrays containing the dta requires tracking properties associated with each array, such as the basis vectors of the lattice
DataGrid
, RealDataGrid
, and ReciprocalDataGrid
An DataGrid{D,B<:Electrum.LatticeBasis,S<:AbstractVector{<:Real},T}
contains data defined in a crystal lattice of D
with basis vectors of type B
, a shift parameter of type S
, and elements of type T
, either in real space (RealDataGrid
) or in reciprocal space (ReciprocalDataGrid
). These aliases are defined as follows:
const RealDataGrid{D,T} = DataGrid{D,RealBasis{D,Float64},SVector{D,Float64},T}
const ReciprocalDataGrid{D,T} = DataGrid{D,ReciprocalBasis{D,Float64},KPoint{D},T}
Look closely at the above definition: the shift data type for RealDataGrid{D}
is SVector{D,Float64}
, but the shift data type for ReciprocalDataGrid{D}
is KPoint{D}
. When the DataGrid
constructor without the shift type parameter is invoked, the basis type is used to infer the appropriate shift type so that a RealDataGrid
or ReciprocalDataGrid
is constructed.
DataGrid
uses zero-based, periodic indexing: the first index of an AbstractDataGrid{D}
is zero(NTuple{D,Int})
, and indices whose moduli with respect to size along that dimension are identical will reference the same element: for instance, for g::AbstractDataGrid{3}
with size (10, 10, 10)
, g[69, 420, 1337] === g[9, 0, 7]
. Encountering a BoundsError
is not possible when indexing an DataGrid
.
The basis of an DataGrid
can be recovered with basis(::DataGrid)
, which will be of the type specified by the type parameter.
Broadcasting and mathematical operations
Broadcasting is defined for DataGrid
with a custom Base.Broadcast.BroadcastStyle
subtype:
Electrum.DataGridStyle{D,B,S} <: Broadcast.AbstractArrayStyle{D}
This allows DataGrid
instances to operated on with dot syntax. However, they must share lattice basis vectors and shift values. If they do not match, an Electrum.LatticeMismatch
exception will be thrown.
Although Base.Broadcast.ArrayStyle
is usually overridden by other subtypes of Base.Broadcast.AbstractArrayStyle
, it does not override Electrum.DataGridStyle
. Adding a DataGrid
to an Array
returns an Array
, and adding a DataGrid
to other AbstractArray
subtypes returns the AbstractArray
subtype defined by the Broadcast.BroadcastStyle
. In the case of a dimension mismatch, the broadcast style wll be Broadcast.ArrayConflict
- the operation will throw a DimensionMismatch
.
The +
and -
operators are defined for DataGrid
instances, and they are faster than the broadcasted .+
and .-
equivalents. As with the broadcasted versions, checks are implemented to ensure that the lattice basis vectors and shifts match.
Similarly, the *
, /
, and \
operators are defined for pairs of DataGrid
and Number
instances, and again, are faster than their broadcasted equivalents.
Fourier transforms
The Fourier transform and its inverse are available through an overload of FFTW.fft()
and FFTW.ifft()
. The transforms are normalized with respect to the basis vectors of the space, so for g::DataGrid
, ifft(fft(g)) ≈ g
(to within floating point error).
fft
and ifft
defined for DataGrid
generally, but it is critical to note that in the vast majority of cases, you will want to call fft
on RealDataGrid
instances and ifft
on ReciprocalDataGrid
instances.