Connect MITC4 drilling evidence across analysis procedures

This commit is contained in:
KOKO\Mimi
2026-10-20 09:21:39 +09:00
parent 294ffbf8a1
commit c6188b3ad7
30 changed files with 763 additions and 28 deletions
@@ -18,6 +18,9 @@
#include "fesa/analysis/prepared_analysis.h"
#include "fesa/assembly/parallel_for.h"
#include "fesa/assembly/sparse_assembler.h"
#include "fesa/elements/element_factory.h"
#include "fesa/results/result_recovery.h"
#include "elements/mitc4_drilling_internal.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/model/domain.h"
#include "fesa/model/model_types.h"
@@ -132,6 +135,8 @@ TEST(LinearFrequencyProcedureExecutor,
fesa::LinearFrequencyProcedureExecutor{}.Execute(domain.Value());
ASSERT_TRUE(result.HasValue()) << StatusText(result.GetStatus());
const auto& state = result.Value();
ASSERT_TRUE(state.drilling_mode);
EXPECT_EQ(*state.drilling_mode, fesa::Mitc4DrillingMode::kDirectSpring);
ASSERT_EQ(state.modes.size(), 1U);
EXPECT_EQ(state.mass_null_dimension, 0U);
EXPECT_EQ(state.finite_dimension, 1U);
@@ -189,10 +194,10 @@ TEST(LinearFrequencyProcedureExecutor,
}
}
// E2-C09 is a pencil oracle. The public static contract conflict is recorded
// separately; direct covariance does not certify spatial moment equilibrium.
// E2-C09 keeps raw spatial imbalance visible while the direct-spring gate
// subtracts only the separately recovered artificial internal moment.
TEST(LinearFrequencyProcedureExecutor,
PartialBoundaryStaticRejectsUnbalancedDrillingMoment) {
PartialBoundaryStaticSeparatesArtificialMomentAndPreservesLegacyGate) {
const auto domain = PanelDomain(false, false, true);
ASSERT_TRUE(domain.HasValue());
const fesa::SerialParallelFor serial;
@@ -200,9 +205,32 @@ TEST(LinearFrequencyProcedureExecutor,
const auto result =
fesa::LinearStaticProcedureExecutor{serial, solver}.Execute(
domain.Value());
ASSERT_FALSE(result.HasValue());
EXPECT_NE(StatusText(result.GetStatus())
.find("global-equilibrium-tolerance-failure"),
ASSERT_TRUE(result.HasValue()) << StatusText(result.GetStatus());
const auto& state = result.Value().state;
ASSERT_TRUE(state.Mitc4Drilling());
EXPECT_NE(state.Equilibrium()[5U], 0.0);
for (std::size_t c = 0U; c < 3U; ++c) {
EXPECT_NEAR(state.Equilibrium()[3U + c], state.Mitc4Drilling()->drilling_moment[c], 1e-14);
EXPECT_NEAR(state.Mitc4Drilling()->equilibrium_with_drilling[3U + c], 0.0, 1e-14);
}
auto model = fesa::AnalysisModel::Create(domain.Value());
ASSERT_TRUE(model.HasValue());
auto dofs = fesa::DofManager::Create(model.Value());
ASSERT_TRUE(dofs.HasValue());
auto element = fesa::ElementFactory{}.Create(domain.Value().Elements()[0U], domain.Value());
ASSERT_TRUE(element.HasValue());
auto* shell = dynamic_cast<fesa::Mitc4Shell*>(element.Value().get());
ASSERT_NE(shell, nullptr);
*shell = fesa::mitc4_drilling_internal::TestAccess::WithMode(
*shell, fesa::Mitc4DrillingMode::kLegacyCorotatedTwist);
fesa::ElementView view{std::cref(*shell)};
auto stiffness = fesa::SparseAssembler::Assemble(view, dofs.Value(), serial);
ASSERT_TRUE(stiffness.HasValue());
auto legacy_state = fesa::AnalysisState::Create(dofs.Value(), {"Step-1", 0U});
const auto legacy = fesa::ResultRecovery::Recover(model.Value(), view, dofs.Value(),
stiffness.Value(), state.Displacement(), state.ExternalForce(), legacy_state);
ASSERT_FALSE(legacy.IsOk());
EXPECT_NE(StatusText(legacy).find("global-equilibrium-tolerance-failure"),
std::string::npos);
}