Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_rk_implicit.F90
Go to the documentation of this file.
1 !----------------------
2 ! A note about notation
3 !----------------------
4 ! rkXY:
5 ! e = explicit
6 ! i = implicit (fully)
7 ! d = diagonally implicit
8 ! m = embedded
9 ! l = low-storage
10 !----------------------
11 
13 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14 #include "sll_assert.h"
15 #include "sll_errors.h"
16 
17  use sll_m_working_precision, only: f64
18 
19  use sll_m_ode_integrator_base, only: &
20  sll_c_ode, &
22 
23  use sll_m_vector_space_base, only: &
25 
26  implicit none
27 
28  public :: &
32 
33  private
34 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
35 
37  integer, parameter :: wp = f64
38 
39  !-----------------------------------------------------------------------------
40  type, abstract, extends(sll_c_ode_integrator) :: sll_c_rk_implicit
41 
42  private
43 
44  real(wp) :: rel_tol = 1.0e-12_wp
45  real(wp) :: abs_tol = 1.0e-15_wp
46  integer :: maxiter = 20
47 
48  contains
49 
50  procedure :: set_params => s_rk_implicit__set_params
51  procedure :: get_params => s_rk_implicit__get_params
52 
53  end type sll_c_rk_implicit
54 
55  !-----------------------------------------------------------------------------
57 
58  contains
59  procedure :: init => rk1d_bwd_euler__init
60  procedure :: step => rk1d_bwd_euler__step
61  procedure :: clean => rk1d_bwd_euler__clean
62 
63  end type sll_t_rk1d_bwd_euler
64 
65  !-----------------------------------------------------------------------------
67 
68  contains
69  procedure :: init => rk1d_trapezoid__init
70  procedure :: step => rk1d_trapezoid__step
71  procedure :: clean => rk1d_trapezoid__clean
72 
73  end type sll_t_rk1d_trapezoid
74 
75 !==============================================================================
76 contains
77 !==============================================================================
78 
79  subroutine s_rk_implicit__set_params(self, rel_tol, abs_tol, maxiter)
80  class(sll_c_rk_implicit), intent(inout) :: self
81  real(wp), intent(in) :: rel_tol
82  real(wp), intent(in) :: abs_tol
83  integer, intent(in) :: maxiter
84 
85  ! Sanity checks
86  sll_assert_always(rel_tol > 0.0_wp)
87  sll_assert_always(abs_tol > 0.0_wp)
88  sll_assert_always(maxiter > 0)
89 
90  self%rel_tol = rel_tol
91  self%abs_tol = abs_tol
92  self%maxiter = maxiter
93 
94  end subroutine s_rk_implicit__set_params
95 
96  !-----------------------------------------------------------------------------
97  subroutine s_rk_implicit__get_params(self, rel_tol, abs_tol, maxiter)
98  class(sll_c_rk_implicit), intent(in) :: self
99  real(wp), intent(out) :: rel_tol
100  real(wp), intent(out) :: abs_tol
101  integer, intent(out) :: maxiter
102 
103  rel_tol = self%rel_tol
104  abs_tol = self%abs_tol
105  maxiter = self%maxiter
106 
107  end subroutine s_rk_implicit__get_params
108 
109  !:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
110  ! Implicit Euler (backward Euler)
111  !:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
112 
113  !-----------------------------------------------------------------------------
114  subroutine rk1d_bwd_euler__init(self, ode, t0, y0)
115  class(sll_t_rk1d_bwd_euler), intent(out) :: self
116  class(sll_c_ode), pointer, intent(in) :: ode
117  real(wp), intent(in) :: t0
118  class(sll_c_vector_space), intent(inout) :: y0
119 
120  self%ode => ode
121  call y0%source(self%work, 2)
122  sll_assert_always(storage_size(y0) > 0)
123 
124  end subroutine rk1d_bwd_euler__init
125 
126  !-----------------------------------------------------------------------------
127  subroutine rk1d_bwd_euler__step(self, t, y, h, ynew)
128  class(sll_t_rk1d_bwd_euler), intent(inout) :: self
129  real(wp), intent(in) :: t
130  class(sll_c_vector_space), intent(in) :: y
131  real(wp), intent(in) :: h
132  class(sll_c_vector_space), intent(inout) :: ynew
133 
134  real(wp) :: err, tol
135  integer :: iter
136  logical :: success
137 
138  character(len=*), parameter :: this_sub_name = "sll_t_rk1d_bwd_euler % step"
139  character(len=256) :: err_msg
140 
141  tol = self%abs_tol + self%rel_tol*y%norm()
142 
143  success = .false.
144 
145  ! y_i = y_old
146  ! work(1) = y_i
147  call self%work(1)%copy(y)
148 
149  do iter = 1, self%maxiter
150 
151  ! k1 = f(t,y_i)
152  ! work(2) = k1
153  call self%ode%rhs(t, self%work(1), self%work(2))
154 
155  ! y_{i+1} = y_old + h*k1
156  call ynew%mult_add(h, self%work(2), y)
157 
158  ! work(1) = y_i - y_{i+1}
159  call self%work(1)%incr_mult(-1.0_wp, ynew)
160 
161  err = self%work(1)%norm()
162 
163  if (err <= tol) then
164  success = .true.
165  exit
166  else
167  call self%work(1)%copy(ynew)
168  end if
169 
170  end do
171 
172  if (.not. success) then
173  write (err_msg, '(A,I0,A)') "could not converge after ", self%maxiter, " iterations"
174  sll_error(this_sub_name, err_msg)
175  end if
176 
177  end subroutine rk1d_bwd_euler__step
178 
179  !-----------------------------------------------------------------------------
180  subroutine rk1d_bwd_euler__clean(self)
181  class(sll_t_rk1d_bwd_euler), intent(inout) :: self
182 
183  deallocate (self%work)
184 
185  end subroutine rk1d_bwd_euler__clean
186 
187  !:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
188  ! Trapezoidal
189  !:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
190 
191  !-----------------------------------------------------------------------------
192  subroutine rk1d_trapezoid__init(self, ode, t0, y0)
193  class(sll_t_rk1d_trapezoid), intent(out) :: self
194  class(sll_c_ode), pointer, intent(in) :: ode
195  real(wp), intent(in) :: t0
196  class(sll_c_vector_space), intent(inout) :: y0
197 
198  self%ode => ode
199  call y0%source(self%work, 2)
200  sll_assert_always(storage_size(y0) > 0)
201 
202  end subroutine rk1d_trapezoid__init
203 
204  !-----------------------------------------------------------------------------
205  subroutine rk1d_trapezoid__step(self, t, y, h, ynew)
206  class(sll_t_rk1d_trapezoid), intent(inout) :: self
207  real(wp), intent(in) :: t
208  class(sll_c_vector_space), intent(in) :: y
209  real(wp), intent(in) :: h
210  class(sll_c_vector_space), intent(inout) :: ynew
211 
212  real(wp) :: err, tol
213  integer :: iter
214  logical :: success
215 
216  character(len=*), parameter :: this_sub_name = "sll_t_rk1d_trapezoid % step"
217  character(len=256) :: err_msg
218 
219  tol = self%abs_tol + self%rel_tol*y%norm()
220 
221  success = .false.
222 
223  ! k1 = f(t,y)
224  ! work(1) = k1
225  call self%ode%rhs(t, y, self%work(1))
226 
227  ! work(2) = y_i = y
228  call self%work(2)%copy(y)
229 
230  do iter = 1, self%maxiter
231 
232  ! k2 = f(t+h,y_i)
233  ! ynew = k2
234  call self%ode%rhs(t + h, self%work(2), ynew)
235 
236  ! ynew = k1+k2
237  call ynew%incr(self%work(1))
238 
239  ! ynew = h/2*(k1+k2)
240  call ynew%scal(0.5_wp*h)
241 
242  ! ynew = y + h/2*(k1+k2)
243  call ynew%incr(y)
244 
245  ! work(2) = y_i - y_{i+1}
246  ! err = l2_norm( work(2) )
247  call self%work(2)%incr_mult(-1.0_wp, ynew)
248  err = self%work(2)%norm()
249 
250  if (err <= tol) then
251  success = .true.
252  exit
253  else
254  call self%work(2)%copy(ynew)
255  end if
256 
257  end do
258 
259  if (.not. success) then
260  write (err_msg, '(A,I0,A)') "could not converge after ", self%maxiter, " iterations"
261  sll_error(this_sub_name, err_msg)
262  end if
263 
264  end subroutine rk1d_trapezoid__step
265 
266  !-----------------------------------------------------------------------------
267  subroutine rk1d_trapezoid__clean(self)
268  class(sll_t_rk1d_trapezoid), intent(inout) :: self
269 
270  deallocate (self%work)
271 
272  end subroutine rk1d_trapezoid__clean
273 
274 end module sll_m_rk_implicit
Abstract types for: 1) generic ODE system, and 2) ODE integrator.
subroutine s_rk_implicit__get_params(self, rel_tol, abs_tol, maxiter)
subroutine s_rk_implicit__set_params(self, rel_tol, abs_tol, maxiter)
subroutine rk1d_bwd_euler__step(self, t, y, h, ynew)
subroutine rk1d_trapezoid__step(self, t, y, h, ynew)
integer, parameter wp
Working precision.
subroutine rk1d_trapezoid__init(self, ode, t0, y0)
subroutine rk1d_bwd_euler__clean(self)
subroutine rk1d_bwd_euler__init(self, ode, t0, y0)
subroutine rk1d_trapezoid__clean(self)
Abstract type implementing a generic vector space.
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