feat(cpp-object-oriented-modular-refactoring): step 9 - result-io-vector3

This commit is contained in:
KOKO\Mimi
2026-08-16 07:40:16 +09:00
parent 1cb1f26cdc
commit 0be8d1bd89
6 changed files with 140 additions and 148 deletions
+29 -43
View File
@@ -20,6 +20,7 @@
#include "fesa/analysis/analysis_model.h"
#include "fesa/build_info.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/math/vector3.h"
namespace fesa {
namespace {
@@ -163,11 +164,6 @@ Status OutputFailure(const std::string& code, const std::string& message) {
{{Severity::kError, code, {}, "", "", message}});
}
bool IsFinite(const std::array<double, 3>& values) {
return std::all_of(values.begin(), values.end(),
[](const double value) { return std::isfinite(value); });
}
template <std::size_t Size>
bool IsFinite(const std::array<double, Size>& values) {
return std::all_of(values.begin(), values.end(),
@@ -244,26 +240,21 @@ const char* ShellSourceTypeName(const ShellSourceElementType type) {
bool IsOrthonormalRightHanded(
const std::array<std::array<double, 3>, 3>& frame) {
constexpr double kTolerance = 1.0e-12;
const auto dot = [](const std::array<double, 3>& left,
const std::array<double, 3>& right) {
return left[0U] * right[0U] + left[1U] * right[1U] + left[2U] * right[2U];
};
for (const auto& axis : frame) {
if (!IsFinite(axis) || std::abs(dot(axis, axis) - 1.0) > kTolerance) {
const std::array<Vector3, 3> axes = {Vector3{frame[0U]}, Vector3{frame[1U]},
Vector3{frame[2U]}};
for (const Vector3& axis : axes) {
if (!axis.IsFinite() || std::abs(axis.Dot(axis) - 1.0) > kTolerance) {
return false;
}
}
if (std::abs(dot(frame[0U], frame[1U])) > kTolerance ||
std::abs(dot(frame[0U], frame[2U])) > kTolerance ||
std::abs(dot(frame[1U], frame[2U])) > kTolerance) {
if (std::abs(axes[0U].Dot(axes[1U])) > kTolerance ||
std::abs(axes[0U].Dot(axes[2U])) > kTolerance ||
std::abs(axes[1U].Dot(axes[2U])) > kTolerance) {
return false;
}
const std::array<double, 3> cross = {
frame[0U][1U] * frame[1U][2U] - frame[0U][2U] * frame[1U][1U],
frame[0U][2U] * frame[1U][0U] - frame[0U][0U] * frame[1U][2U],
frame[0U][0U] * frame[1U][1U] - frame[0U][1U] * frame[1U][0U]};
return dot(cross, frame[2U]) > 0.0 &&
std::abs(dot(cross, frame[2U]) - 1.0) <= kTolerance;
const Vector3 cross = axes[0U].Cross(axes[1U]);
const double handedness = cross.Dot(axes[2U]);
return handedness > 0.0 && std::abs(handedness - 1.0) <= kTolerance;
}
bool ComputeLocalAxes(const Domain& domain,
@@ -275,30 +266,25 @@ bool ComputeLocalAxes(const Domain& domain,
}
const auto& first = domain.Nodes()[element.node_indices[0U]].coordinates;
const auto& second = domain.Nodes()[element.node_indices[1U]].coordinates;
const auto& guide = domain.Sections()[element.section_index].first_axis;
const std::array<double, 3> delta = {
second[0U] - first[0U], second[1U] - first[1U], second[2U] - first[2U]};
const double length = std::hypot(delta[0U], delta[1U], delta[2U]);
if (!IsFinite(first) || !IsFinite(second) || !IsFinite(guide) ||
!IsFinite(delta) || !std::isfinite(length) || !(length > 0.0)) {
const Vector3 first_position{first};
const Vector3 second_position{second};
const Vector3 guide{domain.Sections()[element.section_index].first_axis};
const Vector3 delta = second_position - first_position;
const double length = delta.Norm();
if (!first_position.IsFinite() || !second_position.IsFinite() ||
!guide.IsFinite() || !delta.IsFinite() || !std::isfinite(length) ||
!(length > 0.0)) {
return false;
}
const std::array<double, 3> x = {delta[0U] / length, delta[1U] / length,
delta[2U] / length};
const double projection =
guide[0U] * x[0U] + guide[1U] * x[1U] + guide[2U] * x[2U];
const std::array<double, 3> y_trial = {guide[0U] - projection * x[0U],
guide[1U] - projection * x[1U],
guide[2U] - projection * x[2U]};
const double y_norm = std::hypot(y_trial[0U], y_trial[1U], y_trial[2U]);
if (!IsFinite(y_trial) || !std::isfinite(y_norm) || !(y_norm > 0.0)) {
const Vector3 x = delta / length;
const double projection = guide.Dot(x);
const Vector3 y_trial = guide - projection * x;
const double y_norm = y_trial.Norm();
if (!y_trial.IsFinite() || !std::isfinite(y_norm) || !(y_norm > 0.0)) {
return false;
}
const std::array<double, 3> y = {y_trial[0U] / y_norm, y_trial[1U] / y_norm,
y_trial[2U] / y_norm};
const std::array<double, 3> z = {x[1U] * y[2U] - x[2U] * y[1U],
x[2U] * y[0U] - x[0U] * y[2U],
x[0U] * y[1U] - x[1U] * y[0U]};
const Vector3 y = y_trial / y_norm;
const Vector3 z = x.Cross(y);
axes = {x[0U], x[1U], x[2U], y[0U], y[1U], y[2U], z[0U], z[1U], z[2U]};
return IsFinite(axes);
}
@@ -417,7 +403,7 @@ Status ValidateShellWriterInput(const Domain& domain,
++position) {
if (row.stress[position].position != positions[position] ||
row.stress[position].zeta != kZeta[position] ||
!IsFinite(row.stress[position].components)) {
!Vector3{row.stress[position].components}.IsFinite()) {
return OutputFailure("invalid-result-rows",
"Shell stress rows must preserve BOTTOM, "
"MIDDLE, TOP identity.");
@@ -426,7 +412,7 @@ Status ValidateShellWriterInput(const Domain& domain,
}
if (!std::isfinite(state.PhysicalStrainEnergy()) ||
!IsFinite(state.Equilibrium()) ||
!IsFinite(state.VerificationMetrics())) {
!Vector3{state.VerificationMetrics()}.IsFinite()) {
return OutputFailure(
"invalid-result-rows",
"Shell energy, equilibrium, and verification metrics must be finite.");
@@ -493,7 +479,7 @@ Status ValidateWriterInput(const std::filesystem::path& output_path,
node.source_id.source_label_text.empty() ||
!IsValidUtf8(node.source_id.instance_name) ||
!IsValidUtf8(node.source_id.source_label_text) ||
!IsFinite(node.coordinates)) {
!Vector3{node.coordinates}.IsFinite()) {
return OutputFailure(
"invalid-result-identity",
"Every node requires finite coordinates and UTF-8 source identity.");