MOM6
P3M_functions.F90
1 !> Cubic interpolation functions
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use regrid_edge_values, only : bound_edge_values, average_discontinuous_edge_values
7 
8 implicit none ; private
9 
10 public p3m_interpolation
11 public p3m_boundary_extrapolation
12 
13 real, parameter :: hneglect_dflt = 1.e-30 !< Default value of a negligible cell thickness
14 real, parameter :: hneglect_edge_dflt = 1.e-10 !< Default value of a negligible edge thickness
15 
16 contains
17 
18 !> Set up a piecewise cubic interpolation from cell averages and estimated
19 !! edge slopes and values
20 !!
21 !! Cubic interpolation between edges.
22 !!
23 !! The edge values and slopes MUST have been estimated prior to calling
24 !! this routine.
25 !!
26 !! It is assumed that the size of the array 'u' is equal to the number of cells
27 !! defining 'grid' and 'ppoly'. No consistency check is performed here.
28 subroutine p3m_interpolation( N, h, u, ppoly_E, ppoly_S, ppoly_coef, &
29  h_neglect )
30  integer, intent(in) :: n !< Number of cells
31  real, dimension(:), intent(in) :: h !< cell widths (size N)
32  real, dimension(:), intent(in) :: u !< cell averages (size N)
33  real, dimension(:,:), intent(inout) :: ppoly_e !< Edge value of polynomial,
34  !! with the same units as u.
35  real, dimension(:,:), intent(inout) :: ppoly_s !< Edge slope of polynomial,
36  !! in the units of u over the units of h.
37  real, dimension(:,:), intent(inout) :: ppoly_coef !< Coefficients of polynomial, mainly
38  !! with the same units as u.
39  real, optional, intent(in) :: h_neglect !< A negligibly small width for the
40  !! purpose of cell reconstructions
41  !! in the same units as h.
42 
43  ! Call the limiter for p3m, which takes care of everything from
44  ! computing the coefficients of the cubic to monotonizing it.
45  ! This routine could be called directly instead of having to call
46  ! 'P3M_interpolation' first but we do that to provide an homogeneous
47  ! interface.
48  call p3m_limiter( n, h, u, ppoly_e, ppoly_s, ppoly_coef, h_neglect )
49 
50 end subroutine p3m_interpolation
51 
52 !> Adust a piecewise cubic reconstruction with a limiter that adjusts the edge
53 !! values and slopes
54 !!
55 !! The p3m limiter operates as follows:
56 !!
57 !! 1. Edge values are bounded
58 !! 2. Discontinuous edge values are systematically averaged
59 !! 3. Loop on cells and do the following
60 !! a. Build cubic curve
61 !! b. Check if cubic curve is monotonic
62 !! c. If not, monotonize cubic curve and rebuild it
63 !!
64 !! Step 3 of the monotonization process leaves all edge values unchanged.
65 subroutine p3m_limiter( N, h, u, ppoly_E, ppoly_S, ppoly_coef, h_neglect )
66  integer, intent(in) :: N !< Number of cells
67  real, dimension(:), intent(in) :: h !< cell widths (size N)
68  real, dimension(:), intent(in) :: u !< cell averages (size N)
69  real, dimension(:,:), intent(inout) :: ppoly_E !< Edge value of polynomial,
70  !! with the same units as u.
71  real, dimension(:,:), intent(inout) :: ppoly_S !< Edge slope of polynomial,
72  !! in the units of u over the units of h.
73  real, dimension(:,:), intent(inout) :: ppoly_coef !< Coefficients of polynomial
74  real, optional, intent(in) :: h_neglect !< A negligibly small width for
75  !! the purpose of cell reconstructions
76  !! in the same units as h.
77  ! Local variables
78  integer :: k ! loop index
79  integer :: monotonic ! boolean indicating whether the cubic is monotonic
80  real :: u0_l, u0_r ! edge values
81  real :: u1_l, u1_r ! edge slopes
82  real :: u_l, u_c, u_r ! left, center and right cell averages
83  real :: h_l, h_c, h_r ! left, center and right cell widths
84  real :: sigma_l, sigma_c, sigma_r ! left, center and right
85  ! van Leer slopes
86  real :: slope ! retained PLM slope
87  real :: eps
88  real :: hNeglect
89 
90  hneglect = hneglect_dflt ; if (present(h_neglect)) hneglect = h_neglect
91 
92  eps = 1e-10
93 
94  ! 1. Bound edge values (boundary cells are assumed to be local extrema)
95  call bound_edge_values( n, h, u, ppoly_e, hneglect )
96 
97  ! 2. Systematically average discontinuous edge values
98  call average_discontinuous_edge_values( n, ppoly_e )
99 
100 
101  ! 3. Loop on cells and do the following
102  ! (a) Build cubic curve
103  ! (b) Check if cubic curve is monotonic
104  ! (c) If not, monotonize cubic curve and rebuild it
105  do k = 1,n
106 
107  ! Get edge values, edge slopes and cell width
108  u0_l = ppoly_e(k,1)
109  u0_r = ppoly_e(k,2)
110  u1_l = ppoly_s(k,1)
111  u1_r = ppoly_s(k,2)
112 
113  ! Get cell widths and cell averages (boundary cells are assumed to
114  ! be local extrema for the sake of slopes)
115  u_c = u(k)
116  h_c = h(k)
117 
118  if ( k == 1 ) then
119  h_l = h(k)
120  u_l = u(k)
121  else
122  h_l = h(k-1)
123  u_l = u(k-1)
124  endif
125 
126  if ( k == n ) then
127  h_r = h(k)
128  u_r = u(k)
129  else
130  h_r = h(k+1)
131  u_r = u(k+1)
132  endif
133 
134  ! Compute limited slope
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 )
138 
139  if ( (sigma_l * sigma_r) > 0.0 ) then
140  slope = sign( min(abs(sigma_l),abs(sigma_c),abs(sigma_r)), sigma_c )
141  else
142  slope = 0.0
143  endif
144 
145  ! If the slopes are close to zero in machine precision and in absolute
146  ! value, we set the slope to zero. This prevents asymmetric representation
147  ! near extrema. These expressions are both nondimensional.
148  if ( abs(u1_l*h_c) < eps ) then
149  u1_l = 0.0
150  endif
151 
152  if ( abs(u1_r*h_c) < eps ) then
153  u1_r = 0.0
154  endif
155 
156  ! The edge slopes are limited from above by the respective
157  ! one-sided slopes
158  if ( abs(u1_l) > abs(sigma_l) ) then
159  u1_l = sigma_l
160  endif
161 
162  if ( abs(u1_r) > abs(sigma_r) ) then
163  u1_r = sigma_r
164  endif
165 
166  ! Build cubic interpolant (compute the coefficients)
167  call build_cubic_interpolant( h, k, ppoly_e, ppoly_s, ppoly_coef )
168 
169  ! Check whether cubic is monotonic
170  monotonic = is_cubic_monotonic( ppoly_coef, k )
171 
172  ! If cubic is not monotonic, monotonize it by modifiying the
173  ! edge slopes, store the new edge slopes and recompute the
174  ! cubic coefficients
175  if ( monotonic == 0 ) then
176  call monotonize_cubic( h_c, u0_l, u0_r, sigma_l, sigma_r, slope, u1_l, u1_r )
177  endif
178 
179  ! Store edge slopes
180  ppoly_s(k,1) = u1_l
181  ppoly_s(k,2) = u1_r
182 
183  ! Recompute coefficients of cubic
184  call build_cubic_interpolant( h, k, ppoly_e, ppoly_s, ppoly_coef )
185 
186  enddo ! loop on cells
187 
188 end subroutine p3m_limiter
189 
190 
191 !> Calculate the edge values and slopes at boundary cells as part of building a
192 !! piecewise cubic sub-grid scale profiles
193 !!
194 !! The following explanations apply to the left boundary cell. The same
195 !! reasoning holds for the right boundary cell.
196 !!
197 !! A cubic needs to be built in the cell and requires four degrees of freedom,
198 !! which are the edge values and slopes. The right edge values and slopes are
199 !! taken to be that of the neighboring cell (i.e., the left edge value and slope
200 !! of the neighboring cell). The left edge value and slope are determined by
201 !! computing the parabola based on the cell average and the right edge value
202 !! and slope. The resulting cubic is not necessarily monotonic and the slopes
203 !! are subsequently modified to yield a monotonic cubic.
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 !< Number of cells
207  real, dimension(:), intent(in) :: h !< cell widths (size N)
208  real, dimension(:), intent(in) :: u !< cell averages (size N)
209  real, dimension(:,:), intent(inout) :: ppoly_e !< Edge value of polynomial,
210  !! with the same units as u.
211  real, dimension(:,:), intent(inout) :: ppoly_s !< Edge slope of polynomial,
212  !! in the units of u over the units of h.
213  real, dimension(:,:), intent(inout) :: ppoly_coef !< Coefficients of polynomial, mainly
214  !! with the same units as u.
215  real, optional, intent(in) :: h_neglect !< A negligibly small width for the
216  !! purpose of cell reconstructions
217  !! in the same units as h.
218  real, optional, intent(in) :: h_neglect_edge !< A negligibly small width
219  !! for the purpose of finding edge values
220  !! in the same units as h.
221  ! Local variables
222  integer :: i0, i1
223  integer :: monotonic
224  real :: u0, u1
225  real :: h0, h1
226  real :: b, c, d
227  real :: u0_l, u0_r
228  real :: u1_l, u1_r
229  real :: slope
230  real :: hneglect, hneglect_edge
231 
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
235 
236  ! ----- Left boundary -----
237  i0 = 1
238  i1 = 2
239  h0 = h(i0) + hneglect_edge
240  h1 = h(i1) + hneglect_edge
241  u0 = u(i0)
242  u1 = u(i1)
243 
244  ! Compute the left edge slope in neighboring cell and express it in
245  ! the global coordinate system
246  b = ppoly_coef(i1,2)
247  u1_r = b / h1 ! derivative evaluated at xi = 0.0, expressed w.r.t. x
248 
249  ! Limit the right slope by the PLM limited slope
250  slope = 2.0 * ( u1 - u0 ) / ( h0 + hneglect )
251  if ( abs(u1_r) > abs(slope) ) then
252  u1_r = slope
253  endif
254 
255  ! The right edge value in the boundary cell is taken to be the left
256  ! edge value in the neighboring cell
257  u0_r = ppoly_e(i1,1)
258 
259  ! Given the right edge value and slope, we determine the left
260  ! edge value and slope by computing the parabola as determined by
261  ! the right edge value and slope and the boundary cell average
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 )
264 
265  ! Check whether the edge values are monotonic. For example, if the left edge
266  ! value is larger than the right edge value while the slope is positive, the
267  ! edge values are inconsistent and we need to modify the left edge value
268  if ( (u0_r-u0_l) * slope < 0.0 ) then
269  u0_l = u0_r
270  u1_l = 0.0
271  u1_r = 0.0
272  endif
273 
274  ! Store edge values and slope, build cubic and check monotonicity
275  ppoly_e(i0,1) = u0_l
276  ppoly_e(i0,2) = u0_r
277  ppoly_s(i0,1) = u1_l
278  ppoly_s(i0,2) = u1_r
279 
280  ! Store edge values and slope, build cubic and check monotonicity
281  call build_cubic_interpolant( h, i0, ppoly_e, ppoly_s, ppoly_coef )
282  monotonic = is_cubic_monotonic( ppoly_coef, i0 )
283 
284  if ( monotonic == 0 ) then
285  call monotonize_cubic( h0, u0_l, u0_r, 0.0, slope, slope, u1_l, u1_r )
286 
287  ! Rebuild cubic after monotonization
288  ppoly_s(i0,1) = u1_l
289  ppoly_s(i0,2) = u1_r
290  call build_cubic_interpolant( h, i0, ppoly_e, ppoly_s, ppoly_coef )
291 
292  endif
293 
294  ! ----- Right boundary -----
295  i0 = n-1
296  i1 = n
297  h0 = h(i0) + hneglect_edge
298  h1 = h(i1) + hneglect_edge
299  u0 = u(i0)
300  u1 = u(i1)
301 
302  ! Compute the right edge slope in neighboring cell and express it in
303  ! the global coordinate system
304  b = ppoly_coef(i0,2)
305  c = ppoly_coef(i0,3)
306  d = ppoly_coef(i0,4)
307  u1_l = (b + 2*c + 3*d) / ( h0 + hneglect ) ! derivative evaluated at xi = 1.0
308 
309  ! Limit the left slope by the PLM limited slope
310  slope = 2.0 * ( u1 - u0 ) / ( h1 + hneglect )
311  if ( abs(u1_l) > abs(slope) ) then
312  u1_l = slope
313  endif
314 
315  ! The left edge value in the boundary cell is taken to be the right
316  ! edge value in the neighboring cell
317  u0_l = ppoly_e(i0,2)
318 
319  ! Given the left edge value and slope, we determine the right
320  ! edge value and slope by computing the parabola as determined by
321  ! the left edge value and slope and the boundary cell average
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 )
324 
325  ! Check whether the edge values are monotonic. For example, if the right edge
326  ! value is smaller than the left edge value while the slope is positive, the
327  ! edge values are inconsistent and we need to modify the right edge value
328  if ( (u0_r-u0_l) * slope < 0.0 ) then
329  u0_r = u0_l
330  u1_l = 0.0
331  u1_r = 0.0
332  endif
333 
334  ! Store edge values and slope, build cubic and check monotonicity
335  ppoly_e(i1,1) = u0_l
336  ppoly_e(i1,2) = u0_r
337  ppoly_s(i1,1) = u1_l
338  ppoly_s(i1,2) = u1_r
339 
340  call build_cubic_interpolant( h, i1, ppoly_e, ppoly_s, ppoly_coef )
341  monotonic = is_cubic_monotonic( ppoly_coef, i1 )
342 
343  if ( monotonic == 0 ) then
344  call monotonize_cubic( h1, u0_l, u0_r, slope, 0.0, slope, u1_l, u1_r )
345 
346  ! Rebuild cubic after monotonization
347  ppoly_s(i1,1) = u1_l
348  ppoly_s(i1,2) = u1_r
349  call build_cubic_interpolant( h, i1, ppoly_e, ppoly_s, ppoly_coef )
350 
351  endif
352 
353 end subroutine p3m_boundary_extrapolation
354 
355 
356 !> Build cubic interpolant in cell k
357 !!
358 !! Given edge values and edge slopes, compute coefficients of cubic in cell k.
359 !!
360 !! NOTE: edge values and slopes MUST have been properly calculated prior to
361 !! calling this routine.
362 subroutine build_cubic_interpolant( h, k, ppoly_E, ppoly_S, ppoly_coef )
363  real, dimension(:), intent(in) :: h !< cell widths (size N)
364  integer, intent(in) :: k !< The index of the cell to work on
365  real, dimension(:,:), intent(in) :: ppoly_E !< Edge value of polynomial,
366  !! with the same units as u.
367  real, dimension(:,:), intent(in) :: ppoly_S !< Edge slope of polynomial,
368  !! in the units of u over the units of h.
369  real, dimension(:,:), intent(inout) :: ppoly_coef !< Coefficients of polynomial, mainly
370  !! with the same units as u.
371  ! Local variables
372  real :: u0_l, u0_r ! edge values
373  real :: u1_l, u1_r ! edge slopes
374  real :: h_c ! cell width
375  real :: a0, a1, a2, a3 ! cubic coefficients
376 
377  h_c = h(k)
378 
379  u0_l = ppoly_e(k,1)
380  u0_r = ppoly_e(k,2)
381 
382  u1_l = ppoly_s(k,1) * h_c
383  u1_r = ppoly_s(k,2) * h_c
384 
385  a0 = u0_l
386  a1 = u1_l
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 )
389 
390  ppoly_coef(k,1) = a0
391  ppoly_coef(k,2) = a1
392  ppoly_coef(k,3) = a2
393  ppoly_coef(k,4) = a3
394 
395 end subroutine build_cubic_interpolant
396 
397 
398 !> Check whether the cubic reconstruction in cell k is monotonic
399 !!
400 !! This function checks whether the cubic curve in cell k is monotonic.
401 !! If so, returns 1. Otherwise, returns 0.
402 !!
403 !! The cubic is monotonic if the first derivative is single-signed in [0,1].
404 !! Hence, we check whether the roots (if any) lie inside this interval. If there
405 !! is no root or if both roots lie outside this interval, the cubic is monotonic.
406 integer function is_cubic_monotonic( ppoly_coef, k )
407  real, dimension(:,:), intent(in) :: ppoly_coef !< Coefficients of cubic polynomial
408  integer, intent(in) :: k !< The index of the cell to work on
409  ! Local variables
410  integer :: monotonic ! boolean indicating if monotonic or not
411  real :: a0, a1, a2, a3 ! cubic coefficients
412  real :: a, b, c ! coefficients of first derivative
413  real :: xi_0, xi_1 ! roots of first derivative (if any !)
414  real :: rho
415  real :: eps
416 
417  ! Define the radius of the ball around 0 and 1 in which all values are assumed
418  ! to be equal to 0 or 1, respectively
419  eps = 1e-14
420 
421  a0 = ppoly_coef(k,1)
422  a1 = ppoly_coef(k,2)
423  a2 = ppoly_coef(k,3)
424  a3 = ppoly_coef(k,4)
425 
426  a = a1
427  b = 2.0 * a2
428  c = 3.0 * a3
429 
430  xi_0 = -1.0
431  xi_1 = -1.0
432 
433  rho = b*b - 4.0*a*c
434 
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
440  xi_0 = - a / b
441  xi_1 = - a / b
442  endif
443 
444  ! If one of the roots of the first derivative lies in (0,1),
445  ! the cubic is not monotonic.
446  if ( ( (xi_0 > eps) .AND. (xi_0 < 1.0-eps) ) .OR. &
447  ( (xi_1 > eps) .AND. (xi_1 < 1.0-eps) ) ) then
448  monotonic = 0
449  else
450  monotonic = 1
451  endif
452 
453  else ! there are no real roots --> cubic is monotonic
454  monotonic = 1
455  endif
456 
457  ! Set the return value
458  is_cubic_monotonic = monotonic
459 
460 end function is_cubic_monotonic
461 
462 !> Monotonize a cubic curve by modifying the edge slopes.
463 !!
464 !! This routine takes care of monotonizing a cubic on [0,1] by modifying the
465 !! edge slopes. The edge values are NOT modified. The cubic is entirely
466 !! determined by the four degrees of freedom u0_l, u0_r, u1_l and u1_r.
467 !!
468 !! u1_l and u1_r are the edge slopes expressed in the GLOBAL coordinate system.
469 !!
470 !! The monotonization occurs as follows.
471 !
472 !! 1. The edge slopes are set to 0 if they are inconsistent with the limited
473 !! PLM slope
474 !! 2. We check whether we can find an inflexion point in [0,1]. At most one
475 !! inflexion point may exist.
476 !! a. If there is no inflexion point, the cubic is monotonic.
477 !! b. If there is one inflexion point and it lies outside [0,1], the
478 !! cubic is monotonic.
479 !! c. If there is one inflexion point and it lies in [0,1] and the slope
480 !! at the location of the inflexion point is consistent, the cubic
481 !! is monotonic.
482 !! d. If the inflexion point lies in [0,1] but the slope is inconsistent,
483 !! we go to (3) to shift the location of the inflexion point to the left
484 !! or to the right. To the left when the 2nd-order left slope is smaller
485 !! than the 2nd order right slope.
486 !! 3. Edge slopes are modified to shift the inflexion point, either onto the left
487 !! edge or onto the right edge.
488 
489 subroutine monotonize_cubic( h, u0_l, u0_r, sigma_l, sigma_r, slope, u1_l, u1_r )
490  real, intent(in) :: h !< cell width
491  real, intent(in) :: u0_l !< left edge value
492  real, intent(in) :: u0_r !< right edge value
493  real, intent(in) :: sigma_l !< left 2nd-order slopes
494  real, intent(in) :: sigma_r !< right 2nd-order slopes
495  real, intent(in) :: slope !< limited PLM slope
496  real, intent(inout) :: u1_l !< left edge slopes
497  real, intent(inout) :: u1_r !< right edge slopes
498  ! Local variables
499  integer :: found_ip
500  integer :: inflexion_l ! bool telling if inflex. pt must be on left
501  integer :: inflexion_r ! bool telling if inflex. pt must be on right
502  real :: eps
503  real :: a1, a2, a3
504  real :: u1_l_tmp ! trial left edge slope
505  real :: u1_r_tmp ! trial right edge slope
506  real :: xi_ip ! location of inflexion point
507  real :: slope_ip ! slope at inflexion point
508 
509  eps = 1e-14
510 
511  found_ip = 0
512  inflexion_l = 0
513  inflexion_r = 0
514 
515  ! If the edge slopes are inconsistent w.r.t. the limited PLM slope,
516  ! set them to zero
517  if ( u1_l*slope <= 0.0 ) then
518  u1_l = 0.0
519  endif
520 
521  if ( u1_r*slope <= 0.0 ) then
522  u1_r = 0.0
523  endif
524 
525  ! Compute the location of the inflexion point, which is the root
526  ! of the second derivative
527  a1 = h * u1_l
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)
530 
531  ! There is a possible root (and inflexion point) only if a3 is nonzero.
532  ! When a3 is zero, the second derivative of the cubic is constant (the
533  ! cubic degenerates into a parabola) and no inflexion point exists.
534  if ( a3 /= 0.0 ) then
535  ! Location of inflexion point
536  xi_ip = - a2 / (3.0 * a3)
537 
538  ! If the inflexion point lies in [0,1], change boolean value
539  if ( (xi_ip >= 0.0) .AND. (xi_ip <= 1.0) ) then
540  found_ip = 1
541  endif
542  endif
543 
544  ! When there is an inflexion point within [0,1], check the slope
545  ! to see if it is consistent with the limited PLM slope. If not,
546  ! decide on which side we want to collapse the inflexion point.
547  ! If the inflexion point lies on one of the edges, the cubic is
548  ! guaranteed to be monotonic
549  if ( found_ip == 1 ) then
550  slope_ip = a1 + 2.0*a2*xi_ip + 3.0*a3*xi_ip*xi_ip
551 
552  ! Check whether slope is consistent
553  if ( slope_ip*slope < 0.0 ) then
554  if ( abs(sigma_l) < abs(sigma_r) ) then
555  inflexion_l = 1
556  else
557  inflexion_r = 1
558  endif
559  endif
560  endif ! found_ip
561 
562  ! At this point, if the cubic is not monotonic, we know where the
563  ! inflexion point should lie. When the cubic is monotonic, both
564  ! 'inflexion_l' and 'inflexion_r' are set to 0 and nothing is to be done.
565 
566  ! Move inflexion point on the left
567  if ( inflexion_l == 1 ) then
568 
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
571 
572  if ( (u1_l_tmp*slope < 0.0) .AND. (u1_r_tmp*slope < 0.0) ) then
573 
574  u1_l = 0.0
575  u1_r = 3.0 * (u0_r - u0_l) / h
576 
577  elseif (u1_l_tmp*slope < 0.0) then
578 
579  u1_r = u1_r_tmp
580  u1_l = 1.5*(u0_r - u0_l)/h - 0.5*u1_r
581 
582  elseif (u1_r_tmp*slope < 0.0) then
583 
584  u1_l = u1_l_tmp
585  u1_r = 3.0*(u0_r - u0_l)/h - 2.0*u1_l
586 
587  else
588 
589  u1_l = u1_l_tmp
590  u1_r = u1_r_tmp
591 
592  endif
593 
594  endif ! end treating case with inflexion point on the left
595 
596  ! Move inflexion point on the right
597  if ( inflexion_r == 1 ) then
598 
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
601 
602  if ( (u1_l_tmp*slope < 0.0) .AND. (u1_r_tmp*slope < 0.0) ) then
603 
604  u1_l = 3.0 * (u0_r - u0_l) / h
605  u1_r = 0.0
606 
607  elseif (u1_l_tmp*slope < 0.0) then
608 
609  u1_r = u1_r_tmp
610  u1_l = 3.0*(u0_r - u0_l)/h - 2.0*u1_r
611 
612  elseif (u1_r_tmp*slope < 0.0) then
613 
614  u1_l = u1_l_tmp
615  u1_r = 1.5*(u0_r - u0_l)/h - 0.5*u1_l
616 
617  else
618 
619  u1_l = u1_l_tmp
620  u1_r = u1_r_tmp
621 
622  endif
623 
624  endif ! end treating case with inflexion point on the right
625 
626  if ( abs(u1_l*h) < eps ) then
627  u1_l = 0.0
628  endif
629 
630  if ( abs(u1_r*h) < eps ) then
631  u1_r = 0.0
632  endif
633 
634 end subroutine monotonize_cubic
635 
636 !> \namespace p3m_functions
637 !!
638 !! Date of creation: 2008.06.09
639 !! L. White
640 !!
641 !! This module contains p3m interpolation routines.
642 !!
643 !! p3m interpolation is performed by estimating the edge values and slopes
644 !! and constructing a cubic polynomial. We then make sure that the edge values
645 !! are bounded and continuous and we then modify the slopes to get a monotonic
646 !! cubic curve.
647 
648 end module p3m_functions
p3m_functions
Cubic interpolation functions.
Definition: P3M_functions.F90:2
regrid_edge_values
Edge value estimation for high-order resconstruction.
Definition: regrid_edge_values.F90:2