namespace pressio{ namespace ode{
#ifdef PRESSIO_ENABLE_CXX20
template <class T>
concept OdeSystem =
requires(){
typename T::independent_variable_type; }
&& std::copy_constructible<typename T::state_type>
&& std::copy_constructible<typename T::rhs_type>
&& requires(const T & A,
const typename T::state_type & state,
const typename T::independent_variable_type & evalValue,
typename T::rhs_type & f)
{
{ A.createState() } -> std::same_as<typename T::state_type>;
{ A.createRhs() } -> std::same_as<typename T::rhs_type>;
{ A.rhs(state, evalValue, f) } -> std::same_as<void>;
};
template <class T>
concept RealValuedOdeSystem =
OdeSystem<T>
&& std::floating_point< scalar_trait_t<typename T::state_type> >
&& std::floating_point< scalar_trait_t<typename T::rhs_type> >
&& std::convertible_to<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >;
#else
template<class T, class enable = void>
struct OdeSystem : std::false_type{};
template<class T>
struct OdeSystem<
T,
std::enable_if_t<
::pressio::has_independent_variable_typedef<T>::value
&& ::pressio::has_state_typedef<T>::value
&& ::pressio::has_rhs_typedef<T>::value
&& std::is_copy_constructible<typename T::state_type>::value
&& std::is_copy_constructible<typename T::rhs_type>::value
&& ::pressio::ode::has_const_create_state_method_return_result<
T, typename T::state_type >::value
&& ::pressio::ode::has_const_create_rhs_method_return_result<
T, typename T::rhs_type >::value
&& std::is_void<
decltype(
std::declval<T const>().rhs
(
std::declval<typename T::state_type const&>(),
std::declval<typename T::independent_variable_type const &>(),
std::declval<typename T::rhs_type &>()
)
)
>::value
>
> : std::true_type{};
template<class T, class enable = void>
struct RealValuedOdeSystem : std::false_type{};
template<class T>
struct RealValuedOdeSystem<
T, std::enable_if_t<
OdeSystem<T>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::rhs_type> >::value
&& std::is_convertible<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >::value
>
> : std::true_type{};
#endif
#ifdef PRESSIO_ENABLE_CXX20
template <class T>
concept OdeSystemFusingRhsAndJacobian =
requires(){ typename T::independent_variable_type; }
&& std::copy_constructible<typename T::state_type>
&& std::copy_constructible<typename T::rhs_type>
&& std::copy_constructible<typename T::jacobian_type>
&& requires(const T & A,
const typename T::state_type & state,
const typename T::independent_variable_type & evalValue,
typename T::rhs_type & f,
std::optional<typename T::jacobian_type*> J)
{
{ A.createState() } -> std::same_as<typename T::state_type>;
{ A.createRhs() } -> std::same_as<typename T::rhs_type>;
{ A.createJacobian() } -> std::same_as<typename T::jacobian_type>;
{ A.rhsAndJacobian(state, evalValue, f, J) } -> std::same_as<void>;
};
template <class T>
concept RealValuedOdeSystemFusingRhsAndJacobian =
OdeSystemFusingRhsAndJacobian<T>
&& std::floating_point< scalar_trait_t<typename T::state_type> >
&& std::floating_point< scalar_trait_t<typename T::rhs_type> >
&& std::floating_point< scalar_trait_t<typename T::jacobian_type> >
&& std::convertible_to<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >;
#else
template<class T, class enable = void>
struct OdeSystemFusingRhsAndJacobian : std::false_type{};
template<class T>
struct OdeSystemFusingRhsAndJacobian<
T,
std::enable_if_t<
::pressio::has_independent_variable_typedef<T>::value
&& ::pressio::has_state_typedef<T>::value
&& ::pressio::has_rhs_typedef<T>::value
&& ::pressio::has_jacobian_typedef<T>::value
&& std::is_copy_constructible<typename T::state_type>::value
&& std::is_copy_constructible<typename T::rhs_type>::value
&& std::is_copy_constructible<typename T::jacobian_type>::value
&& ::pressio::ode::has_const_create_state_method_return_result<
T, typename T::state_type >::value
&& ::pressio::ode::has_const_create_rhs_method_return_result<
T, typename T::rhs_type >::value
&& ::pressio::ode::has_const_create_jacobian_method_return_result<
T, typename T::jacobian_type >::value
&& std::is_void<
decltype(
std::declval<T const>().rhsAndJacobian
(
std::declval<typename T::state_type const&>(),
std::declval<typename T::independent_variable_type const &>(),
std::declval<typename T::rhs_type &>(),
std::declval< std::optional<typename T::jacobian_type*> >()
)
)
>::value
>
> : std::true_type{};
template<class T, class enable = void>
struct RealValuedOdeSystemFusingRhsAndJacobian : std::false_type{};
template<class T>
struct RealValuedOdeSystemFusingRhsAndJacobian<
T,
std::enable_if_t<
OdeSystemFusingRhsAndJacobian<T>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::rhs_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::jacobian_type> >::value
&& std::is_convertible<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >::value
> > : std::true_type{};
#endif
#ifdef PRESSIO_ENABLE_CXX20
template <class T>
concept OdeSystemFusingMassMatrixAndRhs =
requires(){ typename T::independent_variable_type; }
&& std::copy_constructible<typename T::state_type>
&& std::copy_constructible<typename T::rhs_type>
&& std::copy_constructible<typename T::mass_matrix_type>
&& requires(const T & A,
const typename T::state_type & state,
const typename T::independent_variable_type & evalValue,
typename T::mass_matrix_type & M,
typename T::rhs_type & f)
{
{ A.createState() } -> std::same_as<typename T::state_type>;
{ A.createRhs() } -> std::same_as<typename T::rhs_type>;
{ A.createMassMatrix() } -> std::same_as<typename T::mass_matrix_type>;
{ A.massMatrixAndRhs(state, evalValue, M, f) } -> std::same_as<void>;
};
template <class T>
concept RealValuedOdeSystemFusingMassMatrixAndRhs =
OdeSystemFusingMassMatrixAndRhs<T>
&& std::floating_point< scalar_trait_t<typename T::state_type> >
&& std::floating_point< scalar_trait_t<typename T::rhs_type> >
&& std::floating_point< scalar_trait_t<typename T::mass_matrix_type> >
&& std::convertible_to<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >;
#else
template<class T, class enable = void>
struct OdeSystemFusingMassMatrixAndRhs : std::false_type{};
template<class T>
struct OdeSystemFusingMassMatrixAndRhs<
T,
std::enable_if_t<
::pressio::has_independent_variable_typedef<T>::value
&& ::pressio::has_state_typedef<T>::value
&& ::pressio::has_rhs_typedef<T>::value
&& ::pressio::has_mass_matrix_typedef<T>::value
&& std::is_copy_constructible<typename T::state_type>::value
&& std::is_copy_constructible<typename T::rhs_type>::value
&& std::is_copy_constructible<typename T::mass_matrix_type>::value
&& ::pressio::ode::has_const_create_state_method_return_result<
T, typename T::state_type >::value
&& ::pressio::ode::has_const_create_rhs_method_return_result<
T, typename T::rhs_type >::value
&& ::pressio::ode::has_const_create_mass_matrix_method_return_result<
T, typename T::mass_matrix_type >::value
&& std::is_void<
decltype(
std::declval<T const>().massMatrixAndRhs
(
std::declval<typename T::state_type const&>(),
std::declval<typename T::independent_variable_type const &>(),
std::declval<typename T::mass_matrix_type &>(),
std::declval<typename T::rhs_type &>()
)
)
>::value
>
> : std::true_type{};
template<class T, class enable = void>
struct RealValuedOdeSystemFusingMassMatrixAndRhs : std::false_type{};
template<class T>
struct RealValuedOdeSystemFusingMassMatrixAndRhs<
T, std::enable_if_t<
OdeSystemFusingMassMatrixAndRhs<T>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::rhs_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::mass_matrix_type> >::value
&& std::is_convertible<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >::value
>
> : std::true_type{};
#endif
#ifdef PRESSIO_ENABLE_CXX20
template <class T>
concept CompleteOdeSystem =
requires(){ typename T::independent_variable_type; }
&& std::copy_constructible<typename T::state_type>
&& std::copy_constructible<typename T::rhs_type>
&& std::copy_constructible<typename T::mass_matrix_type>
&& std::copy_constructible<typename T::jacobian_type>
&& requires(const T & A,
const typename T::state_type & state,
const typename T::independent_variable_type & evalValue,
typename T::mass_matrix_type & M,
typename T::rhs_type & f,
std::optional<typename T::jacobian_type*> J)
{
{ A.createState() } -> std::same_as<typename T::state_type>;
{ A.createRhs() } -> std::same_as<typename T::rhs_type>;
{ A.createMassMatrix() } -> std::same_as<typename T::mass_matrix_type>;
{ A.massMatrixAndRhsAndJacobian(state, evalValue, M, f, J) } -> std::same_as<void>;
};
template <class T>
concept RealValuedCompleteOdeSystem =
CompleteOdeSystem<T>
&& std::floating_point< scalar_trait_t<typename T::state_type> >
&& std::floating_point< scalar_trait_t<typename T::rhs_type> >
&& std::floating_point< scalar_trait_t<typename T::mass_matrix_type> >
&& std::floating_point< scalar_trait_t<typename T::jacobian_type> >
&& std::convertible_to<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >;
#else
template<class T, class enable = void>
struct CompleteOdeSystem : std::false_type{};
template<class T>
struct CompleteOdeSystem<
T,
std::enable_if_t<
::pressio::has_independent_variable_typedef<T>::value
&& ::pressio::has_state_typedef<T>::value
&& ::pressio::has_rhs_typedef<T>::value
&& ::pressio::has_mass_matrix_typedef<T>::value
&& ::pressio::has_jacobian_typedef<T>::value
&& std::is_copy_constructible<typename T::state_type>::value
&& std::is_copy_constructible<typename T::rhs_type>::value
&& std::is_copy_constructible<typename T::mass_matrix_type>::value
&& std::is_copy_constructible<typename T::jacobian_type>::value
&& ::pressio::ode::has_const_create_state_method_return_result<
T, typename T::state_type >::value
&& ::pressio::ode::has_const_create_rhs_method_return_result<
T, typename T::rhs_type >::value
&& ::pressio::ode::has_const_create_mass_matrix_method_return_result<
T, typename T::mass_matrix_type >::value
&& ::pressio::ode::has_const_create_jacobian_method_return_result<
T, typename T::jacobian_type >::value
//
&& std::is_void<
decltype(
std::declval<T const>().massMatrixAndRhsAndJacobian
(
std::declval<typename T::state_type const&>(),
std::declval<typename T::independent_variable_type const &>(),
std::declval<typename T::mass_matrix_type &>(),
std::declval<typename T::rhs_type &>(),
std::declval< std::optional<typename T::jacobian_type*> >()
)
)
>::value
>
> : std::true_type{};
template<class T, class enable = void>
struct RealValuedCompleteOdeSystem : std::false_type{};
template<class T>
struct RealValuedCompleteOdeSystem<
T, std::enable_if_t<
CompleteOdeSystem<T>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::rhs_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::mass_matrix_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::jacobian_type> >::value
&& std::is_convertible<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >::value
>
> : std::true_type{};
#endif
#ifdef PRESSIO_ENABLE_CXX20
template<class T>
concept FDJ_Common =
requires { typename T::independent_variable_type; } &&
requires { typename T::state_type; } &&
requires { typename T::discrete_residual_type; } &&
requires { typename T::discrete_jacobian_type; } &&
std::copy_constructible<typename T::state_type> &&
std::copy_constructible<typename T::discrete_residual_type> &&
std::copy_constructible<typename T::discrete_jacobian_type> &&
requires (const T& A) {
{ A.createState() } -> std::same_as<typename T::state_type>;
{ A.createDiscreteResidual() } -> std::same_as<typename T::discrete_residual_type>;
{ A.createDiscreteJacobian() } -> std::same_as<typename T::discrete_jacobian_type>;
};
// ---- Short aliases to keep requires-expressions readable ---------------------
template<class T> using step_t = typename ::pressio::ode::StepCount::value_type; // adjust if you have a different step type
template<class T> using time_t = typename T::independent_variable_type;
template<class T> using state_t = typename T::state_type;
template<class T> using res_t = typename T::discrete_residual_type;
template<class T> using jac_t = typename T::discrete_jacobian_type;
template<class T> using opt_jac_ptr_t = std::optional<jac_t<T>*>;
// ---- Method presence checks for NumStates = 1,2,3,4 --------------------------
template<class T>
concept HasDRJ_1 =
requires (const T& a) {
{ a.discreteResidualAndJacobian(
std::declval<step_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<res_t<T>&>(),
std::declval<opt_jac_ptr_t<T>>(),
std::declval<state_t<T> const&>()
)
} -> std::same_as<void>;
};
template<class T>
concept HasDRJ_2 =
requires (const T& a) {
{ a.discreteResidualAndJacobian(
std::declval<step_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<res_t<T>&>(),
std::declval<opt_jac_ptr_t<T>>(),
std::declval<state_t<T> const&>(),
std::declval<state_t<T> const&>()
)
} -> std::same_as<void>;
};
template<class T>
concept HasDRJ_3 =
requires (const T& a) {
{ a.discreteResidualAndJacobian(
std::declval<step_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<res_t<T>&>(),
std::declval<opt_jac_ptr_t<T>>(),
std::declval<state_t<T> const&>(),
std::declval<state_t<T> const&>(),
std::declval<state_t<T> const&>()
)
} -> std::same_as<void>;
};
template<class T>
concept HasDRJ_4 =
requires (const T& a) {
{ a.discreteResidualAndJacobian(
std::declval<step_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<time_t<T> const&>(),
std::declval<res_t<T>&>(),
std::declval<opt_jac_ptr_t<T>>(),
std::declval<state_t<T> const&>(),
std::declval<state_t<T> const&>(),
std::declval<state_t<T> const&>(),
std::declval<state_t<T> const&>()
)
} -> std::same_as<void>;
};
// select the right arity by NumStates
template<class T, int NumStates>
concept HasDRJ_N =
(NumStates == 1 && HasDRJ_1<T>) ||
(NumStates == 2 && HasDRJ_2<T>) ||
(NumStates == 3 && HasDRJ_3<T>) ||
(NumStates == 4 && HasDRJ_4<T>);
// Actual concepts
template <class T, int NumStates>
concept FullyDiscreteSystemWithJacobian =
FDJ_Common<T> && HasDRJ_N<T, NumStates>;
template <class T, int NumStates>
concept RealValuedFullyDiscreteSystemWithJacobian =
FullyDiscreteSystemWithJacobian<T, NumStates>
&& std::floating_point< scalar_trait_t<typename T::state_type> >
&& std::floating_point< scalar_trait_t<typename T::discrete_residual_type> >
&& std::floating_point< scalar_trait_t<typename T::discrete_jacobian_type> >
&& std::convertible_to<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >;
#else
template<class T, int NumStates,class enable = void>
struct FullyDiscreteSystemWithJacobian : std::false_type{};
template<class T, int NumStates>
struct FullyDiscreteSystemWithJacobian<
T, NumStates,
std::enable_if_t<
::pressio::has_independent_variable_typedef<T>::value
&& ::pressio::has_state_typedef<T>::value
&& ::pressio::has_discrete_residual_typedef<T>::value
&& ::pressio::has_discrete_jacobian_typedef<T>::value
&& std::is_copy_constructible<typename T::state_type>::value
&& std::is_copy_constructible<typename T::discrete_residual_type>::value
&& std::is_copy_constructible<typename T::discrete_jacobian_type>::value
&& ::pressio::ode::has_const_create_state_method_return_result<
T, typename T::state_type >::value
&& ::pressio::ode::has_const_create_discrete_residual_method_return_result<
T, typename T::discrete_residual_type>::value
&& ::pressio::ode::has_const_create_discrete_jacobian_method_return_result<
T, typename T::discrete_jacobian_type>::value
//
&& ::pressio::ode::has_const_discrete_residual_jacobian_method<
T, NumStates,
typename ::pressio::ode::StepCount::value_type,
typename T::independent_variable_type,
typename T::state_type,
typename T::discrete_residual_type,
typename T::discrete_jacobian_type
>::value
>
> : std::true_type{};
template <class T, int NumStates, class = void>
struct RealValuedFullyDiscreteSystemWithJacobian : std::false_type{};
template <class T, int NumStates>
struct RealValuedFullyDiscreteSystemWithJacobian<
T, NumStates,
std::enable_if_t<
FullyDiscreteSystemWithJacobian<T, NumStates>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::discrete_residual_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::discrete_jacobian_type> >::value
&& std::is_convertible<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type> >::value
>
> : std::true_type{};
#endif
//
// ImplicitResidualJacobianPolicy
//
#ifdef PRESSIO_ENABLE_CXX20
template<class T>
concept ImplicitResidualJacobianPolicy =
// --- required nested types
requires {
typename T::independent_variable_type;
typename T::state_type;
typename T::residual_type;
typename T::jacobian_type;
}
// --- known pressio-ops data types & scalar compatibility
&& ::pressio::ops::is_known_data_type<typename T::state_type>::value
&& ::pressio::ops::is_known_data_type<typename T::residual_type>::value
&& ::pressio::ops::is_known_data_type<typename T::jacobian_type>::value
&& ::pressio::all_have_traits_and_same_scalar<
typename T::state_type,
typename T::residual_type,
typename T::jacobian_type
>::value
&& std::convertible_to<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type>
>
// --- factories on a const object
&& requires (T const& a) {
{ a.createState() } -> std::same_as<typename T::state_type>;
{ a.createResidual() } -> std::same_as<typename T::residual_type>;
{ a.createJacobian() } -> std::same_as<typename T::jacobian_type>;
}
// --- call operator with exact signature; must return void and be const
&& requires (T const& a) {
{ a(
std::declval<StepScheme const&>(),
std::declval<typename T::state_type const&>(),
std::declval<ImplicitStencilStatesDynamicContainer<typename T::state_type> const&>(),
std::declval<ImplicitStencilRightHandSideDynamicContainer<typename T::residual_type>&>(),
std::declval<::pressio::ode::StepEndAt<typename T::independent_variable_type>>(),
std::declval<::pressio::ode::StepCount>(),
std::declval<::pressio::ode::StepSize<typename T::independent_variable_type>>(),
std::declval<typename T::residual_type &>(),
std::declval<std::optional<typename T::jacobian_type*> >()
) } -> std::same_as<void>;
};
#else
template<class T, class = void>
struct ImplicitResidualJacobianPolicy : std::false_type{};
template<class T>
struct ImplicitResidualJacobianPolicy<
T,
std::enable_if_t<
::pressio::has_independent_variable_typedef<T>::value
&& ::pressio::has_state_typedef<T>::value
&& ::pressio::has_residual_typedef<T>::value
&& ::pressio::has_jacobian_typedef<T>::value
//
&& ::pressio::ops::is_known_data_type<typename T::state_type>::value
&& ::pressio::ops::is_known_data_type<typename T::residual_type>::value
&& ::pressio::ops::is_known_data_type<typename T::jacobian_type>::value
&& all_have_traits_and_same_scalar<
typename T::state_type,
typename T::residual_type,
typename T::jacobian_type>::value
&& std::is_convertible<
typename T::independent_variable_type,
scalar_trait_t<typename T::state_type>>::value
//
// create methods
//
&& ::pressio::ode::has_const_create_state_method_return_result<
T, typename T::state_type>::value
&& std::is_same<
typename T::residual_type,
decltype(std::declval<T const>().createResidual())
>::value
&& std::is_same<
typename T::jacobian_type,
decltype(std::declval<T const>().createJacobian())
>::value
&& std::is_void<
decltype
(
std::declval<T const>()
(
std::declval<StepScheme const &>(),
std::declval<typename T::state_type const &>(),
std::declval<ImplicitStencilStatesDynamicContainer<typename T::state_type> const & >(),
std::declval<ImplicitStencilRightHandSideDynamicContainer<typename T::residual_type> & >(),
std::declval< ::pressio::ode::StepEndAt<typename T::independent_variable_type> >(),
std::declval< ::pressio::ode::StepCount >(),
std::declval< ::pressio::ode::StepSize<typename T::independent_variable_type> >(),
std::declval<typename T::residual_type &>(),
std::declval< std::optional<typename T::jacobian_type*> >()
)
)
>::value
>
> : std::true_type{};
#endif // end ifdef CXX20
#ifdef PRESSIO_ENABLE_CXX20
template<class T>
concept StepperWithoutSolver =
// required nested types
requires {
typename T::independent_variable_type;
typename T::state_type;
}
// canonical call must exist and return void
&& requires(
T& stepper,
typename T::state_type& y,
const ::pressio::ode::StepStartAt<typename T::independent_variable_type>& t0,
const ::pressio::ode::StepCount& k,
const ::pressio::ode::StepSize<typename T::independent_variable_type>& dt
) {
{ stepper(y, t0, k, dt) } -> std::same_as<void>;
}
// forbid accepting const state&
&& (!requires(
T& stepper,
const typename T::state_type& y,
const ::pressio::ode::StepStartAt<typename T::independent_variable_type>& t0,
const ::pressio::ode::StepCount& k,
const ::pressio::ode::StepSize<typename T::independent_variable_type>& dt
) {
stepper(y, t0, k, dt);
})
// forbid accepting state&&
&& (!requires(
T& stepper,
typename T::state_type&& y,
const ::pressio::ode::StepStartAt<typename T::independent_variable_type>& t0,
const ::pressio::ode::StepCount& k,
const ::pressio::ode::StepSize<typename T::independent_variable_type>& dt
) {
stepper(std::move(y), t0, k, dt);
});
#else