MOM6
regrid_interp.F90
1 !> Vertical interpolation for regridding
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_error_handler, only : mom_error, fatal
7 use mom_string_functions, only : uppercase
8 
9 use regrid_edge_values, only : edge_values_explicit_h2, edge_values_explicit_h4
10 use regrid_edge_values, only : edge_values_implicit_h4, edge_values_implicit_h6
11 use regrid_edge_values, only : edge_slopes_implicit_h3, edge_slopes_implicit_h5
12 
13 use plm_functions, only : plm_reconstruction, plm_boundary_extrapolation
14 use ppm_functions, only : ppm_reconstruction, ppm_boundary_extrapolation
15 use pqm_functions, only : pqm_reconstruction, pqm_boundary_extrapolation_v1
16 
17 use p1m_functions, only : p1m_interpolation, p1m_boundary_extrapolation
18 use p3m_functions, only : p3m_interpolation, p3m_boundary_extrapolation
19 
20 implicit none ; private
21 
22 !> Control structure for regrid_interp module
23 type, public :: interp_cs_type ; private
24 
25  !> The following parameter is only relevant when used with the target
26  !! interface densities regridding scheme. It indicates which interpolation
27  !! to use to determine the grid.
28  integer :: interpolation_scheme = -1
29 
30  !> Indicate whether high-order boundary extrapolation should be used within
31  !! boundary cells
32  logical :: boundary_extrapolation
33 
34  !> If true use older, less acccurate expressions.
35  logical :: answers_2018 = .true.
36 end type interp_cs_type
37 
38 public regridding_set_ppolys, interpolate_grid
39 public build_and_interpolate_grid
40 public set_interp_scheme, set_interp_extrap
41 
42 ! List of interpolation schemes
43 integer, parameter :: interpolation_p1m_h2 = 0 !< O(h^2)
44 integer, parameter :: interpolation_p1m_h4 = 1 !< O(h^2)
45 integer, parameter :: interpolation_p1m_ih4 = 2 !< O(h^2)
46 integer, parameter :: interpolation_plm = 3 !< O(h^2)
47 integer, parameter :: interpolation_ppm_h4 = 4 !< O(h^3)
48 integer, parameter :: interpolation_ppm_ih4 = 5 !< O(h^3)
49 integer, parameter :: interpolation_p3m_ih4ih3 = 6 !< O(h^4)
50 integer, parameter :: interpolation_p3m_ih6ih5 = 7 !< O(h^4)
51 integer, parameter :: interpolation_pqm_ih4ih3 = 8 !< O(h^4)
52 integer, parameter :: interpolation_pqm_ih6ih5 = 9 !< O(h^5)
53 
54 !>@{ Interpolant degrees
55 integer, parameter :: degree_1 = 1, degree_2 = 2, degree_3 = 3, degree_4 = 4
56 integer, public, parameter :: degree_max = 5
57 !>@}
58 
59 !> When the N-R algorithm produces an estimate that lies outside [0,1], the
60 !! estimate is set to be equal to the boundary location, 0 or 1, plus or minus
61 !! an offset, respectively, when the derivative is zero at the boundary [nondim].
62 real, public, parameter :: nr_offset = 1e-6
63 !> Maximum number of Newton-Raphson iterations. Newton-Raphson iterations are
64 !! used to build the new grid by finding the coordinates associated with
65 !! target densities and interpolations of degree larger than 1.
66 integer, public, parameter :: nr_iterations = 8
67 !> Tolerance for Newton-Raphson iterations (stop when increment falls below this) [nondim]
68 real, public, parameter :: nr_tolerance = 1e-12
69 
70 contains
71 
72 !> Builds an interpolated profile for the densities within each grid cell.
73 !!
74 !! It may happen that, given a high-order interpolator, the number of
75 !! available layers is insufficient (e.g., there are two available layers for
76 !! a third-order PPM ih4 scheme). In these cases, we resort to the simplest
77 !! continuous linear scheme (P1M h2).
78 subroutine regridding_set_ppolys(CS, densities, n0, h0, ppoly0_E, ppoly0_S, &
79  ppoly0_coefs, degree, h_neglect, h_neglect_edge)
80  type(interp_cs_type), intent(in) :: CS !< Interpolation control structure
81  integer, intent(in) :: n0 !< Number of cells on source grid
82  real, dimension(n0), intent(in) :: densities !< Actual cell densities [A]
83  real, dimension(n0), intent(in) :: h0 !< cell widths on source grid [H]
84  real, dimension(n0,2), intent(inout) :: ppoly0_E !< Edge value of polynomial [A]
85  real, dimension(n0,2), intent(inout) :: ppoly0_S !< Edge slope of polynomial [A H-1]
86  real, dimension(n0,DEGREE_MAX+1), intent(inout) :: ppoly0_coefs !< Coefficients of polynomial [A]
87  integer, intent(inout) :: degree !< The degree of the polynomials
88  real, optional, intent(in) :: h_neglect !< A negligibly small width for the
89  !! purpose of cell reconstructions [H]
90  !! in the same units as h0.
91  real, optional, intent(in) :: h_neglect_edge !< A negligibly small width
92  !! for the purpose of edge value calculations [H]
93  !! in the same units as h0.
94  ! Local variables
95  logical :: extrapolate
96 
97  ! Reset piecewise polynomials
98  ppoly0_e(:,:) = 0.0
99  ppoly0_s(:,:) = 0.0
100  ppoly0_coefs(:,:) = 0.0
101 
102  extrapolate = cs%boundary_extrapolation
103 
104  ! Compute the interpolated profile of the density field and build grid
105  select case (cs%interpolation_scheme)
106 
107  case ( interpolation_p1m_h2 )
108  degree = degree_1
109  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
110  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
111  if (extrapolate) then
112  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
113  endif
114 
115  case ( interpolation_p1m_h4 )
116  degree = degree_1
117  if ( n0 >= 4 ) then
118  call edge_values_explicit_h4( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
119  else
120  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
121  endif
122  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
123  if (extrapolate) then
124  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
125  endif
126 
127  case ( interpolation_p1m_ih4 )
128  degree = degree_1
129  if ( n0 >= 4 ) then
130  call edge_values_implicit_h4( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
131  else
132  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
133  endif
134  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
135  if (extrapolate) then
136  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
137  endif
138 
139  case ( interpolation_plm )
140  degree = degree_1
141  call plm_reconstruction( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect )
142  if (extrapolate) then
143  call plm_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect )
144  endif
145 
146  case ( interpolation_ppm_h4 )
147  if ( n0 >= 4 ) then
148  degree = degree_2
149  call edge_values_explicit_h4( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
150  call ppm_reconstruction( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
151  if (extrapolate) then
152  call ppm_boundary_extrapolation( n0, h0, densities, ppoly0_e, &
153  ppoly0_coefs, h_neglect )
154  endif
155  else
156  degree = degree_1
157  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
158  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
159  if (extrapolate) then
160  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
161  endif
162  endif
163 
164  case ( interpolation_ppm_ih4 )
165  if ( n0 >= 4 ) then
166  degree = degree_2
167  call edge_values_implicit_h4( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
168  call ppm_reconstruction( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
169  if (extrapolate) then
170  call ppm_boundary_extrapolation( n0, h0, densities, ppoly0_e, &
171  ppoly0_coefs, h_neglect )
172  endif
173  else
174  degree = degree_1
175  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
176  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
177  if (extrapolate) then
178  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
179  endif
180  endif
181 
182  case ( interpolation_p3m_ih4ih3 )
183  if ( n0 >= 4 ) then
184  degree = degree_3
185  call edge_values_implicit_h4( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
186  call edge_slopes_implicit_h3( n0, h0, densities, ppoly0_s, h_neglect, answers_2018=cs%answers_2018 )
187  call p3m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_s, &
188  ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
189  if (extrapolate) then
190  call p3m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_s, &
191  ppoly0_coefs, h_neglect, h_neglect_edge )
192  endif
193  else
194  degree = degree_1
195  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
196  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
197  if (extrapolate) then
198  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
199  endif
200  endif
201 
202  case ( interpolation_p3m_ih6ih5 )
203  if ( n0 >= 6 ) then
204  degree = degree_3
205  call edge_values_implicit_h6( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
206  call edge_slopes_implicit_h5( n0, h0, densities, ppoly0_s, h_neglect, answers_2018=cs%answers_2018 )
207  call p3m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_s, &
208  ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
209  if (extrapolate) then
210  call p3m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_s, &
211  ppoly0_coefs, h_neglect, h_neglect_edge )
212  endif
213  else
214  degree = degree_1
215  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
216  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
217  if (extrapolate) then
218  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
219  endif
220  endif
221 
222  case ( interpolation_pqm_ih4ih3 )
223  if ( n0 >= 4 ) then
224  degree = degree_4
225  call edge_values_implicit_h4( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
226  call edge_slopes_implicit_h3( n0, h0, densities, ppoly0_s, h_neglect, answers_2018=cs%answers_2018 )
227  call pqm_reconstruction( n0, h0, densities, ppoly0_e, ppoly0_s, &
228  ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
229  if (extrapolate) then
230  call pqm_boundary_extrapolation_v1( n0, h0, densities, ppoly0_e, ppoly0_s, &
231  ppoly0_coefs, h_neglect )
232  endif
233  else
234  degree = degree_1
235  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
236  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
237  if (extrapolate) then
238  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
239  endif
240  endif
241 
242  case ( interpolation_pqm_ih6ih5 )
243  if ( n0 >= 6 ) then
244  degree = degree_4
245  call edge_values_implicit_h6( n0, h0, densities, ppoly0_e, h_neglect_edge, answers_2018=cs%answers_2018 )
246  call edge_slopes_implicit_h5( n0, h0, densities, ppoly0_s, h_neglect, answers_2018=cs%answers_2018 )
247  call pqm_reconstruction( n0, h0, densities, ppoly0_e, ppoly0_s, &
248  ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
249  if (extrapolate) then
250  call pqm_boundary_extrapolation_v1( n0, h0, densities, ppoly0_e, ppoly0_s, &
251  ppoly0_coefs, h_neglect )
252  endif
253  else
254  degree = degree_1
255  call edge_values_explicit_h2( n0, h0, densities, ppoly0_e )
256  call p1m_interpolation( n0, h0, densities, ppoly0_e, ppoly0_coefs, h_neglect, answers_2018=cs%answers_2018 )
257  if (extrapolate) then
258  call p1m_boundary_extrapolation( n0, h0, densities, ppoly0_e, ppoly0_coefs )
259  endif
260  endif
261  end select
262 
263 end subroutine regridding_set_ppolys
264 
265 !> Given target values (e.g., density), build new grid based on polynomial
266 !!
267 !! Given the grid 'grid0' and the piecewise polynomial interpolant
268 !! 'ppoly0' (possibly discontinuous), the coordinates of the new grid 'grid1'
269 !! are determined by finding the corresponding target interface densities.
270 subroutine interpolate_grid( n0, h0, x0, ppoly0_E, ppoly0_coefs, &
271  target_values, degree, n1, h1, x1, answers_2018 )
272  integer, intent(in) :: n0 !< Number of points on source grid
273  integer, intent(in) :: n1 !< Number of points on target grid
274  real, dimension(n0), intent(in) :: h0 !< Thicknesses of source grid cells [H]
275  real, dimension(n0+1), intent(in) :: x0 !< Source interface positions [H]
276  real, dimension(n0,2), intent(in) :: ppoly0_E !< Edge values of interpolating polynomials [A]
277  real, dimension(n0,DEGREE_MAX+1), &
278  intent(in) :: ppoly0_coefs !< Coefficients of interpolating polynomials [A]
279  real, dimension(n1+1), intent(in) :: target_values !< Target values of interfaces [A]
280  integer, intent(in) :: degree !< Degree of interpolating polynomials
281  real, dimension(n1), intent(inout) :: h1 !< Thicknesses of target grid cells [H]
282  real, dimension(n1+1), intent(inout) :: x1 !< Target interface positions [H]
283  logical, optional, intent(in) :: answers_2018 !< If true use older, less acccurate expressions.
284 
285  ! Local variables
286  logical :: use_2018_answers ! If true use older, less acccurate expressions.
287  integer :: k ! loop index
288  real :: t ! current interface target density
289 
290  ! Make sure boundary coordinates of new grid coincide with boundary
291  ! coordinates of previous grid
292  x1(1) = x0(1)
293  x1(n1+1) = x0(n0+1)
294 
295  ! Find coordinates for interior target values
296  do k = 2,n1
297  t = target_values(k)
298  x1(k) = get_polynomial_coordinate( n0, h0, x0, ppoly0_e, ppoly0_coefs, t, degree, &
299  answers_2018=answers_2018 )
300  h1(k-1) = x1(k) - x1(k-1)
301  enddo
302  h1(n1) = x1(n1+1) - x1(n1)
303 
304 end subroutine interpolate_grid
305 
306 !> Build a grid by interpolating for target values
307 subroutine build_and_interpolate_grid(CS, densities, n0, h0, x0, target_values, &
308  n1, h1, x1, h_neglect, h_neglect_edge)
309  type(interp_cs_type), intent(in) :: CS !< A control structure for regrid_interp
310  integer, intent(in) :: n0 !< The number of points on the input grid
311  integer, intent(in) :: n1 !< The number of points on the output grid
312  real, dimension(n0), intent(in) :: densities !< Input cell densities [R ~> kg m-3]
313  real, dimension(n1+1), intent(in) :: target_values !< Target values of interfaces [R ~> kg m-3]
314  real, dimension(n0), intent(in) :: h0 !< Initial cell widths [H]
315  real, dimension(n0+1), intent(in) :: x0 !< Source interface positions [H]
316  real, dimension(n1), intent(inout) :: h1 !< Output cell widths [H]
317  real, dimension(n1+1), intent(inout) :: x1 !< Target interface positions [H]
318  real, optional, intent(in) :: h_neglect !< A negligibly small width for the
319  !! purpose of cell reconstructions [H]
320  !! in the same units as h0.
321  real, optional, intent(in) :: h_neglect_edge !< A negligibly small width
322  !! for the purpose of edge value calculations [H]
323  !! in the same units as h0.
324 
325  real, dimension(n0,2) :: ppoly0_E ! Polynomial edge values [R ~> kg m-3]
326  real, dimension(n0,2) :: ppoly0_S ! Polynomial edge slopes [R H-1]
327  real, dimension(n0,DEGREE_MAX+1) :: ppoly0_C ! Polynomial interpolant coeficients on the local 0-1 grid [R ~> kg m-3]
328  integer :: degree
329 
330  call regridding_set_ppolys(cs, densities, n0, h0, ppoly0_e, ppoly0_s, ppoly0_c, &
331  degree, h_neglect, h_neglect_edge)
332  call interpolate_grid(n0, h0, x0, ppoly0_e, ppoly0_c, target_values, degree, &
333  n1, h1, x1, answers_2018=cs%answers_2018)
334 end subroutine build_and_interpolate_grid
335 
336 !> Given a target value, find corresponding coordinate for given polynomial
337 !!
338 !! Here, 'ppoly' is assumed to be a piecewise discontinuous polynomial of degree
339 !! 'degree' throughout the domain defined by 'grid'. A target value is given
340 !! and we need to determine the corresponding grid coordinate to define the
341 !! new grid.
342 !!
343 !! If the target value is out of range, the grid coordinate is simply set to
344 !! be equal to one of the boundary coordinates, which results in vanished layers
345 !! near the boundaries.
346 !!
347 !! IT IS ASSUMED THAT THE PIECEWISE POLYNOMIAL IS MONOTONICALLY INCREASING.
348 !! IF THIS IS NOT THE CASE, THE NEW GRID MAY BE ILL-DEFINED.
349 !!
350 !! It is assumed that the number of cells defining 'grid' and 'ppoly' are the
351 !! same.
352 function get_polynomial_coordinate( N, h, x_g, edge_values, ppoly_coefs, &
353  target_value, degree, answers_2018 ) result ( x_tgt )
354  ! Arguments
355  integer, intent(in) :: N !< Number of grid cells
356  real, dimension(N), intent(in) :: h !< Grid cell thicknesses [H]
357  real, dimension(N+1), intent(in) :: x_g !< Grid interface locations [H]
358  real, dimension(N,2), intent(in) :: edge_values !< Edge values of interpolating polynomials [A]
359  real, dimension(N,DEGREE_MAX+1), intent(in) :: ppoly_coefs !< Coefficients of interpolating polynomials [A]
360  real, intent(in) :: target_value !< Target value to find position for [A]
361  integer, intent(in) :: degree !< Degree of the interpolating polynomials
362  logical, optional, intent(in) :: answers_2018 !< If true use older, less acccurate expressions.
363  real :: x_tgt !< The position of x_g at which target_value is found [H]
364 
365  ! Local variables
366  real :: xi0 ! normalized target coordinate [nondim]
367  real, dimension(DEGREE_MAX) :: a ! polynomial coefficients [A]
368  real :: numerator
369  real :: denominator
370  real :: delta ! Newton-Raphson increment [nondim]
371 ! real :: x ! global target coordinate
372  real :: eps ! offset used to get away from boundaries [nondim]
373  real :: grad ! gradient during N-R iterations [A]
374  integer :: i, k, iter ! loop indices
375  integer :: k_found ! index of target cell
376  character(len=200) :: mesg
377  logical :: use_2018_answers ! If true use older, less acccurate expressions.
378 
379  eps = nr_offset
380  k_found = -1
381  use_2018_answers = .true. ; if (present(answers_2018)) use_2018_answers = answers_2018
382 
383  ! If the target value is outside the range of all values, we
384  ! force the target coordinate to be equal to the lowest or
385  ! largest value, depending on which bound is overtaken
386  if ( target_value <= edge_values(1,1) ) then
387  x_tgt = x_g(1)
388  return ! return because there is no need to look further
389  endif
390 
391  ! Since discontinuous edge values are allowed, we check whether the target
392  ! value lies between two discontinuous edge values at interior interfaces
393  do k = 2,n
394  if ( ( target_value >= edge_values(k-1,2) ) .AND. ( target_value <= edge_values(k,1) ) ) then
395  x_tgt = x_g(k)
396  return ! return because there is no need to look further
397  endif
398  enddo
399 
400  ! If the target value is outside the range of all values, we
401  ! force the target coordinate to be equal to the lowest or
402  ! largest value, depending on which bound is overtaken
403  if ( target_value >= edge_values(n,2) ) then
404  x_tgt = x_g(n+1)
405  return ! return because there is no need to look further
406  endif
407 
408  ! At this point, we know that the target value is bounded and does not
409  ! lie between discontinuous, monotonic edge values. Therefore,
410  ! there is a unique solution. We loop on all cells and find which one
411  ! contains the target value. The variable k_found holds the index value
412  ! of the cell where the taregt value lies.
413  do k = 1,n
414  if ( ( target_value > edge_values(k,1) ) .AND. ( target_value < edge_values(k,2) ) ) then
415  k_found = k
416  exit
417  endif
418  enddo
419 
420  ! At this point, 'k_found' should be strictly positive. If not, this is
421  ! a major failure because it means we could not find any target cell
422  ! despite the fact that the target value lies between the extremes. It
423  ! means there is a major problem with the interpolant. This needs to be
424  ! reported.
425  if ( k_found == -1 ) then
426  write(mesg,*) 'Could not find target coordinate', target_value, 'in get_polynomial_coordinate. This is '//&
427  'caused by an inconsistent interpolant (perhaps not monotonically increasing):', &
428  target_value, edge_values(1,1), edge_values(n,2)
429  call mom_error( fatal, mesg )
430  endif
431 
432  ! Reset all polynomial coefficients to 0 and copy those pertaining to
433  ! the found cell
434  a(:) = 0.0
435  do i = 1,degree+1
436  a(i) = ppoly_coefs(k_found,i)
437  enddo
438 
439  ! Guess the middle of the cell to start Newton-Raphson iterations
440  xi0 = 0.5
441 
442  ! Newton-Raphson iterations
443  do iter = 1,nr_iterations
444 
445  if (use_2018_answers) then
446  numerator = a(1) + a(2)*xi0 + a(3)*xi0*xi0 + a(4)*xi0*xi0*xi0 + &
447  a(5)*xi0*xi0*xi0*xi0 - target_value
448  denominator = a(2) + 2*a(3)*xi0 + 3*a(4)*xi0*xi0 + 4*a(5)*xi0*xi0*xi0
449  else ! These expressions are mathematicaly equivalent but more accurate.
450  numerator = (a(1) - target_value) + xi0*(a(2) + xi0*(a(3) + xi0*(a(4) + a(5)*xi0)))
451  denominator = a(2) + xi0*(2.*a(3) + xi0*(3.*a(4) + 4.*a(5)*xi0))
452  endif
453 
454  delta = -numerator / denominator
455 
456  xi0 = xi0 + delta
457 
458  ! Check whether new estimate is out of bounds. If the new estimate is
459  ! indeed out of bounds, we manually set it to be equal to the overtaken
460  ! bound with a small offset towards the interior when the gradient of
461  ! the function at the boundary is zero (in which case, the Newton-Raphson
462  ! algorithm does not converge).
463  if ( xi0 < 0.0 ) then
464  xi0 = 0.0
465  grad = a(2)
466  if ( grad == 0.0 ) xi0 = xi0 + eps
467  endif
468 
469  if ( xi0 > 1.0 ) then
470  xi0 = 1.0
471  if (use_2018_answers) then
472  grad = a(2) + 2*a(3) + 3*a(4) + 4*a(5)
473  else ! These expressions are mathematicaly equivalent but more accurate.
474  grad = a(2) + (2.*a(3) + (3.*a(4) + 4.*a(5)))
475  endif
476  if ( grad == 0.0 ) xi0 = xi0 - eps
477  endif
478 
479  ! break if converged or too many iterations taken
480  if ( abs(delta) < nr_tolerance ) exit
481  enddo ! end Newton-Raphson iterations
482 
483  x_tgt = x_g(k_found) + xi0 * h(k_found)
484 end function get_polynomial_coordinate
485 
486 !> Numeric value of interpolation_scheme corresponding to scheme name
487 integer function interpolation_scheme(interp_scheme)
488  character(len=*), intent(in) :: interp_scheme !< Name of the interpolation scheme
489  !! Valid values include "P1M_H2", "P1M_H4", "P1M_IH2", "PLM", "PPM_H4",
490  !! "PPM_IH4", "P3M_IH4IH3", "P3M_IH6IH5", "PQM_IH4IH3", and "PQM_IH6IH5"
491 
492  select case ( uppercase(trim(interp_scheme)) )
493  case ("P1M_H2"); interpolation_scheme = interpolation_p1m_h2
494  case ("P1M_H4"); interpolation_scheme = interpolation_p1m_h4
495  case ("P1M_IH2"); interpolation_scheme = interpolation_p1m_ih4
496  case ("PLM"); interpolation_scheme = interpolation_plm
497  case ("PPM_H4"); interpolation_scheme = interpolation_ppm_h4
498  case ("PPM_IH4"); interpolation_scheme = interpolation_ppm_ih4
499  case ("P3M_IH4IH3"); interpolation_scheme = interpolation_p3m_ih4ih3
500  case ("P3M_IH6IH5"); interpolation_scheme = interpolation_p3m_ih6ih5
501  case ("PQM_IH4IH3"); interpolation_scheme = interpolation_pqm_ih4ih3
502  case ("PQM_IH6IH5"); interpolation_scheme = interpolation_pqm_ih6ih5
503  case default ; call mom_error(fatal, "regrid_interp: "//&
504  "Unrecognized choice for INTERPOLATION_SCHEME ("//trim(interp_scheme)//").")
505  end select
506 end function interpolation_scheme
507 
508 !> Store the interpolation_scheme value in the interp_CS based on the input string.
509 subroutine set_interp_scheme(CS, interp_scheme)
510  type(interp_cs_type), intent(inout) :: CS !< A control structure for regrid_interp
511  character(len=*), intent(in) :: interp_scheme !< Name of the interpolation scheme
512  !! Valid values include "P1M_H2", "P1M_H4", "P1M_IH2", "PLM", "PPM_H4",
513  !! "PPM_IH4", "P3M_IH4IH3", "P3M_IH6IH5", "PQM_IH4IH3", and "PQM_IH6IH5"
514 
515  cs%interpolation_scheme = interpolation_scheme(interp_scheme)
516 end subroutine set_interp_scheme
517 
518 !> Store the boundary_extrapolation value in the interp_CS
519 subroutine set_interp_extrap(CS, extrap)
520  type(interp_cs_type), intent(inout) :: CS !< A control structure for regrid_interp
521  logical, intent(in) :: extrap !< Indicate whether high-order boundary
522  !! extrapolation should be used in boundary cells
523 
524  cs%boundary_extrapolation = extrap
525 end subroutine set_interp_extrap
526 
527 end module regrid_interp
Piecewise quartic reconstruction functions.
Provides functions used with the Piecewise-Parabolic-Method in the vertical ALE algorithm.
Piecewise linear reconstruction functions.
Routines for error handling and I/O management.
Cubic interpolation functions.
Control structure for regrid_interp module.
Edge value estimation for high-order resconstruction.
Handy functions for manipulating strings.
Linear interpolation functions.
Vertical interpolation for regridding.