88 lines
3.9 KiB
C++
88 lines
3.9 KiB
C++
#include "results/analysis_state_commit.h"
|
|
|
|
#include <array>
|
|
#include <utility>
|
|
|
|
namespace fesa::results_internal {
|
|
|
|
Status CommitRecoveryCandidate(RecoveryCandidate candidate,
|
|
AnalysisState& state) {
|
|
const std::size_t full_count = state.Displacement().Size();
|
|
if (candidate.displacement.Size() != full_count ||
|
|
candidate.external_force.Size() != full_count ||
|
|
candidate.internal_force.Size() != full_count ||
|
|
candidate.residual.Size() != full_count ||
|
|
candidate.reaction.Size() != full_count) {
|
|
return RecoveryFailure(
|
|
"invalid-recovery-dimensions", {}, state.Identity().step_name,
|
|
"Recovery candidate vectors must match the AnalysisState dimension.");
|
|
}
|
|
if (!IsFiniteVector(candidate.displacement) ||
|
|
!IsFiniteVector(candidate.external_force) ||
|
|
!IsFiniteVector(candidate.internal_force) ||
|
|
!IsFiniteVector(candidate.residual) ||
|
|
!IsFiniteVector(candidate.reaction)) {
|
|
return RecoveryFailure(
|
|
"nonfinite-recovery-value", {}, state.Identity().step_name,
|
|
"Recovery candidate vectors must contain only finite values.");
|
|
}
|
|
|
|
const bool has_any_beam_rows = !candidate.endpoint_rows.empty() ||
|
|
!candidate.gauss_rows.empty() ||
|
|
!candidate.stress_rows.empty();
|
|
const bool has_complete_beam_rows = !candidate.endpoint_rows.empty() &&
|
|
!candidate.gauss_rows.empty() &&
|
|
!candidate.stress_rows.empty();
|
|
if (candidate.has_beam_results != has_complete_beam_rows ||
|
|
(has_any_beam_rows && !has_complete_beam_rows)) {
|
|
return RecoveryFailure(
|
|
"invalid-recovery-result-family", {}, state.Identity().step_name,
|
|
"Beam recovery flags require endpoint, Gauss, and stress rows as one "
|
|
"complete result family.");
|
|
}
|
|
|
|
const std::array<double, 6> zero_equilibrium{};
|
|
const std::array<double, 3> zero_metrics{};
|
|
const bool has_any_shell_results =
|
|
!candidate.expected_shell_elements.empty() ||
|
|
!candidate.shell.rows.empty() ||
|
|
candidate.shell.physical_strain_energy != 0.0 ||
|
|
candidate.shell.equilibrium != zero_equilibrium ||
|
|
candidate.shell.verification_metrics != zero_metrics ||
|
|
candidate.shell.mitc4_drilling.has_value();
|
|
const bool has_complete_shell_inventory =
|
|
!candidate.expected_shell_elements.empty() &&
|
|
!candidate.shell.rows.empty();
|
|
if (candidate.has_shell_results != has_complete_shell_inventory ||
|
|
(has_any_shell_results && !has_complete_shell_inventory)) {
|
|
return RecoveryFailure(
|
|
"invalid-recovery-result-family", {}, state.Identity().step_name,
|
|
"Shell recovery flags require expected elements and physical rows as "
|
|
"one complete result family.");
|
|
}
|
|
if (candidate.has_beam_results && candidate.has_shell_results) {
|
|
return RecoveryFailure(
|
|
"unsupported-mixed-element-model", {}, "mixed-runtime-results",
|
|
"Result recovery does not support mixed beam and shell models.");
|
|
}
|
|
|
|
AnalysisState candidate_state = state;
|
|
candidate_state.Displacement() = std::move(candidate.displacement);
|
|
candidate_state.ExternalForce() = std::move(candidate.external_force);
|
|
candidate_state.InternalForce() = std::move(candidate.internal_force);
|
|
candidate_state.Residual() = std::move(candidate.residual);
|
|
candidate_state.Reaction() = std::move(candidate.reaction);
|
|
candidate_state.EndpointResults() = std::move(candidate.endpoint_rows);
|
|
candidate_state.GaussResults() = std::move(candidate.gauss_rows);
|
|
candidate_state.StressResults() = std::move(candidate.stress_rows);
|
|
const Status shell_commit_status = candidate_state.CommitShellResults(
|
|
candidate.expected_shell_elements, std::move(candidate.shell));
|
|
if (!shell_commit_status.IsOk()) {
|
|
return shell_commit_status;
|
|
}
|
|
state = std::move(candidate_state);
|
|
return Status::Ok();
|
|
}
|
|
|
|
} // namespace fesa::results_internal
|