34 template <
typename PLSOLVER>
37 typedef typename PLSOLVER::element_type::MATRIX MATRIX;
38 typedef typename PLSOLVER::element_type::VECTOR VECTOR;
39 typedef typename gmm::linalg_traits<VECTOR>::value_type T;
40 typedef typename gmm::number_traits<T>::magnitude_type R;
43 PLSOLVER linear_solver;
49 virtual const VECTOR &residual()
const {
return rhs; }
52 virtual const VECTOR &state_vector()
const {
return state; }
53 virtual VECTOR &state_vector() {
return state; }
54 virtual R state_norm()
const {
return gmm::vect_norm1(state_vector()); }
56 virtual void perturbation() {
57 R res =
gmm::vect_norm2(state), ampl = std::max(res*R(1E-20), R(1E-50));
58 std::vector<R> V(gmm::vect_size(state));
60 gmm::add(gmm::scaled(V, ampl), state);
63 virtual void add_to_residual(VECTOR &extra_rhs, R mult=1.) {
64 if (mult == R(1)) gmm::add(extra_rhs, rhs);
65 else if (mult != R(0)) gmm::add(gmm::scaled(extra_rhs, mult), rhs);
69 (*linear_solver)(K, dr, rhs, iter);
72 pb_base(PLSOLVER linsolv,
const MATRIX &K_, VECTOR &rhs_)
73 : linear_solver(linsolv), K(K_), rhs(rhs_), state(gmm::vect_size(rhs_)) {}
80 template <
typename PLSOLVER>
81 class lin_model_pb : pb_base<PLSOLVER> {
84 using typename pb_base<PLSOLVER>::VECTOR;
85 using typename pb_base<PLSOLVER>::R;
86 using pb_base<PLSOLVER>::state_vector;
87 using pb_base<PLSOLVER>::linear_solve;
88 void compute_all() { md.assembly(model::BUILD_ALL); }
89 lin_model_pb(model &, PLSOLVER) =
delete;
93 lin_model_pb<rmodel_plsolver_type>::lin_model_pb
94 (model &md_, rmodel_plsolver_type linsolv)
95 : pb_base<rmodel_plsolver_type>
96 (linsolv, md_.real_tangent_matrix(), md_.set_real_rhs()),
98 { md.from_variables(state_vector()); }
100 lin_model_pb<cmodel_plsolver_type>::lin_model_pb
101 (model &md_, cmodel_plsolver_type linsolv)
102 : pb_base<cmodel_plsolver_type>
103 (linsolv, md_.complex_tangent_matrix(), md_.set_complex_rhs()),
105 { md.from_variables(state_vector()); }
111 template <
typename PLSOLVER>
112 class nonlin_model_pb :
protected pb_base<PLSOLVER> {
114 using typename pb_base<PLSOLVER>::VECTOR;
115 using typename pb_base<PLSOLVER>::R;
118 abstract_newton_line_search &ls;
122 using pb_base<PLSOLVER>::residual;
123 using pb_base<PLSOLVER>::residual_norm;
124 using pb_base<PLSOLVER>::state_vector;
125 using pb_base<PLSOLVER>::state_norm;
126 using pb_base<PLSOLVER>::add_to_residual;
127 using pb_base<PLSOLVER>::perturbation;
128 using pb_base<PLSOLVER>::linear_solve;
130 virtual R approx_external_load_norm() {
return md.approx_external_load(); }
132 virtual void compute_tangent_matrix() {
133 md.to_variables(state_vector());
134 md.assembly(model::BUILD_MATRIX);
137 virtual void compute_residual() {
138 md.to_variables(state_vector());
139 md.assembly(model::BUILD_RHS);
144 gmm::resize(stateinit, gmm::vect_size(state_vector()));
145 gmm::copy(state_vector(), stateinit);
148 res = residual_norm();
150 R0 = gmm::real(gmm::vect_sp(dr, residual()));
151 ls.init_search(res, iter.get_iteration(), R0);
153 alpha = ls.next_try();
154 gmm::add(stateinit, gmm::scaled(dr, alpha), state_vector());
157 res = residual_norm();
159 R0 = gmm::real(gmm::vect_sp(dr, residual()));
161 }
while (!ls.is_converged(res, R0));
163 if (alpha != ls.converged_value()) {
164 alpha = ls.converged_value();
165 gmm::add(stateinit, gmm::scaled(dr, alpha), state_vector());
166 res = ls.converged_residual();
173 nonlin_model_pb(model &md_, abstract_newton_line_search &ls_,
174 PLSOLVER linear_solver_) =
delete;
178 nonlin_model_pb<rmodel_plsolver_type>::nonlin_model_pb
179 (model &md_, abstract_newton_line_search &ls_, rmodel_plsolver_type linsolv)
180 : pb_base<rmodel_plsolver_type>
181 (linsolv, md_.real_tangent_matrix(), md_.set_real_rhs()),
183 { md.from_variables(state_vector()); }
185 nonlin_model_pb<cmodel_plsolver_type>::nonlin_model_pb
186 (model &md_, abstract_newton_line_search &ls_, cmodel_plsolver_type linsolv)
187 : pb_base<cmodel_plsolver_type>
188 (linsolv, md_.complex_tangent_matrix(), md_.set_complex_rhs()),
190 { md.from_variables(state_vector()); }
197 template <
typename PLSOLVER>
198 class nonlin_condensed_model_pb :
public nonlin_model_pb<PLSOLVER> {
200 using typename pb_base<PLSOLVER>::MATRIX;
201 using typename pb_base<PLSOLVER>::VECTOR;
202 using typename pb_base<PLSOLVER>::R;
205 using nonlin_model_pb<PLSOLVER>::md;
207 const MATRIX &internal_K;
211 virtual const VECTOR &residual()
const {
return full_rhs; }
215 using pb_base<PLSOLVER>::state_vector;
216 using pb_base<PLSOLVER>::state_norm;
218 virtual void add_to_residual(VECTOR &extra_rhs, R mult=1.) {
219 if (mult == R(1)) gmm::add(extra_rhs, full_rhs);
220 else if (mult != R(0)) gmm::add(gmm::scaled(extra_rhs, mult), full_rhs);
223 using pb_base<PLSOLVER>::perturbation;
226 VECTOR dr0(md.nb_primary_dof(), R(0));
227 pb_base<PLSOLVER>::linear_solve(dr0, iter);
228 gmm::sub_interval I_prim(0, md.nb_primary_dof()),
229 I_intern(md.nb_primary_dof(), md.nb_internal_dof());
230 gmm::copy(dr0, gmm::sub_vector(dr, I_prim));
232 gmm::mult(internal_K,
233 gmm::scaled(gmm::sub_vector(dr, I_prim), scalar_type(-1)),
234 md.internal_solution(),
235 gmm::sub_vector(dr, I_intern));
238 virtual void compute_tangent_matrix() {
239 md.to_variables(state_vector(), condensed_vars);
240 md.assembly(condensed_vars ? model::BUILD_MATRIX_CONDENSED
241 : model::BUILD_MATRIX);
244 virtual void compute_residual() {
245 md.to_variables(state_vector(), condensed_vars);
246 md.assembly(condensed_vars ? model::BUILD_RHS_WITH_INTERNAL
250 nonlin_condensed_model_pb(model &md_, abstract_newton_line_search &ls_,
251 PLSOLVER linear_solver_) =
delete;
255 nonlin_condensed_model_pb<rmodel_plsolver_type>::nonlin_condensed_model_pb
256 (model &md_, abstract_newton_line_search &ls_, rmodel_plsolver_type linsolv)
257 : nonlin_model_pb<rmodel_plsolver_type>(md_, ls_, linsolv),
258 condensed_vars(md_.has_internal_variables()),
259 internal_K(md_.real_tangent_matrix(condensed_vars)),
260 full_rhs(md_.set_real_rhs(condensed_vars))
262 gmm::resize(state_vector(), md.nb_dof(condensed_vars));
263 md.from_variables(state_vector(), condensed_vars);
267 nonlin_condensed_model_pb<cmodel_plsolver_type>::nonlin_condensed_model_pb
268 (model &md_, abstract_newton_line_search &ls_, cmodel_plsolver_type linsolv)
269 : nonlin_model_pb<cmodel_plsolver_type>(md_, ls_, linsolv),
270 condensed_vars(false), internal_K(md_.complex_tangent_matrix()),
271 full_rhs(md_.set_complex_rhs())
273 GMM_ASSERT1(
false,
"No support for internal variable condensation in "
274 "complex valued models.");
282 static rmodel_plsolver_type rdefault_linear_solver(
const model &md) {
283 return default_linear_solver<model_real_sparse_matrix,
284 model_real_plain_vector>(md);
287 static cmodel_plsolver_type cdefault_linear_solver(
const model &md) {
288 return default_linear_solver<model_complex_sparse_matrix,
289 model_complex_plain_vector>(md);
292 void default_newton_line_search::init_search(
double r,
size_t git,
double) {
293 alpha_min_ratio = 0.9;
295 alpha_max_ratio = 10.0;
298 glob_it = git;
if (git <= 1) count_pat = 0;
299 conv_alpha =
alpha = alpha_old = 1.;
300 conv_r = first_res = r; it = 0;
302 max_ratio_reached =
false;
305 double default_newton_line_search::next_try() {
306 alpha_old =
alpha; ++it;
308 if (alpha >= 0.4)
alpha *= 0.5;
else alpha *= alpha_mult;
312 bool default_newton_line_search::is_converged(
double r,
double) {
314 if (!max_ratio_reached && r < first_res * alpha_max_ratio) {
315 alpha_max_ratio_reached = alpha_old; r_max_ratio_reached = r;
316 it_max_ratio_reached = it; max_ratio_reached =
true;
318 if (max_ratio_reached &&
319 r < r_max_ratio_reached * 0.5 &&
320 r > first_res * 1.1 && it <= it_max_ratio_reached+1) {
321 alpha_max_ratio_reached = alpha_old; r_max_ratio_reached = r;
322 it_max_ratio_reached = it;
324 if (count == 0 || r < conv_r)
325 { conv_r = r; conv_alpha = alpha_old; count = 1; }
326 if (conv_r < first_res) ++count;
328 if (r < first_res * alpha_min_ratio)
329 { count_pat = 0;
return true; }
330 if (count>=5 || (alpha < alpha_min && max_ratio_reached) || alpha<1e-15) {
331 if (conv_r < first_res * 0.99) count_pat = 0;
333 { conv_r=r_max_ratio_reached; conv_alpha=alpha_max_ratio_reached; }
334 if (conv_r >= first_res * 0.999) count_pat++;
346 template <
typename PLSOLVER>
349 abstract_newton_line_search &ls) {
351 typename PLSOLVER::element_type::VECTOR state(md.nb_dof());
352 md.from_variables(state);
353 md.cancel_init_step();
354 md.set_time_integration(2);
355 scalar_type dt = md.get_time_step();
356 scalar_type ddt = md.get_init_time_step();
357 scalar_type t = md.get_time();
360 md.set_time_step(ddt);
363 md.copy_init_time_derivative();
366 md.set_time_step(dt);
368 md.to_variables(state);
369 md.set_time_integration(1);
376 template <
typename PLSOLVER>
379 abstract_newton_line_search &ls) {
381 int time_integration = md.is_time_integration();
382 if (time_integration) {
383 if (time_integration == 1 && md.is_init_step()) {
384 compute_init_values(md, iter, lsolver, ls);
387 md.set_time(md.get_time() + md.get_time_step());
388 md.call_init_affine_dependent_variables(time_integration);
391 if (md.is_linear()) {
392 lin_model_pb<PLSOLVER> mdpb(md, lsolver);
394 mdpb.linear_solve(mdpb.state_vector(), iter);
395 md.to_variables(mdpb.state_vector());
397 std::unique_ptr<nonlin_model_pb<PLSOLVER>> mdpb;
398 if (md.has_internal_variables())
399 mdpb = std::make_unique<nonlin_condensed_model_pb<PLSOLVER>>(md, ls, lsolver);
401 mdpb = std::make_unique<nonlin_model_pb<PLSOLVER>>(md, ls, lsolver);
402 if (
dynamic_cast<newton_search_with_step_control *
>(&ls))
403 Newton_with_step_control(*mdpb, iter);
405 classical_Newton(*mdpb, iter);
406 md.to_variables(mdpb->state_vector());
411 rmodel_plsolver_type lsolver,
412 abstract_newton_line_search &ls) {
413 standard_solve<rmodel_plsolver_type>(md, iter, lsolver, ls);
417 cmodel_plsolver_type lsolver,
418 abstract_newton_line_search &ls) {
419 standard_solve<cmodel_plsolver_type>(md, iter, lsolver, ls);
424 rmodel_plsolver_type lsolver) {
425 default_newton_line_search ls;
430 cmodel_plsolver_type lsolver) {
431 newton_search_with_step_control ls;
437 newton_search_with_step_control ls;