Files
FESADev/tests/unit/analysis/hht_development_probe_test.cpp

115 lines
4.3 KiB
C++

#include "analysis/hht_development_probe.h"
#include <gtest/gtest.h>
#if defined(FESA_HHT_DEVELOPMENT_PROBE)
#include "fesa/math/sparse_matrix.h"
#include "fesa/math/vector.h"
#include "analysis/hht_reduced_internal.h"
namespace fesa::hht_development_probe {
class IdentityTangentSolver final : public TangentSolver {
public:
Status FactorizeFresh(const SparseMatrix&) override { return Status::Ok(); }
Status SolveCorrection(const Vector& rhs, Vector& result) const override {
result = rhs; return Status::Ok();
}
};
TEST(HhtDevelopmentProbe, CountsActualInnerUpdatesForLinearGraphAndZeroRoot) {
hht_reduced_internal::FixedChart chart{};
chart.full_dof_count = 1U;
chart.z_dofs = {0U};
chart.z_columns = {{0U, 1U, false, {{0U, 1.0}}, {0.0}}};
IdentityTangentSolver solver;
const auto evaluate = [](const Vector& q) {
hht_reduced_internal::ConstraintOperators operators;
operators.rows.resize(1U);
operators.rows[0U].value = q[0U];
operators.rows[0U].gradient = {{0U, 1.0}};
return Result<hht_reduced_internal::ConstraintOperators>::Success(
std::move(operators));
};
Statistics statistics;
active = &statistics;
const auto first = hht_reduced_internal::SolveEmbeddingRoot(
chart, Vector{0U}, Vector{1U, 1.0}, evaluate, solver);
active = nullptr;
ASSERT_TRUE(first.HasValue());
EXPECT_EQ(statistics.counts[kInnerCorrection].load(), 1U);
EXPECT_DOUBLE_EQ(first.Value().z[0U], 0.0);
Statistics zero_statistics;
active = &zero_statistics;
const auto zero = hht_reduced_internal::SolveEmbeddingRoot(
chart, Vector{0U}, Vector{1U, 0.0}, evaluate, solver);
active = nullptr;
ASSERT_TRUE(zero.HasValue());
EXPECT_EQ(zero_statistics.counts[kInnerCorrection].load(), 0U);
}
class FailingSolver final : public LinearSolver, public TangentSolver {
public:
Status Factorize(const SparseMatrix&) override {
++factor_calls; return Status::Failure(FailureCategory::kSolver, {});
}
Status FactorizeFresh(const SparseMatrix& matrix) override { return Factorize(matrix); }
Status Solve(const Vector&, Vector&) const override {
++solve_calls; return Status::Failure(FailureCategory::kSolver, {});
}
Status SolveCorrection(const Vector& rhs, Vector& result) const override {
return Solve(rhs, result);
}
int factor_calls = 0;
mutable int solve_calls = 0;
};
TEST(HhtDevelopmentProbe, ForwardsEveryLogicalCallAndPreservesFailure) {
Statistics statistics;
active = &statistics;
FailingSolver backend;
PositiveSolver positive{backend};
CorrectionSolver tangent{backend};
auto matrix = SparseMatrix::FromCoo(0U, 0U, {}, SparsePattern{{0U}, {}});
ASSERT_TRUE(matrix.HasValue());
const Vector rhs{0U};
Vector result{0U};
EXPECT_FALSE(positive.Factorize(matrix.Value()).IsOk());
EXPECT_FALSE(positive.Solve(rhs, result).IsOk());
EXPECT_FALSE(tangent.FactorizeFresh(matrix.Value()).IsOk());
EXPECT_FALSE(tangent.SolveCorrection(rhs, result).IsOk());
active = nullptr;
EXPECT_EQ(backend.factor_calls, 2);
EXPECT_EQ(backend.solve_calls, 2);
EXPECT_EQ(statistics.counts[kFactorCall].load(), 2U);
EXPECT_EQ(statistics.counts[kSolveCall].load(), 2U);
EXPECT_EQ(statistics.counts[kRhs].load(), 2U);
}
TEST(HhtDevelopmentProbe, CountsOnlyWhileActiveAndPreservesMultiplicity) {
Statistics statistics;
active = &statistics;
Count(kOuterCorrection);
Count(kInternalEvaluation, 7U);
active = nullptr;
Count(kOuterCorrection);
EXPECT_EQ(statistics.counts[kOuterCorrection].load(), 1U);
EXPECT_EQ(statistics.counts[kInternalEvaluation].load(), 7U);
EXPECT_EQ(statistics.counts[kInertiaEvaluation].load(), 0U);
}
TEST(HhtDevelopmentProbe, NestedTimesHaveNoDoubleCounting) {
Statistics statistics;
active = &statistics;
{
Scope parent{kProcedure};
{ Scope child{kAssembly}; }
}
active = nullptr;
EXPECT_EQ(statistics.stage_calls[kProcedure], 1U);
EXPECT_EQ(statistics.stage_calls[kAssembly], 1U);
EXPECT_GE(statistics.inclusive_ns[kProcedure], 0);
EXPECT_GE(statistics.inclusive_ns[kAssembly], 0);
EXPECT_EQ(statistics.exclusive_ns[kAssembly],
statistics.inclusive_ns[kAssembly]);
EXPECT_EQ(statistics.exclusive_ns[kProcedure] +
statistics.exclusive_ns[kAssembly],
statistics.inclusive_ns[kProcedure]);
}
} // namespace fesa::hht_development_probe
#endif