139 lines
9.3 KiB
C++
139 lines
9.3 KiB
C++
|
|
#pragma once
|
||
|
|
|
||
|
|
#include "serif/model/description.hpp"
|
||
|
|
#include "serif/model/detail/specification_endpoints.hpp"
|
||
|
|
#include "serif/model/plan.hpp"
|
||
|
|
#include "serif/operators/linearized_system_view.hpp"
|
||
|
|
|
||
|
|
namespace serif::model
|
||
|
|
{
|
||
|
|
/** @brief Name a physical derivative using the shared block-source key convention. */
|
||
|
|
template <typename Row, typename Field>
|
||
|
|
using Derivative = operators::PhysicalBlock<utils::dependencies::KeyList<Row>, utils::dependencies::KeyList<Field>>;
|
||
|
|
|
||
|
|
/** @brief Map physical names and built-in generated identities once; custom identities require explicit bindings. */
|
||
|
|
template <utils::dependencies::IsBinding... Additional>
|
||
|
|
using SpecificationBindings = utils::dependencies::Bindings<
|
||
|
|
utils::dependencies::Binding<state::Density, discretization::blocks::density::mass>,
|
||
|
|
utils::dependencies::Binding<state::SurfaceShape, discretization::blocks::surface_deformation::coefficients>,
|
||
|
|
utils::dependencies::Binding<state::GravitationalPotential, discretization::blocks::gravity::potential>,
|
||
|
|
utils::dependencies::Binding<equation::PoissonBalance, discretization::blocks::gravity::potential>,
|
||
|
|
utils::dependencies::Binding<equation::SurfaceShapeBalance, discretization::blocks::surface_deformation::shape_equilibrium>,
|
||
|
|
utils::dependencies::Binding<equation::HydrostaticBalance, discretization::blocks::density::mass>,
|
||
|
|
utils::dependencies::Binding<GeneratedCoordinateOf<FixedTotalMass>, discretization::blocks::barotropic_constant::mass_normalization>,
|
||
|
|
utils::dependencies::Binding<ConstraintOf<FixedTotalMass>, discretization::blocks::barotropic_constant::mass_normalization>,
|
||
|
|
utils::dependencies::Binding<GeneratedCoordinateOf<FixedAngularMomentum>, discretization::blocks::rotation::angular_velocity>,
|
||
|
|
utils::dependencies::Binding<ConstraintOf<FixedAngularMomentum>, discretization::blocks::rotation::angular_velocity>, Additional...>;
|
||
|
|
|
||
|
|
using DefaultSpecificationBindings = SpecificationBindings<>;
|
||
|
|
|
||
|
|
namespace detail
|
||
|
|
{
|
||
|
|
template <typename Equation, typename Columns>
|
||
|
|
struct EquationCouplings;
|
||
|
|
|
||
|
|
template <typename Equation, typename... Columns>
|
||
|
|
struct EquationCouplings<Equation, utils::types::TypeList<Columns...>>
|
||
|
|
{
|
||
|
|
using Type = utils::dependencies::KeyList<Derivative<typename Equation::Test, typename Columns::term_type>...>;
|
||
|
|
};
|
||
|
|
|
||
|
|
template <typename Registry>
|
||
|
|
struct InteriorCouplings;
|
||
|
|
|
||
|
|
template <operators::VolumeEquation... Equations>
|
||
|
|
struct InteriorCouplings<equations::EquationRegistry<Equations...>>
|
||
|
|
{
|
||
|
|
using Type = utils::dependencies::CombinedKeyList<typename EquationCouplings<Equations, typename operators::EquationPlan<Equations>::Columns>::Type...>;
|
||
|
|
};
|
||
|
|
|
||
|
|
/** @brief Check physical inputs separately from unknowns and explicitly inactive equations. */
|
||
|
|
template <DimensionalScalarSpecification Specification, typename Model, typename Values, typename Inputs, typename Rows, typename InactiveRows, typename Bindings>
|
||
|
|
[[nodiscard]] consteval bool valid_specification_endpoints()
|
||
|
|
{
|
||
|
|
using namespace utils::dependencies;
|
||
|
|
using Endpoints = ResolvedSpecification<Specification, Bindings>;
|
||
|
|
if constexpr (!ContainsKey<typename Endpoints::Coordinate, Values> || !ContainsKey<typename Endpoints::Constraint, Rows> ||
|
||
|
|
!Endpoints::Reads::template owners_present<Model> || !Endpoints::Changes::template owners_present<Model>)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return []<typename... Read, typename... Changed>(KeyList<Read...>, KeyList<Changed...>)
|
||
|
|
{
|
||
|
|
return sizeof...(Read) != 0 && (ContainsKey<Read, Inputs> && ...) && (ContainsKey<Changed, Rows> || ...) &&
|
||
|
|
((ContainsKey<Changed, Rows> || ContainsKey<Changed, InactiveRows>) && ...);
|
||
|
|
}(typename Endpoints::Reads::Keys{}, typename Endpoints::Changes::Keys{});
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @brief Fold independent physical declarations; no equation counting or rank inference is involved. */
|
||
|
|
template <typename Model, typename Values, typename Inputs, typename Rows, typename InactiveRows, typename Bindings, typename... Specifications>
|
||
|
|
[[nodiscard]] consteval bool valid_specifications(utils::types::TypeList<Specifications...>)
|
||
|
|
{
|
||
|
|
using namespace utils::dependencies;
|
||
|
|
constexpr bool declarations = (((!GeneratesState<Specifications>::value && std::same_as<typename Specifications::ModelDefinition::DependsOn, Reads<>> &&
|
||
|
|
std::same_as<typename Specifications::ModelDefinition::Affects, Changes<>>) || DimensionalScalarSpecification<Specifications>) && ...);
|
||
|
|
if constexpr (!declarations)
|
||
|
|
{
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return []<typename... Generated>(utils::types::TypeList<Generated...>)
|
||
|
|
{
|
||
|
|
using Coordinates = CombinedKeyList<KeyList<typename ResolvedSpecification<Generated, Bindings>::Coordinate>...>;
|
||
|
|
using Residuals = CombinedKeyList<KeyList<typename ResolvedSpecification<Generated, Bindings>::Constraint>...>;
|
||
|
|
return key_count_v<Coordinates> == sizeof...(Generated) && key_count_v<Residuals> == sizeof...(Generated) &&
|
||
|
|
(valid_specification_endpoints<Generated, Model, Values, Inputs, Rows, InactiveRows, Bindings>() && ...);
|
||
|
|
}(GeneratedSpecifications<Model>{});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @brief Validate declared derivative contracts without inferring zeros from missing providers. */
|
||
|
|
template <DimensionalScalarSpecification Specification, typename Couplings, typename Bindings>
|
||
|
|
[[nodiscard]] consteval bool specification_derivatives_available()
|
||
|
|
{
|
||
|
|
using namespace utils::dependencies;
|
||
|
|
using Endpoints = ResolvedSpecification<Specification, Bindings>;
|
||
|
|
return []<typename... Read, typename... Changed>(KeyList<Read...>, KeyList<Changed...>)
|
||
|
|
{
|
||
|
|
constexpr auto changed_row = []<typename Row>()
|
||
|
|
{
|
||
|
|
return ContainsKey<Derivative<Row, typename Endpoints::Coordinate>, Couplings> && (ContainsKey<Derivative<Row, Read>, Couplings> && ...);
|
||
|
|
};
|
||
|
|
return (ContainsKey<Derivative<typename Endpoints::Constraint, Read>, Couplings> && ...) && (changed_row.template operator()<Changed>() && ...);
|
||
|
|
}(typename Endpoints::Reads::Keys{}, typename Endpoints::Changes::Keys{});
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @brief Check each prescription against independently supplied derivative registrations. */
|
||
|
|
template <typename Couplings, typename Bindings, typename... Specifications>
|
||
|
|
[[nodiscard]] consteval bool specification_derivatives_available(utils::types::TypeList<Specifications...>)
|
||
|
|
{
|
||
|
|
return (specification_derivatives_available<Specifications, Couplings, Bindings>() && ...);
|
||
|
|
}
|
||
|
|
} // namespace detail
|
||
|
|
|
||
|
|
/** @brief Derive declared interior couplings from actual operands rather than a second physical sparsity table. */
|
||
|
|
template <ExecutableInteriorEquations Registry>
|
||
|
|
using DeclaredEquationCouplings = typename detail::InteriorCouplings<std::remove_cvref_t<Registry>>::Type;
|
||
|
|
|
||
|
|
/** @brief Validate physical ownership, available inputs and uniquely owned generated equations. */
|
||
|
|
template <typename Model, typename Values, typename Inputs, typename Rows, typename InactiveRows = utils::dependencies::KeyList<>, typename Bindings = DefaultSpecificationBindings>
|
||
|
|
concept SpecificationEndpointsValid = StellarModelType<Model> && utils::dependencies::IsKeyList<Values> && utils::dependencies::IsKeyList<Inputs> &&
|
||
|
|
utils::dependencies::IsKeyList<Rows> && utils::dependencies::IsKeyList<InactiveRows> && utils::dependencies::IsBindings<Bindings> &&
|
||
|
|
detail::valid_specifications<std::remove_cvref_t<Model>, Values, Inputs, Rows, InactiveRows, Bindings>(typename std::remove_cvref_t<Model>::SpecificationTypes{});
|
||
|
|
|
||
|
|
/** @brief Validate physical endpoints and every derivative in an explicitly declared contract. */
|
||
|
|
template <typename Model, typename Values, typename Rows, typename DeclaredCouplings, typename Bindings = DefaultSpecificationBindings>
|
||
|
|
concept SpecificationTopologyValid = SpecificationEndpointsValid<Model, Values, Values, Rows, utils::dependencies::KeyList<>, Bindings> &&
|
||
|
|
utils::dependencies::IsKeyList<DeclaredCouplings> && detail::specification_derivatives_available<DeclaredCouplings, Bindings>(detail::GeneratedSpecifications<std::remove_cvref_t<Model>>{});
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Require a registered implementation for every declared generated derivative, including explicit zeros.
|
||
|
|
* @note ImplementedCouplings must come from admitted providers. Missing methods never imply zero; this checks
|
||
|
|
* specification contributions only, leaving the equation backend's own execution contract independent.
|
||
|
|
*/
|
||
|
|
template <typename Model, typename Values, typename Rows, typename DeclaredCouplings, typename ImplementedCouplings, typename Bindings = DefaultSpecificationBindings>
|
||
|
|
concept SpecificationBackendAvailable = SpecificationTopologyValid<Model, Values, Rows, DeclaredCouplings, Bindings> &&
|
||
|
|
SpecificationTopologyValid<Model, Values, Rows, ImplementedCouplings, Bindings>;
|
||
|
|
} // namespace serif::model
|