MOM6
regrid_edge_values Module Reference

Functions/Subroutines

subroutine, public bound_edge_values (N, h, u, edge_values)
 
subroutine, public average_discontinuous_edge_values (N, edge_values)
 
subroutine, public check_discontinuous_edge_values (N, u, edge_values)
 
subroutine, public edge_values_explicit_h2 (N, h, u, edge_values)
 
subroutine, public edge_values_explicit_h4 (N, h, u, edge_values)
 
subroutine, public edge_values_implicit_h4 (N, h, u, edge_values)
 
subroutine, public edge_values_implicit_h6 (N, h, u, edge_values)
 

Variables

real, parameter hnegligible = 1.e-10
 
real, parameter hminfrac = 1.e-5
 

Function/Subroutine Documentation

◆ average_discontinuous_edge_values()

subroutine, public regrid_edge_values::average_discontinuous_edge_values ( integer, intent(in)  N,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 147 of file regrid_edge_values.F90.

Referenced by p1m_functions::p1m_interpolation(), and p3m_functions::p3m_limiter().

147 ! ------------------------------------------------------------------------------
148 ! For each interior edge, check whether the edge values are discontinuous.
149 ! If so, compute the average and replace the edge values by the average.!
150 ! ------------------------------------------------------------------------------
151 
152  ! Arguments
153  integer, intent(in) :: n ! Number of cells
154  real, dimension(:,:), intent(inout) :: edge_values
155 
156  ! Local variables
157  integer :: k ! loop index
158  real :: u0_minus ! left value at given edge
159  real :: u0_plus ! right value at given edge
160  real :: u0_avg ! avg value at given edge
161 
162  ! Loop on interior edges
163  do k = 1,n-1
164 
165  ! Edge value on the left of the edge
166  u0_minus = edge_values(k,2)
167 
168  ! Edge value on the right of the edge
169  u0_plus = edge_values(k+1,1)
170 
171  if ( u0_minus .NE. u0_plus ) then
172  u0_avg = 0.5 * ( u0_minus + u0_plus )
173  edge_values(k,2) = u0_avg
174  edge_values(k+1,1) = u0_avg
175  end if
176 
177  end do ! end loop on interior edges
178 
Here is the caller graph for this function:

◆ bound_edge_values()

subroutine, public regrid_edge_values::bound_edge_values ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 44 of file regrid_edge_values.F90.

Referenced by p1m_functions::p1m_interpolation(), p3m_functions::p3m_limiter(), ppm_functions::ppm_limiter_standard(), and pqm_functions::pqm_limiter().

44 ! ------------------------------------------------------------------------------
45 ! In this routine, we loop on all cells to bound their left and right
46 ! edge values by the cell averages. That is, the left edge value must lie
47 ! between the left cell average and the central cell average. A similar
48 ! reasoning applies to the right edge values.
49 !
50 ! Both boundary edge values are set equal to the boundary cell averages.
51 ! Any extrapolation scheme is applied after this routine has been called.
52 ! Therefore, boundary cells are treated as if they were local extrama.
53 ! ------------------------------------------------------------------------------
54 
55  ! Arguments
56  integer, intent(in) :: n ! Number of cells
57  real, dimension(:), intent(in) :: h ! cell widths (size N)
58  real, dimension(:), intent(in) :: u ! cell averages (size N)
59  real, dimension(:,:), intent(inout) :: edge_values
60 
61  ! Local variables
62  integer :: k ! loop index
63  integer :: k0, k1, k2
64  real :: h_l, h_c, h_r
65  real :: u_l, u_c, u_r
66  real :: u0_l, u0_r
67  real :: sigma_l, sigma_c, sigma_r ! left, center and right
68  ! van Leer slopes
69  real :: slope ! retained PLM slope
70 
71 
72  ! Loop on cells to bound edge value
73  do k = 1,n
74 
75  ! For the sake of bounding boundary edge values, the left neighbor
76  ! of the left boundary cell is assumed to be the same as the left
77  ! boundary cell and the right neighbor of the right boundary cell
78  ! is assumed to be the same as the right boundary cell. This
79  ! effectively makes boundary cells look like extrema.
80  if ( k .EQ. 1 ) then
81  k0 = 1
82  k1 = 1
83  k2 = 2
84  else if ( k .EQ. n ) then
85  k0 = n-1
86  k1 = n
87  k2 = n
88  else
89  k0 = k-1
90  k1 = k
91  k2 = k+1
92  end if
93 
94  ! All cells can now be treated equally
95  h_l = h(k0)
96  h_c = h(k1)
97  h_r = h(k2)
98 
99  u_l = u(k0)
100  u_c = u(k1)
101  u_r = u(k2)
102 
103  u0_l = edge_values(k,1)
104  u0_r = edge_values(k,2)
105 
106  sigma_l = 2.0 * ( u_c - u_l ) / ( h_c + 1.e-30 )
107  sigma_c = 2.0 * ( u_r - u_l ) / ( h_l + 2.0*h_c + h_r + 1.e-30 )
108  sigma_r = 2.0 * ( u_r - u_c ) / ( h_c + 1.e-30 )
109 
110  if ( (sigma_l * sigma_r) .GT. 0.0 ) then
111  slope = sign( min(abs(sigma_l),abs(sigma_c),abs(sigma_r)), sigma_c )
112  else
113  slope = 0.0
114  end if
115 
116  ! The limiter must be used in the local coordinate system to each cell.
117  ! Hence, we must multiply the slope by h1. The multiplication by 0.5 is
118  ! simply a way to make it useable in the limiter (cfr White and Adcroft
119  ! JCP 2008 Eqs 19 and 20)
120  slope = slope * h_c * 0.5
121 
122  if ( (u_l-u0_l)*(u0_l-u_c) .LT. 0.0 ) then
123  u0_l = u_c - sign( min( abs(slope), abs(u0_l-u_c) ), slope )
124  end if
125 
126  if ( (u_r-u0_r)*(u0_r-u_c) .LT. 0.0 ) then
127  u0_r = u_c + sign( min( abs(slope), abs(u0_r-u_c) ), slope )
128  end if
129 
130  ! Finally bound by neighboring cell means in case of round off
131  u0_l = max( min( u0_l, max(u_l, u_c) ), min(u_l, u_c) )
132  u0_r = max( min( u0_r, max(u_r, u_c) ), min(u_r, u_c) )
133 
134  ! Store edge values
135  edge_values(k,1) = u0_l
136  edge_values(k,2) = u0_r
137 
138  end do ! loop on interior edges
139 
Here is the caller graph for this function:

◆ check_discontinuous_edge_values()

subroutine, public regrid_edge_values::check_discontinuous_edge_values ( integer, intent(in)  N,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 186 of file regrid_edge_values.F90.

Referenced by ppm_functions::ppm_limiter_standard(), and pqm_functions::pqm_limiter().

186 ! ------------------------------------------------------------------------------
187 ! For each interior edge, check whether the edge values are discontinuous.
188 ! If so and if they are not monotonic, replace each edge value by their average.
189 ! ------------------------------------------------------------------------------
190 
191  ! Arguments
192  integer, intent(in) :: n ! Number of cells
193  real, dimension(:), intent(in) :: u ! cell averages (size N)
194  real, dimension(:,:), intent(inout) :: edge_values
195 
196  ! Local variables
197  integer :: k ! loop index
198  real :: u0_minus ! left value at given edge
199  real :: u0_plus ! right value at given edge
200  real :: um_minus ! left cell average
201  real :: um_plus ! right cell average
202  real :: u0_avg ! avg value at given edge
203 
204  ! Loop on interior cells
205  do k = 1,n-1
206 
207  ! Edge value on the left of the edge
208  u0_minus = edge_values(k,2)
209 
210  ! Edge value on the right of the edge
211  u0_plus = edge_values(k+1,1)
212 
213  ! Left cell average
214  um_minus = u(k)
215 
216  ! Right cell average
217  um_plus = u(k+1)
218 
219  if ( (u0_plus - u0_minus)*(um_plus - um_minus) .LT. 0.0 ) then
220  u0_avg = 0.5 * ( u0_minus + u0_plus )
221  u0_avg = max( min( u0_avg, max(um_minus, um_plus) ), min(um_minus, um_plus) )
222  edge_values(k,2) = u0_avg
223  edge_values(k+1,1) = u0_avg
224  end if
225 
226  end do ! end loop on interior edges
227 
Here is the caller graph for this function:

◆ edge_values_explicit_h2()

subroutine, public regrid_edge_values::edge_values_explicit_h2 ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 235 of file regrid_edge_values.F90.

References hnegligible.

235 ! ------------------------------------------------------------------------------
236 ! Compute edge values based on second-order explicit estimates.
237 ! These estimates are based on a straight line spanning two cells and evaluated
238 ! at the location of the middle edge. An interpolant spanning cells
239 ! k-1 and k is evaluated at edge k-1/2. The estimate for each edge is unique.
240 !
241 ! k-1 k
242 ! ..--o------o------o--..
243 ! k-1/2
244 !
245 ! Boundary edge values are set to be equal to the boundary cell averages.
246 ! ------------------------------------------------------------------------------
247 
248  ! Arguments
249  integer, intent(in) :: n ! Number of cells
250  real, dimension(:), intent(in) :: h ! cell widths (size N)
251  real, dimension(:), intent(in) :: u ! cell averages (size N)
252  real, dimension(:,:), intent(inout) :: edge_values
253 
254  ! Local variables
255  integer :: k ! loop index
256  real :: h0, h1 ! cell widths
257  real :: u0, u1 ! cell averages
258 
259  ! Loop on interior cells
260  do k = 2,n
261 
262  h0 = h(k-1)
263  h1 = h(k)
264 
265  ! Avoid singularities when h0+h1=0
266  if (h0+h1==0.) then
267  h0 = hnegligible
268  h1 = hnegligible
269  endif
270 
271  u0 = u(k-1)
272  u1 = u(k)
273 
274  ! Compute left edge value
275  edge_values(k,1) = ( u0*h1 + u1*h0 ) / ( h0 + h1 )
276 
277  ! Left edge value of the current cell is equal to right edge
278  ! value of left cell
279  edge_values(k-1,2) = edge_values(k,1)
280 
281  end do ! end loop on interior cells
282 
283  ! Boundary edge values are simply equal to the boundary cell averages
284  edge_values(1,1) = u(1)
285  edge_values(n,2) = u(n)
286 

◆ edge_values_explicit_h4()

subroutine, public regrid_edge_values::edge_values_explicit_h4 ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 294 of file regrid_edge_values.F90.

References polynomial_functions::evaluation_polynomial(), hminfrac, hnegligible, and regrid_solvers::solve_linear_system().

294 ! -----------------------------------------------------------------------------
295 ! Compute edge values based on fourth-order explicit estimates.
296 ! These estimates are based on a cubic interpolant spanning four cells
297 ! and evaluated at the location of the middle edge. An interpolant spanning
298 ! cells i-2, i-1, i and i+1 is evaluated at edge i-1/2. The estimate for
299 ! each edge is unique.
300 !
301 ! i-2 i-1 i i+1
302 ! ..--o------o------o------o------o--..
303 ! i-1/2
304 !
305 ! The first two edge values are estimated by evaluating the first available
306 ! cubic interpolant, i.e., the interpolant spanning cells 1, 2, 3 and 4.
307 ! Similarly, the last two edge values are estimated by evaluating the last
308 ! available interpolant.
309 !
310 ! For this fourth-order scheme, at least four cells must exist.
311 ! -----------------------------------------------------------------------------
312 
313  ! Arguments
314  integer, intent(in) :: n ! Number of cells
315  real, dimension(:), intent(in) :: h ! cell widths (size N)
316  real, dimension(:), intent(in) :: u ! cell averages (size N)
317  real, dimension(:,:), intent(inout) :: edge_values
318 
319  ! Local variables
320  integer :: i, j
321  real :: u0, u1, u2, u3
322  real :: h0, h1, h2, h3
323  real :: f1, f2, f3 ! auxiliary variables
324  real :: e ! edge value
325  real, dimension(5) :: x ! used to compute edge
326  real, dimension(4,4) :: a ! values near the boundaries
327  real, dimension(4) :: b, c
328 
329  ! Loop on interior cells
330  do i = 3,n-1
331 
332  h0 = h(i-2)
333  h1 = h(i-1)
334  h2 = h(i)
335  h3 = h(i+1)
336 
337  ! Avoid singularities when consecutive pairs of h vanish
338  if (h0+h1==0. .or. h1+h2==0. .or. h2+h3==0.) then
339  f1 = max( hnegligible, h0+h1+h2+h3 )
340  h0 = max( hminfrac*f1, h(i-2) )
341  h1 = max( hminfrac*f1, h(i-1) )
342  h2 = max( hminfrac*f1, h(i) )
343  h3 = max( hminfrac*f1, h(i+1) )
344  endif
345 
346  u0 = u(i-2)
347  u1 = u(i-1)
348  u2 = u(i)
349  u3 = u(i+1)
350 
351  f1 = (h0+h1) * (h2+h3) / (h1+h2)
352  f2 = u1 * h2 + u2 * h1
353  f3 = 1.0 / (h0+h1+h2) + 1.0 / (h1+h2+h3)
354 
355  e = f1 * f2 * f3
356 
357  f1 = h2 * (h2+h3) / ( (h0+h1+h2)*(h0+h1) )
358  f2 = u1*(h0+2.0*h1) - u0*h1
359 
360  e = e + f1*f2
361 
362  f1 = h1 * (h0+h1) / ( (h1+h2+h3)*(h2+h3) )
363  f2 = u2*(2.0*h2+h3) - u3*h2
364 
365  e = e + f1*f2
366 
367  e = e / ( h0 + h1 + h2 + h3)
368 
369  edge_values(i,1) = e
370  edge_values(i-1,2) = e
371 
372 #ifdef __DO_SAFETY_CHECKS__
373  if (e /= e) then
374  write(0,*) 'NaN in explicit_edge_h4 at k=',i
375  write(0,*) 'u0-u3=',u0,u1,u2,u3
376  write(0,*) 'h0-h3=',h0,h1,h2,h3
377  write(0,*) 'f1-f3=',f1,f2,f3
378  stop 'Nan during edge_values_explicit_h4'
379  endif
380 #endif
381 
382  end do ! end loop on interior cells
383 
384  ! Determine first two edge values
385  f1 = max( hnegligible, hminfrac*sum(h(1:4)) )
386  x(1) = 0.0
387  do i = 2,5
388  x(i) = x(i-1) + max(f1, h(i-1))
389  end do
390 
391  do i = 1,4
392 
393  do j = 1,4
394  a(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / real(j)
395  end do
396 
397  b(i) = u(i) * max(f1, h(i) )
398 
399  end do
400 
401  call solve_linear_system( a, b, c, 4 )
402 
403  ! First edge value
404  edge_values(1,1) = evaluation_polynomial( c, 4, x(1) )
405 
406  ! Second edge value
407  edge_values(1,2) = evaluation_polynomial( c, 4, x(2) )
408  edge_values(2,1) = edge_values(1,2)
409 
410 #ifdef __DO_SAFETY_CHECKS__
411  if (edge_values(1,1) /= edge_values(1,1) .or. edge_values(1,2) /= edge_values(1,2)) then
412  write(0,*) 'NaN in explicit_edge_h4 at k=',1
413  write(0,*) 'A=',a
414  write(0,*) 'B=',b
415  write(0,*) 'C=',c
416  write(0,*) 'h(1:4)=',h(1:4)
417  write(0,*) 'x=',x
418  stop 'Nan during edge_values_explicit_h4'
419  endif
420 #endif
421 
422  ! Determine last two edge values
423  f1 = max( hnegligible, hminfrac*sum(h(n-3:n)) )
424  x(1) = 0.0
425  do i = 2,5
426  x(i) = x(i-1) + max(f1, h(n-5+i))
427  end do
428 
429  do i = 1,4
430 
431  do j = 1,4
432  a(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / real(j)
433  end do
434 
435  b(i) = u(n-4+i) * max(f1, h(n-4+i) )
436 
437  end do
438 
439  call solve_linear_system( a, b, c, 4 )
440 
441  ! Last edge value
442  edge_values(n,2) = evaluation_polynomial( c, 4, x(5) )
443 
444  ! Second to last edge value
445  edge_values(n,1) = evaluation_polynomial( c, 4, x(4) )
446  edge_values(n-1,2) = edge_values(n,1)
447 
448 #ifdef __DO_SAFETY_CHECKS__
449  if (edge_values(n,1) /= edge_values(n,1) .or. edge_values(n,2) /= edge_values(n,2)) then
450  write(0,*) 'NaN in explicit_edge_h4 at k=',n
451  write(0,*) 'A='
452  do i = 1,4
453  do j = 1,4
454  a(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / real(j)
455  end do
456  write(0,*) a(i,:)
457  b(i) = u(n-4+i) * ( h(n-4+i) )
458  end do
459  write(0,*) 'B=',b
460  write(0,*) 'C=',c
461  write(0,*) 'h(:N)=',h(n-3:n)
462  write(0,*) 'x=',x
463  stop 'Nan during edge_values_explicit_h4'
464  endif
465 #endif
466 
Here is the call graph for this function:

◆ edge_values_implicit_h4()

subroutine, public regrid_edge_values::edge_values_implicit_h4 ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 474 of file regrid_edge_values.F90.

References polynomial_functions::evaluation_polynomial(), hminfrac, hnegligible, regrid_solvers::solve_linear_system(), and regrid_solvers::solve_tridiagonal_system().

Referenced by mom_remapping::build_reconstructions_1d(), mom_ale::pressure_gradient_ppm(), and regrid_interp::regridding_set_ppolys().

474 ! -----------------------------------------------------------------------------
475 ! Compute edge values based on fourth-order implicit estimates.
476 !
477 ! Fourth-order implicit estimates of edge values are based on a two-cell
478 ! stencil. A tridiagonal system is set up and is based on expressing the
479 ! edge values in terms of neighboring cell averages. The generic
480 ! relationship is
481 !
482 ! \alpha u_{i-1/2} + u_{i+1/2} + \beta u_{i+3/2} = a \bar{u}_i + b \bar{u}_{i+1}
483 !
484 ! and the stencil looks like this
485 !
486 ! i i+1
487 ! ..--o------o------o--..
488 ! i-1/2 i+1/2 i+3/2
489 !
490 ! In this routine, the coefficients \alpha, \beta, a and b are computed,
491 ! the tridiagonal system is built, boundary conditions are prescribed and
492 ! the system is solved to yield edge-value estimates.
493 !
494 ! There are N+1 unknowns and we are able to write N-1 equations. The
495 ! boundary conditions close the system.
496 ! -----------------------------------------------------------------------------
497 
498  ! Arguments
499  integer, intent(in) :: n ! Number of cells
500  real, dimension(:), intent(in) :: h ! cell widths (size N)
501  real, dimension(:), intent(in) :: u ! cell averages (size N)
502  real, dimension(:,:), intent(inout) :: edge_values
503 
504  ! Local variables
505  integer :: i, j ! loop indexes
506  real :: h0, h1 ! cell widths
507  real :: h0_2, h1_2, h0h1
508  real :: d2, d4
509  real :: alpha, beta ! stencil coefficients
510  real :: a, b
511  real, dimension(5) :: x ! system used to enforce
512  real, dimension(4,4) :: asys ! boundary conditions
513  real, dimension(4) :: bsys, csys
514  real, dimension(N+1) :: tri_l, & ! trid. system (lower diagonal)
515  tri_d, & ! trid. system (middle diagonal)
516  tri_u, & ! trid. system (upper diagonal)
517  tri_b, & ! trid. system (unknowns vector)
518  tri_x ! trid. system (rhs)
519 
520  ! Loop on cells (except last one)
521  do i = 1,n-1
522 
523  ! Get cell widths
524  h0 = h(i)
525  h1 = h(i+1)
526 
527  ! Avoid singularities when h0+h1=0
528  if (h0+h1==0.) then
529  h0 = hnegligible
530  h1 = hnegligible
531  endif
532 
533  ! Auxiliary calculations
534  d2 = (h0 + h1) ** 2
535  d4 = d2 ** 2
536  h0h1 = h0 * h1
537  h0_2 = h0 * h0
538  h1_2 = h1 * h1
539 
540  ! Coefficients
541  alpha = h1_2 / d2
542  beta = h0_2 / d2
543  a = 2.0 * h1_2 * ( h1_2 + 2.0 * h0_2 + 3.0 * h0h1 ) / d4
544  b = 2.0 * h0_2 * ( h0_2 + 2.0 * h1_2 + 3.0 * h0h1 ) / d4
545 
546  tri_l(i+1) = alpha
547  tri_d(i+1) = 1.0
548  tri_u(i+1) = beta
549 
550  tri_b(i+1) = a * u(i) + b * u(i+1)
551 
552  end do ! end loop on cells
553 
554  ! Boundary conditions: left boundary
555  h0 = max( hnegligible, hminfrac*sum(h(1:4)) )
556  x(1) = 0.0
557  do i = 2,5
558  x(i) = x(i-1) + max( h0, h(i-1) )
559  end do
560 
561  do i = 1,4
562 
563  do j = 1,4
564  asys(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / j
565  end do
566 
567  bsys(i) = u(i) * max( h0, h(i) )
568 
569  end do
570 
571  call solve_linear_system( asys, bsys, csys, 4 )
572 
573  tri_d(1) = 1.0
574  tri_u(1) = 0.0
575  tri_b(1) = evaluation_polynomial( csys, 4, x(1) ) ! first edge value
576 
577  ! Boundary conditions: right boundary
578  h0 = max( hnegligible, hminfrac*sum(h(n-3:n)) )
579  x(1) = 0.0
580  do i = 2,5
581  x(i) = x(i-1) + max( h0, h(n-5+i) )
582  end do
583 
584  do i = 1,4
585 
586  do j = 1,4
587  asys(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / j
588  end do
589 
590  bsys(i) = u(n-4+i) * max( h0, h(n-4+i) )
591 
592  end do
593 
594  call solve_linear_system( asys, bsys, csys, 4 )
595 
596  tri_l(n+1) = 0.0
597  tri_d(n+1) = 1.0
598  tri_b(n+1) = evaluation_polynomial( csys, 4, x(5) ) ! last edge value
599 
600  ! Solve tridiagonal system and assign edge values
601  call solve_tridiagonal_system( tri_l, tri_d, tri_u, tri_b, tri_x, n+1 )
602 
603  do i = 2,n
604  edge_values(i,1) = tri_x(i)
605  edge_values(i-1,2) = tri_x(i)
606  end do
607  edge_values(1,1) = tri_x(1)
608  edge_values(n,2) = tri_x(n+1)
609 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ edge_values_implicit_h6()

subroutine, public regrid_edge_values::edge_values_implicit_h6 ( integer, intent(in)  N,
real, dimension(:), intent(in)  h,
real, dimension(:), intent(in)  u,
real, dimension(:,:), intent(inout)  edge_values 
)

Definition at line 617 of file regrid_edge_values.F90.

References polynomial_functions::evaluation_polynomial(), hminfrac, hnegligible, regrid_solvers::solve_linear_system(), and regrid_solvers::solve_tridiagonal_system().

Referenced by mom_remapping::build_reconstructions_1d(), and regrid_interp::regridding_set_ppolys().

617 ! -----------------------------------------------------------------------------
618 ! Sixth-order implicit estimates of edge values are based on a four-cell,
619 ! three-edge stencil. A tridiagonal system is set up and is based on
620 ! expressing the edge values in terms of neighboring cell averages.
621 !
622 ! The generic relationship is
623 !
624 ! \alpha u_{i-1/2} + u_{i+1/2} + \beta u_{i+3/2} =
625 ! a \bar{u}_{i-1} + b \bar{u}_i + c \bar{u}_{i+1} + d \bar{u}_{i+2}
626 !
627 ! and the stencil looks like this
628 !
629 ! i-1 i i+1 i+2
630 ! ..--o------o------o------o------o--..
631 ! i-1/2 i+1/2 i+3/2
632 !
633 ! In this routine, the coefficients \alpha, \beta, a, b, c and d are
634 ! computed, the tridiagonal system is built, boundary conditions are
635 ! prescribed and the system is solved to yield edge-value estimates.
636 !
637 ! Note that the centered stencil only applies to edges 3 to N-1 (edges are
638 ! numbered 1 to n+1), which yields N-3 equations for N+1 unknowns. Two other
639 ! equations are written by using a right-biased stencil for edge 2 and a
640 ! left-biased stencil for edge N. The prescription of boundary conditions
641 ! (using sixth-order polynomials) closes the system.
642 !
643 ! CAUTION: For each edge, in order to determine the coefficients of the
644 ! implicit expression, a 6x6 linear system is solved. This may
645 ! become computationally expensive if regridding is carried out
646 ! often. Figuring out closed-form expressions for these coefficients
647 ! on nonuniform meshes turned out to be intractable.
648 ! -----------------------------------------------------------------------------
649 
650  ! Arguments
651  integer, intent(in) :: n ! Number of cells
652  real, dimension(:), intent(in) :: h ! cell widths (size N)
653  real, dimension(:), intent(in) :: u ! cell averages (size N)
654  real, dimension(:,:), intent(inout) :: edge_values
655 
656  ! Local variables
657  integer :: i, j, k ! loop indexes
658  real :: h0, h1, h2, h3 ! cell widths
659  real :: g, g_2, g_3 ! the following are
660  real :: g_4, g_5, g_6 ! auxiliary variables
661  real :: d2, d3, d4, d5, d6 ! to set up the systems
662  real :: n2, n3, n4, n5, n6 ! used to compute the
663  real :: h1_2, h2_2 ! the coefficients of the
664  real :: h1_3, h2_3 ! tridiagonal system
665  real :: h1_4, h2_4 ! ...
666  real :: h1_5, h2_5 ! ...
667  real :: h1_6, h2_6 ! ...
668  real :: h0ph1, h0ph1_2 ! ...
669  real :: h0ph1_3, h0ph1_4 ! ...
670  real :: h2ph3, h2ph3_2 ! ...
671  real :: h2ph3_3, h2ph3_4 ! ...
672  real :: h0ph1_5, h2ph3_5 ! ...
673  real :: alpha, beta ! stencil coefficients
674  real :: a, b, c, d ! "
675  real, dimension(7) :: x ! system used to enforce
676  real, dimension(6,6) :: asys ! boundary conditions
677  real, dimension(6) :: bsys, csys ! ...
678  real, dimension(N+1) :: tri_l, & ! trid. system (lower diagonal)
679  tri_d, & ! trid. system (middle diagonal)
680  tri_u, & ! trid. system (upper diagonal)
681  tri_b, & ! trid. system (unknowns vector)
682  tri_x ! trid. system (rhs)
683 
684  ! Loop on cells (except last one)
685  do k = 2,n-2
686 
687  ! Cell widths
688  h0 = h(k-1)
689  h1 = h(k+0)
690  h2 = h(k+1)
691  h3 = h(k+2)
692 
693  ! Avoid singularities when h0=0 or h3=0
694  if (h0*h3==0.) then
695  g = max( hnegligible, h0+h1+h2+h3 )
696  h0 = max( hminfrac*g, h0 )
697  h1 = max( hminfrac*g, h1 )
698  h2 = max( hminfrac*g, h2 )
699  h3 = max( hminfrac*g, h3 )
700  endif
701 
702  ! Auxiliary calculations
703  h1_2 = h1 * h1
704  h1_3 = h1_2 * h1
705  h1_4 = h1_2 * h1_2
706  h1_5 = h1_3 * h1_2
707  h1_6 = h1_3 * h1_3
708 
709  h2_2 = h2 * h2
710  h2_3 = h2_2 * h2
711  h2_4 = h2_2 * h2_2
712  h2_5 = h2_3 * h2_2
713  h2_6 = h2_3 * h2_3
714 
715  g = h0 + h1
716  g_2 = g * g
717  g_3 = g * g_2
718  g_4 = g_2 * g_2
719  g_5 = g_4 * g
720  g_6 = g_3 * g_3
721 
722  d2 = ( h1_2 - g_2 ) / h0
723  d3 = ( h1_3 - g_3 ) / h0
724  d4 = ( h1_4 - g_4 ) / h0
725  d5 = ( h1_5 - g_5 ) / h0
726  d6 = ( h1_6 - g_6 ) / h0
727 
728  g = h2 + h3
729  g_2 = g * g
730  g_3 = g * g_2
731  g_4 = g_2 * g_2
732  g_5 = g_4 * g
733  g_6 = g_3 * g_3
734 
735  n2 = ( g_2 - h2_2 ) / h3
736  n3 = ( g_3 - h2_3 ) / h3
737  n4 = ( g_4 - h2_4 ) / h3
738  n5 = ( g_5 - h2_5 ) / h3
739  n6 = ( g_6 - h2_6 ) / h3
740 
741  ! Compute matrix entries
742  asys(1,1) = 1.0
743  asys(1,2) = 1.0
744  asys(1,3) = -1.0
745  asys(1,4) = -1.0
746  asys(1,5) = -1.0
747  asys(1,6) = -1.0
748 
749  asys(2,1) = - h1
750  asys(2,2) = h2
751  asys(2,3) = -0.5 * d2
752  asys(2,4) = 0.5 * h1
753  asys(2,5) = -0.5 * h2
754  asys(2,6) = -0.5 * n2
755 
756  asys(3,1) = 0.5 * h1_2
757  asys(3,2) = 0.5 * h2_2
758  asys(3,3) = d3 / 6.0
759  asys(3,4) = - h1_2 / 6.0
760  asys(3,5) = - h2_2 / 6.0
761  asys(3,6) = - n3 / 6.0
762 
763  asys(4,1) = - h1_3 / 6.0
764  asys(4,2) = h2_3 / 6.0
765  asys(4,3) = - d4 / 24.0
766  asys(4,4) = h1_3 / 24.0
767  asys(4,5) = - h2_3 / 24.0
768  asys(4,6) = - n4 / 24.0
769 
770  asys(5,1) = h1_4 / 24.0
771  asys(5,2) = h2_4 / 24.0
772  asys(5,3) = d5 / 120.0
773  asys(5,4) = - h1_4 / 120.0
774  asys(5,5) = - h2_4 / 120.0
775  asys(5,6) = - n5 / 120.0
776 
777  asys(6,1) = - h1_5 / 120.0
778  asys(6,2) = h2_5 / 120.0
779  asys(6,3) = - d6 / 720.0
780  asys(6,4) = h1_5 / 720.0
781  asys(6,5) = - h2_5 / 720.0
782  asys(6,6) = - n6 / 720.0
783 
784  bsys(:) = (/ -1.0, 0.0, 0.0, 0.0, 0.0, 0.0 /)
785 
786  call solve_linear_system( asys, bsys, csys, 6 )
787 
788  alpha = csys(1)
789  beta = csys(2)
790  a = csys(3)
791  b = csys(4)
792  c = csys(5)
793  d = csys(6)
794 
795  tri_l(k+1) = alpha
796  tri_d(k+1) = 1.0
797  tri_u(k+1) = beta
798  tri_b(k+1) = a * u(k-1) + b * u(k) + c * u(k+1) + d * u(k+2)
799 
800  end do ! end loop on cells
801 
802  ! Use a right-biased stencil for the second row
803 
804  ! Cell widths
805  h0 = h(1)
806  h1 = h(2)
807  h2 = h(3)
808  h3 = h(4)
809 
810  ! Avoid singularities when h0=0 or h3=0
811  if (h0*h3==0.) then
812  g = max( hnegligible, h0+h1+h2+h3 )
813  h0 = max( hminfrac*g, h0 )
814  h1 = max( hminfrac*g, h1 )
815  h2 = max( hminfrac*g, h2 )
816  h3 = max( hminfrac*g, h3 )
817  endif
818 
819  ! Auxiliary calculations
820  h1_2 = h1 * h1
821  h1_3 = h1_2 * h1
822  h1_4 = h1_2 * h1_2
823  h1_5 = h1_3 * h1_2
824  h1_6 = h1_3 * h1_3
825 
826  h2_2 = h2 * h2
827  h2_3 = h2_2 * h2
828  h2_4 = h2_2 * h2_2
829  h2_5 = h2_3 * h2_2
830  h2_6 = h2_3 * h2_3
831 
832  g = h0 + h1
833  g_2 = g * g
834  g_3 = g * g_2
835  g_4 = g_2 * g_2
836  g_5 = g_4 * g
837  g_6 = g_3 * g_3
838 
839  h0ph1 = h0 + h1
840  h0ph1_2 = h0ph1 * h0ph1
841  h0ph1_3 = h0ph1_2 * h0ph1
842  h0ph1_4 = h0ph1_2 * h0ph1_2
843  h0ph1_5 = h0ph1_3 * h0ph1_2
844 
845  d2 = ( h1_2 - g_2 ) / h0
846  d3 = ( h1_3 - g_3 ) / h0
847  d4 = ( h1_4 - g_4 ) / h0
848  d5 = ( h1_5 - g_5 ) / h0
849  d6 = ( h1_6 - g_6 ) / h0
850 
851  g = h2 + h3
852  g_2 = g * g
853  g_3 = g * g_2
854  g_4 = g_2 * g_2
855  g_5 = g_4 * g
856  g_6 = g_3 * g_3
857 
858  n2 = ( g_2 - h2_2 ) / h3
859  n3 = ( g_3 - h2_3 ) / h3
860  n4 = ( g_4 - h2_4 ) / h3
861  n5 = ( g_5 - h2_5 ) / h3
862  n6 = ( g_6 - h2_6 ) / h3
863 
864  ! Compute matrix entries
865  asys(1,1) = 1.0
866  asys(1,2) = 1.0
867  asys(1,3) = -1.0
868  asys(1,4) = -1.0
869  asys(1,5) = -1.0
870  asys(1,6) = -1.0
871 
872  asys(2,1) = - h0ph1
873  asys(2,2) = 0.0
874  asys(2,3) = -0.5 * d2
875  asys(2,4) = 0.5 * h1
876  asys(2,5) = -0.5 * h2
877  asys(2,6) = -0.5 * n2
878 
879  asys(3,1) = 0.5 * h0ph1_2
880  asys(3,2) = 0.0
881  asys(3,3) = d3 / 6.0
882  asys(3,4) = - h1_2 / 6.0
883  asys(3,5) = - h2_2 / 6.0
884  asys(3,6) = - n3 / 6.0
885 
886  asys(4,1) = - h0ph1_3 / 6.0
887  asys(4,2) = 0.0
888  asys(4,3) = - d4 / 24.0
889  asys(4,4) = h1_3 / 24.0
890  asys(4,5) = - h2_3 / 24.0
891  asys(4,6) = - n4 / 24.0
892 
893  asys(5,1) = h0ph1_4 / 24.0
894  asys(5,2) = 0.0
895  asys(5,3) = d5 / 120.0
896  asys(5,4) = - h1_4 / 120.0
897  asys(5,5) = - h2_4 / 120.0
898  asys(5,6) = - n5 / 120.0
899 
900  asys(6,1) = - h0ph1_5 / 120.0
901  asys(6,2) = 0.0
902  asys(6,3) = - d6 / 720.0
903  asys(6,4) = h1_5 / 720.0
904  asys(6,5) = - h2_5 / 720.0
905  asys(6,6) = - n6 / 720.0
906 
907  bsys(:) = (/ -1.0, h1, -0.5*h1_2, h1_3/6.0, -h1_4/24.0, h1_5/120.0 /)
908 
909  call solve_linear_system( asys, bsys, csys, 6 )
910 
911  alpha = csys(1)
912  beta = csys(2)
913  a = csys(3)
914  b = csys(4)
915  c = csys(5)
916  d = csys(6)
917 
918  tri_l(2) = alpha
919  tri_d(2) = 1.0
920  tri_u(2) = beta
921  tri_b(2) = a * u(1) + b * u(2) + c * u(3) + d * u(4)
922 
923  ! Boundary conditions: left boundary
924  g = max( hnegligible, hminfrac*sum(h(1:6)) )
925  x(1) = 0.0
926  do i = 2,7
927  x(i) = x(i-1) + max( g, h(i-1) )
928  end do
929 
930  do i = 1,6
931 
932  do j = 1,6
933  asys(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / j
934  end do
935 
936  bsys(i) = u(i) * max( g, h(i) )
937 
938  end do
939 
940  call solve_linear_system( asys, bsys, csys, 6 )
941 
942  tri_l(1) = 0.0
943  tri_d(1) = 1.0
944  tri_u(1) = 0.0
945  tri_b(1) = evaluation_polynomial( csys, 6, x(1) ) ! first edge value
946 
947  ! Use a left-biased stencil for the second to last row
948 
949  ! Cell widths
950  h0 = h(n-3)
951  h1 = h(n-2)
952  h2 = h(n-1)
953  h3 = h(n)
954 
955  ! Avoid singularities when h0=0 or h3=0
956  if (h0*h3==0.) then
957  g = max( hnegligible, h0+h1+h2+h3 )
958  h0 = max( hminfrac*g, h0 )
959  h1 = max( hminfrac*g, h1 )
960  h2 = max( hminfrac*g, h2 )
961  h3 = max( hminfrac*g, h3 )
962  endif
963 
964  ! Auxiliary calculations
965  h1_2 = h1 * h1
966  h1_3 = h1_2 * h1
967  h1_4 = h1_2 * h1_2
968  h1_5 = h1_3 * h1_2
969  h1_6 = h1_3 * h1_3
970 
971  h2_2 = h2 * h2
972  h2_3 = h2_2 * h2
973  h2_4 = h2_2 * h2_2
974  h2_5 = h2_3 * h2_2
975  h2_6 = h2_3 * h2_3
976 
977  g = h0 + h1
978  g_2 = g * g
979  g_3 = g * g_2
980  g_4 = g_2 * g_2
981  g_5 = g_4 * g
982  g_6 = g_3 * g_3
983 
984  h2ph3 = h2 + h3
985  h2ph3_2 = h2ph3 * h2ph3
986  h2ph3_3 = h2ph3_2 * h2ph3
987  h2ph3_4 = h2ph3_2 * h2ph3_2
988  h2ph3_5 = h2ph3_3 * h2ph3_2
989 
990  d2 = ( h1_2 - g_2 ) / h0
991  d3 = ( h1_3 - g_3 ) / h0
992  d4 = ( h1_4 - g_4 ) / h0
993  d5 = ( h1_5 - g_5 ) / h0
994  d6 = ( h1_6 - g_6 ) / h0
995 
996  g = h2 + h3
997  g_2 = g * g
998  g_3 = g * g_2
999  g_4 = g_2 * g_2
1000  g_5 = g_4 * g
1001  g_6 = g_3 * g_3
1002 
1003  n2 = ( g_2 - h2_2 ) / h3
1004  n3 = ( g_3 - h2_3 ) / h3
1005  n4 = ( g_4 - h2_4 ) / h3
1006  n5 = ( g_5 - h2_5 ) / h3
1007  n6 = ( g_6 - h2_6 ) / h3
1008 
1009  ! Compute matrix entries
1010  asys(1,1) = 1.0
1011  asys(1,2) = 1.0
1012  asys(1,3) = -1.0
1013  asys(1,4) = -1.0
1014  asys(1,5) = -1.0
1015  asys(1,6) = -1.0
1016 
1017  asys(2,1) = 0.0
1018  asys(2,2) = h2ph3
1019  asys(2,3) = -0.5 * d2
1020  asys(2,4) = 0.5 * h1
1021  asys(2,5) = -0.5 * h2
1022  asys(2,6) = -0.5 * n2
1023 
1024  asys(3,1) = 0.0
1025  asys(3,2) = 0.5 * h2ph3_2
1026  asys(3,3) = d3 / 6.0
1027  asys(3,4) = - h1_2 / 6.0
1028  asys(3,5) = - h2_2 / 6.0
1029  asys(3,6) = - n3 / 6.0
1030 
1031  asys(4,1) = 0.0
1032  asys(4,2) = h2ph3_3 / 6.0
1033  asys(4,3) = - d4 / 24.0
1034  asys(4,4) = h1_3 / 24.0
1035  asys(4,5) = - h2_3 / 24.0
1036  asys(4,6) = - n4 / 24.0
1037 
1038  asys(5,1) = 0.0
1039  asys(5,2) = h2ph3_4 / 24.0
1040  asys(5,3) = d5 / 120.0
1041  asys(5,4) = - h1_4 / 120.0
1042  asys(5,5) = - h2_4 / 120.0
1043  asys(5,6) = - n5 / 120.0
1044 
1045  asys(6,1) = 0.0
1046  asys(6,2) = h2ph3_5 / 120.0
1047  asys(6,3) = - d6 / 720.0
1048  asys(6,4) = h1_5 / 720.0
1049  asys(6,5) = - h2_5 / 720.0
1050  asys(6,6) = - n6 / 720.0
1051 
1052  bsys(:) = (/ -1.0, -h2, -0.5*h2_2, -h2_3/6.0, -h2_4/24.0, -h2_5/120.0 /)
1053 
1054  call solve_linear_system( asys, bsys, csys, 6 )
1055 
1056  alpha = csys(1)
1057  beta = csys(2)
1058  a = csys(3)
1059  b = csys(4)
1060  c = csys(5)
1061  d = csys(6)
1062 
1063  tri_l(n) = alpha
1064  tri_d(n) = 1.0
1065  tri_u(n) = beta
1066  tri_b(n) = a * u(n-3) + b * u(n-2) + c * u(n-1) + d * u(n)
1067 
1068  ! Boundary conditions: right boundary
1069  g = max( hnegligible, hminfrac*sum(h(n-5:n)) )
1070  x(1) = 0.0
1071  do i = 2,7
1072  x(i) = x(i-1) + max( g, h(n-7+i) )
1073  end do
1074 
1075  do i = 1,6
1076 
1077  do j = 1,6
1078  asys(i,j) = ( (x(i+1)**j) - (x(i)**j) ) / j
1079  end do
1080 
1081  bsys(i) = u(n-6+i) * max( g, h(n-6+i) )
1082 
1083  end do
1084 
1085  call solve_linear_system( asys, bsys, csys, 6 )
1086 
1087  tri_l(n+1) = 0.0
1088  tri_d(n+1) = 1.0
1089  tri_u(n+1) = 0.0
1090  tri_b(n+1) = evaluation_polynomial( csys, 6, x(7) ) ! last edge value
1091 
1092  ! Solve tridiagonal system and assign edge values
1093  call solve_tridiagonal_system( tri_l, tri_d, tri_u, tri_b, tri_x, n+1 )
1094 
1095  do i = 2,n
1096  edge_values(i,1) = tri_x(i)
1097  edge_values(i-1,2) = tri_x(i)
1098  end do
1099  edge_values(1,1) = tri_x(1)
1100  edge_values(n,2) = tri_x(n+1)
1101 
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ hminfrac

real, parameter regrid_edge_values::hminfrac = 1.e-5
private

Definition at line 36 of file regrid_edge_values.F90.

Referenced by edge_values_explicit_h4(), edge_values_implicit_h4(), and edge_values_implicit_h6().

36 real, parameter :: hminfrac = 1.e-5 ! A minimum fraction for min(h)/(sum(h)

◆ hnegligible

real, parameter regrid_edge_values::hnegligible = 1.e-10
private

Definition at line 35 of file regrid_edge_values.F90.

Referenced by edge_values_explicit_h2(), edge_values_explicit_h4(), edge_values_implicit_h4(), and edge_values_implicit_h6().

35 real, parameter :: hnegligible = 1.e-10 ! A cut-off minimum thickness for sum(h)