Execution and fields¶
These types connect logical fields to host or device execution. Backend setup and support constraints belong in the GPU path decision guide; halo layout choices are explained in Halo exchange.
pfc::View¶
-
template<typename T, std::size_t Rank, typename Layout = LayoutRight, typename MemorySpace = DefaultMemorySpace>
struct View Kokkos-compatible multi-dimensional View.
- Template Parameters:
T – Value type
Rank – Number of dimensions (runtime extents only)
Layout – LayoutRight or LayoutLeft
MemorySpace – HostSpace, CudaSpace, or HipSpace
Public Functions
-
View() = default
Default constructor: empty view, no allocation.
-
template<typename ...IntType>
inline View(const std::string &name, IntType... extents) Allocating constructor.
- Parameters:
name – Label for debugging/profiling (Kokkos-compatible)
extents – Per-dimension extents (number of args must equal Rank)
-
template<typename ...IntType>
inline View(pointer_type ptr, IntType... extents) Unmanaged constructor: wrap existing pointer.
- Parameters:
ptr – Pointer to existing allocation (not owned)
extents – Per-dimension extents
-
template<typename iType>
inline T &access(iType i0 = 0, iType i1 = 0, iType i2 = 0, iType i3 = 0, iType i4 = 0, iType i5 = 0, iType i6 = 0, iType i7 = 0) Kokkos-compatible access(i0, i1, …) with defaulted trailing zeros.
-
inline bool is_managed() const
Whether this view owns its storage.
-
inline buffer_t *buffer_ptr()
Underlying buffer (only valid when is_managed())
pfc::data::Field¶
-
template<typename T, typename MemorySpace = pfc::HostSpace>
class Field The one owning field container:
DataBuffer+Box3i+ halo + geometry-by-value.Logical indices
(i, j, k)are local (0-based on the owned box). Halo cells are addressable in[-halo, n + halo)on every axis, exactly as the legacyPaddedBrick.- Template Parameters:
T – Element type (e.g.
double,std::complex<double>).MemorySpace – Placement tag (
HostSpacedefault;CudaSpace/HipSpacefrom the runtime headers). Selects theDataBufferbackend viamemory_space_to_backend_t.
Public Functions
-
inline Field(const pfc::Domain &domain, const pfc::Box3i &owned_box, int halo_width = 0)
Construct from the global
Domain, the local owned index box, and a halo width. Allocatesprod(size + 2*halo)zero-initialized cells.halo_widthis both the storage padding and the default iteration halo (PaddedBrick convention). Prefer the four-argument overload when migrating unpaddedLocalFieldface-halo layouts (storage 0, iteration n).- Throws:
std::invalid_argument – on a negative halo or an inconsistent box.
-
inline Field(const pfc::Domain &domain, const pfc::Box3i &owned_box, int storage_halo, int iteration_halo)
Construct with independent storage padding and iteration halo.
storage_halosizes the buffer (prod(size + 2*storage_halo)).iteration_halois whathalo_width()/for_each_interiorreport — matchingLocalField’s metadata halo on an unpadded buffer.
Face-halo FD stacks use
storage_halo=0anditeration_halo=order/2. PaddedBrick-style fields use equal values for both.
-
inline std::size_t size() const noexcept
Total allocated cells, including halo padding.
-
inline std::vector<T> &vec()
Host
std::vectorview of the buffer (FFT / legacy APIs).Note
HostSpace only — device-backed fields have no host
std::vectorprimary storage.
-
inline const pfc::Box3i &box() const noexcept
Owned (interior) index box, in global index coordinates.
-
inline int storage_halo() const noexcept
Storage padding width (cells added on each side of the owned box).
-
inline int halo_width() const noexcept
Iteration / stencil halo (LocalField-compatible).
For padded fields this equals
storage_halo(). For unpadded face-halo layouts it is the metadata width used byfor_each_interiorandFdGradientfactories, while storage stays tightly packed.
-
inline pfc::Int3 local_size() const noexcept
Per-axis count of owned cells (halo excluded).
-
inline pfc::Int3 size3() const noexcept
LocalField-compatible alias of
local_size().
-
inline pfc::Int3 global_size() const noexcept
Global domain extents
{Nx, Ny, Nz}(LocalField-compatible).
-
inline pfc::Int3 lower_global() const noexcept
Global index of local
(0,0,0)(LocalField-compatible).
-
inline int padded_extent(int axis) const noexcept
Per-axis padded extent (owned + both storage-halo slabs).
-
inline pfc::Int3 global(int i, int j, int k) const noexcept
Global index
(gi, gj, gk)of local logical(i, j, k).
-
inline pfc::Real3 coords(int i, int j, int k) const noexcept
Physical coordinates of local logical
(i, j, k).
-
template<typename Fn>
inline void for_each_owned(Fn &&fn) const Visit every owned cell in x-fastest order.
Callable may be any of (auto-detected):
void(int i, int j, int k)void(double x, double y, double z, T value)(LocalField-compatible)void(const Real3& x, T value)(LocalField-compatible)
-
template<typename Fn>
inline void for_each_interior(Fn &&fn) const Iterate interior
[hw, n-hw)per axis (LocalField-compatible).Callable may be either of:
void(double x, double y, double z, T value)void(const Real3& x, T value)
-
template<typename Fn>
inline void apply(Fn &&fn) Fill every owned cell by sampling
fnat its physical coords. AcceptsT(double,double,double)orT(const Real3&). A host-side write, so the device copy (if any) is marked stale.
-
inline const Residency &residency() const noexcept
Host/device coherence state (see residency.hpp).
-
inline void note_device_write() noexcept
Record that a device kernel wrote the device buffer (host mirror stale).
-
inline void note_host_write() noexcept
Record a host-side write (device mirror stale). Public for axpy helpers.
-
inline void sync_to_device()
Push the host mirror to the device buffer when the device copy is stale. No-op for a host-space field. Call before a device kernel reads this field — the sync the audit-4.1 bug omitted.
-
template<typename Fn>
inline void with_host_view(Fn &&fn) Bracket a host-side access. Ensures the host data is current (pulling device->host for a device field), invokes
fn(T* data, std::size_t size)over the padded host buffer, then marks the host side authoritative (device copy stale).
Public Static Attributes
-
static constexpr bool is_host_space
True when this field’s memory space is host-accessible (no device mirror).
pfc::field::LocalField¶
-
template<class T>
class LocalField Public Functions
-
inline std::vector<T> &vec() noexcept
Underlying vector — pass to FFT / halo exchanger / stepper APIs.
-
inline std::size_t idx(int ix, int iy, int iz) const noexcept
Flat row-major index for local logical
(ix, iy, iz)(x fastest).
-
inline pfc::Int3 global(int ix, int iy, int iz) const noexcept
Global index
(gi, gj, gk)of local logical(ix, iy, iz).
-
inline pfc::Real3 coords(int ix, int iy, int iz) const noexcept
Physical coordinates
(x, y, z)of local logical(ix, iy, iz).
-
template<class Fn>
inline void apply(Fn &&fn) Fill every owned cell by sampling
fnat its physical coordinates.Lambda may be either of these signatures (auto-detected):
T(double x, double y, double z)T(const Real3& x)
-
template<class Fn>
inline void for_each_owned(Fn &&fn) const Iterate every owned cell, exposing
coordsandvalue.Lambda may be either of these signatures (auto-detected):
void(double x, double y, double z, T value)void(const Real3& x, T value)
-
template<class U = T, class = std::enable_if_t<std::is_same_v<U, double>>>
inline LocalField &operator+=(const pfc::field::ScaledField &s) In-place axpy:
*this += s.alpha * s.data[0..s.size).ScaledFieldis the proxy returned byoperator*(double, ...), so the call site readswhich is the explicit-Euler update in math-shaped form. The proxy must point to a buffer the same size as this field; an exception is thrown otherwise so layout mismatches surface immediately.u += dt * du;
Only available for
T == double(the proxy is adoubleview).- Throws:
std::invalid_argument – if
s.size() != size().
-
template<class Fn>
inline void for_each_interior(Fn &&fn) const Iterate the interior
[hw, n-hw)of every axis, exposingcoordsandvalue. No-op if the interior is empty.Lambda may be either of these signatures (auto-detected):
void(double x, double y, double z, T value)void(const Real3& x, T value)
Public Static Functions
-
static inline LocalField from_subdomain(const pfc::decomposition::Decomposition &decomp, int rank, int halo_width = 0)
FD subdomain layout: geometry from
, physical metadata fromdecomposition::local_box(decomp,
rank)
decomposition::domain(decomp).Storage is sized to
nx*ny*nzand value-initialized.halo_widthis stored sofor_each_interiorcan skip the per-rank halo region; the actual halo data, if needed, lives in a separate buffer (e.g.pfc::halo::FaceHalos<T>).- Throws:
std::invalid_argument – if
halo_width < 0or the local subdomain is too small to leave any interior cells given that halo width (i.e. requiressize[i] > 2 * halo_widthfor every axis).
-
static inline LocalField from_inbox(const pfc::World &global_world, const pfc::fft::Box3i &inbox)
FFT inbox layout: geometry from a
pfc::fft::Box3i(typicallyIFFT::get_inbox_bounds()) plus the global world.halo_widthis0(spectral apps do not carry per-rank halos).
-
inline std::vector<T> &vec() noexcept
pfc::field::PaddedBrick¶
-
template<class T>
class PaddedBrick Halo-padded contiguous brick: one buffer,
[-hw, n+hw)indexing.Storage layout (row-major, x fastest):
linear = (i + hw) + (j + hw) * nx_pad + (k + hw) * nx_pad * ny_padwherenx_pad = nx + 2*hw, etc. The MPI subarray types built bypfc::halo::create_padded_face_types_6use the same convention.Each brick is self-contained: it owns the
Decomposition(by value), itsrank, andhalo_widthso downstream consumers — exchangers, gradient evaluators, iteration helpers — can pick everything they need from the brick alone. This avoids drift between e.g. an exchanger and an evaluator constructed against the same field but with mismatched halo widths.The brick itself is MPI-unaware: the
MPI_Commlives on the exchanger (pfc::PaddedHaloExchanger<T>), not on the storage.- Template Parameters:
T – Element type (
doublefor the heat equation;float/std::complex<double>are equally valid).
Public Functions
-
inline PaddedBrick(const pfc::decomposition::Decomposition &decomp, int rank, int halo_width)
Construct a padded brick from an existing decomposition.
Geometry comes from
decomposition::local_box(decomp, rank)for the owned size + lower global index, and fromdecomposition::domainfor the physical origin/spacing (soglobal_coords(i, j, k)returns the right physical position even for halo cellsi = -1, which conceptually live at the rank’s left neighbor).The returned buffer is value-initialized (
T{}).- Throws:
std::invalid_argument – if
halo_width < 0. UnlikeLocalField::from_subdomainwe do not require the owned region to exceed2*halo_widthper axis — a padded brick with a tiny owned core is still valid; the user just doesn’t get a non-empty inner region for that halo width.
-
inline T *data() noexcept
Pointer to the start of the padded buffer (i.e. the
(-hw, -hw, -hw)cell, not the(0, 0, 0)owned cell).This is the pointer that
pfc::PaddedHaloExchanger<T>and the matching MPI subarray types inkernel/decomposition/padded_halo_mpi_types.hppoperate on.
-
inline std::size_t size() const noexcept
Total number of elements in the padded buffer (
nx_pad*ny_pad*nz_pad).
-
inline std::vector<T> &vec() noexcept
Underlying vector — pass to allocators, exchangers, raw kernels.
-
inline pfc::Int3 size3() const noexcept
Local owned size
(nx, ny, nz)(excludes the halo ring).
-
inline pfc::Int3 padded_size3() const noexcept
Local padded size
(nx + 2hw, ny + 2hw, nz + 2hw).
-
inline const pfc::decomposition::Decomposition &decomposition() const noexcept
Decomposition that produced this brick (carried by value, MPI-free).
-
inline int rank() const noexcept
Rank in the parent decomposition the brick was built for.
-
inline int nx() const noexcept
Owned-x extent.
-
inline int ny() const noexcept
Owned-y extent.
-
inline int nz() const noexcept
Owned-z extent.
-
inline int nx_padded() const noexcept
Padded-x extent (
nx + 2*hw).
-
inline int ny_padded() const noexcept
Padded-y extent (
ny + 2*hw).
-
inline int nz_padded() const noexcept
Padded-z extent (
nz + 2*hw).
-
inline std::size_t idx(int i, int j, int k) const noexcept
Flat row-major index for local
(i, j, k). Valid for anyi,j,k in [-hw, n+hw). Halo cells map to the outer ring.Note
No bounds checking in the release build. Out-of-range arguments are undefined behaviour; pair with
for_each_owned/_inner/_borderto guarantee the iteration stays in-range.
-
inline T &operator()(int i, int j, int k) noexcept
Element access for any
i,j,k in [-hw, n+hw).
-
inline std::size_t idx(const pfc::Int3 &c) const noexcept
pfc::Int3overloads ofidx/operator().Lets generic code call
brick(idx)after receiving a triple fromfor_eachorindices(), instead of unpacking it manually.
-
inline T &operator[](const pfc::Int3 &c) noexcept
Same as
operator()(c); allowsbrick[idx]withidxfromfor_each.
-
inline detail::OwnedIndexRange indices() const noexcept
Forward range of
pfc::Int3{i, j, k}over the owned region[0, nx) x [0, ny) x [0, nz), in k-outer / j-middle / i-inner order.Pair with
pfc::field::for_each(brick, fn)for a cache-friendly sweep over every owned cell, or use the iterators directly:for (const auto idx : brick.indices()) { brick(idx) = some_value(idx); }
-
inline detail::OwnedIndexRange indices_inner(int r) const noexcept
Forward range of
pfc::Int3{i, j, k}over the inner region[r, n - r)per axis (nor-thick boundary slab).Returns an empty range whenever any axis has
n <= 2*r, so the caller never iterates past the owned region. Stencils that read±rneighbors entirely inside the owned core (without halo data) use this to bound the sweep.
-
inline pfc::Int3 global(int i, int j, int k) const noexcept
Global cell index
(gi, gj, gk)of local(i, j, k).For halo cells (e.g.
i = -1) this returns the conceptual global index before any periodic wrap (so callers can implement either periodic or Dirichlet semantics in their own filling code).
-
inline std::tuple<double, double, double> global_xyz(int i, int j, int k) const noexcept
Physical coordinates
(x, y, z)as scalars for local(i, j, k).Same geometry as
global_coords; pair with structured bindings, e.g.auto [x, y, z] = brick.global_xyz(i, j, k);.
-
inline pfc::Real3 global_coords(int i, int j, int k) const noexcept
Physical coordinates
(x, y, z)of local(i, j, k).Computed as
origin + (lower + i) * spacing— same asLocalField::coordsbut valid across the halo ring as well.
-
template<class Fn>
inline void apply(Fn &&fn) Fill every owned cell by sampling
fnat its physical coordinates. Halo cells are left untouched (zero-initialized).Lambda may be either of these signatures (auto-detected):
T(double x, double y, double z)T(const Real3& x)
-
template<class U = T, class = std::enable_if_t<std::is_same_v<U, double>>>
inline PaddedBrick &operator+=(const ScaledField &s) In-place axpy over the full padded buffer:
m_data[k] += s.alpha * s.data[k].Intended for
u += dt * duwhenduis aDuFieldwhose residual buffer matchessize()and leaves halo lanes at zero (refreshed each step byPaddedHaloExchanger).- Throws:
std::invalid_argument – if
s.size() != size().