fix(elements): reject rounded loss of Hex8 bulk stiffness
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "fesa/assembly/parallel_for.h"
|
||||
#include "fesa/assembly/sparse_assembler.h"
|
||||
#include "fesa/elements/element.h"
|
||||
#include "fesa/elements/hex8_element.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/math/vector3.h"
|
||||
#include "fesa/model/domain.h"
|
||||
@@ -1149,3 +1150,50 @@ TEST(ResultRecovery, InvalidLaterShellLeavesEntirePriorStateUnchanged) {
|
||||
EXPECT_EQ(state.Equilibrium(), prior_equilibrium);
|
||||
EXPECT_EQ(state.VerificationMetrics(), prior_metrics);
|
||||
}
|
||||
|
||||
TEST(ResultRecovery, RealSolidPayloadFailsClosedAndPreservesLegacyState) {
|
||||
const auto fixture = MakeFixture();
|
||||
const auto input = MakeAxialEquilibriumState(fixture);
|
||||
auto state = fesa::AnalysisState::Create(*fixture.dofs, {"prior-step", 9U});
|
||||
state.Displacement()[0] = 37.0;
|
||||
state.InternalForce()[0] = 19.0;
|
||||
const auto prior_bundle = MakeFakeBeamBundle(*fixture.domain, 0U, 11.0);
|
||||
state.EndpointResults() =
|
||||
std::get<fesa::BeamElementResultRows>(prior_bundle.payload).endpoint_rows;
|
||||
fesa::Hex8Element::Coordinates x{{{-1, -1, -1},
|
||||
{1, -1, -1},
|
||||
{1, 1, -1},
|
||||
{-1, 1, -1},
|
||||
{-1, -1, 1},
|
||||
{1, -1, 1},
|
||||
{1, 1, 1},
|
||||
{-1, 1, 1}}};
|
||||
const auto identity = fixture.domain->Elements()[0U].SourceId();
|
||||
fesa::ElementDofLayout layout{
|
||||
identity,
|
||||
{0, 1, 2, 3, 4, 5, 6, 7},
|
||||
{fesa::DofComponent::kUx, fesa::DofComponent::kUy,
|
||||
fesa::DofComponent::kUz}};
|
||||
const fesa::LinearElasticMaterial material{"solid", 120.0, .25, {}};
|
||||
auto solid = fesa::Hex8Element::Create(0U, layout, x, material);
|
||||
ASSERT_TRUE(solid.HasValue());
|
||||
auto recovered = solid.Value().Recover(fesa::Vector{24U});
|
||||
ASSERT_TRUE(recovered.HasValue());
|
||||
ASSERT_EQ(std::get<fesa::SolidElementResultRows>(recovered.Value().payload)
|
||||
.rows.size(),
|
||||
8U);
|
||||
// A legacy six-DOF beam scatter forwards the real solid payload to the
|
||||
// generic visitor; it must reject the incompatible payload before commit.
|
||||
FakeRecoveryElement runtime{MakeRuntimeLayout(*fixture.domain, 0U),
|
||||
std::move(recovered.Value())};
|
||||
const fesa::Status status = fesa::ResultRecovery::Recover(
|
||||
*fixture.model, {std::cref(runtime)}, *fixture.dofs, *fixture.stiffness,
|
||||
input.Displacement(), input.ExternalForce(), state);
|
||||
ExpectStatusCode(status, "unsupported-solid-result-recovery");
|
||||
EXPECT_DOUBLE_EQ(state.Displacement()[0], 37.0);
|
||||
EXPECT_DOUBLE_EQ(state.InternalForce()[0], 19.0);
|
||||
ASSERT_EQ(state.EndpointResults().size(), 2U);
|
||||
EXPECT_DOUBLE_EQ(state.EndpointResults()[0].section_resultant[0], 11.0);
|
||||
EXPECT_EQ(state.Identity().step_name, "prior-step");
|
||||
EXPECT_EQ(state.Identity().frame_index, 9U);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user