feat(cpp-object-oriented-modular-refactoring): step 5 - solver-workflow-google-style

This commit is contained in:
KOKO\Mimi
2026-08-16 06:20:08 +09:00
parent e1c0e357dd
commit 24f006fe4a
52 changed files with 5817 additions and 6369 deletions
+48 -48
View File
@@ -3,10 +3,10 @@
#include "fesa/io/hdf5/hdf5_results_writer.hpp"
#include "fesa/analysis/analysis_model.hpp"
#include "fesa/analysis/analysis_state.hpp"
#include "fesa/analysis/analysis_model.h"
#include "fesa/analysis/analysis_state.h"
#include "fesa/build_info.h"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/fem/dof_manager.h"
#include "fesa/model/domain.h"
#include <hdf5.h>
@@ -164,30 +164,30 @@ WriterFixture makeFixture(
auto domain = std::make_unique<fesa::Domain>(
std::move(domainResult.Value()));
auto modelResult = fesa::AnalysisModel::create(*domain);
auto modelResult = fesa::AnalysisModel::Create(*domain);
if (!modelResult.HasValue()) {
throw std::runtime_error{"Writer fixture AnalysisModel construction failed."};
}
const fesa::AnalysisModel model = std::move(modelResult.Value());
auto dofsResult = fesa::DofManager::create(model);
auto dofsResult = fesa::DofManager::Create(model);
if (!dofsResult.HasValue()) {
throw std::runtime_error{"Writer fixture DofManager construction failed."};
}
auto dofs = std::make_unique<fesa::DofManager>(
std::move(dofsResult.Value()));
auto state = std::make_unique<fesa::AnalysisState>(
fesa::AnalysisState::create(*dofs, {"Step-1", 0U}));
fesa::AnalysisState::Create(*dofs, {"Step-1", 0U}));
for (std::size_t index = 0U; index < state->displacement().Size(); ++index) {
state->displacement()[index] = 0.25 + static_cast<double>(index);
state->externalForce()[index] = 100.0 + static_cast<double>(index);
state->internalForce()[index] = 200.0 + 2.0 * static_cast<double>(index);
state->residual()[index] = 100.0 + static_cast<double>(index);
state->reaction()[index] = 100.0 + static_cast<double>(index);
for (std::size_t index = 0U; index < state->Displacement().Size(); ++index) {
state->Displacement()[index] = 0.25 + static_cast<double>(index);
state->ExternalForce()[index] = 100.0 + static_cast<double>(index);
state->InternalForce()[index] = 200.0 + 2.0 * static_cast<double>(index);
state->Residual()[index] = 100.0 + static_cast<double>(index);
state->Reaction()[index] = 100.0 + static_cast<double>(index);
}
const auto& nodes = domain->Nodes();
state->endpointResults() = {
state->EndpointResults() = {
{0U,
0,
nodes[0U].source_id,
@@ -198,15 +198,15 @@ WriterFixture makeFixture(
nodes[1U].source_id,
{7.0, 8.0, 9.0, 10.0, 11.0, 12.0},
{15.0, 16.0, 17.0, 18.0}}};
state->gaussResults() = {
state->GaussResults() = {
{0U, 1, {0.01, 0.02, 0.03, 0.04}, {21.0, 22.0, 23.0, 24.0}},
{0U, 2, {0.05, 0.06, 0.07, 0.08}, {25.0, 26.0, 27.0, 28.0}}};
if (useDefaultCentroid) {
state->stressResults() = {
state->StressResults() = {
{0U, 1, 0U, 0.0, 0.0, 31.0, "fesa-default"},
{0U, 2, 0U, 0.0, 0.0, 32.0, "fesa-default"}};
} else {
state->stressResults() = {
state->StressResults() = {
{0U, 1, 1U, -0.1, 0.2, 31.0, "input"},
{0U, 1, 2U, 0.3, -0.4, 32.0, "input"},
{0U, 2, 1U, -0.1, 0.2, 33.0, "input"},
@@ -264,25 +264,25 @@ WriterFixture makeShellFixture(const std::filesystem::path& source) {
}
auto domain = std::make_unique<fesa::Domain>(
std::move(domainResult.Value()));
auto modelResult = fesa::AnalysisModel::create(*domain);
auto modelResult = fesa::AnalysisModel::Create(*domain);
if (!modelResult.HasValue()) {
throw std::runtime_error{"Shell writer fixture AnalysisModel construction failed."};
}
const fesa::AnalysisModel model = std::move(modelResult.Value());
auto dofsResult = fesa::DofManager::create(model);
auto dofsResult = fesa::DofManager::Create(model);
if (!dofsResult.HasValue()) {
throw std::runtime_error{"Shell writer fixture DofManager construction failed."};
}
auto dofs = std::make_unique<fesa::DofManager>(
std::move(dofsResult.Value()));
auto state = std::make_unique<fesa::AnalysisState>(
fesa::AnalysisState::create(*dofs, {"Step-1", 0U}));
for (std::size_t index = 0U; index < state->displacement().Size(); ++index) {
state->displacement()[index] = 0.01 * static_cast<double>(index + 1U);
state->externalForce()[index] = 10.0 + static_cast<double>(index);
state->internalForce()[index] = 20.0 + static_cast<double>(index);
state->residual()[index] = 30.0 + static_cast<double>(index);
state->reaction()[index] = 40.0 + static_cast<double>(index);
fesa::AnalysisState::Create(*dofs, {"Step-1", 0U}));
for (std::size_t index = 0U; index < state->Displacement().Size(); ++index) {
state->Displacement()[index] = 0.01 * static_cast<double>(index + 1U);
state->ExternalForce()[index] = 10.0 + static_cast<double>(index);
state->InternalForce()[index] = 20.0 + static_cast<double>(index);
state->Residual()[index] = 30.0 + static_cast<double>(index);
state->Reaction()[index] = 40.0 + static_cast<double>(index);
}
const double gauss = 1.0 / std::sqrt(3.0);
@@ -292,10 +292,10 @@ WriterFixture makeShellFixture(const std::filesystem::path& source) {
{gauss, gauss},
{-gauss, gauss}}};
const std::array<fesa::ShellMidsurfaceLocation, 4> locations{
fesa::ShellMidsurfaceLocation::gp1,
fesa::ShellMidsurfaceLocation::gp2,
fesa::ShellMidsurfaceLocation::gp3,
fesa::ShellMidsurfaceLocation::gp4};
fesa::ShellMidsurfaceLocation::kGp1,
fesa::ShellMidsurfaceLocation::kGp2,
fesa::ShellMidsurfaceLocation::kGp3,
fesa::ShellMidsurfaceLocation::kGp4};
fesa::ShellStateCandidate candidate{};
for (std::size_t point = 0U; point < locations.size(); ++point) {
const double base = 100.0 * static_cast<double>(point + 1U);
@@ -310,20 +310,20 @@ WriterFixture makeShellFixture(const std::filesystem::path& source) {
base + 5.0, base + 6.0, base + 7.0, base + 8.0},
{base + 11.0, base + 12.0, base + 13.0, base + 14.0,
base + 15.0, base + 16.0, base + 17.0, base + 18.0},
{{{fesa::ShellSectionPosition::bottom,
{{{fesa::ShellSectionPosition::kBottom,
-1.0,
{base + 21.0, base + 22.0, base + 23.0}},
{fesa::ShellSectionPosition::middle,
{fesa::ShellSectionPosition::kMiddle,
0.0,
{base + 24.0, base + 25.0, base + 26.0}},
{fesa::ShellSectionPosition::top,
{fesa::ShellSectionPosition::kTop,
1.0,
{base + 27.0, base + 28.0, base + 29.0}}}}});
}
candidate.physicalStrainEnergy = 123.5;
candidate.physical_strain_energy = 123.5;
candidate.equilibrium = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
candidate.verificationMetrics = {1.0e-13, 2.0e-13, 3.0e-13};
const fesa::Status commit = state->commitShellResults(
candidate.verification_metrics = {1.0e-13, 2.0e-13, 3.0e-13};
const fesa::Status commit = state->CommitShellResults(
{0U}, std::move(candidate));
if (!commit.IsOk()) {
throw std::runtime_error{"Shell writer fixture state commit failed."};
@@ -846,7 +846,7 @@ TEST(Hdf5ResultsWriter, WritesExactSchemaShapesAttributesAndIdentity) {
const auto output = directory.path() / "results.h5";
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(writer.write(output, *fixture.domain, *fixture.state, {}).IsOk());
ASSERT_TRUE(writer.Write(output, *fixture.domain, *fixture.state, {}).IsOk());
ASSERT_GT(H5Fis_hdf5(output.string().c_str()), 0);
const auto file = openFile(output);
@@ -1041,7 +1041,7 @@ TEST(Hdf5ResultsWriter, WritesMandatoryOutputsDespiteOutputRequests) {
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(
writer.write(output, *fixture.domain, *fixture.state, {ignoredRequest})
writer.Write(output, *fixture.domain, *fixture.state, {ignoredRequest})
.IsOk());
const auto file = openFile(output);
for (const char* suffix : {
@@ -1078,7 +1078,7 @@ TEST(Hdf5ResultsWriter, WritesWarningsAndDefaultCentroid) {
const auto output = directory.path() / "results.h5";
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(writer.write(output, *fixture.domain, *fixture.state, diagnostics).IsOk());
ASSERT_TRUE(writer.Write(output, *fixture.domain, *fixture.state, diagnostics).IsOk());
const auto file = openFile(output);
auto stressRows = readStressRows(file.get());
ASSERT_EQ(stressRows.size(), 2U);
@@ -1116,15 +1116,15 @@ TEST(Hdf5ResultsWriter, FailureLeavesNoPartialAndPreservesExistingFinal) {
auto fixture = makeFixture(directory.path() / "failure.inp");
fesa::Hdf5ResultsWriter writer;
fixture.state->displacement()[0U] =
fixture.state->Displacement()[0U] =
std::numeric_limits<double>::quiet_NaN();
const auto invalidOutput = directory.path() / "invalid-results.h5";
expectOutputFailure(
writer.write(invalidOutput, *fixture.domain, *fixture.state, {}),
writer.Write(invalidOutput, *fixture.domain, *fixture.state, {}),
"invalid-result-state");
EXPECT_FALSE(std::filesystem::exists(invalidOutput));
EXPECT_EQ(entryCount(directory.path()), 0U);
fixture.state->displacement()[0U] = 0.25;
fixture.state->Displacement()[0U] = 0.25;
const auto final = directory.path() / "results.h5";
const std::vector<char> sentinel = {'p', 'r', 'e', 'v', 'i', 'o', 'u', 's'};
@@ -1140,7 +1140,7 @@ TEST(Hdf5ResultsWriter, FailureLeavesNoPartialAndPreservesExistingFinal) {
ASSERT_NE(lock.get(), INVALID_HANDLE_VALUE);
expectOutputFailure(
writer.write(final, *fixture.domain, *fixture.state, {}),
writer.Write(final, *fixture.domain, *fixture.state, {}),
"hdf5-finalization-failure");
EXPECT_EQ(readBytes(final), sentinel);
EXPECT_EQ(entryCount(directory.path()), 1U);
@@ -1153,7 +1153,7 @@ TEST(Hdf5ResultsWriter, SuccessfullyReplacesExistingFinal) {
writeBytes(final, {'o', 'l', 'd'});
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(writer.write(final, *fixture.domain, *fixture.state, {}).IsOk());
ASSERT_TRUE(writer.Write(final, *fixture.domain, *fixture.state, {}).IsOk());
EXPECT_GT(H5Fis_hdf5(final.string().c_str()), 0);
EXPECT_EQ(entryCount(directory.path()), 1U);
const auto file = openFile(final);
@@ -1171,7 +1171,7 @@ TEST(Hdf5ResultsWriter, WritesExactShellMetadataAndModelIdentity) {
const auto output = directory.path() / "results.h5";
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(writer.write(output, *fixture.domain, *fixture.state, {}).IsOk());
ASSERT_TRUE(writer.Write(output, *fixture.domain, *fixture.state, {}).IsOk());
const auto file = openFile(output);
Hdf5Handle metadata{
@@ -1261,7 +1261,7 @@ TEST(Hdf5ResultsWriter, WritesExactMandatoryShellResultInventory) {
const auto output = directory.path() / "results.h5";
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(writer.write(output, *fixture.domain, *fixture.state, {}).IsOk());
ASSERT_TRUE(writer.Write(output, *fixture.domain, *fixture.state, {}).IsOk());
const auto file = openFile(output);
const std::string shellRoot = std::string{kStepRoot} + "/element/shell";
expectNumericDataset(
@@ -1329,7 +1329,7 @@ TEST(Hdf5ResultsWriter, WritesShellInventoryDespiteRequestsAndOmitsForbiddenPath
fesa::Hdf5ResultsWriter writer;
ASSERT_TRUE(
writer.write(output, *fixture.domain, *fixture.state, {ignoredRequest})
writer.Write(output, *fixture.domain, *fixture.state, {ignoredRequest})
.IsOk());
const auto file = openFile(output);
for (const char* suffix : {
@@ -1359,7 +1359,7 @@ TEST(Hdf5ResultsWriter, WritesShellInventoryDespiteRequestsAndOmitsForbiddenPath
TEST(Hdf5ResultsWriter, InvalidShellInventoryPreservesExistingFinal) {
TempDirectory directory{"shell-atomic"};
auto fixture = makeShellFixture(directory.path() / "shell.inp");
auto invalidState = fesa::AnalysisState::create(
auto invalidState = fesa::AnalysisState::Create(
*fixture.dofs, {"Step-1", 0U});
const auto final = directory.path() / "results.h5";
const std::vector<char> sentinel = {'s', 'h', 'e', 'l', 'l'};
@@ -1367,7 +1367,7 @@ TEST(Hdf5ResultsWriter, InvalidShellInventoryPreservesExistingFinal) {
fesa::Hdf5ResultsWriter writer;
expectOutputFailure(
writer.write(final, *fixture.domain, invalidState, {}),
writer.Write(final, *fixture.domain, invalidState, {}),
"invalid-result-rows");
EXPECT_EQ(readBytes(final), sentinel);
EXPECT_EQ(entryCount(directory.path()), 1U);