feat(cpp-object-oriented-modular-refactoring): step 5 - solver-workflow-google-style
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#include "fesa/analysis/analysis_state.hpp"
|
||||
#include "fesa/analysis/analysis_state.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -12,244 +12,212 @@ namespace {
|
||||
|
||||
constexpr std::size_t kShellLocationsPerElement = 4U;
|
||||
|
||||
Status shellCandidateFailure(
|
||||
const std::string& code,
|
||||
const std::string& identity,
|
||||
const std::string& message) {
|
||||
return Status::Failure(
|
||||
FailureCategory::kModel,
|
||||
{{Severity::kError,
|
||||
code,
|
||||
{},
|
||||
"ANALYSIS_STATE",
|
||||
identity,
|
||||
message}});
|
||||
/// @brief Creates a structured failure without mutating existing state.
|
||||
Status ShellCandidateFailure(const std::string& code,
|
||||
const std::string& identity,
|
||||
const std::string& message) {
|
||||
return Status::Failure(
|
||||
FailureCategory::kModel,
|
||||
{{Severity::kError, code, {}, "ANALYSIS_STATE", identity, message}});
|
||||
}
|
||||
|
||||
template<std::size_t Size>
|
||||
bool finite(const std::array<double, Size>& values) {
|
||||
return std::all_of(
|
||||
values.begin(), values.end(),
|
||||
[](const double value) { return std::isfinite(value); });
|
||||
template <std::size_t Size>
|
||||
/// @brief Tests one fixed-size candidate component array for finite values.
|
||||
bool IsFinite(const std::array<double, Size>& values) {
|
||||
return std::all_of(values.begin(), values.end(),
|
||||
[](const double value) { return std::isfinite(value); });
|
||||
}
|
||||
|
||||
bool finite(const ShellResultRow& row) {
|
||||
if (!finite(row.naturalCoordinates) ||
|
||||
!finite(row.generalizedStrain) ||
|
||||
!finite(row.sectionResultant)) {
|
||||
return false;
|
||||
/// @brief Tests every physical shell row component for finite values.
|
||||
bool IsFinite(const ShellResultRow& row) {
|
||||
if (!IsFinite(row.natural_coordinates) || !IsFinite(row.generalized_strain) ||
|
||||
!IsFinite(row.section_resultant)) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& axis : row.local_frame) {
|
||||
if (!IsFinite(axis)) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& axis : row.localFrame) {
|
||||
if (!finite(axis)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return std::all_of(
|
||||
row.stress.begin(), row.stress.end(),
|
||||
[](const ShellSectionStressRow& stress) {
|
||||
return std::isfinite(stress.zeta) && finite(stress.components);
|
||||
});
|
||||
}
|
||||
return std::all_of(row.stress.begin(), row.stress.end(),
|
||||
[](const ShellSectionStressRow& stress) {
|
||||
return std::isfinite(stress.zeta) &&
|
||||
IsFinite(stress.components);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
AnalysisState AnalysisState::create(
|
||||
const DofManager& dofs, StepFrameIdentity identity) {
|
||||
return AnalysisState{dofs.fullDofCount(), std::move(identity)};
|
||||
AnalysisState AnalysisState::Create(const DofManager& dofs,
|
||||
StepFrameIdentity identity) {
|
||||
return AnalysisState{dofs.FullDofCount(), std::move(identity)};
|
||||
}
|
||||
|
||||
Vector& AnalysisState::displacement() noexcept {
|
||||
return displacement_;
|
||||
Vector& AnalysisState::Displacement() noexcept { return displacement_; }
|
||||
|
||||
const Vector& AnalysisState::Displacement() const noexcept {
|
||||
return displacement_;
|
||||
}
|
||||
|
||||
const Vector& AnalysisState::displacement() const noexcept {
|
||||
return displacement_;
|
||||
Vector& AnalysisState::ExternalForce() noexcept { return external_force_; }
|
||||
|
||||
const Vector& AnalysisState::ExternalForce() const noexcept {
|
||||
return external_force_;
|
||||
}
|
||||
|
||||
Vector& AnalysisState::externalForce() noexcept {
|
||||
return externalForce_;
|
||||
Vector& AnalysisState::InternalForce() noexcept { return internal_force_; }
|
||||
|
||||
const Vector& AnalysisState::InternalForce() const noexcept {
|
||||
return internal_force_;
|
||||
}
|
||||
|
||||
const Vector& AnalysisState::externalForce() const noexcept {
|
||||
return externalForce_;
|
||||
Vector& AnalysisState::Residual() noexcept { return residual_; }
|
||||
|
||||
const Vector& AnalysisState::Residual() const noexcept { return residual_; }
|
||||
|
||||
Vector& AnalysisState::Reaction() noexcept { return reaction_; }
|
||||
|
||||
const Vector& AnalysisState::Reaction() const noexcept { return reaction_; }
|
||||
|
||||
const StepFrameIdentity& AnalysisState::Identity() const noexcept {
|
||||
return identity_;
|
||||
}
|
||||
|
||||
Vector& AnalysisState::internalForce() noexcept {
|
||||
return internalForce_;
|
||||
std::vector<EndpointResultRow>& AnalysisState::EndpointResults() noexcept {
|
||||
return endpoint_results_;
|
||||
}
|
||||
|
||||
const Vector& AnalysisState::internalForce() const noexcept {
|
||||
return internalForce_;
|
||||
const std::vector<EndpointResultRow>& AnalysisState::EndpointResults()
|
||||
const noexcept {
|
||||
return endpoint_results_;
|
||||
}
|
||||
|
||||
Vector& AnalysisState::residual() noexcept {
|
||||
return residual_;
|
||||
std::vector<GaussResultRow>& AnalysisState::GaussResults() noexcept {
|
||||
return gauss_results_;
|
||||
}
|
||||
|
||||
const Vector& AnalysisState::residual() const noexcept {
|
||||
return residual_;
|
||||
const std::vector<GaussResultRow>& AnalysisState::GaussResults()
|
||||
const noexcept {
|
||||
return gauss_results_;
|
||||
}
|
||||
|
||||
Vector& AnalysisState::reaction() noexcept {
|
||||
return reaction_;
|
||||
std::vector<StressS11Row>& AnalysisState::StressResults() noexcept {
|
||||
return stress_results_;
|
||||
}
|
||||
|
||||
const Vector& AnalysisState::reaction() const noexcept {
|
||||
return reaction_;
|
||||
const std::vector<StressS11Row>& AnalysisState::StressResults() const noexcept {
|
||||
return stress_results_;
|
||||
}
|
||||
|
||||
const StepFrameIdentity& AnalysisState::identity() const noexcept {
|
||||
return identity_;
|
||||
}
|
||||
|
||||
std::vector<EndpointResultRow>& AnalysisState::endpointResults() noexcept {
|
||||
return endpointResults_;
|
||||
}
|
||||
|
||||
const std::vector<EndpointResultRow>& AnalysisState::endpointResults() const noexcept {
|
||||
return endpointResults_;
|
||||
}
|
||||
|
||||
std::vector<GaussResultRow>& AnalysisState::gaussResults() noexcept {
|
||||
return gaussResults_;
|
||||
}
|
||||
|
||||
const std::vector<GaussResultRow>& AnalysisState::gaussResults() const noexcept {
|
||||
return gaussResults_;
|
||||
}
|
||||
|
||||
std::vector<StressS11Row>& AnalysisState::stressResults() noexcept {
|
||||
return stressResults_;
|
||||
}
|
||||
|
||||
const std::vector<StressS11Row>& AnalysisState::stressResults() const noexcept {
|
||||
return stressResults_;
|
||||
}
|
||||
|
||||
Status AnalysisState::commitShellResults(
|
||||
const std::vector<EntityIndex>& expectedElementOrder,
|
||||
Status AnalysisState::CommitShellResults(
|
||||
const std::vector<EntityIndex>& expected_element_order,
|
||||
ShellStateCandidate candidate) {
|
||||
if (expectedElementOrder.size() >
|
||||
(std::numeric_limits<std::size_t>::max)() /
|
||||
kShellLocationsPerElement) {
|
||||
return shellCandidateFailure(
|
||||
"invalid-shell-state-inventory",
|
||||
identity_.stepName,
|
||||
"The expected shell result inventory is too large.");
|
||||
}
|
||||
const std::size_t expectedRowCount =
|
||||
expectedElementOrder.size() * kShellLocationsPerElement;
|
||||
if (candidate.rows.size() != expectedRowCount) {
|
||||
return shellCandidateFailure(
|
||||
"invalid-shell-state-inventory",
|
||||
identity_.stepName,
|
||||
"Shell results require exactly four rows per expected element.");
|
||||
}
|
||||
if (std::adjacent_find(
|
||||
expectedElementOrder.begin(), expectedElementOrder.end(),
|
||||
[](const EntityIndex left, const EntityIndex right) {
|
||||
return left >= right;
|
||||
}) != expectedElementOrder.end()) {
|
||||
return shellCandidateFailure(
|
||||
"invalid-shell-state-inventory",
|
||||
identity_.stepName,
|
||||
"Expected shell elements must be unique and in stable index order.");
|
||||
}
|
||||
if (expected_element_order.size() >
|
||||
(std::numeric_limits<std::size_t>::max)() / kShellLocationsPerElement) {
|
||||
return ShellCandidateFailure(
|
||||
"invalid-shell-state-inventory", identity_.step_name,
|
||||
"The expected shell result inventory is too large.");
|
||||
}
|
||||
const std::size_t expected_row_count =
|
||||
expected_element_order.size() * kShellLocationsPerElement;
|
||||
if (candidate.rows.size() != expected_row_count) {
|
||||
return ShellCandidateFailure(
|
||||
"invalid-shell-state-inventory", identity_.step_name,
|
||||
"Shell results require exactly four rows per expected element.");
|
||||
}
|
||||
if (std::adjacent_find(expected_element_order.begin(),
|
||||
expected_element_order.end(),
|
||||
[](const EntityIndex left, const EntityIndex right) {
|
||||
return left >= right;
|
||||
}) != expected_element_order.end()) {
|
||||
return ShellCandidateFailure(
|
||||
"invalid-shell-state-inventory", identity_.step_name,
|
||||
"Expected shell elements must be unique and in stable index order.");
|
||||
}
|
||||
|
||||
const std::array<ShellMidsurfaceLocation, kShellLocationsPerElement>
|
||||
expectedLocations{
|
||||
ShellMidsurfaceLocation::gp1,
|
||||
ShellMidsurfaceLocation::gp2,
|
||||
ShellMidsurfaceLocation::gp3,
|
||||
ShellMidsurfaceLocation::gp4};
|
||||
const double gauss = 1.0 / std::sqrt(3.0);
|
||||
const std::array<std::array<double, 2>, kShellLocationsPerElement>
|
||||
expectedCoordinates{
|
||||
std::array<double, 2>{-gauss, -gauss},
|
||||
std::array<double, 2>{gauss, -gauss},
|
||||
std::array<double, 2>{gauss, gauss},
|
||||
std::array<double, 2>{-gauss, gauss}};
|
||||
const std::array<ShellSectionPosition, 3> expectedPositions{
|
||||
ShellSectionPosition::bottom,
|
||||
ShellSectionPosition::middle,
|
||||
ShellSectionPosition::top};
|
||||
constexpr std::array<double, 3> expectedZeta{-1.0, 0.0, 1.0};
|
||||
for (std::size_t elementOrder = 0U;
|
||||
elementOrder < expectedElementOrder.size();
|
||||
++elementOrder) {
|
||||
for (std::size_t point = 0U;
|
||||
point < kShellLocationsPerElement;
|
||||
++point) {
|
||||
const auto& row = candidate.rows[
|
||||
elementOrder * kShellLocationsPerElement + point];
|
||||
if (row.element != expectedElementOrder[elementOrder] ||
|
||||
row.location != expectedLocations[point] ||
|
||||
row.naturalCoordinates != expectedCoordinates[point]) {
|
||||
return shellCandidateFailure(
|
||||
"invalid-shell-state-inventory",
|
||||
std::to_string(row.element),
|
||||
"Shell rows must preserve element and GP1 through GP4 identity.");
|
||||
}
|
||||
for (std::size_t position = 0U;
|
||||
position < expectedPositions.size();
|
||||
++position) {
|
||||
if (row.stress[position].position !=
|
||||
expectedPositions[position] ||
|
||||
row.stress[position].zeta != expectedZeta[position]) {
|
||||
return shellCandidateFailure(
|
||||
"invalid-shell-state-inventory",
|
||||
std::to_string(row.element),
|
||||
"Shell stress rows require BOTTOM, MIDDLE, TOP identity.");
|
||||
}
|
||||
}
|
||||
if (!finite(row)) {
|
||||
return shellCandidateFailure(
|
||||
"nonfinite-shell-state-value",
|
||||
std::to_string(row.element),
|
||||
"Shell result rows must contain only finite values.");
|
||||
}
|
||||
const std::array<ShellMidsurfaceLocation, kShellLocationsPerElement>
|
||||
expected_locations{
|
||||
ShellMidsurfaceLocation::kGp1, ShellMidsurfaceLocation::kGp2,
|
||||
ShellMidsurfaceLocation::kGp3, ShellMidsurfaceLocation::kGp4};
|
||||
const double gauss = 1.0 / std::sqrt(3.0);
|
||||
const std::array<std::array<double, 2>, kShellLocationsPerElement>
|
||||
expected_coordinates{std::array<double, 2>{-gauss, -gauss},
|
||||
std::array<double, 2>{gauss, -gauss},
|
||||
std::array<double, 2>{gauss, gauss},
|
||||
std::array<double, 2>{-gauss, gauss}};
|
||||
const std::array<ShellSectionPosition, 3> expected_positions{
|
||||
ShellSectionPosition::kBottom, ShellSectionPosition::kMiddle,
|
||||
ShellSectionPosition::kTop};
|
||||
constexpr std::array<double, 3> expected_zeta{-1.0, 0.0, 1.0};
|
||||
for (std::size_t element_order = 0U;
|
||||
element_order < expected_element_order.size(); ++element_order) {
|
||||
for (std::size_t point = 0U; point < kShellLocationsPerElement; ++point) {
|
||||
const auto& row =
|
||||
candidate.rows[element_order * kShellLocationsPerElement + point];
|
||||
if (row.element != expected_element_order[element_order] ||
|
||||
row.location != expected_locations[point] ||
|
||||
row.natural_coordinates != expected_coordinates[point]) {
|
||||
return ShellCandidateFailure(
|
||||
"invalid-shell-state-inventory", std::to_string(row.element),
|
||||
"Shell rows must preserve element and GP1 through GP4 identity.");
|
||||
}
|
||||
for (std::size_t position = 0U; position < expected_positions.size();
|
||||
++position) {
|
||||
if (row.stress[position].position != expected_positions[position] ||
|
||||
row.stress[position].zeta != expected_zeta[position]) {
|
||||
return ShellCandidateFailure(
|
||||
"invalid-shell-state-inventory", std::to_string(row.element),
|
||||
"Shell stress rows require BOTTOM, MIDDLE, TOP identity.");
|
||||
}
|
||||
}
|
||||
if (!IsFinite(row)) {
|
||||
return ShellCandidateFailure(
|
||||
"nonfinite-shell-state-value", std::to_string(row.element),
|
||||
"Shell result rows must contain only finite values.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!std::isfinite(candidate.physicalStrainEnergy) ||
|
||||
!finite(candidate.equilibrium) ||
|
||||
!finite(candidate.verificationMetrics)) {
|
||||
return shellCandidateFailure(
|
||||
"nonfinite-shell-state-value",
|
||||
identity_.stepName,
|
||||
"Shell energy, equilibrium, and normalized metrics must be finite.");
|
||||
}
|
||||
if (!std::isfinite(candidate.physical_strain_energy) ||
|
||||
!IsFinite(candidate.equilibrium) ||
|
||||
!IsFinite(candidate.verification_metrics)) {
|
||||
return ShellCandidateFailure(
|
||||
"nonfinite-shell-state-value", identity_.step_name,
|
||||
"Shell energy, equilibrium, and normalized metrics must be finite.");
|
||||
}
|
||||
|
||||
shellResults_ = std::move(candidate.rows);
|
||||
physicalStrainEnergy_ = candidate.physicalStrainEnergy;
|
||||
equilibrium_ = candidate.equilibrium;
|
||||
verificationMetrics_ = candidate.verificationMetrics;
|
||||
return Status::Ok();
|
||||
shell_results_ = std::move(candidate.rows);
|
||||
physical_strain_energy_ = candidate.physical_strain_energy;
|
||||
equilibrium_ = candidate.equilibrium;
|
||||
verification_metrics_ = candidate.verification_metrics;
|
||||
return Status::Ok();
|
||||
}
|
||||
|
||||
const std::vector<ShellResultRow>& AnalysisState::shellResults() const noexcept {
|
||||
return shellResults_;
|
||||
const std::vector<ShellResultRow>& AnalysisState::ShellResults()
|
||||
const noexcept {
|
||||
return shell_results_;
|
||||
}
|
||||
|
||||
double AnalysisState::physicalStrainEnergy() const noexcept {
|
||||
return physicalStrainEnergy_;
|
||||
double AnalysisState::PhysicalStrainEnergy() const noexcept {
|
||||
return physical_strain_energy_;
|
||||
}
|
||||
|
||||
const std::array<double, 6>& AnalysisState::equilibrium() const noexcept {
|
||||
return equilibrium_;
|
||||
const std::array<double, 6>& AnalysisState::Equilibrium() const noexcept {
|
||||
return equilibrium_;
|
||||
}
|
||||
|
||||
const std::array<double, 3>& AnalysisState::verificationMetrics() const noexcept {
|
||||
return verificationMetrics_;
|
||||
const std::array<double, 3>& AnalysisState::VerificationMetrics()
|
||||
const noexcept {
|
||||
return verification_metrics_;
|
||||
}
|
||||
|
||||
AnalysisState::AnalysisState(
|
||||
std::size_t fullDofCount, StepFrameIdentity identity)
|
||||
AnalysisState::AnalysisState(std::size_t full_dof_count,
|
||||
StepFrameIdentity identity)
|
||||
: identity_{std::move(identity)},
|
||||
displacement_{fullDofCount},
|
||||
externalForce_{fullDofCount},
|
||||
internalForce_{fullDofCount},
|
||||
residual_{fullDofCount},
|
||||
reaction_{fullDofCount} {}
|
||||
displacement_{full_dof_count},
|
||||
external_force_{full_dof_count},
|
||||
internal_force_{full_dof_count},
|
||||
residual_{full_dof_count},
|
||||
reaction_{full_dof_count} {}
|
||||
|
||||
} // namespace fesa
|
||||
} // namespace fesa
|
||||
|
||||
Reference in New Issue
Block a user