115 lines
4.3 KiB
C++
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
|