Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_ode_solvers.F90
Go to the documentation of this file.
2 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 #include "sll_assert.h"
4 #include "sll_memory.h"
5 #include "sll_working_precision.h"
6 
7  implicit none
8 
9  public :: &
13 
14  private
15 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 
17  integer, parameter :: sll_p_periodic_ode = 0, sll_p_compact_ode = 1
18 
19  abstract interface
20  function scalar_function_1d(eta)
22  sll_real64 :: scalar_function_1d
23  sll_real64, intent(in) :: eta
24  end function scalar_function_1d
25  end interface
26 
27 contains
28 
29  function f_one(eta)
31  sll_real64 :: f_one
32  sll_real64, intent(in) :: eta
33 
34  f_one = 1.0_f64 + eta - eta
35 
36  end function f_one
37 
38  ! Computes the solution of functional equation
39  !
40  ! xi-xout = c*deltat*(b(xi)+a(xout))
41  !
42  ! for initial conditions xi corresponding to all points of a uniform grid
43  ! with c=1 and b=0 this is a first order method for solving backward
44  !
45  ! dx/dt = a(x,t)
46  !
47  ! with c=1/2 and b = a(.,t_(n+1)) this is a second order method for the
48  ! same problem.
49  !
50  ! In practise the first order method needs to be called in order to
51  ! compute b for the second order method
52  !
53  ! based on algorithm described in Crouseilles, Mehrenberger, Sonnendrucker, JCP 2010
54  subroutine implicit_ode(order, &
55  deltat, &
56  xmin, &
57  ncx, &
58  deltax, &
59  bt, &
60  xout, &
61  a, &
62  a_np1)
63  intrinsic :: floor, present
64  sll_int32 :: order
65  sll_real64 :: deltat
66  sll_real64 :: xmin
67  sll_int32 :: ncx ! number of cells of uniform grid
68  sll_real64 :: deltax
69  sll_int32 :: bt ! boundary_type
70  ! solution for all initial conditions:
71  sll_real64, dimension(:) :: xout
72  sll_real64, dimension(:) :: a ! rhs at t = t_n
73  sll_real64, dimension(:), pointer, optional :: a_np1 ! rhs at t = t_n+1
74  ! local variables
75  sll_int32 :: i, id, ileft, iright, i0
76  sll_real64 :: xmax, xi, alpha
77  sll_real64 :: c ! real coefficient
78  sll_real64, dimension(ncx + 1), target :: zeros ! array if zeros
79  sll_real64, dimension(:), pointer :: b
80 
81  ! initialize zeros
82  zeros = 0.0_f64
83  ! check order. The implementation with a 'select' construct permits
84  ! to extend this solver to higher orders more conveniently.
85  select case (order)
86  case (1)
87  c = 1.0_f64
88  b => zeros
89  case (2)
90  c = 0.5_f64
91  if (present(a_np1)) then
92  b => a_np1
93  else
94  stop 'implicit_ode: need field at time t_n+1 for higher order'
95  end if
96  case default
97  print *, 'order = ', order, ' not implemented'
98  stop
99  end select
100 
101  ! compute xmax of the grid
102  sll_assert(size(a) == ncx + 1)
103  sll_assert(size(b) == ncx + 1)
104  sll_assert(size(xout) == ncx + 1)
105 
106  xmax = xmin + ncx*deltax
107 
108  ! localize cell [i0, i0+1] containing origin of characteristic ending at xmin
109  i = 1
110  if (a(i) + b(i) > 0) then
111  ! search on the left
112  if (bt == sll_p_periodic_ode) then
113  i0 = 0
114  do while (i0 + c*deltat/deltax*(a(modulo(i0 - 1, ncx) + 1) + b(i)) >= i)
115  i0 = i0 - 1
116  end do
117  else if (bt == sll_p_compact_ode) then
118  i0 = 1
119  else
120  stop 'implicit_ode : boundary_type not implemented'
121  end if
122  else
123  ! search on the right
124  i0 = 1
125  do while (i0 + c*deltat/deltax*(a(i0) + b(i)) < i)
126  i0 = i0 + 1
127  end do
128  i0 = i0 - 1
129  end if
130 
131  do i = 1, ncx + 1
132  xi = xmin + (i - 1)*deltax ! current grid point
133  ! find cell which contains origin of characteristic
134  do while (i0 + c*deltat/deltax*(a(modulo(i0 - 1, ncx) + 1) + b(i)) <= i)
135  i0 = i0 + 1
136  end do
137  i0 = i0 - 1
138  !print*, 'out ',i, i0, i0 + c*deltat/deltax*( a(modulo(i0-1,ncx)+1) + b(i) )
139  id = i - i0
140  ! handle boundary conditions
141  if (bt == sll_p_periodic_ode) then
142  ileft = modulo(i0 - 1, ncx) + 1
143  iright = modulo(i0, ncx) + 1
144  else if (bt == sll_p_compact_ode) then
145  ileft = min(max(i0, 1), ncx + 1)
146  iright = max(min(i0 + 1, ncx + 1), 1)
147  else
148  stop 'implicit_ode : boundary_type not implemented'
149  end if
150  !print*, i, ileft, iright, a(iright) - a(ileft), deltax + c * deltat * (a(iright) - a(ileft))
151  sll_assert((ileft >= 1) .and. (ileft <= ncx + 1))
152  sll_assert((iright >= 1) .and. (iright <= ncx + 1))
153  sll_assert(deltax + c*deltat*(a(iright) - a(ileft)) > 0.0)
154  ! compute xout using linear interpolation of a
155  alpha = c*deltat*(b(i) + (1 - id)*a(ileft) + id*a(iright)) &
156  /(deltax + c*deltat*(a(iright) - a(ileft)))
157  xout(i) = xi - alpha*deltax
158  ! handle boundary conditions
159  if (bt == sll_p_periodic_ode) then
160  xout(i) = modulo(xout(i) - xmin, xmax - xmin) + xmin
161  else if (bt == sll_p_compact_ode) then
162  if (xout(i) < xmin) then
163  ! put particles on the left of the domain on the left boundary
164  xout(i) = xmin
165  elseif (xout(i) > xmax) then
166  ! put particles on the right of the domain on the right boundary
167  xout(i) = xmax
168  end if
169  else
170  stop 'implicit_ode : boundary_type not implemented'
171  end if
172 
173  sll_assert((xout(i) >= xmin) .and. (xout(i) <= xmax))
174  !print*,'interv ', xmin + (ileft-1)*deltax , xout(i), xmin + ileft*deltax
175  end do
176  end subroutine implicit_ode
177 
178  subroutine sll_s_implicit_ode_nonuniform(order, &
179  deltat, &
180  xin, &
181  ncx, &
182  bt, &
183  xout, &
184  a, &
185  a_np1)
186  intrinsic :: floor, present
187  sll_int32, intent(in) :: order
188  sll_real64, intent(in) :: deltat
189  sll_int32, intent(in) :: ncx ! number of cells of uniform grid
190  sll_int32, intent(in) :: bt ! boundary_type
191  sll_real64, dimension(:) :: xin(:)
192  ! solution for all initial conditions
193  sll_real64, dimension(:) :: xout
194  sll_real64, dimension(:) :: a ! rhs at t = t_n
195  sll_real64, dimension(:), pointer, optional :: a_np1 ! rhs at t = t_n+1
196  ! local variables
197  sll_int32 :: i, ileft, iright, i0, imax
198  sll_real64 :: xi, xi0, yi0, yi0p1, x1, beta
199  sll_real64 :: c ! real coefficient
200  sll_real64 :: period ! period of periodic domain
201  sll_real64, dimension(ncx + 1), target :: zeros ! array of zeros
202  sll_real64, dimension(:), pointer :: b
203  sll_real64, parameter :: eps = 1.0d-14 ! small real number
204  sll_real64 :: tmp
205  ! initialize zeros
206  zeros(:) = 0.0_f64
207  ! check order. The implementation with a 'select' construct permits
208  ! to extend this solver to higher orders more conveniently.
209 
210  yi0 = 0._f64
211  select case (order)
212  case (1)
213  c = 1.0_f64
214  b => zeros(1:ncx + 1)
215  case (2)
216  c = 0.5_f64
217  if (present(a_np1)) then
218  b => a_np1(1:ncx + 1)
219  else
220  stop 'implicit_ode: need field at time t_n+1 for higher order'
221  end if
222  case default
223  print *, 'order = ', order, ' not implemented'
224  stop
225  end select
226 
227  ! check array sizes
228  sll_assert(size(a) == ncx + 1)
229  sll_assert(size(b) == ncx + 1)
230  sll_assert(size(xout) == ncx + 1)
231  sll_assert(size(xin) == ncx + 1)
232 
233  ! case of periodic boundary conditions
234  !-------------------------------------
235  if (bt == sll_p_periodic_ode) then
236  !begin modif
237  tmp = 0._f64
238  do i = 1, ncx
239  tmp = tmp + abs(a(i))
240  end do
241  tmp = tmp/real(ncx, f64)
242  if (tmp < 1.e-14) then
243  xout = xin
244  return
245  end if
246  !end modif
247  x1 = xin(1)
248  period = xin(ncx + 1) - x1
249 
250  do i = 1, ncx
251  xi = xin(i) ! current grid point
252  ! check that displacement is less than 1 period for first point
253  ! localize cell [i0, i0+1] containing origin of characteristic
254  ! ending at xin(1)
255  ! we consider the mesh of the same period consisting of the points
256  ! yi0 = xi0 + c*deltat*( a(i0) + b(i) )
257  ! modulo n. If there was no periodicity the sequence would be
258  ! strictly increasing
259  ! we first look for i0 such that y(i0+1) < y(i0) due to periodicity
260  if (a(1) + b(i) > 0) then
261  ! y(ncx+1) > x(1) in this case so we look backward
262  i0 = ncx + 1
263  yi0p1 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
264  i0 = ncx
265  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
266  do while (yi0p1 > yi0)
267  i0 = i0 - 1
268  yi0p1 = yi0
269  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
270  end do
271  else
272  ! search on the right
273  i0 = 1
274  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
275  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
276  do while (yi0p1 > yi0)
277  i0 = i0 + 1
278  yi0 = yi0p1
279  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
280  end do
281  end if
282 
283  if ((i0 < 1) .or. (i0 > ncx)) then ! yi0 is strictly increasing
284  i0 = 1
285  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
286  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
287  end if
288  imax = i0
289  ! find cell which contains origin of characteristic
290  do while ((yi0p1 < xi + eps))
291  i0 = modulo(i0, ncx) + 1
292  if (i0 == imax) then
293  yi0 = yi0p1
294  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
295  exit
296  else
297  yi0 = yi0p1
298  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
299  end if
300  end do
301 
302  sll_assert((i0 >= 1) .and. (i0 <= ncx))
303  ! compute xout using linear interpolation of a
304  if (yi0p1 > yi0) then
305  beta = (xi - yi0)/(yi0p1 - yi0)
306  else if (xi >= yi0) then
307  beta = (xi - yi0)/(yi0p1 - yi0 + period)
308  else
309  beta = (xi - yi0 + period)/(yi0p1 - yi0 + period)
310  end if
311  !print*, i, i0, yi0, xi, yi0p1, beta, period, x1
312  if (.not. ((beta >= -eps) .and. (beta <= 1))) then
313  print *, xin
314  print *, a
315  print *, beta, eps, i0, beta - 1._f64, i
316  print *, 'problem'
317  end if
318  !SLL_ASSERT((beta>=-eps) .and. (beta < 1))
319  sll_assert((beta >= -eps) .and. (beta <= 1))
320  xout(i) = xin(i0) + beta*(xin(i0 + 1) - xin(i0))
321  ! handle periodic boundary conditions
322  xout(i) = modulo(xout(i) - xin(1), xin(ncx + 1) - xin(1)) + xin(1)
323  sll_assert((xout(i) >= xin(1)) .and. (xout(i) <= xin(ncx + 1)))
324  end do
325  ! due to periodicity, origin of last point is same as origin of first
326  ! point
327  xout(ncx + 1) = xout(1)
328  else if (bt == sll_p_compact_ode) then
329  ! localize cell [i0, i0+1] containing origin of characteristic ending
330  ! at xmin
331  i = 1
332  if (a(i) + b(i) > 0) then
333  i0 = 1
334  else
335  ! search on the right
336  i0 = 2
337  do while (xin(i0) + c*deltat*(a(i0) + b(i)) < xin(i))
338  i0 = i0 + 1
339  end do
340  i0 = i0 - 1
341  end if
342 
343  do i = 1, ncx + 1
344  xi = xin(i) ! current grid point
345  ! find cell which contains origin of characteristic
346  xi0 = xin(i0)
347  if (yi0 <= xi) then
348  i0 = i0 + 1
349  yi0 = xin(i0) + c*deltat*(a(i0) + b(i))
350  do while ((yi0 <= xi) .and. (i0 < ncx + 1))
351  i0 = i0 + 1
352  yi0 = xin(i0) + c*deltat*(a(i0) + b(i))
353  !print*, 'i0 ', i, i0, yi0, modulo(xi - y1, period) + y1
354  end do
355  i0 = i0 - 1
356  else
357  do while ((yi0 > xi) .and. (i0 > 1))
358  i0 = i0 - 1
359  yi0 = xin(i0) + c*deltat*(a(i0) + b(i))
360  !print*, 'i0 ', i, i0, yi0, xin(i0), xi, modulo(xi - y1, period) + y1
361  end do
362  end if
363 
364  ileft = i0
365  iright = i0 + 1
366  sll_assert((ileft >= 1) .and. (ileft <= ncx))
367  sll_assert((iright >= 2) .and. (iright <= ncx + 1))
368  sll_assert(xin(ileft + 1) - xin(ileft) + c*deltat*(a(iright) - a(ileft)) > 0.0)
369  ! compute xout using linear interpolation of a
370  beta = (xin(i) - xin(ileft) - c*deltat*(b(i) + a(ileft))) &
371  /(xin(ileft + 1) - xin(ileft) + c*deltat*(a(iright) - a(ileft)))
372  xout(i) = xin(ileft) + beta*(xin(ileft + 1) - xin(ileft))
373 
374  ! Handle characteristics that have gone out of domain
375  if (xout(i) < xin(1)) then
376  ! put particles on the left of the domain on the left boundary
377  xout(i) = xin(1)
378  elseif (xout(i) > xin(ncx + 1)) then
379  ! put particles on the right of the domain on the right boundary
380  xout(i) = xin(ncx + 1)
381  end if
382  sll_assert((xout(i) >= xin(1)) .and. (xout(i) <= xin(ncx + 1)))
383  end do
384  else
385  stop 'implicit_ode : boundary_type not implemented'
386  end if
387 
388  end subroutine sll_s_implicit_ode_nonuniform
389 
390  subroutine implicit_ode_nonuniform_old(order, &
391  deltat, &
392  xin, &
393  ncx, &
394  bt, &
395  xout, &
396  a, &
397  a_np1)
398  intrinsic :: floor, present
399  sll_int32 :: order
400  sll_real64 :: deltat
401  sll_int32 :: ncx ! number of cells of uniform grid
402  sll_int32 :: bt ! boundary_type
403  sll_real64, dimension(:) :: xin(:)
404  ! solution for all initial conditions
405  sll_real64, dimension(:) :: xout
406  sll_real64, dimension(:) :: a ! rhs at t = t_n
407  sll_real64, dimension(:), pointer, optional :: a_np1 ! rhs at t = t_n+1
408  ! local variables
409  sll_int32 :: i, ileft, iright, i0, imax
410  sll_real64 :: xi, xi0, yi0, yi0p1, x1, beta
411  sll_real64 :: c ! real coefficient
412  sll_real64 :: period ! period of periodic domain
413  sll_real64, dimension(ncx + 1), target :: zeros ! array of zeros
414  sll_real64, dimension(:), pointer :: b
415  sll_real64, parameter :: eps = 1.0d-14 ! small real number
416  sll_real64 :: tmp
417  ! initialize zeros
418  zeros(:) = 0.0_f64
419  ! check order. The implementation with a 'select' construct permits
420  ! to extend this solver to higher orders more conveniently.
421  select case (order)
422  case (1)
423  c = 1.0_f64
424  b => zeros(1:ncx + 1)
425  case (2)
426  c = 0.5_f64
427  if (present(a_np1)) then
428  b => a_np1(1:ncx + 1)
429  else
430  stop 'implicit_ode: need field at time t_n+1 for higher order'
431  end if
432  case default
433  print *, 'order = ', order, ' not implemented'
434  stop
435  end select
436 
437  ! check array sizes
438  sll_assert(size(a) == ncx + 1)
439  sll_assert(size(b) == ncx + 1)
440  sll_assert(size(xout) == ncx + 1)
441  sll_assert(size(xin) == ncx + 1)
442 
443  ! case of periodic boundary conditions
444  !-------------------------------------
445  if (bt == sll_p_periodic_ode) then
446  !begin modif
447  tmp = 0._f64
448  do i = 1, ncx
449  tmp = tmp + abs(a(i))
450  end do
451  tmp = tmp/real(ncx, f64)
452  if (tmp < 1.e-14) then
453  xout = xin
454  return
455  end if
456  !end modif
457  x1 = xin(1)
458  period = xin(ncx + 1) - x1
459 
460  do i = 1, ncx
461  xi = xin(i) ! current grid point
462  ! check that displacement is less than 1 period for first point
463  ! localize cell [i0, i0+1] containing origin of characteristic ending at xin(1)
464  ! we consider the mesh of the same period consisting of the points yi0 = xi0 + c*deltat*( a(i0) + b(i) )
465  ! modulo n. If there was no periodicity the sequence would be strictly increasing
466  ! we first look for i0 such that y(i0+1) < y(i0) due to periodicity
467  if (a(1) + b(i) > 0) then
468  ! y(ncx+1) > x(1) in this case so we look backward
469  i0 = ncx + 1
470  yi0p1 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
471  i0 = ncx
472  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
473  do while (yi0p1 > yi0)
474  i0 = i0 - 1
475  yi0p1 = yi0
476  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
477  end do
478  else
479  ! search on the right
480  i0 = 1
481  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
482  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
483  do while (yi0p1 > yi0)
484  i0 = i0 + 1
485  yi0 = yi0p1
486  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
487  end do
488  end if
489 
490  if ((i0 < 1) .or. (i0 > ncx)) then ! yi0 is strictly increasing
491  i0 = 1
492  yi0 = modulo(xin(i0) + c*deltat*(a(i0) + b(i)) - x1, period) + x1
493  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
494  end if
495  imax = i0
496  ! find cell which contains origin of characteristic
497  do while ((yi0p1 < xi + eps))
498  i0 = modulo(i0, ncx) + 1
499  if (i0 == imax) then
500  yi0 = yi0p1
501  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
502  exit
503  else
504  yi0 = yi0p1
505  yi0p1 = modulo(xin(i0 + 1) + c*deltat*(a(i0 + 1) + b(i)) - x1, period) + x1
506  end if
507  end do
508 
509  sll_assert((i0 >= 1) .and. (i0 <= ncx))
510  ! compute xout using linear interpolation of a
511  if (yi0p1 > yi0) then
512  beta = (xi - yi0)/(yi0p1 - yi0)
513  else if (xi >= yi0) then
514  beta = (xi - yi0)/(yi0p1 - yi0 + period)
515  else
516  beta = (xi - yi0 + period)/(yi0p1 - yi0 + period)
517  end if
518  !print*, i, i0, yi0, xi, yi0p1, beta, period, x1
519  if (.not. ((beta >= -eps) .and. (beta <= 1))) then
520  print *, xin
521  print *, a
522  print *, beta, eps, i0, beta - 1._f64, i
523  print *, 'problem'
524  end if
525  !SLL_ASSERT((beta>=-eps) .and. (beta < 1))
526  sll_assert((beta >= -eps) .and. (beta <= 1))
527  xout(i) = xin(i0) + beta*(xin(i0 + 1) - xin(i0))
528  ! handle periodic boundary conditions
529  xout(i) = modulo(xout(i) - xin(1), xin(ncx + 1) - xin(1)) + xin(1)
530  sll_assert((xout(i) >= xin(1)) .and. (xout(i) <= xin(ncx + 1)))
531  end do
532  ! due to periodicity, origin of last point is same as origin of first point
533  xout(ncx + 1) = xout(1)
534  else if (bt == sll_p_compact_ode) then
535  ! localize cell [i0, i0+1] containing origin of characteristic ending at xmin
536  i = 1
537  if (a(i) + b(i) > 0) then
538  i0 = 1
539  else
540  ! search on the right
541  i0 = 2
542  do while (xin(i0) + c*deltat*(a(i0) + b(i)) < xin(i))
543  i0 = i0 + 1
544  end do
545  i0 = i0 - 1
546  end if
547  do i = 1, ncx + 1
548  xi = xin(i) ! current grid point
549  ! find cell which contains origin of characteristic
550  xi0 = xin(i0)
551  if (yi0 <= xi) then
552  i0 = i0 + 1
553  yi0 = xin(i0) + c*deltat*(a(i0) + b(i))
554  do while ((yi0 <= xi) .and. (i0 < ncx + 1))
555  i0 = i0 + 1
556  yi0 = xin(i0) + c*deltat*(a(i0) + b(i))
557  !print*, 'i0 ', i, i0, yi0, modulo(xi - y1, period) + y1
558  end do
559  i0 = i0 - 1
560  else
561  do while ((yi0 > xi) .and. (i0 > 1))
562  i0 = i0 - 1
563  yi0 = xin(i0) + c*deltat*(a(i0) + b(i))
564  !print*, 'i0 ', i, i0, yi0, xin(i0), xi, modulo(xi - y1, period) + y1
565  end do
566  end if
567  ileft = i0
568  iright = i0 + 1
569  sll_assert((ileft >= 1) .and. (ileft <= ncx))
570  sll_assert((iright >= 2) .and. (iright <= ncx + 1))
571  sll_assert(xin(ileft + 1) - xin(ileft) + c*deltat*(a(iright) - a(ileft)) > 0.0)
572  ! compute xout using linear interpolation of a
573  beta = (xin(i) - xin(ileft) - c*deltat*(b(i) + a(ileft))) &
574  /(xin(ileft + 1) - xin(ileft) + c*deltat*(a(iright) - a(ileft)))
575  xout(i) = xin(ileft) + beta*(xin(ileft + 1) - xin(ileft))
576 
577  ! Handle characteristics that have gone out of domain
578  if (xout(i) < xin(1)) then
579  ! put particles on the left of the domain on the left boundary
580  xout(i) = xin(1)
581  elseif (xout(i) > xin(ncx + 1)) then
582  ! put particles on the right of the domain on the right boundary
583  xout(i) = xin(ncx + 1)
584  end if
585  sll_assert((xout(i) >= xin(1)) .and. (xout(i) <= xin(ncx + 1)))
586  end do
587  else
588  stop 'implicit_ode : boundary_type not implemented'
589  end if
590 
591  end subroutine implicit_ode_nonuniform_old
592 
593  ! Computes the solution of functional equation obtained on a curvilinear grid
594  !
595  ! xi-x(eta_out) = c*deltat*(b(xi)+a(eta_out))
596  !
597  ! for initial conditions xi=x(eta_i) corresponding to the images of all points
598  ! of a uniform gridwith c=1 and b=0 this is a first order method for solving backward
599  !
600  ! dx(eta)/dt = a(x(eta(t)),t)
601  !
602  ! with c=1/2 and b = a(.,t_(n+1)) this is a second order method for the
603  ! same problem.
604  !
605  ! In practise the first order method needs to be called in order to
606  ! compute b for the second order method
607  subroutine implicit_ode_curv(order, &
608  deltat, &
609  eta_min, &
610  nc_eta, &
611  delta_eta, &
612  bt, &
613  eta_out, &
614  xfunc, &
615  xprimefunc, &
616  a, &
617  a_np1)
618  intrinsic :: floor, present
619  sll_int32 :: order
620  sll_real64 :: deltat
621  sll_real64 :: eta_min
622  sll_int32 :: nc_eta ! number of cells of uniform grid
623  sll_real64 :: delta_eta
624  sll_int32 :: bt ! boundary_type
625  ! solution for all initial conditions:
626  sll_real64, dimension(:) :: eta_out
627  procedure(scalar_function_1d), pointer :: xfunc
628  procedure(scalar_function_1d), pointer :: xprimefunc
629  sll_real64, dimension(:) :: a ! rhs at t = t_n
630  sll_real64, dimension(:), pointer, optional :: a_np1 ! rhs at t = t_n+1
631  ! local variables
632  sll_int32 :: i, id
633  sll_real64 :: alpha, aint, eta_max, eta_i, eta_k, eta_kp1, xi
634  sll_real64 :: c ! real coefficient
635  sll_real64, dimension(nc_eta + 1), target :: zeros ! array if zeros
636  sll_real64, dimension(:), pointer :: b
637 
638  ! initialize zeros
639  zeros = 0.0_f64
640  ! check order. The implementation with a 'select' construct permits
641  ! to extend this solver to higher orders more conveniently.
642  select case (order)
643  case (1)
644  c = 1.0_f64
645  b => zeros
646  case (2)
647  c = 0.5_f64
648  if (present(a_np1)) then
649  b => a_np1
650  else
651  stop 'implicit_ode_curv: need field at time t_n+1 for higher order'
652  end if
653  case default
654  print *, 'order = ', order, ' not implemented'
655  stop
656  end select
657 
658  ! compute eta_max of the grid
659  sll_assert(size(a) == nc_eta + 1)
660  sll_assert(size(b) == nc_eta + 1)
661  sll_assert(size(eta_out) == nc_eta + 1)
662 
663  eta_max = eta_min + nc_eta*delta_eta
664  eta_i = eta_min
665  do i = 1, nc_eta + 1
666  xi = xfunc(eta_i) ! current grid point
667  ! initial guess for the Newton solver: take eta_i
668  eta_kp1 = eta_i
669  do while (abs(eta_k - eta_kp1) > 1.0d-8)
670  eta_k = eta_kp1
671  ! handle boundary conditions
672  if (bt == sll_p_periodic_ode) then
673  eta_k = eta_min + modulo(eta_k - eta_min, eta_max - eta_min)
674  else if (bt == sll_p_compact_ode) then
675  if (eta_k < eta_min) then
676  eta_k = eta_min
677  cycle
678  else if (eta_k > eta_max) then
679  eta_k = eta_max
680  cycle
681  end if
682  else
683  stop 'implicit_ode_curv: boundary_type not implemented'
684  end if
685  ! localize cell [id, id+1] where eta_k is in
686  id = floor((eta_k - eta_min)/delta_eta)
687  alpha = (eta_k - eta_min)/delta_eta - id
688 
689  ! compute linear interpolation of a at eta_k
690  aint = (1.0_f64 - alpha)*a(id) + alpha*a(id + 1)
691  ! compute next iterate of Newton's method
692  eta_kp1 = eta_k - (c*deltat*(b(i)*aint) + xfunc(eta_k) - xi)/ &
693  (c*deltat*(a(id + 1) - a(id))/delta_eta + xprimefunc(eta_k))
694  end do
695 
696  sll_assert((eta_kp1 >= eta_min) .and. (eta_kp1 <= eta_max))
697  eta_out(i) = eta_kp1
698  eta_i = eta_i + delta_eta
699  end do
700  end subroutine implicit_ode_curv
701 
702  ! Classical second order Runge-Kutta ODE solver for an ode of the form
703  ! d eta/ dt = a(eta)
704  ! a is known only at grid points and linear interpolation is used in between
705  subroutine rk2(nsubsteps, &
706  deltat, &
707  eta_min, &
708  nc_eta, &
709  delta_eta, &
710  bt, &
711  eta_out, &
712  a, &
713  jac)
714  intrinsic :: floor
715  sll_int32 :: nsubsteps
716  sll_real64 :: deltat
717  sll_real64 :: eta_min
718  sll_int32 :: nc_eta ! number of cells of uniform grid
719  sll_real64 :: delta_eta
720  sll_int32 :: bt ! boundary_type
721  ! solution for all initial conditions:
722  sll_real64, dimension(:) :: eta_out
723  sll_real64, dimension(:) :: a ! rhs of ode
724  procedure(scalar_function_1d), pointer, optional :: jac
725  ! local variables
726  procedure(scalar_function_1d), pointer :: jacobian
727  sll_real64 :: eta_max
728  sll_real64 :: eta_i, eta_k, eta_kp1
729  sll_real64 :: deltatsub
730  sll_real64 :: a_n, a_np1, alpha
731  sll_int32 :: i, id, isub
732 
733  if (present(jac)) then
734  jacobian => jac
735  else
736  jacobian => f_one
737  end if
738 
739  sll_assert(size(a) == nc_eta + 1)
740  sll_assert(size(eta_out) == nc_eta + 1)
741  ! compute eta_max of the grid
742  eta_max = eta_min + nc_eta*delta_eta
743  do i = 1, nc_eta + 1
744  eta_i = eta_min + (i - 1)*delta_eta ! current grid point
745  ! loop over substeps
746  eta_k = eta_i
747  a_n = a(i)/jacobian(eta_i)
748  deltatsub = deltat/nsubsteps
749  do isub = 1, nsubsteps
750  ! first stage
751  eta_kp1 = eta_k + deltatsub*a_n
752  ! handle boundary conditions
753  if (bt == sll_p_periodic_ode) then
754  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
755  else if (bt == sll_p_compact_ode) then
756  if (eta_kp1 < eta_min) then
757  eta_kp1 = eta_min
758  else if (eta_kp1 > eta_max) then
759  eta_kp1 = eta_max
760  end if
761  else
762  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
763  end if
764 
765  ! localize cell [id, id+1] where eta_k is in
766  id = floor((eta_kp1 - eta_min)/delta_eta)
767  alpha = (eta_kp1 - eta_min)/delta_eta - id
768  ! compute linear interpolation of a at eta_k
769  a_np1 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
770  ! divide by jacobian of mesh
771  a_np1 = a_np1/jacobian(eta_kp1)
772  ! compute cubic Lagrange interpolation of a at eta_k
773  !a_np1 = -alpha*(alpha-1)*(alpha-2)/6 * a(id) + (alpha+1)*(alpha-1)*(alpha-2)/2 * a(id+1) &
774  ! - (alpha+1)*alpha*(alpha-2)/2 * a(id+2) + (alpha+1)*alpha*(alpha-1)/6 * a(id+3)
775  ! compute solution of ode for current grid point
776  eta_kp1 = eta_k + 0.5_f64*deltatsub*(a_n + a_np1)
777  ! handle boundary conditions
778  !print*, i, eta_kp1, eta_min, eta_max
779  if (bt == sll_p_periodic_ode) then
780  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
781  else if (bt == sll_p_compact_ode) then
782  if (eta_kp1 < eta_min) then
783  eta_kp1 = eta_min
784  else if (eta_kp1 > eta_max) then
785  eta_kp1 = eta_max
786  end if
787  else
788  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
789  end if
790  ! compute a_np1 at eta_kp1 for next substeps
791  ! localize cell [id, id+1] where eta_k is in
792  id = floor((eta_kp1 - eta_min)/delta_eta)
793  alpha = (eta_kp1 - eta_min)/delta_eta - id
794  ! compute linear interpolation of a at eta_k
795  a_np1 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
796  ! divide by jacobian of mesh
797  a_np1 = a_np1/jacobian(eta_kp1)
798  ! update
799  eta_k = eta_kp1
800  a_n = a_np1
801  end do
802  eta_out(i) = eta_k
803 
804  sll_assert((eta_out(i) >= eta_min) .and. (eta_out(i) <= eta_max))
805  end do
806  end subroutine rk2
807 
808  ! Classical fourth order Runge-Kutta ODE solver for an ode of the form
809  ! d eta/ dt = a(eta)
810  ! a is known only at grid points and linear interpolation is used in between
811  subroutine rk4(nsubsteps, &
812  deltat, &
813  eta_min, &
814  nc_eta, &
815  delta_eta, &
816  bt, &
817  eta_out, &
818  a, &
819  jac)
820  intrinsic :: floor
821  sll_int32 :: nsubsteps
822  sll_real64 :: deltat
823  sll_real64 :: eta_min
824  sll_int32 :: nc_eta ! number of cells of uniform grid
825  sll_real64 :: delta_eta
826  sll_int32 :: bt ! boundary_type
827  ! solution for all initial conditions:
828  sll_real64, dimension(:) :: eta_out
829  sll_real64, dimension(:) :: a ! rhs of ode
830  procedure(scalar_function_1d), pointer, optional :: jac
831  ! local variables
832  procedure(scalar_function_1d), pointer :: jacobian
833  sll_real64 :: eta_max
834  sll_real64 :: eta_i, eta_k, eta_kp1
835  sll_real64 :: deltatsub
836  sll_real64 :: a_n, a_np1, alpha, k2, k3, k4
837  sll_int32 :: i, id, isub
838 
839  if (present(jac)) then
840  jacobian => jac
841  else
842  jacobian => f_one
843  end if
844 
845  sll_assert(size(a) == nc_eta + 1)
846  sll_assert(size(eta_out) == nc_eta + 1)
847  ! compute eta_max of the grid
848  eta_max = eta_min + nc_eta*delta_eta
849  do i = 1, nc_eta + 1
850  eta_i = eta_min + (i - 1)*delta_eta ! current grid point
851  ! loop over substeps
852  eta_k = eta_i
853  a_n = a(i)/jacobian(eta_i)
854  deltatsub = deltat/nsubsteps
855  do isub = 1, nsubsteps
856  ! second stage
857  eta_kp1 = eta_k + 0.5_f64*deltatsub*a_n
858  ! handle boundary conditions
859  if (bt == sll_p_periodic_ode) then
860  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
861  else if (bt == sll_p_compact_ode) then
862  if (eta_kp1 < eta_min) then
863  eta_kp1 = eta_min
864  else if (eta_kp1 > eta_max) then
865  eta_kp1 = eta_max
866  end if
867  else
868  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
869  end if
870  ! localize cell [id, id+1] where eta_k is in
871  id = floor((eta_kp1 - eta_min)/delta_eta)
872  alpha = (eta_kp1 - eta_min)/delta_eta - id
873  ! compute linear interpolation of a at eta_k
874  k2 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
875  ! divide by jacobian of mesh
876  k2 = k2/jacobian(eta_kp1)
877 
878  ! third stage
879  eta_kp1 = eta_k + 0.5_f64*deltatsub*k2
880  ! handle boundary conditions
881  if (bt == sll_p_periodic_ode) then
882  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
883  else if (bt == sll_p_compact_ode) then
884  if (eta_kp1 < eta_min) then
885  eta_kp1 = eta_min
886  else if (eta_kp1 > eta_max) then
887  eta_kp1 = eta_max
888  end if
889  else
890  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
891  end if
892  ! localize cell [id, id+1] where eta_k is in
893  id = floor((eta_kp1 - eta_min)/delta_eta)
894  alpha = (eta_kp1 - eta_min)/delta_eta - id
895  ! compute linear interpolation of a at eta_k
896  k3 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
897  ! divide by jacobian of mesh
898  k3 = k3/jacobian(eta_kp1)
899 
900  ! fourth stage
901  eta_kp1 = eta_k + deltatsub*k3
902  ! handle boundary conditions
903  if (bt == sll_p_periodic_ode) then
904  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
905  else if (bt == sll_p_compact_ode) then
906  if (eta_kp1 < eta_min) then
907  eta_kp1 = eta_min
908  else if (eta_kp1 > eta_max) then
909  eta_kp1 = eta_max
910  end if
911  else
912  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
913  end if
914  ! localize cell [id, id+1] where eta_k is in
915  id = floor((eta_kp1 - eta_min)/delta_eta)
916  alpha = (eta_kp1 - eta_min)/delta_eta - id
917  ! compute linear interpolation of a at eta_k
918  k4 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
919  ! divide by jacobian of mesh
920  k4 = k4/jacobian(eta_kp1)
921  ! compute solution of ode for current grid point
922  eta_kp1 = eta_k + deltatsub/6.0_f64*(a_n + 2.0_f64*(k2 + k3) + k4)
923  ! handle boundary conditions
924  !print*, i, eta_kp1, eta_min, eta_max
925  if (bt == sll_p_periodic_ode) then
926  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
927  else if (bt == sll_p_compact_ode) then
928  if (eta_kp1 < eta_min) then
929  eta_kp1 = eta_min
930  else if (eta_kp1 > eta_max) then
931  eta_kp1 = eta_max
932  end if
933  else
934  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
935  end if
936  ! compute a_np1 at eta_kp1 for next substeps
937  ! localize cell [id, id+1] where eta_k is in
938  id = floor((eta_kp1 - eta_min)/delta_eta)
939  alpha = (eta_kp1 - eta_min)/delta_eta - id
940  ! compute linear interpolation of a at eta_k
941  a_np1 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
942  ! divide by jacobian of mesh
943  a_np1 = a_np1/jacobian(eta_kp1)
944  ! update
945  eta_k = eta_kp1
946  a_n = a_np1
947  end do
948  eta_out(i) = eta_k
949 
950  sll_assert((eta_out(i) >= eta_min) .and. (eta_out(i) <= eta_max))
951  end do
952  end subroutine rk4
953 
954  ! Classical fourth order Runge-Kutta ODE solver for an ode of the form
955  ! d eta/ dt = a(eta)
956  ! a is known only at grid points and linear interpolation is used in between
957  subroutine rk4_non_unif(nsubsteps, &
958  deltat, &
959  eta_min, &
960  nc_eta, &
961  delta_eta, &
962  bt, &
963  eta_out, &
964  a, &
965  xin)
966  intrinsic :: floor
967  sll_int32 :: nsubsteps
968  sll_real64 :: deltat
969  sll_real64 :: eta_min
970  sll_int32 :: nc_eta ! number of cells of uniform grid
971  sll_real64 :: delta_eta
972  sll_int32 :: bt ! boundary_type
973  ! solution for all initial conditions:
974  sll_real64, dimension(:) :: eta_out
975  sll_real64, dimension(:) :: a ! rhs of ode
976  sll_real64, dimension(:) :: xin ! rhs of ode
977 
978  sll_real64 :: eta_max
979  sll_real64 :: eta_i, eta_k, eta_kp1
980  sll_real64 :: deltatsub
981  sll_real64 :: a_n, a_np1, alpha, k2, k3, k4
982  sll_int32 :: i, id, isub
983 
984  sll_assert(size(a) == nc_eta + 1)
985  sll_assert(size(eta_out) == nc_eta + 1)
986  ! compute eta_max of the grid
987  eta_max = eta_min + nc_eta*delta_eta
988  do i = 1, nc_eta + 1
989  eta_i = eta_min + (i - 1)*delta_eta ! current grid point
990  ! loop over substeps
991  eta_k = eta_i
992  a_n = a(i)
993  deltatsub = deltat/nsubsteps
994  do isub = 1, nsubsteps
995  ! second stage
996  eta_kp1 = eta_k + 0.5_f64*deltatsub*a_n
997  ! handle boundary conditions
998  if (bt == sll_p_periodic_ode) then
999  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
1000  else if (bt == sll_p_compact_ode) then
1001  if (eta_kp1 < eta_min) then
1002  eta_kp1 = eta_min
1003  else if (eta_kp1 > eta_max) then
1004  eta_kp1 = eta_max
1005  end if
1006  else
1007  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
1008  end if
1009  ! localize cell [id, id+1] where eta_k is in
1010  id = floor((eta_kp1 - eta_min)/delta_eta)
1011  alpha = (eta_kp1 - eta_min)/delta_eta - id
1012  ! compute linear interpolation of a at eta_k
1013  k2 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
1014  ! divide by jacobian of mesh
1015 
1016  ! third stage
1017  eta_kp1 = eta_k + 0.5_f64*deltatsub*k2
1018  ! handle boundary conditions
1019  if (bt == sll_p_periodic_ode) then
1020  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
1021  else if (bt == sll_p_compact_ode) then
1022  if (eta_kp1 < eta_min) then
1023  eta_kp1 = eta_min
1024  else if (eta_kp1 > eta_max) then
1025  eta_kp1 = eta_max
1026  end if
1027  else
1028  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
1029  end if
1030  ! localize cell [id, id+1] where eta_k is in
1031  id = floor((eta_kp1 - eta_min)/delta_eta)
1032  alpha = (eta_kp1 - eta_min)/delta_eta - id
1033  ! compute linear interpolation of a at eta_k
1034  k3 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
1035  ! divide by jacobian of mesh
1036 
1037  ! fourth stage
1038  eta_kp1 = eta_k + deltatsub*k3
1039  ! handle boundary conditions
1040  if (bt == sll_p_periodic_ode) then
1041  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
1042  else if (bt == sll_p_compact_ode) then
1043  if (eta_kp1 < eta_min) then
1044  eta_kp1 = eta_min
1045  else if (eta_kp1 > eta_max) then
1046  eta_kp1 = eta_max
1047  end if
1048  else
1049  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
1050  end if
1051  ! localize cell [id, id+1] where eta_k is in
1052  id = floor((eta_kp1 - eta_min)/delta_eta)
1053  alpha = (eta_kp1 - eta_min)/delta_eta - id
1054  ! compute linear interpolation of a at eta_k
1055  k4 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
1056  ! divide by jacobian of mesh
1057 
1058  ! compute solution of ode for current grid point
1059  eta_kp1 = eta_k + deltatsub/6.0_f64*(a_n + 2.0_f64*(k2 + k3) + k4)
1060  ! handle boundary conditions
1061  !print*, i, eta_kp1, eta_min, eta_max
1062  if (bt == sll_p_periodic_ode) then
1063  eta_kp1 = eta_min + modulo(eta_kp1 - eta_min, eta_max - eta_min)
1064  else if (bt == sll_p_compact_ode) then
1065  if (eta_kp1 < eta_min) then
1066  eta_kp1 = eta_min
1067  else if (eta_kp1 > eta_max) then
1068  eta_kp1 = eta_max
1069  end if
1070  else
1071  stop 'sll_ode_solvers, rk2: boundary_type not implemented'
1072  end if
1073  ! compute a_np1 at eta_kp1 for next substeps
1074  ! localize cell [id, id+1] where eta_k is in
1075  id = floor((eta_kp1 - eta_min)/delta_eta)
1076  alpha = (eta_kp1 - eta_min)/delta_eta - id
1077  ! compute linear interpolation of a at eta_k
1078  a_np1 = (1.0_f64 - alpha)*a(id + 1) + alpha*a(id + 2)
1079  ! divide by jacobian of mesh
1080 
1081  ! update
1082  eta_k = eta_kp1
1083  a_n = a_np1
1084  end do
1085  eta_out(i) = eta_k
1086 
1087  sll_assert((eta_out(i) >= eta_min) .and. (eta_out(i) <= eta_max))
1088  end do
1089 
1090  return
1091  print *, xin !PN ADDED TO AVOID WARNING
1092  end subroutine rk4_non_unif
1093 
1094 end module sll_m_ode_solvers
subroutine implicit_ode_curv(order, deltat, eta_min, nc_eta, delta_eta, bt, eta_out, xfunc, xprimefunc, a, a_np1)
integer, parameter, public sll_p_compact_ode
integer, parameter, public sll_p_periodic_ode
subroutine, public sll_s_implicit_ode_nonuniform(order, deltat, xin, ncx, bt, xout, a, a_np1)
real(kind=f64) function f_one(eta)
subroutine implicit_ode_nonuniform_old(order, deltat, xin, ncx, bt, xout, a, a_np1)
subroutine rk4(nsubsteps, deltat, eta_min, nc_eta, delta_eta, bt, eta_out, a, jac)
subroutine rk2(nsubsteps, deltat, eta_min, nc_eta, delta_eta, bt, eta_out, a, jac)
subroutine rk4_non_unif(nsubsteps, deltat, eta_min, nc_eta, delta_eta, bt, eta_out, a, xin)
subroutine implicit_ode(order, deltat, xmin, ncx, deltax, bt, xout, a, a_np1)
Module to select the kind parameter.
    Report Typos and Errors