1274 lines
62 KiB
C++
1274 lines
62 KiB
C++
#include <algorithm>
|
|
#include <array>
|
|
#include <concepts>
|
|
#include <limits>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <string_view>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <catch2/matchers/catch_matchers.hpp>
|
|
#include <mfem.hpp>
|
|
|
|
import mean_field;
|
|
import test_helpers;
|
|
|
|
namespace {
|
|
template <typename ManifestType, typename Specification>
|
|
concept HasRootManifestSpecificationDescriptor = requires(const ManifestType &manifest) {
|
|
{
|
|
manifest.template specification<Specification>()
|
|
} -> std::same_as<const mean_field::operators::RootConstraintDescriptor &>;
|
|
};
|
|
|
|
template <typename View, typename Term>
|
|
concept CanMutateManifestBlock = requires(View &view, const Term &term) { view.block(term)(0) = 1.0; };
|
|
|
|
template <typename ManifestType>
|
|
concept HasLvalueRootViewFactories =
|
|
requires(const ManifestType &manifest, mfem::Vector &mutableVector, const mfem::Vector &readOnlyVector) {
|
|
{ manifest.stateView(mutableVector) } -> std::same_as<typename ManifestType::MutableStateView>;
|
|
{ manifest.stateView(readOnlyVector) } -> std::same_as<typename ManifestType::StateView>;
|
|
{ manifest.directionView(readOnlyVector) } -> std::same_as<typename ManifestType::DirectionView>;
|
|
{ manifest.residualView(mutableVector) } -> std::same_as<typename ManifestType::RootResidualView>;
|
|
};
|
|
|
|
template <typename ManifestType>
|
|
concept StateViewAcceptsTemporaryVector =
|
|
requires(const ManifestType &manifest) { manifest.stateView(std::declval<mfem::Vector &&>()); };
|
|
|
|
template <typename ManifestType>
|
|
concept StateViewAcceptsConstTemporaryVector =
|
|
requires(const ManifestType &manifest) { manifest.stateView(std::declval<const mfem::Vector &&>()); };
|
|
|
|
template <typename ManifestType>
|
|
concept DirectionViewAcceptsTemporaryVector =
|
|
requires(const ManifestType &manifest) { manifest.directionView(std::declval<mfem::Vector &&>()); };
|
|
|
|
template <typename ManifestType>
|
|
concept DirectionViewAcceptsConstTemporaryVector =
|
|
requires(const ManifestType &manifest) { manifest.directionView(std::declval<const mfem::Vector &&>()); };
|
|
|
|
template <typename ManifestType>
|
|
concept ResidualViewAcceptsTemporaryVector =
|
|
requires(const ManifestType &manifest) { manifest.residualView(std::declval<mfem::Vector &&>()); };
|
|
|
|
template <typename ManifestType>
|
|
concept ResidualViewAcceptsConstTemporaryVector =
|
|
requires(const ManifestType &manifest) { manifest.residualView(std::declval<const mfem::Vector &&>()); };
|
|
|
|
template <typename ManifestType>
|
|
concept TemporaryManifestProvidesStateView =
|
|
requires(mfem::Vector &vector) { std::declval<ManifestType &&>().stateView(vector); };
|
|
|
|
template <typename ManifestType>
|
|
concept TemporaryManifestProvidesReadOnlyStateView =
|
|
requires(const mfem::Vector &vector) { std::declval<ManifestType &&>().stateView(vector); };
|
|
|
|
template <typename ManifestType>
|
|
concept TemporaryManifestProvidesDirectionView =
|
|
requires(const mfem::Vector &vector) { std::declval<ManifestType &&>().directionView(vector); };
|
|
|
|
template <typename ManifestType>
|
|
concept TemporaryManifestProvidesResidualView =
|
|
requires(mfem::Vector &vector) { std::declval<ManifestType &&>().residualView(vector); };
|
|
|
|
using CanonicalModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::models::FixedTotalMass,
|
|
mean_field::surface::Isobaric>>;
|
|
|
|
using PermutedModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::models::FixedTotalMass,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::eos::Polytrope>>;
|
|
|
|
using CentralDensityModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::models::FixedCentralDensity,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::eos::Polytrope,
|
|
mean_field::models::FixedTotalMass>>;
|
|
|
|
using Form = mean_field::operators::CompiledStellarEquilibriumForm<CanonicalModel>;
|
|
using JacobianForm = mean_field::operators::CompiledStellarEquilibriumJacobianForm<CanonicalModel>;
|
|
using Manifest = mean_field::operators::CompiledRootManifest<CanonicalModel, Form, JacobianForm>;
|
|
using CentralForm = mean_field::utils::blocks::central_density_bordered_stellar_equilibrium_form;
|
|
using CentralJacobianForm = mean_field::utils::blocks::central_density_bordered_stellar_equilibrium_jacobian_form;
|
|
using CentralManifest =
|
|
mean_field::operators::CompiledRootManifest<CentralDensityModel, CentralForm, CentralJacobianForm>;
|
|
|
|
using AngularMomentumModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
mean_field::models::FixedAngularMomentum>>;
|
|
using AngularMomentumForm = mean_field::operators::CompiledStellarEquilibriumForm<AngularMomentumModel>;
|
|
using AngularMomentumJacobian = mean_field::operators::CompiledStellarEquilibriumJacobianForm<AngularMomentumModel>;
|
|
using AngularMomentumManifest =
|
|
mean_field::operators::CompiledRootManifest<AngularMomentumModel, AngularMomentumForm, AngularMomentumJacobian>;
|
|
|
|
class MockFixedMagneticSpecificEnergy final {
|
|
public:
|
|
struct Parameters final {
|
|
mean_field::dimensions::SpecificEnergyValue target;
|
|
};
|
|
|
|
using ScalarDimensionless = mean_field::models::CoordinateNormalization<
|
|
mean_field::models::RieszTopology::global_scalar,
|
|
mean_field::models::PhysicalScaleLaw::dimensionless>;
|
|
using ScalarSpecificEnergy = mean_field::models::CoordinateNormalization<
|
|
mean_field::models::RieszTopology::global_scalar,
|
|
mean_field::models::PhysicalScaleLaw::specific_energy>;
|
|
using ModelDefinition = mean_field::integral::FixedWithPhysicalCoordinate<
|
|
MockFixedMagneticSpecificEnergy,
|
|
"RootManifestMockFixedMagneticSpecificEnergy",
|
|
mean_field::models::ModelTypeList<
|
|
mean_field::utils::blocks::density::mass::value,
|
|
mean_field::utils::blocks::surface_deformation::parameters::value>,
|
|
mean_field::models::ModelTypeList<mean_field::utils::blocks::enthalpy::specific::residual>,
|
|
mean_field::models::GeneratedNormalization<ScalarDimensionless, ScalarSpecificEnergy>,
|
|
mean_field::models::GeneratedManifest<
|
|
"mock_magnetic_specific_energy.amplitude",
|
|
"a_B",
|
|
"mock_magnetic_specific_energy.residual",
|
|
"R_EB",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
explicit MockFixedMagneticSpecificEnergy(const Parameters parameters) noexcept : m_target(parameters.target) {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::SpecificEnergyValue target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
private:
|
|
mean_field::dimensions::SpecificEnergyValue m_target;
|
|
};
|
|
|
|
template <mean_field::models::FixedString Name, typename ManifestDefinition>
|
|
class MockManifestIdentityConstraint final {
|
|
public:
|
|
struct Parameters final {
|
|
mean_field::dimensions::SpecificEnergyValue target;
|
|
};
|
|
|
|
using ModelDefinition = mean_field::integral::FixedWithPhysicalCoordinate<
|
|
MockManifestIdentityConstraint,
|
|
Name,
|
|
mean_field::models::DependsOn<mean_field::models::stellar::state::Density>,
|
|
mean_field::models::Affects<mean_field::models::stellar::equation::HydrostaticBalance>,
|
|
mean_field::models::GlobalScalarNormalization<
|
|
mean_field::models::PhysicalScaleLaw::dimensionless,
|
|
mean_field::models::PhysicalScaleLaw::specific_energy>,
|
|
ManifestDefinition>;
|
|
|
|
explicit MockManifestIdentityConstraint(Parameters parameters) noexcept : m_target(parameters.target) {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::SpecificEnergyValue target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
private:
|
|
mean_field::dimensions::SpecificEnergyValue m_target;
|
|
};
|
|
|
|
struct NonConstexprGeneratedManifest final {
|
|
inline static std::string_view valueStableId = "nonconstexpr_manifest.coordinate";
|
|
static constexpr std::string_view valueSymbol = "q_nc";
|
|
static constexpr std::string_view residualStableId = "nonconstexpr_manifest.residual";
|
|
static constexpr std::string_view residualSymbol = "R_nc";
|
|
static constexpr std::string_view targetUnits = "specific_energy";
|
|
static constexpr std::string_view residualUnits = "specific_energy";
|
|
static constexpr bool available = true;
|
|
};
|
|
|
|
struct ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view valueStableId = "valid_structural_manifest.coordinate";
|
|
static constexpr std::string_view valueSymbol = "q_valid";
|
|
static constexpr std::string_view residualStableId = "valid_structural_manifest.residual";
|
|
static constexpr std::string_view residualSymbol = "R_valid";
|
|
static constexpr std::string_view targetUnits = "specific_energy";
|
|
static constexpr std::string_view residualUnits = "specific_energy";
|
|
static constexpr bool available = true;
|
|
};
|
|
|
|
struct EmptyValueStableIdManifest final : ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view valueStableId = "";
|
|
};
|
|
|
|
struct EmptyValueSymbolManifest final : ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view valueSymbol = "";
|
|
};
|
|
|
|
struct EmptyResidualStableIdManifest final : ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view residualStableId = "";
|
|
};
|
|
|
|
struct EmptyResidualSymbolManifest final : ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view residualSymbol = "";
|
|
};
|
|
|
|
struct EmptyTargetUnitsManifest final : ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view targetUnits = "";
|
|
};
|
|
|
|
struct EmptyResidualUnitsManifest final : ValidStructuralGeneratedManifest {
|
|
static constexpr std::string_view residualUnits = "";
|
|
};
|
|
|
|
struct NonConstexprGeneratedUnitsManifest final : ValidStructuralGeneratedManifest {
|
|
inline static std::string_view targetUnits = "specific_energy";
|
|
};
|
|
|
|
using MockGeneratedValueIdCollision = MockManifestIdentityConstraint<
|
|
"RootManifestMockGeneratedValueIdCollision",
|
|
mean_field::models::GeneratedManifest<
|
|
"fixed_total_mass.multiplier",
|
|
"C_value_collision",
|
|
"mock_generated_value_collision.residual",
|
|
"R_value_collision",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
using MockGeneratedResidualIdCollision = MockManifestIdentityConstraint<
|
|
"RootManifestMockGeneratedResidualIdCollision",
|
|
mean_field::models::GeneratedManifest<
|
|
"mock_generated_residual_collision.coordinate",
|
|
"q_residual_collision",
|
|
"fixed_total_mass.residual",
|
|
"R_residual_collision",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
using MockPhysicalValueIdCollision = MockManifestIdentityConstraint<
|
|
"RootManifestMockPhysicalValueIdCollision",
|
|
mean_field::models::GeneratedManifest<
|
|
"density",
|
|
"q_physical_value_collision",
|
|
"mock_physical_value_collision.residual",
|
|
"R_physical_value_collision",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
using MockPhysicalResidualIdCollision = MockManifestIdentityConstraint<
|
|
"RootManifestMockPhysicalResidualIdCollision",
|
|
mean_field::models::GeneratedManifest<
|
|
"mock_physical_residual_collision.coordinate",
|
|
"q_physical_residual_collision",
|
|
"hydrostatic_balance",
|
|
"R_physical_residual_collision",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
using MockReusedManifestSymbols = MockManifestIdentityConstraint<
|
|
"RootManifestMockReusedSymbols",
|
|
mean_field::models::GeneratedManifest<
|
|
"mock_reused_symbols.coordinate",
|
|
"C",
|
|
"mock_reused_symbols.residual",
|
|
"R_M",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
using MockNonConstexprManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockNonConstexprManifest", NonConstexprGeneratedManifest>;
|
|
|
|
using MockValidStructuralManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockValidStructuralManifest", ValidStructuralGeneratedManifest>;
|
|
using MockEmptyValueStableIdManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockEmptyValueStableIdManifest", EmptyValueStableIdManifest>;
|
|
using MockEmptyValueSymbolManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockEmptyValueSymbolManifest", EmptyValueSymbolManifest>;
|
|
using MockEmptyResidualStableIdManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockEmptyResidualStableIdManifest", EmptyResidualStableIdManifest>;
|
|
using MockEmptyResidualSymbolManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockEmptyResidualSymbolManifest", EmptyResidualSymbolManifest>;
|
|
using MockEmptyTargetUnitsManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockEmptyTargetUnitsManifest", EmptyTargetUnitsManifest>;
|
|
using MockEmptyResidualUnitsManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockEmptyResidualUnitsManifest", EmptyResidualUnitsManifest>;
|
|
using MockNonConstexprUnitsManifest =
|
|
MockManifestIdentityConstraint<"RootManifestMockNonConstexprUnitsManifest", NonConstexprGeneratedUnitsManifest>;
|
|
|
|
struct AlternatingManifestTarget final {
|
|
double first;
|
|
double subsequent;
|
|
mutable int evaluations{0};
|
|
|
|
[[nodiscard]] double value() const noexcept {
|
|
return evaluations++ == 0 ? first : subsequent;
|
|
}
|
|
};
|
|
|
|
class MockInconsistentManifestScale final {
|
|
public:
|
|
struct Parameters final {
|
|
double first;
|
|
double subsequent;
|
|
};
|
|
|
|
using ModelDefinition = mean_field::integral::FixedWithPhysicalCoordinate<
|
|
MockInconsistentManifestScale,
|
|
"RootManifestMockInconsistentScale",
|
|
mean_field::models::DependsOn<mean_field::models::stellar::state::Density>,
|
|
mean_field::models::Affects<mean_field::models::stellar::equation::HydrostaticBalance>,
|
|
mean_field::models::GlobalScalarNormalization<
|
|
mean_field::models::PhysicalScaleLaw::dimensionless,
|
|
mean_field::models::PhysicalScaleLaw::specific_energy>,
|
|
ValidStructuralGeneratedManifest>;
|
|
|
|
explicit MockInconsistentManifestScale(const Parameters parameters) noexcept
|
|
: m_target{
|
|
parameters.first,
|
|
parameters.subsequent
|
|
} {
|
|
}
|
|
|
|
[[nodiscard]] const AlternatingManifestTarget &target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
private:
|
|
AlternatingManifestTarget m_target;
|
|
};
|
|
|
|
struct NonConvertibleTarget final {
|
|
struct Magnitude final { };
|
|
|
|
[[nodiscard]] constexpr Magnitude value() const noexcept {
|
|
return {};
|
|
}
|
|
};
|
|
|
|
class MockNonConvertibleManifestTarget final {
|
|
public:
|
|
struct Parameters final { };
|
|
|
|
using ScalarDescription = mean_field::stellar::ScalarConstraint<
|
|
mean_field::dimensions::quantity::SpecificEnergy,
|
|
mean_field::dimensions::quantity::Dimensionless,
|
|
mean_field::dimensions::quantity::SpecificEnergy,
|
|
"mock_nonconvertible_target.coordinate",
|
|
"q_bad",
|
|
"mock_nonconvertible_target.residual",
|
|
"R_bad">;
|
|
using ModelDefinition = mean_field::integral::FixedScalarWithPhysicalCoordinate<
|
|
MockNonConvertibleManifestTarget,
|
|
"RootManifestMockNonConvertibleTarget",
|
|
mean_field::stellar::Reads<mean_field::stellar::state::Density>,
|
|
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
|
|
ScalarDescription>;
|
|
|
|
explicit MockNonConvertibleManifestTarget(Parameters) noexcept {
|
|
}
|
|
|
|
[[nodiscard]] constexpr NonConvertibleTarget target() const noexcept {
|
|
return {};
|
|
}
|
|
};
|
|
|
|
class MockMismatchedManifestWithoutResidualReference final {
|
|
public:
|
|
struct Parameters final {
|
|
mean_field::dimensions::DensityValue target;
|
|
};
|
|
|
|
using ScalarDescription = mean_field::stellar::ScalarConstraint<
|
|
mean_field::dimensions::quantity::Density,
|
|
mean_field::dimensions::quantity::Dimensionless,
|
|
mean_field::dimensions::quantity::SpecificEnergy,
|
|
"mock_mismatched_without_reference.coordinate",
|
|
"q_missing_ref",
|
|
"mock_mismatched_without_reference.residual",
|
|
"R_missing_ref">;
|
|
using ModelDefinition = mean_field::integral::FixedScalarWithPhysicalCoordinate<
|
|
MockMismatchedManifestWithoutResidualReference,
|
|
"RootManifestMockMismatchedWithoutResidualReference",
|
|
mean_field::stellar::Reads<mean_field::stellar::state::Density>,
|
|
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
|
|
ScalarDescription>;
|
|
|
|
explicit MockMismatchedManifestWithoutResidualReference(const Parameters parameters) noexcept
|
|
: m_target(parameters.target) {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::DensityValue target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
private:
|
|
mean_field::dimensions::DensityValue m_target;
|
|
};
|
|
|
|
class MockMismatchedManifestWithResidualReference final {
|
|
public:
|
|
struct Parameters final {
|
|
mean_field::dimensions::DensityValue target;
|
|
mean_field::dimensions::SpecificEnergyValue residualReference;
|
|
};
|
|
|
|
using ScalarDescription = mean_field::stellar::ScalarConstraint<
|
|
mean_field::dimensions::quantity::Density,
|
|
mean_field::dimensions::quantity::Dimensionless,
|
|
mean_field::dimensions::quantity::SpecificEnergy,
|
|
"mock_mismatched_with_reference.coordinate",
|
|
"q_ref",
|
|
"mock_mismatched_with_reference.residual",
|
|
"R_ref">;
|
|
using ModelDefinition = mean_field::integral::FixedScalarWithPhysicalCoordinate<
|
|
MockMismatchedManifestWithResidualReference,
|
|
"RootManifestMockMismatchedWithResidualReference",
|
|
mean_field::stellar::Reads<mean_field::stellar::state::Density>,
|
|
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
|
|
ScalarDescription>;
|
|
|
|
explicit MockMismatchedManifestWithResidualReference(const Parameters parameters) noexcept
|
|
: m_target(parameters.target),
|
|
m_residualReference(parameters.residualReference) {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::DensityValue target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::SpecificEnergyValue residualReference() const noexcept {
|
|
return m_residualReference;
|
|
}
|
|
|
|
private:
|
|
mean_field::dimensions::DensityValue m_target;
|
|
mean_field::dimensions::SpecificEnergyValue m_residualReference;
|
|
};
|
|
|
|
class MockMismatchedManifestWithWrongResidualReference final {
|
|
public:
|
|
struct Parameters final {
|
|
mean_field::dimensions::DensityValue target;
|
|
};
|
|
|
|
using ScalarDescription = mean_field::stellar::ScalarConstraint<
|
|
mean_field::dimensions::quantity::Density,
|
|
mean_field::dimensions::quantity::Dimensionless,
|
|
mean_field::dimensions::quantity::SpecificEnergy,
|
|
"mock_mismatched_wrong_reference.coordinate",
|
|
"q_wrong_ref",
|
|
"mock_mismatched_wrong_reference.residual",
|
|
"R_wrong_ref">;
|
|
using ModelDefinition = mean_field::integral::FixedScalarWithPhysicalCoordinate<
|
|
MockMismatchedManifestWithWrongResidualReference,
|
|
"RootManifestMockMismatchedWithWrongResidualReference",
|
|
mean_field::stellar::Reads<mean_field::stellar::state::Density>,
|
|
mean_field::stellar::Changes<mean_field::stellar::equation::HydrostaticBalance>,
|
|
ScalarDescription>;
|
|
|
|
explicit MockMismatchedManifestWithWrongResidualReference(const Parameters parameters) noexcept
|
|
: m_target(parameters.target) {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::DensityValue target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::DensityValue residualReference() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
private:
|
|
mean_field::dimensions::DensityValue m_target;
|
|
};
|
|
|
|
class MockMissingManifest final {
|
|
public:
|
|
struct Parameters final { };
|
|
|
|
using ModelDefinition = mean_field::integral::FixedWithPhysicalCoordinate<
|
|
MockMissingManifest,
|
|
"RootManifestMockMissingManifest",
|
|
mean_field::models::ModelTypeList<mean_field::utils::blocks::density::mass::value>,
|
|
mean_field::models::ModelTypeList<mean_field::utils::blocks::enthalpy::specific::residual>>;
|
|
|
|
explicit MockMissingManifest(Parameters) noexcept {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::SpecificEnergyValue target() const noexcept {
|
|
return mean_field::dimensions::SpecificEnergyValue{1.0};
|
|
}
|
|
};
|
|
|
|
class MockUncompiledSurface final {
|
|
public:
|
|
struct Parameters final { };
|
|
using ModelDefinition =
|
|
mean_field::surface::BoundaryCondition<MockUncompiledSurface, "RootManifestMockUncompiledSurface">;
|
|
|
|
explicit MockUncompiledSurface(Parameters) noexcept {
|
|
}
|
|
};
|
|
|
|
class MockInvariantNamedLikeSurface final {
|
|
public:
|
|
struct Parameters final {
|
|
mean_field::dimensions::SpecificEnergyValue target;
|
|
};
|
|
|
|
using ModelDefinition = mean_field::integral::FixedWithPhysicalCoordinate<
|
|
MockInvariantNamedLikeSurface,
|
|
"IsobaricSurface",
|
|
mean_field::models::DependsOn<mean_field::models::stellar::state::Density>,
|
|
mean_field::models::Affects<mean_field::models::stellar::equation::HydrostaticBalance>,
|
|
mean_field::models::GlobalScalarNormalization<
|
|
mean_field::models::PhysicalScaleLaw::dimensionless,
|
|
mean_field::models::PhysicalScaleLaw::specific_energy>,
|
|
mean_field::models::GeneratedManifest<
|
|
"same_name_invariant.coordinate",
|
|
"q_same",
|
|
"same_name_invariant.residual",
|
|
"R_same",
|
|
"specific_energy",
|
|
"specific_energy">>;
|
|
|
|
explicit MockInvariantNamedLikeSurface(Parameters parameters) noexcept : m_target(parameters.target) {
|
|
}
|
|
|
|
[[nodiscard]] mean_field::dimensions::SpecificEnergyValue target() const noexcept {
|
|
return m_target;
|
|
}
|
|
|
|
private:
|
|
mean_field::dimensions::SpecificEnergyValue m_target;
|
|
};
|
|
|
|
using GenericManifestModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
MockFixedMagneticSpecificEnergy>>;
|
|
using GenericManifestForm = mean_field::operators::CompiledStellarEquilibriumForm<GenericManifestModel>;
|
|
using GenericManifestJacobian = mean_field::operators::CompiledStellarEquilibriumJacobianForm<GenericManifestModel>;
|
|
using GenericManifest = mean_field::operators::
|
|
EquilibriumSystemManifest<GenericManifestModel, GenericManifestForm, GenericManifestJacobian>;
|
|
|
|
using InconsistentScaleModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
MockInconsistentManifestScale>>;
|
|
using InconsistentScaleForm = mean_field::operators::CompiledStellarEquilibriumForm<InconsistentScaleModel>;
|
|
using InconsistentScaleJacobian =
|
|
mean_field::operators::CompiledStellarEquilibriumJacobianForm<InconsistentScaleModel>;
|
|
using InconsistentScaleManifest = mean_field::operators::
|
|
EquilibriumSystemManifest<InconsistentScaleModel, InconsistentScaleForm, InconsistentScaleJacobian>;
|
|
|
|
using NonConvertibleTargetModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
MockNonConvertibleManifestTarget>>;
|
|
using NonConvertibleTargetForm = mean_field::operators::CompiledStellarEquilibriumForm<NonConvertibleTargetModel>;
|
|
|
|
using MissingManifestModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
MockMissingManifest>>;
|
|
using MissingManifestForm = mean_field::operators::CompiledStellarEquilibriumForm<MissingManifestModel>;
|
|
|
|
using UncompiledSurfaceModel = mean_field::model::StellarModel<
|
|
mean_field::models::
|
|
SpecificationSet<mean_field::eos::Polytrope, MockUncompiledSurface, mean_field::models::FixedTotalMass>>;
|
|
using UncompiledSurfaceForm = mean_field::operators::CompiledStellarEquilibriumForm<UncompiledSurfaceModel>;
|
|
using UncompiledSurfaceJacobian =
|
|
mean_field::operators::CompiledStellarEquilibriumJacobianForm<UncompiledSurfaceModel>;
|
|
using UncompiledSurfaceManifest = mean_field::operators::
|
|
EquilibriumSystemManifest<UncompiledSurfaceModel, UncompiledSurfaceForm, UncompiledSurfaceJacobian>;
|
|
|
|
using CrossRoleNameCollisionModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
MockInvariantNamedLikeSurface>>;
|
|
using CrossRoleNameCollisionForm =
|
|
mean_field::operators::CompiledStellarEquilibriumForm<CrossRoleNameCollisionModel>;
|
|
using CrossRoleNameCollisionJacobian =
|
|
mean_field::operators::CompiledStellarEquilibriumJacobianForm<CrossRoleNameCollisionModel>;
|
|
using CrossRoleNameCollisionManifest = mean_field::operators::EquilibriumSystemManifest<
|
|
CrossRoleNameCollisionModel,
|
|
CrossRoleNameCollisionForm,
|
|
CrossRoleNameCollisionJacobian>;
|
|
|
|
template <typename Specification>
|
|
using ManifestExtensionModel = mean_field::model::StellarModel<mean_field::models::SpecificationSet<
|
|
mean_field::eos::Polytrope,
|
|
mean_field::surface::Isobaric,
|
|
mean_field::models::FixedTotalMass,
|
|
Specification>>;
|
|
|
|
template <typename Specification>
|
|
using ManifestExtensionForm =
|
|
mean_field::operators::CompiledStellarEquilibriumForm<ManifestExtensionModel<Specification>>;
|
|
|
|
using MissingResidualReferenceModel = ManifestExtensionModel<MockMismatchedManifestWithoutResidualReference>;
|
|
using MissingResidualReferenceForm = ManifestExtensionForm<MockMismatchedManifestWithoutResidualReference>;
|
|
using WrongResidualReferenceModel = ManifestExtensionModel<MockMismatchedManifestWithWrongResidualReference>;
|
|
using WrongResidualReferenceForm = ManifestExtensionForm<MockMismatchedManifestWithWrongResidualReference>;
|
|
using DistinctResidualReferenceModel = ManifestExtensionModel<MockMismatchedManifestWithResidualReference>;
|
|
using DistinctResidualReferenceForm = ManifestExtensionForm<MockMismatchedManifestWithResidualReference>;
|
|
using DistinctResidualReferenceJacobian =
|
|
mean_field::operators::CompiledStellarEquilibriumJacobianForm<DistinctResidualReferenceModel>;
|
|
using DistinctResidualReferenceManifest = mean_field::operators::EquilibriumSystemManifest<
|
|
DistinctResidualReferenceModel,
|
|
DistinctResidualReferenceForm,
|
|
DistinctResidualReferenceJacobian>;
|
|
|
|
[[nodiscard]] Manifest make_manifest() {
|
|
const std::array<int, Form::value_block_count> valueSizes{2, 3, 4, 5, 6, 1};
|
|
const std::array<int, Form::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1};
|
|
const CanonicalModel model{
|
|
mean_field::eos::Polytrope{1.0, 0.25},
|
|
mean_field::surface::Isobaric{mean_field::dimensions::PressureValue{0.125}},
|
|
mean_field::models::FixedTotalMass{mean_field::dimensions::MassValue{2.5}}
|
|
};
|
|
return {valueSizes, residualSizes, model, 3};
|
|
}
|
|
} // namespace
|
|
|
|
TEST_CASE(
|
|
"Manifest Capability Rejects Malformed Targets And Foreign Generated Blocks",
|
|
"[root-manifest][type-contract][sfinae]"
|
|
) {
|
|
using namespace mean_field;
|
|
|
|
STATIC_CHECK(models::ModelSpecification<MockNonConvertibleManifestTarget>);
|
|
STATIC_CHECK_FALSE(std::convertible_to<NonConvertibleTarget::Magnitude, double>);
|
|
STATIC_CHECK_FALSE(models::CompleteGeneratedScalarDimensionsFor<MockNonConvertibleManifestTarget>);
|
|
STATIC_CHECK_FALSE(models::CompleteGeneratedNormalizationFor<MockNonConvertibleManifestTarget>);
|
|
STATIC_CHECK_FALSE(models::CompleteGeneratedManifestFor<MockNonConvertibleManifestTarget>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<NonConvertibleTargetModel>);
|
|
STATIC_CHECK_FALSE(operators::CompilableRootManifestFor<NonConvertibleTargetModel, NonConvertibleTargetForm>);
|
|
|
|
// A typed target may intentionally differ from the equation's residual
|
|
// quantity, but then the manifest needs a residual-valued physical
|
|
// reference. Absence and the wrong quantity are both rejected without a
|
|
// hard template error.
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockMismatchedManifestWithoutResidualReference>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockMismatchedManifestWithWrongResidualReference>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockMismatchedManifestWithResidualReference>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<MissingResidualReferenceModel>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<WrongResidualReferenceModel>);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<MissingResidualReferenceModel, MissingResidualReferenceForm>
|
|
);
|
|
STATIC_CHECK_FALSE(operators::CompilableRootManifestFor<WrongResidualReferenceModel, WrongResidualReferenceForm>);
|
|
STATIC_CHECK(operators::CompilableRootManifestFor<DistinctResidualReferenceModel, DistinctResidualReferenceForm>);
|
|
|
|
// This is a valid compiled form for GenericManifestModel, but its magnetic
|
|
// generated pair is foreign to CanonicalModel. Described metadata alone
|
|
// must not make that mismatched model/form pair manifest-compilable.
|
|
STATIC_CHECK(operators::CompilableRootManifestFor<GenericManifestModel, GenericManifestForm>);
|
|
STATIC_CHECK_FALSE(operators::CompilableRootManifestFor<CanonicalModel, GenericManifestForm>);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Dimensionally Distinct Constraint Residuals Use Their Own Physical Reference",
|
|
"[root-manifest][type-contract][physics][scaling]"
|
|
) {
|
|
using namespace mean_field;
|
|
|
|
const auto model = model::StellarModel(
|
|
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.125}}),
|
|
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{2.5}}),
|
|
MockMismatchedManifestWithResidualReference(
|
|
{.target = dimensions::DensityValue{12.0}, .residualReference = dimensions::SpecificEnergyValue{3.25}}
|
|
)
|
|
);
|
|
const std::array<int, DistinctResidualReferenceForm::value_block_count> valueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, DistinctResidualReferenceForm::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
const DistinctResidualReferenceManifest manifest(valueSizes, residualSizes, model, 3);
|
|
|
|
const auto &descriptor = manifest.template specification<MockMismatchedManifestWithResidualReference>();
|
|
CHECK(descriptor.target == 12.0);
|
|
CHECK(descriptor.targetUnits == "density");
|
|
CHECK(descriptor.residualUnits == "specific_energy");
|
|
CHECK(descriptor.residualScale == 3.25);
|
|
CHECK(manifest.residualBlocks().back().scale == 3.25);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Root Manifest Stable IDs Are Unique Per Block Kind",
|
|
"[root-manifest][identity][type-contract]"
|
|
) {
|
|
using namespace mean_field;
|
|
|
|
using GeneratedValueCollisionModel = ManifestExtensionModel<MockGeneratedValueIdCollision>;
|
|
using GeneratedResidualCollisionModel = ManifestExtensionModel<MockGeneratedResidualIdCollision>;
|
|
using PhysicalValueCollisionModel = ManifestExtensionModel<MockPhysicalValueIdCollision>;
|
|
using PhysicalResidualCollisionModel = ManifestExtensionModel<MockPhysicalResidualIdCollision>;
|
|
using ReusedSymbolsModel = ManifestExtensionModel<MockReusedManifestSymbols>;
|
|
using NonConstexprManifestModel = ManifestExtensionModel<MockNonConstexprManifest>;
|
|
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockGeneratedValueIdCollision>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockGeneratedResidualIdCollision>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockPhysicalValueIdCollision>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockPhysicalResidualIdCollision>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockReusedManifestSymbols>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<GeneratedValueCollisionModel>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<GeneratedResidualCollisionModel>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<PhysicalValueCollisionModel>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<PhysicalResidualCollisionModel>);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
GeneratedValueCollisionModel, ManifestExtensionForm<MockGeneratedValueIdCollision>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
GeneratedResidualCollisionModel, ManifestExtensionForm<MockGeneratedResidualIdCollision>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
PhysicalValueCollisionModel, ManifestExtensionForm<MockPhysicalValueIdCollision>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
PhysicalResidualCollisionModel, ManifestExtensionForm<MockPhysicalResidualIdCollision>>
|
|
);
|
|
|
|
// Symbols are mathematical presentation labels, not machine identities.
|
|
STATIC_CHECK(
|
|
operators::CompilableRootManifestFor<ReusedSymbolsModel, ManifestExtensionForm<MockReusedManifestSymbols>>
|
|
);
|
|
|
|
// A broad physics manifest may be structurally complete while its identity
|
|
// strings are unsuitable for a constexpr compiled root descriptor. The
|
|
// root capability must reject it through detection, not a hard error.
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<NonConstexprGeneratedManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockNonConstexprManifest>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<NonConstexprManifestModel>);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<NonConstexprManifestModel, ManifestExtensionForm<MockNonConstexprManifest>>
|
|
);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Root Manifest Requires Complete Constant Generated Metadata",
|
|
"[root-manifest][identity][type-contract][sfinae]"
|
|
) {
|
|
using namespace mean_field;
|
|
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<ValidStructuralGeneratedManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockValidStructuralManifest>);
|
|
STATIC_CHECK(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockValidStructuralManifest>, ManifestExtensionForm<MockValidStructuralManifest>>
|
|
);
|
|
|
|
// These structural manifests deliberately lie through available=true.
|
|
// The root capability must inspect every identity and unit field itself.
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<EmptyValueStableIdManifest>);
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<EmptyValueSymbolManifest>);
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<EmptyResidualStableIdManifest>);
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<EmptyResidualSymbolManifest>);
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<EmptyTargetUnitsManifest>);
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<EmptyResidualUnitsManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockEmptyValueStableIdManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockEmptyValueSymbolManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockEmptyResidualStableIdManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockEmptyResidualSymbolManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockEmptyTargetUnitsManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockEmptyResidualUnitsManifest>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<ManifestExtensionModel<MockEmptyValueStableIdManifest>>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<ManifestExtensionModel<MockEmptyValueSymbolManifest>>);
|
|
STATIC_CHECK(
|
|
operators::StellarEquilibriumSystemCompilable<ManifestExtensionModel<MockEmptyResidualStableIdManifest>>
|
|
);
|
|
STATIC_CHECK(
|
|
operators::StellarEquilibriumSystemCompilable<ManifestExtensionModel<MockEmptyResidualSymbolManifest>>
|
|
);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<ManifestExtensionModel<MockEmptyTargetUnitsManifest>>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<ManifestExtensionModel<MockEmptyResidualUnitsManifest>>);
|
|
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockEmptyValueStableIdManifest>,
|
|
ManifestExtensionForm<MockEmptyValueStableIdManifest>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockEmptyValueSymbolManifest>, ManifestExtensionForm<MockEmptyValueSymbolManifest>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockEmptyResidualStableIdManifest>,
|
|
ManifestExtensionForm<MockEmptyResidualStableIdManifest>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockEmptyResidualSymbolManifest>,
|
|
ManifestExtensionForm<MockEmptyResidualSymbolManifest>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockEmptyTargetUnitsManifest>, ManifestExtensionForm<MockEmptyTargetUnitsManifest>>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockEmptyResidualUnitsManifest>,
|
|
ManifestExtensionForm<MockEmptyResidualUnitsManifest>>
|
|
);
|
|
|
|
// Constexpr enforcement covers unit metadata as well as IDs and symbols.
|
|
STATIC_CHECK(models::GeneratedManifestDefinition<NonConstexprGeneratedUnitsManifest>);
|
|
STATIC_CHECK(models::CompleteGeneratedManifestFor<MockNonConstexprUnitsManifest>);
|
|
STATIC_CHECK_FALSE(
|
|
operators::CompilableRootManifestFor<
|
|
ManifestExtensionModel<MockNonConstexprUnitsManifest>, ManifestExtensionForm<MockNonConstexprUnitsManifest>>
|
|
);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Self-Described Generated Specifications Enter The Manifest Without Combination Code",
|
|
"[root-manifest][variadic][extension]"
|
|
) {
|
|
using namespace mean_field;
|
|
using MockValue =
|
|
utils::blocks::generated_value_block<models::PhysicalCoordinateFor<MockFixedMagneticSpecificEnergy>>;
|
|
using MockResidual = utils::blocks::generated_residual_block<models::ResidualFor<MockFixedMagneticSpecificEnergy>>;
|
|
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<GenericManifestModel>);
|
|
STATIC_CHECK(operators::CompilableRootManifestFor<GenericManifestModel, GenericManifestForm>);
|
|
STATIC_CHECK_FALSE(operators::CompilableRootManifestFor<MissingManifestModel, MissingManifestForm>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<UncompiledSurfaceModel>);
|
|
STATIC_CHECK_FALSE(operators::CompilableRootManifestFor<UncompiledSurfaceModel, UncompiledSurfaceForm>);
|
|
STATIC_CHECK_FALSE(UncompiledSurfaceManifest::hasCompleteEquilibriumCompiler);
|
|
STATIC_CHECK(
|
|
UncompiledSurfaceManifest::compilationClass == models::EquilibriumSystemCompilation::equation_contributions_only
|
|
);
|
|
STATIC_CHECK(normalization::CompleteGeneratedPhysicalRieszNormalizationFor<MockFixedMagneticSpecificEnergy>);
|
|
STATIC_CHECK(preconditioning::SpecificationBorderContribution<MockFixedMagneticSpecificEnergy>::registered);
|
|
STATIC_CHECK(
|
|
utils::blocks::contains_type_v<
|
|
MockValue, typename preconditioning::SpecificationBorderContribution<
|
|
MockFixedMagneticSpecificEnergy>::CorrectionBlocks>
|
|
);
|
|
STATIC_CHECK(
|
|
utils::blocks::contains_type_v<
|
|
preconditioning::Coupling<utils::blocks::enthalpy::specific::residual, MockValue>,
|
|
typename preconditioning::SpecificationBorderContribution<
|
|
MockFixedMagneticSpecificEnergy>::RequiredCouplings>
|
|
);
|
|
STATIC_CHECK_FALSE(operators::hasCompleteStellarEquilibriumRuntime<GenericManifestModel>);
|
|
|
|
const auto model = model::StellarModel(
|
|
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.125}}),
|
|
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{2.5}}),
|
|
MockFixedMagneticSpecificEnergy({.target = dimensions::SpecificEnergyValue{7.5}})
|
|
);
|
|
const std::array<int, GenericManifestForm::value_block_count> valueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, GenericManifestForm::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
const GenericManifest manifest(valueSizes, residualSizes, model, 3);
|
|
|
|
REQUIRE(manifest.valueBlocks().size() == 7);
|
|
REQUIRE(manifest.residualBlocks().size() == 7);
|
|
CHECK(manifest.valueBlocks().back().stableId == "mock_magnetic_specific_energy.amplitude");
|
|
CHECK(manifest.valueBlocks().back().symbol == "a_B");
|
|
CHECK(manifest.valueBlocks().back().columnPolicy == operators::RootColumnPolicy::generated_physical_coordinate);
|
|
CHECK(manifest.residualBlocks().back().stableId == "mock_magnetic_specific_energy.residual");
|
|
CHECK(manifest.residualBlocks().back().symbol == "R_EB");
|
|
CHECK(manifest.residualBlocks().back().scale == 7.5);
|
|
|
|
const auto descriptor = std::find_if(
|
|
manifest.constraints().begin(), manifest.constraints().end(),
|
|
[](const operators::RootConstraintDescriptor &candidate) {
|
|
return candidate.stableId == "RootManifestMockFixedMagneticSpecificEnergy";
|
|
}
|
|
);
|
|
REQUIRE(descriptor != manifest.constraints().end());
|
|
CHECK(descriptor->valueBlock == utils::blocks::type_index_v<MockValue, typename GenericManifestForm::value_blocks>);
|
|
CHECK(
|
|
descriptor->residualBlock ==
|
|
utils::blocks::type_index_v<MockResidual, typename GenericManifestForm::residual_blocks>
|
|
);
|
|
CHECK(descriptor->target == 7.5);
|
|
CHECK(descriptor->residualScale == 7.5);
|
|
CHECK(descriptor->targetUnits == "specific_energy");
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Root Manifest Rejects Non-Finite Targets And Scales",
|
|
"[root-manifest][runtime-contract][scaling]"
|
|
) {
|
|
using namespace mean_field;
|
|
|
|
const std::array<int, GenericManifestForm::value_block_count> valueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, GenericManifestForm::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
const auto nonFiniteTargetModel = model::StellarModel(
|
|
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.125}}),
|
|
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{2.5}}),
|
|
MockFixedMagneticSpecificEnergy(
|
|
{.target = dimensions::SpecificEnergyValue{std::numeric_limits<double>::quiet_NaN()}}
|
|
)
|
|
);
|
|
|
|
CHECK_THROWS_WITH(
|
|
GenericManifest(valueSizes, residualSizes, nonFiniteTargetModel, 3),
|
|
"An equilibrium-system manifest constraint requires a finite target."
|
|
);
|
|
|
|
const auto nonFiniteResidualReferenceModel = model::StellarModel(
|
|
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.125}}),
|
|
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{2.5}}),
|
|
MockMismatchedManifestWithResidualReference(
|
|
{.target = dimensions::DensityValue{12.0},
|
|
.residualReference = dimensions::SpecificEnergyValue{std::numeric_limits<double>::quiet_NaN()}}
|
|
)
|
|
);
|
|
const std::array<int, DistinctResidualReferenceForm::value_block_count> distinctValueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, DistinctResidualReferenceForm::residual_block_count> distinctResidualSizes{4, 5, 2, 3,
|
|
6, 1, 1};
|
|
CHECK_THROWS_WITH(
|
|
DistinctResidualReferenceManifest(
|
|
distinctValueSizes, distinctResidualSizes, nonFiniteResidualReferenceModel, 3
|
|
),
|
|
"An equilibrium-system manifest constraint requires a finite, positive residual scale."
|
|
);
|
|
|
|
/*
|
|
* This adversarial target is non-finite when the generated residual block
|
|
* obtains its scale, then finite when the constraint descriptor is built.
|
|
* It independently verifies the final block-scale guard rather than
|
|
* reaching the target guard twice for the same NaN.
|
|
*/
|
|
const auto inconsistentScaleModel = model::StellarModel(
|
|
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.125}}),
|
|
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{2.5}}),
|
|
MockInconsistentManifestScale({.first = std::numeric_limits<double>::quiet_NaN(), .subsequent = 2.0})
|
|
);
|
|
STATIC_CHECK(std::same_as<std::remove_cvref_t<decltype(inconsistentScaleModel)>, InconsistentScaleModel>);
|
|
const std::array<int, InconsistentScaleForm::value_block_count> inconsistentValueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, InconsistentScaleForm::residual_block_count> inconsistentResidualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
|
|
CHECK_THROWS_WITH(
|
|
InconsistentScaleManifest(inconsistentValueSizes, inconsistentResidualSizes, inconsistentScaleModel, 3),
|
|
"An equilibrium-system manifest block requires a finite, positive scale."
|
|
);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Manifest Lookup Uses Role And Stable Name Together",
|
|
"[root-manifest][identity][type-contract]"
|
|
) {
|
|
using namespace mean_field;
|
|
constexpr auto surfaceKey = models::SpecificationTraits<surface::Isobaric>::key;
|
|
constexpr auto invariantKey = models::SpecificationTraits<MockInvariantNamedLikeSurface>::key;
|
|
|
|
STATIC_CHECK(surfaceKey.stableName == invariantKey.stableName);
|
|
STATIC_CHECK(surfaceKey.role != invariantKey.role);
|
|
STATIC_CHECK(models::specificationKeysAreUnique<surface::Isobaric, MockInvariantNamedLikeSurface>);
|
|
STATIC_CHECK(operators::StellarEquilibriumSystemCompilable<CrossRoleNameCollisionModel>);
|
|
STATIC_CHECK(operators::CompilableRootManifestFor<CrossRoleNameCollisionModel, CrossRoleNameCollisionForm>);
|
|
|
|
const auto model = model::StellarModel(
|
|
eos::Polytrope({.n = 1.0, .K = 0.25}), surface::Isobaric({.Psurf = dimensions::PressureValue{0.125}}),
|
|
integral::FixedTotalMass({.Mtotal = dimensions::MassValue{2.5}}),
|
|
MockInvariantNamedLikeSurface({.target = dimensions::SpecificEnergyValue{7.5}})
|
|
);
|
|
const std::array<int, CrossRoleNameCollisionForm::value_block_count> valueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, CrossRoleNameCollisionForm::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
const CrossRoleNameCollisionManifest manifest(valueSizes, residualSizes, model, 3);
|
|
|
|
const auto &surfaceDescriptor = manifest.specification<surface::Isobaric>();
|
|
const auto &invariantDescriptor = manifest.specification<MockInvariantNamedLikeSurface>();
|
|
CHECK(surfaceDescriptor.stableId == "IsobaricSurface");
|
|
CHECK(invariantDescriptor.stableId == "IsobaricSurface");
|
|
CHECK(surfaceDescriptor.role == models::SpecificationRole::boundary_condition);
|
|
CHECK(invariantDescriptor.role == models::SpecificationRole::invariant);
|
|
CHECK(surfaceDescriptor.target == 0.125);
|
|
CHECK(invariantDescriptor.target == 7.5);
|
|
CHECK(invariantDescriptor.valueBlock == 6);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Model Values Are Stored In Canonical Specification Order",
|
|
tags::model_specification_type_contract
|
|
) {
|
|
STATIC_CHECK(std::same_as<CanonicalModel, PermutedModel>);
|
|
STATIC_CHECK(CanonicalModel::symbolicallySquare);
|
|
STATIC_CHECK(CanonicalModel::hasCompleteEquilibriumDeclaration);
|
|
STATIC_CHECK(mean_field::operators::StellarEquilibriumSystemCompilable<CanonicalModel>);
|
|
STATIC_CHECK(CentralDensityModel::symbolicallySquare);
|
|
STATIC_CHECK(CentralDensityModel::hasCompleteEquilibriumDeclaration);
|
|
STATIC_CHECK(mean_field::operators::StellarEquilibriumSystemCompilable<CentralDensityModel>);
|
|
|
|
const mean_field::eos::Polytrope equationOfState{2.0, 0.75};
|
|
const mean_field::surface::Isobaric surface{mean_field::dimensions::PressureValue{0.125}};
|
|
const mean_field::models::FixedTotalMass mass{mean_field::dimensions::MassValue{1.75}};
|
|
|
|
const CanonicalModel model{mass, surface, equationOfState};
|
|
|
|
CHECK(model.specification<mean_field::eos::Polytrope>().polytropic_index() == 2.0);
|
|
CHECK(model.specification<mean_field::surface::Isobaric>().targetPressure().value() == 0.125);
|
|
CHECK(
|
|
model.specification<mean_field::models::FixedTotalMass>().targetMass() ==
|
|
mean_field::dimensions::MassValue{1.75}
|
|
);
|
|
|
|
const auto descriptors = model.runtimeSpecificationDescriptors();
|
|
REQUIRE(descriptors.size() == 3);
|
|
CHECK(descriptors[0].specification.name == "Polytrope");
|
|
CHECK(descriptors[1].specification.name == "IsobaricSurface");
|
|
CHECK(descriptors[2].specification.name == "FixedTotalMass");
|
|
CHECK(descriptors[0].canonicalIndex == 0);
|
|
CHECK(descriptors[1].canonicalIndex == 1);
|
|
CHECK(descriptors[2].canonicalIndex == 2);
|
|
CHECK(descriptors[0].hasDeclarativeDefinition);
|
|
CHECK(descriptors[1].hasDeclarativeDefinition);
|
|
CHECK(descriptors[2].hasDeclarativeDefinition);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Fixed Angular Momentum Manifest Appends A Generated Physical Coordinate And Invariant Row",
|
|
tags::root_manifest_type_contract
|
|
) {
|
|
using namespace mean_field;
|
|
const std::array<int, AngularMomentumForm::value_block_count> valueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, AngularMomentumForm::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
const AngularMomentumModel model(
|
|
eos::Polytrope{1.0, 0.25}, surface::Isobaric{dimensions::PressureValue{0.125}},
|
|
models::FixedTotalMass{dimensions::MassValue{2.5}},
|
|
models::FixedAngularMomentum{dimensions::AngularMomentumValue{7.5}}
|
|
);
|
|
const AngularMomentumManifest manifest(valueSizes, residualSizes, model, 3);
|
|
|
|
STATIC_CHECK(AngularMomentumForm::value_block_count == 7);
|
|
STATIC_CHECK(AngularMomentumForm::residual_block_count == 7);
|
|
REQUIRE(manifest.valueBlocks().size() == 7);
|
|
REQUIRE(manifest.residualBlocks().size() == 7);
|
|
CHECK(manifest.layout().value_offsets().Last() == 22);
|
|
CHECK(manifest.layout().residual_offsets().Last() == 22);
|
|
CHECK(manifest.valueBlocks()[6].stableId == "fixed_angular_momentum.angular_velocity");
|
|
CHECK(manifest.valueBlocks()[6].symbol == "Omega");
|
|
CHECK(manifest.valueBlocks()[6].columnPolicy == operators::RootColumnPolicy::generated_physical_coordinate);
|
|
CHECK(manifest.residualBlocks()[6].stableId == "fixed_angular_momentum.residual");
|
|
CHECK(manifest.residualBlocks()[6].symbol == "R_J");
|
|
CHECK(manifest.residualBlocks()[6].scale == 7.5);
|
|
|
|
const auto constraints = manifest.constraints();
|
|
REQUIRE(constraints.size() == 3);
|
|
CHECK(constraints[2].stableId == "FixedAngularMomentum");
|
|
CHECK(constraints[2].role == models::SpecificationRole::invariant);
|
|
CHECK(constraints[2].valueBlock == 6);
|
|
CHECK(constraints[2].residualBlock == 6);
|
|
CHECK(constraints[2].rowArity == 1);
|
|
CHECK(constraints[2].columnArity == 1);
|
|
CHECK(constraints[2].target == 7.5);
|
|
CHECK_FALSE(constraints[2].carrierTarget.has_value());
|
|
CHECK(constraints[2].targetUnits == "angular_momentum");
|
|
CHECK(constraints[2].residualScale == 7.5);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Central Density Root Manifest Appends A Carrier Phase Row And Solver Border",
|
|
tags::root_manifest_type_contract
|
|
) {
|
|
STATIC_CHECK(mean_field::operators::CompilableRootManifestFor<CentralDensityModel, CentralForm>);
|
|
|
|
const std::array<int, CentralForm::value_block_count> valueSizes{2, 3, 4, 5, 6, 1, 1};
|
|
const std::array<int, CentralForm::residual_block_count> residualSizes{4, 5, 2, 3, 6, 1, 1};
|
|
const CentralDensityModel model{
|
|
mean_field::eos::Polytrope{1.0, 0.125},
|
|
mean_field::surface::Isobaric{mean_field::dimensions::PressureValue{0.125}},
|
|
mean_field::models::FixedTotalMass{mean_field::dimensions::MassValue{2.5}},
|
|
mean_field::models::FixedCentralDensity{mean_field::dimensions::DensityValue{8.0}}
|
|
};
|
|
const CentralManifest manifest(valueSizes, residualSizes, model, 3);
|
|
|
|
CHECK(manifest.layout().value_offsets().Last() == 22);
|
|
CHECK(manifest.layout().residual_offsets().Last() == 22);
|
|
REQUIRE(manifest.valueBlocks().size() == 7);
|
|
REQUIRE(manifest.residualBlocks().size() == 7);
|
|
CHECK(manifest.valueBlocks()[6].stableId == "fixed_central_density.border");
|
|
CHECK(manifest.valueBlocks()[6].symbol == "lambda_rho_c");
|
|
CHECK(manifest.valueBlocks()[6].columnPolicy == mean_field::operators::RootColumnPolicy::solver_border);
|
|
CHECK(manifest.residualBlocks()[6].stableId == "fixed_central_density.residual");
|
|
CHECK(manifest.residualBlocks()[6].symbol == "R_rho_c");
|
|
CHECK(manifest.residualBlocks()[6].scale == 2.0);
|
|
|
|
const auto constraints = manifest.constraints();
|
|
REQUIRE(constraints.size() == 3);
|
|
CHECK(constraints[2].stableId == "FixedCentralDensity");
|
|
CHECK(constraints[2].role == mean_field::models::SpecificationRole::phase_condition);
|
|
CHECK(constraints[2].valueBlock == 6);
|
|
CHECK(constraints[2].residualBlock == 6);
|
|
CHECK(constraints[2].target == 8.0);
|
|
REQUIRE(constraints[2].carrierTarget.has_value());
|
|
CHECK(*constraints[2].carrierTarget == 2.0);
|
|
CHECK(constraints[2].residualScale == 2.0);
|
|
|
|
CHECK(manifest.specification<mean_field::surface::Isobaric>().target == 0.125);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Compiled Root Manifest Centralizes Canonical Blocks Provenance And Scaling",
|
|
tags::root_manifest_type_contract
|
|
) {
|
|
const Manifest manifest = make_manifest();
|
|
|
|
STATIC_CHECK(Manifest::symbolicallySquare);
|
|
STATIC_CHECK(Manifest::compilationClass == mean_field::models::ModelCompilationClass::isolated_root);
|
|
STATIC_CHECK(
|
|
mean_field::operators::RootManifestSpecificationDescriptorFor<
|
|
mean_field::models::FixedTotalMass, CanonicalModel>
|
|
);
|
|
STATIC_CHECK(
|
|
mean_field::operators::RootManifestSpecificationDescriptorFor<mean_field::surface::Isobaric, CanonicalModel>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
mean_field::operators::RootManifestSpecificationDescriptorFor<mean_field::eos::Polytrope, CanonicalModel>
|
|
);
|
|
STATIC_CHECK(HasRootManifestSpecificationDescriptor<Manifest, mean_field::models::FixedTotalMass>);
|
|
STATIC_CHECK(HasRootManifestSpecificationDescriptor<Manifest, mean_field::surface::Isobaric>);
|
|
STATIC_CHECK_FALSE(HasRootManifestSpecificationDescriptor<Manifest, mean_field::eos::Polytrope>);
|
|
STATIC_CHECK_FALSE(
|
|
CanMutateManifestBlock<
|
|
typename Manifest::StateView, decltype(mean_field::utils::blocks::density_field.mass_term)>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
CanMutateManifestBlock<
|
|
typename Manifest::DirectionView, decltype(mean_field::utils::blocks::density_field.mass_term)>
|
|
);
|
|
STATIC_CHECK(
|
|
CanMutateManifestBlock<
|
|
typename Manifest::MutableStateView, decltype(mean_field::utils::blocks::density_field.mass_term)>
|
|
);
|
|
|
|
CHECK(manifest.layout().value_offsets().Last() == 21);
|
|
CHECK(manifest.layout().residual_offsets().Last() == 21);
|
|
|
|
const auto values = manifest.valueBlocks();
|
|
const auto residuals = manifest.residualBlocks();
|
|
|
|
REQUIRE(values.size() == 6);
|
|
REQUIRE(residuals.size() == 6);
|
|
CHECK(values[0].stableId == "density");
|
|
CHECK(values[0].symbol == "rho");
|
|
CHECK(values[1].stableId == "surface_deformation");
|
|
CHECK(values[5].stableId == "fixed_total_mass.multiplier");
|
|
CHECK(values[5].symbol == "C");
|
|
CHECK(values[5].provenance == mean_field::operators::RootBlockProvenance::model_specification);
|
|
CHECK(values[5].source == "FixedTotalMass");
|
|
CHECK(values[5].columnPolicy == mean_field::operators::RootColumnPolicy::existing_physical_multiplier);
|
|
|
|
CHECK(residuals[5].stableId == "fixed_total_mass.residual");
|
|
CHECK(residuals[5].symbol == "R_M");
|
|
CHECK(residuals[5].rowInjection == mean_field::operators::RootRowInjection::append_global);
|
|
CHECK(residuals[5].scalePolicy == mean_field::operators::RootScalePolicy::target_relative);
|
|
CHECK(residuals[5].scale == 2.5);
|
|
|
|
const auto replacements = manifest.rowReplacements();
|
|
REQUIRE(replacements.size() == 1);
|
|
CHECK(replacements[0].sourceSpecification == "IsobaricSurface");
|
|
CHECK(replacements[0].replacedRowCount == 3);
|
|
CHECK(replacements[0].carrierResidualBlock == 4);
|
|
|
|
const auto constraints = manifest.constraints();
|
|
REQUIRE(constraints.size() == 2);
|
|
const auto &massConstraint = manifest.specification<mean_field::models::FixedTotalMass>();
|
|
CHECK(massConstraint.stableId == "FixedTotalMass");
|
|
CHECK(massConstraint.valueBlock == 5);
|
|
CHECK(massConstraint.residualBlock == 5);
|
|
CHECK(massConstraint.target == 2.5);
|
|
CHECK(massConstraint.residualScale == 2.5);
|
|
const auto &surfaceConstraint = manifest.specification<mean_field::surface::Isobaric>();
|
|
CHECK(surfaceConstraint.stableId == "IsobaricSurface");
|
|
CHECK(surfaceConstraint.rowInjection == mean_field::operators::RootRowInjection::replace_carrier_rows);
|
|
CHECK(surfaceConstraint.target == 0.125);
|
|
CHECK_FALSE(surfaceConstraint.carrierTarget.has_value());
|
|
|
|
const auto report = manifest.fixedMassReport(2.75);
|
|
CHECK(report.achieved == 2.75);
|
|
CHECK(report.dimensionalResidual == 0.25);
|
|
CHECK(report.scaledResidual == 0.1);
|
|
}
|
|
|
|
TEST_CASE(
|
|
"Typed Root Views Resolve Blocks Through The Compiled Manifest",
|
|
tags::root_manifest_type_contract
|
|
) {
|
|
const Manifest manifest = make_manifest();
|
|
|
|
STATIC_CHECK(HasLvalueRootViewFactories<Manifest>);
|
|
STATIC_CHECK_FALSE(StateViewAcceptsTemporaryVector<Manifest>);
|
|
STATIC_CHECK_FALSE(StateViewAcceptsConstTemporaryVector<Manifest>);
|
|
STATIC_CHECK_FALSE(DirectionViewAcceptsTemporaryVector<Manifest>);
|
|
STATIC_CHECK_FALSE(DirectionViewAcceptsConstTemporaryVector<Manifest>);
|
|
STATIC_CHECK_FALSE(ResidualViewAcceptsTemporaryVector<Manifest>);
|
|
STATIC_CHECK_FALSE(ResidualViewAcceptsConstTemporaryVector<Manifest>);
|
|
STATIC_CHECK_FALSE(TemporaryManifestProvidesStateView<Manifest>);
|
|
STATIC_CHECK_FALSE(TemporaryManifestProvidesReadOnlyStateView<Manifest>);
|
|
STATIC_CHECK_FALSE(TemporaryManifestProvidesDirectionView<Manifest>);
|
|
STATIC_CHECK_FALSE(TemporaryManifestProvidesResidualView<Manifest>);
|
|
|
|
STATIC_CHECK(
|
|
std::constructible_from<typename Manifest::StateView, const mfem::Vector &, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK(
|
|
std::constructible_from<typename Manifest::MutableStateView, mfem::Vector &, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK(
|
|
std::constructible_from<typename Manifest::RootResidualView, mfem::Vector &, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::StateView, mfem::Vector &&, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::StateView, const mfem::Vector &&, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::MutableStateView, mfem::Vector &&, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::RootResidualView, mfem::Vector &&, const typename Manifest::Layout &>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::StateView, const mfem::Vector &, typename Manifest::Layout &&>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::MutableStateView, mfem::Vector &, typename Manifest::Layout &&>
|
|
);
|
|
STATIC_CHECK_FALSE(
|
|
std::constructible_from<typename Manifest::RootResidualView, mfem::Vector &, typename Manifest::Layout &&>
|
|
);
|
|
|
|
mfem::Vector state(manifest.layout().value_offsets().Last());
|
|
for (int index = 0; index < state.Size(); ++index) {
|
|
state(index) = static_cast<double>(index + 1);
|
|
}
|
|
|
|
const auto stateView = manifest.stateView(state);
|
|
const mfem::Vector density = stateView.block(mean_field::utils::blocks::density_field.mass_term);
|
|
const mfem::Vector surface = stateView.block(mean_field::utils::blocks::surface_deformation_field.parameters_term);
|
|
const mfem::Vector multiplier =
|
|
stateView.block(mean_field::utils::blocks::fixed_total_mass_constraint.mass_normalization_term);
|
|
|
|
REQUIRE(density.Size() == 2);
|
|
REQUIRE(surface.Size() == 3);
|
|
REQUIRE(multiplier.Size() == 1);
|
|
CHECK(density(0) == 1.0);
|
|
CHECK(surface(0) == 3.0);
|
|
CHECK(multiplier(0) == 21.0);
|
|
|
|
mfem::Vector residual(manifest.layout().residual_offsets().Last());
|
|
residual = 0.0;
|
|
const auto residualView = manifest.residualView(residual);
|
|
mfem::Vector massResidual(1);
|
|
massResidual(0) = -0.375;
|
|
residualView.assign(mean_field::utils::blocks::fixed_total_mass_constraint.mass_normalization_term, massResidual);
|
|
CHECK(residual(20) == -0.375);
|
|
|
|
mfem::Vector wrongState(state.Size() - 1);
|
|
CHECK_THROWS_AS(manifest.stateView(wrongState), std::invalid_argument);
|
|
}
|