feat(linear-static-mitc4-shell): step 5 - mitc4-physical-recovery
This commit is contained in:
@@ -823,3 +823,114 @@ TEST(Mitc4ShellDrilling, FailsNonfiniteReferenceAndStabilizesEachPureDrillCoordi
|
||||
repeatedFailure.status().diagnostics()[0].message,
|
||||
failure.status().diagnostics()[0].message);
|
||||
}
|
||||
|
||||
// MITC4-KERNEL-007
|
||||
TEST(Mitc4ShellDrilling, ExcludesPureDrillFromPhysicalRecoveryAndEnergy) {
|
||||
const auto nodes = planarNodes();
|
||||
const auto shellCandidate = fesa::Mitc4Shell::create(
|
||||
nodePointers(nodes), directors(), section(), material());
|
||||
ASSERT_TRUE(shellCandidate.hasValue());
|
||||
const auto& shell = shellCandidate.value();
|
||||
const auto stiffnessCandidate = shell.stiffness();
|
||||
ASSERT_TRUE(stiffnessCandidate.hasValue());
|
||||
|
||||
for (std::size_t nodeIndex = 0U; nodeIndex < nodes.size(); ++nodeIndex) {
|
||||
fesa::Vector pureDrill{24U};
|
||||
pureDrill[6U * nodeIndex + 5U] = 1.0;
|
||||
EXPECT_GT(
|
||||
stiffnessCandidate.value().stabilizedGlobal24.multiply(pureDrill).norm(),
|
||||
0.0);
|
||||
|
||||
const auto recoveryCandidate = shell.recoverPhysical(pureDrill);
|
||||
ASSERT_TRUE(recoveryCandidate.hasValue());
|
||||
const auto& recovery = recoveryCandidate.value();
|
||||
EXPECT_DOUBLE_EQ(recovery.strainEnergy, 0.0);
|
||||
for (const auto& point : recovery.points) {
|
||||
for (double value : point.generalizedStrain) {
|
||||
EXPECT_DOUBLE_EQ(value, 0.0);
|
||||
}
|
||||
for (double value : point.sectionResultant) {
|
||||
EXPECT_DOUBLE_EQ(value, 0.0);
|
||||
}
|
||||
for (const auto& stress : point.inPlaneStress) {
|
||||
for (double value : stress) {
|
||||
EXPECT_DOUBLE_EQ(value, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MITC4-PHYSREC-001
|
||||
TEST(Mitc4ShellPhysicalRecovery, RecoversHandFieldAtFixedLocationsAndSectionPositions) {
|
||||
const auto nodes = planarNodes();
|
||||
const auto shellCandidate = fesa::Mitc4Shell::create(
|
||||
nodePointers(nodes), directors(), section(), material());
|
||||
ASSERT_TRUE(shellCandidate.hasValue());
|
||||
const auto& shell = shellCandidate.value();
|
||||
|
||||
constexpr std::array<double, 8> generalized{
|
||||
0.1, -0.05, 0.2, 0.3, -0.15, 0.25, 0.4, -0.3};
|
||||
fesa::Vector globalField{24U};
|
||||
for (std::size_t nodeIndex = 0U; nodeIndex < nodes.size(); ++nodeIndex) {
|
||||
const double x = nodes[nodeIndex].coordinates[0];
|
||||
const double y = nodes[nodeIndex].coordinates[1];
|
||||
const std::size_t offset = 6U * nodeIndex;
|
||||
globalField[offset] = generalized[0] * x + 0.5 * generalized[2] * y;
|
||||
globalField[offset + 1U] =
|
||||
generalized[1] * y + 0.5 * generalized[2] * x;
|
||||
globalField[offset + 2U] =
|
||||
generalized[6] * x + generalized[7] * y -
|
||||
0.5 * generalized[5] * x * y;
|
||||
globalField[offset + 3U] =
|
||||
-generalized[4] * y - 0.5 * generalized[5] * x;
|
||||
globalField[offset + 4U] =
|
||||
generalized[3] * x + 0.5 * generalized[5] * y;
|
||||
}
|
||||
|
||||
const auto recoveryCandidate = shell.recoverPhysical(globalField);
|
||||
ASSERT_TRUE(recoveryCandidate.hasValue());
|
||||
const auto& recovery = recoveryCandidate.value();
|
||||
const double gauss = 1.0 / std::sqrt(3.0);
|
||||
const std::array<std::array<double, 2>, 4> expectedCoordinates{
|
||||
std::array<double, 2>{-gauss, -gauss},
|
||||
std::array<double, 2>{gauss, -gauss},
|
||||
std::array<double, 2>{gauss, gauss},
|
||||
std::array<double, 2>{-gauss, gauss}};
|
||||
constexpr std::array<double, 8> expectedResultant{
|
||||
22.4, -6.4, 19.2, 22.4, -6.4, 8.0, 32.0, -24.0};
|
||||
constexpr std::array<std::array<double, 3>, 3> expectedStress{
|
||||
std::array<double, 3>{-22.4, 6.4, -2.4},
|
||||
std::array<double, 3>{11.2, -3.2, 9.6},
|
||||
std::array<double, 3>{44.8, -12.8, 21.6}};
|
||||
|
||||
ASSERT_EQ(recovery.points.size(), expectedCoordinates.size());
|
||||
for (std::size_t pointIndex = 0U;
|
||||
pointIndex < recovery.points.size(); ++pointIndex) {
|
||||
const auto& point = recovery.points[pointIndex];
|
||||
EXPECT_EQ(point.naturalCoordinates, expectedCoordinates[pointIndex]);
|
||||
expectOrthonormalRightHanded(point.localFrame);
|
||||
expectVectorNear(point.localFrame.e1, {1.0, 0.0, 0.0});
|
||||
expectVectorNear(point.localFrame.e2, {0.0, 1.0, 0.0});
|
||||
expectVectorNear(point.localFrame.e3, {0.0, 0.0, 1.0});
|
||||
for (std::size_t component = 0U;
|
||||
component < generalized.size(); ++component) {
|
||||
EXPECT_NEAR(
|
||||
point.generalizedStrain[component], generalized[component],
|
||||
1.0e-12);
|
||||
EXPECT_NEAR(
|
||||
point.sectionResultant[component], expectedResultant[component],
|
||||
1.0e-12);
|
||||
}
|
||||
for (std::size_t position = 0U;
|
||||
position < expectedStress.size(); ++position) {
|
||||
for (std::size_t component = 0U;
|
||||
component < expectedStress[position].size(); ++component) {
|
||||
EXPECT_NEAR(
|
||||
point.inPlaneStress[position][component],
|
||||
expectedStress[position][component], 1.0e-12);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_NEAR(recovery.strainEnergy, 72.16, 1.0e-12);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user