feat(equations/arithmetic): added sum and different equation types
these are needed for things like the displacment force which is the sum of the rotational, gravitational, and pressure forces
This commit is contained in:
186
src/include/serif/equations/arithmetic.hpp
Normal file
186
src/include/serif/equations/arithmetic.hpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file arithmetic.hpp
|
||||
* @author Emily M. Boudreaux
|
||||
*
|
||||
* @brief File containing the EquationScale and EquationSum templates, which allow for scaling and summing equations.
|
||||
*
|
||||
* The astute observer will notice that none of the code in this file or indeed in in any part of the equations module actually implements summation or scaled
|
||||
* addition more generally. Rather, the code to manage that is implemented in the operator/backend/mfem module. Effectively these
|
||||
* templates are compile time tags telling that system how to combine weak contributions. The reason for this comes down to we dont really want to sum
|
||||
* at the point wise level; rather, we generally want to sum already integrated contributions. Since equations, by design, do not know any details about
|
||||
* the global system they are unable to manage this themselves.
|
||||
*
|
||||
* There is another, as yet unexplored case, where we introduce some point-wise summation equation. This could be implemented in a much more
|
||||
* local fashion and would probably be easier to trace; however, it would be semantically different in its meaning.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <concepts>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "serif/equations/concepts.hpp"
|
||||
#include "serif/utils/error/errors.hpp"
|
||||
|
||||
namespace serif::equations {
|
||||
|
||||
/**
|
||||
* @brief Scale an equation by a constant coefficient.
|
||||
*
|
||||
* This class is a compile-time tag that indicates that the weak contributions from a given equation should be scaled by the given coefficient.
|
||||
* The actual scaling is performed by the backend. A simple example would be if the scale is set to 1 then the weak contributions would be integrated unchanged;
|
||||
* whereas if the scale were set to -1 then the weak contributions would be integrated and then negated.
|
||||
*
|
||||
* @tparam EquationT The equation type to scale.
|
||||
*/
|
||||
template <Equation EquationT>
|
||||
class EquationScale final {
|
||||
public:
|
||||
using Test = typename EquationT::Test; ///< The test type of the scaled equation is the same as the test type of the original equation.
|
||||
|
||||
static constexpr std::string_view name = "scaled equation"; ///< Compile time name for the scaled equation, used for debugging and logging.
|
||||
|
||||
/**
|
||||
* @brief Construct a scaled equation.
|
||||
*
|
||||
* @param equation The equation to scale.
|
||||
* @param coefficient The coefficient to scale the equation by. Must be finite.
|
||||
*
|
||||
* @throws std::invalid_argument If the coefficient is not finite.
|
||||
*/
|
||||
explicit EquationScale(
|
||||
EquationT equation,
|
||||
const double coefficient
|
||||
) :
|
||||
m_equation(std::move(equation)),
|
||||
m_coefficient(coefficient) {
|
||||
using namespace utils::errors;
|
||||
|
||||
serif_ensure<SERiFErrorCode::NON_FINITE_VALUE_ERROR, std::invalid_argument>(std::isfinite(coefficient), "An equation coefficient must be finite.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the contributions of the scaled equation.
|
||||
*
|
||||
* @return A tuple containing the contributions of the scaled equation.
|
||||
*/
|
||||
[[nodiscard]] auto contributions() const noexcept {
|
||||
return std::tie(m_equation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the coefficient of the scaled equation.
|
||||
*
|
||||
* @return The coefficient of the scaled equation.
|
||||
*/
|
||||
[[nodiscard]] double coefficient() const noexcept {
|
||||
return m_coefficient;
|
||||
}
|
||||
|
||||
private:
|
||||
EquationT m_equation; ///< The equation being scaled.
|
||||
double m_coefficient; ///< The coefficient to scale the equation by. Must be finite.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sum multiple equations together.
|
||||
*
|
||||
* This class is a compile-time tag that indicates that the weak contributions from multiple equations should be summed together. The actual summation is performed by the backend.
|
||||
* A simple example would be if two equations are summed together, then the weak contributions from both equations would be integrated and then added together to form the final residual.
|
||||
* Note also that we do not define a coefficient here. The backend only ever sums things, as you can see in EquationDifference to subtract we locally
|
||||
* introduce a -1 scaling factor.
|
||||
*
|
||||
* @requires The FirstT and RestTs equations must share the same test type, otherwise the summation is not well-defined.
|
||||
*
|
||||
* @note Only equations sharing a residual row can or should be summed together.
|
||||
*
|
||||
* @tparam FirstT The first equation type to sum.
|
||||
* @tparam RestTs The remaining equation types to sum.
|
||||
*/
|
||||
template <Equation FirstT, Equation... RestTs>
|
||||
requires (std::same_as<typename FirstT::Test, typename RestTs::Test> && ...)
|
||||
class EquationSum final {
|
||||
public:
|
||||
using Test = typename FirstT::Test; ///< The test type of the summed equations is the same as the test type of the first equation.
|
||||
|
||||
static constexpr std::string_view name = "equation sum"; ///< Compile time name for the summed equations, used for debugging and logging.
|
||||
|
||||
/**
|
||||
* @brief Construct a summed equation.
|
||||
*
|
||||
* @param first The first equation to sum.
|
||||
* @param rest Pack of the remaining equations to sum.
|
||||
*
|
||||
* @note the constructor uses the initializer list for m_equations, note that the coefficient defaults to 1.0
|
||||
*/
|
||||
explicit EquationSum(
|
||||
FirstT first,
|
||||
RestTs... rest
|
||||
) :
|
||||
m_equations(std::move(first), std::move(rest)...) {}
|
||||
|
||||
/**
|
||||
* @brief Return the contributions of the summed equations.
|
||||
*
|
||||
* @return A tuple containing the contributions of the summed equations.
|
||||
*/
|
||||
[[nodiscard]] const auto& contributions() const noexcept {
|
||||
return m_equations;
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<FirstT, RestTs...> m_equations; ///< The equations being summed together.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Subtract one equation from another.
|
||||
*
|
||||
* This class is a compile-time tag that indicates that the weak contributions from the right equation should be subtracted from the weak contributions of the left equation.
|
||||
* The actual subtraction is performed by the backend. A simple example would be if the left equation has a weak contribution of 1 and the right equation has a weak contribution of 2,
|
||||
* then the final residual would be -1.
|
||||
*
|
||||
* @requires The left and right equations must share the same test type, otherwise the subtraction is not well-defined.
|
||||
*
|
||||
* @note Only equations sharing a residual row can or should be subtracted from one another.
|
||||
*
|
||||
* @tparam LeftT The left equation type to subtract from.
|
||||
* @tparam RightT The right equation type to subtract.
|
||||
*/
|
||||
template <Equation LeftT, Equation RightT>
|
||||
requires std::same_as<typename LeftT::Test, typename RightT::Test>
|
||||
class EquationDifference final {
|
||||
public:
|
||||
using Test = typename LeftT::Test; ///< The test type of the difference equation is the same as the test type of the left equation.
|
||||
|
||||
static constexpr std::string_view name = "equation difference"; ///< Compile time name for the difference equation, used for debugging and logging.
|
||||
|
||||
/**
|
||||
* @brief Construct a difference equation.
|
||||
*
|
||||
* @param left The left equation to subtract from.
|
||||
* @param right The right equation to subtract.
|
||||
*/
|
||||
explicit EquationDifference(
|
||||
LeftT left,
|
||||
RightT right
|
||||
) :
|
||||
m_equation(std::move(left), EquationScale{std::move(right), -1.0}) {}
|
||||
|
||||
/**
|
||||
* @brief Return the contributions of the difference equation.
|
||||
*
|
||||
* @return A tuple containing the contributions of the difference equation.
|
||||
*/
|
||||
[[nodiscard]] const auto& contributions() const noexcept {
|
||||
return m_equation.contributions();
|
||||
}
|
||||
|
||||
private:
|
||||
EquationSum<LeftT, EquationScale<RightT>> m_equation; ///< The equation representing the difference, which is a sum of the left equation and the scaled right equation (scaled by -1).
|
||||
};
|
||||
} // namespace serif::equations
|
||||
Reference in New Issue
Block a user