Connect MITC4 drilling evidence across analysis procedures
This commit is contained in:
@@ -17,9 +17,12 @@
|
||||
#include "fesa/assembly/parallel_for.h"
|
||||
#include "fesa/assembly/sparse_assembler.h"
|
||||
#include "fesa/elements/element.h"
|
||||
#include "fesa/elements/element_factory.h"
|
||||
#include "fesa/elements/mitc4_shell.h"
|
||||
#include "fesa/fem/dof_manager.h"
|
||||
#include "fesa/math/vector3.h"
|
||||
#include "fesa/model/domain.h"
|
||||
#include "fesa/results/result_recovery.h"
|
||||
#include "results/analysis_state_commit.h"
|
||||
#include "results/beam_result_recovery.h"
|
||||
#include "results/global_equilibrium_recovery.h"
|
||||
@@ -627,3 +630,99 @@ TEST(ResultRecoveryComponents,
|
||||
ExpectStatusCode(status, "nonfinite-recovery-value");
|
||||
ExpectAnalysisStateEqual(state, prior);
|
||||
}
|
||||
|
||||
TEST(Mitc4DrillingEvidence, LinearDirectSpringAcceptsKnownArtificialTorque) {
|
||||
auto definition = MakeShellDefinition();
|
||||
for (std::size_t node = 0U; node < 4U; ++node) {
|
||||
definition.steps[0U].boundaries.push_back(
|
||||
{std::to_string(node + 1U), 1, 5, 0.0, {definition.source_path, 51U}});
|
||||
definition.steps[0U].boundaries.push_back(
|
||||
{std::to_string(node + 1U), 6, 6, 0.125, {definition.source_path, 52U}});
|
||||
}
|
||||
const auto fixture = MakeShellFixture(std::move(definition));
|
||||
auto state = fesa::AnalysisState::Create(*fixture.dofs, {"Step-1", 0U});
|
||||
for (std::size_t node = 0U; node < 4U; ++node)
|
||||
state.Displacement()[6U * node + 5U] = 0.125;
|
||||
const auto status = fesa::ResultRecovery::Recover(
|
||||
*fixture.model, *fixture.dofs, *fixture.stiffness, state);
|
||||
ASSERT_TRUE(status.IsOk()) << (status.Diagnostics().empty() ? "" : status.Diagnostics()[0U].message);
|
||||
}
|
||||
|
||||
TEST(Mitc4DrillingEvidence, LinearTorqueOracleAndSignedGateKeepRealImbalance) {
|
||||
auto definition = MakeShellDefinition();
|
||||
for (std::size_t node = 0U; node < 4U; ++node) {
|
||||
definition.steps[0U].boundaries.push_back(
|
||||
{std::to_string(node + 1U), 1, 5, 0.0, {definition.source_path, 51U}});
|
||||
definition.steps[0U].boundaries.push_back(
|
||||
{std::to_string(node + 1U), 6, 6, 0.125, {definition.source_path, 52U}});
|
||||
}
|
||||
const auto fixture = MakeShellFixture(std::move(definition));
|
||||
auto element = fesa::ElementFactory{}.Create(fixture.domain->Elements()[0U],
|
||||
*fixture.domain);
|
||||
ASSERT_TRUE(element.HasValue());
|
||||
const auto* shell = dynamic_cast<const fesa::Mitc4Shell*>(element.Value().get());
|
||||
ASSERT_NE(shell, nullptr);
|
||||
const auto stiffness = shell->Stiffness();
|
||||
ASSERT_TRUE(stiffness.HasValue());
|
||||
double rotary_trace = 0.0;
|
||||
for (std::size_t node = 0U; node < 4U; ++node)
|
||||
for (std::size_t c = 3U; c < 5U; ++c)
|
||||
rotary_trace += stiffness.Value().physical_local20(5U * node + c, 5U * node + c);
|
||||
const double expected_torque = 4.0 * 0.125 * (1e-3 * rotary_trace / 8.0);
|
||||
auto state = fesa::AnalysisState::Create(*fixture.dofs, {"Step-1", 0U});
|
||||
for (std::size_t node = 0U; node < 4U; ++node)
|
||||
state.Displacement()[6U * node + 5U] = 0.125;
|
||||
ASSERT_TRUE(fesa::ResultRecovery::Recover(*fixture.model, *fixture.dofs,
|
||||
*fixture.stiffness, state).IsOk());
|
||||
ASSERT_TRUE(state.Mitc4Drilling());
|
||||
EXPECT_EQ(state.Mitc4Drilling()->mode, fesa::Mitc4DrillingMode::kDirectSpring);
|
||||
EXPECT_NEAR(state.Equilibrium()[5U], expected_torque, 1e-14);
|
||||
EXPECT_NEAR(state.Mitc4Drilling()->drilling_moment[2U], expected_torque, 1e-14);
|
||||
EXPECT_DOUBLE_EQ(state.Mitc4Drilling()->drilling_moment[0U], 0.0);
|
||||
EXPECT_DOUBLE_EQ(state.Mitc4Drilling()->drilling_moment[1U], 0.0);
|
||||
for (double value : state.Mitc4Drilling()->equilibrium_with_drilling)
|
||||
EXPECT_NEAR(value, 0.0, 1e-14);
|
||||
EXPECT_DOUBLE_EQ(state.PhysicalStrainEnergy(), 0.0);
|
||||
|
||||
auto global = fesa::results_internal::GlobalEquilibriumRecovery(
|
||||
*fixture.domain, *fixture.dofs, *fixture.stiffness, state.Displacement(),
|
||||
state.ExternalForce());
|
||||
ASSERT_TRUE(global.HasValue());
|
||||
for (const int kind : {0, 1, 2, 3}) {
|
||||
auto changed = global.Value();
|
||||
fesa::results_internal::RecoveryCandidate candidate{24U};
|
||||
candidate.shell.mitc4_drilling = *state.Mitc4Drilling();
|
||||
if (kind == 0) candidate.shell.mitc4_drilling->drilling_moment[2U] *= -1.0;
|
||||
if (kind == 1) changed.residual[0U] += 1.0;
|
||||
if (kind == 2) changed.residual[4U] += 1.0;
|
||||
if (kind == 3) candidate.shell.mitc4_drilling->mode =
|
||||
fesa::Mitc4DrillingMode::kLegacyCorotatedTwist;
|
||||
const auto rejected = fesa::results_internal::RecoverShellGlobalEvidence(
|
||||
*fixture.domain, *fixture.dofs, state.ExternalForce(), changed, candidate);
|
||||
EXPECT_FALSE(rejected.IsOk()) << kind;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Mitc4DrillingEvidence, StaticCommitRejectsInvalidEvidenceAtomically) {
|
||||
const auto fixture = MakeShellFixture(MakeShellDefinition());
|
||||
auto state = fesa::AnalysisState::Create(*fixture.dofs, {"Step-1", 0U});
|
||||
fesa::ShellStateCandidate candidate{};
|
||||
candidate.rows = MakeShellRows(0U, 1.0).rows;
|
||||
candidate.mitc4_drilling = fesa::Mitc4DrillingEvidence{
|
||||
fesa::Mitc4DrillingMode::kDirectSpring, {0.0, 0.0, 2.0}, {0, 0, 0, 0, 0, -2}};
|
||||
ASSERT_TRUE(state.CommitShellResults({0U}, candidate).IsOk());
|
||||
for (const int kind : {0, 1, 2, 3, 4}) {
|
||||
auto invalid = candidate;
|
||||
invalid.physical_strain_energy = 77.0;
|
||||
if (kind == 0) invalid.mitc4_drilling->mode = static_cast<fesa::Mitc4DrillingMode>(99);
|
||||
if (kind == 1) invalid.mitc4_drilling->mode = fesa::Mitc4DrillingMode::kLegacyCorotatedTwist;
|
||||
if (kind == 2) invalid.mitc4_drilling->drilling_moment[0U] = std::numeric_limits<double>::infinity();
|
||||
if (kind == 3) invalid.mitc4_drilling->equilibrium_with_drilling[5U] = 2.0;
|
||||
if (kind == 4) invalid.mitc4_drilling.reset();
|
||||
EXPECT_FALSE(state.CommitShellResults({0U}, invalid).IsOk()) << kind;
|
||||
EXPECT_DOUBLE_EQ(state.PhysicalStrainEnergy(), 0.0);
|
||||
ASSERT_TRUE(state.Mitc4Drilling());
|
||||
EXPECT_EQ(state.Mitc4Drilling()->mode, candidate.mitc4_drilling->mode);
|
||||
EXPECT_EQ(state.Mitc4Drilling()->drilling_moment, candidate.mitc4_drilling->drilling_moment);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user