gjp_rec.f90
Go to the documentation of this file.
1 ! BEGIN_HEADER
2 ! -----------------------------------------------------------------------------
3 ! Gauss-Jacobi Quadrature Implementation
4 ! Authors: Rohit Goswami <rgoswami[at]ieee.org>
5 ! Source: GaussJacobiQuad Library
6 ! License: MIT
7 ! GitHub Repository: https://github.com/HaoZeke/GaussJacobiQuad
8 ! Date: 2023-08-28
9 ! Commit: c442f77
10 ! -----------------------------------------------------------------------------
11 ! This code is part of the GaussJacobiQuad library, providing an efficient
12 ! implementation for Gauss-Jacobi quadrature nodes and weights computation.
13 ! -----------------------------------------------------------------------------
14 ! To cite this software:
15 ! Rohit Goswami (2023). HaoZeke/GaussJacobiQuad: v0.1.0.
16 ! Zenodo: https://doi.org/10.5281/ZENODO.8285112
17 ! ---------------------------------------------------------------------
18 ! END_HEADER
20 !
21 !! @details This module implements the Gauss-Jacobi quadrature method for numerical integration.
22 !! It provides subroutines for computing the Jacobi polynomials, recurrence relations,
23 !! and evaluation of the polynomials and their derivatives.
24 !! The implementation is based on the recurrence method in chebfun (https://chebfun.org)
25 !! and the paper:
26 !! Hale and Townsend, Fast and accurate computation of Gauss–Legendre and
27 !! Gauss–Jacobi quadrature nodes and weights, SIAM J. Sci. Comp. 2013
28 module gjp_rec
29 use gjp_types, only: dp
30 use gjp_constants, only: pi
31 implicit none
32 contains
33 
34 ! This returns unsorted roots and weights
35 subroutine gauss_jacobi_rec(npts, alpha, beta, x, wts)
36  integer, intent(in) :: npts
37  real(dp), intent(in) :: alpha, beta
38  real(dp), intent(out) :: x(npts), wts(npts)
39  real(dp), dimension(ceiling(npts/2._dp)) :: x1, ders1
40  real(dp), dimension(npts/2) :: x2, ders2
41  real(dp) :: ders(npts), C
42  integer :: idx
43  call recurrence(npts, ceiling(npts / 2._dp), alpha, beta, x1, ders1)
44  call recurrence(npts, npts / 2, beta, alpha, x2, ders2)
45  do idx = 1, npts / 2
46  x(idx) = -x2(npts / 2 - idx + 1)
47  ders(idx) = ders2(npts / 2 - idx + 1)
48  end do
49  do idx = 1, ceiling(npts / 2._dp)
50  x(npts / 2 + idx) = x1(idx)
51  ders(npts / 2 + idx) = ders1(idx)
52  end do
53  wts = 1.0_dp / ((1.0_dp - x**2) * ders**2)
54  c = 2**(alpha + beta + 1) * exp(log_gamma(npts + alpha + 1) - &
55  log_gamma(npts + alpha + beta + 1) + &
56  log_gamma(npts + beta + 1) - log_gamma(npts + 1._dp))
57  wts = wts * c
58 end subroutine gauss_jacobi_rec
59 
60 subroutine recurrence(npts, n2, alpha, beta, x, PP)
61  integer, intent(in) :: npts, n2
62  real(dp), intent(in) :: alpha, beta
63  real(dp), intent(out) :: x(n2), PP(n2)
64  real(dp) :: dx(n2), P(n2)
65  integer :: r(n2), l, i
66  real(dp) :: C, T
67 
68  do i = 1, n2
69  r(i) = n2 - i + 1
70  end do
71 
72  do i = 1, n2
73  c = (2 * r(i) + alpha - 0.5_dp) * pi / (2 * npts + alpha + beta + 1)
74  t = c + 1 / (2 * npts + alpha + beta + 1)**2 * ((0.25_dp - alpha**2) / tan(0.5_dp * c) - (0.25_dp - beta**2) * tan(0.5_dp * c))
75  x(i) = cos(t)
76  end do
77 
78  dx = 1.0_dp
79  l = 0
80 
81  do while (maxval(abs(dx)) > sqrt(epsilon(1.0_dp)) / 1000 .and. l < 10)
82  l = l + 1
83  call eval_jacobi_poly(x, npts, alpha, beta, p, pp)
84  dx = -p / pp
85  x = x + dx
86  end do
87 
88  call eval_jacobi_poly(x, npts, alpha, beta, p, pp)
89 end subroutine
90 
91 subroutine eval_jacobi_poly(x, npts, alpha, beta, P, Pp)
92  integer, intent(in) :: npts
93  real(dp), intent(in) :: alpha, beta
94  real(dp), intent(in) :: x(:)
95  real(dp), dimension(size(x)), intent(out) :: P, Pp
96  real(dp), dimension(size(x)) :: Pm1, Ppm1, Pa1, Ppa1
97  integer :: k, i
98  real(dp) :: A_val, B_val, C_val, D_val
99 
100  p = 0.5_dp * (alpha - beta + (alpha + beta + 2) * x)
101  pm1 = 1.0_dp
102  pp = 0.5_dp * (alpha + beta + 2)
103  ppm1 = 0.0_dp
104 
105  if (npts == 0) then
106  p = pm1
107  pp = ppm1
108  end if
109 
110  do k = 1, npts - 1
111  a_val = 2 * (k + 1) * (k + alpha + beta + 1) * (2 * k + alpha + beta)
112  b_val = (2 * k + alpha + beta + 1) * (alpha**2 - beta**2)
113  c_val = product([(2 * k + alpha + beta + i, i=0, 2)])
114  d_val = 2 * (k + alpha) * (k + beta) * (2 * k + alpha + beta + 2)
115 
116  pa1 = ((b_val + c_val * x) * p - d_val * pm1) / a_val
117  ppa1 = ((b_val + c_val * x) * pp + c_val * p - d_val * ppm1) / a_val
118 
119  pm1 = p
120  p = pa1
121  ppm1 = pp
122  pp = ppa1
123  end do
124 end subroutine
125 
126 end module gjp_rec
Constants contain more digits than double precision, so that they are rounded correctly.
real(dp), parameter, public pi
This is derived from the recurrence relations in chebfun.
Definition: gjp_rec.f90:28
subroutine recurrence(npts, n2, alpha, beta, x, PP)
Definition: gjp_rec.f90:61
subroutine gauss_jacobi_rec(npts, alpha, beta, x, wts)
Definition: gjp_rec.f90:36
subroutine eval_jacobi_poly(x, npts, alpha, beta, P, Pp)
Definition: gjp_rec.f90:92
Module for defining types and precision levels for Gauss-Jacobi Polynomial (GJP) calculations.
Definition: gjp_types.f90:33
integer, parameter, public dp
Define various kinds for real numbers.
Definition: gjp_types.f90:39