Integrate Refactor solver sources and dual MSVC CMake builds
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
#include "fesa/analysis/solid_static_procedure.h"
|
||||
#include "analysis/solid_static_core.h"
|
||||
#include "analysis/equilibrium_algorithm.h"
|
||||
#include "fesa/core/source_identity.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -7,6 +10,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
@@ -824,3 +828,116 @@ TEST(SolidStaticProcedure,
|
||||
<< " energy=" << frame.physical_strain_energy << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
fesa::Status StaticPolicyFailure() {
|
||||
return fesa::Status::Failure(fesa::FailureCategory::kSolver,
|
||||
{{fesa::Severity::kError, "injected-static-algorithm", {}, "STATIC",
|
||||
"original-owner", "Original algorithm failure."}});
|
||||
}
|
||||
class UnusedStaticSolvers final : public fesa::LinearSolver,
|
||||
public fesa::TangentSolver {
|
||||
public:
|
||||
mutable int calls = 0;
|
||||
fesa::Status Factorize(const fesa::SparseMatrix&) override {
|
||||
++calls; return StaticPolicyFailure();
|
||||
}
|
||||
fesa::Status Solve(const fesa::Vector&, fesa::Vector&) const override {
|
||||
++calls; return StaticPolicyFailure();
|
||||
}
|
||||
fesa::Status FactorizeFresh(const fesa::SparseMatrix&) override {
|
||||
++calls; return StaticPolicyFailure();
|
||||
}
|
||||
fesa::Status SolveCorrection(const fesa::Vector&, fesa::Vector&) const override {
|
||||
++calls; return StaticPolicyFailure();
|
||||
}
|
||||
};
|
||||
class RefusingStaticAlgorithm final : public fesa::EquilibriumAlgorithm {
|
||||
public:
|
||||
RefusingStaticAlgorithm(const fesa::SolidStaticState& state, bool& destroyed)
|
||||
: state_(state), destroyed_(destroyed) {}
|
||||
~RefusingStaticAlgorithm() override { destroyed_ = true; }
|
||||
int calls = 0;
|
||||
fesa::SolidStaticFrame baseline;
|
||||
fesa::Status SolveCurrentStep(std::uint32_t first, std::uint32_t last,
|
||||
const Evaluation&) override {
|
||||
++calls;
|
||||
EXPECT_EQ(first, 1U); EXPECT_EQ(last, 100U);
|
||||
EXPECT_TRUE(state_.AcceptedFrames().empty());
|
||||
EXPECT_TRUE(state_.IterationRecords().empty());
|
||||
baseline = state_.CommittedState();
|
||||
return StaticPolicyFailure();
|
||||
}
|
||||
private:
|
||||
const fesa::SolidStaticState& state_;
|
||||
bool& destroyed_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(SolidStaticProcedure, InjectedAlgorithmFailurePreservesInitializedBaseline) {
|
||||
auto domain = Map(Deck(Supports(), Tension(1.0), true));
|
||||
ASSERT_TRUE(domain.HasValue()) << Message(domain.GetStatus());
|
||||
fesa::SerialParallelFor serial;
|
||||
UnusedStaticSolvers solvers;
|
||||
fesa::SolidStaticState state;
|
||||
bool destroyed = false;
|
||||
auto owned = std::make_unique<RefusingStaticAlgorithm>(state, destroyed);
|
||||
auto* selected = owned.get();
|
||||
std::unique_ptr<fesa::EquilibriumAlgorithm> algorithm = std::move(owned);
|
||||
{
|
||||
fesa::SolidStaticCore core(serial, solvers, solvers, *algorithm);
|
||||
const auto status = core.ExecuteInto(domain.Value(), state);
|
||||
ASSERT_FALSE(status.IsOk());
|
||||
EXPECT_EQ(status.Category(), fesa::FailureCategory::kSolver);
|
||||
ASSERT_EQ(status.Diagnostics().size(), 1U);
|
||||
const auto& diagnostic = status.Diagnostics()[0];
|
||||
EXPECT_EQ(diagnostic.code, "injected-static-algorithm");
|
||||
EXPECT_EQ(diagnostic.keyword, "STATIC");
|
||||
EXPECT_EQ(diagnostic.entity_identity, "original-owner");
|
||||
EXPECT_EQ(diagnostic.message, "Original algorithm failure.");
|
||||
}
|
||||
EXPECT_EQ(selected->calls, 1); EXPECT_EQ(solvers.calls, 0);
|
||||
EXPECT_TRUE(state.AcceptedFrames().empty());
|
||||
EXPECT_TRUE(state.IterationRecords().empty());
|
||||
// Core initialization legitimately installs the zero-factor baseline before
|
||||
// iteration. Compare to that exact baseline at algorithm entry, not to the
|
||||
// initially uninitialized observer.
|
||||
const auto& expected = selected->baseline;
|
||||
const auto& actual = state.CommittedState();
|
||||
EXPECT_EQ(actual.frame_index, expected.frame_index);
|
||||
EXPECT_EQ(actual.increment_index, expected.increment_index);
|
||||
EXPECT_DOUBLE_EQ(actual.load_factor, expected.load_factor);
|
||||
EXPECT_EQ(actual.iteration_count, expected.iteration_count);
|
||||
EXPECT_EQ(actual.is_factor_one, expected.is_factor_one);
|
||||
EXPECT_EQ(actual.nodal_internal_order, expected.nodal_internal_order);
|
||||
ASSERT_EQ(actual.nodal_source_ids.size(), expected.nodal_source_ids.size());
|
||||
for (std::size_t i = 0; i < actual.nodal_source_ids.size(); ++i)
|
||||
EXPECT_TRUE(fesa::SourceIdentityEquals(actual.nodal_source_ids[i], expected.nodal_source_ids[i]));
|
||||
const auto same_vector = [](const fesa::Vector& a, const fesa::Vector& b) {
|
||||
ASSERT_EQ(a.Size(), b.Size());
|
||||
for (std::size_t i = 0; i < a.Size(); ++i) EXPECT_DOUBLE_EQ(a[i], b[i]);
|
||||
};
|
||||
same_vector(actual.displacement, expected.displacement);
|
||||
same_vector(actual.internal_force, expected.internal_force);
|
||||
same_vector(actual.external_force, expected.external_force);
|
||||
same_vector(actual.residual, expected.residual); same_vector(actual.reaction, expected.reaction);
|
||||
EXPECT_DOUBLE_EQ(actual.physical_strain_energy, expected.physical_strain_energy);
|
||||
EXPECT_EQ(actual.global_equilibrium, expected.global_equilibrium);
|
||||
EXPECT_EQ(actual.balance.internal_force_sum, expected.balance.internal_force_sum);
|
||||
EXPECT_EQ(actual.balance.reference_internal_moment, expected.balance.reference_internal_moment);
|
||||
EXPECT_EQ(actual.balance.current_internal_moment, expected.balance.current_internal_moment);
|
||||
EXPECT_EQ(actual.balance.free_residual_moment, expected.balance.free_residual_moment);
|
||||
EXPECT_EQ(actual.balance.linearization_moment, expected.balance.linearization_moment);
|
||||
EXPECT_EQ(actual.balance.internal_force_scale, expected.balance.internal_force_scale);
|
||||
EXPECT_EQ(actual.balance.reference_moment_scale, expected.balance.reference_moment_scale);
|
||||
EXPECT_EQ(actual.balance.current_moment_scale, expected.balance.current_moment_scale);
|
||||
ASSERT_EQ(actual.solid_results.size(), expected.solid_results.size());
|
||||
for (std::size_t i = 0; i < actual.solid_results.size(); ++i) {
|
||||
const auto& a = actual.solid_results[i]; const auto& b = expected.solid_results[i];
|
||||
EXPECT_EQ(a.element, b.element); EXPECT_EQ(a.integration_point, b.integration_point);
|
||||
EXPECT_EQ(a.natural_coordinates, b.natural_coordinates);
|
||||
EXPECT_EQ(a.reference_coordinates, b.reference_coordinates);
|
||||
EXPECT_EQ(a.cauchy_stress, b.cauchy_stress); EXPECT_EQ(a.strain, b.strain);
|
||||
}
|
||||
EXPECT_FALSE(destroyed); algorithm.reset(); EXPECT_TRUE(destroyed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user