feat(equations): added contribution(s) which allows equations authors to more quickly write equations without writing the boiler plate required by the backend
This commit is contained in:
184
src/include/serif/equations/contributions.hpp
Normal file
184
src/include/serif/equations/contributions.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file contributions.hpp
|
||||
* @author Emily M. Boudreaux
|
||||
*
|
||||
* @brief File containing the Contribution struct. This is effectively a helper struct for
|
||||
* authoring equations with fewer lines of boiler-plate. The idea here is that every equation must report
|
||||
* certain members so that the backend can inspect at compile time. An author could certainly
|
||||
* write these members themselves, but the Contribution struct auto generates
|
||||
* those members based on its template parameters. Therefore, by inheriting from
|
||||
* the Contribution struct an equation author can avoid writing those members themselves. Note that while
|
||||
* this is inheritance it is still a compile-time relation. Contribution does
|
||||
* not add any runtime overhead to the equation.
|
||||
*/
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "serif/discretization/blocks/traits.hpp"
|
||||
#include "serif/discretization/forms/operands.hpp"
|
||||
|
||||
namespace serif::equations {
|
||||
/**
|
||||
* @struct Contribution
|
||||
*
|
||||
* @brief A helper struct for authoring equations with fewer lines of boiler-plate. The idea here is that every equation must report
|
||||
* certain members so that the backend can inspect at compile time. An author could certainly
|
||||
* write these members themselves, but the Contribution struct auto generates
|
||||
* those members based on its template parameters. Therefore, by inheriting from
|
||||
* the Contribution struct an equation author can avoid writing those members themselves. Note that while
|
||||
* this is inheritance it is still a compile-time relation. Contribution does
|
||||
* not add any runtime overhead to the equation.
|
||||
*
|
||||
* @tparam TestOperandT The test operation type, which must be a valid operand (@ref IsOperand).
|
||||
* @tparam SupportT The support type, which must be a valid support (@ref IsSupport). This defaults to the support of the test term.
|
||||
*
|
||||
* @note The support type is, by default, read from the test term. There are very few situations where
|
||||
* you should need to override this default.
|
||||
*
|
||||
* @note Read this as "residuals are contributed to the row(s) defined by the test operation. e.g Some density constraint function
|
||||
* might contribute to the residuals of the overall system through some density row.
|
||||
*/
|
||||
template <discretization::forms::IsOperand TestOperandT, typename SupportT = discretization::blocks::SupportOf<typename TestOperandT::term_type>>
|
||||
struct Contribution {
|
||||
/**
|
||||
* @brief The test type of the contribution.
|
||||
*
|
||||
* The terminology Test here comes from finite element analysis. Specifically, the test type is the type
|
||||
* of the test function used in the weak formulation of the equation. More concretely,
|
||||
* the test type is the type for which the residuals are computed. Therefore think of
|
||||
* this as the type of the residual row that this contribution contributes to. There are a lot
|
||||
* of repetitions of the word type here, which I can recognize is a bit confusing. Effectively, the way
|
||||
* that we have structured much of this code is that we embed particular functions into the type system. Therefore
|
||||
* when I say "the type of the test function" what I mean is the c++ type that we have defined
|
||||
* to represent the test function.
|
||||
*
|
||||
* @note The above comment would probably make any actual writer shake in their boots. I'm sure there is a better way
|
||||
* to phrase that; however, I am at a loss for the moment. The TL;DR here is that since we
|
||||
* encode so much information into the type system we use the word type a lot. If this makes you rationally upset
|
||||
* please email me...
|
||||
*/
|
||||
using Test = TestOperandT::term_type;
|
||||
using TestOperand = TestOperandT; ///< The operand type of the contribution (associating a test function and a term)
|
||||
using Support = SupportT; ///< The domain support of the contribution (which then boils down to the dofs which are supported by the term on that test function)
|
||||
};
|
||||
|
||||
/**
|
||||
* @struct TestOperandTraits
|
||||
*
|
||||
* @brief A helper struct to extract the test operand type from a contribution or equation. This is used to determine the test type of an equation or contribution.
|
||||
*
|
||||
* @note The default void template parameter helps us to use SFINAE to detect if the type has a TestOperand member type.
|
||||
*
|
||||
* @todo Can we replace SFINAE here with requires or concepts?
|
||||
*
|
||||
* @tparam T The type to extract the test operand from
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct TestOperandTraits {
|
||||
using type = discretization::forms::Operand<typename T::Test>; ///< The default test operand type is the operand of the test type of the contribution or equation.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization of TestOperandTraits for types that have a TestOperand member type.
|
||||
* This allows us to extract the test operand type from contributions or equations that define a TestOperand type.
|
||||
*/
|
||||
template <typename T>
|
||||
struct TestOperandTraits<T, std::void_t<typename T::TestOperand>> {
|
||||
using type = T::TestOperand; ///< The test operand type is the TestOperand member type of the contribution or equation.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper alias to extract the test operand type from a contribution or equation.
|
||||
*
|
||||
* @tparam T The type to extract the test operand from
|
||||
*/
|
||||
template <typename T>
|
||||
using TestOperandOf = TestOperandTraits<T>::type;
|
||||
|
||||
/**
|
||||
* @brief Helper alias to extract the support type for a given contribution.
|
||||
*
|
||||
* @tparam T The type to extract the support type from
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct ContributionSupport {
|
||||
using type = discretization::blocks::SupportOf<typename T::Test>; ///< The default support type is the support of the test type of the contribution or equation.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization of ContributionSupport for types that have a Support member type.
|
||||
* This allows us to extract the support type from contributions or equations that define a Support type.
|
||||
*/
|
||||
template <typename T>
|
||||
struct ContributionSupport<T, std::void_t<typename T::Support>> {
|
||||
using type = T::Support; ///< The support type is the Support member type of the contribution or equation.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper alias to extract the support type for a given contribution.
|
||||
*
|
||||
* @tparam T The type to extract the support type from
|
||||
*/
|
||||
template <typename T>
|
||||
using SupportOf = ContributionSupport<T>::type;
|
||||
|
||||
/**
|
||||
* @brief Helper struct to pack a list of contributions into a tuple. This is used to define the set of contributions of an equation.
|
||||
*
|
||||
* @tparam T The type to pack into a tuple of contributions. This can be a single contribution or a tuple of contributions.
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct Contributions {
|
||||
using type = std::tuple<T>; ///< tuple of whatever is T
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type representing the contributions of an equation.
|
||||
* @tparam TupleT Some tuple (e.g. from Contributions::type). In this default specialization we always let the type be void
|
||||
*/
|
||||
template <typename TupleT, typename = void>
|
||||
struct ContributionTuple {
|
||||
using type = void; ///< The default type is void, indicating that the contributions are not valid.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization of ContributionTuple for tuples of contributions. This allows us to extract the contributions from a tuple of contributions.
|
||||
* @tparam Ts The types of the contributions in the tuple.
|
||||
*
|
||||
* @note The syntax of this specialization is not easy to parse. What we say here is
|
||||
* - We accept some pack of types Ts...
|
||||
* - We unpack all of those into the first template argument of the default specialization of ContributionTuple, which is a tuple of Ts...
|
||||
* - We use SFINAE to check if the tuple of contributions is valid by
|
||||
* - Checking if a tuple of the test operands of the contributions is valid (i.e. all contributions have the same test operand)
|
||||
*
|
||||
* @todo Replace SFINAE with requires or concepts if possible. This would make the code more readable and easier to understand.
|
||||
*/
|
||||
template <typename... Ts>
|
||||
struct ContributionTuple<std::tuple<Ts...>, std::void_t<decltype(std::tuple_cat(std::declval<typename Contributions<std::remove_cvref_t<Ts>>::type>()...))>> {
|
||||
/**
|
||||
* @brief The tuple representing all contributions, Using the pack of contributions Ts... we can extract the contributions of each and then concatenate them into a single tuple.
|
||||
* using C++17 folding
|
||||
*/
|
||||
using type = decltype(std::tuple_cat(std::declval<typename Contributions<std::remove_cvref_t<Ts>>::type>()...));
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specialization of Contributions for types that have the contributions() method.
|
||||
*
|
||||
* @todo Replace SFINAE with requires or concepts if possible. This would make the code more readable and easier to understand.
|
||||
*/
|
||||
template <typename T>
|
||||
struct Contributions<T, std::void_t<decltype(std::declval<const T&>().contributions())>> :
|
||||
ContributionTuple<std::remove_cvref_t<decltype(std::declval<const T&>().contributions())>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper alias to extract the contributions (::type) of some type T.
|
||||
*
|
||||
* @tparam T The type to extract the contributions from
|
||||
*/
|
||||
template <typename T>
|
||||
using ContributionsOf = Contributions<std::remove_cvref_t<T>>::type;
|
||||
} // namespace serif::equations
|
||||
Reference in New Issue
Block a user