Integrate Refactor solver sources and dual MSVC CMake builds
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
#include "fesa/analysis/solid_hht_dynamic_procedure.h"
|
||||
|
||||
#include "equilibrium_algorithm.h"
|
||||
#include "analysis/solid_hht_core.h"
|
||||
#include "solid_hht_integrator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
@@ -85,7 +89,7 @@ Status CheckArithmeticEnvironment(const Domain& domain) {
|
||||
/// @brief Owns immutable kernels and the stable full-space translation scatter.
|
||||
struct RuntimeSolid {
|
||||
std::unique_ptr<Element> owner;
|
||||
const Hex8Element* solid;
|
||||
std::unique_ptr<SolidTrialElement> solid;
|
||||
std::vector<std::size_t> scatter;
|
||||
};
|
||||
/// @brief Creates checked kernels in declaration order, with no mutable element
|
||||
@@ -98,7 +102,7 @@ Result<std::vector<RuntimeSolid>> BuildSolids(const Domain& domain,
|
||||
auto owner = factory.Create(domain.Elements()[e], domain);
|
||||
if (!owner.HasValue())
|
||||
return Result<std::vector<RuntimeSolid>>::Failure(owner.GetStatus());
|
||||
const auto* solid = dynamic_cast<const Hex8Element*>(owner.Value().get());
|
||||
auto solid = factory.BindSolidTrial(*owner.Value());
|
||||
if (solid == nullptr)
|
||||
return Result<std::vector<RuntimeSolid>>::Failure(
|
||||
Failure(domain, "solid-dynamic-element-family",
|
||||
@@ -107,7 +111,7 @@ Result<std::vector<RuntimeSolid>> BuildSolids(const Domain& domain,
|
||||
if (!scatter.HasValue())
|
||||
return Result<std::vector<RuntimeSolid>>::Failure(scatter.GetStatus());
|
||||
solids.push_back(
|
||||
{std::move(owner.Value()), solid, std::move(scatter.Value())});
|
||||
{std::move(owner.Value()), std::move(solid), std::move(scatter.Value())});
|
||||
}
|
||||
return Result<std::vector<RuntimeSolid>>::Success(std::move(solids));
|
||||
}
|
||||
@@ -239,7 +243,7 @@ Result<double> ReferenceLength(const Domain& domain) {
|
||||
"Reference length is not finite positive."));
|
||||
return Result<double>::Success(length);
|
||||
}
|
||||
/// @brief Forms M/(beta*h²)+(1+alpha)*Kt in the unchanged full sparse pattern.
|
||||
/// @brief Forms M/(beta*h^2)+(1+alpha)*Kt in the unchanged full sparse pattern.
|
||||
Result<SparseMatrix> EffectiveTangent(const SparseMatrix& m,
|
||||
const PairedTangent& k,
|
||||
const DofManager& dofs, double h,
|
||||
@@ -549,24 +553,6 @@ bool CorrectionPass(const std::array<HighLow, 4>& metrics) {
|
||||
Compare(x, HighLow(1e-10)) <= 0;
|
||||
});
|
||||
}
|
||||
Status SetRates(const SolidDynamicAcceptedFrameState& old,
|
||||
const detail::SolidHhtPairedPredictor& predictor, double h,
|
||||
const HhtParameters& p,
|
||||
SolidDynamicAcceptedFrameState* candidate) {
|
||||
auto rates = detail::EvaluateSolidHhtHighLowRates(
|
||||
candidate->displacement, candidate->low.displacement, predictor,
|
||||
old.acceleration, old.low.acceleration, h, p);
|
||||
if (!rates.HasValue()) return rates.GetStatus();
|
||||
candidate->velocity = std::move(rates.Value().velocity);
|
||||
candidate->low.velocity = std::move(rates.Value().velocity_low);
|
||||
candidate->acceleration = std::move(rates.Value().acceleration);
|
||||
candidate->low.acceleration = std::move(rates.Value().acceleration_low);
|
||||
candidate->algorithmic_acceleration =
|
||||
std::move(rates.Value().algorithmic_acceleration);
|
||||
candidate->low.algorithmic_acceleration =
|
||||
std::move(rates.Value().algorithmic_acceleration_low);
|
||||
return Status::Ok();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SolidHhtDynamicProcedureExecutor::SolidHhtDynamicProcedureExecutor(
|
||||
@@ -600,6 +586,17 @@ Status SolidHhtDynamicProcedureExecutor::ExecuteInto(
|
||||
Status SolidHhtDynamicProcedureExecutor::ExecuteIntoForVerification(
|
||||
const Domain& domain, SolidDynamicAnalysisState& state,
|
||||
double alpha) const {
|
||||
const detail::PairedSolidHhtIntegrator integrator;
|
||||
NewtonStepAlgorithm algorithm;
|
||||
return ExecuteSolidHhtCore(domain, state, alpha, parallel_for_, mass_solver_,
|
||||
tangent_solver_, integrator, algorithm);
|
||||
}
|
||||
|
||||
Status ExecuteSolidHhtCore(
|
||||
const Domain& domain, SolidDynamicAnalysisState& state, double alpha,
|
||||
const ParallelFor& parallel_for, LinearSolver& mass_solver,
|
||||
TangentSolver& tangent_solver, const detail::SolidHhtIntegrator& integrator,
|
||||
EquilibriumAlgorithm& algorithm) {
|
||||
SolidDynamicIterationRecord record;
|
||||
auto fail = [&](const Status& failure) {
|
||||
record.stage = "failed";
|
||||
@@ -630,7 +627,7 @@ Status SolidHhtDynamicProcedureExecutor::ExecuteIntoForVerification(
|
||||
auto mass_partition = partition.Partition(mass.Value(), dofs);
|
||||
if (!mass_partition.HasValue()) return fail(mass_partition.GetStatus());
|
||||
if (dofs.FreeDofCount() != 0) {
|
||||
const auto status = mass_solver_.Factorize(mass_partition.Value().k_ff);
|
||||
const auto status = mass_solver.Factorize(mass_partition.Value().k_ff);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
environment = CheckArithmeticEnvironment(domain);
|
||||
if (!environment.IsOk()) return fail(environment);
|
||||
@@ -655,7 +652,7 @@ Status SolidHhtDynamicProcedureExecutor::ExecuteIntoForVerification(
|
||||
if (!force.HasValue()) return fail(force.GetStatus());
|
||||
initial.external_force = std::move(force.Value());
|
||||
auto tangent =
|
||||
EvaluateSolids(domain, solids.Value(), dofs, parallel_for_, &initial);
|
||||
EvaluateSolids(domain, solids.Value(), dofs, parallel_for, &initial);
|
||||
if (!tangent.HasValue()) return fail(tangent.GetStatus());
|
||||
SolidDynamicIterationEvidence evidence;
|
||||
bool initial_converged = false;
|
||||
@@ -682,7 +679,7 @@ Status SolidHhtDynamicProcedureExecutor::ExecuteIntoForVerification(
|
||||
const auto i = dofs.FreeDofs()[j];
|
||||
rhs[j] = Rounded(Negate(Pair(initial.residual, initial.low.residual, i)));
|
||||
}
|
||||
status = mass_solver_.Solve(rhs, a);
|
||||
status = mass_solver.Solve(rhs, a);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
environment = CheckArithmeticEnvironment(domain);
|
||||
if (!environment.IsOk()) return fail(environment);
|
||||
@@ -726,145 +723,188 @@ Status SolidHhtDynamicProcedureExecutor::ExecuteIntoForVerification(
|
||||
record = {};
|
||||
record.increment_index = increment;
|
||||
record.time = static_cast<double>(increment) * h;
|
||||
auto predictor = detail::PredictSolidHhtHighLow(old, h, p);
|
||||
if (!predictor.HasValue()) return fail(predictor.GetStatus());
|
||||
auto candidate = old;
|
||||
candidate.frame_index = candidate.increment_index = increment;
|
||||
candidate.iteration_count = 0;
|
||||
candidate.time = record.time;
|
||||
candidate.is_initial = false;
|
||||
candidate.iterations.clear();
|
||||
// Begin from certified accepted geometry, not an unchecked predictor.
|
||||
force = LoadAssembler::AssembleFullNodalLoad(model.Value(), dofs,
|
||||
candidate.time);
|
||||
if (!force.HasValue()) return fail(force.GetStatus());
|
||||
candidate.external_force = std::move(force.Value());
|
||||
candidate.low.external_force = Vector(dofs.FullDofCount());
|
||||
std::array<HighLow, 4> correction{}, fresh_correction{};
|
||||
bool accepted = false;
|
||||
for (std::uint32_t iteration = 0; iteration <= 100; ++iteration) {
|
||||
record.stage = "evaluation";
|
||||
record.outcome = "paired-candidate";
|
||||
record.evidence = {};
|
||||
record.evidence.iteration_index = iteration;
|
||||
status = SetRates(old, predictor.Value(), h, p, &candidate);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
tangent = EvaluateSolids(domain, solids.Value(), dofs, parallel_for_,
|
||||
&candidate);
|
||||
if (!tangent.HasValue()) return fail(tangent.GetStatus());
|
||||
status = RecoverEndpoint(domain, dofs, mass.Value(), &old, initial_energy,
|
||||
&candidate, &record.evidence);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
auto MA = detail::MultiplySolidHhtMassHighLow(
|
||||
mass.Value(), candidate.algorithmic_acceleration,
|
||||
candidate.low.algorithmic_acceleration);
|
||||
if (!MA.HasValue()) return fail(MA.GetStatus());
|
||||
Vector rhs(dofs.FreeDofCount());
|
||||
HighLow identity_metric, original_norm, solved_norm, old_norm;
|
||||
for (std::size_t j = 0; j < dofs.FreeDofCount(); ++j) {
|
||||
const auto i = dofs.FreeDofs()[j];
|
||||
detail::SolidHhtPairedForceIdentity identity;
|
||||
if (!detail::EvaluateSolidHhtHighLowForceIdentity(
|
||||
mass.Value(), i, Pair(MA.Value().high, MA.Value().low, i),
|
||||
candidate, old, p.alpha, &identity))
|
||||
return fail(
|
||||
Failure(domain, "solid-dynamic-nonfinite-residual",
|
||||
"Paired weighted force arithmetic is unsupported."));
|
||||
rhs[j] = Rounded(Negate(identity.solved));
|
||||
identity_metric = Maximum(identity_metric, identity.metric);
|
||||
original_norm = Maximum(original_norm, Abs(identity.original));
|
||||
solved_norm = Maximum(solved_norm, Abs(identity.solved));
|
||||
old_norm =
|
||||
Maximum(old_norm, Abs(Pair(old.residual, old.low.residual, i)));
|
||||
if (i == record.evidence.worst_full_dof)
|
||||
record.evidence.worst_weighted_terms = {
|
||||
Rounded(identity.original), Rounded(identity.solved),
|
||||
Rounded(Pair(old.residual, old.low.residual, i)),
|
||||
Rounded(identity.scale)};
|
||||
}
|
||||
if (!Valid(identity_metric) || !Valid(original_norm) ||
|
||||
!Valid(solved_norm) || !Valid(old_norm) ||
|
||||
Compare(identity_metric, HighLow(1e-12)) > 0)
|
||||
return fail(Failure(domain,
|
||||
"solid-dynamic-weighted-algebra-inconsistency",
|
||||
"Paired original and solved forces disagree beyond "
|
||||
"their uncancelled scale."));
|
||||
record.evidence.weighted_equivalence_metric = Rounded(identity_metric);
|
||||
record.evidence.weighted_residual_numerator = Rounded(original_norm);
|
||||
record.evidence.recombined_residual_numerator = Rounded(solved_norm);
|
||||
record.evidence.old_residual_numerator = Rounded(old_norm);
|
||||
for (std::size_t c = 0; c < 4; ++c) {
|
||||
if (!Valid(correction[c]) || !Valid(fresh_correction[c]))
|
||||
return fail(detail::SolidHhtPairedKinematicsFailure());
|
||||
record.evidence.correction_metrics[c] = Rounded(correction[c]);
|
||||
}
|
||||
record.evidence.correction_pass =
|
||||
CorrectionPass(correction) && CorrectionPass(fresh_correction);
|
||||
const auto update = CheckUpdates(old, candidate, p, h);
|
||||
if (!Valid(update))
|
||||
return fail(detail::SolidHhtPairedKinematicsFailure());
|
||||
record.evidence.update_metric = Rounded(update);
|
||||
record.evidence.update_pass = Compare(update, HighLow(1e-12)) <= 0;
|
||||
candidate.iterations.push_back(record.evidence);
|
||||
candidate.iteration_count = iteration;
|
||||
if (record.evidence.residual_pass && record.evidence.correction_pass &&
|
||||
record.evidence.update_pass) {
|
||||
status = state.CommitAcceptedFrame(candidate);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
record.stage = "accepted";
|
||||
record.outcome = "increment";
|
||||
state.RecordIteration(record);
|
||||
accepted = true;
|
||||
break;
|
||||
}
|
||||
state.RecordIteration(record);
|
||||
if (iteration == 100)
|
||||
return fail(Failure(
|
||||
domain, "solid-dynamic-nonconvergence",
|
||||
"Paired HHT endpoint did not converge in100 Newton solves."));
|
||||
auto effective =
|
||||
EffectiveTangent(mass.Value(), tangent.Value(), dofs, h, p);
|
||||
if (!effective.HasValue()) return fail(effective.GetStatus());
|
||||
auto reduced = partition.Partition(effective.Value(), dofs);
|
||||
if (!reduced.HasValue()) return fail(reduced.GetStatus());
|
||||
Vector du(dofs.FreeDofCount());
|
||||
if (dofs.FreeDofCount() != 0) {
|
||||
status = tangent_solver_.FactorizeFresh(reduced.Value().k_ff);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
environment = CheckArithmeticEnvironment(domain);
|
||||
if (!environment.IsOk()) return fail(environment);
|
||||
status = tangent_solver_.SolveCorrection(rhs, du);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
environment = CheckArithmeticEnvironment(domain);
|
||||
if (!environment.IsOk()) return fail(environment);
|
||||
}
|
||||
if (du.Size() != dofs.FreeDofCount())
|
||||
return fail(Failure(domain, "solid-dynamic-invalid-backend-result",
|
||||
"Tangent solve returned incompatible correction."));
|
||||
for (std::size_t j = 0; j < du.Size(); ++j)
|
||||
if (!std::isfinite(du[j]))
|
||||
return fail(Failure(domain, "solid-dynamic-invalid-backend-result",
|
||||
"Tangent solve returned nonfinite correction."));
|
||||
fresh_correction = FreshCorrectionMetrics(du, length.Value(), p);
|
||||
const auto before = candidate;
|
||||
for (std::size_t j = 0; j < du.Size(); ++j) {
|
||||
const auto i = dofs.FreeDofs()[j];
|
||||
const auto value =
|
||||
Add(Pair(candidate.displacement, candidate.low.displacement, i),
|
||||
HighLow(du[j] == 0 ? 0.0 : du[j]));
|
||||
if (!Valid(value))
|
||||
return fail(detail::SolidHhtPairedKinematicsFailure());
|
||||
Store(value, &candidate.displacement, &candidate.low.displacement, i);
|
||||
}
|
||||
status = SetRates(old, predictor.Value(), h, p, &candidate);
|
||||
if (!status.IsOk()) return fail(status);
|
||||
correction =
|
||||
ObservedCorrectionMetrics(before, candidate, h, length.Value());
|
||||
}
|
||||
if (!accepted)
|
||||
return fail(Failure(domain, "solid-dynamic-nonconvergence",
|
||||
"No complete paired endpoint was accepted."));
|
||||
status = detail::RunSolidHhtStep(
|
||||
integrator, old, h, p, fail,
|
||||
[&](const detail::SolidHhtIntegrator& step_integrator,
|
||||
const detail::SolidHhtPairedPredictor& predictor)
|
||||
-> Result<SolidDynamicAcceptedFrameState> {
|
||||
auto candidate = old;
|
||||
candidate.frame_index = candidate.increment_index = increment;
|
||||
candidate.iteration_count = 0;
|
||||
candidate.time = record.time;
|
||||
candidate.is_initial = false;
|
||||
candidate.iterations.clear();
|
||||
// Begin from certified accepted geometry, not an unchecked predictor.
|
||||
force = LoadAssembler::AssembleFullNodalLoad(model.Value(), dofs,
|
||||
candidate.time);
|
||||
if (!force.HasValue())
|
||||
return Result<SolidDynamicAcceptedFrameState>::Failure(fail(force.GetStatus()));
|
||||
candidate.external_force = std::move(force.Value());
|
||||
candidate.low.external_force = Vector(dofs.FullDofCount());
|
||||
std::array<HighLow, 4> correction{}, fresh_correction{};
|
||||
using StepResult = Result<std::optional<SolidDynamicAcceptedFrameState>>;
|
||||
const auto report_failure = fail;
|
||||
const auto record_iteration = [&](const auto& value) {
|
||||
state.RecordIteration(value);
|
||||
};
|
||||
SolidHhtStep<SolidDynamicAcceptedFrameState> iteration_step(
|
||||
[&](std::uint32_t iteration) -> StepResult {
|
||||
const auto fail = [&](const Status& failure) {
|
||||
return StepResult::Failure(report_failure(failure));
|
||||
};
|
||||
record.stage = "evaluation";
|
||||
record.outcome = "paired-candidate";
|
||||
record.evidence = {};
|
||||
record.evidence.iteration_index = iteration;
|
||||
status =
|
||||
detail::SetSolidHhtRates(step_integrator, old, predictor, h, p, &candidate);
|
||||
if (!status.IsOk())
|
||||
return fail(status);
|
||||
tangent = EvaluateSolids(domain, solids.Value(), dofs, parallel_for,
|
||||
&candidate);
|
||||
if (!tangent.HasValue())
|
||||
return fail(tangent.GetStatus());
|
||||
status =
|
||||
RecoverEndpoint(domain, dofs, mass.Value(), &old, initial_energy,
|
||||
&candidate, &record.evidence);
|
||||
if (!status.IsOk())
|
||||
return fail(status);
|
||||
auto MA = detail::MultiplySolidHhtMassHighLow(
|
||||
mass.Value(), candidate.algorithmic_acceleration,
|
||||
candidate.low.algorithmic_acceleration);
|
||||
if (!MA.HasValue())
|
||||
return fail(MA.GetStatus());
|
||||
Vector rhs(dofs.FreeDofCount());
|
||||
HighLow identity_metric, original_norm, solved_norm, old_norm;
|
||||
for (std::size_t j = 0; j < dofs.FreeDofCount(); ++j) {
|
||||
const auto i = dofs.FreeDofs()[j];
|
||||
detail::SolidHhtPairedForceIdentity identity;
|
||||
if (!detail::EvaluateSolidHhtHighLowForceIdentity(
|
||||
mass.Value(), i, Pair(MA.Value().high, MA.Value().low, i),
|
||||
candidate, old, p.alpha, &identity))
|
||||
return fail(
|
||||
Failure(domain, "solid-dynamic-nonfinite-residual",
|
||||
"Paired weighted force arithmetic is unsupported."));
|
||||
rhs[j] = Rounded(Negate(identity.solved));
|
||||
identity_metric = Maximum(identity_metric, identity.metric);
|
||||
original_norm = Maximum(original_norm, Abs(identity.original));
|
||||
solved_norm = Maximum(solved_norm, Abs(identity.solved));
|
||||
old_norm =
|
||||
Maximum(old_norm, Abs(Pair(old.residual, old.low.residual, i)));
|
||||
if (i == record.evidence.worst_full_dof)
|
||||
record.evidence.worst_weighted_terms = {
|
||||
Rounded(identity.original), Rounded(identity.solved),
|
||||
Rounded(Pair(old.residual, old.low.residual, i)),
|
||||
Rounded(identity.scale)};
|
||||
}
|
||||
if (!Valid(identity_metric) || !Valid(original_norm) ||
|
||||
!Valid(solved_norm) || !Valid(old_norm) ||
|
||||
Compare(identity_metric, HighLow(1e-12)) > 0)
|
||||
return fail(
|
||||
Failure(domain, "solid-dynamic-weighted-algebra-inconsistency",
|
||||
"Paired original and solved forces disagree beyond "
|
||||
"their uncancelled scale."));
|
||||
record.evidence.weighted_equivalence_metric =
|
||||
Rounded(identity_metric);
|
||||
record.evidence.weighted_residual_numerator = Rounded(original_norm);
|
||||
record.evidence.recombined_residual_numerator = Rounded(solved_norm);
|
||||
record.evidence.old_residual_numerator = Rounded(old_norm);
|
||||
for (std::size_t c = 0; c < 4; ++c) {
|
||||
if (!Valid(correction[c]) || !Valid(fresh_correction[c]))
|
||||
return fail(detail::SolidHhtPairedKinematicsFailure());
|
||||
record.evidence.correction_metrics[c] = Rounded(correction[c]);
|
||||
}
|
||||
record.evidence.correction_pass =
|
||||
CorrectionPass(correction) && CorrectionPass(fresh_correction);
|
||||
const auto update = CheckUpdates(old, candidate, p, h);
|
||||
if (!Valid(update))
|
||||
return fail(detail::SolidHhtPairedKinematicsFailure());
|
||||
record.evidence.update_metric = Rounded(update);
|
||||
record.evidence.update_pass = Compare(update, HighLow(1e-12)) <= 0;
|
||||
candidate.iterations.push_back(record.evidence);
|
||||
candidate.iteration_count = iteration;
|
||||
if (record.evidence.residual_pass &&
|
||||
record.evidence.correction_pass && record.evidence.update_pass) {
|
||||
return StepResult::Success(candidate);
|
||||
}
|
||||
record_iteration(record);
|
||||
if (iteration == 100)
|
||||
return fail(Failure(
|
||||
domain, "solid-dynamic-nonconvergence",
|
||||
"Paired HHT endpoint did not converge in100 Newton solves."));
|
||||
auto effective =
|
||||
EffectiveTangent(mass.Value(), tangent.Value(), dofs, h, p);
|
||||
if (!effective.HasValue())
|
||||
return fail(effective.GetStatus());
|
||||
auto reduced = partition.Partition(effective.Value(), dofs);
|
||||
if (!reduced.HasValue())
|
||||
return fail(reduced.GetStatus());
|
||||
Vector du(dofs.FreeDofCount());
|
||||
if (dofs.FreeDofCount() != 0) {
|
||||
status = tangent_solver.FactorizeFresh(reduced.Value().k_ff);
|
||||
if (!status.IsOk())
|
||||
return fail(status);
|
||||
environment = CheckArithmeticEnvironment(domain);
|
||||
if (!environment.IsOk())
|
||||
return fail(environment);
|
||||
status = tangent_solver.SolveCorrection(rhs, du);
|
||||
if (!status.IsOk())
|
||||
return fail(status);
|
||||
environment = CheckArithmeticEnvironment(domain);
|
||||
if (!environment.IsOk())
|
||||
return fail(environment);
|
||||
}
|
||||
if (du.Size() != dofs.FreeDofCount())
|
||||
return fail(
|
||||
Failure(domain, "solid-dynamic-invalid-backend-result",
|
||||
"Tangent solve returned incompatible correction."));
|
||||
for (std::size_t j = 0; j < du.Size(); ++j)
|
||||
if (!std::isfinite(du[j]))
|
||||
return fail(
|
||||
Failure(domain, "solid-dynamic-invalid-backend-result",
|
||||
"Tangent solve returned nonfinite correction."));
|
||||
fresh_correction = FreshCorrectionMetrics(du, length.Value(), p);
|
||||
const auto before = candidate;
|
||||
for (std::size_t j = 0; j < du.Size(); ++j) {
|
||||
const auto i = dofs.FreeDofs()[j];
|
||||
const auto value =
|
||||
Add(Pair(candidate.displacement, candidate.low.displacement, i),
|
||||
HighLow(du[j] == 0 ? 0.0 : du[j]));
|
||||
if (!Valid(value))
|
||||
return fail(detail::SolidHhtPairedKinematicsFailure());
|
||||
Store(value, &candidate.displacement, &candidate.low.displacement,
|
||||
i);
|
||||
}
|
||||
status =
|
||||
detail::SetSolidHhtRates(step_integrator, old, predictor, h, p, &candidate);
|
||||
if (!status.IsOk())
|
||||
return fail(status);
|
||||
correction =
|
||||
ObservedCorrectionMetrics(before, candidate, h, length.Value());
|
||||
return StepResult::Success(std::nullopt);
|
||||
},
|
||||
100U);
|
||||
const Status solved = iteration_step.Solve(algorithm);
|
||||
if (!solved.IsOk())
|
||||
return Result<SolidDynamicAcceptedFrameState>::Failure(solved);
|
||||
if (!iteration_step.HasCandidate())
|
||||
return Result<SolidDynamicAcceptedFrameState>::Failure(
|
||||
fail(Failure(domain, "solid-dynamic-nonconvergence",
|
||||
"No complete paired endpoint was accepted.")));
|
||||
return Result<SolidDynamicAcceptedFrameState>::Success(
|
||||
iteration_step.TakeCandidate());
|
||||
},
|
||||
[&](SolidDynamicAcceptedFrameState&& accepted_candidate) -> Status {
|
||||
status = state.CommitAcceptedFrame(accepted_candidate);
|
||||
if (!status.IsOk())
|
||||
return fail(status);
|
||||
record.stage = "accepted";
|
||||
record.outcome = "increment";
|
||||
state.RecordIteration(record);
|
||||
return Status::Ok();
|
||||
});
|
||||
if (!status.IsOk()) return status;
|
||||
}
|
||||
return Status::Ok();
|
||||
}
|
||||
} // namespace fesa
|
||||
} // namespace fesa
|
||||
|
||||
Reference in New Issue
Block a user