test(tests): added test suite
The test suite is extensive. Note that LLMs were used to aid in the development of the test suite. All LLM generated code was manually reviewed.
This commit is contained in:
101
tests/normalization/scales.cpp
Normal file
101
tests/normalization/scales.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "serif/solver/normalization/scales.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace dimensions = serif::dimensions;
|
||||
namespace normalization = serif::solver::normalization;
|
||||
|
||||
/** @brief Supply typed reference values while retaining concise physical test cases. */
|
||||
std::expected<normalization::StellarReferenceScales, std::string> scales(double mass, double radius, double gravity = 1.0)
|
||||
{
|
||||
return normalization::prepare_stellar_reference_scales(dimensions::QuantityValue<dimensions::Mass>{mass}, dimensions::QuantityValue<dimensions::Length>{radius}, dimensions::QuantityValue<dimensions::GravitationalConstant>{gravity});
|
||||
}
|
||||
}
|
||||
|
||||
// Ported from MeanField tests/normalization/physical_riesz.cpp.
|
||||
TEST_CASE("Characteristic stellar scales satisfy gravity virial and rotation identities", "[normalization][unit][physics]")
|
||||
{
|
||||
constexpr double mass = 7.0;
|
||||
constexpr double radius = 3.0;
|
||||
constexpr double gravity = 5.0;
|
||||
const auto prepared = scales(mass, radius, gravity);
|
||||
REQUIRE(prepared);
|
||||
const normalization::StellarReferenceScales &reference = *prepared;
|
||||
|
||||
CHECK(reference.density.value() == Catch::Approx(mass / std::pow(radius, 3)));
|
||||
CHECK(reference.acceleration.value() == Catch::Approx(gravity * mass / std::pow(radius, 2)));
|
||||
CHECK(reference.specific_energy.value() == Catch::Approx(gravity * mass / radius));
|
||||
CHECK(reference.pressure.value() == Catch::Approx(gravity * mass * mass / std::pow(radius, 4)));
|
||||
CHECK(reference.angular_velocity.value() == Catch::Approx(std::sqrt(gravity * mass / std::pow(radius, 3))));
|
||||
CHECK(reference.angular_momentum.value() == Catch::Approx(mass * std::sqrt(gravity * mass * radius)));
|
||||
|
||||
const double virial = reference.pressure.value() * std::pow(radius, 3);
|
||||
CHECK(virial == Catch::Approx(mass * reference.specific_energy.value()).epsilon(2.0e-15));
|
||||
CHECK(virial == Catch::Approx(reference.force.value() * radius).epsilon(2.0e-15));
|
||||
CHECK(reference.angular_velocity.value() * reference.angular_velocity.value() * radius == Catch::Approx(reference.acceleration.value()).epsilon(2.0e-15));
|
||||
CHECK(reference.angular_momentum.value() == Catch::Approx(mass * radius * radius * reference.angular_velocity.value()).epsilon(2.0e-15));
|
||||
}
|
||||
|
||||
TEST_CASE("Characteristic scales obey stellar homology exponents", "[normalization][unit][physics]")
|
||||
{
|
||||
const auto reference = scales(2.5, 4.0, 3.0);
|
||||
constexpr double mass_factor = 11.0;
|
||||
constexpr double radius_factor = 0.2;
|
||||
constexpr double gravity_factor = 7.0;
|
||||
const auto transformed = scales(2.5 * mass_factor, 4.0 * radius_factor, 3.0 * gravity_factor);
|
||||
REQUIRE(reference);
|
||||
REQUIRE(transformed);
|
||||
|
||||
CHECK(transformed->density.value() / reference->density.value() == Catch::Approx(mass_factor / std::pow(radius_factor, 3)).epsilon(4.0e-15));
|
||||
CHECK(transformed->acceleration.value() / reference->acceleration.value() == Catch::Approx(gravity_factor * mass_factor / std::pow(radius_factor, 2)).epsilon(4.0e-15));
|
||||
CHECK(transformed->inverse_time_squared.value() / reference->inverse_time_squared.value() == Catch::Approx(gravity_factor * mass_factor / std::pow(radius_factor, 3)).epsilon(4.0e-15));
|
||||
CHECK(transformed->specific_energy.value() / reference->specific_energy.value() == Catch::Approx(gravity_factor * mass_factor / radius_factor).epsilon(4.0e-15));
|
||||
CHECK(transformed->pressure.value() / reference->pressure.value() == Catch::Approx(gravity_factor * mass_factor * mass_factor / std::pow(radius_factor, 4)).epsilon(4.0e-15));
|
||||
CHECK(transformed->angular_velocity.value() / reference->angular_velocity.value() == Catch::Approx(std::sqrt(gravity_factor * mass_factor / std::pow(radius_factor, 3))).epsilon(4.0e-15));
|
||||
CHECK(transformed->angular_momentum.value() / reference->angular_momentum.value() == Catch::Approx(mass_factor * std::sqrt(gravity_factor * mass_factor * radius_factor)).epsilon(4.0e-15));
|
||||
CHECK(transformed->force.value() / reference->force.value() == Catch::Approx(gravity_factor * mass_factor * mass_factor / std::pow(radius_factor, 2)).epsilon(4.0e-15));
|
||||
}
|
||||
|
||||
TEST_CASE("Typed scales distinguish residual quantities and share the gravitational energy scale", "[normalization][unit][physics]")
|
||||
{
|
||||
const auto reference = scales(9.0, 2.0, 4.0);
|
||||
REQUIRE(reference);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::Dimensionless{}).value() == 1.0);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::Mass{}).value() == 9.0);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::Length{}).value() == 2.0);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::MassDensity{}) == reference->density);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::Acceleration{}) == reference->acceleration);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::InverseTimeSquared{}) == reference->inverse_time_squared);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::Pressure{}) == reference->pressure);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::AngularVelocity{}) == reference->angular_velocity);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::AngularMomentum{}) == reference->angular_momentum);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::Force{}) == reference->force);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::SpecificEnergy{}) == reference->specific_energy);
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::SpecificEnthalpy{}).value() == reference->specific_energy.value());
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::GravitationalPotential{}).value() == reference->specific_energy.value());
|
||||
CHECK(normalization::characteristic_scale(*reference, dimensions::SpecificEnthalpy{}).value() != reference->density.value());
|
||||
CHECK(*reference == *scales(9.0, 2.0, 4.0));
|
||||
CHECK_FALSE(*reference == *scales(9.0, 2.1, 4.0));
|
||||
}
|
||||
|
||||
TEST_CASE("Characteristic scale preparation rejects invalid and unrepresentable references", "[normalization][unit][validation]")
|
||||
{
|
||||
for (const double invalid : {0.0, -1.0, std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::infinity()})
|
||||
{
|
||||
CHECK_FALSE(scales(invalid, 1.0));
|
||||
CHECK_FALSE(scales(1.0, invalid));
|
||||
CHECK_FALSE(scales(1.0, 1.0, invalid));
|
||||
}
|
||||
CHECK_FALSE(scales(1.0e300, 1.0e-200, 1.0e100));
|
||||
CHECK_FALSE(scales(1.0, 1.0e300));
|
||||
CHECK_FALSE(scales(1.0e-300, 1.0));
|
||||
REQUIRE(scales(1.0, 1.0));
|
||||
}
|
||||
Reference in New Issue
Block a user