174 lines
6.6 KiB
C++
174 lines
6.6 KiB
C++
#include "reference_tolerance_policy.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace {
|
|
|
|
using fesa::test::ReferenceToleranceBranch;
|
|
using fesa::test::ReferenceToleranceFamily;
|
|
using fesa::test::ReferenceTolerancePolicy;
|
|
using fesa::test::ReferenceToleranceRow;
|
|
|
|
ReferenceToleranceFamily MakeFamily(std::string identity,
|
|
std::vector<std::string> components,
|
|
bool blocking,
|
|
std::vector<ReferenceToleranceRow> rows) {
|
|
return {std::move(identity), std::move(components), blocking,
|
|
std::move(rows)};
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
AppliesRelativeAndNearZeroThresholdsAtTheirInclusiveBoundaries) {
|
|
const auto evaluation = ReferenceTolerancePolicy::Evaluate({MakeFamily(
|
|
"displacement-translation", {"UX", "UY", "UZ"}, true,
|
|
{{105.0, 100.0}, {105.001, 100.0}, {2.0, 1.0}, {2.001, 1.0}})});
|
|
|
|
ASSERT_TRUE(evaluation.valid);
|
|
ASSERT_EQ(evaluation.families.size(), 1U);
|
|
const auto& family = evaluation.families.front();
|
|
EXPECT_EQ(family.row_count, 4U);
|
|
EXPECT_DOUBLE_EQ(family.reference_scale, 100.0);
|
|
EXPECT_DOUBLE_EQ(family.near_zero_band, 1.0);
|
|
EXPECT_EQ(family.near_zero_count, 2U);
|
|
EXPECT_FALSE(family.passed);
|
|
ASSERT_EQ(family.rows.size(), 4U);
|
|
EXPECT_EQ(family.rows[0U].branch, ReferenceToleranceBranch::kRelative);
|
|
EXPECT_TRUE(family.rows[0U].relative_error_applicable);
|
|
EXPECT_DOUBLE_EQ(family.rows[0U].relative_error, 0.05);
|
|
EXPECT_DOUBLE_EQ(family.rows[0U].threshold, 5.0);
|
|
EXPECT_TRUE(family.rows[0U].passed);
|
|
EXPECT_FALSE(family.rows[1U].passed);
|
|
EXPECT_EQ(family.rows[2U].branch, ReferenceToleranceBranch::kNearZero);
|
|
EXPECT_FALSE(family.rows[2U].relative_error_applicable);
|
|
EXPECT_DOUBLE_EQ(family.rows[2U].threshold, 1.0);
|
|
EXPECT_TRUE(family.rows[2U].passed);
|
|
EXPECT_FALSE(family.rows[3U].passed);
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
RejectsFamiliesWhoseScaleRelativeRmsExceedsOnePercent) {
|
|
const auto evaluation = ReferenceTolerancePolicy::Evaluate({MakeFamily(
|
|
"reaction-force", {"RF1", "RF2", "RF3"}, true,
|
|
{{101.1, 100.0}, {101.1, 100.0}, {101.1, 100.0}, {101.1, 100.0}})});
|
|
|
|
ASSERT_TRUE(evaluation.valid);
|
|
const auto& family = evaluation.families.front();
|
|
EXPECT_EQ(family.row_count, 4U);
|
|
EXPECT_TRUE(std::all_of(family.rows.begin(), family.rows.end(),
|
|
[](const auto& row) { return row.passed; }));
|
|
EXPECT_NEAR(family.relative_rms, 0.011, 1.0e-15);
|
|
EXPECT_FALSE(family.rms_passed);
|
|
EXPECT_FALSE(family.passed);
|
|
EXPECT_FALSE(evaluation.passed);
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
FailsClosedForZeroScaleNonzeroErrorWithoutNonfiniteMetrics) {
|
|
const auto evaluation = ReferenceTolerancePolicy::Evaluate(
|
|
{MakeFamily("section-force", {"N"}, true, {{0.0, 0.0}, {1.0, 0.0}})});
|
|
|
|
ASSERT_TRUE(evaluation.valid);
|
|
const auto& family = evaluation.families.front();
|
|
EXPECT_EQ(family.row_count, 2U);
|
|
EXPECT_DOUBLE_EQ(family.reference_scale, 0.0);
|
|
EXPECT_DOUBLE_EQ(family.near_zero_band, 0.0);
|
|
EXPECT_EQ(family.near_zero_count, 2U);
|
|
EXPECT_EQ(family.diagnostic_code, "zero-reference-scale-nonzero-error");
|
|
EXPECT_EQ(family.rows[0U].branch, ReferenceToleranceBranch::kZeroScaleExact);
|
|
EXPECT_TRUE(family.rows[0U].passed);
|
|
EXPECT_FALSE(family.rows[1U].passed);
|
|
EXPECT_FALSE(family.rows[1U].relative_error_applicable);
|
|
EXPECT_TRUE(std::isfinite(family.relative_rms));
|
|
EXPECT_DOUBLE_EQ(family.relative_rms, 0.0);
|
|
EXPECT_FALSE(family.rms_passed);
|
|
EXPECT_FALSE(family.passed);
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
KeepsWarningOnlyFamilyExceedanceOutOfBlockingVerdict) {
|
|
const auto evaluation = ReferenceTolerancePolicy::Evaluate(
|
|
{MakeFamily("translation", {"U1", "U2", "U3"}, true, {{0.0, 0.0}}),
|
|
MakeFamily("rotation", {"UR1", "UR2", "UR3"}, false, {{1.0, 0.0}})});
|
|
|
|
ASSERT_TRUE(evaluation.valid);
|
|
ASSERT_EQ(evaluation.families.size(), 2U);
|
|
EXPECT_TRUE(evaluation.families[0U].passed);
|
|
EXPECT_FALSE(evaluation.families[1U].passed);
|
|
EXPECT_TRUE(evaluation.passed);
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
RejectsNonfiniteInputsBeforeToleranceEvaluation) {
|
|
const auto evaluation = ReferenceTolerancePolicy::Evaluate(
|
|
{MakeFamily("displacement-translation", {"UX", "UY", "UZ"}, true,
|
|
{{std::numeric_limits<double>::quiet_NaN(), 0.0}})});
|
|
|
|
EXPECT_FALSE(evaluation.valid);
|
|
EXPECT_EQ(evaluation.diagnostic_code, "nonfinite-comparison-value");
|
|
EXPECT_TRUE(evaluation.families.empty());
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
EigenFirstImplementationDoesNotRelaxCommonPolicy) {
|
|
const std::vector<ReferenceToleranceFamily> families{
|
|
MakeFamily("mode-1", {"Value"}, true, {{105.0, 100.0}})};
|
|
const auto common = ReferenceTolerancePolicy::Evaluate(families);
|
|
const auto eigen =
|
|
ReferenceTolerancePolicy::EvaluateMitc4EigenFirstImplementation(families);
|
|
ASSERT_TRUE(common.valid);
|
|
ASSERT_TRUE(eigen.valid);
|
|
EXPECT_FALSE(common.passed);
|
|
EXPECT_TRUE(eigen.passed);
|
|
EXPECT_DOUBLE_EQ(eigen.families[0].relative_rms, 0.05);
|
|
EXPECT_DOUBLE_EQ(common.families[0].relative_rms,
|
|
eigen.families[0].relative_rms);
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
EigenFirstImplementationPreservesZeroAndFiniteChecks) {
|
|
for (const auto& row : std::vector<ReferenceToleranceRow>{
|
|
{0.0, 0.0}, {1.0, 0.0},
|
|
{std::numeric_limits<double>::quiet_NaN(), 1.0}}) {
|
|
const auto result =
|
|
ReferenceTolerancePolicy::EvaluateMitc4EigenFirstImplementation(
|
|
{MakeFamily("mode-1", {"Value"}, true, {row})});
|
|
if (!std::isfinite(row.fesa_value)) {
|
|
EXPECT_FALSE(result.valid);
|
|
EXPECT_FALSE(result.passed);
|
|
} else {
|
|
ASSERT_TRUE(result.valid);
|
|
EXPECT_EQ(result.passed, row.fesa_value == 0.0);
|
|
if (row.fesa_value != 0.0) {
|
|
EXPECT_EQ(result.families[0].diagnostic_code,
|
|
"zero-reference-scale-nonzero-error");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(ReferenceTolerancePolicy,
|
|
EigenFirstImplementationRejectsNonmodalFamilies) {
|
|
for (const auto& families :
|
|
std::vector<std::vector<ReferenceToleranceFamily>>{
|
|
{},
|
|
{MakeFamily("mode-1", {"U1"}, true, {{100.0, 100.0}})},
|
|
{MakeFamily("mode-1", {"Value"}, false, {{100.0, 100.0}})},
|
|
{MakeFamily("modes", {"Value"}, true,
|
|
{{100.0, 100.0}, {100.0, 100.0}})}}) {
|
|
const auto result =
|
|
ReferenceTolerancePolicy::EvaluateMitc4EigenFirstImplementation(families);
|
|
EXPECT_FALSE(result.valid);
|
|
EXPECT_FALSE(result.passed);
|
|
EXPECT_EQ(result.diagnostic_code, "invalid-eigen-tolerance-family");
|
|
}
|
|
}
|
|
|
|
}
|