From d465245bdd53e6922237302614bf791688ac702c Mon Sep 17 00:00:00 2001 From: "KOKO\\Mimi" Date: Sat, 26 Sep 2026 23:57:39 +0900 Subject: [PATCH] test: cover unloaded HHT free degree channels --- .../analysis/hht_dynamic_procedure_test.cpp | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/unit/analysis/hht_dynamic_procedure_test.cpp b/tests/unit/analysis/hht_dynamic_procedure_test.cpp index f72ba56..b4013e5 100644 --- a/tests/unit/analysis/hht_dynamic_procedure_test.cpp +++ b/tests/unit/analysis/hht_dynamic_procedure_test.cpp @@ -83,6 +83,54 @@ TEST(HhtDynamicProcedure, ClampedStepLoadHasPhysicalReactionAndZeroMotion) { } } +TEST(HhtDynamicProcedure, UnloadedFreeChannelsRemainExactlyAtRest) { + for (const int fixed_first_dof : {0, 1, 4}) { + SCOPED_TRACE(fixed_first_dof); + auto definition = MakeDefinition(false); + if (fixed_first_dof != 0) { + definition.dynamic_step->boundaries = {{"All", + fixed_first_dof, + fixed_first_dof + 2, + 0.0, + {"dynamic-state.inp", 11U}}}; + } + auto domain = fesa::Domain::Create(std::move(definition)); + ASSERT_TRUE(domain.HasValue()); + fesa::SerialParallelFor parallel; + fesa::MklPardisoSolver mass; + fesa::MklPardisoTangentSolver tangent; + fesa::NewtonIterationLogWriter log; + const auto path = + std::filesystem::temp_directory_path() / "fesa-hht-rest.log"; + ASSERT_TRUE(log.Open(path).IsOk()); + auto result = fesa::HhtDynamicProcedureExecutor(parallel, mass, tangent) + .Execute(domain.Value(), log); + ASSERT_TRUE(log.Close().IsOk()); + std::filesystem::remove(path); + ASSERT_TRUE(result.HasValue()) + << (result.HasValue() + ? "" + : result.GetStatus().Diagnostics().front().message); + ASSERT_EQ(result.Value().state.AcceptedFrames().size(), 3U); + for (const auto& frame : result.Value().state.AcceptedFrames()) { + EXPECT_EQ(frame.iteration_count, 0U); + for (const auto* values : + {&frame.generalized_coordinates, &frame.velocity, + &frame.acceleration, &frame.algorithmic_acceleration, + &frame.reaction, &frame.residual}) { + for (std::size_t i = 0; i < values->Size(); ++i) + EXPECT_DOUBLE_EQ((*values)[i], 0.0); + } + EXPECT_DOUBLE_EQ(frame.kinetic_energy, 0.0); + EXPECT_DOUBLE_EQ(frame.physical_strain_energy, 0.0); + EXPECT_DOUBLE_EQ(frame.drilling_energy, 0.0); + EXPECT_DOUBLE_EQ(frame.energy_defect, 0.0); + for (const double metric : frame.free_residual_metrics) + EXPECT_DOUBLE_EQ(metric, 0.0); + } + } +} + TEST(HhtDynamicProcedure, LargeDirectStepStartsFromAcceptedGeometry) { auto definition = MakeDefinition(false); definition.materials[0U].youngs_modulus = 1e9;