feat(result-contract-completion): step 0 — beam-element-end-recovery

This commit is contained in:
KOKO\Mimi
2026-08-02 01:14:40 +09:00
parent 5618636f0d
commit 5fe57cb145
7 changed files with 341 additions and 11 deletions
+188
View File
@@ -22,6 +22,7 @@ constexpr double kShearAreaZ = 0.2;
fesa::Beam3D2Input make_x_axis_input(const double length) {
return {
{{{0.0, 0.0, 0.0}, {length, 0.0, 0.0}}},
{fesa::NodeId{1}, fesa::NodeId{2}},
{fesa::MaterialId{1}, "elastic", kYoung, kPoisson},
{
fesa::SectionId{1},
@@ -369,4 +370,191 @@ TEST(Beam3D2, PreservesGlobalEnergyUnderRigidCoordinateRotation) {
4096.0 * std::numeric_limits<double>::epsilon());
}
TEST(BeamRecovery, RecoversPureAxialStrainAndForceAtBothEnds) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[6] = 0.4;
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
EXPECT_DOUBLE_EQ(results[0].xi, -1.0);
EXPECT_EQ(results[0].end_node, fesa::NodeId{101});
EXPECT_DOUBLE_EQ(results[1].xi, 1.0);
EXPECT_EQ(results[1].end_node, fesa::NodeId{202});
for (const auto& result : results) {
expect_relative_near(result.section_strain[0], 0.2);
expect_relative_near(result.section_force[0], 16.8);
expect_relative_near(result.centroid_sigma_xx, 42.0);
for (std::size_t component = 1; component < 6; ++component) {
expect_relative_near(result.section_strain[component], 0.0);
expect_relative_near(result.section_force[component], 0.0);
}
EXPECT_TRUE(result.sigma_xx.empty());
}
}
TEST(BeamRecovery, RecoversPureTorsionAtBothEnds) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[9] = 0.6;
const double shear_modulus = kYoung / (2.0 * (1.0 + kPoisson));
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.section_strain[3], 0.3);
expect_relative_near(
result.section_force[3],
shear_modulus * kTorsionJ * 0.3);
for (const std::size_t component :
std::array<std::size_t, 5>{0, 1, 2, 4, 5}) {
expect_relative_near(result.section_strain[component], 0.0);
expect_relative_near(result.section_force[component], 0.0);
}
}
}
TEST(BeamRecovery, UsesReducedIntegrationPointForShearAtBothEnds) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
std::array<double, 12> displacement{};
displacement[7] = 1.2;
displacement[5] = 0.2;
displacement[11] = 0.6;
displacement[8] = -0.4;
displacement[4] = 0.1;
displacement[10] = 0.5;
const double shear_modulus = kYoung / (2.0 * (1.0 + kPoisson));
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.section_strain[1], 0.2);
expect_relative_near(result.section_strain[2], 0.1);
expect_relative_near(
result.section_force[1],
shear_modulus * kShearAreaY * 0.2);
expect_relative_near(
result.section_force[2],
shear_modulus * kShearAreaZ * 0.1);
}
}
TEST(BeamRecovery, UsesBeamFrameForGlobalDisplacements) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.coordinates = {{{0.0, 0.0, 0.0}, {0.0, 2.0, 0.0}}};
input.section.orientation = {0.0, 0.0, 1.0};
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[7] = 0.4;
displacement[10] = 0.6;
const double shear_modulus = kYoung / (2.0 * (1.0 + kPoisson));
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.section_strain[0], 0.2);
expect_relative_near(result.section_force[0], 16.8);
expect_relative_near(result.section_strain[3], 0.3);
expect_relative_near(
result.section_force[3],
shear_modulus * kTorsionJ * 0.3);
}
}
TEST(SectionForce, RecoversPureBendingAboutLocalYAtBothEnds) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[4] = -0.4;
displacement[10] = 0.4;
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.section_strain[4], 0.4);
expect_relative_near(result.section_force[4], 2.52);
for (const std::size_t component :
std::array<std::size_t, 5>{0, 1, 2, 3, 5}) {
expect_relative_near(result.section_strain[component], 0.0);
expect_relative_near(result.section_force[component], 0.0);
}
}
}
TEST(SectionForce, RecoversPureBendingAboutLocalZAtBothEnds) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[5] = 0.25;
displacement[11] = -0.25;
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.section_strain[5], -0.25);
expect_relative_near(result.section_force[5], -2.625);
for (const std::size_t component :
std::array<std::size_t, 5>{0, 1, 2, 3, 4}) {
expect_relative_near(result.section_strain[component], 0.0);
expect_relative_near(result.section_force[component], 0.0);
}
}
}
TEST(SectionForce, PreservesBiaxialBendingSignsAtBothEnds) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[4] = -0.4;
displacement[10] = 0.4;
displacement[5] = 0.25;
displacement[11] = -0.25;
const auto results = fesa::recover_beam3d2(input, displacement, {});
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.section_force[4], 2.52);
expect_relative_near(result.section_force[5], -2.625);
}
}
TEST(CentroidStress, UsesAxialStressAndPreservesRecoveryPointOrder) {
fesa::Beam3D2Input input = make_x_axis_input(2.0);
input.node_ids = {fesa::NodeId{101}, fesa::NodeId{202}};
std::array<double, 12> displacement{};
displacement[6] = 0.2;
displacement[4] = -0.2;
displacement[10] = 0.2;
displacement[5] = 0.3;
displacement[11] = -0.3;
const std::array<std::array<double, 2>, 3> recovery_points{{
{2.0, 3.0},
{-1.0, 4.0},
{5.0, -2.0},
}};
const auto results = fesa::recover_beam3d2(
input,
displacement,
recovery_points);
ASSERT_EQ(results.size(), 2U);
for (const auto& result : results) {
expect_relative_near(result.centroid_sigma_xx, 21.0);
ASSERT_EQ(result.sigma_xx.size(), recovery_points.size());
expect_relative_near(result.sigma_xx[0], 273.0);
expect_relative_near(result.sigma_xx[1], 126.0);
expect_relative_near(result.sigma_xx[2], 252.0);
}
}
} // namespace