SERiF defines a so-called "model" subsystem. A model is a fully compile-time description of a problem. Note that this is a description not an evaluation tool. The basic idea is that since we have this robust description we can more easily serialize and be confident that others who load a model are getting the exact same thing. Further, this provides a convient place to do things like validate that all options are compatible, do some limited initial construction of the needed computational graph, allocate needed memory, etc... Some of the stuff that might initially seem to belong to a model will be in the discritization system though (e.g. FEM object lifetimes)
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
|