Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_linear_solver_mgmres.F90
Go to the documentation of this file.
1 
10 
12  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 #include "sll_working_precision.h"
14 
17 
20 
21  use sll_m_linear_solver_abstract, only: &
23 
24  implicit none
25 
26  public :: &
28 
29  private
30  ! ..................................................
31  sll_int32, parameter :: sll_solver_bool_false = 0
32  sll_int32, parameter :: sll_solver_maxiter = 1000
33  sll_real64, parameter :: sll_solver_tolerance = 1.0d-9
34  sll_int32, parameter :: sll_solver_restart = 30
35  ! ..................................................
39  sll_int32 :: n_mr = 2
40  sll_real64 :: rtol = 1.0d-14
41 
42  contains
43  procedure :: create => create_linear_solver_mgmres
44  procedure :: initialize => initialize_linear_solver_mgmres
45  procedure :: set_guess => set_guess_linear_solver_mgmres
46  procedure :: check_convergence => check_convergence_linear_solver_mgmres
47 
48  procedure :: read_from_file => read_from_file_linear_solver_mgmres
49  procedure :: set_verbose => set_verbose_linear_solver_mgmres
50  procedure :: solve_real => solve_real_linear_solver_mgmres
51  procedure :: print_info => print_info_linear_solver_mgmres
52  procedure :: free => free_linear_solver_mgmres
53 
55  ! ..................................................
56 
57 contains
58 
59  ! ..................................................
67  subroutine create_linear_solver_mgmres(self, linear_operator, pc_left, filename)
68  implicit none
69  class(sll_t_linear_solver_mgmres) , intent(inout) :: self
70  class(sll_t_linear_operator_abstract) , target, intent(in) :: linear_operator
71  class(sll_t_linear_solver_abstract) , optional, target, intent(in) :: pc_left
72  character(len=*), optional, intent(in) :: filename
73 
74  ! ...
75  if (present(pc_left)) then
76  self%ptr_pc_left => pc_left
77  end if
78  ! ...
79 
80  ! ...
81  call self%initialize(linear_operator)
82  ! ...
83 
84  ! ...
85  allocate(self%x_0(self%n_total_rows))
86  self%x_0 = 0.0_f64
87  ! ...
88 
89  ! ...
90  if (present(filename)) then
91  call self%read_from_file(filename)
92  end if
93  ! ...
94 
95  end subroutine create_linear_solver_mgmres
96  ! ..................................................
97 
98  ! ..................................................
104  subroutine initialize_linear_solver_mgmres(self, linear_operator, x_0)
105  implicit none
106  class(sll_t_linear_solver_mgmres), intent(inout) :: self
107  class(sll_t_linear_operator_abstract), target, intent(in) :: linear_operator
108  sll_real64,dimension(:), optional, intent(in) :: x_0
109 
110  ! ...
111  if (present(x_0)) then
112  self%x_0 = x_0
113  end if
114  ! ...
115 
116  ! ... linear solver abstract initialization
117  call self%initialize_abstract(linear_operator)
118  ! ...
119 
120  ! ... iterative linear solver abstract initialization
121  call self%set_linear_operator(linear_operator)
122  ! ...
123 
124  end subroutine initialize_linear_solver_mgmres
125  ! ..................................................
126 
127  ! ..................................................
132  subroutine set_guess_linear_solver_mgmres(self, x_0)
133  implicit none
134  class(sll_t_linear_solver_mgmres), intent(inout) :: self
135  sll_real64,dimension(:), intent(in) :: x_0
136 
137  self%x_0 = x_0
138 
139  end subroutine set_guess_linear_solver_mgmres
140  ! ..................................................
141 
142  ! ..................................................
150  ! ............................................
151  subroutine check_convergence_linear_solver_mgmres(self, i_iteration, flag, r_err, arr_err)
152  implicit none
153  class(sll_t_linear_solver_mgmres), intent(in) :: self
154  sll_int32, intent(in) :: i_iteration
155  logical, intent(inout) :: flag
156  sll_real64, optional, intent(in) :: r_err
157  sll_real64, dimension(:), optional, intent(in) :: arr_err
158 
159  ! ...
160  if (self%verbose) then
161  if (present(r_err)) then
162  if (i_iteration <= self%n_maxiter) then
163  print*, '* mgmres: convegence after', i_iteration, 'iterations. Error ', r_err
164  else
165  print *, '* mgmres: Warning - max iterations', self%n_maxiter, 'achieved without convergence. Error', r_err
166  end if
167  end if
168  end if
169  !...
170 
172  ! ............................................
173 
174  ! ..................................................
179  subroutine read_from_file_linear_solver_mgmres(self, filename)
180  implicit none
181  class(sll_t_linear_solver_mgmres), intent(inout) :: self
182  character(len=*) , intent(in) :: filename
183  ! local
184  sll_int32, parameter :: input_file_id = 111
185  sll_int32 :: int_maxiter = sll_solver_maxiter
186  sll_int32 :: int_restart = sll_solver_restart
187  sll_int32 :: int_null_space = sll_solver_bool_false
188  sll_int32 :: int_verbose = sll_solver_bool_false
189  sll_real64 :: real_rtol = sll_solver_tolerance
190  sll_real64 :: real_atol = sll_solver_tolerance
191 
192  ! ...
193  namelist /linear_solver/ int_null_space, &
194  & int_maxiter, &
195  & int_restart, &
196  & real_rtol, &
197  & real_atol, &
198  & int_verbose
199  ! ...
200 
201  ! ...
202  open(unit=input_file_id, file=trim(filename))
203  read( input_file_id, linear_solver)
204  ! ...
205 
206  ! ...
207  self%n_maxiter = int_maxiter
208  self%n_mr = int_restart
209  self%rtol = real_rtol
210  self%atol = real_atol
211  ! ...
212 
213  ! ...
214  self%null_space = .false.
215  if (int_null_space == 1) then
216  self%null_space = .true.
217  end if
218  ! ...
219 
220  ! ...
221  self%verbose = .false.
222  if (int_verbose == 1) then
223  self%verbose = .true.
224  end if
225  ! ...
226 
227  ! ...
228  close(input_file_id)
229  ! ...
230 
232  ! ..................................................
233 
234  ! ............................................
239  subroutine set_verbose_linear_solver_mgmres(self, verbose)
240  implicit none
241  class(sll_t_linear_solver_mgmres), intent(inout) :: self
242  logical , intent(in) :: verbose
243 
244  ! ...
245  call self%set_verbose_abstract(verbose)
246  ! ...
247 
248  end subroutine set_verbose_linear_solver_mgmres
249  ! ..................................................
250 
251  ! ..................................................
257  subroutine solve_real_linear_solver_mgmres(self, rhs, unknown)
258  implicit none
259  class(sll_t_linear_solver_mgmres), intent(inout) :: self
260  sll_real64, dimension(:), intent(in ) :: rhs
261  sll_real64, dimension(:), intent( out) :: unknown
262  ! local
263  sll_real64, dimension(:), allocatable :: l_rhs
264  sll_int32 :: itr_used
265  sll_real64 :: res
266  logical :: flag
267 
268  ! ...
269  allocate(l_rhs(self%n_total_rows))
270  l_rhs = rhs
271  ! ...
272 
273  ! ...
274  if (associated(self%ptr_pc_left)) then
275  call self%ptr_pc_left % solve(rhs, l_rhs)
276  end if
277  ! ...
278 
279  ! ...
280  unknown = self%x_0
281  ! ...
282 
283  ! ...
284  call mgmres_linear_solver ( self, unknown, l_rhs, &
285  & self%n_maxiter, self%n_mr, &
286  & self%atol, self%rtol, &
287  & itr_used, res)
288  ! ...
289 
290  ! ...
291  deallocate(l_rhs)
292  ! ...
293 
294  ! ...
295  call self%check_convergence( i_iteration=itr_used, &
296  & flag=flag, &
297  & r_err=res)
298  ! ...
299 
300  end subroutine solve_real_linear_solver_mgmres
301  ! ..................................................
302 
303 
304  ! ...................................................
305  subroutine mgmres_linear_solver( self, x, rhs, itr_max, mr, &
306  & tol_abs, tol_rel, itr_used, rho )
307 
308  !*****************************************************************************80
309  !
310  !! mgmres_csr applies restarted gmres to a sparse triplet matrix.
311  !
312  ! discussion:
313  !
314  ! the linear system a*x=b is solved iteratively.
315  !
316  ! the matrix a is assumed to be stored in sparse triplet form. only
317  ! the nonzero entries of a are stored. for instance, the k-th nonzero
318  ! entry in the matrix is stored by:
319  !
320  ! a(k) = value of entry,
321  ! ia(k) = row of entry,
322  ! ja(k) = column of entry.
323  !
324  ! thanks to jesus pueblas sanchez-guerra for supplying two
325  ! corrections to the code on 31 may 2007.
326  !
327  ! licensing:
328  !
329  ! this code is distributed under the gnu lgpl license.
330  !
331  ! modified:
332  !
333  ! 13 july 2007
334  !
335  ! author:
336  !
337  ! original c version by lili ju.
338  ! fortran90 version by john burkardt.
339  !
340  ! reference:
341  !
342  ! richard barrett, michael berry, tony chan, james demmel,
343  ! june donato, jack dongarra, victor eijkhout, roidan pozo,
344  ! charles romine, henk van der vorst,
345  ! templates for the solution of linear systems:
346  ! building blocks for iterative methods,
347  ! siam, 1994.
348  ! isbn: 0898714710,
349  ! lc: qa297.8.t45.
350  !
351  ! tim kelley,
352  ! iterative methods for linear and nonlinear equations,
353  ! siam, 2004,
354  ! isbn: 0898713528,
355  ! lc: qa297.8.k45.
356  !
357  ! yousef saad,
358  ! iterative methods for sparse linear systems,
359  ! second edition,
360  ! siam, 2003,
361  ! isbn: 0898715342,
362  ! lc: qa188.s17.
363  !
364  ! parameters:
365  !
366  ! input, sll_int32 ( kind = 4 ) n, the order of the linear system.
367  !
368  ! input, sll_int32 ( kind = 4 ) nz_num, the number of nonzero matrix values.
369  !
370  ! input, sll_int32 ( kind = 4 ) ia(nz_num), ja(nz_num), the row and column
371  ! indices of the matrix values.
372  !
373  ! input, real ( kind = 8 ) a(nz_num), the matrix values.
374  !
375  ! input/output, real ( kind = 8 ) x(n); on input, an approximation to
376  ! the solution. on output, an improved approximation.
377  !
378  ! input, real ( kind = 8 ) rhs(n), the right hand side of the linear system.
379  !
380  ! input, sll_int32 ( kind = 4 ) itr_max, the maximum number of (outer)
381  ! iterations to take.
382  !
383  ! input, sll_int32 ( kind = 4 ) mr, the maximum number of (inner) iterations
384  ! to take. 0 < mr <= n.
385  !
386  ! input, real ( kind = 8 ) tol_abs, an absolute tolerance applied to the
387  ! current residual.
388  !
389  ! input, real ( kind = 8 ) tol_rel, a relative tolerance comparing the
390  ! current residual to the initial residual.
391  !
392  implicit none
393  class(sll_t_linear_solver_mgmres), intent(in) :: self
394 
395  sll_int32 :: mr
396 
397  sll_real64 :: av
398  sll_real64 :: c(1:mr)
399  sll_real64, parameter :: delta = 1.0d-03
400  sll_real64 :: g(1:mr+1)
401  sll_real64 :: h(1:mr+1,1:mr)
402  sll_real64 :: htmp
403  sll_int32 :: i
404  sll_int32 :: itr
405  sll_int32 :: itr_max
406  sll_int32 :: itr_used
407  sll_int32 :: j
408  sll_int32 :: k
409  sll_int32 :: k_copy
410  sll_real64 :: mu
411  sll_real64 :: r(1:self%n_total_rows)
412  sll_real64 :: p(1:self%n_total_rows)
413  sll_real64 :: rho
414  sll_real64 :: rho_tol
415  sll_real64 :: rhs(1:self%n_total_rows)
416  sll_real64 :: s(1:mr)
417  sll_real64 :: tol_abs
418  sll_real64 :: tol_rel
419  sll_real64 :: v(1:self%n_total_rows,1:mr+1)
420  ! logical, parameter :: verbose = .false.
421  sll_real64 :: x(1:self%n_total_rows)
422  sll_real64 :: y(1:mr+1)
423 
424  itr_used = 0
425 
426  if ( self%verbose .and. ( self%n_total_rows < mr ) ) then
427  write ( *, '(a)' ) ' '
428  write ( *, '(a)' ) 'mgmres_csr - fatal error!'
429  write ( *, '(a)' ) ' n < mr.'
430  write ( *, '(a,i8)' ) ' n = ', self%n_total_rows
431  write ( *, '(a,i8)' ) ' mr = ', mr
432  stop
433  end if
434 
435  r =0.0_f64
436 
437  do itr = 1, itr_max
438 
439  call self%ptr_linear_operator % dot(x, r)
440 
441  ! ...
442  if (associated(self%ptr_pc_left)) then
443  call self%ptr_pc_left % solve(r, p)
444  r=p
445  end if
446  ! ...
447 
448  r(1:self%n_total_rows) = rhs(1:self%n_total_rows) - r(1:self%n_total_rows)
449 
450  rho = sqrt( dot_product( r(1:self%n_total_rows), r(1:self%n_total_rows) ) )
451 
452  ! if ( self%verbose ) then
453  ! write ( *, '(a,i8,a,g14.6)' ) ' itr = ', itr, ' residual = ', rho
454  ! end if
455 
456  if ( itr == 1 ) then
457  rho_tol = rho * tol_rel
458  end if
459 
460  if ( rho <= rho_tol .or. rho <= tol_abs ) then
461  exit
462  end if
463  v(1:self%n_total_rows,1) = r(1:self%n_total_rows) / rho
464 
465 
466  g(1) = rho
467  g(2:mr+1) = 0.0d+00
468 
469  h(1:mr+1,1:mr) = 0.0d+00
470 
471  do k = 1, mr
472 
473  k_copy = k
474 
475  call self%ptr_linear_operator % dot(v(1:self%n_total_rows,k), v(1:self%n_total_rows,k+1))
476 
477  ! ...
478  if (associated(self%ptr_pc_left)) then
479  call self%ptr_pc_left % solve(v(1:self%n_total_rows,k+1), p)
480  v(1:self%n_total_rows,k+1) = p
481  end if
482  ! ...
483 
484  av = sqrt( dot_product( v(1:self%n_total_rows,k+1), v(1:self%n_total_rows,k+1) ) )
485 
486 
487  do j = 1, k
488  h(j,k) = dot_product( v(1:self%n_total_rows,k+1), v(1:self%n_total_rows,j) )
489  v(1:self%n_total_rows,k+1) = v(1:self%n_total_rows,k+1) - h(j,k) * v(1:self%n_total_rows,j)
490  end do
491 
492  h(k+1,k) = sqrt( dot_product( v(1:self%n_total_rows,k+1), v(1:self%n_total_rows,k+1) ) )
493 
494  if ( av + delta * h(k+1,k) == av ) then
495 
496  do j = 1, k
497  htmp = dot_product( v(1:self%n_total_rows,k+1), v(1:self%n_total_rows,j) )
498  h(j,k) = h(j,k) + htmp
499  v(1:self%n_total_rows,k+1) = v(1:self%n_total_rows,k+1) - htmp * v(1:self%n_total_rows,j)
500  end do
501 
502  h(k+1,k) = sqrt( dot_product( v(1:self%n_total_rows,k+1), v(1:self%n_total_rows,k+1) ) )
503 
504  end if
505 
506  if ( h(k+1,k) /= 0.0d+00 ) then
507  v(1:self%n_total_rows,k+1) = v(1:self%n_total_rows,k+1) / h(k+1,k)
508  end if
509 
510  if ( 1 < k ) then
511 
512  y(1:k+1) = h(1:k+1,k)
513 
514  do j = 1, k - 1
515  call mult_givens ( c(j), s(j), j, y(1:k+1) )
516  end do
517 
518  h(1:k+1,k) = y(1:k+1)
519 
520  end if
521 
522  mu = sqrt( h(k,k)**2 + h(k+1,k)**2 )
523  c(k) = h(k,k) / mu
524  s(k) = -h(k+1,k) / mu
525  h(k,k) = c(k) * h(k,k) - s(k) * h(k+1,k)
526  h(k+1,k) = 0.0d+00
527  call mult_givens ( c(k), s(k), k, g(1:k+1) )
528  rho = abs( g(k+1) )
529 
530  itr_used = itr_used + 1
531 
532  ! if ( self%verbose ) then
533  ! write ( *, '(a,i8,a,g14.6)' ) ' k = ', k, ' residual = ', rho
534  ! end if
535 
536  if ( rho <= rho_tol .or. rho <= tol_abs ) then
537  exit
538  end if
539 
540  end do
541 
542  k = k_copy - 1
543 
544  y(k+1) = g(k+1) / h(k+1,k+1)
545 
546  do i = k, 1, -1
547  y(i) = ( g(i) - dot_product( h(i,i+1:k+1), y(i+1:k+1) ) ) / h(i,i)
548  end do
549 
550  do i = 1, self%n_total_rows
551  x(i) = x(i) + dot_product( v(i,1:k+1), y(1:k+1) )
552  end do
553 
554  if ( rho <= rho_tol .or. rho <= tol_abs ) then
555  exit
556  end if
557 
558  end do
559 
560  if ( self%verbose ) then
561  write ( *, '(a)' ) ' '
562  write ( *, '(a)' ) 'mgmres_csr:'
563  write ( *, '(a,i8)' ) ' iterations = ', itr_used
564  write ( *, '(a,g14.6)' ) ' final residual = ', rho
565  end if
566  return
567  end subroutine mgmres_linear_solver
568  ! ...................................................
569 
570  ! ...................................................
571  subroutine mult_givens ( c, s, k, g )
572 
573  !*****************************************************************************80
574  !
575  !! mult_givens applies a givens rotation to two successive entries of a vector.
576  !
577  ! discussion:
578  !
579  ! in order to make it easier to compare this code with the original c,
580  ! the vector indexing is 0-based.
581  !
582  ! licensing:
583  !
584  ! this code is distributed under the gnu lgpl license.
585  !
586  ! modified:
587  !
588  ! 08 august 2006
589  !
590  ! author:
591  !
592  ! original c version by lili ju.
593  ! fortran90 version by john burkardt.
594  !
595  ! reference:
596  !
597  ! richard barrett, michael berry, tony chan, james demmel,
598  ! june donato, jack dongarra, victor eijkhout, roidan pozo,
599  ! charles romine, henk van der vorst,
600  ! templates for the solution of linear systems:
601  ! building blocks for iterative methods,
602  ! siam, 1994.
603  ! isbn: 0898714710,
604  ! lc: qa297.8.t45.
605  !
606  ! tim kelley,
607  ! iterative methods for linear and nonlinear equations,
608  ! siam, 2004,
609  ! isbn: 0898713528,
610  ! lc: qa297.8.k45.
611  !
612  ! yousef saad,
613  ! iterative methods for sparse linear systems,
614  ! second edition,
615  ! siam, 2003,
616  ! isbn: 0898715342,
617  ! lc: qa188.s17.
618  !
619  ! parameters:
620  !
621  ! input, real ( kind = 8 ) c, s, the cosine and sine of a givens
622  ! rotation.
623  !
624  ! input, sll_int32 ( kind = 4 ) k, indicates the location of the first
625  ! vector entry.
626  !
627  ! input/output, real ( kind = 8 ) g(1:k+1), the vector to be modified.
628  ! on output, the givens rotation has been applied to entries g(k) and g(k+1).
629  !
630  implicit none
631 
632  sll_int32 :: k
633 
634  sll_real64 :: c
635  sll_real64 :: g(1:k+1)
636  sll_real64 :: g1
637  sll_real64 :: g2
638  sll_real64 :: s
639 
640  g1 = c * g(k) - s * g(k+1)
641  g2 = s * g(k) + c * g(k+1)
642 
643  g(k) = g1
644  g(k+1) = g2
645 
646  return
647  end subroutine mult_givens
648  ! ...................................................
649 
650  ! ............................................
655  implicit none
656  class(sll_t_linear_solver_mgmres), intent(in) :: self
657  ! local
658 
659  print *, ">>>> linear_solver_mgmres"
660  print *, "* verbose : ", self%verbose
661  print *, "* n_mr : ", self%n_mr
662  print *, "* rtol : ", self%rtol
663  print *, "* atol : ", self%atol
664  print *, "* null_space : ", self%null_space
665  print *, "* n_maxiter : ", self%n_maxiter
666  print *, "<<<< "
667 
668  end subroutine print_info_linear_solver_mgmres
669  ! ............................................
670 
671  ! ..................................................
675  subroutine free_linear_solver_mgmres(self)
676  implicit none
677  class(sll_t_linear_solver_mgmres), intent(inout) :: self
678 
679  deallocate (self%x_0)
680 
681  end subroutine free_linear_solver_mgmres
682  ! ..................................................
683 
module for abstract linear operator
module for abstract linear solver
module for abstract iterative linear solvers
module for a sequential gmres
subroutine initialize_linear_solver_mgmres(self, linear_operator, x_0)
initializes the linear solver
subroutine mgmres_linear_solver(self, x, rhs, itr_max, mr, tol_abs, tol_rel, itr_used, rho)
integer(kind=i32), parameter sll_solver_maxiter
default maximum number of iterations for
subroutine create_linear_solver_mgmres(self, linear_operator, pc_left, filename)
creates a linear solver
integer(kind=i32), parameter sll_solver_restart
default number of restarts for gmres
subroutine free_linear_solver_mgmres(self)
destroys the current object
subroutine solve_real_linear_solver_mgmres(self, rhs, unknown)
solves the linear system with real vectors
subroutine read_from_file_linear_solver_mgmres(self, filename)
read from file
subroutine set_guess_linear_solver_mgmres(self, x_0)
sets the initial guess
subroutine check_convergence_linear_solver_mgmres(self, i_iteration, flag, r_err, arr_err)
check the convergence of the current linear solver
real(kind=f64), parameter sll_solver_tolerance
default tolerance for iterative solvers
subroutine set_verbose_linear_solver_mgmres(self, verbose)
sets the verbose for the linear solver object
subroutine print_info_linear_solver_mgmres(self)
destroys a finite element cell
integer(kind=i32), parameter sll_solver_bool_false
code id for False
    Report Typos and Errors