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
@@ -3,6 +3,7 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <cmath>
#include <filesystem>
#include <fstream>
#include <iterator>
@@ -13,6 +14,7 @@
#include <vector>
#include "fesa/io/abaqus/input_reader.h"
#include "fesa/math/vector3.h"
namespace {
@@ -239,6 +241,7 @@ RootAssembly, 6, -12.5
} // namespace
// C-DUP-002
TEST(InpDomainMapping, MapsEverySupportedKeywordAndLegacyDeck) {
auto result = MapText("supported-inventory", SupportedInventoryDeck(true));
ASSERT_TRUE(result.HasValue());
@@ -425,6 +428,17 @@ OnlySecond, 2, 5.
"2, 1., 0., 0.", "2, 1e308, 1e297, 0."),
"0., 1., 0.", "1e308, 0., 0."));
ASSERT_TRUE(large_finite.HasValue());
const auto& large_domain = large_finite.Value();
ASSERT_EQ(large_domain.Nodes().size(), 2U);
const fesa::Vector3 large_delta =
fesa::Vector3{large_domain.Nodes()[1U].coordinates} -
fesa::Vector3{large_domain.Nodes()[0U].coordinates};
EXPECT_TRUE(large_delta.IsFinite());
EXPECT_TRUE(std::isfinite(large_delta.Norm()));
EXPECT_DOUBLE_EQ(large_delta.Y(), 1.0e297);
const fesa::Vector3 large_guide{large_domain.Sections()[0U].first_axis};
EXPECT_TRUE(large_guide.IsFinite());
EXPECT_TRUE(std::isfinite(large_guide.Norm()));
}
TEST(InpDomainMapping, KeepsNodeAndElementSetNamesInSeparateNamespaces) {
@@ -24,6 +24,7 @@
#include "fesa/analysis/analysis_state.h"
#include "fesa/build_info.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/math/vector3.h"
#include "fesa/model/domain.h"
namespace {
@@ -1114,7 +1115,7 @@ TEST(Hdf5ResultsWriter, SuccessfullyReplacesExistingFinal) {
EXPECT_EQ(ReadUint64Attribute(metadata.Get(), "schema_version"), 0U);
}
// MITC4-H5-001
// MITC4-H5-001, C-DUP-002
TEST(Hdf5ResultsWriter, WritesExactShellMetadataAndModelIdentity) {
TempDirectory directory{"shell-model"};
const auto source = directory.Path() / "shell.inp";
@@ -1150,9 +1151,15 @@ TEST(Hdf5ResultsWriter, WritesExactShellMetadataAndModelIdentity) {
EXPECT_EQ(DatasetDimensions(file.Get(), "/model/shell/nodal_director"),
std::vector<hsize_t>({4U, 3U}));
constexpr fesa::Vector3 director{0.0, 0.0, 1.0};
std::vector<double> expected_directors;
for (std::size_t node = 0U; node < 4U; ++node) {
expected_directors.insert(expected_directors.end(),
director.Components().begin(),
director.Components().end());
}
EXPECT_EQ(ReadDoubleDataset(file.Get(), "/model/shell/nodal_director"),
std::vector<double>(
{0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0}));
expected_directors);
EXPECT_EQ(DatasetDimensions(file.Get(), "/model/shell/nodal_frame"),
std::vector<hsize_t>({4U, 3U, 3U}));
ExpectCompoundMemberNames(file.Get(), "/model/shell/materials",
@@ -1305,3 +1312,31 @@ TEST(Hdf5ResultsWriter, InvalidShellInventoryPreservesExistingFinal) {
EXPECT_EQ(ReadBytes(final), sentinel);
EXPECT_EQ(EntryCount(directory.Path()), 1U);
}
// C-DUP-002
TEST(Hdf5ResultsWriter,
Vector3ShellSerializationRejectsNonfiniteWithoutReplacingFinal) {
TempDirectory directory{"shell-vector3-atomic"};
auto fixture = MakeShellFixture(directory.Path() / "shell.inp");
const auto final = directory.Path() / "results.h5";
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(writer.Write(final, *fixture.domain, *fixture.state, {}).IsOk());
const std::vector<char> valid_bytes = ReadBytes(final);
const auto file = OpenFile(final);
const auto directors =
ReadDoubleDataset(file.Get(), "/model/shell/nodal_director");
ASSERT_EQ(directors.size(), 12U);
for (std::size_t offset = 0U; offset < directors.size(); offset += 3U) {
const fesa::Vector3 director{directors[offset], directors[offset + 1U],
directors[offset + 2U]};
EXPECT_TRUE(director.IsFinite());
EXPECT_EQ(director, (fesa::Vector3{0.0, 0.0, 1.0}));
}
fixture.state->Displacement()[0U] = std::numeric_limits<double>::quiet_NaN();
ExpectOutputFailure(writer.Write(final, *fixture.domain, *fixture.state, {}),
"invalid-result-state");
EXPECT_EQ(ReadBytes(final), valid_bytes);
EXPECT_EQ(EntryCount(directory.Path()), 1U);
}
+7 -11
View File
@@ -20,6 +20,7 @@
#include "fesa/assembly/parallel_for.h"
#include "fesa/assembly/sparse_assembler.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/math/vector3.h"
#include "fesa/model/domain.h"
namespace {
@@ -719,14 +720,14 @@ TEST(ResultRecovery, KeepsFullResidualAndComputesGlobalShellEquilibrium) {
}
}
// MITC4-REC-004
// MITC4-REC-004, C-DUP-002
TEST(ResultRecovery, UsesGlobalOriginForShellMomentBalance) {
auto centered_definition = MakeShellDefinition();
auto translated_definition = centered_definition;
constexpr std::array<double, 3> translation{7.0, 11.0, 0.0};
constexpr fesa::Vector3 translation{7.0, 11.0, 0.0};
for (auto& node : translated_definition.nodes) {
for (std::size_t component = 0U; component < translation.size();
++component) {
for (std::size_t component = 0U;
component < translation.Components().size(); ++component) {
node.coordinates[component] += translation[component];
}
}
@@ -753,13 +754,8 @@ TEST(ResultRecovery, UsesGlobalOriginForShellMomentBalance) {
EXPECT_NEAR(translated.Equilibrium()[component], centered_force[component],
1.0e-12);
}
const std::array<double, 3> translated_moment_delta{
translation[1U] * centered_force[2U] -
translation[2U] * centered_force[1U],
translation[2U] * centered_force[0U] -
translation[0U] * centered_force[2U],
translation[0U] * centered_force[1U] -
translation[1U] * centered_force[0U]};
const fesa::Vector3 translated_moment_delta =
translation.Cross(fesa::Vector3{centered_force});
for (std::size_t component = 0U; component < 3U; ++component) {
EXPECT_NEAR(translated.Equilibrium()[3U + component] -
centered.Equilibrium()[3U + component],