feat(cpp-object-oriented-modular-refactoring): step 4 - model-element-google-style

This commit is contained in:
KOKO\Mimi
2026-08-16 05:37:40 +09:00
parent 34ab8b5bf1
commit 8bc0ea2f8e
46 changed files with 5184 additions and 5323 deletions
+149 -149
View File
@@ -1,7 +1,7 @@
#include "fesa/results/result_recovery.hpp"
#include "fesa/elements/euler_beam_3d.hpp"
#include "fesa/elements/mitc4_shell.hpp"
#include "fesa/elements/euler_beam_3d.h"
#include "fesa/elements/mitc4_shell.h"
#include <algorithm>
#include <array>
@@ -131,15 +131,15 @@ Status validateRecoveryInputs(const AnalysisModel& model,
const SparseMatrix& fullStiffness,
const AnalysisState& state) {
const Domain& domain = model.domain();
if (domain.nodes().size() >
if (domain.Nodes().size() >
(std::numeric_limits<std::size_t>::max)() / kDofsPerNode) {
return recoveryFailure(
"invalid-recovery-dimensions",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"The semantic node count cannot be represented in full-DOF space.");
}
const std::size_t fullCount = domain.nodes().size() * kDofsPerNode;
const std::size_t fullCount = domain.Nodes().size() * kDofsPerNode;
if (dofs.fullDofCount() != fullCount ||
fullStiffness.Rows() != fullCount ||
fullStiffness.Columns() != fullCount ||
@@ -150,8 +150,8 @@ Status validateRecoveryInputs(const AnalysisModel& model,
state.reaction().Size() != fullCount) {
return recoveryFailure(
"invalid-recovery-dimensions",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"Model, DOF, stiffness, and AnalysisState full-space dimensions must agree.");
}
const Status matrixStatus = fullStiffness.Validate();
@@ -161,8 +161,8 @@ Status validateRecoveryInputs(const AnalysisModel& model,
if (!finite(state.displacement()) || !finite(state.externalForce())) {
return recoveryFailure(
"nonfinite-recovery-value",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"Displacement and external-force inputs must be finite.");
}
@@ -176,8 +176,8 @@ Status validateRecoveryInputs(const AnalysisModel& model,
!strictlyIncreasing(constrainedDofs)) {
return recoveryFailure(
"invalid-recovery-order",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"Free and constrained DOFs must form stable increasing full-space orders.");
}
std::vector<unsigned char> ownership(fullCount, 0U);
@@ -188,7 +188,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
dofs.freeEquation(fullDof) != equation) {
return recoveryFailure(
"invalid-recovery-order",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
std::to_string(fullDof),
"Free equations must match stable full-DOF order.");
}
@@ -202,7 +202,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
dofs.freeEquation(fullDof).has_value()) {
return recoveryFailure(
"invalid-recovery-order",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
std::to_string(fullDof),
"Constrained DOFs must be unique and absent from free equations.");
}
@@ -211,7 +211,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
dofs.prescribedValues()[constrained]) {
return recoveryFailure(
"invalid-recovery-state",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
std::to_string(fullDof),
"Constrained displacement must equal its prescribed value before recovery.");
}
@@ -220,40 +220,40 @@ Status validateRecoveryInputs(const AnalysisModel& model,
} catch (const std::out_of_range&) {
return recoveryFailure(
"invalid-recovery-dimensions",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"DofManager equation storage must cover every full DOF.");
}
if (std::find(ownership.begin(), ownership.end(), 0U) != ownership.end()) {
return recoveryFailure(
"invalid-recovery-order",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"Free and constrained DOFs must partition the full range.");
}
EntityIndex previousElement = 0U;
bool firstElement = true;
for (const EntityIndex element : model.activeElements()) {
if (element >= domain.elements().size() ||
if (element >= domain.Elements().size() ||
(!firstElement && element <= previousElement)) {
return recoveryFailure(
"invalid-recovery-entity",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
std::to_string(element),
"Active elements must be unique in stable internal-index order.");
}
firstElement = false;
previousElement = element;
const auto& definition = domain.elements()[element];
if (definition.nodeIndices[0U] >= domain.nodes().size() ||
definition.nodeIndices[1U] >= domain.nodes().size() ||
definition.materialIndex >= domain.materials().size() ||
definition.sectionIndex >= domain.sections().size()) {
const auto& definition = domain.Elements()[element];
if (definition.node_indices[0U] >= domain.Nodes().size() ||
definition.node_indices[1U] >= domain.Nodes().size() ||
definition.material_index >= domain.Materials().size() ||
definition.section_index >= domain.Sections().size()) {
return recoveryFailure(
"invalid-recovery-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Active beam references must resolve before recovery.");
}
try {
@@ -263,7 +263,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
component < kDofsPerNode;
++component) {
const std::size_t expected =
static_cast<std::size_t>(definition.nodeIndices[endpoint]) *
static_cast<std::size_t>(definition.node_indices[endpoint]) *
kDofsPerNode +
component;
if (scatter[endpoint * kDofsPerNode + component] != expected ||
@@ -271,7 +271,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
return recoveryFailure(
"invalid-recovery-order",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Element scatter must preserve endpoint/component full-DOF order.");
}
}
@@ -280,51 +280,51 @@ Status validateRecoveryInputs(const AnalysisModel& model,
return recoveryFailure(
"invalid-recovery-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Every active element requires one twelve-DOF scatter map.");
}
}
if (!model.activeElements().empty() && !domain.shellElements().empty()) {
if (!model.activeElements().empty() && !domain.ShellElements().empty()) {
return recoveryFailure(
"unsupported-mixed-element-model",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
"B33:FESA-MITC4",
"Result recovery does not support mixed beam and shell models.");
}
if (domain.shellElements().size() >
if (domain.ShellElements().size() >
static_cast<std::size_t>(
(std::numeric_limits<EntityIndex>::max)())) {
return recoveryFailure(
"invalid-recovery-dimensions",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"The shell element count cannot be represented by stable element identities.");
}
for (std::size_t elementOrder = 0U;
elementOrder < domain.shellElements().size();
elementOrder < domain.ShellElements().size();
++elementOrder) {
const auto& definition = domain.shellElements()[elementOrder];
if (definition.materialIndex >= domain.materials().size() ||
definition.sectionIndex >= domain.shellSections().size()) {
const auto& definition = domain.ShellElements()[elementOrder];
if (definition.material_index >= domain.Materials().size() ||
definition.section_index >= domain.ShellSections().size()) {
return recoveryFailure(
"invalid-recovery-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Active shell material and section references must resolve before recovery.");
}
try {
const auto& scatter = dofs.shellElementScatter(
static_cast<EntityIndex>(elementOrder));
for (std::size_t nodePosition = 0U;
nodePosition < definition.nodeIndices.size();
nodePosition < definition.node_indices.size();
++nodePosition) {
const EntityIndex node = definition.nodeIndices[nodePosition];
if (node >= domain.nodes().size()) {
const EntityIndex node = definition.node_indices[nodePosition];
if (node >= domain.Nodes().size()) {
return recoveryFailure(
"invalid-recovery-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Active shell node references must resolve before recovery.");
}
for (std::size_t component = 0U;
@@ -339,7 +339,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
return recoveryFailure(
"invalid-recovery-order",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Shell scatter must preserve node/component full-DOF order.");
}
}
@@ -348,7 +348,7 @@ Status validateRecoveryInputs(const AnalysisModel& model,
return recoveryFailure(
"invalid-recovery-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Every active shell requires one twenty-four-DOF scatter map.");
}
}
@@ -381,7 +381,7 @@ bool tryPositiveInteger(const std::string& text, std::int64_t& value) {
Result<std::vector<EntityIndex>> resolveLoadTarget(const Domain& domain,
const NodalLoad& load) {
std::vector<const NodeSet*> sets;
for (const auto& set : domain.nodeSets()) {
for (const auto& set : domain.NodeSets()) {
if (equalName(set.name, load.target)) {
sets.push_back(&set);
}
@@ -389,8 +389,8 @@ Result<std::vector<EntityIndex>> resolveLoadTarget(const Domain& domain,
std::vector<EntityIndex> nodes;
std::int64_t sourceLabel = 0;
if (tryPositiveInteger(load.target, sourceLabel)) {
for (std::size_t node = 0U; node < domain.nodes().size(); ++node) {
if (domain.nodes()[node].sourceId.source_label == sourceLabel) {
for (std::size_t node = 0U; node < domain.Nodes().size(); ++node) {
if (domain.Nodes()[node].source_id.source_label == sourceLabel) {
nodes.push_back(static_cast<EntityIndex>(node));
}
}
@@ -404,9 +404,9 @@ Result<std::vector<EntityIndex>> resolveLoadTarget(const Domain& domain,
"A station-eligibility load target must resolve unambiguously.");
}
if (!sets.empty()) {
std::vector<unsigned char> seen(domain.nodes().size(), 0U);
for (const EntityIndex node : sets.front()->nodeIndices) {
if (node >= domain.nodes().size() || seen[node] != 0U) {
std::vector<unsigned char> seen(domain.Nodes().size(), 0U);
for (const EntityIndex node : sets.front()->node_indices) {
if (node >= domain.Nodes().size() || seen[node] != 0U) {
return recoveryResultFailure<std::vector<EntityIndex>>(
"invalid-node-station-entity",
load.location,
@@ -416,7 +416,7 @@ Result<std::vector<EntityIndex>> resolveLoadTarget(const Domain& domain,
seen[node] = 1U;
}
return Result<std::vector<EntityIndex>>::Success(
sets.front()->nodeIndices);
sets.front()->node_indices);
}
if (!nodes.empty()) {
return Result<std::vector<EntityIndex>>::Success(std::move(nodes));
@@ -504,7 +504,7 @@ Status populateShellGlobalEvidence(
double reactionForceScale = 0.0;
double appliedMomentScale = 0.0;
double reactionMomentScale = 0.0;
for (std::size_t node = 0U; node < domain.nodes().size(); ++node) {
for (std::size_t node = 0U; node < domain.Nodes().size(); ++node) {
const std::size_t offset = node * kDofsPerNode;
std::array<double, 3> nodalAppliedForce{};
std::array<double, 3> nodalReactionForce{};
@@ -524,9 +524,9 @@ Status populateShellGlobalEvidence(
}
const auto appliedForceMoment =
cross(domain.nodes()[node].coordinates, nodalAppliedForce);
cross(domain.Nodes()[node].coordinates, nodalAppliedForce);
const auto reactionForceMoment =
cross(domain.nodes()[node].coordinates, nodalReactionForce);
cross(domain.Nodes()[node].coordinates, nodalReactionForce);
for (std::size_t component = 0U; component < 3U; ++component) {
nodalAppliedMoment[component] += appliedForceMoment[component];
nodalReactionMoment[component] += reactionForceMoment[component];
@@ -541,8 +541,8 @@ Status populateShellGlobalEvidence(
reactionMoment, reactionMomentScale, nodalReactionMoment)) {
return recoveryFailure(
"nonfinite-recovery-value",
domain.nodes()[node].location,
domain.nodes()[node].sourceId.source_label_text,
domain.Nodes()[node].location,
domain.Nodes()[node].source_id.source_label_text,
"Global force and moment evidence must remain finite in source-node order.");
}
}
@@ -569,7 +569,7 @@ Status populateShellGlobalEvidence(
!finite(candidate.verificationMetrics)) {
return recoveryFailure(
"nonfinite-recovery-value",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
"global-equilibrium",
"Global equilibrium values and their physical normalization scales must be finite.");
}
@@ -577,7 +577,7 @@ Status populateShellGlobalEvidence(
momentMetric > kGlobalEquilibriumTolerance) {
return recoveryFailure(
"global-equilibrium-tolerance-failure",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
"global-equilibrium",
"Normalized global force or moment balance exceeds 1e-10.");
}
@@ -586,8 +586,8 @@ Status populateShellGlobalEvidence(
std::optional<AxisSet> localAxes(const Domain& domain,
const EulerBeam3DDefinition& element) {
const auto& first = domain.nodes()[element.nodeIndices[0U]].coordinates;
const auto& second = domain.nodes()[element.nodeIndices[1U]].coordinates;
const auto& first = domain.Nodes()[element.node_indices[0U]].coordinates;
const auto& second = domain.Nodes()[element.node_indices[1U]].coordinates;
const std::array<double, 3> delta = {
second[0U] - first[0U],
second[1U] - first[1U],
@@ -598,7 +598,7 @@ std::optional<AxisSet> localAxes(const Domain& domain,
}
const std::array<double, 3> ex = {
delta[0U] / length, delta[1U] / length, delta[2U] / length};
const auto& guide = domain.sections()[element.sectionIndex].firstAxis;
const auto& guide = domain.Sections()[element.section_index].first_axis;
const double projection = dot(guide, ex);
const std::array<double, 3> eyTrial = {
guide[0U] - projection * ex[0U],
@@ -654,8 +654,8 @@ Status ResultRecovery::recover(const AnalysisModel& model,
if (!finite(internalForce)) {
return recoveryFailure(
"nonfinite-recovery-value",
{model.domain().sourcePath(), 0U},
model.domain().sourceContentIdentity(),
{model.domain().SourcePath(), 0U},
model.domain().SourceContentIdentity(),
"Full stiffness multiplication must produce finite internal force.");
}
Vector residual{dofs.fullDofCount()};
@@ -665,7 +665,7 @@ Status ResultRecovery::recover(const AnalysisModel& model,
if (!std::isfinite(residual[fullDof])) {
return recoveryFailure(
"nonfinite-recovery-value",
{model.domain().sourcePath(), 0U},
{model.domain().SourcePath(), 0U},
std::to_string(fullDof),
"Internal-minus-external residual must remain finite.");
}
@@ -684,7 +684,7 @@ Status ResultRecovery::recover(const AnalysisModel& model,
if (!std::isfinite(residualNorm) || !std::isfinite(denominator)) {
return recoveryFailure(
"nonfinite-recovery-value",
{model.domain().sourcePath(), 0U},
{model.domain().SourcePath(), 0U},
"free-residual",
"Free residual and its physical normalization scale must be finite.");
}
@@ -699,7 +699,7 @@ Status ResultRecovery::recover(const AnalysisModel& model,
normalizedResidual > kFreeResidualTolerance) {
return recoveryFailure(
"free-residual-tolerance-failure",
{model.domain().sourcePath(), 0U},
{model.domain().SourcePath(), 0U},
"free-residual",
"The normalized free residual exceeds 1e-10.");
}
@@ -716,12 +716,12 @@ Status ResultRecovery::recover(const AnalysisModel& model,
gaussRows.reserve(model.activeElements().size() * 2U);
const Domain& domain = model.domain();
for (const EntityIndex elementIndex : model.activeElements()) {
const auto& definition = domain.elements()[elementIndex];
auto beam = EulerBeam3D::create(
domain.nodes()[definition.nodeIndices[0U]],
domain.nodes()[definition.nodeIndices[1U]],
domain.sections()[definition.sectionIndex],
domain.materials()[definition.materialIndex]);
const auto& definition = domain.Elements()[elementIndex];
auto beam = EulerBeam3D::Create(
domain.Nodes()[definition.node_indices[0U]],
domain.Nodes()[definition.node_indices[1U]],
domain.Sections()[definition.section_index],
domain.Materials()[definition.material_index]);
if (!beam.HasValue()) {
return beam.GetStatus();
}
@@ -735,52 +735,52 @@ Status ResultRecovery::recover(const AnalysisModel& model,
state.displacement()[scatter[localDof]];
}
const BeamRecovery recovered =
beam.Value().recover(elementDisplacement);
beam.Value().Recover(elementDisplacement);
for (std::size_t endpoint = 0U; endpoint < 2U; ++endpoint) {
if (!finite(recovered.equilibriumEndActions[endpoint]) ||
!finite(recovered.endpointSectionResultants[endpoint])) {
if (!finite(recovered.equilibrium_end_actions[endpoint]) ||
!finite(recovered.endpoint_section_resultants[endpoint])) {
return recoveryFailure(
"nonfinite-recovery-value",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Endpoint recovery values must be finite.");
}
endpointRows.push_back({
elementIndex,
static_cast<int>(endpoint),
domain.nodes()[definition.nodeIndices[endpoint]].sourceId,
recovered.equilibriumEndActions[endpoint],
recovered.endpointSectionResultants[endpoint]});
domain.Nodes()[definition.node_indices[endpoint]].source_id,
recovered.equilibrium_end_actions[endpoint],
recovered.endpoint_section_resultants[endpoint]});
}
for (std::size_t gauss = 0U; gauss < 2U; ++gauss) {
if (!finite(recovered.gaussGeneralizedStrains[gauss]) ||
!finite(recovered.gaussGeneralizedResultants[gauss])) {
if (!finite(recovered.gauss_generalized_strains[gauss]) ||
!finite(recovered.gauss_generalized_resultants[gauss])) {
return recoveryFailure(
"nonfinite-recovery-value",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Gauss recovery values must be finite.");
}
gaussRows.push_back({
elementIndex,
static_cast<int>(gauss + 1U),
recovered.gaussGeneralizedStrains[gauss],
recovered.gaussGeneralizedResultants[gauss]});
recovered.gauss_generalized_strains[gauss],
recovered.gauss_generalized_resultants[gauss]});
}
for (const auto& point : recovered.stressPoints) {
if ((point.gaussPoint != 1 && point.gaussPoint != 2) ||
for (const auto& point : recovered.stress_points) {
if ((point.gauss_point != 1 && point.gauss_point != 2) ||
!std::isfinite(point.x1) || !std::isfinite(point.x2) ||
!std::isfinite(point.s11)) {
return recoveryFailure(
"nonfinite-recovery-value",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Stress recovery identity and values must be finite and ordered.");
}
stressRows.push_back({
elementIndex,
point.gaussPoint,
point.sectionPoint,
point.gauss_point,
point.section_point,
point.x1,
point.x2,
point.s11,
@@ -790,33 +790,33 @@ Status ResultRecovery::recover(const AnalysisModel& model,
ShellStateCandidate shellCandidate{};
std::vector<EntityIndex> expectedShellElements;
if (!domain.shellElements().empty()) {
if (domain.shellElements().size() >
if (!domain.ShellElements().empty()) {
if (domain.ShellElements().size() >
(std::numeric_limits<std::size_t>::max)() /
kShellLocationCount) {
return recoveryFailure(
"invalid-recovery-dimensions",
{domain.sourcePath(), 0U},
domain.sourceContentIdentity(),
{domain.SourcePath(), 0U},
domain.SourceContentIdentity(),
"The shell result-row inventory exceeds the addressable range.");
}
std::vector<std::optional<std::array<double, 3>>> directorsByNode(
domain.nodes().size());
for (const auto& frame : domain.shellNodeInitialFrames()) {
if (frame.nodeIndex >= directorsByNode.size() ||
directorsByNode[frame.nodeIndex].has_value()) {
domain.Nodes().size());
for (const auto& frame : domain.ShellNodeInitialFrames()) {
if (frame.node_index >= directorsByNode.size() ||
directorsByNode[frame.node_index].has_value()) {
return recoveryFailure(
"invalid-recovery-entity",
{domain.sourcePath(), 0U},
std::to_string(frame.nodeIndex),
{domain.SourcePath(), 0U},
std::to_string(frame.node_index),
"Shell initial directors must map uniquely to model nodes.");
}
directorsByNode[frame.nodeIndex] = frame.director;
directorsByNode[frame.node_index] = frame.director;
}
shellCandidate.rows.reserve(
domain.shellElements().size() * kShellLocationCount);
expectedShellElements.reserve(domain.shellElements().size());
domain.ShellElements().size() * kShellLocationCount);
expectedShellElements.reserve(domain.ShellElements().size());
constexpr std::array<ShellMidsurfaceLocation, kShellLocationCount>
locations{
ShellMidsurfaceLocation::gp1,
@@ -829,33 +829,33 @@ Status ResultRecovery::recover(const AnalysisModel& model,
ShellSectionPosition::top};
constexpr std::array<double, 3> zeta{-1.0, 0.0, 1.0};
for (std::size_t elementOrder = 0U;
elementOrder < domain.shellElements().size();
elementOrder < domain.ShellElements().size();
++elementOrder) {
const EntityIndex elementIndex =
static_cast<EntityIndex>(elementOrder);
const auto& definition = domain.shellElements()[elementOrder];
const auto& definition = domain.ShellElements()[elementOrder];
std::array<const Node*, 4> nodes{};
std::array<std::array<double, 3>, 4> directors{};
for (std::size_t nodePosition = 0U;
nodePosition < definition.nodeIndices.size();
nodePosition < definition.node_indices.size();
++nodePosition) {
const EntityIndex node = definition.nodeIndices[nodePosition];
const EntityIndex node = definition.node_indices[nodePosition];
if (!directorsByNode[node].has_value()) {
return recoveryFailure(
"invalid-recovery-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Shell recovery requires one initial director per element node.");
}
nodes[nodePosition] = &domain.nodes()[node];
nodes[nodePosition] = &domain.Nodes()[node];
directors[nodePosition] = *directorsByNode[node];
}
auto shell = Mitc4Shell::create(
auto shell = Mitc4Shell::Create(
nodes,
directors,
domain.shellSections()[definition.sectionIndex],
domain.materials()[definition.materialIndex]);
domain.ShellSections()[definition.section_index],
domain.Materials()[definition.material_index]);
if (!shell.HasValue()) {
return shell.GetStatus();
}
@@ -867,19 +867,19 @@ Status ResultRecovery::recover(const AnalysisModel& model,
elementDisplacement[localDof] =
state.displacement()[scatter[localDof]];
}
auto recovered = shell.Value().recoverPhysical(
auto recovered = shell.Value().RecoverPhysical(
elementDisplacement);
if (!recovered.HasValue()) {
return recovered.GetStatus();
}
const double accumulatedEnergy =
shellCandidate.physicalStrainEnergy +
recovered.Value().strainEnergy;
recovered.Value().strain_energy;
if (!std::isfinite(accumulatedEnergy)) {
return recoveryFailure(
"nonfinite-recovery-value",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Source-order physical shell energy reduction must remain finite.");
}
shellCandidate.physicalStrainEnergy = accumulatedEnergy;
@@ -892,20 +892,20 @@ Status ResultRecovery::recover(const AnalysisModel& model,
ShellResultRow row{};
row.element = elementIndex;
row.location = locations[point];
row.naturalCoordinates = physicalPoint.naturalCoordinates;
row.naturalCoordinates = physicalPoint.natural_coordinates;
row.localFrame = {
physicalPoint.localFrame.e1,
physicalPoint.localFrame.e2,
physicalPoint.localFrame.e3};
row.generalizedStrain = physicalPoint.generalizedStrain;
row.sectionResultant = physicalPoint.sectionResultant;
physicalPoint.local_frame.e1,
physicalPoint.local_frame.e2,
physicalPoint.local_frame.e3};
row.generalizedStrain = physicalPoint.generalized_strain;
row.sectionResultant = physicalPoint.section_resultant;
for (std::size_t position = 0U;
position < positions.size();
++position) {
row.stress[position] = {
positions[position],
zeta[position],
physicalPoint.inPlaneStress[position]};
physicalPoint.in_plane_stress[position]};
}
shellCandidate.rows.push_back(std::move(row));
}
@@ -951,7 +951,7 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
if (!std::isfinite(tolerance) || tolerance < 0.0) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"invalid-node-station-tolerance",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
"component-tolerances",
"Node-station component tolerances must be finite and nonnegative.");
}
@@ -961,50 +961,50 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
endpointRows.size() != model.activeElements().size() * 2U) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"invalid-node-station-shape",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
std::to_string(endpointRows.size()),
"Endpoint rows must contain exactly two rows per active element.");
}
std::vector<std::vector<const EndpointResultRow*>> rowsByNode(
domain.nodes().size());
domain.Nodes().size());
for (std::size_t order = 0U;
order < model.activeElements().size();
++order) {
const EntityIndex elementIndex = model.activeElements()[order];
if (elementIndex >= domain.elements().size()) {
if (elementIndex >= domain.Elements().size()) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"invalid-node-station-entity",
{domain.sourcePath(), 0U},
{domain.SourcePath(), 0U},
std::to_string(elementIndex),
"Every active station element must be a valid stable entity.");
}
const auto& definition = domain.elements()[elementIndex];
const auto& definition = domain.Elements()[elementIndex];
for (std::size_t endpoint = 0U; endpoint < 2U; ++endpoint) {
const auto& row = endpointRows[order * 2U + endpoint];
const EntityIndex nodeIndex = definition.nodeIndices[endpoint];
if (nodeIndex >= domain.nodes().size() ||
const EntityIndex nodeIndex = definition.node_indices[endpoint];
if (nodeIndex >= domain.Nodes().size() ||
row.element != elementIndex ||
row.endpoint != static_cast<int>(endpoint) ||
!sameSourceIdentity(row.node, domain.nodes()[nodeIndex].sourceId)) {
!sameSourceIdentity(row.node, domain.Nodes()[nodeIndex].source_id)) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"invalid-node-station-entity",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Endpoint rows must preserve active element, endpoint, and source-node order.");
}
if (!finite(row.sectionResultant)) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"nonfinite-node-station-value",
definition.location,
definition.sourceId.source_label_text,
definition.source_id.source_label_text,
"Node-station section resultants must be finite.");
}
rowsByNode[nodeIndex].push_back(&row);
}
}
std::vector<unsigned char> loadedNodes(domain.nodes().size(), 0U);
std::vector<unsigned char> loadedNodes(domain.Nodes().size(), 0U);
if (model.activeLoads().size() != model.step().loads.size()) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"invalid-node-station-entity",
@@ -1042,7 +1042,7 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
}
std::vector<NodeStationResultRow> stations;
stations.reserve(domain.nodes().size());
stations.reserve(domain.Nodes().size());
for (std::size_t nodeIndex = 0U;
nodeIndex < rowsByNode.size();
++nodeIndex) {
@@ -1052,7 +1052,7 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
}
if (incident.size() == 1U) {
stations.push_back({
domain.nodes()[nodeIndex].sourceId,
domain.Nodes()[nodeIndex].source_id,
incident.front()->element,
incident.front()->sectionResultant});
continue;
@@ -1060,13 +1060,13 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
if (incident.size() != 2U || loadedNodes[nodeIndex] != 0U) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"ineligible-node-station",
domain.nodes()[nodeIndex].location,
domain.nodes()[nodeIndex].sourceId.source_label_text,
domain.Nodes()[nodeIndex].location,
domain.Nodes()[nodeIndex].source_id.source_label_text,
"Interior station collapse requires exactly two unloaded endpoints.");
}
const auto& firstElement = domain.elements()[incident[0U]->element];
const auto& secondElement = domain.elements()[incident[1U]->element];
const auto& firstElement = domain.Elements()[incident[0U]->element];
const auto& secondElement = domain.Elements()[incident[1U]->element];
const bool chainOrientation =
incident[0U]->endpoint != incident[1U]->endpoint &&
((incident[0U]->endpoint == 1 && incident[1U]->endpoint == 0) ||
@@ -1074,13 +1074,13 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
const auto firstAxes = localAxes(domain, firstElement);
const auto secondAxes = localAxes(domain, secondElement);
if (!chainOrientation ||
firstElement.sectionIndex != secondElement.sectionIndex ||
firstElement.section_index != secondElement.section_index ||
!firstAxes.has_value() || !secondAxes.has_value() ||
!sameAxes(*firstAxes, *secondAxes)) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"ineligible-node-station",
domain.nodes()[nodeIndex].location,
domain.nodes()[nodeIndex].sourceId.source_label_text,
domain.Nodes()[nodeIndex].location,
domain.Nodes()[nodeIndex].source_id.source_label_text,
"Interior station endpoints require one consistent section and local-axis chain.");
}
@@ -1096,15 +1096,15 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
if (!std::isfinite(difference)) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"nonfinite-node-station-value",
domain.nodes()[nodeIndex].location,
domain.nodes()[nodeIndex].sourceId.source_label_text,
domain.Nodes()[nodeIndex].location,
domain.Nodes()[nodeIndex].source_id.source_label_text,
"Endpoint comparison must produce a finite difference.");
}
if (difference > componentTolerances[component]) {
return recoveryResultFailure<std::vector<NodeStationResultRow>>(
"node-station-tolerance-failure",
domain.nodes()[nodeIndex].location,
domain.nodes()[nodeIndex].sourceId.source_label_text,
domain.Nodes()[nodeIndex].location,
domain.Nodes()[nodeIndex].source_id.source_label_text,
"Interior endpoint resultants disagree beyond component tolerance.");
}
}
@@ -1114,7 +1114,7 @@ ResultRecovery::normalizeSectionResultantsToNodeStations(
? incident[0U]
: incident[1U];
stations.push_back({
domain.nodes()[nodeIndex].sourceId,
domain.Nodes()[nodeIndex].source_id,
representative->element,
representative->sectionResultant});
}