Integrate Refactor solver sources and dual MSVC CMake builds
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
#include "fesa/analysis/nonlinear_static_procedure.h"
|
||||
|
||||
#include "equilibrium_algorithm.h"
|
||||
#include "analysis/nonlinear_static_core.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -17,6 +21,7 @@
|
||||
#include "fesa/assembly/parallel_for.h"
|
||||
#include "fesa/assembly/surface_pressure_assembler.h"
|
||||
#include "fesa/constraints/essential_constraint_policy.h"
|
||||
#include "fesa/elements/element_capabilities.h"
|
||||
#include "fesa/elements/finite_rotation.h"
|
||||
#include "fesa/elements/mitc4_shell.h"
|
||||
#include "fesa/elements/nonlinear_mitc4_shell.h"
|
||||
@@ -25,9 +30,16 @@
|
||||
#include "fesa/properties/shell_section.h"
|
||||
#include "fesa/solvers/linear/tangent_solver.h"
|
||||
|
||||
#include "assembly/ordered_contribution_internal.h"
|
||||
#include "math/finite_values.h"
|
||||
#include "elements/shell_kernel_values.h"
|
||||
|
||||
namespace fesa {
|
||||
namespace {
|
||||
|
||||
using shell_kernel_internal::FrameMatrix;
|
||||
using math_internal::IsFinite;
|
||||
|
||||
constexpr std::size_t kDofsPerNode = 6U;
|
||||
constexpr std::size_t kTranslationsPerNode = 3U;
|
||||
constexpr std::size_t kShellDofCount = 24U;
|
||||
@@ -36,7 +48,8 @@ constexpr std::uint32_t kMaximumNewtonIterations = 100U;
|
||||
struct RuntimeShell {
|
||||
EntityIndex element_index;
|
||||
std::array<std::size_t, kShellDofCount> scatter;
|
||||
NonlinearMitc4Shell element;
|
||||
std::unique_ptr<NonlinearMitc4Shell> kernel;
|
||||
std::unique_ptr<ShellTrialElement> element;
|
||||
};
|
||||
|
||||
struct InternalAssembly {
|
||||
@@ -124,16 +137,6 @@ Status RecordFailure(NewtonIterationLogWriter& log,
|
||||
return log_status.IsOk() ? failure : log_status;
|
||||
}
|
||||
|
||||
Matrix InitialFrame(const ShellNodeInitialFrame& frame) {
|
||||
Matrix result{3U, 3U};
|
||||
for (std::size_t row = 0U; row < kTranslationsPerNode; ++row) {
|
||||
result(row, 0U) = frame.tangent_a[row];
|
||||
result(row, 1U) = frame.tangent_b[row];
|
||||
result(row, 2U) = frame.director[row];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<DofManager> BuildDofManager(const Domain& domain) {
|
||||
Result<AnalysisModel> model = AnalysisModel::Create(domain);
|
||||
if (!model.HasValue()) {
|
||||
@@ -239,9 +242,20 @@ Result<std::vector<RuntimeShell>> BuildRuntimeShells(const Domain& domain,
|
||||
return Result<std::vector<RuntimeShell>>::Failure(shell.GetStatus());
|
||||
}
|
||||
const EntityIndex element_index = static_cast<EntityIndex>(index);
|
||||
auto kernel =
|
||||
std::make_unique<NonlinearMitc4Shell>(std::move(shell.Value()));
|
||||
auto element = std::make_unique<Mitc4TrialAdapter>(
|
||||
ElementDofLayout{definition->SourceId(), definition->NodeIndices(),
|
||||
{DofComponent::kUx, DofComponent::kUy, DofComponent::kUz,
|
||||
DofComponent::kUrx, DofComponent::kUry, DofComponent::kUrz}},
|
||||
*kernel);
|
||||
auto mapped = dofs.ElementScatter(element->DofLayout());
|
||||
if (!mapped.HasValue())
|
||||
return Result<std::vector<RuntimeShell>>::Failure(mapped.GetStatus());
|
||||
std::array<std::size_t, kShellDofCount> scatter{};
|
||||
std::copy(mapped.Value().begin(), mapped.Value().end(), scatter.begin());
|
||||
shells.push_back(
|
||||
{element_index, dofs.ShellElementScatter(element_index),
|
||||
std::move(shell.Value())});
|
||||
{element_index, scatter, std::move(kernel), std::move(element)});
|
||||
}
|
||||
return Result<std::vector<RuntimeShell>>::Success(std::move(shells));
|
||||
}
|
||||
@@ -269,7 +283,7 @@ Status PopulateNodalKinematics(const Domain& domain,
|
||||
trial->generalized_coordinates[first + 4U],
|
||||
trial->generalized_coordinates[first + 5U]};
|
||||
Result<FiniteRotationState> rotation = MakeFiniteRotationState(
|
||||
phi, InitialFrame(domain.ShellNodeInitialFrames()[node]));
|
||||
phi, FrameMatrix(domain.ShellNodeInitialFrames()[node]));
|
||||
if (!rotation.HasValue()) {
|
||||
return rotation.GetStatus();
|
||||
}
|
||||
@@ -304,26 +318,6 @@ NonlinearMitc4TrialDofs ExtractElementTrial(
|
||||
return trial;
|
||||
}
|
||||
|
||||
bool IsFinite(const Vector& values) {
|
||||
for (std::size_t index = 0U; index < values.Size(); ++index) {
|
||||
if (!std::isfinite(values[index])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsFinite(const Matrix& values) {
|
||||
for (std::size_t row = 0U; row < values.Rows(); ++row) {
|
||||
for (std::size_t column = 0U; column < values.Columns(); ++column) {
|
||||
if (!std::isfinite(values(row, column))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Result<InternalAssembly> AssembleInternal(
|
||||
const std::vector<RuntimeShell>& shells, const DofManager& dofs,
|
||||
const Vector& coordinates, const ParallelFor& parallel_for) {
|
||||
@@ -332,9 +326,8 @@ Result<InternalAssembly> AssembleInternal(
|
||||
std::vector<std::optional<Status>> failures(shells.size());
|
||||
parallel_for.Execute(shells.size(), [&](const std::size_t index) {
|
||||
Result<NonlinearMitc4InternalEquilibrium> result =
|
||||
EvaluateInternalResidualAndTangent(shells[index].element,
|
||||
ExtractElementTrial(shells[index],
|
||||
coordinates));
|
||||
shells[index].element->EvaluateTrial(
|
||||
ExtractElementTrial(shells[index], coordinates));
|
||||
if (!result.HasValue()) {
|
||||
failures[index] = result.GetStatus();
|
||||
return;
|
||||
@@ -363,12 +356,9 @@ Result<InternalAssembly> AssembleInternal(
|
||||
}
|
||||
for (std::size_t row = 0U; row < kShellDofCount; ++row) {
|
||||
force[shells[index].scatter[row]] += local[index]->internal_residual[row];
|
||||
for (std::size_t column = 0U; column < kShellDofCount; ++column) {
|
||||
contributions.push_back(
|
||||
{shells[index].scatter[row], shells[index].scatter[column],
|
||||
local[index]->internal_tangent(row, column), index,
|
||||
row * kShellDofCount + column});
|
||||
}
|
||||
assembly_internal::AppendLocalMatrixRow(
|
||||
local[index]->internal_tangent, shells[index].scatter, row, index,
|
||||
contributions);
|
||||
}
|
||||
for (const NonlinearMitc4RecoveryPoint& point :
|
||||
local[index]->recovery.gauss_points) {
|
||||
@@ -573,19 +563,6 @@ Vector CurrentIncrementComponents(const Vector& current, const Vector& start,
|
||||
return SelectFreeComponents(difference, dofs, rotations);
|
||||
}
|
||||
|
||||
Vector3 SpatialMoment(const Matrix& transform,
|
||||
const std::array<double, 3>& generalized) {
|
||||
return {transform(0U, 0U) * generalized[0U] +
|
||||
transform(0U, 1U) * generalized[1U] +
|
||||
transform(0U, 2U) * generalized[2U],
|
||||
transform(1U, 0U) * generalized[0U] +
|
||||
transform(1U, 1U) * generalized[1U] +
|
||||
transform(1U, 2U) * generalized[2U],
|
||||
transform(2U, 0U) * generalized[0U] +
|
||||
transform(2U, 1U) * generalized[1U] +
|
||||
transform(2U, 2U) * generalized[2U]};
|
||||
}
|
||||
|
||||
/// @brief Computes accepted-state applied-plus-reaction balance evidence.
|
||||
Result<std::array<double, 6>> GlobalEquilibrium(
|
||||
const Domain& domain, const DofManager& dofs,
|
||||
@@ -634,7 +611,6 @@ Result<std::array<double, 6>> GlobalEquilibrium(
|
||||
constrained[first] ? trial.residual[first] : 0.0,
|
||||
constrained[first + 1U] ? trial.residual[first + 1U] : 0.0,
|
||||
constrained[first + 2U] ? trial.residual[first + 2U] : 0.0};
|
||||
const Matrix transform = InverseTransposeLeftJacobianSO3(phi);
|
||||
const std::array<double, 3> applied_generalized{
|
||||
trial.external_force[first + 3U], trial.external_force[first + 4U],
|
||||
trial.external_force[first + 5U]};
|
||||
@@ -642,9 +618,16 @@ Result<std::array<double, 6>> GlobalEquilibrium(
|
||||
constrained[first + 3U] ? trial.residual[first + 3U] : 0.0,
|
||||
constrained[first + 4U] ? trial.residual[first + 4U] : 0.0,
|
||||
constrained[first + 5U] ? trial.residual[first + 5U] : 0.0};
|
||||
const Vector3 applied_moment = SpatialMoment(transform, applied_generalized);
|
||||
const Vector3 reaction_moment =
|
||||
SpatialMoment(transform, reaction_generalized);
|
||||
const auto applied = SpatialMomentSO3(phi, Vector3(applied_generalized));
|
||||
const auto reaction = SpatialMomentSO3(phi, Vector3(reaction_generalized));
|
||||
if (!applied.HasValue() || !reaction.HasValue())
|
||||
return Result<std::array<double, 6>>::Failure(ProcedureFailure(
|
||||
FailureCategory::kSolver, "nonfinite-newton-data",
|
||||
{domain.SourcePath(), 0U}, "NONLINEAR_STATIC_PROCEDURE",
|
||||
domain.SourceContentIdentity(),
|
||||
"Nonlinear global equilibrium balance is nonfinite."));
|
||||
const Vector3 applied_moment = applied.Value();
|
||||
const Vector3 reaction_moment = reaction.Value();
|
||||
applied_force_resultant = applied_force_resultant + applied_force;
|
||||
applied_moment_resultant =
|
||||
applied_moment_resultant + position.Cross(applied_force) + applied_moment;
|
||||
@@ -694,11 +677,11 @@ Status ApplyIncrementConstraints(const StepDefinition& step,
|
||||
return Status::Ok();
|
||||
}
|
||||
|
||||
AcceptedFrameState AcceptedFrame(const NonlinearAnalysisState& state,
|
||||
AcceptedFrameState AcceptedFrame(const std::uint32_t frame_index,
|
||||
const NonlinearTrialState& trial,
|
||||
const LoadFactorIncrement& increment,
|
||||
const std::uint32_t iteration) {
|
||||
return {static_cast<std::uint32_t>(state.AcceptedFrames().size()),
|
||||
return {frame_index,
|
||||
increment.increment_index,
|
||||
increment.load_factor,
|
||||
iteration,
|
||||
@@ -728,6 +711,15 @@ NonlinearStaticProcedureExecutor::NonlinearStaticProcedureExecutor(
|
||||
Result<NonlinearStaticExecutionResult>
|
||||
NonlinearStaticProcedureExecutor::Execute(
|
||||
const Domain& domain, NewtonIterationLogWriter& log) const {
|
||||
NewtonStepAlgorithm algorithm;
|
||||
return ExecuteNonlinearStaticCore(domain, log, parallel_for_, tangent_solver_,
|
||||
algorithm);
|
||||
}
|
||||
|
||||
Result<NonlinearStaticExecutionResult> ExecuteNonlinearStaticCore(
|
||||
const Domain& domain, NewtonIterationLogWriter& log,
|
||||
const ParallelFor& parallel_for, TangentSolver& tangent_solver,
|
||||
EquilibriumAlgorithm& algorithm) {
|
||||
if (domain.Steps().Size() != 1U || !domain.Steps()[0U].IsNonlinearStatic()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(ProcedureFailure(
|
||||
FailureCategory::kInput, "invalid-nonlinear-static-data",
|
||||
@@ -782,199 +774,237 @@ NonlinearStaticProcedureExecutor::Execute(
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(constraint_status);
|
||||
}
|
||||
|
||||
for (std::uint32_t iteration = 1U; iteration <= kMaximumNewtonIterations;
|
||||
++iteration) {
|
||||
NewtonIterationLogRecord record =
|
||||
NewLogRecord(step, increment, iteration);
|
||||
trial.Value().increment_index = increment.increment_index;
|
||||
trial.Value().load_factor = increment.load_factor;
|
||||
trial.Value().is_factor_zero_baseline = false;
|
||||
struct ShellStepCandidate {
|
||||
AcceptedFrameState frame;
|
||||
NewtonIterationLogRecord record;
|
||||
};
|
||||
const auto next_frame_index =
|
||||
static_cast<std::uint32_t>(state.Value().AcceptedFrames().size());
|
||||
const auto report_failure = [&](NewtonIterationLogRecord* record,
|
||||
const Status& failure,
|
||||
NewtonIterationStage stage) {
|
||||
return RecordFailure(log, record, failure, stage);
|
||||
};
|
||||
const auto write_iteration = [&](const NewtonIterationLogRecord& record) {
|
||||
return WriteAndFlush(log, record);
|
||||
};
|
||||
ShellFullNewtonStep<ShellStepCandidate> iteration_step(
|
||||
[&](std::uint32_t iteration)
|
||||
-> Result<std::optional<ShellStepCandidate>> {
|
||||
NewtonIterationLogRecord record =
|
||||
NewLogRecord(step, increment, iteration);
|
||||
trial.Value().increment_index = increment.increment_index;
|
||||
trial.Value().load_factor = increment.load_factor;
|
||||
trial.Value().is_factor_zero_baseline = false;
|
||||
|
||||
Status kinematics = PopulateNodalKinematics(domain, &trial.Value());
|
||||
if (!kinematics.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(
|
||||
RecordFailure(log, &record, kinematics,
|
||||
NewtonIterationStage::kKinematicsEvaluated));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kKinematicsEvaluated;
|
||||
Status kinematics = PopulateNodalKinematics(domain, &trial.Value());
|
||||
if (!kinematics.IsOk()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, kinematics,
|
||||
NewtonIterationStage::kKinematicsEvaluated));
|
||||
}
|
||||
record.last_completed_stage =
|
||||
NewtonIterationStage::kKinematicsEvaluated;
|
||||
|
||||
Result<InternalAssembly> internal = AssembleInternal(
|
||||
shells.Value(), dofs.Value(), trial.Value().generalized_coordinates,
|
||||
parallel_for_);
|
||||
if (!internal.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, internal.GetStatus(),
|
||||
NewtonIterationStage::kInternalAssembled));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kInternalAssembled;
|
||||
Result<InternalAssembly> internal = AssembleInternal(
|
||||
shells.Value(), dofs.Value(),
|
||||
trial.Value().generalized_coordinates, parallel_for);
|
||||
if (!internal.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, internal.GetStatus(),
|
||||
NewtonIterationStage::kInternalAssembled));
|
||||
}
|
||||
record.last_completed_stage =
|
||||
NewtonIterationStage::kInternalAssembled;
|
||||
|
||||
Result<GlobalFixedLoadContribution> fixed =
|
||||
AssembleGlobalFixedLoadContribution(
|
||||
domain, dofs.Value(), trial.Value().generalized_coordinates,
|
||||
increment.load_factor);
|
||||
if (!fixed.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(
|
||||
RecordFailure(log, &record, fixed.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
Result<SurfacePressureAssemblyCandidate> pressure =
|
||||
AssembleSurfacePressure(
|
||||
analysis_model.Value(), dofs.Value(),
|
||||
trial.Value().generalized_coordinates, increment.load_factor,
|
||||
SurfacePressureConfiguration::kCurrent, parallel_for_);
|
||||
if (!pressure.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(
|
||||
RecordFailure(log, &record, pressure.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
Result<GlobalFixedLoadContribution> external =
|
||||
CombineExternalContributions(fixed.Value(), pressure.Value(),
|
||||
dofs.Value());
|
||||
if (!external.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(
|
||||
RecordFailure(log, &record, external.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kExternalAssembled;
|
||||
Result<GlobalFixedLoadContribution> fixed =
|
||||
AssembleGlobalFixedLoadContribution(
|
||||
domain, dofs.Value(), trial.Value().generalized_coordinates,
|
||||
increment.load_factor);
|
||||
if (!fixed.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, fixed.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
Result<SurfacePressureAssemblyCandidate> pressure =
|
||||
AssembleSurfacePressure(
|
||||
analysis_model.Value(), dofs.Value(),
|
||||
trial.Value().generalized_coordinates, increment.load_factor,
|
||||
SurfacePressureConfiguration::kCurrent, parallel_for);
|
||||
if (!pressure.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, pressure.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
Result<GlobalFixedLoadContribution> external =
|
||||
CombineExternalContributions(fixed.Value(), pressure.Value(),
|
||||
dofs.Value());
|
||||
if (!external.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, external.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
record.last_completed_stage =
|
||||
NewtonIterationStage::kExternalAssembled;
|
||||
|
||||
Result<Vector> residual =
|
||||
Difference(internal.Value().force,
|
||||
external.Value().generalized_external_force);
|
||||
if (!residual.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, residual.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
Result<SparseMatrix> tangent =
|
||||
Difference(internal.Value().tangent,
|
||||
external.Value().generalized_external_tangent,
|
||||
dofs.Value());
|
||||
if (!tangent.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, tangent.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
trial.Value().internal_force = std::move(internal.Value().force);
|
||||
trial.Value().external_force =
|
||||
std::move(external.Value().generalized_external_force);
|
||||
trial.Value().residual = std::move(residual.Value());
|
||||
trial.Value().reaction = trial.Value().residual;
|
||||
trial.Value().shell_results = std::move(internal.Value().shell_rows);
|
||||
trial.Value().physical_strain_energy =
|
||||
internal.Value().physical_strain_energy;
|
||||
Result<std::array<double, 6>> global_equilibrium =
|
||||
GlobalEquilibrium(domain, dofs.Value(), trial.Value());
|
||||
if (!global_equilibrium.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, global_equilibrium.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
trial.Value().global_equilibrium = global_equilibrium.Value();
|
||||
Result<Vector> residual =
|
||||
Difference(internal.Value().force,
|
||||
external.Value().generalized_external_force);
|
||||
if (!residual.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, residual.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
Result<SparseMatrix> tangent = Difference(
|
||||
internal.Value().tangent,
|
||||
external.Value().generalized_external_tangent, dofs.Value());
|
||||
if (!tangent.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, tangent.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
trial.Value().internal_force = std::move(internal.Value().force);
|
||||
trial.Value().external_force =
|
||||
std::move(external.Value().generalized_external_force);
|
||||
trial.Value().residual = std::move(residual.Value());
|
||||
trial.Value().reaction = trial.Value().residual;
|
||||
trial.Value().shell_results = std::move(internal.Value().shell_rows);
|
||||
trial.Value().physical_strain_energy =
|
||||
internal.Value().physical_strain_energy;
|
||||
Result<std::array<double, 6>> global_equilibrium =
|
||||
GlobalEquilibrium(domain, dofs.Value(), trial.Value());
|
||||
if (!global_equilibrium.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, global_equilibrium.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
trial.Value().global_equilibrium = global_equilibrium.Value();
|
||||
|
||||
Result<PartitionedStiffness> partition =
|
||||
constraints.Partition(tangent.Value(), dofs.Value());
|
||||
if (!partition.HasValue()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, partition.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
const Status factorization = tangent_solver_.FactorizeFresh(
|
||||
partition.Value().k_ff);
|
||||
if (!factorization.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, factorization,
|
||||
NewtonIterationStage::kSolvedCorrection));
|
||||
}
|
||||
Result<PartitionedStiffness> partition =
|
||||
constraints.Partition(tangent.Value(), dofs.Value());
|
||||
if (!partition.HasValue()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, partition.GetStatus(),
|
||||
NewtonIterationStage::kExternalAssembled));
|
||||
}
|
||||
const Status factorization =
|
||||
tangent_solver.FactorizeFresh(partition.Value().k_ff);
|
||||
if (!factorization.IsOk()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, factorization,
|
||||
NewtonIterationStage::kSolvedCorrection));
|
||||
}
|
||||
|
||||
Vector correction_rhs = constraints.GatherFree(trial.Value().residual,
|
||||
dofs.Value());
|
||||
for (std::size_t index = 0U; index < correction_rhs.Size(); ++index) {
|
||||
correction_rhs[index] = -correction_rhs[index];
|
||||
}
|
||||
Vector correction{dofs.Value().FreeDofCount()};
|
||||
const Status solve =
|
||||
tangent_solver_.SolveCorrection(correction_rhs, correction);
|
||||
if (!solve.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, solve, NewtonIterationStage::kSolvedCorrection));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kSolvedCorrection;
|
||||
Vector correction_rhs =
|
||||
constraints.GatherFree(trial.Value().residual, dofs.Value());
|
||||
for (std::size_t index = 0U; index < correction_rhs.Size(); ++index) {
|
||||
correction_rhs[index] = -correction_rhs[index];
|
||||
}
|
||||
Vector correction{dofs.Value().FreeDofCount()};
|
||||
const Status solve =
|
||||
tangent_solver.SolveCorrection(correction_rhs, correction);
|
||||
if (!solve.IsOk()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, solve,
|
||||
NewtonIterationStage::kSolvedCorrection));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kSolvedCorrection;
|
||||
|
||||
const NewtonConvergenceResult convergence = EvaluateNewtonConvergence({
|
||||
{"residual_force", SelectFreeComponents(trial.Value().residual,
|
||||
dofs.Value(), false),
|
||||
SelectFreeComponents(trial.Value().internal_force, dofs.Value(),
|
||||
false),
|
||||
SelectFreeComponents(trial.Value().external_force, dofs.Value(),
|
||||
false)},
|
||||
{"residual_moment", SelectFreeComponents(trial.Value().residual,
|
||||
dofs.Value(), true),
|
||||
SelectFreeComponents(trial.Value().internal_force, dofs.Value(),
|
||||
true),
|
||||
SelectFreeComponents(trial.Value().external_force, dofs.Value(),
|
||||
true)},
|
||||
{"correction_translation",
|
||||
SelectCorrectionComponents(correction, dofs.Value(), false),
|
||||
CurrentIncrementComponents(trial.Value().generalized_coordinates,
|
||||
increment_start, dofs.Value(), false)},
|
||||
{"correction_rotation",
|
||||
SelectCorrectionComponents(correction, dofs.Value(), true),
|
||||
CurrentIncrementComponents(trial.Value().generalized_coordinates,
|
||||
increment_start, dofs.Value(), true)}});
|
||||
record.force_residual = convergence.force_residual;
|
||||
record.moment_residual = convergence.moment_residual;
|
||||
record.translation_correction = convergence.translation_correction;
|
||||
record.rotation_correction = convergence.rotation_correction;
|
||||
record.combined_passed = convergence.combined_passed;
|
||||
record.last_completed_stage = NewtonIterationStage::kConvergenceEvaluated;
|
||||
const NewtonConvergenceResult convergence = EvaluateNewtonConvergence(
|
||||
{{"residual_force",
|
||||
SelectFreeComponents(trial.Value().residual, dofs.Value(),
|
||||
false),
|
||||
SelectFreeComponents(trial.Value().internal_force, dofs.Value(),
|
||||
false),
|
||||
SelectFreeComponents(trial.Value().external_force, dofs.Value(),
|
||||
false)},
|
||||
{"residual_moment",
|
||||
SelectFreeComponents(trial.Value().residual, dofs.Value(),
|
||||
true),
|
||||
SelectFreeComponents(trial.Value().internal_force, dofs.Value(),
|
||||
true),
|
||||
SelectFreeComponents(trial.Value().external_force, dofs.Value(),
|
||||
true)},
|
||||
{"correction_translation",
|
||||
SelectCorrectionComponents(correction, dofs.Value(), false),
|
||||
CurrentIncrementComponents(
|
||||
trial.Value().generalized_coordinates, increment_start,
|
||||
dofs.Value(), false)},
|
||||
{"correction_rotation",
|
||||
SelectCorrectionComponents(correction, dofs.Value(), true),
|
||||
CurrentIncrementComponents(
|
||||
trial.Value().generalized_coordinates, increment_start,
|
||||
dofs.Value(), true)}});
|
||||
record.force_residual = convergence.force_residual;
|
||||
record.moment_residual = convergence.moment_residual;
|
||||
record.translation_correction = convergence.translation_correction;
|
||||
record.rotation_correction = convergence.rotation_correction;
|
||||
record.combined_passed = convergence.combined_passed;
|
||||
record.last_completed_stage =
|
||||
NewtonIterationStage::kConvergenceEvaluated;
|
||||
|
||||
if (convergence.combined_passed) {
|
||||
const Status committed = state.Value().CommitAcceptedFrame(
|
||||
AcceptedFrame(state.Value(), trial.Value(), increment, iteration));
|
||||
if (!committed.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, committed, NewtonIterationStage::kAccepted));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kAccepted;
|
||||
record.transition = "accepted";
|
||||
record.outcome = "accepted";
|
||||
const Status log_status = WriteAndFlush(log, record);
|
||||
if (!log_status.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(log_status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (convergence.combined_passed) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Success(
|
||||
ShellStepCandidate{AcceptedFrame(next_frame_index,
|
||||
trial.Value(), increment,
|
||||
iteration),
|
||||
record});
|
||||
}
|
||||
|
||||
if (iteration == kMaximumNewtonIterations) {
|
||||
const Status failure = ProcedureFailure(
|
||||
FailureCategory::kSolver, "nonlinear-nonconvergence",
|
||||
step.Location(), "STATIC", step.Name(),
|
||||
"The nonlinear procedure did not converge within 100 iterations.");
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, failure,
|
||||
NewtonIterationStage::kConvergenceEvaluated));
|
||||
}
|
||||
if (iteration == kMaximumNewtonIterations) {
|
||||
const Status failure = ProcedureFailure(
|
||||
FailureCategory::kSolver, "nonlinear-nonconvergence",
|
||||
step.Location(), "STATIC", step.Name(),
|
||||
"The nonlinear procedure did not converge within 100 "
|
||||
"iterations.");
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, failure,
|
||||
NewtonIterationStage::kConvergenceEvaluated));
|
||||
}
|
||||
|
||||
for (std::size_t equation = 0U; equation < dofs.Value().FreeDofs().size();
|
||||
++equation) {
|
||||
const std::size_t full_dof = dofs.Value().FreeDofs()[equation];
|
||||
trial.Value().generalized_coordinates[full_dof] += correction[equation];
|
||||
if (!std::isfinite(trial.Value().generalized_coordinates[full_dof])) {
|
||||
const Status failure = ProcedureFailure(
|
||||
FailureCategory::kSolver, "nonfinite-newton-data", {},
|
||||
"NONLINEAR_STATIC_PROCEDURE", std::to_string(full_dof),
|
||||
"A nonlinear free-coordinate correction is nonfinite.");
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, failure, NewtonIterationStage::kSolvedCorrection));
|
||||
}
|
||||
}
|
||||
record.transition = "continue";
|
||||
record.outcome = "not-converged";
|
||||
const Status log_status = WriteAndFlush(log, record);
|
||||
if (!log_status.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(log_status);
|
||||
}
|
||||
for (std::size_t equation = 0U;
|
||||
equation < dofs.Value().FreeDofs().size(); ++equation) {
|
||||
const std::size_t full_dof = dofs.Value().FreeDofs()[equation];
|
||||
trial.Value().generalized_coordinates[full_dof] +=
|
||||
correction[equation];
|
||||
if (!std::isfinite(
|
||||
trial.Value().generalized_coordinates[full_dof])) {
|
||||
const Status failure = ProcedureFailure(
|
||||
FailureCategory::kSolver, "nonfinite-newton-data", {},
|
||||
"NONLINEAR_STATIC_PROCEDURE", std::to_string(full_dof),
|
||||
"A nonlinear free-coordinate correction is nonfinite.");
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
report_failure(&record, failure,
|
||||
NewtonIterationStage::kSolvedCorrection));
|
||||
}
|
||||
}
|
||||
record.transition = "continue";
|
||||
record.outcome = "not-converged";
|
||||
const Status log_status = write_iteration(record);
|
||||
if (!log_status.IsOk()) {
|
||||
return Result<std::optional<ShellStepCandidate>>::Failure(
|
||||
log_status);
|
||||
}
|
||||
return Result<std::optional<ShellStepCandidate>>::Success(
|
||||
std::nullopt);
|
||||
},
|
||||
kMaximumNewtonIterations);
|
||||
const Status solved = iteration_step.Solve(algorithm);
|
||||
if (!solved.IsOk())
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(solved);
|
||||
auto candidate = iteration_step.TakeCandidate();
|
||||
auto& record = candidate.record;
|
||||
const Status committed = state.Value().CommitAcceptedFrame(candidate.frame);
|
||||
if (!committed.IsOk()) {
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(RecordFailure(
|
||||
log, &record, committed, NewtonIterationStage::kAccepted));
|
||||
}
|
||||
record.last_completed_stage = NewtonIterationStage::kAccepted;
|
||||
record.transition = "accepted";
|
||||
record.outcome = "accepted";
|
||||
const Status log_status = WriteAndFlush(log, record);
|
||||
if (!log_status.IsOk())
|
||||
return Result<NonlinearStaticExecutionResult>::Failure(log_status);
|
||||
}
|
||||
|
||||
std::vector<Diagnostic> diagnostics = domain.Warnings();
|
||||
@@ -983,4 +1013,4 @@ NonlinearStaticProcedureExecutor::Execute(
|
||||
{std::move(state.Value()), std::move(diagnostics)});
|
||||
}
|
||||
|
||||
} // namespace fesa
|
||||
} // namespace fesa
|
||||
|
||||
Reference in New Issue
Block a user