Integrate Refactor solver sources and dual MSVC CMake builds

This commit is contained in:
KOKO\Mimi
2026-10-18 02:10:51 +09:00
parent 7ee32e5837
commit 12d51480de
218 changed files with 17842 additions and 9689 deletions
+138 -90
View File
@@ -1,5 +1,8 @@
#include "fesa/analysis/solid_static_procedure.h"
#include "equilibrium_algorithm.h"
#include "analysis/solid_static_core.h"
#include <algorithm>
#include <array>
#include <cmath>
@@ -21,6 +24,8 @@
#include "fesa/solvers/linear/linear_solver.h"
#include "fesa/solvers/linear/tangent_solver.h"
#include "assembly/ordered_contribution_internal.h"
namespace fesa {
namespace {
constexpr std::uint32_t kMaximumIterations = 100U;
@@ -28,7 +33,7 @@ constexpr double kRoundoffBudget =
512.0 * std::numeric_limits<double>::epsilon();
struct RuntimeSolid {
const Hex8Element* element;
std::unique_ptr<SolidTrialElement> element;
std::vector<std::size_t> scatter;
};
struct SolidAssembly {
@@ -131,9 +136,8 @@ Result<SolidAssembly> Assemble(const std::vector<RuntimeSolid>& solids,
const auto& response = responses[e]->Value();
for (std::size_t i = 0U; i < 24U; ++i) {
force[solids[e].scatter[i]] += response.internal_force[i];
for (std::size_t j = 0U; j < 24U; ++j)
contributions.push_back({solids[e].scatter[i], solids[e].scatter[j],
response.tangent(i, j), e, 24U * i + j});
assembly_internal::AppendLocalMatrixRow(
response.tangent, solids[e].scatter, i, e, contributions);
}
energy += response.strain_energy;
points.insert(points.end(), response.points.begin(), response.points.end());
@@ -283,6 +287,13 @@ SolidStaticProcedureExecutor::SolidStaticProcedureExecutor(
Status SolidStaticProcedureExecutor::ExecuteInto(
const Domain& domain, SolidStaticState& state) const {
NewtonStepAlgorithm algorithm;
return SolidStaticCore(parallel_for_, linear_solver_, tangent_solver_, algorithm)
.ExecuteInto(domain, state);
}
Status SolidStaticCore::ExecuteInto(
const Domain& domain, SolidStaticState& state) const {
if (state.initialized_)
return Failure(domain, "solid-static-observer-not-fresh",
"Execution requires a fresh static observer.");
@@ -309,14 +320,14 @@ Status SolidStaticProcedureExecutor::ExecuteInto(
state = std::move(baseline.Value());
std::vector<RuntimeSolid> solids;
for (const auto& element : elements) {
const auto* hex = dynamic_cast<const Hex8Element*>(element.get());
auto hex = ElementFactory{}.BindSolidTrial(*element);
if (hex == nullptr)
return Failure(domain, "invalid-solid-static-element",
"Solid STATIC requires full-integration Hex8 kernels.",
FailureCategory::kModel);
auto scatter = dofs.ElementScatter(hex->DofLayout());
if (!scatter.HasValue()) return scatter.GetStatus();
solids.push_back({hex, std::move(scatter.Value())});
solids.push_back({std::move(hex), std::move(scatter.Value())});
}
auto stiffness = SparseAssembler::Assemble(view, dofs, parallel_for_);
if (!stiffness.HasValue()) return stiffness.GetStatus();
@@ -336,7 +347,7 @@ Status SolidStaticProcedureExecutor::ExecuteInto(
// Preserve the required factorization-before-load-assembly lifecycle.
auto load = LoadAssembler::AssembleFullNodalLoad(model.Value(), dofs);
if (!load.HasValue()) return load.GetStatus();
auto rhs = LoadAssembler::EffectiveFreeRhs(
auto rhs = constraints.EffectiveFreeRhs(
load.Value(), partition.Value().k_fc, dofs.PrescribedValues(), dofs);
if (!rhs.HasValue()) return rhs.GetStatus();
Vector free{dofs.FreeDofCount()};
@@ -369,91 +380,128 @@ Status SolidStaticProcedureExecutor::ExecuteInto(
for (std::size_t c = 0U; c < dofs.ConstrainedDofCount(); ++c)
trial[dofs.ConstrainedDofs()[c]] =
increment.load_factor * dofs.PrescribedValues()[c];
for (std::uint32_t iteration = 1U; iteration <= kMaximumIterations;
++iteration) {
struct SolidStepCandidate {
SolidStaticFrame frame;
SolidStaticIterationRecord record;
record.increment_index = increment.increment_index;
record.load_factor = increment.load_factor;
record.iteration = iteration;
record.stage = "entered";
const auto fail = [&](const Status& failure) {
record.diagnostic_code = failure.Diagnostics().empty()
? "solid-static-failure"
: failure.Diagnostics()[0].code;
record.failure_reason = failure.Diagnostics().empty()
? "Static trial failed."
: failure.Diagnostics()[0].message;
state.iterations_.push_back(record);
return failure;
};
record.stage = "trial-recovery";
auto assembly = Assemble(solids, dofs, trial, true, parallel_for_);
if (!assembly.HasValue()) return fail(assembly.GetStatus());
SolidStaticFrame frame = state.committed_;
frame.balance = {};
frame.global_equilibrium = {};
frame.frame_index =
static_cast<std::uint32_t>(state.accepted_frames_.size());
frame.increment_index = increment.increment_index;
frame.load_factor = increment.load_factor;
frame.iteration_count = iteration;
frame.is_factor_one = increment.is_factor_one;
frame.displacement = trial;
frame.internal_force = std::move(assembly.Value().force);
frame.external_force = base_load.Value();
frame.external_force.Scale(increment.load_factor);
frame.solid_results = std::move(assembly.Value().points);
frame.physical_strain_energy = assembly.Value().energy;
auto status = CompleteFrame(domain, dofs, true, stiffness.Value(), frame);
if (!status.IsOk()) return fail(status);
record.stage = "tangent-partition";
auto partition = constraints.Partition(assembly.Value().tangent, dofs);
if (!partition.HasValue()) return fail(partition.GetStatus());
Vector correction{dofs.FreeDofCount()};
// Empty free is vacuous; prescribed geometry/recovery above still runs.
if (dofs.FreeDofCount() != 0U) {
record.stage = "tangent-factorization";
status = tangent_solver_.FactorizeFresh(partition.Value().k_ff);
if (!status.IsOk()) return fail(status);
auto rhs = constraints.GatherFree(frame.residual, dofs);
rhs.Scale(-1.0);
record.stage = "correction-solve";
status = tangent_solver_.SolveCorrection(rhs, correction);
if (!status.IsOk()) return fail(status);
}
Vector current_increment{dofs.FreeDofCount()};
for (std::size_t f = 0U; f < dofs.FreeDofCount(); ++f) {
const auto full = dofs.FreeDofs()[f];
current_increment[f] = trial[full] - start[full];
}
record.stage = "convergence";
auto convergence = EvaluateSolidStaticConvergence(
constraints.GatherFree(frame.residual, dofs),
constraints.GatherFree(frame.internal_force, dofs),
constraints.GatherFree(frame.external_force, dofs), correction,
current_increment);
if (!convergence.HasValue()) return fail(convergence.GetStatus());
record.force_residual = convergence.Value().force_residual;
record.translation_correction =
convergence.Value().translation_correction;
record.convergence_evaluated = true;
if (record.force_residual.passed &&
record.translation_correction.passed) {
record.stage = "commit";
status = state.CommitAcceptedFrame(frame);
if (!status.IsOk()) return fail(status);
record.accepted = true;
state.iterations_.push_back(record);
break;
}
if (iteration == kMaximumIterations)
return fail(Failure(domain, "solid-static-nonconvergence",
"Solid STATIC exceeded 100 Newton iterations."));
for (std::size_t f = 0U; f < dofs.FreeDofCount(); ++f)
trial[dofs.FreeDofs()[f]] += correction[f];
record.stage = "continue";
state.iterations_.push_back(record);
};
const auto observe_iteration =
[&](const SolidStaticIterationRecord& record) {
state.iterations_.push_back(record);
};
SolidFullNewtonStep<SolidStepCandidate> iteration_step(
[&](std::uint32_t iteration)
-> Result<std::optional<SolidStepCandidate>> {
SolidStaticIterationRecord record;
record.increment_index = increment.increment_index;
record.load_factor = increment.load_factor;
record.iteration = iteration;
record.stage = "entered";
const auto fail = [&](const Status& failure) {
record.diagnostic_code = failure.Diagnostics().empty()
? "solid-static-failure"
: failure.Diagnostics()[0].code;
record.failure_reason = failure.Diagnostics().empty()
? "Static trial failed."
: failure.Diagnostics()[0].message;
observe_iteration(record);
return Result<std::optional<SolidStepCandidate>>::Failure(failure);
};
record.stage = "trial-recovery";
auto assembly = Assemble(solids, dofs, trial, true, parallel_for_);
if (!assembly.HasValue())
return fail(assembly.GetStatus());
SolidStaticFrame frame = state.committed_;
frame.balance = {};
frame.global_equilibrium = {};
frame.frame_index =
static_cast<std::uint32_t>(state.accepted_frames_.size());
frame.increment_index = increment.increment_index;
frame.load_factor = increment.load_factor;
frame.iteration_count = iteration;
frame.is_factor_one = increment.is_factor_one;
frame.displacement = trial;
frame.internal_force = std::move(assembly.Value().force);
frame.external_force = base_load.Value();
frame.external_force.Scale(increment.load_factor);
frame.solid_results = std::move(assembly.Value().points);
frame.physical_strain_energy = assembly.Value().energy;
auto status =
CompleteFrame(domain, dofs, true, stiffness.Value(), frame);
if (!status.IsOk())
return fail(status);
record.stage = "tangent-partition";
auto partition =
constraints.Partition(assembly.Value().tangent, dofs);
if (!partition.HasValue())
return fail(partition.GetStatus());
Vector correction{dofs.FreeDofCount()};
// Empty free is vacuous; prescribed geometry/recovery above still
// runs.
if (dofs.FreeDofCount() != 0U) {
record.stage = "tangent-factorization";
status = tangent_solver_.FactorizeFresh(partition.Value().k_ff);
if (!status.IsOk())
return fail(status);
auto rhs = constraints.GatherFree(frame.residual, dofs);
rhs.Scale(-1.0);
record.stage = "correction-solve";
status = tangent_solver_.SolveCorrection(rhs, correction);
if (!status.IsOk())
return fail(status);
}
Vector current_increment{dofs.FreeDofCount()};
for (std::size_t f = 0U; f < dofs.FreeDofCount(); ++f) {
const auto full = dofs.FreeDofs()[f];
current_increment[f] = trial[full] - start[full];
}
record.stage = "convergence";
auto convergence = EvaluateSolidStaticConvergence(
constraints.GatherFree(frame.residual, dofs),
constraints.GatherFree(frame.internal_force, dofs),
constraints.GatherFree(frame.external_force, dofs), correction,
current_increment);
if (!convergence.HasValue())
return fail(convergence.GetStatus());
record.force_residual = convergence.Value().force_residual;
record.translation_correction =
convergence.Value().translation_correction;
record.convergence_evaluated = true;
if (record.force_residual.passed &&
record.translation_correction.passed) {
record.stage = "commit";
return Result<std::optional<SolidStepCandidate>>::Success(
SolidStepCandidate{std::move(frame), record});
}
if (iteration == kMaximumIterations)
return fail(
Failure(domain, "solid-static-nonconvergence",
"Solid STATIC exceeded 100 Newton iterations."));
for (std::size_t f = 0U; f < dofs.FreeDofCount(); ++f)
trial[dofs.FreeDofs()[f]] += correction[f];
record.stage = "continue";
observe_iteration(record);
return Result<std::optional<SolidStepCandidate>>::Success(
std::nullopt);
},
kMaximumIterations);
const Status solved = iteration_step.Solve(algorithm_);
if (!solved.IsOk())
return solved;
auto candidate = iteration_step.TakeCandidate();
auto& record = candidate.record;
const Status committed = state.CommitAcceptedFrame(candidate.frame);
if (!committed.IsOk()) {
record.diagnostic_code = committed.Diagnostics().empty()
? "solid-static-failure"
: committed.Diagnostics()[0].code;
record.failure_reason = committed.Diagnostics().empty()
? "Static trial failed."
: committed.Diagnostics()[0].message;
observe_iteration(record);
return committed;
}
record.accepted = true;
observe_iteration(record);
}
return Status::Ok();
}