feat(nonlinear-static-newton-raphson): step 11 - equilibrium-projection-and-reference-gate

This commit is contained in:
KOKO\Mimi
2026-08-28 09:22:33 +09:00
parent 65b56b1755
commit 6dbf1b2bcf
30 changed files with 13122 additions and 728 deletions
@@ -80,6 +80,14 @@ std::string ValueAfterEquals(const std::string& field) {
return field.substr(field.find('=') + 1U);
}
fesa::Vector VectorFrom(const std::vector<double>& values) {
fesa::Vector result{values.size()};
for (std::size_t index = 0U; index < values.size(); ++index) {
result[index] = values[index];
}
return result;
}
fesa::NewtonChannelDecision MakeDecision(const std::string& identity) {
return {identity,
0.0012345678901234567,
@@ -324,4 +332,84 @@ TEST(NewtonIterationLog, LeavesZeroByteLogForNonNewtonControlledFailurePath) {
EXPECT_EQ(std::filesystem::file_size(path), 0U);
}
// NSNR-LOG-012
TEST(NewtonIterationLog,
SerializesEvaluatorProducedExternalScaleResidualDecisions) {
TempDirectory directory{"external-scale"};
const fesa::NewtonConvergenceInput zero_external{
{"residual_force", VectorFrom({1.0e-3}), VectorFrom({2.0}),
VectorFrom({0.0})},
{"residual_moment", VectorFrom({1.0e-3}), VectorFrom({3.0}),
VectorFrom({0.0})},
{"correction_translation", VectorFrom({1.0e-2}), VectorFrom({1.0})},
{"correction_rotation", VectorFrom({1.0e-2}), VectorFrom({1.0})},
};
const auto zero_decisions = fesa::EvaluateNewtonConvergence(zero_external);
auto zero_record = CompleteRecord();
zero_record.force_residual = zero_decisions.force_residual;
zero_record.moment_residual = zero_decisions.moment_residual;
zero_record.translation_correction = zero_decisions.translation_correction;
zero_record.rotation_correction = zero_decisions.rotation_correction;
zero_record.combined_passed = zero_decisions.combined_passed;
const auto zero_fields =
WriteAndRead(directory.Path() / "zero_log.txt", zero_record);
ASSERT_EQ(zero_fields.size(), 39U);
EXPECT_EQ(FieldValue(zero_fields, "schema"), "schema=nsnr-log-v1");
EXPECT_EQ(FieldValue(zero_fields, "residual_force_denominator_scale"),
"residual_force_denominator_scale=0");
EXPECT_EQ(FieldValue(zero_fields, "residual_moment_denominator_scale"),
"residual_moment_denominator_scale=0");
EXPECT_EQ(FieldValue(zero_fields, "residual_force_branch"),
"residual_force_branch=zero-scale");
EXPECT_EQ(FieldValue(zero_fields, "residual_moment_branch"),
"residual_moment_branch=zero-scale");
EXPECT_EQ(FieldValue(zero_fields, "residual_force_threshold"),
"residual_force_threshold=0.001");
EXPECT_EQ(FieldValue(zero_fields, "residual_moment_threshold"),
"residual_moment_threshold=0.001");
EXPECT_EQ(FieldValue(zero_fields, "residual_force_threshold_unit"),
"residual_force_threshold_unit=force");
EXPECT_EQ(FieldValue(zero_fields, "residual_moment_threshold_unit"),
"residual_moment_threshold_unit=force*length");
const fesa::NewtonConvergenceInput nonzero_external{
{"residual_force", VectorFrom({2.0e-2}), VectorFrom({2.0}),
VectorFrom({1.0})},
{"residual_moment", VectorFrom({2.0e-2}), VectorFrom({1.0}),
VectorFrom({2.0})},
{"correction_translation", VectorFrom({1.0e-2}), VectorFrom({1.0})},
{"correction_rotation", VectorFrom({1.0e-2}), VectorFrom({1.0})},
};
const auto relative_decisions =
fesa::EvaluateNewtonConvergence(nonzero_external);
auto relative_record = CompleteRecord();
relative_record.force_residual = relative_decisions.force_residual;
relative_record.moment_residual = relative_decisions.moment_residual;
relative_record.translation_correction =
relative_decisions.translation_correction;
relative_record.rotation_correction = relative_decisions.rotation_correction;
relative_record.combined_passed = relative_decisions.combined_passed;
const auto relative_fields =
WriteAndRead(directory.Path() / "relative_log.txt", relative_record);
ASSERT_EQ(relative_fields.size(), 39U);
EXPECT_EQ(FieldValue(relative_fields, "residual_force_denominator_scale"),
"residual_force_denominator_scale=2");
EXPECT_EQ(FieldValue(relative_fields, "residual_moment_denominator_scale"),
"residual_moment_denominator_scale=2");
EXPECT_EQ(FieldValue(relative_fields, "residual_force_branch"),
"residual_force_branch=relative");
EXPECT_EQ(FieldValue(relative_fields, "residual_moment_branch"),
"residual_moment_branch=relative");
EXPECT_EQ(FieldValue(relative_fields, "residual_force_threshold"),
"residual_force_threshold=0.01");
EXPECT_EQ(FieldValue(relative_fields, "residual_moment_threshold"),
"residual_moment_threshold=0.01");
EXPECT_EQ(FieldValue(relative_fields, "residual_force_threshold_unit"),
"residual_force_threshold_unit=1");
EXPECT_EQ(FieldValue(relative_fields, "residual_moment_threshold_unit"),
"residual_moment_threshold_unit=1");
}
} // namespace