Files
MeanField_SERiF/src/include/serif/model/validation.hpp

139 lines
9.3 KiB
C++
Raw Normal View History

#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