diff --git a/doc/sphinx/src/sparse_packs.rst b/doc/sphinx/src/sparse_packs.rst index 026e437b60866..43a0f4470405e 100644 --- a/doc/sphinx/src/sparse_packs.rst +++ b/doc/sphinx/src/sparse_packs.rst @@ -85,6 +85,83 @@ snippet. care should be taken not to assume that scratch variables can persist between tasks, even when they are directly dependent on each other. Issues resolved by setting ``-DPARTHENON_DEBUG_SCRATCH=ON`` can be an indication of this issue. +Slicing into ``SparsePack``\ s with ``SubPack``\ s +-------------------------------------------------- + +A `SubPack` provdies a view into a slice of a `SparsePack` along a given dimension(s). +`SubPack`\ s are constructed with a block + `kji` index to give a slice into the +fields at the meshblock + cell index. When a `SubPack` is constructed with the +`Axis` template parameters then the `SubPack` also providies a view into slices +of the `SparsePack` along the provided axes offset from the provided `ijk` indices. + +.. code:: c++ + + const int ni = ib.e - ib.s + 1; + const int ic = ib.s + ni / 2; + par_for( + PARTHENON_AUTO_LABEL, 0, sparse_pack.GetNBlocks() - 1, kb.s, kb.e, jb.s, jb.e, + KOKKOS_LAMBDA(int b, int k, int j) { + int ltot = 0; + int lo = sparse_pack.GetLowerBound(b, v3()); + int hi = sparse_pack.GetUpperBound(b, v3()); + auto sub_pack = parthenon::SubPack(sparse_pack, b, k, j, ic); + + for (int i = ib.s - ni / 2; i <= ib.e - ni / 2; i++) { + for (int c = 0; c <= hi - lo; ++c) { + Real n = i + ic + 1e1 * j + 1e2 * k + 1e4 * c + 1e5 * v + 1e3 * b; + // indexes into sparse_pack(b, v3(c), k, j, ic + i) + if (n != sub_pack(v3(c), i)) ltot += 1; + } + } + }); + +Using Virtual Fields +-------------------- + +Type-based ``SparsePack``\ s, when indexed with special ``virtual_variable_t`` types will return a value that is +calculated from other variables in the pack from the ``evaluate`` function registered to the type. Virtual variable types +need to export the other fields that their ``evaluate`` method depends on, allowing the virtual variable type, when included +in the ``PackDescriptor``, to pack the real variables. + +At the simplest a virtual variable's ``evaluate`` method has its signature take in a ``SparsePack`` as well as the ``i,j,k`` +indices and returns a ``Real`` as the value for the virtual field. + +Additionally a virtual variable can declare a ``pack_type`` to refer to a 0D, 1D, 2D, or 3D ``SubPack``, which case the ``evaluate`` +signature only takes in the desired ``SubPack`` centered at teh ``i,j,k`` index. + +.. code:: c++ + + struct d1 : parthenon::variable_names::virtual_variable_t { + KOKKOS_INLINE_FUNCTION d1() : x(0.0) {} + + KOKKOS_INLINE_FUNCTION d1(const Real &xx) : x(xx) {} + + template + KOKKOS_INLINE_FUNCTION Real evaluate(const Pack_t &pack, const int b, const int k, + const int j, const int i) const { + return pack(b, v1(), k, j, i) * pack(b, v3(1), k, j, i) * pack(b, v3(2), k, j, i) + x; + } + + Real x; + }; + + // use a subpack to index into the sparse pack + struct d1_subpack : public parthenon::variable_names::virtual_variable_t { + // declare the type of subpack we want to use for our evaluate method + using pack_type = parthenon::SubPack0D; + + KOKKOS_INLINE_FUNCTION d1_subpack() : x(0.0) {} + + KOKKOS_INLINE_FUNCTION d1_subpack(const Real &xx) : x(xx) {} + + template + KOKKOS_INLINE_FUNCTION Real evaluate(const Pack_t &pack) const { + return pack(v1()) * pack(v3(1)) * pack(v3(2)) + x; + } + + Real x; + }; + Building and Using a ``SparsePack`` ----------------------------------- diff --git a/src/basic_types.hpp b/src/basic_types.hpp index e55b6d1c6edc1..c039dcc235b7e 100644 --- a/src/basic_types.hpp +++ b/src/basic_types.hpp @@ -177,6 +177,9 @@ inline bool operator<(const GridIdentifier &lhs, const GridIdentifier &rhs) { return lhs.logical_level() < rhs.logical_level(); } +// Enumeration for accessing spatial axes of a meshblock +enum class Axis { I = 0, J = 1, K = 2 }; + // Enumeration for accessing a field on different locations of the grid: // CC = cell center of (i, j, k) // F1 = x-normal face at (i - 1/2, j, k) diff --git a/src/pack/pack_utils.hpp b/src/pack/pack_utils.hpp index 0c1087c7c0a95..21cd2603a6b7d 100644 --- a/src/pack/pack_utils.hpp +++ b/src/pack/pack_utils.hpp @@ -22,7 +22,12 @@ #include #include +#include + #include "basic_types.hpp" +#include "utils/concepts_lite.hpp" +#include "utils/error_checking.hpp" +#include "utils/type_list.hpp" // SFINAE for block iter so that Sparse/SwarmPacks can work for MeshBlockData and MeshData namespace { @@ -161,6 +166,65 @@ struct any_nonautoflux : public base_t { } }; using any = any_nonautoflux; + +// Concept to state that a typed-field is dependent on other +// fields, and is not itself an actual indexable field. +template +concept DependentVariable = + requires { typename T::independent_vars; }; // NOLINT(readability/braces) + +template +struct virtual_variable_t { + using type = virtual_variable_t; + using independent_vars = TypeList; +}; + +// Concept to check that a type shares an ancestor with virtual_variable_t +template +concept VirtualVariable = requires { + typename T::type; + requires is_specialization_of::value; +}; // NOLINT(readability/braces) + +// Concept to check that a type wants a subpack to evaluate the virtual field +template +concept VirtualSubPack = requires { + typename T::pack_type; + requires std::is_same_v; +}; // NOLINT(readability/braces) + +namespace impl { + +struct AllIndependentVariables { + template + requires(!DependentVariable) + static auto get(T) { + return TypeList(); + } + + template