b2api
B2000++ API Reference Manual, VERSION 4.6
 
Loading...
Searching...
No Matches
b2static_nonlinear_solver.H
1//------------------------------------------------------------------------
2// b2static_nonlinear_solver.H --
3//
4//
5// written by Mathias Doreille
6// Neda Ebrahimi Pour <neda.ebrahimipour@dlr.de>
7// Thomas Blome <thomas.blome@dlr.de>
8//
9// (c) 2004-2012 SMR Engineering & Development SA
10// 2502 Bienne, Switzerland
11//
12// (c) 2023 Deutsches Zentrum für Luft- und Raumfahrt (DLR) e.V.
13// Linder Höhe, 51147 Köln
14//
15// All Rights Reserved. Proprietary source code. The contents of
16// this file may not be disclosed to third parties, copied or
17// duplicated in any form, in whole or in part, without the prior
18// written permission of SMR.
19//------------------------------------------------------------------------
20
21#ifndef B2STATIC_NONLINEAR_SOLVER_H_
22#define B2STATIC_NONLINEAR_SOLVER_H_
23
24#include <memory>
25
26#include "b2ppconfig.h"
28#include "model/b2domain.H"
30#include "model/b2model.H"
31#include "model/b2solution.H"
32#include "model/b2solver.H"
33#include "solvers/b2static_nonlinear_utile.H"
34#include "utils/b2logging.H"
35#include "utils/b2object.H"
36
37// This is part of the Monolithic solver and should be removed here:
38namespace {
39const int MAX_STEPS_DEFAULT = 99999;
40}
41
42namespace b2000::solver {
43
44template <typename T, typename MATRIX_FORMAT>
45class StaticNonLinearSolver : public Solver {
46public:
47 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
48 using type_t = ObjectTypeComplete<StaticNonLinearSolver, Solver::type_t>;
49
50 void solve() override {
51 while (solve_iteration()) { ; }
52 }
53
54 bool solve_iteration() override;
55
56 static type_t type;
57
58protected:
59 void solve_init();
60
61 Domain* domain{};
62 SolutionStaticNonlinear<T>* solution{};
63
64 logging::Logger& logger{logging::get_logger("solver.static_nonlinear")};
65
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{};
69
70 int increment_iteration_number{};
71 int first_increment_iteration_number_of_stage{};
72 double time{};
73 // Contains dof solution. Size: ndofs
74 b2linalg::Vector<T, b2linalg::Vdense> d_;
75 // Contains reduced dof solution
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;
79
80 int max_number_of_iteration_by_stage{};
81};
82
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);
88
89template <typename T, typename MATRIX_FORMAT>
90void b2000::solver::StaticNonLinearSolver<T, MATRIX_FORMAT>::solve_init() {
91 if (model_ == nullptr) { Exception() << THROW; }
92
93 if (case_iterator_.get() == nullptr) {
94 case_iterator_ = model_->get_case_list().get_case_iterator();
95 }
96
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;
103 }
104
105 logger << logging::info << "Start static nonlinear solver for case " << case_->get_id()
106 << logging::LOGFLUSH;
107
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());
112 if (solution == 0) {
113 TypeError() << "The solver only accepts solutions of type "
114 << typeid(SolutionStaticNonlinear<T>) << THROW;
115 }
116
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_);
126
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_);
135
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_);
144
145 increment_iteration_number = 0;
146 first_increment_iteration_number_of_stage = 0;
147 size_t s = residue_function->get_number_of_dof();
148
149 d_red_.resize(s);
150 d_red_.set_zero();
151 K.set_zero();
152 K.resize(s, 1, domain->get_dof_connectivity_type(), *case_);
153 q.resize(s);
154 {
155 std::string domain_state_id;
156 int stage;
157
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);
161
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); }
170 }
171}
172
178template <typename T, typename MATRIX_FORMAT>
179bool b2000::solver::StaticNonLinearSolver<T, MATRIX_FORMAT>::solve_iteration() {
180 if (case_ == nullptr) {
181 solve_init();
182 if (case_ == nullptr) { return false; }
183 }
184
185 ++increment_iteration_number;
186 std::string domain_state_id;
187 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result result;
188 const double old_time = time;
189 try {
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;
195 while (1) {
196 // prediction step
197 logger << logging::debug << "Start prediction of increment "
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);
203
204 if (result != IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage) { break; }
205
206 // correction step
207 logger << logging::debug << "Start correction of increment "
208 << increment_iteration_number << " of stage " << case_->get_stage_id()
209 << " for time " << time << "." << logging::LOGFLUSH;
210
211 try {
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);
216 }
217
218 if (result == IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry) {
219 logger << logging::debug
220 << "Correction has diverged, retrying the prediction-correction step "
221 "with a different predictor."
222 << logging::LOGFLUSH;
223 equilibrium_solution.input_level = 0;
224 } else {
225 break;
226 }
227 }
228
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;
234 }
235
236 // save the solution for the current stage and increment
237 d_.resize(domain->get_number_of_dof());
238 residue_function->get_solution(d_red_, time, true, d_);
239 solution->new_cycle(
240 result
241 == IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success);
242 solution->set_dof(
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();
246 } else {
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;
252 } else {
253 result = IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
254 }
255 }
256
257 {
258 typename SolutionStaticNonlinear<T>::gradient_container gc =
259 solution->get_gradient_container();
260 domain->set_dof(d_);
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());
267 }
268 if (!domain_state_id.empty()) { domain->save_state(domain_state_id); }
269 RTable attributes;
270 solution->terminate_cycle(time, time - old_time, attributes);
271 } catch (...) {
272 solution->terminate_stage(false);
273 RTable attributes;
274 solution->terminate_case(false, attributes);
275 throw;
276 }
277
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_);
282 time = 0;
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);
289 return true;
290 }
291 RTable attributes;
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();
296 case_ = nullptr;
297 return true;
298 }
299
300 if (increment_iteration_number - first_increment_iteration_number_of_stage
301 > max_number_of_iteration_by_stage) {
302 solution->terminate_stage(false);
303 RTable attributes;
304 solution->terminate_case(false, attributes);
305 logger << logging::error
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;
310 }
311
312 return true;
313}
314
315} // namespace b2000::solver
316
317#endif // B2STATIC_NONLINEAR_SOLVER_H_
#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