21#ifndef B2STATIC_NONLINEAR_SOLVER_H_
22#define B2STATIC_NONLINEAR_SOLVER_H_
26#include "b2ppconfig.h"
33#include "solvers/b2static_nonlinear_utile.H"
39const int MAX_STEPS_DEFAULT = 99999;
42namespace b2000::solver {
44template <
typename T,
typename MATRIX_FORMAT>
45class StaticNonLinearSolver :
public Solver {
47 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
48 using type_t = ObjectTypeComplete<StaticNonLinearSolver, Solver::type_t>;
50 void solve()
override {
51 while (solve_iteration()) { ; }
54 bool solve_iteration()
override;
62 SolutionStaticNonlinear<T>* solution{};
66 std::unique_ptr<StaticResidueFunction<T, MATRIX_FORMAT>> residue_function{};
67 std::unique_ptr<IncrementConstraintStrategy<T, MATRIX_FORMAT>> constraint{};
68 std::unique_ptr<CorrectionStrategy<T, MATRIX_FORMAT>> correction{};
70 int increment_iteration_number{};
71 int first_increment_iteration_number_of_stage{};
74 b2linalg::Vector<T, b2linalg::Vdense> d_;
76 b2linalg::Vector<T, b2linalg::Vdense> d_red_;
77 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext> K;
78 b2linalg::Vector<T, b2linalg::Vdense> q;
80 int max_number_of_iteration_by_stage{};
83template <
typename T,
typename MATRIX_FORMAT>
84typename StaticNonLinearSolver<T, MATRIX_FORMAT>::type_t
85 StaticNonLinearSolver<T, MATRIX_FORMAT>::type(
86 "StaticNonLinearSolver", type_name<T, MATRIX_FORMAT>(),
87 StringList(
"NONLINEAR",
"COLLAPSE"), module, &Solver::type);
89template <
typename T,
typename MATRIX_FORMAT>
90void b2000::solver::StaticNonLinearSolver<T, MATRIX_FORMAT>::solve_init() {
91 if (model_ ==
nullptr) { Exception() <<
THROW; }
93 if (case_iterator_.get() ==
nullptr) {
94 case_iterator_ = model_->get_case_list().get_case_iterator();
97 case_ = case_iterator_->next();
98 if (case_ ==
nullptr) {
return; }
99 if (case_->get_number_of_stage() == 0) {
100 Exception() <<
"The static nonlinear solver must have a case that contains at least one "
101 "stage but the case "
102 << case_->get_id() <<
" does not have a stage." <<
THROW;
105 logger <<
logging::info <<
"Start static nonlinear solver for case " << case_->get_id()
106 << logging::LOGFLUSH;
108 model_->set_case(*case_);
109 max_number_of_iteration_by_stage = case_->get_int(
"MAX_STEPS", MAX_STEPS_DEFAULT);
110 domain = &model_->get_domain();
111 solution =
dynamic_cast<SolutionStaticNonlinear<T>*
>(&model_->get_solution());
113 TypeError() <<
"The solver only accepts solutions of type "
114 <<
typeid(SolutionStaticNonlinear<T>) <<
THROW;
117 std::string control_type_name = case_->get_string(
"INCREMENT_CONTROL_TYPE",
"LOAD");
118 if (control_type_name !=
"") { control_type_name +=
"_CONTROL_CONSTRAINT_STRATEGY"; }
119 control_type_name = type_name<T, MATRIX_FORMAT>(control_type_name);
120 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t* control_type =
121 IncrementConstraintStrategy<T, MATRIX_FORMAT>::type.get_subtype(
122 control_type_name, solver::module);
123 constraint.reset(control_type->new_object());
124 constraint->set_max_time(case_->get_stage_size());
125 constraint->init(*model_, *case_);
127 std::string residue_function_name = case_->get_string(
"RESIDUE_FUNCTION_TYPE",
"DEFAULT");
128 if (residue_function_name !=
"") { residue_function_name +=
"_STATIC_RESIDUE_FUNCTION"; }
129 residue_function_name = type_name<T, MATRIX_FORMAT>(residue_function_name);
130 typename StaticResidueFunction<T, MATRIX_FORMAT>::type_t* residue_function_type =
131 StaticResidueFunction<T, MATRIX_FORMAT>::type.get_subtype(
132 residue_function_name, solver::module);
133 residue_function.reset(residue_function_type->new_object());
134 residue_function->init(*model_, *case_);
136 std::string correction_type_name = case_->get_string(
"CORRECTION_TYPE",
"NEWTON");
137 if (!correction_type_name.empty()) { correction_type_name +=
"_METHOD"; }
138 correction_type_name = type_name<T, MATRIX_FORMAT>(correction_type_name);
139 typename CorrectionStrategy<T, MATRIX_FORMAT>::type_t* correction_type =
140 CorrectionStrategy<T, MATRIX_FORMAT>::type.get_subtype(
141 correction_type_name, solver::module);
142 correction.reset(correction_type->new_object());
143 correction->init(*model_, *case_);
145 increment_iteration_number = 0;
146 first_increment_iteration_number_of_stage = 0;
147 size_t s = residue_function->get_number_of_dof();
152 K.resize(s, 1, domain->get_dof_connectivity_type(), *case_);
155 std::string domain_state_id;
158 b2linalg::Vector<T, b2linalg::Vdense> dof_init(domain->get_number_of_dof());
159 dynamic_cast<TypedInitialCondition<T>&
>(model_->get_initial_condition())
160 .get_static_initial_condition_value(dof_init, time, stage, domain_state_id);
162 dynamic_cast<mrbc_t&
>(
163 model_->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
164 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())))
165 .get_nonlinear_inverse_value(
166 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(dof_init), time,
167 b2linalg::Matrix<T, b2linalg::Mrectangle_ref>(d_red_));
168 case_->set_stage(stage);
169 if (!domain_state_id.empty()) { domain->load_state(domain_state_id); }
178template <
typename T,
typename MATRIX_FORMAT>
179bool b2000::solver::StaticNonLinearSolver<T, MATRIX_FORMAT>::solve_iteration() {
180 if (case_ ==
nullptr) {
182 if (case_ ==
nullptr) {
return false; }
185 ++increment_iteration_number;
186 std::string domain_state_id;
187 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result result;
188 const double old_time = time;
190 if (!case_->get_bool(
"GRADIENTS_ONLY",
false)) {
191 EquilibriumSolution equilibrium_solution(0, 1);
192 logger <<
logging::info <<
"Start increment " << increment_iteration_number
193 <<
" of stage " << case_->get_stage_id() <<
" for time " << time
194 <<
" and time step " << constraint->get_delta_time() <<
"." << logging::LOGFLUSH;
198 << increment_iteration_number <<
" of stage " << case_->get_stage_id()
199 <<
" for time " << time <<
"." << logging::LOGFLUSH;
200 equilibrium_solution.distance_to_iterative_convergence = -1;
201 result = constraint->set_increment(
202 *residue_function, K, q, d_red_, time, equilibrium_solution);
204 if (result != IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage) {
break; }
208 << increment_iteration_number <<
" of stage " << case_->get_stage_id()
209 <<
" for time " << time <<
"." << logging::LOGFLUSH;
212 result = correction->compute_correction(
213 *residue_function, K, q, *constraint, d_red_, time, equilibrium_solution);
214 }
catch (b2linalg::SingularMatrixError& e) {
215 result = constraint->set_correction_result(d_red_, time,
false, 0);
218 if (result == IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry) {
220 <<
"Correction has diverged, retrying the prediction-correction step "
221 "with a different predictor."
222 << logging::LOGFLUSH;
223 equilibrium_solution.input_level = 0;
229 if (result == IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error) {
230 solution->terminate_stage(
false);
231 logger <<
logging::error <<
"Static nonlinear solver terminates with error(s)."
232 << logging::LOGFLUSH;
233 Exception() <<
THROW;
237 d_.resize(domain->get_number_of_dof());
238 residue_function->get_solution(d_red_, time,
true, d_);
241 == IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success);
243 time, d_, residue_function->get_nbc_sol(),
244 residue_function->get_residuum_sol(d_red_, time));
245 domain_state_id = solution->get_domain_state_id();
247 solution->new_cycle(
true);
248 d_.resize(domain->get_number_of_dof());
249 solution->get_dof(time, d_);
250 if (std::abs(time - case_->get_stage_size()) < 1e-8) {
251 result = IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success;
253 result = IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
258 typename SolutionStaticNonlinear<T>::gradient_container gc =
259 solution->get_gradient_container();
261 EquilibriumSolution es(1, 0);
262 residue_function->get_residue(
263 d_red_, time, time - old_time, es,
264 b2linalg::Vector<T, b2linalg::Vdense_ref>::null,
265 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
266 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0, gc.get());
268 if (!domain_state_id.empty()) { domain->save_state(domain_state_id); }
270 solution->terminate_cycle(time, time - old_time, attributes);
272 solution->terminate_stage(
false);
274 solution->terminate_case(
false, attributes);
278 if (result == IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success) {
279 solution->terminate_stage(
true);
280 if (case_->next_stage()) {
281 model_->set_case(*case_);
283 constraint->set_max_time(case_->get_stage_size());
284 constraint->init(*model_, *case_);
285 residue_function->init(*model_, *case_);
286 correction->init(*model_, *case_);
287 first_increment_iteration_number_of_stage = increment_iteration_number;
288 max_number_of_iteration_by_stage = case_->get_int(
"MAX_STEPS", MAX_STEPS_DEFAULT);
292 solution->terminate_case(
true, attributes);
293 logger <<
logging::info <<
"End static nonlinear analysis for case " << case_->get_id()
294 <<
" with success." << logging::LOGFLUSH;
295 case_->warn_on_non_used_key();
300 if (increment_iteration_number - first_increment_iteration_number_of_stage
301 > max_number_of_iteration_by_stage) {
302 solution->terminate_stage(
false);
304 solution->terminate_case(
false, attributes);
306 <<
"Static nonlinear solver terminates with error(s). The number "
307 "of iterations for stage "
308 << case_->get_stage_id() <<
" exceeds the maximum specified." << logging::LOGFLUSH;
309 Exception() <<
THROW;
#define THROW
Definition b2exception.H:198
Interface to C++ representations of FE solvers.
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
GenericException< TypeError_name > TypeError
Definition b2exception.H:325