GetFEM  5.4.3
getfem_model_solvers.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2004-2020 Yves Renard
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program; if not, write to the Free Software Foundation,
19  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21  As a special exception, you may use this file as it is a part of a free
22  software library without restriction. Specifically, if other files
23  instantiate templates or use macros or inline functions from this file,
24  or you compile this file and link it with other files to produce an
25  executable, this file does not by itself cause the resulting executable
26  to be covered by the GNU Lesser General Public License. This exception
27  does not however invalidate any other reasons why the executable file
28  might be covered by the GNU Lesser General Public License.
29 
30 ===========================================================================*/
31 
32 /**
33  @file getfem_model_solvers.h
34  @author Yves Renard <Yves.Renard@insa-lyon.fr>
35  @date June 15, 2004.
36  @brief Standard solvers for model bricks
37  @see getfem_modeling.h
38 */
39 
40 #ifndef GETFEM_MODEL_SOLVERS_H__
41 #define GETFEM_MODEL_SOLVERS_H__
42 #include "getfem_models.h"
45 #include "gmm/gmm_iter.h"
46 #include "gmm/gmm_iter_solvers.h"
47 #include "gmm/gmm_dense_qr.h"
48 
49 //#include "gmm/gmm_inoutput.h"
50 
51 
52 namespace getfem {
53 
54  template <typename T> struct sort_abs_val_
55  { bool operator()(T x, T y) { return (gmm::abs(x) < gmm::abs(y)); } };
56 
57  template <typename MAT> void print_eigval(const MAT &M) {
58  // just to test a stiffness matrix if needing
59  typedef typename gmm::linalg_traits<MAT>::value_type T;
60  size_type n = gmm::mat_nrows(M);
61  gmm::dense_matrix<T> MM(n, n), Q(n, n);
62  std::vector<T> eigval(n);
63  gmm::copy(M, MM);
64  // gmm::symmetric_qr_algorithm(MM, eigval, Q);
65  gmm::implicit_qr_algorithm(MM, eigval, Q);
66  std::sort(eigval.begin(), eigval.end(), sort_abs_val_<T>());
67  cout << "eival = " << eigval << endl;
68 // cout << "vectp : " << gmm::mat_col(Q, n-1) << endl;
69 // cout << "vectp : " << gmm::mat_col(Q, n-2) << endl;
70 // double emax, emin;
71 // cout << "condition number" << condition_number(MM,emax,emin) << endl;
72 // cout << "emin = " << emin << endl;
73 // cout << "emax = " << emax << endl;
74  }
75 
76 
77  /* ***************************************************************** */
78  /* Linear solvers definition */
79  /* ***************************************************************** */
80 
81  template <typename MAT, typename VECT>
82  struct abstract_linear_solver {
83  typedef MAT MATRIX;
84  typedef VECT VECTOR;
85  virtual void operator ()(const MAT &, VECT &, const VECT &,
86  gmm::iteration &) const = 0;
87  virtual ~abstract_linear_solver() {}
88  };
89 
90  template <typename MAT, typename VECT>
91  struct linear_solver_cg_preconditioned_ildlt
92  : public abstract_linear_solver<MAT, VECT> {
93  void operator ()(const MAT &M, VECT &x, const VECT &b,
94  gmm::iteration &iter) const {
96  gmm::cg(M, x, b, P, iter);
97  if (!iter.converged()) GMM_WARNING2("cg did not converge!");
98  }
99  };
100 
101  template <typename MAT, typename VECT>
102  struct linear_solver_gmres_preconditioned_ilu
103  : public abstract_linear_solver<MAT, VECT> {
104  void operator ()(const MAT &M, VECT &x, const VECT &b,
105  gmm::iteration &iter) const {
107  gmm::gmres(M, x, b, P, 500, iter);
108  if (!iter.converged()) GMM_WARNING2("gmres did not converge!");
109  }
110  };
111 
112  template <typename MAT, typename VECT>
113  struct linear_solver_gmres_unpreconditioned
114  : public abstract_linear_solver<MAT, VECT> {
115  void operator ()(const MAT &M, VECT &x, const VECT &b,
116  gmm::iteration &iter) const {
117  gmm::identity_matrix P;
118  gmm::gmres(M, x, b, P, 500, iter);
119  if (!iter.converged()) GMM_WARNING2("gmres did not converge!");
120  }
121  };
122 
123  template <typename MAT, typename VECT>
124  struct linear_solver_gmres_preconditioned_ilut
125  : public abstract_linear_solver<MAT, VECT> {
126  void operator ()(const MAT &M, VECT &x, const VECT &b,
127  gmm::iteration &iter) const {
128  gmm::ilut_precond<MAT> P(M, 40, 1E-7);
129  gmm::gmres(M, x, b, P, 500, iter);
130  if (!iter.converged()) GMM_WARNING2("gmres did not converge!");
131  }
132  };
133 
134  template <typename MAT, typename VECT>
135  struct linear_solver_gmres_preconditioned_ilutp
136  : public abstract_linear_solver<MAT, VECT> {
137  void operator ()(const MAT &M, VECT &x, const VECT &b,
138  gmm::iteration &iter) const {
139  gmm::ilutp_precond<MAT> P(M, 20, 1E-7);
140  gmm::gmres(M, x, b, P, 500, iter);
141  if (!iter.converged()) GMM_WARNING2("gmres did not converge!");
142  }
143  };
144 
145 #if defined(GMM_USES_SUPERLU)
146  template <typename MAT, typename VECT>
147  struct linear_solver_superlu
148  : public abstract_linear_solver<MAT, VECT> {
149  void operator ()(const MAT &M, VECT &x, const VECT &b,
150  gmm::iteration &iter) const {
151  double rcond;
152  /*gmm::HarwellBoeing_IO::write("test.hb", M);
153  std::fstream f("bbb", std::ios::out);
154  for (unsigned i=0; i < gmm::vect_size(b); ++i) f << b[i] << "\n";*/
155  int info = gmm::SuperLU_solve(M, x, b, rcond);
156  iter.enforce_converged(info == 0);
157  if (iter.get_noisy()) cout << "condition number: " << 1.0/rcond<< endl;
158  }
159  };
160 #endif
161 
162  template <typename MAT, typename VECT>
163  struct linear_solver_dense_lu : public abstract_linear_solver<MAT, VECT> {
164  void operator ()(const MAT &M, VECT &x, const VECT &b,
165  gmm::iteration &iter) const {
166  typedef typename gmm::linalg_traits<MAT>::value_type T;
167  gmm::dense_matrix<T> MM(gmm::mat_nrows(M),gmm::mat_ncols(M));
168  gmm::copy(M, MM);
169  gmm::lu_solve(MM, x, b);
170  iter.enforce_converged(true);
171  }
172  };
173 
174 #if defined(GMM_USES_MUMPS)
175  template <typename MAT, typename VECT>
176  struct linear_solver_mumps : public abstract_linear_solver<MAT, VECT> {
177  void operator ()(const MAT &M, VECT &x, const VECT &b,
178  gmm::iteration &iter) const {
179  bool ok = gmm::MUMPS_solve(M, x, b, false);
180  iter.enforce_converged(ok);
181  }
182  };
183  template <typename MAT, typename VECT>
184  struct linear_solver_mumps_sym : public abstract_linear_solver<MAT, VECT> {
185  void operator ()(const MAT &M, VECT &x, const VECT &b,
186  gmm::iteration &iter) const {
187  bool ok = gmm::MUMPS_solve(M, x, b, true);
188  iter.enforce_converged(ok);
189  }
190  };
191 #endif
192 
193 #if GETFEM_PARA_LEVEL > 1 && GETFEM_PARA_SOLVER == MUMPS_PARA_SOLVER
194  template <typename MAT, typename VECT>
195  struct linear_solver_distributed_mumps
196  : public abstract_linear_solver<MAT, VECT> {
197  void operator ()(const MAT &M, VECT &x, const VECT &b,
198  gmm::iteration &iter) const {
199  double tt_ref=MPI_Wtime();
200  bool ok = MUMPS_distributed_matrix_solve(M, x, b, false);
201  iter.enforce_converged(ok);
202  if (MPI_IS_MASTER()) cout<<"UNSYMMETRIC MUMPS time "<< MPI_Wtime() - tt_ref<<endl;
203  }
204  };
205 
206  template <typename MAT, typename VECT>
207  struct linear_solver_distributed_mumps_sym
208  : public abstract_linear_solver<MAT, VECT> {
209  void operator ()(const MAT &M, VECT &x, const VECT &b,
210  gmm::iteration &iter) const {
211  double tt_ref=MPI_Wtime();
212  bool ok = MUMPS_distributed_matrix_solve(M, x, b, true);
213  iter.enforce_converged(ok);
214  if (MPI_IS_MASTER()) cout<<"SYMMETRIC MUMPS time "<< MPI_Wtime() - tt_ref<<endl;
215  }
216  };
217 #endif
218 
219 
220  /* ***************************************************************** */
221  /* Newton Line search definition */
222  /* ***************************************************************** */
223 
224  struct abstract_newton_line_search {
225  double conv_alpha, conv_r;
226  size_t it, itmax, glob_it;
227  // size_t tot_it;
228  virtual void init_search(double r, size_t git, double R0 = 0.0) = 0;
229  virtual double next_try(void) = 0;
230  virtual bool is_converged(double, double R1 = 0.0) = 0;
231  virtual double converged_value(void) {
232  // tot_it += it; cout << "tot_it = " << tot_it << endl; it = 0;
233  return conv_alpha;
234  };
235  virtual double converged_residual(void) { return conv_r; };
236  virtual ~abstract_newton_line_search() { }
237  };
238 
239  // Dummy linesearch for the newton with step control
240  struct newton_search_with_step_control : public abstract_newton_line_search {
241 
242  virtual void init_search(double /*r*/, size_t /*git*/, double /*R0*/ = 0.0)
243  { GMM_ASSERT1(false, "Not to be used"); }
244 
245  virtual double next_try(void)
246  { GMM_ASSERT1(false, "Not to be used"); }
247 
248  virtual bool is_converged(double /*r*/, double /*R1*/ = 0.0)
249  { GMM_ASSERT1(false, "Not to be used"); }
250 
251  newton_search_with_step_control() {}
252  };
253 
254 
255  struct quadratic_newton_line_search : public abstract_newton_line_search {
256  double R0_, R1_;
257 
258  double alpha, first_res;
259  virtual void init_search(double r, size_t git, double R0 = 0.0) {
260  GMM_ASSERT1(R0 != 0.0, "You have to specify R0");
261  glob_it = git;
262  conv_alpha = alpha = double(1); conv_r = first_res = r; it = 0;
263  R0_ = R0;
264  }
265  virtual double next_try(void) {
266  ++it;
267  if (it == 1) return double(1);
268  GMM_ASSERT1(R1_ != 0.0, "You have to specify R1");
269  double a = R0_ / R1_;
270  return (a < 0) ? (a*0.5 + sqrt(a*a*0.25-a)) : a*0.5;
271  }
272  virtual bool is_converged(double r, double R1 = 0.0) {
273  conv_r = r;
274  R1_ = R1; return ((gmm::abs(R1_) < gmm::abs(R0_*0.5)) || it >= itmax);
275  }
276  quadratic_newton_line_search(size_t imax = size_t(-1)) { itmax = imax; }
277  };
278 
279 
280  struct simplest_newton_line_search : public abstract_newton_line_search {
281  double alpha, alpha_mult, first_res, alpha_max_ratio, alpha_min,
282  alpha_threshold_res;
283  virtual void init_search(double r, size_t git, double = 0.0) {
284  glob_it = git;
285  conv_alpha = alpha = double(1); conv_r = first_res = r; it = 0;
286  }
287  virtual double next_try(void)
288  { conv_alpha = alpha; alpha *= alpha_mult; ++it; return conv_alpha; }
289  virtual bool is_converged(double r, double = 0.0) {
290  conv_r = r;
291  return ((it <= 1 && r < first_res)
292  || (r <= first_res * alpha_max_ratio && r <= alpha_threshold_res)
293  || (conv_alpha <= alpha_min && r < first_res * 1e5)
294  || it >= itmax);
295  }
296  simplest_newton_line_search
297  (size_t imax = size_t(-1), double a_max_ratio = 6.0/5.0,
298  double a_min = 1.0/1000.0, double a_mult = 3.0/5.0,
299  double a_threshold_res = 1e50)
300  : alpha_mult(a_mult), alpha_max_ratio(a_max_ratio), alpha_min(a_min),
301  alpha_threshold_res(a_threshold_res)
302  { itmax = imax; }
303  };
304 
305  struct default_newton_line_search : public abstract_newton_line_search {
306  // This line search try to detect where is the minimum, dividing the step
307  // by a factor two each time.
308  // - it stops if the residual is less than the previous residual
309  // times alpha_min_ratio (= 0.9).
310  // - if the minimal step is reached with a residual greater than
311  // the previous residual times alpha_min_ratio then it decides
312  // between two options :
313  // - return with the step corresponding to the smallest residual
314  // - return with a greater residual corresponding to a residual
315  // less than the previous residual times alpha_max_ratio.
316  // the decision is taken regarding the previous iterations.
317  // - in order to shorten the line search, the process stops when
318  // the residual increases three times consecutively.
319  // possible improvment : detect the curvature at the origin
320  // (only one evaluation) and take it into account.
321  // Fitted to some experiments in contrib/tests_newton
322 
323  double alpha, alpha_old, alpha_mult, first_res, alpha_max_ratio;
324  double alpha_min_ratio, alpha_min;
325  size_type count, count_pat;
326  bool max_ratio_reached;
327  double alpha_max_ratio_reached, r_max_ratio_reached;
328  size_type it_max_ratio_reached;
329 
330  virtual void init_search(double r, size_t git, double = 0.0);
331  virtual double next_try(void);
332  virtual bool is_converged(double r, double = 0.0);
333  default_newton_line_search(void) { count_pat = 0; }
334  };
335 
336  /* the former default_newton_line_search */
337  struct basic_newton_line_search : public abstract_newton_line_search {
338  double alpha, alpha_mult, first_res, alpha_max_ratio;
339  double alpha_min, prev_res, alpha_max_augment;
340  virtual void init_search(double r, size_t git, double = 0.0) {
341  glob_it = git;
342  conv_alpha = alpha = double(1);
343  prev_res = conv_r = first_res = r; it = 0;
344  }
345  virtual double next_try(void)
346  { conv_alpha = alpha; alpha *= alpha_mult; ++it; return conv_alpha; }
347  virtual bool is_converged(double r, double = 0.0) {
348  if (glob_it == 0 || (r < first_res / double(2))
349  || (conv_alpha <= alpha_min && r < first_res * alpha_max_augment)
350  || it >= itmax)
351  { conv_r = r; return true; }
352  if (it > 1 && r > prev_res && prev_res < alpha_max_ratio * first_res)
353  return true;
354  prev_res = conv_r = r;
355  return false;
356  }
357  basic_newton_line_search
358  (size_t imax = size_t(-1),
359  double a_max_ratio = 5.0/3.0,
360  double a_min = 1.0/1000.0, double a_mult = 3.0/5.0, double a_augm = 2.0)
361  : alpha_mult(a_mult), alpha_max_ratio(a_max_ratio),
362  alpha_min(a_min), alpha_max_augment(a_augm) { itmax = imax; }
363  };
364 
365 
366  struct systematic_newton_line_search : public abstract_newton_line_search {
367  double alpha, alpha_mult, first_res;
368  double alpha_min, prev_res;
369  bool first;
370  virtual void init_search(double r, size_t git, double = 0.0) {
371  glob_it = git;
372  conv_alpha = alpha = double(1);
373  prev_res = conv_r = first_res = r; it = 0; first = true;
374  }
375  virtual double next_try(void)
376  { double a = alpha; alpha *= alpha_mult; ++it; return a; }
377  virtual bool is_converged(double r, double = 0.0) {
378  // cout << "a = " << alpha / alpha_mult << " r = " << r << endl;
379  if (r < conv_r || first)
380  { conv_r = r; conv_alpha = alpha / alpha_mult; first = false; }
381  if ((alpha <= alpha_min*alpha_mult) || it >= itmax) return true;
382  return false;
383  }
384  systematic_newton_line_search
385  (size_t imax = size_t(-1),
386  double a_min = 1.0/10000.0, double a_mult = 3.0/5.0)
387  : alpha_mult(a_mult), alpha_min(a_min) { itmax = imax; }
388  };
389 
390 
391  /* ***************************************************************** */
392  /* Newton(-Raphson) algorithm with step control. */
393  /* ***************************************************************** */
394  /* Still solves a problem F(X) = 0 starting at X0 but setting */
395  /* B0 = F(X0) and solving */
396  /* F(X) = (1-alpha)B0 (1) */
397  /* with alpha growing from 0 to 1. */
398  /* A very basic line search is applied. */
399  /* */
400  /* Step 0 : set alpha0 = 0, alpha = 1, X0 given and B0 = F(X0). */
401  /* Step 1 : Set Ri = F(Xi) - (1-alpha)B0 */
402  /* If ||Ri|| < rho, Xi+1 = Xi and go to step 2 */
403  /* Perform Newton step on problem (1) */
404  /* If the Newton do not converge (stagnation) */
405  /* alpha <- max(alpha0+1E-4, (alpha+alpha0)/2) */
406  /* Loop on step 1 with Xi unchanged */
407  /* Step 2 : if alpha=1 stop */
408  /* else alpha0 <- alpha, */
409  /* alpha <- min(1,alpha0+2*(alpha-alpha0)), */
410  /* Go to step 1 with Xi+1 */
411  /* being the result of Newton iterations of step1. */
412  /* */
413  /*********************************************************************/
414 
415  template <typename PB>
416  void Newton_with_step_control(PB &pb, gmm::iteration &iter)
417  {
418  typedef typename gmm::linalg_traits<typename PB::VECTOR>::value_type T;
419  typedef typename gmm::number_traits<T>::magnitude_type R;
420  gmm::iteration iter_linsolv0 = iter;
421  iter_linsolv0.reduce_noisy();
422  iter_linsolv0.set_resmax(iter.get_resmax()/20.0);
423  iter_linsolv0.set_maxiter(10000); // arbitrary
424 
425  pb.compute_residual();
426  R approx_eln = pb.approx_external_load_norm();
427  if (approx_eln == R(0)) approx_eln = R(1);
428 
429  typename PB::VECTOR b0(gmm::vect_size(pb.residual()));
430  gmm::copy(pb.residual(), b0);
431  typename PB::VECTOR Xi(gmm::vect_size(pb.residual()));
432  gmm::copy(pb.state_vector(), Xi);
433 
434  typename PB::VECTOR dr(gmm::vect_size(pb.residual()));
435 
436  R alpha0(0), alpha(1), res0(gmm::vect_norm1(b0)), minres(res0);
437  // const newton_search_with_step_control *ls
438  // = dynamic_cast<const newton_search_with_step_control *>(&(pb.ls));
439  // GMM_ASSERT1(ls, "Internal error");
440  size_type nit = 0, stagn = 0;
441  R coeff = R(2);
442 
443  scalar_type crit = pb.residual_norm() / approx_eln;
444  if (iter.finished(crit)) return;
445  for(;;) {
446 
447  crit = gmm::vect_dist1(pb.residual(), gmm::scaled(b0, R(1)-alpha))
448  / approx_eln;
449  if (!iter.converged(crit)) {
450  gmm::iteration iter_linsolv = iter_linsolv0;
451 
452  int is_singular = 1;
453  while (is_singular) { // Linear system solve
454  gmm::clear(dr);
455  pb.add_to_residual(b0, alpha-R(1)); // canceled at next compute_residual
456  iter_linsolv.init();
457  if (iter.get_noisy() > 1)
458  cout << "starting tangent matrix computation" << endl;
459  pb.compute_tangent_matrix();
460  if (iter.get_noisy() > 1)
461  cout << "starting linear solver" << endl;
462  pb.linear_solve(dr, iter_linsolv);
463  if (!iter_linsolv.converged()) {
464  is_singular++;
465  if (is_singular <= 4) {
466  if (iter.get_noisy())
467  cout << "Singular tangent matrix:"
468  " perturbation of the state vector." << endl;
469  pb.perturbation();
470  pb.compute_residual(); // cancels add_to_residual
471  } else {
472  if (iter.get_noisy())
473  cout << "Singular tangent matrix: perturbation failed, "
474  << "aborting." << endl;
475  return;
476  }
477  }
478  else is_singular = 0;
479  }
480  if (iter.get_noisy() > 1) cout << "linear solver done" << endl;
481 
482  gmm::add(dr, pb.state_vector());
483  pb.compute_residual(); // cancels add_to_residual
484  R res = gmm::vect_dist1(pb.residual(), gmm::scaled(b0, R(1)-alpha));
485  R dec = R(1)/R(2), coeff2 = coeff * R(1.5);
486 
487  while (dec > R(1E-5) && res >= res0 * coeff) {
488  gmm::add(gmm::scaled(dr, -dec), pb.state_vector());
489  pb.compute_residual();
490  R res2 = gmm::vect_dist1(pb.residual(), gmm::scaled(b0, R(1)-alpha));
491  if (res2 < res*R(0.95) || res2 >= res0 * coeff2) {
492  dec /= R(2); res = res2; coeff2 *= R(1.5);
493  } else {
494  gmm::add(gmm::scaled(dr, dec), pb.state_vector());
495  break;
496  }
497  }
498  dec *= R(2);
499 
500  nit++;
501  coeff = std::max(R(1.05), coeff*R(0.93));
502  bool near_end = (iter.get_iteration() > iter.get_maxiter()/2);
503  bool cut = (alpha < R(1)) && near_end;
504  if ((res > minres && nit > 4) || cut) {
505  stagn++;
506 
507  if ((stagn > 10 && alpha > alpha0 + R(5E-2)) || cut) {
508  alpha = (alpha + alpha0) / R(2);
509  if (near_end) alpha = R(1);
510  gmm::copy(Xi, pb.state_vector());
511  pb.compute_residual();
512  res = gmm::vect_dist1(pb.residual(), gmm::scaled(b0, R(1)-alpha));
513  nit = 0;
514  stagn = 0; coeff = R(2);
515  }
516  }
517  if (res < minres || (alpha == R(1) && nit < 10)) stagn = 0;
518  res0 = res;
519  if (nit < 5) minres = res0; else minres = std::min(minres, res0);
520 
521  if (iter.get_noisy())
522  cout << "step control [" << std::setw(8) << alpha0 << ","
523  << std::setw(8) << alpha << "," << std::setw(10) << dec << "]";
524  ++iter;
525  // crit = std::min(res / approx_eln,
526  // gmm::vect_norm1(dr) / std::max(1E-25,pb.state_norm()));
527  crit = res / approx_eln;
528  }
529 
530  if (iter.finished(crit)) {
531  if (iter.converged() && alpha < R(1)) {
532  R a = alpha;
533  alpha = std::min(R(1), alpha*R(3) - alpha0*R(2));
534  alpha0 = a;
535  gmm::copy(pb.state_vector(), Xi);
536  nit = 0; stagn = 0; coeff = R(2);
537  } else return;
538  }
539  }
540  }
541 
542 
543 
544  /* ***************************************************************** */
545  /* Classical Newton(-Raphson) algorithm. */
546  /* ***************************************************************** */
547 
548  template <typename PB>
549  void classical_Newton(PB &pb, gmm::iteration &iter)
550  {
551  typedef typename gmm::linalg_traits<typename PB::VECTOR>::value_type T;
552  typedef typename gmm::number_traits<T>::magnitude_type R;
553  gmm::iteration iter_linsolv0 = iter;
554  iter_linsolv0.reduce_noisy();
555  iter_linsolv0.set_resmax(iter.get_resmax()/20.0);
556  iter_linsolv0.set_maxiter(10000); // arbitrary
557 
558  pb.compute_residual();
559  R approx_eln = pb.approx_external_load_norm();
560  if (approx_eln == R(0)) approx_eln = R(1);
561 
562  typename PB::VECTOR dr(gmm::vect_size(pb.residual()));
563 
564  scalar_type crit = pb.residual_norm() / approx_eln;
565  while (!iter.finished(crit)) {
566  gmm::iteration iter_linsolv = iter_linsolv0;
567 
568  int is_singular = 1;
569  while (is_singular) {
570  gmm::clear(dr);
571  iter_linsolv.init();
572  if (iter.get_noisy() > 1)
573  cout << "starting computing tangent matrix" << endl;
574  pb.compute_tangent_matrix();
575  if (iter.get_noisy() > 1)
576  cout << "starting linear solver" << endl;
577  pb.linear_solve(dr, iter_linsolv);
578  if (!iter_linsolv.converged()) {
579  is_singular++;
580  if (is_singular <= 4) {
581  if (iter.get_noisy())
582  cout << "Singular tangent matrix:"
583  " perturbation of the state vector." << endl;
584  pb.perturbation();
585  pb.compute_residual();
586  } else {
587  if (iter.get_noisy())
588  cout << "Singular tangent matrix: perturbation failed, aborting."
589  << endl;
590  return;
591  }
592  }
593  else is_singular = 0;
594  }
595 
596  if (iter.get_noisy() > 1) cout << "linear solver done" << endl;
597  R alpha = pb.line_search(dr, iter); //it is assumed that the linesearch
598  //executes a pb.compute_residual();
599  if (iter.get_noisy()) cout << "alpha = " << std::setw(6) << alpha << " ";
600  ++iter;
601  crit = std::min(pb.residual_norm() / approx_eln,
602  gmm::vect_norm1(dr) / std::max(1E-25, pb.state_norm()));
603  }
604  }
605 
606 
607 
608  //---------------------------------------------------------------------
609  // Default linear solver.
610  //---------------------------------------------------------------------
611 
612  typedef std::shared_ptr<abstract_linear_solver<model_real_sparse_matrix,
613  model_real_plain_vector> >
614  rmodel_plsolver_type;
615  typedef std::shared_ptr<abstract_linear_solver<model_complex_sparse_matrix,
616  model_complex_plain_vector> >
617  cmodel_plsolver_type;
618 
619  template<typename MATRIX, typename VECTOR>
620  std::shared_ptr<abstract_linear_solver<MATRIX, VECTOR>>
621  default_linear_solver(const model &md) {
622 
623 #if GETFEM_PARA_LEVEL == 1 && GETFEM_PARA_SOLVER == MUMPS_PARA_SOLVER
624  if (md.is_symmetric())
625  return std::make_shared<linear_solver_mumps_sym<MATRIX, VECTOR>>();
626  else
627  return std::make_shared<linear_solver_mumps<MATRIX, VECTOR>>();
628 #elif GETFEM_PARA_LEVEL > 1 && GETFEM_PARA_SOLVER == MUMPS_PARA_SOLVER
629  if (md.is_symmetric())
630  return std::make_shared
631  <linear_solver_distributed_mumps_sym<MATRIX, VECTOR>>();
632  else
633  return std::make_shared
634  <linear_solver_distributed_mumps<MATRIX, VECTOR>>();
635 #else
636  size_type ndof = md.nb_dof(), max3d = 15000, dim = md.leading_dimension();
637 # if defined(GMM_USES_MUMPS)
638  max3d = 250000;
639 # endif
640  if ((ndof<300000 && dim<=2) || (ndof<max3d && dim<=3) || (ndof<1000)) {
641 # if defined(GMM_USES_MUMPS)
642  if (md.is_symmetric())
643  return std::make_shared<linear_solver_mumps_sym<MATRIX, VECTOR>>();
644  else
645  return std::make_shared<linear_solver_mumps<MATRIX, VECTOR>>();
646 # elif defined(GMM_USES_SUPERLU)
647  return std::make_shared<linear_solver_superlu<MATRIX, VECTOR>>();
648 # else
649  static_assert(false,
650  "At least one direct solver (MUMPS or SuperLU) is required");
651 # endif
652  }
653  else {
654  if (md.is_coercive())
655  return std::make_shared
656  <linear_solver_cg_preconditioned_ildlt<MATRIX, VECTOR>>();
657  else {
658  if (dim <= 2)
659  return std::make_shared
660  <linear_solver_gmres_preconditioned_ilut<MATRIX,VECTOR>>();
661  else
662  return std::make_shared
663  <linear_solver_gmres_preconditioned_ilu<MATRIX,VECTOR>>();
664  }
665  }
666 #endif
667  return std::shared_ptr<abstract_linear_solver<MATRIX, VECTOR>>();
668  }
669 
670  template <typename MATRIX, typename VECTOR>
671  std::shared_ptr<abstract_linear_solver<MATRIX, VECTOR>>
672  select_linear_solver(const model &md, const std::string &name) {
673  std::shared_ptr<abstract_linear_solver<MATRIX, VECTOR>> p;
674  if (bgeot::casecmp(name, "superlu") == 0) {
675 #if defined(GMM_USES_SUPERLU)
676  return std::make_shared<linear_solver_superlu<MATRIX, VECTOR>>();
677 #else
678  GMM_ASSERT1(false, "SuperLU is not interfaced");
679 #endif
680  }
681  else if (bgeot::casecmp(name, "dense_lu") == 0)
682  return std::make_shared<linear_solver_dense_lu<MATRIX, VECTOR>>();
683  else if (bgeot::casecmp(name, "mumps") == 0) {
684 #if defined(GMM_USES_MUMPS)
685 # if GETFEM_PARA_LEVEL <= 1
686  return std::make_shared<linear_solver_mumps<MATRIX, VECTOR>>();
687 # else
688  return std::make_shared
689  <linear_solver_distributed_mumps<MATRIX, VECTOR>>();
690 # endif
691 #else
692  GMM_ASSERT1(false, "Mumps is not interfaced");
693 #endif
694  }
695  else if (bgeot::casecmp(name, "cg/ildlt") == 0)
696  return std::make_shared
697  <linear_solver_cg_preconditioned_ildlt<MATRIX, VECTOR>>();
698  else if (bgeot::casecmp(name, "gmres/ilu") == 0)
699  return std::make_shared
700  <linear_solver_gmres_preconditioned_ilu<MATRIX, VECTOR>>();
701  else if (bgeot::casecmp(name, "gmres/ilut") == 0)
702  return std::make_shared
703  <linear_solver_gmres_preconditioned_ilut<MATRIX, VECTOR>>();
704  else if (bgeot::casecmp(name, "gmres/ilutp") == 0)
705  return std::make_shared
706  <linear_solver_gmres_preconditioned_ilutp<MATRIX, VECTOR>>();
707  else if (bgeot::casecmp(name, "auto") == 0)
708  return default_linear_solver<MATRIX, VECTOR>(md);
709  else
710  GMM_ASSERT1(false, "Unknown linear solver");
711  return std::shared_ptr<abstract_linear_solver<MATRIX, VECTOR>>();
712  }
713 
714  inline rmodel_plsolver_type rselect_linear_solver(const model &md,
715  const std::string &name) {
716  return select_linear_solver<model_real_sparse_matrix,
717  model_real_plain_vector>(md, name);
718  }
719 
720  inline cmodel_plsolver_type cselect_linear_solver(const model &md,
721  const std::string &name) {
722  return select_linear_solver<model_complex_sparse_matrix,
723  model_complex_plain_vector>(md, name);
724  }
725 
726  //---------------------------------------------------------------------
727  // Standard solve.
728  //---------------------------------------------------------------------
729 
730 
731  /** A default solver for the model brick system.
732  Of course it could be not very well suited for a particular
733  problem, so it could be copied and adapted to change solvers,
734  add a special traitement on the problem, etc ... This is in
735  fact a model for your own solver.
736 
737  For small problems, a direct solver is used (gmm::SuperLU_solve),
738  for larger problems, a conjugate gradient gmm::cg (if the problem is
739  coercive) or a gmm::gmres is used (preconditioned with an incomplete
740  factorization).
741 
742  When MPI/METIS is enabled, a partition is done via METIS, and a parallel
743  solver can be used.
744 
745  Note that it is possible to disable some variables
746  (see the md.disable_variable(varname) method) in order to
747  solve the problem only with respect to a subset of variables (the
748  disabled variables are the considered as data) for instance to
749  replace the global Newton strategy with a fixed point one.
750 
751  @ingroup bricks
752  */
753  void standard_solve(model &md, gmm::iteration &iter,
754  rmodel_plsolver_type lsolver,
755  abstract_newton_line_search &ls);
756 
757  void standard_solve(model &md, gmm::iteration &iter,
758  cmodel_plsolver_type lsolver,
759  abstract_newton_line_search &ls);
760 
761  void standard_solve(model &md, gmm::iteration &iter,
762  rmodel_plsolver_type lsolver);
763 
764  void standard_solve(model &md, gmm::iteration &iter,
765  cmodel_plsolver_type lsolver);
766 
767  void standard_solve(model &md, gmm::iteration &iter);
768 
769 } /* end of namespace getfem. */
770 
771 
772 #endif /* GETFEM_MODEL_SOLVERS_H__ */
Incomplete Level 0 LDLT Preconditioner.
Incomplete LU without fill-in Preconditioner.
Incomplete LU with threshold and K fill-in Preconditioner.
ILUTP: Incomplete LU with threshold and K fill-in Preconditioner and column pivoting.
The Iteration object calculates whether the solution has reached the desired accuracy,...
Definition: gmm_iter.h:53
Model representation in Getfem.
Interface with MUMPS (LU direct solver for sparse matrices).
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:978
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist1(const V1 &v1, const V2 &v2)
1-distance between two vectors
Definition: gmm_blas.h:659
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1277
void lu_solve(const DenseMatrix &LU, const Pvector &pvector, VectorX &x, const VectorB &b)
LU Solve : Solve equation Ax=b, given an LU factored matrix.
Definition: gmm_dense_lu.h:130
Dense QR factorization.
Iteration object.
Include standard gmm iterative solvers (cg, gmres, ...)
void gmres(const Mat &A, Vec &x, const VecB &b, const Precond &M, int restart, iteration &outer, Basis &KS)
Generalized Minimum Residual.
Interface with SuperLU (LU direct solver for sparse matrices).
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree .
Definition: bgeot_poly.cc:47
GEneric Tool for Finite Element Methods.
void standard_solve(model &md, gmm::iteration &iter, rmodel_plsolver_type lsolver, abstract_newton_line_search &ls)
A default solver for the model brick system.