MOM6
plm_functions Module Reference

Detailed Description

Piecewise linear reconstruction functions.

Date of creation: 2008.06.06 L. White.

This module contains routines that handle one-dimensionnal finite volume reconstruction using the piecewise linear method (PLM).

Functions/Subroutines

real elemental pure function, public plm_slope_wa (h_l, h_c, h_r, h_neglect, u_l, u_c, u_r)
 Returns a limited PLM slope following White and Adcroft, 2008. [units of u] Note that this is not the same as the Colella and Woodward method. More...
 
real elemental pure function, public plm_slope_cw (h_l, h_c, h_r, h_neglect, u_l, u_c, u_r)
 Returns a limited PLM slope following Colella and Woodward 1984. More...
 
real elemental pure function, public plm_monotonized_slope (u_l, u_c, u_r, s_l, s_c, s_r)
 Returns a limited PLM slope following Colella and Woodward 1984. More...
 
real elemental pure function, public plm_extrapolate_slope (h_l, h_c, h_neglect, u_l, u_c)
 Returns a PLM slope using h2 extrapolation from a cell to the left. Use the negative to extrapolate from the a cell to the right. More...
 
subroutine, public plm_reconstruction (N, h, u, edge_values, ppoly_coef, h_neglect)
 Reconstruction by linear polynomials within each cell. More...
 
subroutine, public plm_boundary_extrapolation (N, h, u, edge_values, ppoly_coef, h_neglect)
 Reconstruction by linear polynomials within boundary cells. More...
 

Variables

real, parameter hneglect_dflt = 1.E-30
 Default negligible cell thickness.
 

Function/Subroutine Documentation

◆ plm_boundary_extrapolation()

subroutine, public plm_functions::plm_boundary_extrapolation ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values,
real, dimension(:,:), intent(inout)  ppoly_coef,
real, intent(in), optional  h_neglect 
)

Reconstruction by linear polynomials within boundary cells.

The left and right edge values in the left and right boundary cells, respectively, are estimated using a linear extrapolation within the cells.

This extrapolation is EXACT when the underlying profile is linear.

It is assumed that the size of the array 'u' is equal to the number of cells defining 'grid' and 'ppoly'. No consistency check is performed here.

Parameters
[in]nNumber of cells
[in]hcell widths (size N)
[in]ucell averages (size N)
[in,out]edge_valuesedge values of piecewise polynomials, with the same units as u.
[in,out]ppoly_coefcoefficients of piecewise polynomials, mainly with the same units as u.
[in]h_neglectA negligibly small width for the purpose of cell reconstructions in the same units as h

Definition at line 269 of file PLM_functions.F90.

269  integer, intent(in) :: n !< Number of cells
270  real, dimension(:), intent(in) :: h !< cell widths (size N)
271  real, dimension(:), intent(in) :: u !< cell averages (size N)
272  real, dimension(:,:), intent(inout) :: edge_values !< edge values of piecewise polynomials,
273  !! with the same units as u.
274  real, dimension(:,:), intent(inout) :: ppoly_coef !< coefficients of piecewise polynomials, mainly
275  !! with the same units as u.
276  real, optional, intent(in) :: h_neglect !< A negligibly small width for
277  !! the purpose of cell reconstructions
278  !! in the same units as h
279  ! Local variables
280  real :: slope ! retained PLM slope
281  real :: hneglect
282 
283  hneglect = hneglect_dflt ; if (present(h_neglect)) hneglect = h_neglect
284 
285  ! Extrapolate from 2 to 1 to estimate slope
286  slope = - plm_extrapolate_slope( h(2), h(1), hneglect, u(2), u(1) )
287 
288  edge_values(1,1) = u(1) - 0.5 * slope
289  edge_values(1,2) = u(1) + 0.5 * slope
290 
291  ppoly_coef(1,1) = edge_values(1,1)
292  ppoly_coef(1,2) = edge_values(1,2) - edge_values(1,1)
293 
294  ! Extrapolate from N-1 to N to estimate slope
295  slope = plm_extrapolate_slope( h(n-1), h(n), hneglect, u(n-1), u(n) )
296 
297  edge_values(n,1) = u(n) - 0.5 * slope
298  edge_values(n,2) = u(n) + 0.5 * slope
299 
300  ppoly_coef(n,1) = edge_values(n,1)
301  ppoly_coef(n,2) = edge_values(n,2) - edge_values(n,1)
302 

◆ plm_extrapolate_slope()

real elemental pure function, public plm_functions::plm_extrapolate_slope ( real, intent(in)  h_l,
real, intent(in)  h_c,
real, intent(in)  h_neglect,
real, intent(in)  u_l,
real, intent(in)  u_c 
)

Returns a PLM slope using h2 extrapolation from a cell to the left. Use the negative to extrapolate from the a cell to the right.

Parameters
[in]h_lThickness of left cell [units of grid thickness]
[in]h_cThickness of center cell [units of grid thickness]
[in]h_neglectA negligible thickness [units of grid thickness]
[in]u_lValue of left cell [units of u]
[in]u_cValue of center cell [units of u]

Definition at line 161 of file PLM_functions.F90.

161  real, intent(in) :: h_l !< Thickness of left cell [units of grid thickness]
162  real, intent(in) :: h_c !< Thickness of center cell [units of grid thickness]
163  real, intent(in) :: h_neglect !< A negligible thickness [units of grid thickness]
164  real, intent(in) :: u_l !< Value of left cell [units of u]
165  real, intent(in) :: u_c !< Value of center cell [units of u]
166  ! Local variables
167  real :: left_edge ! Left edge value [units of u]
168  real :: hl, hc ! Left and central cell thicknesses [units of grid thickness]
169 
170  ! Avoid division by zero for vanished cells
171  hl = h_l + h_neglect
172  hc = h_c + h_neglect
173 
174  ! The h2 scheme is used to compute the left edge value
175  left_edge = (u_l*hc + u_c*hl) / (hl + hc)
176 
177  plm_extrapolate_slope = 2.0 * ( u_c - left_edge )
178 

◆ plm_monotonized_slope()

real elemental pure function, public plm_functions::plm_monotonized_slope ( real, intent(in)  u_l,
real, intent(in)  u_c,
real, intent(in)  u_r,
real, intent(in)  s_l,
real, intent(in)  s_c,
real, intent(in)  s_r 
)

Returns a limited PLM slope following Colella and Woodward 1984.

Parameters
[in]u_lValue of left cell [units of u]
[in]u_cValue of center cell [units of u]
[in]u_rValue of right cell [units of u]
[in]s_lPLM slope of left cell [units of u]
[in]s_cPLM slope of center cell [units of u]
[in]s_rPLM slope of right cell [units of u]

Definition at line 122 of file PLM_functions.F90.

122  real, intent(in) :: u_l !< Value of left cell [units of u]
123  real, intent(in) :: u_c !< Value of center cell [units of u]
124  real, intent(in) :: u_r !< Value of right cell [units of u]
125  real, intent(in) :: s_l !< PLM slope of left cell [units of u]
126  real, intent(in) :: s_c !< PLM slope of center cell [units of u]
127  real, intent(in) :: s_r !< PLM slope of right cell [units of u]
128  ! Local variables
129  real :: e_r, e_l, edge ! Right, left and temporary edge values [units of u]
130  real :: almost_two ! The number 2, almost.
131  real :: slp ! Magnitude of PLM central slope [units of u]
132 
133  almost_two = 2. * ( 1. - epsilon(s_c) )
134 
135  ! Edge values of neighbors abutting this cell
136  e_r = u_l + 0.5*s_l
137  e_l = u_r - 0.5*s_r
138  slp = abs(s_c)
139 
140  ! Check that left edge is between right edge of cell to the left and this cell mean
141  edge = u_c - 0.5 * s_c
142  if ( ( edge - e_r ) * ( u_c - edge ) < 0. ) then
143  edge = 0.5 * ( edge + e_r )
144  slp = min( slp, abs( edge - u_c ) * almost_two )
145  endif
146 
147  ! Check that right edge is between left edge of cell to the right and this cell mean
148  edge = u_c + 0.5 * s_c
149  if ( ( edge - u_c ) * ( e_l - edge ) < 0. ) then
150  edge = 0.5 * ( edge + e_l )
151  slp = min( slp, abs( edge - u_c ) * almost_two )
152  endif
153 
154  plm_monotonized_slope = sign( slp, s_c )
155 

◆ plm_reconstruction()

subroutine, public plm_functions::plm_reconstruction ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values,
real, dimension(:,:), intent(inout)  ppoly_coef,
real, intent(in), optional  h_neglect 
)

Reconstruction by linear polynomials within each cell.

It is assumed that the size of the array 'u' is equal to the number of cells defining 'grid' and 'ppoly'. No consistency check is performed here.

Parameters
[in]nNumber of cells
[in]hcell widths (size N)
[in]ucell averages (size N)
[in,out]edge_valuesedge values of piecewise polynomials, with the same units as u.
[in,out]ppoly_coefcoefficients of piecewise polynomials, mainly with the same units as u.
[in]h_neglectA negligibly small width for the purpose of cell reconstructions in the same units as h

Definition at line 187 of file PLM_functions.F90.

187  integer, intent(in) :: n !< Number of cells
188  real, dimension(:), intent(in) :: h !< cell widths (size N)
189  real, dimension(:), intent(in) :: u !< cell averages (size N)
190  real, dimension(:,:), intent(inout) :: edge_values !< edge values of piecewise polynomials,
191  !! with the same units as u.
192  real, dimension(:,:), intent(inout) :: ppoly_coef !< coefficients of piecewise polynomials, mainly
193  !! with the same units as u.
194  real, optional, intent(in) :: h_neglect !< A negligibly small width for
195  !! the purpose of cell reconstructions
196  !! in the same units as h
197 
198  ! Local variables
199  integer :: k ! loop index
200  real :: u_l, u_c, u_r ! left, center and right cell averages
201  real :: h_l, h_c, h_r, h_cn ! left, center and right cell widths
202  real :: slope ! retained PLM slope
203  real :: a, b ! auxiliary variables
204  real :: u_min, u_max, e_l, e_r, edge
205  real :: almost_one
206  real, dimension(N) :: slp, mslp
207  real :: hneglect
208 
209  hneglect = hneglect_dflt ; if (present(h_neglect)) hneglect = h_neglect
210 
211  almost_one = 1. - epsilon(slope)
212 
213  ! Loop on interior cells
214  do k = 2,n-1
215  slp(k) = plm_slope_wa(h(k-1), h(k), h(k+1), hneglect, u(k-1), u(k), u(k+1))
216  enddo ! end loop on interior cells
217 
218  ! Boundary cells use PCM. Extrapolation is handled after monotonization.
219  slp(1) = 0.
220  slp(n) = 0.
221 
222  ! This loop adjusts the slope so that edge values are monotonic.
223  do k = 2, n-1
224  mslp(k) = plm_monotonized_slope( u(k-1), u(k), u(k+1), slp(k-1), slp(k), slp(k+1) )
225  enddo ! end loop on interior cells
226  mslp(1) = 0.
227  mslp(n) = 0.
228 
229  ! Store and return edge values and polynomial coefficients.
230  edge_values(1,1) = u(1)
231  edge_values(1,2) = u(1)
232  ppoly_coef(1,1) = u(1)
233  ppoly_coef(1,2) = 0.
234  do k = 2, n-1
235  slope = mslp(k)
236  u_l = u(k) - 0.5 * slope ! Left edge value of cell k
237  u_r = u(k) + 0.5 * slope ! Right edge value of cell k
238 
239  edge_values(k,1) = u_l
240  edge_values(k,2) = u_r
241  ppoly_coef(k,1) = u_l
242  ppoly_coef(k,2) = ( u_r - u_l )
243  ! Check to see if this evaluation of the polynomial at x=1 would be
244  ! monotonic w.r.t. the next cell's edge value. If not, scale back!
245  edge = ppoly_coef(k,2) + ppoly_coef(k,1)
246  e_r = u(k+1) - 0.5 * sign( mslp(k+1), slp(k+1) )
247  if ( (edge-u(k))*(e_r-edge)<0.) then
248  ppoly_coef(k,2) = ppoly_coef(k,2) * almost_one
249  endif
250  enddo
251  edge_values(n,1) = u(n)
252  edge_values(n,2) = u(n)
253  ppoly_coef(n,1) = u(n)
254  ppoly_coef(n,2) = 0.
255 

◆ plm_slope_cw()

real elemental pure function, public plm_functions::plm_slope_cw ( real, intent(in)  h_l,
real, intent(in)  h_c,
real, intent(in)  h_r,
real, intent(in)  h_neglect,
real, intent(in)  u_l,
real, intent(in)  u_c,
real, intent(in)  u_r 
)

Returns a limited PLM slope following Colella and Woodward 1984.

Parameters
[in]h_lThickness of left cell [units of grid thickness]
[in]h_cThickness of center cell [units of grid thickness]
[in]h_rThickness of right cell [units of grid thickness]
[in]h_neglectA negligible thickness [units of grid thickness]
[in]u_lValue of left cell [units of u]
[in]u_cValue of center cell [units of u]
[in]u_rValue of right cell [units of u]

Definition at line 68 of file PLM_functions.F90.

68  real, intent(in) :: h_l !< Thickness of left cell [units of grid thickness]
69  real, intent(in) :: h_c !< Thickness of center cell [units of grid thickness]
70  real, intent(in) :: h_r !< Thickness of right cell [units of grid thickness]
71  real, intent(in) :: h_neglect !< A negligible thickness [units of grid thickness]
72  real, intent(in) :: u_l !< Value of left cell [units of u]
73  real, intent(in) :: u_c !< Value of center cell [units of u]
74  real, intent(in) :: u_r !< Value of right cell [units of u]
75  ! Local variables
76  real :: sigma_l, sigma_c, sigma_r ! Left, central and right slope estimates as
77  ! differences across the cell [units of u]
78  real :: u_min, u_max ! Minimum and maximum value across cell [units of u]
79  real :: h_cn ! Thickness of center cell [units of grid thickness]
80 
81  h_cn = h_c + h_neglect
82 
83  ! Side differences
84  sigma_r = u_r - u_c
85  sigma_l = u_c - u_l
86 
87  ! This is the second order slope given by equation 1.7 of
88  ! Piecewise Parabolic Method, Colella and Woodward (1984),
89  ! http://dx.doi.org/10.1016/0021-991(84)90143-8.
90  ! For uniform resolution it simplifies to ( u_r - u_l )/2 .
91  sigma_c = ( h_c / ( h_cn + ( h_l + h_r ) ) ) * ( &
92  ( 2.*h_l + h_c ) / ( h_r + h_cn ) * sigma_r &
93  + ( 2.*h_r + h_c ) / ( h_l + h_cn ) * sigma_l )
94 
95  ! Limit slope so that reconstructions are bounded by neighbors
96  u_min = min( u_l, u_c, u_r )
97  u_max = max( u_l, u_c, u_r )
98  if ( (sigma_l * sigma_r) > 0.0 ) then
99  ! This limits the slope so that the edge values are bounded by the
100  ! two cell averages spanning the edge.
101  plm_slope_cw = sign( min( abs(sigma_c), 2.*min( u_c - u_min, u_max - u_c ) ), sigma_c )
102  else
103  ! Extrema in the mean values require a PCM reconstruction avoid generating
104  ! larger extreme values.
105  plm_slope_cw = 0.0
106  endif
107 
108  ! This block tests to see if roundoff causes edge values to be out of bounds
109  if (u_c - 0.5*abs(plm_slope_cw) < u_min .or. u_c + 0.5*abs(plm_slope_cw) > u_max) then
110  plm_slope_cw = plm_slope_cw * ( 1. - epsilon(plm_slope_cw) )
111  endif
112 
113  ! An attempt to avoid inconsistency when the values become unrepresentable.
114  ! ### The following 1.E-140 is dimensionally inconsistent. A newer version of
115  ! PLM is progress that will avoid the need for such rounding.
116  if (abs(plm_slope_cw) < 1.e-140) plm_slope_cw = 0.
117 

◆ plm_slope_wa()

real elemental pure function, public plm_functions::plm_slope_wa ( real, intent(in)  h_l,
real, intent(in)  h_c,
real, intent(in)  h_r,
real, intent(in)  h_neglect,
real, intent(in)  u_l,
real, intent(in)  u_c,
real, intent(in)  u_r 
)

Returns a limited PLM slope following White and Adcroft, 2008. [units of u] Note that this is not the same as the Colella and Woodward method.

Parameters
[in]h_lThickness of left cell [units of grid thickness]
[in]h_cThickness of center cell [units of grid thickness]
[in]h_rThickness of right cell [units of grid thickness]
[in]h_neglectA negligible thickness [units of grid thickness]
[in]u_lValue of left cell [units of u]
[in]u_cValue of center cell [units of u]
[in]u_rValue of right cell [units of u]

Definition at line 22 of file PLM_functions.F90.

22  real, intent(in) :: h_l !< Thickness of left cell [units of grid thickness]
23  real, intent(in) :: h_c !< Thickness of center cell [units of grid thickness]
24  real, intent(in) :: h_r !< Thickness of right cell [units of grid thickness]
25  real, intent(in) :: h_neglect !< A negligible thickness [units of grid thickness]
26  real, intent(in) :: u_l !< Value of left cell [units of u]
27  real, intent(in) :: u_c !< Value of center cell [units of u]
28  real, intent(in) :: u_r !< Value of right cell [units of u]
29  ! Local variables
30  real :: sigma_l, sigma_c, sigma_r ! Left, central and right slope estimates as
31  ! differences across the cell [units of u]
32  real :: u_min, u_max ! Minimum and maximum value across cell [units of u]
33 
34  ! Side differences
35  sigma_r = u_r - u_c
36  sigma_l = u_c - u_l
37 
38  ! Quasi-second order difference
39  sigma_c = 2.0 * ( u_r - u_l ) * ( h_c / ( h_l + 2.0*h_c + h_r + h_neglect) )
40 
41  ! Limit slope so that reconstructions are bounded by neighbors
42  u_min = min( u_l, u_c, u_r )
43  u_max = max( u_l, u_c, u_r )
44  if ( (sigma_l * sigma_r) > 0.0 ) then
45  ! This limits the slope so that the edge values are bounded by the
46  ! two cell averages spanning the edge.
47  plm_slope_wa = sign( min( abs(sigma_c), 2.*min( u_c - u_min, u_max - u_c ) ), sigma_c )
48  else
49  ! Extrema in the mean values require a PCM reconstruction avoid generating
50  ! larger extreme values.
51  plm_slope_wa = 0.0
52  endif
53 
54  ! This block tests to see if roundoff causes edge values to be out of bounds
55  if (u_c - 0.5*abs(plm_slope_wa) < u_min .or. u_c + 0.5*abs(plm_slope_wa) > u_max) then
56  plm_slope_wa = plm_slope_wa * ( 1. - epsilon(plm_slope_wa) )
57  endif
58 
59  ! An attempt to avoid inconsistency when the values become unrepresentable.
60  ! ### The following 1.E-140 is dimensionally inconsistent. A newer version of
61  ! PLM is progress that will avoid the need for such rounding.
62  if (abs(plm_slope_wa) < 1.e-140) plm_slope_wa = 0.
63