Skip to content

Commit

Permalink
Add type to hold values and derivatives
Browse files Browse the repository at this point in the history
In order to handle patches derivatives will be needed at the boundaries of the domain. This MR introduces a structure to link values and derivatives of a field in one structure which fixes #224. DDC does not provide a sub-domain type. Such a type is important as `DiscreteElement`s are linked to coordinates and we want values on the same grid. This MR therefore implements a sub-domain type and stores data internally on mdspans instead of `ddc::Chunk`s.

See merge request gysela-developpers/gyselalibxx!484

--------------------------------------------
  • Loading branch information
Emily Bourne committed Jun 24, 2024
1 parent dbde8e7 commit dd66f44
Show file tree
Hide file tree
Showing 25 changed files with 2,841 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

cmake_minimum_required(VERSION 3.15)

add_subdirectory(data_types)
add_subdirectory(utils)
add_subdirectory(speciesinfo)
add_subdirectory(io)
Expand Down
22 changes: 22 additions & 0 deletions src/data_types/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: MIT

add_library("data_types" INTERFACE)

target_compile_features("data_types"
INTERFACE
cxx_std_17
)

target_include_directories("data_types"
INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}"
)

target_link_libraries("data_types"
INTERFACE
DDC::DDC
sll::SLL
gslx::utils
)

add_library("gslx::data_types" ALIAS "data_types")

22 changes: 22 additions & 0 deletions src/data_types/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Utility Functions

## VectorField

The classes VectorField and VectorFieldSpan provide a way to represent a vector field. The two classes are required as VectorField contains ddc::Chunk objects while VectorFieldSpan contains ddc::ChunkSpan objects.

A VectorField or VectorFieldSpan contains an array of ddc::Chunk or ddc::ChunkSpan objects. When the VectorField is indexed using the `operator()` a ddc::detail::TaggedVector type is returned. This is similiar to a `ddc::Coordinate` and can be accessed in the same way.
Internally the information for the vector fields along each dimension is stored in separate memory chunks. As a result it is not possible to obtain a reference to an element of a VectorField. Instead you must access the internal chunk using `ddcHelper::get`.

In order to facilitate the usage of VectorField the utility functions `ddcHelper::get_domain`, `ddcHelper::deepcopy`, and `ddcHelper::get` are provided. However for the best access it is advised to retrieve the ChunkSpan and use this directly.


## DerivField

The classes DerivField and DerivFieldSpan provide a way to represent a field with its associated derivatives. The two classes are required as DerivField contains ddc::Chunk objects while DerivFieldSpan contains ddc::ChunkSpan objects.

The values and the different combinations of derivatives are each stored in their own chunk as these objects usually have different domains. The chunk itself can be accessed using slicing methods (`operator[]`). The values additionally have a helper method `get_values_span`.
When slicing a DerivField, you can use either domains or elements. These describe the derivatives which should appear in the chunk of interest and any additional information necessary to obtain a ddc::ChunkSpan. If a dimension is not described then it is assumed that the derivative in this direction is not of interest.

Beware: A ddc::ChunkSpan cannot store data defined on a non-contiguous domain (e.g. a DiscreteSubDomain) so when accessing derivatives the position of the derivative must also be included in the slice index.

As for VectorField it is advised to use this object for storage and to interact with the underlying chunks directly. However the utility function `ddcHelper::deepcopy` is nevertheless provided.
185 changes: 185 additions & 0 deletions src/data_types/deriv_details.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// SPDX-License-Identifier: MIT

#pragma once

#include <ddc/ddc.hpp>

namespace detail {

/**
* @brief A structure to determine if a tag is a derivative tag.
*
* @tparam Tag the class which may be a derivative.
*/
template <class Tag>
struct is_deriv_dim : std::false_type
{
};

template <class Tag>
struct is_deriv_dim<ddc::Deriv<Tag>> : std::true_type
{
};

/**
* @brief A shortcut to get a boolean indicating if a tag is a derivative tag.
*
* @tparam Tag the class which may be a derivative.
*/
template <class T>
inline constexpr bool is_deriv_dim_v = is_deriv_dim<T>::value;

//-----------------------------------------------------------------------------

/**
* @brief A class which extracts the derivative dimensions from a type sequence.
*/
template <class Tag>
struct DerivSubSet;

template <>
struct DerivSubSet<ddc::detail::TypeSeq<>>
{
using type = ddc::detail::TypeSeq<>;
};

template <class Tag>
struct DerivSubSet<ddc::detail::TypeSeq<Tag>>
{
using type = std::
conditional_t<is_deriv_dim_v<Tag>, ddc::detail::TypeSeq<Tag>, ddc::detail::TypeSeq<>>;
};

template <class HeadTag, class... Tags>
struct DerivSubSet<ddc::detail::TypeSeq<HeadTag, Tags...>>
{
using type = ddc::type_seq_merge_t<
typename DerivSubSet<ddc::detail::TypeSeq<HeadTag>>::type,
typename DerivSubSet<ddc::detail::TypeSeq<Tags...>>::type>;
};

/// A helper function to extract the derivative dimensions from a type sequence.
template <class Seq>
using deriv_sub_set_t = typename DerivSubSet<Seq>::type;

//-----------------------------------------------------------------------------

/**
* @brief A class which gets the physical dimension associated with the provided derivative.
*/
template <class Tag>
struct StripDeriv;

template <class Tags>
struct StripDeriv<ddc::Deriv<Tags>>
{
using type = Tags;
};

template <class... Tags>
struct StripDeriv<ddc::detail::TypeSeq<ddc::Deriv<Tags>...>>
{
using type = ddc::detail::TypeSeq<Tags...>;
};

/// A helper function to get the physical dimension associated with the provided derivative.
template <class Seq>
using strip_deriv_t = typename StripDeriv<Seq>::type;

//-----------------------------------------------------------------------------

/**
* @brief Select a tagged object by combining a limited number of known values
* with a default value.
*
* For example this function can be used to build DDC objects.
*
* Example:
* ddc::DiscreteElement<ddc::Deriv<X>> known_derivatives(2);
* ddc::DiscreteElement<ddc::Deriv<X>, ddc::Deriv<Y>, ddc::Deriv<Z>> default_derivatives(0, 0, 0);
* ddc::DiscreteElement<ddc::Deriv<X>, ddc::Deriv<Y>, ddc::Deriv<Z>> complete_derivative
* = select_default(known_derivatives, default_derivatives);
* // Equivalent to:
* // ddc::DiscreteElement<ddc::Deriv<X>, ddc::Deriv<Y>, ddc::Deriv<Z>> complete_derivative(2, 0, 0);
*
* @param known_values The values that are known and should appear in the result.
* @param default_values The values that should be used if no value is provided for the related tag.
*
* @return A tagged object containing the known values at the tags where this
* information is provided and the default values everywhere else.
*/
template <
template <typename...>
class Container,
class HeadQueryTag,
class... QueryTags,
class... Tags>
KOKKOS_FUNCTION Container<HeadQueryTag, QueryTags...> select_default(
Container<Tags...> const& known_values,
Container<HeadQueryTag, QueryTags...> const& default_values)
{
if constexpr (sizeof...(QueryTags) == 0) {
if constexpr (ddc::in_tags_v<HeadQueryTag, ddc::detail::TypeSeq<Tags...>>) {
return ddc::select<HeadQueryTag>(known_values);
} else {
return ddc::select<HeadQueryTag>(default_values);
}
} else {
return Container<HeadQueryTag, QueryTags...>(
select_default(known_values, ddc::select<HeadQueryTag>(default_values)),
select_default(known_values, ddc::select<QueryTags...>(default_values)));
}
}

//-----------------------------------------------------------------------------

/**
* @brief A class which provides a getter to collect the default discrete element
* describing derivatives from a type sequence of derivative dimensions.
*/
template <class DerivSeq>
class DefaultDerivElem;

template <class... Tags>
struct DefaultDerivElem<ddc::detail::TypeSeq<Tags...>>
{
static_assert((is_deriv_dim_v<Tags> && ...));
KOKKOS_FUNCTION constexpr static ddc::DiscreteElement<Tags...> get_element()
{
return ddc::DiscreteElement<Tags...>(ddc::DiscreteElement<Tags>(0)...);
}
};

/**
* @brief Helper function to clean the call syntax of DefaultDerivElem.
* A getter to collect the default discrete element describing derivatives
* from a type sequence of derivative dimensions.
*
* @tparam A type sequence of derivative dimensions.
*
* @return A DiscreteElement of 0s.
*/
template <class DerivSeq>
KOKKOS_FUNCTION auto no_derivative_element()
{
return DefaultDerivElem<DerivSeq>::get_element();
}

//-----------------------------------------------------------------------------

/**
* @brief A helper function to get the domain which only contains the one specified element.
*
* @param idx The element that the domain should describe.
*
* @return The domain containing the point.
*/
template <class... Tag>
KOKKOS_FUNCTION ddc::DiscreteDomain<Tag...> get_domain_from_element(
ddc::DiscreteElement<Tag...> idx)
{
return ddc::DiscreteDomain<Tag...>(
ddc::DiscreteDomain<Tag> {ddc::select<Tag>(idx), ddc::DiscreteVector<Tag>(1)}...);
}

} // namespace detail
Loading

0 comments on commit dd66f44

Please sign in to comment.