Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_gauss_legendre_integration.F90
Go to the documentation of this file.
1 
9 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 #include "sll_assert.h"
11 #include "sll_working_precision.h"
12 
13  implicit none
14 
15  public :: &
20 
21  private
22 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 
24  ! The following interface is supposed to represent any function of one
25  ! real argument that returns a real value (double precision).
26  !
27  ! We are exploring the approach of having multiple versions of the
28  ! integrators, each with an interface as simple as possible. Ultimately,
29  ! all of these functions can be made to exist behind a single
30  ! generic interface.
31  !
32  ! The ugly aspect of this approach is that it loses modularity: for
33  ! example, to specialize the integrator on the 'interpolated_function_1d'
34  ! requires use of the spline module.
35 
36 ! Doxygen do not manage abstract interface
37 #ifndef DOXYGEN_SHOULD_SKIP_THIS
38  abstract interface
39 
40  function function_1d_legendre(x)
41  use sll_m_working_precision ! can't pass a header file because the
42  ! preprocessor prevents double inclusion.
43  ! This is very rare.
44  sll_real64 :: function_1d_legendre
45  sll_real64, intent(in) :: x
46  end function function_1d_legendre
47  end interface
48 #endif
49 
50 ! abstract interface
51 ! function interpolated_function_1d(x,spline_obj)
52 ! use sll_m_working_precision
53 ! use sll_splines
54 ! sll_real64 :: interpolated_function_1d
55 ! sll_real64, intent(in) :: x
56 ! type(sll_spline_1d), pointer :: spline_obj
57 ! end function interpolated_function_1d
58 ! end interface
59 
62  module procedure gauss_legendre_integral_1d !,gauss_legendre_integral_interpolated_1d
63  end interface
64 
65 contains
66 
67  ! object macro to put all the gauss points and weights in a single place.
68  ! The fact that we have such case statement in a function that could be
69  ! used inside a critical loop is a flaw. Eventually we should split
70  ! the integrators into individual cases. For now, we leave this as is
71  ! due to the advantage of the simplified interface.
72 
73 #define SELECT_CASES \
74  case (1); \
75  xk(1) = 0.0_f64; wk(1) = 2.0_f64; \
76  case (2); \
77  xk(1) = -1.0_f64/sqrt(3.0_f64); wk(1) = 1.0_f64; \
78  xk(2) = 1.0_f64/sqrt(3.0_f64); wk(2) = 1.0_f64; \
79  case (3); \
80  xk(1) = -sqrt(3.0_f64/5.0_f64); wk(1) = 5.0_f64/9.0_f64; \
81  xk(2) = 0.0_f64; wk(2) = 8.0_f64/9.0_f64; \
82  xk(3) = sqrt(3.0_f64/5.0_f64); wk(3) = 5.0_f64/9.0_f64; \
83  case (4); \
84  xk(1) = -sqrt((3.0_f64 + 2.0_f64*sqrt(6.0_f64/5.0_f64))/7.0_f64); \
85  xk(2) = -sqrt((3.0_f64 - 2.0_f64*sqrt(6.0_f64/5.0_f64))/7.0_f64); \
86  xk(3) = sqrt((3.0_f64 - 2.0_f64*sqrt(6.0_f64/5.0_f64))/7.0_f64); \
87  xk(4) = sqrt((3.0_f64 + 2.0_f64*sqrt(6.0_f64/5.0_f64))/7.0_f64); \
88  wk(1) = (18.0_f64 - sqrt(30.0_f64))/36.0_f64; \
89  wk(2) = (18.0_f64 + sqrt(30.0_f64))/36.0_f64; \
90  wk(3) = (18.0_f64 + sqrt(30.0_f64))/36.0_f64; \
91  wk(4) = (18.0_f64 - sqrt(30.0_f64))/36.0_f64; \
92  case (5); \
93  xk(1) = -0.9061798459386637_f64; wk(1) = 0.2369268850561887_f64; \
94  xk(2) = -0.5384693101056831_f64; wk(2) = 0.4786286704993665_f64; \
95  xk(3) = 0.0_f64; wk(3) = 0.5688888888888888_f64; \
96  xk(4) = 0.5384693101056831_f64; wk(4) = 0.4786286704993665_f64; \
97  xk(5) = 0.9061798459386637_f64; wk(5) = 0.2369268850561887_f64; \
98  case (6); \
99  xk(1) = -0.9324695142031524_f64; wk(1) = 0.1713244923791715_f64; \
100  xk(2) = -0.6612093864662643_f64; wk(2) = 0.3607615730481376_f64; \
101  xk(3) = -0.2386191860831966_f64; wk(3) = 0.4679139345726911_f64; \
102  xk(4) = 0.2386191860831966_f64; wk(4) = 0.4679139345726911_f64; \
103  xk(5) = 0.6612093864662643_f64; wk(5) = 0.3607615730481376_f64; \
104  xk(6) = 0.9324695142031524_f64; wk(6) = 0.1713244923791715_f64; \
105  case (7); \
106  xk(1) = -0.9491079123427587_f64; wk(1) = 0.1294849661688697_f64; \
107  xk(2) = -0.7415311855993930_f64; wk(2) = 0.2797053914892763_f64; \
108  xk(3) = -0.4058451513773973_f64; wk(3) = 0.3818300505051193_f64; \
109  xk(4) = 0._f64; wk(4) = 0.41795918367346824_f64; \
110  xk(5) = 0.4058451513773973_f64; wk(5) = 0.3818300505051193_f64; \
111  xk(6) = 0.7415311855993930_f64; wk(6) = 0.2797053914892763_f64; \
112  xk(7) = 0.9491079123427587_f64; wk(7) = 0.1294849661688697_f64; \
113  case (8); \
114  xk(1) = -0.9602898564975370_f64; wk(1) = 0.10122853629037747_f64; \
115  xk(2) = -0.7966664774136267_f64; wk(2) = 0.22238103445337337_f64; \
116  xk(3) = -0.5255324099163288_f64; wk(3) = 0.31370664587788677_f64; \
117  xk(4) = -0.1834346424956503_f64; wk(4) = 0.36268378337836155_f64; \
118  xk(5) = 0.1834346424956503_f64; wk(5) = 0.36268378337836155_f64; \
119  xk(6) = 0.5255324099163288_f64; wk(6) = 0.31370664587788677_f64; \
120  xk(7) = 0.7966664774136267_f64; wk(7) = 0.22238103445337337_f64; \
121  xk(8) = 0.9602898564975370_f64; wk(8) = 0.10122853629037747_f64; \
122  case (9); \
123  xk(1) = -0.968160239507626_f64; wk(1) = 0.081274388361574_f64; \
124  xk(2) = -0.836031107326636_f64; wk(2) = 0.180648160694857_f64; \
125  xk(3) = -0.613371432700590_f64; wk(3) = 0.260610696402935_f64; \
126  xk(4) = -0.324253423403809_f64; wk(4) = 0.312347077040003_f64; \
127  xk(5) = 0.0_f64; wk(5) = 0.330239355001260_f64; \
128  xk(6) = 0.324253423403809_f64; wk(6) = 0.312347077040003_f64; \
129  xk(7) = 0.613371432700590_f64; wk(7) = 0.260610696402935_f64; \
130  xk(8) = 0.836031107326636_f64; wk(8) = 0.180648160694857_f64; \
131  xk(9) = 0.968160239507626_f64; wk(9) = 0.081274388361574_f64; \
132  case (10); \
133  xk(1) = -0.973906528517172_f64; wk(1) = 0.066671344308688_f64; \
134  xk(2) = -0.865063366688985_f64; wk(2) = 0.149451349150581_f64; \
135  xk(3) = -0.679409568299024_f64; wk(3) = 0.219086362515982_f64; \
136  xk(4) = -0.433395394129247_f64; wk(4) = 0.269266719309996_f64; \
137  xk(5) = -0.148874338981631_f64; wk(5) = 0.295524224714753_f64; \
138  xk(6) = 0.148874338981631_f64; wk(6) = 0.295524224714753_f64; \
139  xk(7) = 0.433395394129247_f64; wk(7) = 0.269266719309996_f64; \
140  xk(8) = 0.679409568299024_f64; wk(8) = 0.219086362515982_f64; \
141  xk(9) = 0.865063366688985_f64; wk(9) = 0.149451349150581_f64; \
142  xk(10) = 0.973906528517172_f64; wk(10) = 0.066671344308688_f64; \
143  case default; \
144  print *, 'sll_m_gauss_legendre_integration: '; \
145  print *, 'degree of integration not implemented. Exiting...'; \
146  stop;
164  function gauss_legendre_integral_1d(f, a, b, n)
165  intrinsic :: sqrt
166  sll_real64 :: gauss_legendre_integral_1d
167  procedure(function_1d_legendre) :: f
168  sll_real64, intent(in) :: a
169  sll_real64, intent(in) :: b
170  sll_int32, intent(in) :: n ! needs better name
171  sll_real64, dimension(1:10) :: xk
172  sll_real64, dimension(1:10) :: wk
173  sll_int32 :: k
174  sll_real64 :: x
175  sll_real64 :: c1
176  sll_real64 :: c2
177  sll_real64 :: ans
178  xk(:) = 0.0_f64
179  wk(:) = 0.0_f64
180  select case (n)
181  select_cases
182  end select
183  ans = 0.0_f64
184  ! need to map the interval [-1,1] into the interval [a,b]
185  c1 = 0.5_f64*(b - a)
186  c2 = 0.5_f64*(b + a)
187  do k = 1, n
188  x = c1*xk(k) + c2
189  ans = ans + f(x)*wk(k)
190  end do
192  end function gauss_legendre_integral_1d
193 
194  ! Consider changing this into a function that simply receives as an
195  ! argument the spline_1d object and internally calls the interpolate_from_interpolant_value()
196  ! function. This would have a simpler interface. Although, there could be
197  ! some advantages to have the interpolating function parametrized also, like
198  ! in this case.
199  !---------------------------------------------------------------------------
200  ! @author
201  ! Routine Author Name and Affiliation.
202  !
203  ! DESCRIPTION:
204  ! @brief Integrates a function represented by a spline object.
205  ! @details The function f in this case is the spline interpolation function.
206  ! It looks like this interface could be simplified and we could eliminate
207  ! the first parameter and pass only the spline object.
208  ! The only reason to leave the interpolation function as an argument is if
209  ! we find some compelling reason to parametrize the interpolation function as well.
210  !
211  ! REVISION HISTORY:
212  ! TODO_dd_mmm_yyyy - TODO_describe_appropriate_changes - TODO_name
213  !
214  ! @param f the spline interpolation function
215  ! @param spline a spline
216  ! @param[in] a left-bound of the definition interval of f
217  ! @param[in] b right-bound of the definition interval of f
218  ! @param[in] n the desired number of Gauss points
219  ! @return The value of the integral
220  !---------------------------------------------------------------------------
221 !!$ function gauss_legendre_integral_interpolated_1d( f, spline, a, b, n )
222 !!$ intrinsic :: sqrt
223 !!$ sll_real64 :: gauss_legendre_integral_interpolated_1d
224 !!$ procedure(interpolated_function_1d) :: f
225 !!$ type(sll_spline_1d), pointer :: spline
226 !!$ sll_real64, intent(in) :: a
227 !!$ sll_real64, intent(in) :: b
228 !!$ sll_int32, intent(in) :: n ! needs better name
229 !!$ sll_real64, dimension(1:10) :: xk
230 !!$ sll_real64, dimension(1:10) :: wk
231 !!$ sll_int32 :: k
232 !!$ sll_real64 :: x
233 !!$ sll_real64 :: c1
234 !!$ sll_real64 :: c2
235 !!$ sll_real64 :: ans
236 !!$ xk(:) = 0.0_f64
237 !!$ wk(:) = 0.0_f64
238 !!$ select case(n)
239 !!$ /* SELECT_CASES */
240 !!$ end select
241 !!$ ans = 0.0
242 !!$ ! need to map the interval [-1,1] into the interval [a,b]
243 !!$ c1 = 0.5_f64*(b-a)
244 !!$ c2 = 0.5_f64*(b+a)
245 !!$ do k=1,n
246 !!$ x = c1*xk(k) + c2
247 !!$ ans = ans + f(x,spline)*wk(k)
248 !!$ end do
249 !!$ gauss_legendre_integral_interpolated_1d = c1*ans
250 !!$ end function gauss_legendre_integral_interpolated_1d
251 
264  function sll_f_gauss_legendre_points_and_weights(npoints, a, b) result(xw)
265  sll_int32, intent(in) :: npoints
266  sll_real64, intent(in), optional :: a
267  sll_real64, intent(in), optional :: b
268  sll_real64, dimension(2, 1:npoints) :: xw
269  sll_real64, dimension(1:npoints) :: xk
270  sll_real64, dimension(1:npoints) :: wk
271  sll_real64 :: c1
272  sll_real64 :: c2
273  sll_int32 :: k
274 
275  sll_assert(npoints >= 1)
276 
277  xk(:) = 0.0_f64
278  wk(:) = 0.0_f64
279 
280  ! fill out the xk and wk arrays.
281  select case (npoints)
282  select_cases
283  end select
284 
285  if (present(a) .and. present(b)) then
286  ! need to map the interval [-1,1] into the interval [a,b].
287  c1 = 0.5_f64*(b - a)
288  c2 = 0.5_f64*(b + a)
289  do k = 1, npoints
290  xw(1, k) = c1*xk(k) + c2
291  xw(2, k) = wk(k)*c1
292  end do
293  else ! use default values in the [-1,1] interval
294  xw(1, 1:npoints) = xk(1:npoints)
295  xw(2, 1:npoints) = wk(1:npoints)
296  end if
297 
299 
300  function sll_f_gauss_legendre_points(npoints, a, b) result(xw)
301  sll_int32, intent(in) :: npoints
302  sll_real64, intent(in), optional :: a
303  sll_real64, intent(in), optional :: b
304  sll_real64, dimension(1:npoints) :: xw
305  sll_real64, dimension(1:npoints) :: xk
306  sll_real64, dimension(1:npoints) :: wk
307  sll_real64 :: c1
308  sll_real64 :: c2
309  sll_int32 :: k
310 
311  sll_assert(npoints >= 1)
312 
313  xk(:) = 0.0_f64
314  wk(:) = 0.0_f64
315 
316  ! fill out the xk and wk arrays.
317  select case (npoints)
318  select_cases
319  end select
320 
321  if (present(a) .and. present(b)) then
322  ! need to map the interval [-1,1] into the interval [a,b].
323  c1 = 0.5_f64*(b - a)
324  c2 = 0.5_f64*(b + a)
325  do k = 1, npoints
326  xw(k) = c1*xk(k) + c2
327  end do
328  else ! use default values in the [-1,1] interval
329  xw(1:npoints) = xk(1:npoints)
330  end if
331 
332  end function sll_f_gauss_legendre_points
333 
334  function sll_f_gauss_legendre_weights(npoints, a, b) result(xw)
335  sll_int32, intent(in) :: npoints
336  sll_real64, intent(in), optional :: a
337  sll_real64, intent(in), optional :: b
338  sll_real64, dimension(1:npoints) :: xw
339  sll_real64, dimension(1:npoints) :: xk
340  sll_real64, dimension(1:npoints) :: wk
341  sll_real64 :: c1
342  sll_real64 :: c2
343  sll_int32 :: k
344 
345  sll_assert(npoints >= 1)
346 
347  xk(:) = 0.0_f64
348  wk(:) = 0.0_f64
349 
350  ! fill out the xk and wk arrays.
351  select case (npoints)
352  select_cases
353  end select
354 
355  if (present(a) .and. present(b)) then
356  ! need to map the interval [-1,1] into the interval [a,b].
357  c1 = 0.5_f64*(b - a)
358  c2 = 0.5_f64*(b + a)
359  do k = 1, npoints
360  xw(k) = wk(k)*c1
361  end do
362  else ! use default values in the [-1,1] interval
363  xw(1:npoints) = wk(1:npoints)
364  end if
365 
366  end function sll_f_gauss_legendre_weights
367 
real(kind=f64) function, dimension(2, 1:npoints), public sll_f_gauss_legendre_points_and_weights(npoints, a, b)
Returns a 2d array of size (2,npoints) containing gauss-legendre points and weights in the interval [...
real(kind=f64) function, dimension(1:npoints), public sll_f_gauss_legendre_points(npoints, a, b)
real(kind=f64) function, dimension(1:npoints), public sll_f_gauss_legendre_weights(npoints, a, b)
real(kind=f64) function gauss_legendre_integral_1d(f, a, b, n)
Gauss-Legendre Quadrature.
Module to select the kind parameter.
    Report Typos and Errors