Files
MeanField/tests/field/field_registry.cpp
2026-09-06 10:15:00 -04:00

434 lines
16 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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(field::FieldTag<field::AngularVelocity>);
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(field::NonSpatialField<field::AngularVelocity>);
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>);
STATIC_REQUIRE(std::same_as<field::FieldSupportT<field::AngularVelocity>, 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);
}