FE-Project
Loading...
Searching...
No Matches
scale_polynomial.F90
Go to the documentation of this file.
1!> Module common / Polynomial
2!!
3!! @par Description
4!! A module to provide utilities for polynomials
5!!
6!! @par Reference
7!!
8!! @author Yuta Kawai, Team SCALE
9!!
10#include "scaleFElib.h"
12 !-----------------------------------------------------------------------------
13 !
14 !++ used modules
15 !
16 use scale_precision
17 use scale_const, only: &
18 pi => const_pi
19 use scale_io
20
21 !-----------------------------------------------------------------------------
22 implicit none
23 private
24 !-----------------------------------------------------------------------------
25 !
26 !++ Public procedure
27 !
28
32
35
38
42
43 !-----------------------------------------------------------------------------
44 !
45 !++ Public parameters & variables
46 !
47
48 !-----------------------------------------------------------------------------
49 !
50 !++ Private procedure
51 !
52
53 !-----------------------------------------------------------------------------
54 !
55 !++ Private parameters & variables
56 !
57 private :: gen_jacobigaussquadraturepts
58
59 !-----------------------------------------------------------------------------
60
61contains
62 !> A function to obtain the Lagrange basis functions related to the Gauss-Legendre-Lobatto (GLL) points
63 !!
64 !! @param Nord Order of Lagrange polynomial
65 !! @param x_lgl Positions of GLL points
66 !! @param x Positions where the Lagrange basis functions are evaluated
67!OCL SERIAL
68 function polynomial_genlagrangepoly(Nord, x_lgl, x) result(l)
69 implicit none
70
71 integer, intent(in) :: nord
72 real(rp), intent(in) :: x_lgl(nord+1)
73 real(rp), intent(in) :: x(:)
74 real(rp) :: l(size(x), nord+1)
75
76 integer :: n, i
77 real(rp) :: p_lgl(nord+1,nord+1)
78 real(rp) :: p(size(x),nord+1)
79 real(rp) :: pr(size(x),nord+1)
80
81 ! real(RP) :: w(Nord+1)
82 ! real(RP) :: int_w(Nord+1)
83 !---------------------------------------------------------------------------
84
85 p_lgl(:,:) = polynomial_genlegendrepoly(nord, x_lgl)
86 p(:,:) = polynomial_genlegendrepoly(nord, x)
87 pr(:,:) = polynomial_gendlegendrepoly(nord, x, p)
88
89 do n=1, nord+1
90 do i=1, size(x)
91 if ( abs(x(i)-x_lgl(n)) < 1e-15_rp ) then
92 l(i,n) = 1.0_rp
93 else
94 l(i,n) = &
95 (x(i) - 1.0_rp)*(x(i) + 1.0_rp)*pr(i,nord+1) &
96 / (dble(nord*(nord+1))*p_lgl(n,nord+1)*(x(i) - x_lgl(n)))
97 end if
98 end do
99 end do
100
101 !- Calculate interpolation coefficient based on barycentric form
102 ! Eq. (3.46) in Wang, Huybrechs & Vandewalle (2012): Explicit barycentric weights for polynomial interpolation in the roots or extrema of classical orthogonal polynomials
103 ! int_w(:) = Polynomial_GenGaussLobattoPtIntWeight( Nord )
104 ! do n=1, Nord+1
105 ! w(n) = (-1)**mod(n-1,2) * sqrt(int_w(n))
106 ! end do
107 ! do n=1, Nord+1
108 ! do i=1, size(x)
109 ! if ( abs(x(i)-x_lgl(n)) < 1E-16_RP ) then
110 ! l(i,n) = 1.0_RP
111 ! else
112 ! l(i,n) = &
113 ! ( w(n) / ( x(i) - x_lgl(n) ) ) &
114 ! / sum( w(:) / ( x(i) - x_lgl(:) ) )
115 ! end if
116 ! end do
117 ! end do
118
119 return
120 end function polynomial_genlagrangepoly
121
122 !> Differential values of Lagrange basis functions at the GLL points
123 !!
124 !! @param Nord Order of Lagrange polynomial
125 !! @param x_lgl Positions of GLL points
126!OCL SERIAL
127 function polynomial_gendlagrangepoly_lglpt(Nord, x_lgl) result(lr)
128 implicit none
129
130 integer, intent(in) :: nord
131 real(rp), intent(in) :: x_lgl(nord+1)
132 real(rp) :: lr(nord+1, nord+1) !> lr(n,k) = derivative of k-th Lagrange basis at x_lgl(n)
133
134 integer :: n, k
135 real(rp) :: p(nord+1,nord+1)
136 real(rp) :: lr_nn
137 !---------------------------------------------------------------------------
138
139 p(:,:) = polynomial_genlegendrepoly(nord, x_lgl)
140
141 do n=1, nord+1
142 lr_nn = 0.0_rp
143 do k=1, nord+1
144 if (k==1 .and. n==1) then
145 lr(k,n) = - 0.25_rp*dble(nord*(nord+1))
146 else if (k==nord+1 .and. n==nord+1) then
147 lr(k,n) = + 0.25_rp*dble(nord*(nord+1))
148 else if (k==n) then
149 lr(k,n) = 0.0_rp
150 else
151 lr(k,n) = p(n,nord+1)/(p(k,nord+1)*(x_lgl(n) - x_lgl(k)))
152 end if
153
154 if ( k /= n ) then
155 lr_nn = lr_nn + lr(k,n)
156 end if
157 end do
158 lr(n,n) = - lr_nn
159 end do
160
161 return
163
164 !> Differential values of Lagrange basis functions defined at GLL nodes, evaluated at arbitrary points.
165 !!
166 !! @param Nord Polynomial order
167 !! @param x_lgl GLL interpolation nodes
168 !! @param Neval Number of evaluation points
169 !! @param x_eval Evaluation points
170!OCL SERIAL
171 function polynomial_gendlagrangepoly( Nord, x_lgl, x_eval ) result(lr)
172 implicit none
173 integer, intent(in) :: nord
174 real(rp), intent(in) :: x_lgl(nord+1)
175 real(rp), intent(in) :: x_eval(:)
176 real(rp) :: lr(size(x_eval),nord+1) !> lr(m,k) = derivative of k-th Lagrange basis at x_eval(m)
177
178 real(rp) :: p(nord+1,nord+1)
179 real(rp) :: bw(nord+1) ! Barycentric weights. Common normalization factor is unnecessary.
180
181 real(rp) :: a(nord+1)
182 real(rp) :: s1, s2
183 real(rp) :: dx
184 real(rp) :: tol
185
186 integer :: k, j, m
187 integer :: knode
188 !-------------------------------------------------------------
189
190 p(:,:) = polynomial_genlegendrepoly(nord, x_lgl)
191 bw(:) = 1.0_rp / p(:,nord+1)
192
193 tol = 100.0_rp * epsilon(1.0_rp)
194
195 do m = 1, size(x_eval)
196
197 !- Check whether evaluation point coincides with a GLL node
198 knode = 0
199 do k=1, nord+1
200 if ( abs(x_eval(m)-x_lgl(k)) <= tol ) then
201 knode = k
202 exit
203 end if
204 end do
205
206 if ( knode /= 0 ) then
207 !* Evaluation exactly at a GLL node. Use the existing nodal formula.
208 do k = 1, nord+1
209 if ( k /= knode ) then
210 lr(m,k) = p(knode,nord+1) / ( p(k,nord+1) * ( x_lgl(knode)-x_lgl(k) ) )
211 else
212 lr(m,k) = 0.0_rp
213 end if
214 end do
215
216 ! Sum of derivatives of all basis functions is zero: sum_k l'_k(x) = 0
217 lr(m,knode) = -sum(lr(m,:))
218
219 else
220 !* General evaluation point
221 ! l'_k(x) = l_k(x) * [ ( sum_j w_j/(x - x_j,lgl)**2 ) / [sum_j a_j(x)] - 1 / ( x - x_k,lgl ) ]
222 ! where
223 ! l_k(x) = a_k(x) / sum_j a_j(x),
224 ! a_k(x) = w_k / ( x - x_k,lgl )
225
226 s1 = 0.0_rp; s2 = 0.0_rp
227 do j = 1, nord+1
228 dx = x_eval(m) - x_lgl(j)
229
230 a(j) = bw(j) / dx
231 s1 = s1 + a(j)
232 s2 = s2 + bw(j) / ( dx * dx )
233 end do
234
235 ! l'_k(x)
236 do k = 1, nord+1
237 dx = x_eval(m) - x_lgl(k)
238 lr(m,k) = ( a(k) / s1 ) * ( s2 / s1 - 1.0_rp / dx )
239 end do
240
241 end if
242
243 end do
244 return
245 end function polynomial_gendlagrangepoly
246
247 !> A function to obtain the values of Legendre polynomials which are evaluated at arbitrary points.
248 !!
249 !! @param Nord Order of Lagrange polynomial
250 !! @param x Positions where the Legendre polynomials are evaluated
251 !! @param P Values of the Legendre polynomials at x
252!OCL SERIAL
253 subroutine polynomial_genlegendrepoly_sub(Nord, x, P)
254 implicit none
255
256 integer, intent(in) :: nord
257 real(rp), intent(in) :: x(:)
258 real(rp), intent(out) :: p(size(x), nord+1)
259
260 integer :: n
261 !---------------------------------------------------------------------------
262
263 if (nord < 0) then
264 log_error("Polynomial_GenLegendrePoly",*) "Nord must be larger than 0."
265 end if
266
267 p(:,1) = 1.0_rp
268 if (nord==0) return
269
270 p(:,2) = x(:)
271 do n=2, nord
272 p(:,n+1) = ( dble(2*n-1)*x(:)*p(:,n) - dble(n-1)*p(:,n-1) )/dble(n)
273 end do
274
275 return
276 end subroutine polynomial_genlegendrepoly_sub
277
278 !> A function to obtain the values of Legendre polynomials which are evaluated at arbitrary points.
279 !!
280 !! @param Nord Order of Lagrange polynomial
281 !! @param x Positions where the Legendre polynomials are evaluated
282 !! @param P Values of the Legendre polynomials at x
283!OCL SERIAL
284 function polynomial_genlegendrepoly(Nord, x) result(P)
285 implicit none
286
287 integer, intent(in) :: nord
288 real(rp), intent(in) :: x(:)
289 real(rp) :: p(size(x), nord+1)
290 !---------------------------------------------------------------------------
291
292 call polynomial_genlegendrepoly_sub( nord, x(:), & ! (in)
293 p(:,:) ) ! (out)
294 return
295 end function polynomial_genlegendrepoly
296
297 !> A function to obtain differential values of Legendre polynomials which are evaluated at arbitrary points.
298 !!
299 !! @param Nord Order of Lagrange polynomial
300 !! @param x Positions where the Legendre polynomials are evaluated
301 !! @param P Values of the Legendre polynomials at x
302!OCL SERIAL
303 function polynomial_gendlegendrepoly(Nord, x, P) result(GradP)
304 implicit none
305
306 integer, intent(in) :: nord
307 real(rp), intent(in) :: x(:)
308 real(rp), intent(in) :: p(:,:)
309 real(rp) :: gradp(size(x), nord+1)
310
311 integer :: n
312 !---------------------------------------------------------------------------
313
314 if (nord < 0) then
315 log_error("Polynomial_GenDLegendrePoly",*) "Nord must be larger than 0."
316 end if
317
318 gradp(:,1) = 0.0_rp
319 if (nord == 0) return
320
321 gradp(:,2) = 1.0_rp
322 do n=2, nord
323 gradp(:,n+1) = 2.0_rp*x(:)*gradp(:,n) - gradp(:,n-1) + p(:,n)
324 end do
325
326 return
327 end function polynomial_gendlegendrepoly
328
329 !> A function to calculate the Legendre-Gauss-Lobatto (LGL) points.
330 !!
331 !! @param Nord Order of Lagrange polynomial
332 !! @param pts Position of the LGL points
333!OCL SERIAL
334 function polynomial_gengausslobattopt(Nord) result(pts)
335 implicit none
336
337 integer, intent(in) :: nord
338 real(rp) :: pts(nord+1)
339
340 integer :: n1
341 !---------------------------------------------------------------------------
342
343 pts(1) = -1.0_rp; pts(nord+1) = 1.0_rp
344 if (nord==1) return
345
346 call gen_jacobigaussquadraturepts( 1, 1, nord-2, pts(2:nord) )
347 return
349
350 !> A function to calculate the Gauss-Lobbato weights.
351 !!
352 !! @param Nord Order of Lagrange polynomial
353 !! @param int_weight_lgl Gauss-Lobbato weights
354!OCL SERIAL
355 function polynomial_gengausslobattoptintweight(Nord) result(int_weight_lgl)
356 implicit none
357
358 integer, intent(in) :: nord
359 real(rp) :: int_weight_lgl(nord+1)
360
361 real(rp) :: lglpts1d(nord+1)
362 real(rp) :: p1d_ori(nord+1, nord+1)
363 !---------------------------------------------------------------------------
364
365 lglpts1d(:) = polynomial_gengausslobattopt( nord )
366 p1d_ori(:,:) = polynomial_genlegendrepoly( nord, lglpts1d )
367
368 int_weight_lgl(:) = 2.0_rp/(dble(nord*(nord+1))*p1d_ori(:,nord+1)**2)
369
370 return
372
373 !> A function to calculate the Gauss-Legendre (GL) points.
374 !!
375 !! @param Nord Order of the Legendre polynomial
376 !! @param pts Position of the GL points
377!OCL SERIAL
378 function polynomial_gengausslegendrept(Nord) result(pts)
379 implicit none
380
381 integer, intent(in) :: nord
382 real(rp) :: pts(nord)
383 !---------------------------------------------------------------------------
384
385 call gen_jacobigaussquadraturepts( 0, 0, nord-1, pts(:) )
386 return
388
389 !> A function to calculate the Gauss-Legendre (GL) weights.
390 !!
391 !! @param Nord Order of the Legendre polynomial
392 !! @param int_weight_gl Gauss-Legendre weights
393!OCL SERIAL
394 function polynomial_gengausslegendreptintweight(Nord) result(int_weight_gl)
395 implicit none
396
397 integer, intent(in) :: nord
398 real(rp) :: int_weight_gl(nord)
399
400 real(rp) :: glpts1d(nord)
401 real(rp) :: p1d_ori(nord, nord+1)
402 real(rp) :: dp1d_ori(nord, nord+1)
403 !---------------------------------------------------------------------------
404
405 glpts1d(:) = polynomial_gengausslegendrept( nord )
406 p1d_ori(:,:) = polynomial_genlegendrepoly( nord, glpts1d )
407 dp1d_ori(:,:) = polynomial_gendlegendrepoly( nord, glpts1d, p1d_ori )
408
409 int_weight_gl(:) = 2.0_rp / ( (1.0_rp - glpts1d(:)**2) * dp1d_ori(:,nord+1)**2 )
410
411 return
413
414 !- private -------------------------------
415
416 !> Calculate the N'th-order Gauss quadrature points and weights associated the Jacobi polynomial of type (alpha,beta).
417!OCL SERIAL
418 subroutine gen_jacobigaussquadraturepts( alpha, beta, N, &
419 x )
420
421 implicit none
422 integer, intent(in) :: alpha
423 integer, intent(in) :: beta
424 integer, intent(in) :: n
425 real(rp), intent(out) :: x(n+1)
426
427 integer :: i
428 real(dp) :: d(n+1), e(n)
429 real(dp) :: work(2*(n+1)-2), z(n+1,n+1)
430 real(dp) :: h1(n+1)
431 integer :: info
432 !--------------------------------------------------------------
433
434 if (n==0) then
435 x(1) = - dble(alpha - beta) / dble(alpha + beta + 2)
436 return
437 end if
438
439 do i=0, n
440 h1(i+1) = dble( 2*i + alpha + beta )
441 end do
442
443 do i=1, n+1
444 d(i) = - dble(alpha**2 - beta**2) / (h1(i) * (h1(i) + 2d0))
445 end do
446 do i=1, n
447 e(i) = 2d0 / (h1(i) + 2d0) &
448 * sqrt( dble(i * (i + alpha + beta) * (i + alpha) * (i + beta)) &
449 / ((h1(i) + 1d0) * (h1(i) + 3d0)) )
450 end do
451 if ( dble(alpha + beta) < 1d-16) d(1) = 0.0_rp
452
453 call dstev( 'Vectors', n+1, d, e, z, n+1, work, info )
454 x(:) = d(:)
455
456 return
457 end subroutine gen_jacobigaussquadraturepts
458
459end module scale_polynomial
Module common / Polynomial.
real(rp) function, dimension(nord), public polynomial_gengausslegendreptintweight(nord)
A function to calculate the Gauss-Legendre (GL) weights.
real(rp) function, dimension(size(x), nord+1), public polynomial_gendlegendrepoly(nord, x, p)
A function to obtain differential values of Legendre polynomials which are evaluated at arbitrary poi...
real(rp) function, dimension(size(x), nord+1), public polynomial_genlegendrepoly(nord, x)
A function to obtain the values of Legendre polynomials which are evaluated at arbitrary points.
real(rp) function, dimension(nord+1), public polynomial_gengausslobattopt(nord)
A function to calculate the Legendre-Gauss-Lobatto (LGL) points.
real(rp) function, dimension(size(x), nord+1), public polynomial_genlagrangepoly(nord, x_lgl, x)
A function to obtain the Lagrange basis functions related to the Gauss-Legendre-Lobatto (GLL) points.
real(rp) function, dimension(nord), public polynomial_gengausslegendrept(nord)
A function to calculate the Gauss-Legendre (GL) points.
real(rp) real(rp) function, dimension(n, k), public polynomial_gendlagrangepoly_lglpt(nord, x_lgl)
Differential values of Lagrange basis functions at the GLL points.
real(rp) real(rp) function, dimension(m, k), public polynomial_gendlagrangepoly(nord, x_lgl, x_eval)
Differential values of Lagrange basis functions defined at GLL nodes, evaluated at arbitrary points.
real(rp) function, dimension(nord+1), public polynomial_gengausslobattoptintweight(nord)
A function to calculate the Gauss-Lobbato weights.
subroutine, public polynomial_genlegendrepoly_sub(nord, x, p)
A function to obtain the values of Legendre polynomials which are evaluated at arbitrary points.