8 implicit none ;
private
10 public p3m_interpolation
11 public p3m_boundary_extrapolation
13 real,
parameter :: hneglect_dflt = 1.e-30
14 real,
parameter :: hneglect_edge_dflt = 1.e-10
28 subroutine p3m_interpolation( N, h, u, ppoly_E, ppoly_S, ppoly_coef, &
30 integer,
intent(in) :: n
31 real,
dimension(:),
intent(in) :: h
32 real,
dimension(:),
intent(in) :: u
33 real,
dimension(:,:),
intent(inout) :: ppoly_e
35 real,
dimension(:,:),
intent(inout) :: ppoly_s
37 real,
dimension(:,:),
intent(inout) :: ppoly_coef
39 real,
optional,
intent(in) :: h_neglect
48 call p3m_limiter( n, h, u, ppoly_e, ppoly_s, ppoly_coef, h_neglect )
50 end subroutine p3m_interpolation
65 subroutine p3m_limiter( N, h, u, ppoly_E, ppoly_S, ppoly_coef, h_neglect )
66 integer,
intent(in) :: N
67 real,
dimension(:),
intent(in) :: h
68 real,
dimension(:),
intent(in) :: u
69 real,
dimension(:,:),
intent(inout) :: ppoly_E
71 real,
dimension(:,:),
intent(inout) :: ppoly_S
73 real,
dimension(:,:),
intent(inout) :: ppoly_coef
74 real,
optional,
intent(in) :: h_neglect
84 real :: sigma_l, sigma_c, sigma_r
90 hneglect = hneglect_dflt ;
if (
present(h_neglect)) hneglect = h_neglect
95 call bound_edge_values( n, h, u, ppoly_e, hneglect )
98 call average_discontinuous_edge_values( n, ppoly_e )
135 sigma_l = 2.0 * ( u_c - u_l ) / ( h_c + hneglect )
136 sigma_c = 2.0 * ( u_r - u_l ) / ( h_l + 2.0*h_c + h_r + hneglect )
137 sigma_r = 2.0 * ( u_r - u_c ) / ( h_c + hneglect )
139 if ( (sigma_l * sigma_r) > 0.0 )
then
140 slope = sign( min(abs(sigma_l),abs(sigma_c),abs(sigma_r)), sigma_c )
148 if ( abs(u1_l*h_c) < eps )
then
152 if ( abs(u1_r*h_c) < eps )
then
158 if ( abs(u1_l) > abs(sigma_l) )
then
162 if ( abs(u1_r) > abs(sigma_r) )
then
167 call build_cubic_interpolant( h, k, ppoly_e, ppoly_s, ppoly_coef )
170 monotonic = is_cubic_monotonic( ppoly_coef, k )
175 if ( monotonic == 0 )
then
176 call monotonize_cubic( h_c, u0_l, u0_r, sigma_l, sigma_r, slope, u1_l, u1_r )
184 call build_cubic_interpolant( h, k, ppoly_e, ppoly_s, ppoly_coef )
188 end subroutine p3m_limiter
204 subroutine p3m_boundary_extrapolation( N, h, u, ppoly_E, ppoly_S, ppoly_coef, &
205 h_neglect, h_neglect_edge )
206 integer,
intent(in) :: n
207 real,
dimension(:),
intent(in) :: h
208 real,
dimension(:),
intent(in) :: u
209 real,
dimension(:,:),
intent(inout) :: ppoly_e
211 real,
dimension(:,:),
intent(inout) :: ppoly_s
213 real,
dimension(:,:),
intent(inout) :: ppoly_coef
215 real,
optional,
intent(in) :: h_neglect
218 real,
optional,
intent(in) :: h_neglect_edge
230 real :: hneglect, hneglect_edge
232 hneglect = hneglect_dflt ;
if (
present(h_neglect)) hneglect = h_neglect
233 hneglect_edge = hneglect_edge_dflt
234 if (
present(h_neglect_edge)) hneglect_edge = h_neglect_edge
239 h0 = h(i0) + hneglect_edge
240 h1 = h(i1) + hneglect_edge
250 slope = 2.0 * ( u1 - u0 ) / ( h0 + hneglect )
251 if ( abs(u1_r) > abs(slope) )
then
262 u0_l = 3.0 * u0 + 0.5 * h0*u1_r - 2.0 * u0_r
263 u1_l = ( - 6.0 * u0 - 2.0 * h0*u1_r + 6.0 * u0_r) / ( h0 + hneglect )
268 if ( (u0_r-u0_l) * slope < 0.0 )
then
281 call build_cubic_interpolant( h, i0, ppoly_e, ppoly_s, ppoly_coef )
282 monotonic = is_cubic_monotonic( ppoly_coef, i0 )
284 if ( monotonic == 0 )
then
285 call monotonize_cubic( h0, u0_l, u0_r, 0.0, slope, slope, u1_l, u1_r )
290 call build_cubic_interpolant( h, i0, ppoly_e, ppoly_s, ppoly_coef )
297 h0 = h(i0) + hneglect_edge
298 h1 = h(i1) + hneglect_edge
307 u1_l = (b + 2*c + 3*d) / ( h0 + hneglect )
310 slope = 2.0 * ( u1 - u0 ) / ( h1 + hneglect )
311 if ( abs(u1_l) > abs(slope) )
then
322 u0_r = 3.0 * u1 - 0.5 * h1*u1_l - 2.0 * u0_l
323 u1_r = ( 6.0 * u1 - 2.0 * h1*u1_l - 6.0 * u0_l) / ( h1 + hneglect )
328 if ( (u0_r-u0_l) * slope < 0.0 )
then
340 call build_cubic_interpolant( h, i1, ppoly_e, ppoly_s, ppoly_coef )
341 monotonic = is_cubic_monotonic( ppoly_coef, i1 )
343 if ( monotonic == 0 )
then
344 call monotonize_cubic( h1, u0_l, u0_r, slope, 0.0, slope, u1_l, u1_r )
349 call build_cubic_interpolant( h, i1, ppoly_e, ppoly_s, ppoly_coef )
353 end subroutine p3m_boundary_extrapolation
362 subroutine build_cubic_interpolant( h, k, ppoly_E, ppoly_S, ppoly_coef )
363 real,
dimension(:),
intent(in) :: h
364 integer,
intent(in) :: k
365 real,
dimension(:,:),
intent(in) :: ppoly_E
367 real,
dimension(:,:),
intent(in) :: ppoly_S
369 real,
dimension(:,:),
intent(inout) :: ppoly_coef
375 real :: a0, a1, a2, a3
382 u1_l = ppoly_s(k,1) * h_c
383 u1_r = ppoly_s(k,2) * h_c
387 a2 = 3.0 * ( u0_r - u0_l ) - u1_r - 2.0 * u1_l
388 a3 = u1_r + u1_l + 2.0 * ( u0_l - u0_r )
395 end subroutine build_cubic_interpolant
406 integer function is_cubic_monotonic( ppoly_coef, k )
407 real,
dimension(:,:),
intent(in) :: ppoly_coef
408 integer,
intent(in) :: k
411 real :: a0, a1, a2, a3
435 if ( rho >= 0.0 )
then
436 if ( abs(c) > 1e-15 )
then
437 xi_0 = 0.5 * ( -b - sqrt( rho ) ) / c
438 xi_1 = 0.5 * ( -b + sqrt( rho ) ) / c
439 elseif ( abs(b) > 1e-15 )
then
446 if ( ( (xi_0 > eps) .AND. (xi_0 < 1.0-eps) ) .OR. &
447 ( (xi_1 > eps) .AND. (xi_1 < 1.0-eps) ) )
then
458 is_cubic_monotonic = monotonic
460 end function is_cubic_monotonic
489 subroutine monotonize_cubic( h, u0_l, u0_r, sigma_l, sigma_r, slope, u1_l, u1_r )
490 real,
intent(in) :: h
491 real,
intent(in) :: u0_l
492 real,
intent(in) :: u0_r
493 real,
intent(in) :: sigma_l
494 real,
intent(in) :: sigma_r
495 real,
intent(in) :: slope
496 real,
intent(inout) :: u1_l
497 real,
intent(inout) :: u1_r
500 integer :: inflexion_l
501 integer :: inflexion_r
517 if ( u1_l*slope <= 0.0 )
then
521 if ( u1_r*slope <= 0.0 )
then
528 a2 = 3.0 * ( u0_r - u0_l ) - h*(u1_r + 2.0*u1_l)
529 a3 = h*(u1_r + u1_l) + 2.0*(u0_l - u0_r)
534 if ( a3 /= 0.0 )
then
536 xi_ip = - a2 / (3.0 * a3)
539 if ( (xi_ip >= 0.0) .AND. (xi_ip <= 1.0) )
then
549 if ( found_ip == 1 )
then
550 slope_ip = a1 + 2.0*a2*xi_ip + 3.0*a3*xi_ip*xi_ip
553 if ( slope_ip*slope < 0.0 )
then
554 if ( abs(sigma_l) < abs(sigma_r) )
then
567 if ( inflexion_l == 1 )
then
569 u1_l_tmp = 1.5*(u0_r-u0_l)/h - 0.5*u1_r
570 u1_r_tmp = 3.0*(u0_r-u0_l)/h - 2.0*u1_l
572 if ( (u1_l_tmp*slope < 0.0) .AND. (u1_r_tmp*slope < 0.0) )
then
575 u1_r = 3.0 * (u0_r - u0_l) / h
577 elseif (u1_l_tmp*slope < 0.0)
then
580 u1_l = 1.5*(u0_r - u0_l)/h - 0.5*u1_r
582 elseif (u1_r_tmp*slope < 0.0)
then
585 u1_r = 3.0*(u0_r - u0_l)/h - 2.0*u1_l
597 if ( inflexion_r == 1 )
then
599 u1_l_tmp = 3.0*(u0_r-u0_l)/h - 2.0*u1_r
600 u1_r_tmp = 1.5*(u0_r-u0_l)/h - 0.5*u1_l
602 if ( (u1_l_tmp*slope < 0.0) .AND. (u1_r_tmp*slope < 0.0) )
then
604 u1_l = 3.0 * (u0_r - u0_l) / h
607 elseif (u1_l_tmp*slope < 0.0)
then
610 u1_l = 3.0*(u0_r - u0_l)/h - 2.0*u1_r
612 elseif (u1_r_tmp*slope < 0.0)
then
615 u1_r = 1.5*(u0_r - u0_l)/h - 0.5*u1_l
626 if ( abs(u1_l*h) < eps )
then
630 if ( abs(u1_r*h) < eps )
then
634 end subroutine monotonize_cubic