Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_gauss_lobatto_integration.F90
Go to the documentation of this file.
1 
9 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 #include "sll_working_precision.h"
11 
12  implicit none
13 
14  public :: &
20 
21  private
22 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 
24 #ifndef DOXYGEN_SHOULD_SKIP_THIS
25  abstract interface
26 
27  function function_1d(x)
28  use sll_m_working_precision ! can't pass a header file because the
29  ! preprocessor prevents double inclusion.
30  ! This is very rare.
31  sll_real64 :: function_1d
32  sll_real64, intent(in) :: x
33  end function function_1d
34  end interface
35 #endif
36 
39  module procedure gauss_lobatto_integral_1d
40  end interface
41 
42 contains
43 
61  function gauss_lobatto_integral_1d(f, a, b, n)
62  sll_real64 :: gauss_lobatto_integral_1d
63  procedure(function_1d) :: f
64  sll_real64, intent(in) :: a
65  sll_real64, intent(in) :: b
66  sll_int32, intent(in) :: n
67  sll_real64, dimension(n) :: xk
68  sll_real64, dimension(n) :: wk
69  sll_int32 :: k
70  sll_int32 :: err
71  sll_real64 :: alpha(0:n - 1), beta(0:n - 1)
72  sll_real64 :: de(n), da(n), db(n)
73  sll_real64 :: ans
74  !sll_real64 :: x
75  sll_real64 :: c1
76  sll_real64 :: c2
77 
78  xk(:) = 0.0_f64
79  wk(:) = 0.0_f64
80 
81  alpha = 0.0_f64
82  do k = 0, n - 1
83  beta(k) = real(k**2, f64)/real((2*k + 1)*(2*k - 1), f64)
84  end do
85 
86  !for Gauss-Legendre and Gauss-Lobatto, beta(0)=int(dlambda)
87  !see Algorithm xxx - ORTHPOL: A package of routines for generating orthogonal
88  !polynomials and Gauss-type quadrature rules by _Walter Gautschi_
89  beta(0) = 2.0_f64
90 
91  call dlob(n - 2, alpha, beta, -1.0_f64, 1.0_f64, xk, wk, err, de, da, db)
92 
93  xk(1) = -1.0_f64
94  xk(n) = 1.0_f64
95 
96  c1 = 0.5_f64*(b - a)
97  c2 = 0.5_f64*(b + a)
98  xk = c1*xk + c2
99  wk = c1*wk
100 
101  ans = 0.0_f64
102  do k = 1, n
103  ans = ans + f(xk(k))*wk(k)
104  end do
106 
107  end function gauss_lobatto_integral_1d
108 
115  function sll_f_gauss_lobatto_points_and_weights(n, a, b) result(wx)
116  sll_int32, intent(in) :: n
117  sll_real64, intent(in), optional :: a
118  sll_real64, intent(in), optional :: b
119  sll_real64, dimension(2, n) :: wx
120 
121  wx(1, 1:n) = sll_f_gauss_lobatto_points(n, a, b)
122  wx(2, 1:n) = sll_f_gauss_lobatto_weights(n, a, b)
123 
125 
132  function sll_f_gauss_lobatto_points(n, a, b) result(xk)
133  sll_int32, intent(in) :: n
134  sll_real64, intent(in), optional :: a
135  sll_real64, intent(in), optional :: b
136  sll_real64, dimension(n) :: xk
137  sll_real64, dimension(n) :: wk
138  sll_real64 :: c1, c2
139  sll_int32 :: k
140  sll_int32 :: err
141  sll_real64 :: alpha(0:n - 1), beta(0:n - 1)
142  sll_real64 :: de(n), da(n), db(n)
143 
144  xk(:) = 0.0_f64
145  wk(:) = 0.0_f64
146 
147  alpha = 0.0_f64
148  do k = 0, n - 1
149  beta(k) = real(k**2, f64)/real((2*k + 1)*(2*k - 1), f64)
150  end do
151 
152  !for Gauss-Legendre and Gauss-Lobatto, beta(0)=int(dlambda)
153  !see Algorithm xxx - ORTHPOL: A package of routines for generating orthogonal
154  !polynomials and Gauss-type quadrature rules by _Walter Gautschi_
155  beta(0) = 2.0_f64
156 
157  call dlob(n - 2, alpha, beta, -1._f64, 1._f64, xk, wk, err, de, da, db)
158  ! The results of this call can yield values that are beyond
159  ! the [-1;1] interval. Therefore we try to correct it
160  ! by forcing the boundary values.
161  ! FIXME : IT NEEDS TO BE CORRECTED. (TODO)
162  xk(1) = -1.0_f64
163  xk(n) = 1.0_f64
164 
165  if (present(a) .and. present(b)) then
166  c1 = 0.5_f64*(b - a)
167  c2 = 0.5_f64*(b + a)
168  xk = c1*xk + c2
169  end if
170 
171  end function sll_f_gauss_lobatto_points
172 
179  function sll_f_gauss_lobatto_weights(n, a, b) result(wk)
180  sll_int32, intent(in) :: n
181  sll_real64, intent(in), optional :: a
182  sll_real64, intent(in), optional :: b
183  sll_real64, dimension(n) :: xk
184  sll_real64, dimension(n) :: wk
185  sll_int32 :: k
186  sll_int32 :: err
187  sll_real64 :: alpha(0:n - 1), beta(0:n - 1)
188  sll_real64 :: de(n), da(n), db(n)
189  sll_real64 :: c1
190 
191  xk(:) = 0.0_f64
192  wk(:) = 0.0_f64
193 
194  alpha = 0.0_f64
195  do k = 0, n - 1
196  beta(k) = real(k**2, f64)/real((2*k + 1)*(2*k - 1), f64)
197  end do
198 
199  !for Gauss-Legendre and Gauss-Lobatto, beta(0)=int(dlambda)
200  !see Algorithm xxx - ORTHPOL: A package of routines for generating orthogonal
201  !polynomials and Gauss-type quadrature rules by _Walter Gautschi_
202  beta(0) = 2.0_f64
203 
204  call dlob(n - 2, alpha, beta, -1._f64, 1._f64, xk, wk, err, de, da, db)
205 
206  if (present(a) .and. present(b)) then
207  c1 = 0.5_f64*(b - a)
208  wk = c1*wk
209  end if
210  end function sll_f_gauss_lobatto_weights
211 
217  function sll_f_gauss_lobatto_derivative_matrix(n, y) result(d)
218  sll_int32, intent(in) :: n
219  sll_real64, optional :: y(n)
220  sll_real64 :: x(n)
221  sll_int32 :: i, j, l, m
222  sll_real64 :: prod
223  sll_real64 :: d(n, n)
224 
225  if (present(y)) then
226  x = y
227  else
229  end if
230 
231  d = 0.0_f64
232 
233  do j = 1, n
234  do i = 1, n
235  do l = 1, j - 1
236  prod = 1.0_f64
237  do m = 1, l - 1!min(j,l)-1
238  prod = prod*(x(i) - x(m))/(x(j) - x(m))
239  end do
240  do m = l + 1, j - 1!min(j,l)+1,max(j,l)-1
241  prod = prod*(x(i) - x(m))/(x(j) - x(m))
242  end do
243  do m = j + 1, n!max(j,l)+1,n
244  prod = prod*(x(i) - x(m))/(x(j) - x(m))
245  end do
246  prod = prod/(x(j) - x(l))
247  d(i, j) = d(i, j) + prod
248  end do
249  do l = j + 1, n
250  prod = 1.0_f64
251  do m = 1, j - 1!min(j,l)-1
252  prod = prod*(x(i) - x(m))/(x(j) - x(m))
253  end do
254  do m = j + 1, l - 1!min(j,l)+1,max(j,l)-1
255  prod = prod*(x(i) - x(m))/(x(j) - x(m))
256  end do
257  do m = l + 1, n!max(j,l)+1,n
258  prod = prod*(x(i) - x(m))/(x(j) - x(m))
259  end do
260  prod = prod/(x(j) - x(l))
261  d(i, j) = d(i, j) + prod
262  end do
263  end do
264  end do
265 
267 
312  subroutine dlob(n, dalpha, dbeta, dleft, dright, dzero, dweigh, ierr, de, da, db)
313 
314  sll_int32 :: n, ierr, k, np1, np2
315  sll_real64 :: dleft, dright, depsma, dp0l, dp0r, dp1l, dp1r, dpm1l
316  sll_real64 :: dpm1r, ddet, dalpha(*), dbeta(*), dzero(*), dweigh(*), de(*), da(*), db(*)
317 
318  depsma = epsilon(1.0_f64)
319  np1 = n + 1
320  np2 = n + 2
321  do 10 k = 1, np2
322  da(k) = dalpha(k)
323  db(k) = dbeta(k)
324 10 continue
325  dp0l = 0.0_f64
326  dp0r = 0.0_f64
327  dp1l = 1.0_f64
328  dp1r = 1.0_f64
329  do 20 k = 1, np1
330  dpm1l = dp0l
331  dp0l = dp1l
332  dpm1r = dp0r
333  dp0r = dp1r
334  dp1l = (dleft - da(k))*dp0l - db(k)*dpm1l
335  dp1r = (dright - da(k))*dp0r - db(k)*dpm1r
336 20 continue
337  ddet = dp1l*dp0r - dp1r*dp0l
338  da(np2) = (dleft*dp1l*dp0r - dright*dp1r*dp0l)/ddet
339  db(np2) = (dright - dleft)*dp1l*dp1r/ddet
340  call dgauss(np2, da, db, depsma, dzero, dweigh, ierr, de)
341  return
342  end subroutine dlob
343 
388  subroutine dgauss(n, dalpha, dbeta, deps, dzero, dweigh, ierr, de)
389  sll_int32 :: n, ierr, i, ii, j, k, l, m, mml
390  sll_real64 :: deps
391  sll_real64 :: dp, dg, dr, ds, dc, df, db
392  sll_real64 :: dalpha(n), dbeta(n), dzero(n), dweigh(n), de(n)
393 
394  if (n .lt. 1) then
395  ierr = -1
396  return
397  end if
398  ierr = 0
399  dzero(1) = dalpha(1)
400  if (dbeta(1) .lt. 0.0_f64) then
401  ierr = -2
402  return
403  end if
404  dweigh(1) = dbeta(1)
405  if (n .eq. 1) return
406  dweigh(1) = 1.0_f64
407  de(n) = 0.0_f64
408  do 100 k = 2, n
409  dzero(k) = dalpha(k)
410  if (dbeta(k) .lt. 0.0_f64) then
411  ierr = -2
412  return
413  end if
414  de(k - 1) = sqrt(dbeta(k))
415  dweigh(k) = 0.0_f64
416 100 continue
417  do 240 l = 1, n
418  j = 0
419 105 do 110 m = l, n
420  if (m .eq. n) goto 120
421  if (abs(de(m)) .le. deps*(abs(dzero(m)) + abs(dzero(m + 1)))) goto 120
422 110 continue
423 120 dp = dzero(l)
424  if (m .eq. l) goto 240
425  if (j .eq. 30) goto 400
426  j = j + 1
427  dg = (dzero(l + 1) - dp)/(2.0_f64*de(l))
428  dr = sqrt(dg*dg + 1.0_f64)
429  dg = dzero(m) - dp + de(l)/(dg + sign(dr, dg))
430  ds = 1.0_f64
431  dc = 1.0_f64
432  dp = 0.0_f64
433  mml = m - l
434  do 200 ii = 1, mml
435  i = m - ii
436  df = ds*de(i)
437  db = dc*de(i)
438  if (abs(df) .lt. abs(dg)) goto 150
439  dc = dg/df
440  dr = sqrt(dc*dc + 1.0_f64)
441  de(i + 1) = df*dr
442  ds = 1.0_f64/dr
443  dc = dc*ds
444  goto 160
445 150 ds = df/dg
446  dr = sqrt(ds*ds + 1.0_f64)
447  de(i + 1) = dg*dr
448  dc = 1.0_f64/dr
449  ds = ds*dc
450 160 dg = dzero(i + 1) - dp
451  dr = (dzero(i) - dg)*ds + 2.0_f64*dc*db
452  dp = ds*dr
453  dzero(i + 1) = dg + dp
454  dg = dc*dr - db
455  df = dweigh(i + 1)
456  dweigh(i + 1) = ds*dweigh(i) + dc*df
457  dweigh(i) = dc*dweigh(i) - ds*df
458 200 continue
459  dzero(l) = dzero(l) - dp
460  de(l) = dg
461  de(m) = 0.0_f64
462  goto 105
463 240 continue
464  do 300 ii = 2, n
465  i = ii - 1
466  k = i
467  dp = dzero(i)
468  do 260 j = ii, n
469  if (dzero(j) .ge. dp) goto 260
470  k = j
471  dp = dzero(j)
472 260 continue
473  if (k .eq. i) goto 300
474  dzero(k) = dzero(i)
475  dzero(i) = dp
476  dp = dweigh(i)
477  dweigh(i) = dweigh(k)
478  dweigh(k) = dp
479 300 continue
480  do 310 k = 1, n
481  dweigh(k) = dbeta(1)*dweigh(k)*dweigh(k)
482 310 continue
483  return
484 400 ierr = l
485  return
486  end subroutine dgauss
487 
function, public sll_f_gauss_lobatto_derivative_matrix(n, y)
Construction of the derivative matrix for Gauss-Lobatto, The matrix must be already allocated of size...
subroutine dgauss(n, dalpha, dbeta, deps, dzero, dweigh, ierr, de)
Given n and a measure dlambda, this routine generates the n-point Gaussian quadrature formula.
real(kind=f64) function, dimension(n), public sll_f_gauss_lobatto_points(n, a, b)
Returns a 1d array of size (n) containing gauss-lobatto points in the interval [a,...
real(kind=f64) function, dimension(n), public sll_f_gauss_lobatto_weights(n, a, b)
Returns a 1d array of size (n) containing gauss-lobatto weights in the interval [a,...
real(kind=f64) function, dimension(2, n), public sll_f_gauss_lobatto_points_and_weights(n, a, b)
Returns a 2d array of size (2,n) containing gauss-lobatto points and weights in the interval [a,...
subroutine dlob(n, dalpha, dbeta, dleft, dright, dzero, dweigh, ierr, de, da, db)
This comes from http://dl.acm.org, Algorithme 726 : ORTHPOL, appendices and supplements To use those ...
real(kind=f64) function gauss_lobatto_integral_1d(f, a, b, n)
Gauss-Lobatto Quadrature.
Module to select the kind parameter.
    Report Typos and Errors