feat(field-support): added field support system, mid migration

currently the barotope and the pressure force operator are migrated to the new support system
This commit is contained in:
2026-08-23 10:13:53 -04:00
parent dc912fd15e
commit 0f3ca8050b
137 changed files with 29975 additions and 16389 deletions

View File

@@ -0,0 +1,427 @@
#include <catch2/catch_test_macros.hpp>
#include <concepts>
#include <cstddef>
#include <string_view>
#include <type_traits>
import mean_field;
import test_helpers;
namespace field_registry_test_utils {
namespace field = mean_field::field;
namespace domain = mean_field::utils::domain;
namespace quadrature = mean_field::quadrature;
template <typename ListT> struct TypeListSize;
template <typename... Ts>
struct TypeListSize<field::TypeList<Ts...>> : std::integral_constant<std::size_t, sizeof...(Ts)> { };
template <typename ListT> inline constexpr std::size_t typeListSize = TypeListSize<ListT>::value;
struct MissingSupportField {
static constexpr std::string_view name = "missing_support";
using Quantities = field::TypeList<field::GlobalScalarQ>;
using Constraints = field::TypeList<>;
using FormList = field::TypeList<>;
};
struct InvalidSupportField {
static constexpr std::string_view name = "invalid_support";
struct InvalidSupport { };
using Support = InvalidSupport;
using Quantities = field::TypeList<field::GlobalScalarQ>;
using Constraints = field::TypeList<>;
using FormList = field::TypeList<>;
};
struct InvalidQuantityListField {
static constexpr std::string_view name = "invalid_quantity_list";
using Support = field::NonSpatialSupport;
using Quantities = field::TypeList<int>;
using Constraints = field::TypeList<>;
using FormList = field::TypeList<>;
};
struct InvalidFormListField {
static constexpr std::string_view name = "invalid_form_list";
using Support = field::NonSpatialSupport;
using Quantities = field::TypeList<field::GlobalScalarQ>;
using Constraints = field::TypeList<>;
using FormList = field::TypeList<int>;
};
} // namespace field_registry_test_utils
TEST_CASE(
"Field Registry Recognizes Every Production Field And Rejects Incomplete Definitions",
tags::unit &tags::field
) {
namespace field = mean_field::field;
STATIC_REQUIRE(field::FieldTag<field::Density>);
STATIC_REQUIRE(field::FieldTag<field::Gravity>);
STATIC_REQUIRE(field::FieldTag<field::Displacement>);
STATIC_REQUIRE(field::FieldTag<field::Enthalpy>);
STATIC_REQUIRE(field::FieldTag<field::BarotropicConstant>);
STATIC_REQUIRE_FALSE(field::FieldTag<field_registry_test_utils::MissingSupportField>);
STATIC_REQUIRE_FALSE(field::FieldTag<field_registry_test_utils::InvalidSupportField>);
STATIC_REQUIRE_FALSE(field::FieldTag<field_registry_test_utils::InvalidQuantityListField>);
STATIC_REQUIRE_FALSE(field::FieldTag<field_registry_test_utils::InvalidFormListField>);
CHECK(true);
}
TEST_CASE(
"Field Registry Assigns The Intended Semantic Support To Every Production Field",
tags::unit &tags::field
) {
namespace field = mean_field::field;
namespace domain = mean_field::utils::domain;
STATIC_REQUIRE(field::DomainSupportedField<field::Density>);
STATIC_REQUIRE(field::DomainSupportedField<field::Enthalpy>);
STATIC_REQUIRE(field::DomainSupportedField<field::Gravity>);
STATIC_REQUIRE(field::DomainSupportedField<field::Displacement>);
STATIC_REQUIRE(field::NonSpatialField<field::BarotropicConstant>);
STATIC_REQUIRE(std::same_as<field::FieldDomainT<field::Density>, domain::Stellar>);
STATIC_REQUIRE(std::same_as<field::FieldDomainT<field::Enthalpy>, domain::Stellar>);
STATIC_REQUIRE(std::same_as<field::FieldDomainT<field::Gravity>, domain::All>);
STATIC_REQUIRE(std::same_as<field::FieldDomainT<field::Displacement>, domain::All>);
STATIC_REQUIRE(std::same_as<field::FieldSupportT<field::BarotropicConstant>, field::NonSpatialSupport>);
CHECK(true);
}
TEST_CASE(
"Density Registry Definition Is Complete And Self Consistent",
tags::unit &tags::field
) {
namespace field = mean_field::field;
namespace quadrature = mean_field::quadrature;
CHECK(field::Density::name == std::string_view{"density"});
CHECK(field::Density::Scalar::symbol == std::string_view{"ρ"});
STATIC_REQUIRE(field::Density::scalarOrder == 2);
STATIC_REQUIRE(field::Density::Scalar::rankValue == 0);
STATIC_REQUIRE(field::Density::Scalar::familyOrder == field::Density::scalarOrder);
STATIC_REQUIRE(std::same_as<typename field::Density::Scalar::Space, field::L2>);
STATIC_REQUIRE(std::same_as<typename field::Density::Scalar::Relation, field::FieldRelation::Independent>);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Density::Quantities> == 1);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Density::Constraints> == 0);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Density::FormList> == 8);
STATIC_REQUIRE(field::Density::constraintsAreValid);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::ProjectionMass, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::ProjectionSource, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::EosClosureMass, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::MassConservation, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::MassNormalization, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::CenterOfMass, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::Quadrupole, field::Density::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Density::Form::ErrorNorm, field::Density::FormList>);
STATIC_REQUIRE(field::Density::Form::ProjectionMass::policyKey == quadrature::Term::density_projection);
STATIC_REQUIRE(field::Density::Form::ProjectionMass::dynamicOrderCount == 0);
STATIC_REQUIRE(
std::same_as<
typename field::Density::Form::ProjectionMass::Operands,
field::TypeList<field::Operand<field::Density::Scalar>, field::Operand<field::Density::Scalar>>>
);
STATIC_REQUIRE(field::Density::Form::ProjectionSource::dynamicOrderCount == 1);
STATIC_REQUIRE(field::Density::Form::EosClosureMass::policyKey == quadrature::Term::eos_closure);
STATIC_REQUIRE(field::Density::Form::MassConservation::policyKey == quadrature::Term::mass_conservation);
STATIC_REQUIRE(field::Density::Form::MassNormalization::policyKey == quadrature::Term::mass_normalization);
STATIC_REQUIRE(field::Density::Form::CenterOfMass::dynamicOrderCount == 1);
STATIC_REQUIRE(field::Density::Form::Quadrupole::dynamicOrderCount == 1);
CHECK(true);
}
TEST_CASE(
"Gravity Registry Defines A Stable Mixed RT L2 Pair And All Registered Forms",
tags::unit &tags::field
) {
namespace field = mean_field::field;
namespace quadrature = mean_field::quadrature;
CHECK(field::Gravity::name == std::string_view{"gravity"});
CHECK(field::Gravity::Potential::symbol == std::string_view{"φ"});
CHECK(field::Gravity::Flux::symbol == std::string_view{"∇φ"});
STATIC_REQUIRE(field::Gravity::potentialOrder == 2);
STATIC_REQUIRE(field::Gravity::fluxOrder == 2);
STATIC_REQUIRE(std::same_as<typename field::Gravity::Potential::Space, field::L2>);
STATIC_REQUIRE(std::same_as<typename field::Gravity::Flux::Space, field::RT>);
STATIC_REQUIRE(field::Gravity::Potential::rankValue == 0);
STATIC_REQUIRE(field::Gravity::Flux::rankValue == 1);
STATIC_REQUIRE(field::DerivedQuantity<field::Gravity::Flux>);
STATIC_REQUIRE(std::same_as<field::RelationTargetT<field::Gravity::Flux>, field::Gravity::Potential>);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Gravity::Quantities> == 2);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Gravity::Constraints> == 1);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Gravity::FormList> == 7);
STATIC_REQUIRE(field::Gravity::constraintsAreValid);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::HDivMass, field::Gravity::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::DivergenceCoupling, field::Gravity::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::Boundary, field::Gravity::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::SourceLinear, field::Gravity::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::SourceProjection, field::Gravity::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::PotentialErrorNorm, field::Gravity::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Gravity::Form::FluxErrorNorm, field::Gravity::FormList>);
STATIC_REQUIRE(field::Gravity::Form::HDivMass::policyKey == quadrature::Term::gravity_hdiv_mass);
STATIC_REQUIRE(
std::same_as<
typename field::Gravity::Form::HDivMass::Operands,
field::TypeList<field::Operand<field::Gravity::Flux>, field::Operand<field::Gravity::Flux>>>
);
STATIC_REQUIRE(
std::same_as<
typename field::Gravity::Form::DivergenceCoupling::Operands,
field::TypeList<
field::Operand<field::Gravity::Flux, field::FieldOperation::Divergence>,
field::Operand<field::Gravity::Potential>>>
);
STATIC_REQUIRE(
std::same_as<
typename field::Gravity::Form::Boundary::Operands,
field::TypeList<
field::Operand<field::Gravity::Flux, field::FieldOperation::NormalTrace>,
field::Operand<field::Gravity::Flux, field::FieldOperation::NormalTrace>>>
);
STATIC_REQUIRE(
std::same_as<
typename field::Gravity::Form::SourceLinear::Operands,
field::TypeList<field::Operand<field::Density::Scalar>, field::Operand<field::Gravity::Potential>>>
);
CHECK(true);
}
TEST_CASE(
"Displacement Registry Preserves Vector H1 Geometry And Force Forms",
tags::unit &tags::field
) {
namespace field = mean_field::field;
namespace quadrature = mean_field::quadrature;
CHECK(field::Displacement::name == std::string_view{"displacement"});
CHECK(field::Displacement::Vector::symbol == std::string_view{"d"});
STATIC_REQUIRE(field::Displacement::vectorOrder == 3);
STATIC_REQUIRE(field::Displacement::Vector::rankValue == 1);
STATIC_REQUIRE(std::same_as<typename field::Displacement::Vector::Space, field::H1>);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Displacement::FormList> == 4);
STATIC_REQUIRE(field::Displacement::constraintsAreValid);
STATIC_REQUIRE(field::Displacement::Form::MeshExtension::policyKey == quadrature::Term::mesh_extension);
STATIC_REQUIRE(
std::same_as<
typename field::Displacement::Form::MeshExtension::Operands,
field::TypeList<
field::Operand<field::Displacement::Vector, field::FieldOperation::Gradient>,
field::Operand<field::Displacement::Vector, field::FieldOperation::Gradient>>>
);
STATIC_REQUIRE(
std::same_as<
typename field::Displacement::Form::GravityForce::Operands,
field::TypeList<
field::Operand<field::Density::Scalar>, field::Operand<field::Gravity::Flux>,
field::Operand<field::Displacement::Vector, field::FieldOperation::Gradient>,
field::Operand<field::Displacement::Vector>>>
);
STATIC_REQUIRE(field::Displacement::Form::CentrifugalForce::dynamicOrderCount == 1);
STATIC_REQUIRE(field::Displacement::Form::CentrifugalForce::policyKey == quadrature::Term::centrifugal);
CHECK(true);
}
TEST_CASE(
"Enthalpy Registry Preserves Continuous Stellar Field And Coupled Forms",
tags::unit &tags::field
) {
namespace field = mean_field::field;
namespace quadrature = mean_field::quadrature;
CHECK(field::Enthalpy::name == std::string_view{"specific_enthalpy"});
CHECK(field::Enthalpy::Scalar::symbol == std::string_view{"h"});
STATIC_REQUIRE(field::Enthalpy::scalarOrder == 3);
STATIC_REQUIRE(field::Enthalpy::Scalar::rankValue == 0);
STATIC_REQUIRE(std::same_as<typename field::Enthalpy::Scalar::Space, field::H1>);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::Enthalpy::FormList> == 9);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::EosClosureSource, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::EquilibriumEnthalpy, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::EquilibriumGravity, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::EquilibriumRotation, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::EquilibriumConstant, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::IsobaricSurface, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::PressureIntegral, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::PressureForce, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::typeListContains<field::Enthalpy::Form::ErrorNorm, field::Enthalpy::FormList>);
STATIC_REQUIRE(field::Enthalpy::Form::EosClosureSource::dynamicOrderCount == 1);
STATIC_REQUIRE(
std::same_as<
typename field::Enthalpy::Form::EosClosureSource::Operands,
field::TypeList<field::Operand<field::Enthalpy::Scalar>, field::Operand<field::Density::Scalar>>>
);
STATIC_REQUIRE(
std::same_as<
typename field::Enthalpy::Form::EquilibriumGravity::Operands,
field::TypeList<field::Operand<field::Gravity::Potential>, field::Operand<field::Enthalpy::Scalar>>>
);
STATIC_REQUIRE(
std::same_as<
typename field::Enthalpy::Form::EquilibriumConstant::Operands,
field::TypeList<field::Operand<field::BarotropicConstant::Scalar>, field::Operand<field::Enthalpy::Scalar>>>
);
STATIC_REQUIRE(field::Enthalpy::Form::IsobaricSurface::policyKey == quadrature::Term::isobaric_surface);
STATIC_REQUIRE(field::Enthalpy::Form::PressureIntegral::policyKey == quadrature::Term::pressure_integral);
STATIC_REQUIRE(field::Enthalpy::Form::PressureForce::policyKey == quadrature::Term::pressure_force);
STATIC_REQUIRE(
std::same_as<
typename field::Enthalpy::Form::PressureForce::Operands,
field::TypeList<
field::Operand<field::Enthalpy::Scalar>,
field::Operand<field::Displacement::Vector, field::FieldOperation::Gradient>>>
);
CHECK(true);
}
TEST_CASE(
"Barotropic Constant Registry Is A Non Spatial Unit Sized Scalar",
tags::unit &tags::field
) {
namespace field = mean_field::field;
CHECK(field::BarotropicConstant::name == std::string_view{"barotropic_constant"});
CHECK(field::BarotropicConstant::Scalar::symbol == std::string_view{"C"});
STATIC_REQUIRE(field::GlobalScalarQuantity<field::BarotropicConstant::Scalar>);
STATIC_REQUIRE(field::BarotropicConstant::Scalar::staticBlockSize == 1);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::BarotropicConstant::Quantities> == 1);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::BarotropicConstant::Constraints> == 0);
STATIC_REQUIRE(field_registry_test_utils::typeListSize<field::BarotropicConstant::FormList> == 0);
STATIC_REQUIRE(field::BarotropicConstant::constraintsAreValid);
CHECK(true);
}