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
@@ -16,6 +16,13 @@
#include <vector>
#include "fesa/elements/finite_rotation.h"
#include "fesa/analysis/prepared_analysis.h"
#include "fesa/analysis/nonlinear_static_procedure.h"
#include "fesa/analysis/newton_iteration_log.h"
#include "fesa/assembly/parallel_for.h"
#include "fesa/elements/element_factory.h"
#include "fesa/elements/mitc4_shell.h"
#include "fesa/solvers/linear/mkl_pardiso_tangent_solver.h"
#include "fesa/math/vector3.h"
namespace {
@@ -343,3 +350,57 @@ TEST(NonlinearStaticProcedure,
}
} // namespace
TEST(Mitc4DrillingEvidence, NonlinearAndPressureFramesRetainSignedTorqueOracle) {
for (const bool pressure : {false, true}) {
SCOPED_TRACE(pressure);
TempDirectory directory{"drilling"};
auto deck = AllConstrainedNonlinearShellDeck();
const auto boundary = deck.find("All, 1, 6");
ASSERT_NE(boundary, std::string::npos);
deck.replace(boundary, std::string{"All, 1, 6"}.size(), "All, 1, 5\nAll, 6, 6, 0.125");
if (pressure) {
const auto assembly_end = deck.find("*End Assembly");
deck.insert(assembly_end, "*Surface, TYPE=ELEMENT, NAME=Pressure\nShell-1.1, SPOS\n");
deck.insert(deck.find("*End Step"), "*Dsload\nPressure, P, 4.0\n");
}
const auto path = directory.Path() / "drilling.inp";
WriteText(path, deck);
auto prepared = fesa::PrepareAnalysisInput(path);
ASSERT_TRUE(prepared.HasValue());
const auto& domain = prepared.Value().domain;
auto element = fesa::ElementFactory{}.Create(domain.Elements()[0U], 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 trace = 0.0;
for (std::size_t node = 0U; node < 4U; ++node)
for (std::size_t c = 3U; c < 5U; ++c)
trace += stiffness.Value().physical_local20(5U * node + c, 5U * node + c);
const double kd = 1e-3 * trace / 8.0;
fesa::SerialParallelFor serial;
fesa::MklPardisoTangentSolver tangent;
fesa::NewtonIterationLogWriter log;
ASSERT_TRUE(log.Open(directory.Path() / "drilling.log").IsOk());
auto result = fesa::NonlinearStaticProcedureExecutor{serial, tangent}.Execute(domain, log);
ASSERT_TRUE(log.Close().IsOk());
ASSERT_TRUE(result.HasValue()) << (result.GetStatus().Diagnostics().empty() ? "" : result.GetStatus().Diagnostics()[0U].message);
ASSERT_EQ(result.Value().state.AcceptedFrames().size(), 10U);
for (const auto& frame : result.Value().state.AcceptedFrames()) {
ASSERT_TRUE(frame.mitc4_drilling);
EXPECT_EQ(frame.mitc4_drilling->mode, fesa::Mitc4DrillingMode::kDirectSpring);
const double torque = 4.0 * kd * 0.125 * frame.load_factor;
EXPECT_NEAR(frame.global_equilibrium[5U], torque, 1e-13);
EXPECT_NEAR(frame.mitc4_drilling->drilling_moment[2U], torque, 1e-13);
for (const double value : frame.mitc4_drilling->equilibrium_with_drilling)
EXPECT_NEAR(value, 0.0, 1e-13);
EXPECT_NEAR(frame.physical_strain_energy, 0.0, 1e-20);
if (pressure) EXPECT_NE(frame.external_force[2U], 0.0);
}
ASSERT_TRUE(result.Value().state.CommittedState().mitc4_drilling);
EXPECT_EQ(result.Value().state.CommittedState().mitc4_drilling->drilling_moment,
result.Value().state.AcceptedFrames().back().mitc4_drilling->drilling_moment);
}
}