Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_conjugate_gradient.F90
Go to the documentation of this file.
2 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 #include "sll_assert.h"
4 
6 
8 
10 
12 
14 
16 
17  implicit none
18 
19  public :: sll_t_conjugate_gradient
20 
21  private
22 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 
24  ! Working precision
25  integer, parameter :: wp = f64
26 
28 
29  ! Default parameters (can be overwritten from method 'init')
30  real(wp) :: tol = 1.0e-14_wp
31  logical :: verbose = .true.
32 
33  ! Output information
34  integer :: iterations
35  logical :: success
36  real(wp) :: residual
37 
38  ! Temporary vector spaces needed by solver
39  class(sll_c_vector_space), private, allocatable :: p
40  class(sll_c_vector_space), private, allocatable :: r
41  class(sll_c_vector_space), private, allocatable :: v
42 
43  ! Logical flag telling whether temporary vector spaces are (de)allocated only once
44  logical :: allocate_once
45 
46  contains
47 
48  procedure :: init => s_conjugate_gradient__init
49  procedure :: solve => s_conjugate_gradient__solve
50  procedure :: free => s_conjugate_gradient__free
51 
53 
54 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
55 contains
56 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
57 
58  ! Initializer
59  subroutine s_conjugate_gradient__init(self, tol, verbose, template_vector)
60  class(sll_t_conjugate_gradient), intent(inout) :: self
61  real(wp), optional, intent(in) :: tol
62  logical, optional, intent(in) :: verbose
63  class(sll_c_vector_space), optional, intent(in) :: template_vector
64 
65  if (present(tol)) self%tol = tol
66  if (present(verbose)) self%verbose = verbose
67 
68  ! Construct temporary vector spaces
69  if (present(template_vector)) then
70 
71  call template_vector%source(self%p)
72  call template_vector%source(self%r)
73  call template_vector%source(self%v)
74 
75  self%allocate_once = .true.
76 
77  else
78 
79  self%allocate_once = .false.
80 
81  end if
82 
83  end subroutine s_conjugate_gradient__init
84 
85  ! Conjugate gradient algorithm for solving linear system Ax = b
86  subroutine s_conjugate_gradient__solve(self, A, b, x)
87  class(sll_t_conjugate_gradient), intent(inout) :: self
88  class(sll_c_linear_operator), intent(in) :: A
89  class(sll_c_vector_space), intent(in) :: b
90  class(sll_c_vector_space), intent(inout) :: x ! already constructed, first guess
91 
92  integer :: m, n(2)
93  real(wp) :: am, am1, l, tol_sqr
94 
95  ! Get shape of linear operator
96  n = a%get_shape()
97 
98  ! Some checks
99  sll_assert(n(1) == n(2))
100 
101  ! Construct temporary vector spaces, if not done already at initialization
102  if (.not. self%allocate_once) then
103 
104  call x%source(self%p)
105  call x%source(self%r)
106  call x%source(self%v)
107 
108  end if
109 
110  ! Conjugate gradient algorithm
111  associate(p => self%p, r => self%r, v => self%v)
112 
113  ! First values
114  call a%dot(x, p) ! p = Ax
115  call p%scal(-1.0_wp) ! p = -Ax
116  call p%incr(b) ! p = b - Ax
117  call r%copy(p) ! r = b - Ax
118  am = r%inner(r) ! am = < r, r >
119 
120  tol_sqr = self%tol**2
121 
122  ! Iterate to convergence
123  do m = 0, n(1) - 1
124 
125  if (am < tol_sqr) exit
126 
127  call a%dot(p, v) ! v = Ap
128  l = v%inner(p) ! l = < v, p >
129  l = am/l ! l = am / < v, p >
130  call x%incr_mult(l, p) ! x = x + l*p
131  call r%incr_mult(-l, v) ! r = r - l*v
132  am1 = r%inner(r) ! am1 = < r, r >
133  call p%scal(am1/am) ! p = am1/am*p
134  call p%incr(r) ! p = r + am1/am*p
135  am = am1
136 
137  end do
138 
139  end associate
140 
141  ! Destroy temporary vector spaces, if not done only once by 'free' method
142  if (.not. self%allocate_once) then
143 
144  select type (p => self%p)
146  deallocate (p%array)
148  deallocate (p%array)
150  deallocate (p%array)
151  end select
152 
153  select type (r => self%r)
155  deallocate (r%array)
157  deallocate (r%array)
159  deallocate (r%array)
160  end select
161 
162  select type (v => self%v)
164  deallocate (v%array)
166  deallocate (v%array)
168  deallocate (v%array)
169  end select
170 
171  end if
172 
173  ! Store info
174  self%iterations = m
175  self%success = .true.
176  self%residual = sqrt(am)
177 
178  ! Verbose output
179  if (self%verbose) write (*, '(/a,i0,a,es8.2)') " CG method converged after ", &
180  self%iterations, " iterations with residual ", self%residual
181 
182  end subroutine s_conjugate_gradient__solve
183 
184  ! Free
185  subroutine s_conjugate_gradient__free(self)
186  class(sll_t_conjugate_gradient), intent(inout) :: self
187 
188  if (self%allocate_once) then
189 
190  select type (p => self%p)
191  type is (sll_t_vector_space_real_array_1d)
192  deallocate (p%array)
193  type is (sll_t_vector_space_real_array_2d)
194  deallocate (p%array)
195  type is (sll_t_vector_space_real_array_3d)
196  deallocate (p%array)
197  end select
198 
199  select type (r => self%r)
200  type is (sll_t_vector_space_real_array_1d)
201  deallocate (r%array)
202  type is (sll_t_vector_space_real_array_2d)
203  deallocate (r%array)
204  type is (sll_t_vector_space_real_array_3d)
205  deallocate (r%array)
206  end select
207 
208  select type (v => self%v)
209  type is (sll_t_vector_space_real_array_1d)
210  deallocate (v%array)
211  type is (sll_t_vector_space_real_array_2d)
212  deallocate (v%array)
213  type is (sll_t_vector_space_real_array_3d)
214  deallocate (v%array)
215  end select
216 
217  end if
218 
219  end subroutine s_conjugate_gradient__free
220 
221 end module sll_m_conjugate_gradient
subroutine s_conjugate_gradient__init(self, tol, verbose, template_vector)
subroutine s_conjugate_gradient__solve(self, A, b, x)
Abstract type implementing a generic vector space.
Vector space for wrapping 1D Fortran real arrays.
Vector space for wrapping 2D Fortran real arrays.
Vector space for wrapping 3D Fortran real arrays.
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
Abstract base class for all vector spaces.
    Report Typos and Errors