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
+79 -79
View File
@@ -3,9 +3,9 @@
#include "fesa/io/hdf5/hdf5_results_writer.hpp"
#include "fesa/analysis/analysis_model.hpp"
#include "fesa/analysis/analysis_model.h"
#include "fesa/build_info.h"
#include "fesa/fem/dof_manager.hpp"
#include "fesa/fem/dof_manager.h"
#include <hdf5.h>
@@ -389,38 +389,38 @@ Status validateShellWriterInput(
std::size_t expectedRows = 0U;
if (!sizeProductFits(
domain.ShellElements().size(), kShellLocationCount, expectedRows) ||
state.shellResults().size() != expectedRows) {
state.ShellResults().size() != expectedRows) {
return outputFailure(
"invalid-result-rows",
"Shell output requires exactly GP1 through GP4 for every shell element.");
}
const double gauss = 1.0 / std::sqrt(3.0);
const std::array<ShellMidsurfaceLocation, kShellLocationCount> locations{
ShellMidsurfaceLocation::gp1,
ShellMidsurfaceLocation::gp2,
ShellMidsurfaceLocation::gp3,
ShellMidsurfaceLocation::gp4};
ShellMidsurfaceLocation::kGp1,
ShellMidsurfaceLocation::kGp2,
ShellMidsurfaceLocation::kGp3,
ShellMidsurfaceLocation::kGp4};
const std::array<std::array<double, 2>, kShellLocationCount> coordinates{{
{-gauss, -gauss},
{gauss, -gauss},
{gauss, gauss},
{-gauss, gauss}}};
const std::array<ShellSectionPosition, kShellSectionPositionCount> positions{
ShellSectionPosition::bottom,
ShellSectionPosition::middle,
ShellSectionPosition::top};
ShellSectionPosition::kBottom,
ShellSectionPosition::kMiddle,
ShellSectionPosition::kTop};
constexpr std::array<double, kShellSectionPositionCount> zeta{-1.0, 0.0, 1.0};
for (std::size_t rowIndex = 0U;
rowIndex < state.shellResults().size();
rowIndex < state.ShellResults().size();
++rowIndex) {
const auto& row = state.shellResults()[rowIndex];
const auto& row = state.ShellResults()[rowIndex];
const std::size_t element = rowIndex / kShellLocationCount;
const std::size_t location = rowIndex % kShellLocationCount;
if (row.element != element || row.location != locations[location] ||
row.naturalCoordinates != coordinates[location] ||
!isOrthonormalRightHanded(row.localFrame) ||
!isFinite(row.generalizedStrain) ||
!isFinite(row.sectionResultant)) {
row.natural_coordinates != coordinates[location] ||
!isOrthonormalRightHanded(row.local_frame) ||
!isFinite(row.generalized_strain) ||
!isFinite(row.section_resultant)) {
return outputFailure(
"invalid-result-rows",
"Shell result rows must be finite and preserve element/GP/frame identity.");
@@ -437,9 +437,9 @@ Status validateShellWriterInput(
}
}
}
if (!std::isfinite(state.physicalStrainEnergy()) ||
!isFinite(state.equilibrium()) ||
!isFinite(state.verificationMetrics())) {
if (!std::isfinite(state.PhysicalStrainEnergy()) ||
!isFinite(state.Equilibrium()) ||
!isFinite(state.VerificationMetrics())) {
return outputFailure(
"invalid-result-rows",
"Shell energy, equilibrium, and verification metrics must be finite.");
@@ -457,8 +457,8 @@ Status validateWriterInput(
return outputFailure(
"invalid-output-path", "The HDF5 output path must name a file.");
}
if (state.identity().stepName != kStepName ||
state.identity().frameIndex != kFrameIndex) {
if (state.Identity().step_name != kStepName ||
state.Identity().frame_index != kFrameIndex) {
return outputFailure(
"invalid-result-state",
"Schema v0 requires literal Step-1 and frame index 0.");
@@ -470,7 +470,7 @@ Status validateWriterInput(
if (!shellValidation.IsOk()) {
return shellValidation;
}
} else if (!state.shellResults().empty()) {
} else if (!state.ShellResults().empty()) {
return outputFailure(
"invalid-result-rows",
"Beam output cannot contain shell recovery rows.");
@@ -482,11 +482,11 @@ Status validateWriterInput(
"invalid-result-state", "The nodal result shape overflows size_t.");
}
const std::array<const Vector*, 5> vectors = {
&state.displacement(),
&state.externalForce(),
&state.internalForce(),
&state.residual(),
&state.reaction()};
&state.Displacement(),
&state.ExternalForce(),
&state.InternalForce(),
&state.Residual(),
&state.Reaction()};
for (const Vector* vector : vectors) {
if (vector->Size() != fullDofCount) {
return outputFailure(
@@ -542,42 +542,42 @@ Status validateWriterInput(
std::size_t gaussCount = 0U;
if (!sizeProductFits(domain.Elements().size(), kEndpointCount, endpointCount) ||
!sizeProductFits(domain.Elements().size(), kGaussPointCount, gaussCount) ||
state.endpointResults().size() != endpointCount ||
state.gaussResults().size() != gaussCount) {
state.EndpointResults().size() != endpointCount ||
state.GaussResults().size() != gaussCount) {
return outputFailure(
"invalid-result-rows",
"Endpoint and Gauss row counts must match every element and location.");
}
for (std::size_t rowIndex = 0U;
rowIndex < state.endpointResults().size();
rowIndex < state.EndpointResults().size();
++rowIndex) {
const EntityIndex expectedElement =
static_cast<EntityIndex>(rowIndex / kEndpointCount);
const int expectedEndpoint = static_cast<int>(rowIndex % kEndpointCount);
const EndpointResultRow& row = state.endpointResults()[rowIndex];
const EndpointResultRow& row = state.EndpointResults()[rowIndex];
const auto& element = domain.Elements()[expectedElement];
const auto& expectedNode =
domain.Nodes()[element.node_indices[static_cast<std::size_t>(expectedEndpoint)]];
if (row.element != expectedElement || row.endpoint != expectedEndpoint ||
!sameIdentity(row.node, expectedNode.source_id) ||
!isFinite(row.endAction) || !isFinite(row.sectionResultant)) {
!isFinite(row.end_action) || !isFinite(row.section_resultant)) {
return outputFailure(
"invalid-result-rows",
"Endpoint result rows must follow element/endpoint order and identity.");
}
}
for (std::size_t rowIndex = 0U;
rowIndex < state.gaussResults().size();
rowIndex < state.GaussResults().size();
++rowIndex) {
const EntityIndex expectedElement =
static_cast<EntityIndex>(rowIndex / kGaussPointCount);
const int expectedGaussPoint =
static_cast<int>(rowIndex % kGaussPointCount) + 1;
const GaussResultRow& row = state.gaussResults()[rowIndex];
const GaussResultRow& row = state.GaussResults()[rowIndex];
if (row.element != expectedElement ||
row.gaussPoint != expectedGaussPoint ||
!isFinite(row.generalizedStrain) ||
!isFinite(row.generalizedResultant)) {
row.gauss_point != expectedGaussPoint ||
!isFinite(row.generalized_strain) ||
!isFinite(row.generalized_resultant)) {
return outputFailure(
"invalid-result-rows",
"Gauss result rows must follow element/Gauss order and identity.");
@@ -594,19 +594,19 @@ Status validateWriterInput(
for (std::size_t gauss = 0U; gauss < kGaussPointCount; ++gauss) {
const std::size_t count = sectionPoints.empty() ? 1U : sectionPoints.size();
for (std::size_t point = 0U; point < count; ++point) {
if (stressIndex >= state.stressResults().size()) {
if (stressIndex >= state.StressResults().size()) {
return outputFailure(
"invalid-result-rows",
"Axial stress rows are missing required element/Gauss/section locations.");
}
const StressS11Row& row = state.stressResults()[stressIndex++];
const StressS11Row& row = state.StressResults()[stressIndex++];
const std::size_t expectedPoint = sectionPoints.empty() ? 0U : point + 1U;
const double expectedX1 = sectionPoints.empty() ? 0.0 : sectionPoints[point][0U];
const double expectedX2 = sectionPoints.empty() ? 0.0 : sectionPoints[point][1U];
const char* expectedSource = sectionPoints.empty() ? "fesa-default" : "input";
if (row.element != static_cast<EntityIndex>(elementIndex) ||
row.gaussPoint != static_cast<int>(gauss + 1U) ||
row.sectionPoint != expectedPoint ||
row.gauss_point != static_cast<int>(gauss + 1U) ||
row.section_point != expectedPoint ||
row.x1 != expectedX1 || row.x2 != expectedX2 ||
row.source != expectedSource || !isValidUtf8(row.source) ||
!std::isfinite(row.x1) || !std::isfinite(row.x2) ||
@@ -618,7 +618,7 @@ Status validateWriterInput(
}
}
}
if (stressIndex != state.stressResults().size()) {
if (stressIndex != state.StressResults().size()) {
return outputFailure(
"invalid-result-rows", "Axial stress output contains extra rows.");
}
@@ -635,7 +635,7 @@ Status validateWriterInput(
}
auto analysisModelResult = AnalysisModel::create(domain);
auto analysisModelResult = AnalysisModel::Create(domain);
if (!analysisModelResult.HasValue()) {
return outputFailure(
"invalid-result-state",
@@ -643,7 +643,7 @@ Status validateWriterInput(
}
const AnalysisModel analysisModel =
std::move(analysisModelResult.Value());
auto dofResult = DofManager::create(analysisModel);
auto dofResult = DofManager::Create(analysisModel);
if (!dofResult.HasValue()) {
return outputFailure(
"invalid-result-state",
@@ -652,16 +652,16 @@ Status validateWriterInput(
const DofManager dofs = std::move(dofResult.Value());
modelData.constraintMask.assign(fullDofCount, 0U);
modelData.prescribedDisplacement.assign(fullDofCount, 0.0);
if (dofs.constrainedDofs().size() != dofs.prescribedValues().Size()) {
if (dofs.ConstrainedDofs().size() != dofs.PrescribedValues().Size()) {
return outputFailure(
"invalid-result-state",
"Constraint identities and prescribed values have inconsistent sizes.");
}
for (std::size_t index = 0U;
index < dofs.constrainedDofs().size();
index < dofs.ConstrainedDofs().size();
++index) {
const std::size_t fullDof = dofs.constrainedDofs()[index];
const double prescribed = dofs.prescribedValues()[index];
const std::size_t fullDof = dofs.ConstrainedDofs()[index];
const double prescribed = dofs.PrescribedValues()[index];
if (fullDof >= fullDofCount || !std::isfinite(prescribed)) {
return outputFailure(
"invalid-result-state",
@@ -1422,9 +1422,9 @@ std::vector<double> flattenEndpointValues(
for (const auto& row : rows) {
if (sectionResultants) {
values.insert(
values.end(), row.sectionResultant.begin(), row.sectionResultant.end());
values.end(), row.section_resultant.begin(), row.section_resultant.end());
} else {
values.insert(values.end(), row.endAction.begin(), row.endAction.end());
values.insert(values.end(), row.end_action.begin(), row.end_action.end());
}
}
return values;
@@ -1437,7 +1437,7 @@ std::vector<double> flattenGaussValues(
values.reserve(rows.size() * kGeneralizedComponentCount);
for (const auto& row : rows) {
const auto& rowValues =
resultants ? row.generalizedResultant : row.generalizedStrain;
resultants ? row.generalized_resultant : row.generalized_strain;
values.insert(values.end(), rowValues.begin(), rowValues.end());
}
return values;
@@ -1445,12 +1445,12 @@ std::vector<double> flattenGaussValues(
void writeStress(const hid_t file, const AnalysisState& state) {
std::vector<StressWriteRow> rows;
rows.reserve(state.stressResults().size());
for (const auto& row : state.stressResults()) {
rows.reserve(state.StressResults().size());
for (const auto& row : state.StressResults()) {
rows.push_back({
static_cast<std::uint64_t>(row.element),
static_cast<std::uint64_t>(row.gaussPoint),
static_cast<std::uint64_t>(row.sectionPoint),
static_cast<std::uint64_t>(row.gauss_point),
static_cast<std::uint64_t>(row.section_point),
row.x1,
row.x2,
row.source.c_str(),
@@ -1544,26 +1544,26 @@ void writeShellResultDatasets(
std::vector<double> generalizedStrains;
std::vector<double> sectionResultants;
std::vector<double> stresses;
localFrames.reserve(state.shellResults().size() * 9U);
localFrames.reserve(state.ShellResults().size() * 9U);
generalizedStrains.reserve(
state.shellResults().size() * kShellGeneralizedComponentCount);
state.ShellResults().size() * kShellGeneralizedComponentCount);
sectionResultants.reserve(
state.shellResults().size() * kShellGeneralizedComponentCount);
state.ShellResults().size() * kShellGeneralizedComponentCount);
stresses.reserve(
state.shellResults().size() * kShellSectionPositionCount *
state.ShellResults().size() * kShellSectionPositionCount *
kShellStressComponentCount);
for (const auto& row : state.shellResults()) {
for (const auto& axis : row.localFrame) {
for (const auto& row : state.ShellResults()) {
for (const auto& axis : row.local_frame) {
localFrames.insert(localFrames.end(), axis.begin(), axis.end());
}
generalizedStrains.insert(
generalizedStrains.end(),
row.generalizedStrain.begin(),
row.generalizedStrain.end());
row.generalized_strain.begin(),
row.generalized_strain.end());
sectionResultants.insert(
sectionResultants.end(),
row.sectionResultant.begin(),
row.sectionResultant.end());
row.section_resultant.begin(),
row.section_resultant.end());
for (const auto& position : row.stress) {
stresses.insert(
stresses.end(),
@@ -1624,22 +1624,22 @@ void writeShellResultDatasets(
"shell-local", "section-position");
writeShellResultIdentity(file, stressPath, true);
const double energy = state.physicalStrainEnergy();
const double energy = state.PhysicalStrainEnergy();
writeDoubleDataset(
file, std::string{kStepRoot} + "/global/energy", {1U},
&energy, 1U, "PHYSICAL_STRAIN_ENERGY", "force*length",
"global", "global");
writeDoubleDataset(
file, std::string{kStepRoot} + "/global/equilibrium", {6U},
state.equilibrium().data(), state.equilibrium().size(),
state.Equilibrium().data(), state.Equilibrium().size(),
"FORCE_1,FORCE_2,FORCE_3,MOMENT_1,MOMENT_2,MOMENT_3",
"force,force,force,force*length,force*length,force*length",
"global-cartesian", "global-origin");
const std::string metricsPath =
std::string{kStepRoot} + "/global/verification_metrics";
writeDoubleDataset(
file, metricsPath, {3U}, state.verificationMetrics().data(),
state.verificationMetrics().size(),
file, metricsPath, {3U}, state.VerificationMetrics().data(),
state.VerificationMetrics().size(),
"FREE_RESIDUAL_NORMALIZED,FORCE_BALANCE_NORMALIZED,MOMENT_BALANCE_NORMALIZED",
"1,1,1", "global", "verification");
{
@@ -1735,8 +1735,8 @@ void writeResultDatasets(
file,
std::string{kStepRoot} + "/nodal/displacement",
nodalDimensions,
state.displacement().Data(),
state.displacement().Size(),
state.Displacement().Data(),
state.Displacement().Size(),
"UX,UY,UZ,URX,URY,URZ",
"length,length,length,radian,radian,radian",
"global-cartesian",
@@ -1745,8 +1745,8 @@ void writeResultDatasets(
file,
std::string{kStepRoot} + "/nodal/reaction",
nodalDimensions,
state.reaction().Data(),
state.reaction().Size(),
state.Reaction().Data(),
state.Reaction().Size(),
"RF1,RF2,RF3,RM1,RM2,RM3",
"force,force,force,force*length,force*length,force*length",
"global-cartesian",
@@ -1765,7 +1765,7 @@ void writeResultDatasets(
static_cast<hsize_t>(domain.Elements().size()),
kEndpointCount,
kGeneralizedComponentCount};
const auto endActions = flattenEndpointValues(state.endpointResults(), false);
const auto endActions = flattenEndpointValues(state.EndpointResults(), false);
writeDoubleDataset(
file,
std::string{kStepRoot} + "/element/end_force_local",
@@ -1777,7 +1777,7 @@ void writeResultDatasets(
"beam-local",
"endpoint-outward-action");
const auto sectionResultants =
flattenEndpointValues(state.endpointResults(), true);
flattenEndpointValues(state.EndpointResults(), true);
writeDoubleDataset(
file,
std::string{kStepRoot} + "/element/section_resultant",
@@ -1789,7 +1789,7 @@ void writeResultDatasets(
"beam-local",
"endpoint-positive-local-x-section-cut");
const auto generalizedStrains =
flattenGaussValues(state.gaussResults(), false);
flattenGaussValues(state.GaussResults(), false);
writeDoubleDataset(
file,
std::string{kStepRoot} + "/element/generalized_strain",
@@ -1801,7 +1801,7 @@ void writeResultDatasets(
"beam-local",
"integration-point");
const auto generalizedResultants =
flattenGaussValues(state.gaussResults(), true);
flattenGaussValues(state.GaussResults(), true);
writeDoubleDataset(
file,
std::string{kStepRoot} + "/element/generalized_resultant",
@@ -2494,7 +2494,7 @@ void selfCheckFile(
"beam-local", "integration-point");
requireCompoundDataset(
file.get(), "/steps/Step-1/frames/0/element/stress_s11",
static_cast<hsize_t>(state.stressResults().size()),
static_cast<hsize_t>(state.StressResults().size()),
{"internal_element_id", "gauss_point_index", "section_point_index",
"x1", "x2", "source", "S11"});
auto stress = openDatasetForCheck(
@@ -2563,7 +2563,7 @@ bool finalizeFile(
} // namespace
Status Hdf5ResultsWriter::write(
Status Hdf5ResultsWriter::Write(
const std::filesystem::path& outputPath,
const Domain& domain,
const AnalysisState& state,