feat(shell-surface-pressure-load): step 5 - integrate-nonlinear-follower-pressure

This commit is contained in:
KOKO\Mimi
2026-09-01 15:48:52 +09:00
parent ecbdc7dc49
commit 9b19cc1b18
5 changed files with 580 additions and 4 deletions
@@ -15,6 +15,7 @@
#include "fesa/analysis/newton_iteration_log.h"
#include "fesa/analysis/nonlinear_static_control.h"
#include "fesa/assembly/parallel_for.h"
#include "fesa/assembly/surface_pressure_assembler.h"
#include "fesa/constraints/essential_constraint_policy.h"
#include "fesa/elements/finite_rotation.h"
#include "fesa/elements/mitc4_shell.h"
@@ -453,6 +454,76 @@ Result<SparseMatrix> Difference(const SparseMatrix& internal,
dofs.GetSparsePattern());
}
/// @brief Adds fixed and follower external candidates in stable CSR order.
Result<GlobalFixedLoadContribution> CombineExternalContributions(
const GlobalFixedLoadContribution& fixed,
const SurfacePressureAssemblyCandidate& pressure, const DofManager& dofs) {
if (fixed.generalized_external_force.Size() !=
pressure.full_external_force.Size() ||
fixed.generalized_external_tangent.Rows() !=
pressure.full_external_tangent.Rows() ||
fixed.generalized_external_tangent.Columns() !=
pressure.full_external_tangent.Columns() ||
fixed.generalized_external_tangent.RowOffsets() !=
pressure.full_external_tangent.RowOffsets() ||
fixed.generalized_external_tangent.ColumnIndices() !=
pressure.full_external_tangent.ColumnIndices()) {
return Result<GlobalFixedLoadContribution>::Failure(ProcedureFailure(
FailureCategory::kSolver, "nonfinite-newton-data", {},
"NONLINEAR_STATIC_PROCEDURE", {},
"Nonlinear fixed and pressure external candidates must share the "
"stable full-space dimension and pattern."));
}
Vector force{fixed.generalized_external_force.Size()};
for (std::size_t index = 0U; index < force.Size(); ++index) {
force[index] = fixed.generalized_external_force[index] +
pressure.full_external_force[index];
if (!std::isfinite(force[index])) {
return Result<GlobalFixedLoadContribution>::Failure(ProcedureFailure(
FailureCategory::kSolver, "nonfinite-newton-data", {},
"NONLINEAR_STATIC_PROCEDURE", std::to_string(index),
"Nonlinear fixed and pressure force composition is nonfinite."));
}
}
std::vector<CooContribution> contributions;
contributions.reserve(fixed.generalized_external_tangent.Values().size());
for (std::size_t row = 0U; row < fixed.generalized_external_tangent.Rows();
++row) {
for (std::size_t offset =
fixed.generalized_external_tangent.RowOffsets()[row];
offset < fixed.generalized_external_tangent.RowOffsets()[row + 1U];
++offset) {
const double tangent =
fixed.generalized_external_tangent.Values()[offset] +
pressure.full_external_tangent.Values()[offset];
if (!std::isfinite(tangent)) {
return Result<GlobalFixedLoadContribution>::Failure(ProcedureFailure(
FailureCategory::kSolver, "nonfinite-newton-data", {},
"NONLINEAR_STATIC_PROCEDURE", std::to_string(row),
"Nonlinear fixed and pressure tangent composition is nonfinite."));
}
contributions.push_back(
{row, fixed.generalized_external_tangent.ColumnIndices()[offset],
tangent, row, offset});
}
}
Result<SparseMatrix> tangent =
SparseMatrix::FromCoo(fixed.generalized_external_tangent.Rows(),
fixed.generalized_external_tangent.Columns(),
std::move(contributions), dofs.GetSparsePattern());
if (!tangent.HasValue()) {
return Result<GlobalFixedLoadContribution>::Failure(tangent.GetStatus());
}
std::vector<Diagnostic> diagnostics = fixed.diagnostics;
diagnostics.insert(diagnostics.end(), pressure.diagnostics.begin(),
pressure.diagnostics.end());
return Result<GlobalFixedLoadContribution>::Success(
{std::move(force), std::move(tangent.Value()), std::move(diagnostics)});
}
Vector SelectFreeComponents(const Vector& full, const DofManager& dofs,
const bool rotations) {
std::size_t count = 0U;
@@ -670,6 +741,11 @@ NonlinearStaticProcedureExecutor::Execute(
if (!dofs.HasValue()) {
return Result<NonlinearStaticExecutionResult>::Failure(dofs.GetStatus());
}
Result<AnalysisModel> analysis_model = AnalysisModel::Create(domain);
if (!analysis_model.HasValue()) {
return Result<NonlinearStaticExecutionResult>::Failure(
analysis_model.GetStatus());
}
Result<NonlinearStateBaselineInput> baseline = BuildBaseline(domain);
if (!baseline.HasValue()) {
return Result<NonlinearStaticExecutionResult>::Failure(
@@ -732,14 +808,32 @@ NonlinearStaticProcedureExecutor::Execute(
}
record.last_completed_stage = NewtonIterationStage::kInternalAssembled;
Result<GlobalFixedLoadContribution> external =
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));
return Result<NonlinearStaticExecutionResult>::Failure(
RecordFailure(log, &record, external.GetStatus(),
NewtonIterationStage::kExternalAssembled));
}
record.last_completed_stage = NewtonIterationStage::kExternalAssembled;