Scale prepared gravity consistency by uncancelled field contributions
This commit is contained in:
@@ -421,3 +421,59 @@ TEST_CASE("Reduced gravity action is repeatable, linear, and alias safe with an
|
||||
operation.Mult(first, secondAction);
|
||||
CHECK(relativeError(firstAction, secondAction) == 0.0);
|
||||
}
|
||||
|
||||
TEST_CASE("Prepared gravity assessment retains the scale of cancelling field contributions",
|
||||
"[solver][gravity_prepared_residual]") {
|
||||
using mean_field::solver::detail::AssessGravityPreparedResidual;
|
||||
const std::array contributions{1.e6, 1.e6, 1.e-8, 2.0, 3.0, 1.e-8, 1.e-8, 1.e-8};
|
||||
const double affineDisagreement = 1.e-8;
|
||||
const double measuredInnerResidual = 5.e-15;
|
||||
const auto result = AssessGravityPreparedResidual(contributions, affineDisagreement,
|
||||
affineDisagreement + measuredInnerResidual, measuredInnerResidual);
|
||||
REQUIRE(result.admissible);
|
||||
CHECK(result.arithmeticAllowance > affineDisagreement);
|
||||
CHECK(result.targetThreshold == result.arithmeticAllowance + measuredInnerResidual);
|
||||
|
||||
const std::array residualOnly{1.e-8, 1.e-8, 1.e-8};
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(residualOnly, affineDisagreement,
|
||||
affineDisagreement + measuredInnerResidual, measuredInnerResidual).admissible);
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(contributions, 2.0 * result.arithmeticAllowance,
|
||||
measuredInnerResidual, measuredInnerResidual).admissible);
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(contributions, 0.0,
|
||||
2.0 * result.targetThreshold, measuredInnerResidual).admissible);
|
||||
}
|
||||
|
||||
TEST_CASE("Prepared gravity assessment scales with equation units without an absolute floor",
|
||||
"[solver][gravity_prepared_residual]") {
|
||||
using mean_field::solver::detail::AssessGravityPreparedResidual;
|
||||
const std::array contributions{1.e8, 1.e8, 5.0, 3.0, 2.0};
|
||||
const auto reference = AssessGravityPreparedResidual(contributions, 1.e-7, 1.5e-7, 1.e-8);
|
||||
REQUIRE(reference.admissible);
|
||||
for (const double factor : {1.e-12, 1.e12}) {
|
||||
auto scaled = contributions;
|
||||
for (double &value : scaled) value *= factor;
|
||||
const auto result = AssessGravityPreparedResidual(scaled, factor * 1.e-7, factor * 1.5e-7, factor * 1.e-8);
|
||||
CHECK(result.admissible == reference.admissible);
|
||||
CHECK(result.arithmeticAllowance / factor == Catch::Approx(reference.arithmeticAllowance).epsilon(1.e-14));
|
||||
CHECK(result.targetThreshold / factor == Catch::Approx(reference.targetThreshold).epsilon(1.e-14));
|
||||
}
|
||||
const std::array zero{0.0};
|
||||
const auto exactZero = AssessGravityPreparedResidual(zero, 0.0, 0.0, 0.0);
|
||||
CHECK(exactZero.admissible);
|
||||
CHECK(exactZero.arithmeticAllowance == 0.0);
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(zero, 1.e-30, 0.0, 0.0).admissible);
|
||||
}
|
||||
|
||||
TEST_CASE("Prepared gravity assessment rejects nonfinite or invalid measurements",
|
||||
"[solver][gravity_prepared_residual]") {
|
||||
using mean_field::solver::detail::AssessGravityPreparedResidual;
|
||||
const std::array contributions{1.0, 2.0};
|
||||
for (const double invalid : {-1.0, std::numeric_limits<double>::infinity(),
|
||||
std::numeric_limits<double>::quiet_NaN()}) {
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(contributions, invalid, 0.0, 0.0).admissible);
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(contributions, 0.0, invalid, 0.0).admissible);
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(contributions, 0.0, 0.0, invalid).admissible);
|
||||
const std::array invalidContributions{1.0, invalid};
|
||||
CHECK_FALSE(AssessGravityPreparedResidual(invalidContributions, 0.0, 0.0, 0.0).admissible);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user