MOM6
mom_continuity_ppm Module Reference

Detailed Description

Solve the layer continuity equation using the PPM method for layer fluxes.

This module contains the subroutines that advect layer thickness. The scheme here uses a Piecewise-Parabolic method with a positive definite limiter.

Data Types

type  continuity_ppm_cs
 Control structure for mom_continuity_ppm. More...
 
type  loop_bounds_type
 A container for loop bounds. More...
 

Functions/Subroutines

subroutine, public continuity_ppm (u, v, hin, h, uh, vh, dt, G, GV, CS, uhbt, vhbt, OBC, visc_rem_u, visc_rem_v, u_cor, v_cor, uhbt_aux, vhbt_aux, u_cor_aux, v_cor_aux, BT_cont)
 Time steps the layer thicknesses, using a monotonically limit, directionally split PPM scheme, based on Lin (1994). More...
 
subroutine zonal_mass_flux (u, h_in, uh, dt, G, GV, CS, LB, uhbt, OBC, visc_rem_u, u_cor, uhbt_aux, u_cor_aux, BT_cont)
 Calculates the mass or volume fluxes through the zonal faces, and other related quantities. More...
 
subroutine zonal_flux_layer (u, h, h_L, h_R, uh, duhdu, visc_rem, dt, G, j, ish, ieh, do_I, vol_CFL)
 Evaluates the zonal mass or volume fluxes in a layer. More...
 
subroutine zonal_face_thickness (u, h, h_L, h_R, h_u, dt, G, LB, vol_CFL, marginal, visc_rem_u)
 Sets the effective interface thickness at each zonal velocity point. More...
 
subroutine zonal_flux_adjust (u, h_in, h_L, h_R, uhbt, uh_tot_0, duhdu_tot_0, du, du_max_CFL, du_min_CFL, dt, G, CS, visc_rem, j, ish, ieh, do_I_in, full_precision, uh_3d)
 Returns the barotropic velocity adjustment that gives the desired barotropic (layer-summed) transport. More...
 
subroutine set_zonal_bt_cont (u, h_in, h_L, h_R, BT_cont, uh_tot_0, duhdu_tot_0, du_max_CFL, du_min_CFL, dt, G, CS, visc_rem, visc_rem_max, j, ish, ieh, do_I)
 Sets a structure that describes the zonal barotropic volume or mass fluxes as a function of barotropic flow to agree closely with the sum of the layer's transports. More...
 
subroutine meridional_mass_flux (v, h_in, vh, dt, G, GV, CS, LB, vhbt, OBC, visc_rem_v, v_cor, vhbt_aux, v_cor_aux, BT_cont)
 Calculates the mass or volume fluxes through the meridional faces, and other related quantities. More...
 
subroutine merid_flux_layer (v, h, h_L, h_R, vh, dvhdv, visc_rem, dt, G, J, ish, ieh, do_I, vol_CFL)
 Evaluates the meridional mass or volume fluxes in a layer. More...
 
subroutine merid_face_thickness (v, h, h_L, h_R, h_v, dt, G, LB, vol_CFL, marginal, visc_rem_v)
 Sets the effective interface thickness at each meridional velocity point. More...
 
subroutine meridional_flux_adjust (v, h_in, h_L, h_R, vhbt, vh_tot_0, dvhdv_tot_0, dv, dv_max_CFL, dv_min_CFL, dt, G, CS, visc_rem, j, ish, ieh, do_I_in, full_precision, vh_3d)
 Returns the barotropic velocity adjustment that gives the desired barotropic (layer-summed) transport. More...
 
subroutine set_merid_bt_cont (v, h_in, h_L, h_R, BT_cont, vh_tot_0, dvhdv_tot_0, dv_max_CFL, dv_min_CFL, dt, G, CS, visc_rem, visc_rem_max, j, ish, ieh, do_I)
 Sets of a structure that describes the meridional barotropic volume or mass fluxes as a function of barotropic flow to agree closely with the sum of the layer's transports. More...
 
subroutine ppm_reconstruction_x (h_in, h_L, h_R, G, LB, h_min, monotonic, simple_2nd)
 Calculates left/right edge values for PPM reconstruction. More...
 
subroutine ppm_reconstruction_y (h_in, h_L, h_R, G, LB, h_min, monotonic, simple_2nd)
 Calculates left/right edge values for PPM reconstruction. More...
 
subroutine ppm_limit_pos (h_in, h_L, h_R, h_min, G, iis, iie, jis, jie)
 This subroutine limits the left/right edge values of the PPM reconstruction to give a reconstruction that is positive-definite. Here this is reinterpreted as giving a constant thickness if the mean thickness is less than h_min, with a minimum of h_min otherwise. More...
 
subroutine ppm_limit_cw84 (h_in, h_L, h_R, G, iis, iie, jis, jie)
 This subroutine limits the left/right edge values of the PPM reconstruction according to the monotonic prescription of Colella and Woodward, 1984. More...
 
real function ratio_max (a, b, maxrat)
 Return the maximum ratio of a/b or maxrat. More...
 
subroutine, public continuity_ppm_init (Time, G, GV, param_file, diag, CS)
 Initializes continuity_ppm_cs. More...
 
integer function, public continuity_ppm_stencil (CS)
 continuity_PPM_stencil returns the continuity solver stencil size More...
 
subroutine, public continuity_ppm_end (CS)
 Destructor for continuity_ppm_cs. More...
 

Variables

integer id_clock_update
 
integer id_clock_correct
 

Function/Subroutine Documentation

◆ continuity_ppm()

subroutine, public mom_continuity_ppm::continuity_ppm ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  u,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(in)  v,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(inout)  hin,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(inout)  h,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(out)  uh,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(out)  vh,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(continuity_ppm_cs), pointer  CS,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed), intent(in), optional  uhbt,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb), intent(in), optional  vhbt,
type(ocean_obc_type), optional, pointer  OBC,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in), optional  visc_rem_u,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in), optional  visc_rem_v,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(out), optional  u_cor,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(out), optional  v_cor,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed), intent(in), optional  uhbt_aux,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb), intent(in), optional  vhbt_aux,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(out), optional  u_cor_aux,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(out), optional  v_cor_aux,
type(bt_cont_type), optional, pointer  BT_cont 
)

Time steps the layer thicknesses, using a monotonically limit, directionally split PPM scheme, based on Lin (1994).

Parameters
[in,out]gThe ocean's grid structure.
csModule's control structure.
[in]uZonal velocity, in m s-1.
[in]vMeridional velocity, in m s-1.
[in,out]hinInitial layer thickness, in H.
[in,out]hFinal layer thickness, in H.
[out]uhZonal volume flux, u*h*dy, H m2 s-1.
[out]vhMeridional volume flux, v*h*dx, H m2 s-1.
[in]dtTime increment in s.
[in]gvVertical grid structure.
[in]uhbtThe summed volume flux through zonal faces, H m2 s-1.
[in]vhbtThe summed volume flux through meridional faces, H m2 s-1.
obcOpen boundaries control structure.
[in]visc_rem_uThe fraction of zonal momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]visc_rem_vThe fraction of meridional momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[out]u_corThe zonal velocities that give uhbt as the depth-integrated transport, in m s-1.
[out]v_corThe meridional velocities that give vhbt as the depth-integrated transport, in m s-1.
[in]uhbt_auxA second set of summed volume fluxes through zonal faces, in H m2 s-1.
[in]vhbt_auxA second set of summed volume fluxes through meridional faces, in H m2 s-1.
[out]u_cor_auxThe zonal velocities that give uhbt_aux as the depth-integrated transports, in m s-1.
[out]v_cor_auxThe meridional velocities that give vhbt_aux as the depth-integrated transports, in m s-1.
bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.

Definition at line 77 of file MOM_continuity_PPM.F90.

References id_clock_update, meridional_mass_flux(), mom_error_handler::mom_error(), mom_open_boundary::obc_direction_e, mom_open_boundary::obc_direction_n, mom_open_boundary::obc_direction_s, mom_open_boundary::obc_direction_w, and zonal_mass_flux().

77  ! In the following documentation, H is used for the units of thickness (usually m or kg m-2.)
78  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
79  type(continuity_ppm_cs), pointer :: cs !< Module's control structure.
80  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Zonal velocity, in m s-1.
81  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity, in m s-1.
82  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: hin !< Initial layer thickness, in H.
83  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< Final layer thickness, in H.
84  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(out) :: uh !< Zonal volume flux,
85  !! u*h*dy, H m2 s-1.
86  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(out) :: vh !< Meridional volume flux,
87  !! v*h*dx, H m2 s-1.
88  real, intent(in) :: dt !< Time increment in s.
89  type(verticalgrid_type), intent(in) :: gv !< Vertical grid structure.
90  real, dimension(SZIB_(G),SZJ_(G)), intent(in), optional :: uhbt
91  !< The summed volume flux through zonal faces, H m2 s-1.
92  real, dimension(SZI_(G),SZJB_(G)), intent(in), optional :: vhbt
93  !< The summed volume flux through meridional faces, H m2 s-1.
94  type(ocean_obc_type), pointer, optional :: obc !< Open boundaries control structure.
95  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in), optional :: visc_rem_u
96  !< The fraction of zonal momentum originally in a layer that remains after a time-step
97  !! of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that
98  !! a layer experiences after viscosity is applied.
99  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
100  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in), optional :: visc_rem_v
101  !< The fraction of meridional momentum originally in a layer that remains after a time-step
102  !! of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that
103  !! a layer experiences after viscosity is applied.
104  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
105  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(out), optional :: u_cor
106  !< The zonal velocities that give uhbt as the depth-integrated transport, in m s-1.
107  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(out), optional :: v_cor
108  !< The meridional velocities that give vhbt as the depth-integrated transport, in m s-1.
109  real, dimension(SZIB_(G),SZJ_(G)), intent(in), optional :: uhbt_aux
110  !< A second set of summed volume fluxes through zonal faces, in H m2 s-1.
111  real, dimension(SZI_(G),SZJB_(G)), intent(in), optional :: vhbt_aux
112  !< A second set of summed volume fluxes through meridional faces, in H m2 s-1.
113  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(out), optional :: u_cor_aux
114  !< The zonal velocities that give uhbt_aux as the depth-integrated transports, in m s-1.
115  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(out), optional :: v_cor_aux
116  !< The meridional velocities that give vhbt_aux as the depth-integrated transports, in m s-1.
117  type(bt_cont_type), pointer, optional :: bt_cont !< A structure with
118  !! elements that describe the effective open face areas as a function of barotropic flow.
119  ! Local variables
120  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_input ! Left and right face thicknesses, in H.
121  real :: h_min
122  type(loop_bounds_type) :: lb
123  integer :: is, ie, js, je, nz, stencil
124  integer :: i, j, k
125 
126  logical :: x_first
127  logical :: local_flather_ew, local_flather_ns
128  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
129 
130  h_min = gv%Angstrom
131 
132  if (.not.associated(cs)) call mom_error(fatal, &
133  "MOM_continuity_PPM: Module must be initialized before it is used.")
134  x_first = (mod(g%first_direction,2) == 0)
135 
136  local_flather_ew = .false. ; local_flather_ns = .false.
137  if (present(obc)) then ; if (associated(obc)) then ; if (obc%OBC_pe) then
138  local_flather_ew = obc%Flather_u_BCs_exist_globally
139  local_flather_ns = obc%Flather_v_BCs_exist_globally
140  ! If an OBC is being applied, copy the input thicknesses so that the
141  ! OBC code works even if hin == h.
142  if (local_flather_ew .or. local_flather_ns) &
143  h_input(:,:,:) = hin(:,:,:)
144  endif ; endif ; endif
145 
146  if (present(visc_rem_u) .neqv. present(visc_rem_v)) call mom_error(fatal, &
147  "MOM_continuity_PPM: Either both visc_rem_u and visc_rem_v or neither"// &
148  " one must be present in call to continuity_PPM.")
149 
150  stencil = 3 ; if (cs%simple_2nd) stencil = 2 ; if (cs%upwind_1st) stencil = 1
151 
152  if (x_first) then
153  ! First, advect zonally.
154  lb%ish = g%isc ; lb%ieh = g%iec
155  lb%jsh = g%jsc-stencil ; lb%jeh = g%jec+stencil
156  call zonal_mass_flux(u, hin, uh, dt, g, gv, cs, lb, uhbt, obc, visc_rem_u, &
157  u_cor, uhbt_aux, u_cor_aux, bt_cont)
158 
159  call cpu_clock_begin(id_clock_update)
160 !$OMP parallel do default(none) shared(LB,nz,G,uh,hin,dt,h)
161  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
162  h(i,j,k) = hin(i,j,k) - dt* g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
163  ! Uncomment this line to prevent underflow.
164  ! if (h(i,j,k) < h_min) h(i,j,k) = h_min
165  enddo ; enddo ; enddo
166  call cpu_clock_end(id_clock_update)
167 
168  if (local_flather_ew) then
169  do k=1,nz
170  do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh+1
171  if (obc%segnum_u(i-1,j) /= obc_none) then
172  if (obc%segment(obc%segnum_u(i-1,j))%direction == obc_direction_e) &
173  h(i,j,k) = h_input(i-1,j,k)
174  endif
175  enddo
176  do i=lb%ish-1,lb%ieh
177  if (obc%segnum_u(i,j) /= obc_none) then
178  if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_w) &
179  h(i,j,k) = h_input(i+1,j,k)
180  endif
181  enddo ; enddo
182  enddo
183  endif
184  lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
185 
186  ! Now advect meridionally, using the updated thicknesses to determine
187  ! the fluxes.
188  call meridional_mass_flux(v, h, vh, dt, g, gv, cs, lb, vhbt, obc, visc_rem_v, &
189  v_cor, vhbt_aux, v_cor_aux, bt_cont)
190 
191  call cpu_clock_begin(id_clock_update)
192 !$OMP parallel do default(none) shared(h_min,nz,LB,h,dt,G,vh)
193  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
194  h(i,j,k) = h(i,j,k) - dt*g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
195  ! This line prevents underflow.
196  if (h(i,j,k) < h_min) h(i,j,k) = h_min
197  enddo ; enddo ; enddo
198  call cpu_clock_end(id_clock_update)
199 
200  if (local_flather_ns) then
201  do k=1,nz
202  do j=lb%jsh,lb%jeh+1 ; do i=lb%ish-1,lb%ieh+1
203  if (obc%segnum_v(i,j-1) /= obc_none) then
204  if (obc%segment(obc%segnum_v(i,j-1))%direction == obc_direction_n) &
205  h(i,j,k) = h_input(i,j-1,k)
206  endif
207  enddo ; enddo
208  do j=lb%jsh-1,lb%jeh ; do i=lb%ish-1,lb%ieh+1
209  if (obc%segnum_v(i,j) /= obc_none) then
210  if (obc%segment(obc%segnum_v(i,j))%direction == obc_direction_s) &
211  h(i,j,k) = h_input(i,j+1,k)
212  endif
213  enddo ; enddo
214  enddo
215  endif
216  else ! .not. x_first
217  ! First, advect meridionally, so set the loop bounds accordingly.
218  lb%ish = g%isc-stencil ; lb%ieh = g%iec+stencil
219  lb%jsh = g%jsc ; lb%jeh = g%jec
220 
221  call meridional_mass_flux(v, hin, vh, dt, g, gv, cs, lb, vhbt, obc, visc_rem_v, &
222  v_cor, vhbt_aux, v_cor_aux, bt_cont)
223 
224  call cpu_clock_begin(id_clock_update)
225 !$OMP parallel do default(none) shared(nz,LB,h,hin,dt,G,vh)
226  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
227  h(i,j,k) = hin(i,j,k) - dt*g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
228  enddo ; enddo ; enddo
229  call cpu_clock_end(id_clock_update)
230 
231  if (local_flather_ns) then
232  do k=1,nz
233  do j=lb%jsh,lb%jeh+1 ; do i=lb%ish-1,lb%ieh+1
234  if (obc%segnum_v(i,j-1) /= obc_none) then
235  if (obc%segment(obc%segnum_v(i,j-1))%direction == obc_direction_n) &
236  h(i,j,k) = h_input(i,j-1,k)
237  endif
238  enddo ; enddo
239  do j=lb%jsh-1,lb%jeh ; do i=lb%ish-1,lb%ieh+1
240  if (obc%segnum_v(i,j) /= obc_none) then
241  if (obc%segment(obc%segnum_v(i,j))%direction == obc_direction_s) &
242  h(i,j,k) = h_input(i,j+1,k)
243  endif
244  enddo ; enddo
245  enddo
246  endif
247 
248  ! Now advect zonally, using the updated thicknesses to determine
249  ! the fluxes.
250  lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
251  call zonal_mass_flux(u, h, uh, dt, g, gv, cs, lb, uhbt, obc, visc_rem_u, &
252  u_cor, uhbt_aux, u_cor_aux, bt_cont)
253 
254  call cpu_clock_begin(id_clock_update)
255 !$OMP parallel do default(none) shared(h_min,nz,LB,h,dt,G,uh)
256  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
257  h(i,j,k) = h(i,j,k) - dt* g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
258  ! This line prevents underflow.
259  if (h(i,j,k) < h_min) h(i,j,k) = h_min
260  enddo ; enddo ; enddo
261  call cpu_clock_end(id_clock_update)
262 
263  if (local_flather_ew) then
264  do k=1,nz
265  do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh+1
266  if (obc%segnum_u(i-1,j) /= obc_none) then
267  if (obc%segment(obc%segnum_u(i-1,j))%direction == obc_direction_e) &
268  h(i,j,k) = h_input(i-1,j,k)
269  endif
270  enddo
271  do i=lb%ish-1,lb%ieh
272  if (obc%segnum_u(i,j) /= obc_none) then
273  if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_w) &
274  h(i,j,k) = h_input(i+1,j,k)
275  endif
276  enddo ; enddo
277  enddo
278  endif
279  endif
280 
Here is the call graph for this function:

◆ continuity_ppm_end()

subroutine, public mom_continuity_ppm::continuity_ppm_end ( type(continuity_ppm_cs), pointer  CS)

Destructor for continuity_ppm_cs.

Parameters
csModule's control structure.

Definition at line 2209 of file MOM_continuity_PPM.F90.

Referenced by mom_continuity::continuity_end().

2209  type(continuity_ppm_cs), pointer :: cs !< Module's control structure.
2210  deallocate(cs)
Here is the caller graph for this function:

◆ continuity_ppm_init()

subroutine, public mom_continuity_ppm::continuity_ppm_init ( type(time_type), intent(in), target  Time,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(param_file_type), intent(in)  param_file,
type(diag_ctrl), intent(inout), target  diag,
type(continuity_ppm_cs), pointer  CS 
)

Initializes continuity_ppm_cs.

Parameters
[in]timeTime increment in s.
[in]gThe ocean's grid structure.
[in]gvVertical grid structure.
[in]param_fileA structure indicating the open file to parse for model parameter values.
[in,out]diagA structure that is used to regulate diagnostic output.
csModule's control structure.

This include declares and sets the variable "version".

Definition at line 2105 of file MOM_continuity_PPM.F90.

References id_clock_correct, and id_clock_update.

2105  type(time_type), target, intent(in) :: time !< Time increment in s.
2106  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
2107  type(verticalgrid_type), intent(in) :: gv !< Vertical grid structure.
2108  type(param_file_type), intent(in) :: param_file !< A structure indicating
2109  !! the open file to parse for model parameter values.
2110  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to
2111  !! regulate diagnostic output.
2112  type(continuity_ppm_cs), pointer :: cs !< Module's control structure.
2113 !> This include declares and sets the variable "version".
2114 #include "version_variable.h"
2115  character(len=40) :: mdl = "MOM_continuity_PPM" ! This module's name.
2116 
2117  if (associated(cs)) then
2118  call mom_error(warning, "continuity_PPM_init called with associated control structure.")
2119  return
2120  endif
2121  allocate(cs)
2122 
2123 ! Read all relevant parameters and write them to the model log.
2124  call log_version(param_file, mdl, version, "")
2125  call get_param(param_file, mdl, "MONOTONIC_CONTINUITY", cs%monotonic, &
2126  "If true, CONTINUITY_PPM uses the Colella and Woodward \n"//&
2127  "monotonic limiter. The default (false) is to use a \n"//&
2128  "simple positive definite limiter.", default=.false.)
2129  call get_param(param_file, mdl, "SIMPLE_2ND_PPM_CONTINUITY", cs%simple_2nd, &
2130  "If true, CONTINUITY_PPM uses a simple 2nd order \n"//&
2131  "(arithmetic mean) interpolation of the edge values. \n"//&
2132  "This may give better PV conservation propterties. While \n"//&
2133  "it formally reduces the accuracy of the continuity \n"//&
2134  "solver itself in the strongly advective limit, it does \n"//&
2135  "not reduce the overall order of accuracy of the dynamic \n"//&
2136  "core.", default=.false.)
2137  call get_param(param_file, mdl, "UPWIND_1ST_CONTINUITY", cs%upwind_1st, &
2138  "If true, CONTINUITY_PPM becomes a 1st-order upwind \n"//&
2139  "continuity solver. This scheme is highly diffusive \n"//&
2140  "but may be useful for debugging or in single-column \n"//&
2141  "mode where its minimal stencil is useful.", default=.false.)
2142  call get_param(param_file, mdl, "ETA_TOLERANCE", cs%tol_eta, &
2143  "The tolerance for the differences between the \n"//&
2144  "barotropic and baroclinic estimates of the sea surface \n"//&
2145  "height due to the fluxes through each face. The total \n"//&
2146  "tolerance for SSH is 4 times this value. The default \n"//&
2147  "is 0.5*NK*ANGSTROM, and this should not be set less x\n"//&
2148  "than about 10^-15*MAXIMUM_DEPTH.", units="m", &
2149  default=0.5*g%ke*gv%Angstrom_z)
2150 
2151  call get_param(param_file, mdl, "ETA_TOLERANCE_AUX", cs%tol_eta_aux, &
2152  "The tolerance for free-surface height discrepancies \n"//&
2153  "between the barotropic solution and the sum of the \n"//&
2154  "layer thicknesses when calculating the auxiliary \n"//&
2155  "corrected velocities. By default, this is the same as \n"//&
2156  "ETA_TOLERANCE, but can be made larger for efficiency.", &
2157  units="m", default=cs%tol_eta)
2158  call get_param(param_file, mdl, "VELOCITY_TOLERANCE", cs%tol_vel, &
2159  "The tolerance for barotropic velocity discrepancies \n"//&
2160  "between the barotropic solution and the sum of the \n"//&
2161  "layer thicknesses.", units="m s-1", default=3.0e8) ! The speed of light is the default.
2162 
2163  call get_param(param_file, mdl, "CONT_PPM_AGGRESS_ADJUST", cs%aggress_adjust,&
2164  "If true, allow the adjusted velocities to have a \n"//&
2165  "relative CFL change up to 0.5.", default=.false.)
2166  cs%vol_CFL = cs%aggress_adjust
2167  call get_param(param_file, mdl, "CONT_PPM_VOLUME_BASED_CFL", cs%vol_CFL, &
2168  "If true, use the ratio of the open face lengths to the \n"//&
2169  "tracer cell areas when estimating CFL numbers. The \n"//&
2170  "default is set by CONT_PPM_AGGRESS_ADJUST.", &
2171  default=cs%aggress_adjust, do_not_read=cs%aggress_adjust)
2172  call get_param(param_file, mdl, "CONTINUITY_CFL_LIMIT", cs%CFL_limit_adjust, &
2173  "The maximum CFL of the adjusted velocities.", units="nondim", &
2174  default=0.5)
2175  call get_param(param_file, mdl, "CONT_PPM_BETTER_ITER", cs%better_iter, &
2176  "If true, stop corrective iterations using a velocity \n"//&
2177  "based criterion and only stop if the iteration is \n"//&
2178  "better than all predecessors.", default=.true.)
2179  call get_param(param_file, mdl, "CONT_PPM_USE_VISC_REM_MAX", &
2180  cs%use_visc_rem_max, &
2181  "If true, use more appropriate limiting bounds for \n"//&
2182  "corrections in strongly viscous columns.", default=.true.)
2183  call get_param(param_file, mdl, "CONT_PPM_MARGINAL_FACE_AREAS", cs%marginal_faces, &
2184  "If true, use the marginal face areas from the continuity \n"//&
2185  "solver for use as the weights in the barotropic solver. \n"//&
2186  "Otherwise use the transport averaged areas.", default=.true.)
2187 
2188  cs%diag => diag
2189 
2190  id_clock_update = cpu_clock_id('(Ocean continuity update)', grain=clock_routine)
2191  id_clock_correct = cpu_clock_id('(Ocean continuity correction)', grain=clock_routine)
2192 
2193  cs%tol_eta = cs%tol_eta * gv%m_to_H
2194  cs%tol_eta_aux = cs%tol_eta_aux * gv%m_to_H
2195 

◆ continuity_ppm_stencil()

integer function, public mom_continuity_ppm::continuity_ppm_stencil ( type(continuity_ppm_cs), pointer  CS)

continuity_PPM_stencil returns the continuity solver stencil size

Parameters
csModule's control structure.
Returns
The continuity solver stencil size with the current settings.

Definition at line 2200 of file MOM_continuity_PPM.F90.

2200  type(continuity_ppm_cs), pointer :: cs !< Module's control structure.
2201  integer :: stencil !< The continuity solver stencil size with the current settings.
2202 
2203  stencil = 3 ; if (cs%simple_2nd) stencil = 2 ; if (cs%upwind_1st) stencil = 1
2204 

◆ merid_face_thickness()

subroutine mom_continuity_ppm::merid_face_thickness ( real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_L,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_R,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(inout)  h_v,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(loop_bounds_type), intent(in)  LB,
logical, intent(in)  vol_CFL,
logical, intent(in)  marginal,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in), optional  visc_rem_v 
)
private

Sets the effective interface thickness at each meridional velocity point.

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity, in m s-1.
[in]hLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in,out]h_vThickness at meridional faces, in H.
[in]dtTime increment in s.
[in]lbLoop bounds structure.
[in]vol_cflIf true, rescale the ratio of face areas to the cell areas when estimating the CFL number.
[in]marginalIf true, report the marginal face thicknesses; otherwise report transport-averaged thicknesses.
[in]visc_rem_vBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).

Definition at line 1420 of file MOM_continuity_PPM.F90.

Referenced by meridional_mass_flux().

1420  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
1421  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity, in m s-1.
1422  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness used to
1423  !! calculate fluxes, in H.
1424  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_l !< Left thickness in the
1425  !! reconstruction, in H.
1426  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_r !< Right thickness in the
1427  !! reconstruction, in H.
1428  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: h_v !< Thickness at meridional faces,
1429  !! in H.
1430  real, intent(in) :: dt !< Time increment in s.
1431  type(loop_bounds_type), intent(in) :: lb !< Loop bounds structure.
1432  logical, intent(in) :: vol_cfl !<
1433  !! If true, rescale the ratio of face areas to the cell
1434  !! areas when estimating the CFL number.
1435  logical, intent(in) :: marginal !<
1436  !! If true, report the marginal face thicknesses; otherwise
1437  !! report transport-averaged thicknesses.
1438  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in), optional :: visc_rem_v !<
1439  !! Both the fraction of the momentum originally in a
1440  !! layer that remains after a time-step of viscosity,
1441  !! and the fraction of a time-step's worth of a
1442  !! barotropic acceleration that a layer experiences
1443  !! after viscosity is applied. Non-dimensional between
1444  !! 0 (at the bottom) and 1 (far above the bottom).
1445  ! Local variables
1446  real :: cfl ! The CFL number based on the local velocity and grid spacing, ND.
1447  real :: curv_3 ! A measure of the thickness curvature over a grid length,
1448  ! with the same units as h_in.
1449  real :: h_avg ! The average thickness of a flux, in H.
1450  real :: h_marg ! The marginal thickness of a flux, in H.
1451  integer :: i, j, k, ish, ieh, jsh, jeh, nz
1452  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1453 
1454 !$OMP parallel default(none) shared(ish,ieh,jsh,jeh,nz,v,vol_CFL,dt,G, &
1455 !$OMP h_L,h_R,h,h_v,visc_rem_v,marginal) &
1456 !$OMP private(CFL,curv_3,h_marg,h_avg)
1457 !$OMP do
1458  do k=1,nz ; do j=jsh-1,jeh ; do i=ish,ieh
1459  if (v(i,j,k) > 0.0) then
1460  if (vol_cfl) then ; cfl = (v(i,j,k) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1461  else ; cfl = v(i,j,k) * dt * g%IdyT(i,j) ; endif
1462  curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
1463  h_avg = h_r(i,j,k) + cfl * (0.5*(h_l(i,j,k) - h_r(i,j,k)) + curv_3*(cfl - 1.5))
1464  h_marg = h_r(i,j,k) + cfl * ((h_l(i,j,k) - h_r(i,j,k)) + &
1465  3.0*curv_3*(cfl - 1.0))
1466  elseif (v(i,j,k) < 0.0) then
1467  if (vol_cfl) then ; cfl = (-v(i,j,k)*dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1468  else ; cfl = -v(i,j,k) * dt * g%IdyT(i,j+1) ; endif
1469  curv_3 = h_l(i,j+1,k) + h_r(i,j+1,k) - 2.0*h(i,j+1,k)
1470  h_avg = h_l(i,j+1,k) + cfl * (0.5*(h_r(i,j+1,k)-h_l(i,j+1,k)) + curv_3*(cfl - 1.5))
1471  h_marg = h_l(i,j+1,k) + cfl * ((h_r(i,j+1,k)-h_l(i,j+1,k)) + &
1472  3.0*curv_3*(cfl - 1.0))
1473  else
1474  h_avg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1475  ! The choice to use the arithmetic mean here is somewhat arbitrariy, but
1476  ! it should be noted that h_L(i+1,j,k) and h_R(i,j,k) are usually the same.
1477  h_marg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1478  ! h_marg = (2.0 * h_L(i,j+1,k) * h_R(i,j,k)) / &
1479  ! (h_L(i,j+1,k) + h_R(i,j,k) + GV%H_subroundoff)
1480  endif
1481 
1482  if (marginal) then ; h_v(i,j,k) = h_marg
1483  else ; h_v(i,j,k) = h_avg ; endif
1484  enddo ; enddo ; enddo
1485 
1486  if (present(visc_rem_v)) then
1487 !$OMP do
1488  do k=1,nz ; do j=jsh-1,jeh ; do i=ish,ieh
1489  h_v(i,j,k) = h_v(i,j,k) * visc_rem_v(i,j,k)
1490  enddo ; enddo ; enddo
1491  endif
1492 !$OMP end parallel
1493 
Here is the caller graph for this function:

◆ merid_flux_layer()

subroutine mom_continuity_ppm::merid_flux_layer ( real, dimension(szi_(g)), intent(in)  v,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h_L,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h_R,
real, dimension( g %isd: g %ied), intent(inout)  vh,
real, dimension( g %isd: g %ied), intent(inout)  dvhdv,
real, dimension(szi_(g)), intent(in)  visc_rem,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
integer, intent(in)  J,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, dimension( g %isd: g %ied), intent(in)  do_I,
logical, intent(in)  vol_CFL 
)
private

Evaluates the meridional mass or volume fluxes in a layer.

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity, in m s-1.
[in]visc_remBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]hLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in,out]vhMeridional mass or volume transport, in H m2 s-1.
[in,out]dvhdvPartial derivative of vh with v, in H m.
[in]dtTime increment in s.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_iWhich i values to work on.
[in]vol_cflIf true, rescale the ratio of face areas to the cell areas when estimating the CFL number.

Definition at line 1360 of file MOM_continuity_PPM.F90.

Referenced by meridional_flux_adjust(), meridional_mass_flux(), and set_merid_bt_cont().

1360  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
1361  real, dimension(SZI_(G)), intent(in) :: v !< Meridional velocity, in m s-1.
1362  real, dimension(SZI_(G)), intent(in) :: visc_rem !< Both the fraction of the
1363  !! momentum originally in a layer that remains after a time-step
1364  !! of viscosity, and the fraction of a time-step's worth of a barotropic
1365  !! acceleration that a layer experiences after viscosity is applied.
1366  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
1367  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h !< Layer thickness used to
1368  !! calculate fluxes, in H.
1369  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_l !< Left thickness in the
1370  !! reconstruction, in H.
1371  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_r !< Right thickness in the
1372  !! reconstruction, in H.
1373  real, dimension(SZI_(G)), intent(inout) :: vh !< Meridional mass or volume
1374  !! transport, in H m2 s-1.
1375  real, dimension(SZI_(G)), intent(inout) :: dvhdv !< Partial derivative of vh
1376  !! with v, in H m.
1377  real, intent(in) :: dt !< Time increment in s.
1378  integer, intent(in) :: j !< Spatial index.
1379  integer, intent(in) :: ish !< Start of index range.
1380  integer, intent(in) :: ieh !< End of index range.
1381  logical, dimension(SZI_(G)), intent(in) :: do_i !< Which i values to work on.
1382  logical, intent(in) :: vol_cfl !< If true, rescale the
1383  !! ratio of face areas to the cell areas when estimating the CFL number.
1384  ! Local variables
1385  real :: cfl ! The CFL number based on the local velocity and grid spacing, ND.
1386  real :: curv_3 ! A measure of the thickness curvature over a grid length,
1387  ! with the same units as h_in.
1388  real :: h_marg ! The marginal thickness of a flux, in m.
1389  integer :: i
1390 
1391  do i=ish,ieh ; if (do_i(i)) then
1392  if (v(i) > 0.0) then
1393  if (vol_cfl) then ; cfl = (v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1394  else ; cfl = v(i) * dt * g%IdyT(i,j) ; endif
1395  curv_3 = h_l(i,j) + h_r(i,j) - 2.0*h(i,j)
1396  vh(i) = g%dx_Cv(i,j) * v(i) * ( h_r(i,j) + cfl * &
1397  (0.5*(h_l(i,j) - h_r(i,j)) + curv_3*(cfl - 1.5)) )
1398  h_marg = h_r(i,j) + cfl * ((h_l(i,j) - h_r(i,j)) + &
1399  3.0*curv_3*(cfl - 1.0))
1400  elseif (v(i) < 0.0) then
1401  if (vol_cfl) then ; cfl = (-v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1402  else ; cfl = -v(i) * dt * g%IdyT(i,j+1) ; endif
1403  curv_3 = h_l(i,j+1) + h_r(i,j+1) - 2.0*h(i,j+1)
1404  vh(i) = g%dx_Cv(i,j) * v(i) * ( h_l(i,j+1) + cfl * &
1405  (0.5*(h_r(i,j+1)-h_l(i,j+1)) + curv_3*(cfl - 1.5)) )
1406  h_marg = h_l(i,j+1) + cfl * ((h_r(i,j+1)-h_l(i,j+1)) + &
1407  3.0*curv_3*(cfl - 1.0))
1408  else
1409  vh(i) = 0.0
1410  h_marg = 0.5 * (h_l(i,j+1) + h_r(i,j))
1411  endif
1412  dvhdv(i) = g%dx_Cv(i,j) * h_marg * visc_rem(i)
1413  endif ; enddo
1414 
Here is the caller graph for this function:

◆ meridional_flux_adjust()

subroutine mom_continuity_ppm::meridional_flux_adjust ( real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_in,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_L,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_R,
real, dimension( g %isd: g %ied), intent(in), optional  vhbt,
real, dimension( g %isd: g %ied), intent(in)  vh_tot_0,
real, dimension( g %isd: g %ied), intent(in)  dvhdv_tot_0,
real, dimension( g %isd: g %ied), intent(out)  dv,
real, dimension( g %isd: g %ied), intent(in)  dv_max_CFL,
real, dimension( g %isd: g %ied), intent(in)  dv_min_CFL,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(continuity_ppm_cs), pointer  CS,
real, dimension(szi_(g),szk_(g)), intent(in)  visc_rem,
integer, intent(in)  j,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, dimension(szi_(g)), intent(in)  do_I_in,
logical, intent(in), optional  full_precision,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(inout), optional  vh_3d 
)
private

Returns the barotropic velocity adjustment that gives the desired barotropic (layer-summed) transport.

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity, in m s-1.
[in]h_inLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in]visc_remBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]vhbtThe summed volume flux through meridional faces, H m2 s-1.
[in]dv_max_cflMaximum acceptable value of dv, in m s-1.
[in]dv_min_cflMinimum acceptable value of dv, in m s-1.
[in]vh_tot_0The summed transport with 0 adjustment, in H m2 s-1.
[in]dvhdv_tot_0The partial derivative of dv_err with dv at 0 adjustment, in H m.
[out]dvThe barotropic velocity adjustment, in m s-1.
[in]dtTime increment in s.
csThis module's control structure.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_i_inA logical flag indicating which I values to work on.
[in]full_precisionfull_precision - A flag indicating how carefully to iterate. The default is .true. (more accurate).
[in,out]vh_3dVolume flux through meridional faces = v*h*dx, H m2 s-1.

Definition at line 1500 of file MOM_continuity_PPM.F90.

References merid_flux_layer().

Referenced by meridional_mass_flux(), and set_merid_bt_cont().

1500  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
1501  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity, in m s-1.
1502  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_in !< Layer thickness used to
1503  !! calculate fluxes, in H.
1504  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_l !< Left thickness in the
1505  !! reconstruction, in H.
1506  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_r !< Right thickness in the
1507  !! reconstruction, in H.
1508  real, dimension(SZI_(G),SZK_(G)), intent(in) :: visc_rem !<
1509  !! Both the fraction of the momentum originally in a
1510  !! layer that remains after a time-step of viscosity,
1511  !! and the fraction of a time-step's worth of a
1512  !! barotropic acceleration that a layer experiences
1513  !! after viscosity is applied. Non-dimensional between
1514  !! 0 (at the bottom) and 1 (far above the bottom).
1515  real, dimension(SZI_(G)), intent(in), optional :: vhbt !<
1516  !! The summed volume flux through meridional faces, H m2 s-1.
1517  real, dimension(SZI_(G)), intent(in) :: dv_max_cfl !< Maximum acceptable value
1518  !! of dv, in m s-1.
1519  real, dimension(SZI_(G)), intent(in) :: dv_min_cfl !< Minimum acceptable value
1520  !! of dv, in m s-1.
1521  real, dimension(SZI_(G)), intent(in) :: vh_tot_0 !<
1522  !! The summed transport with 0 adjustment, in H m2 s-1.
1523  real, dimension(SZI_(G)), intent(in) :: dvhdv_tot_0 !<
1524  !! The partial derivative of dv_err with dv at 0 adjustment, in H m.
1525  real, dimension(SZI_(G)), intent(out) :: dv !<
1526  !! The barotropic velocity adjustment, in m s-1.
1527  real, intent(in) :: dt !< Time increment in s.
1528  type(continuity_ppm_cs), pointer :: cs !< This module's control structure.
1529  integer, intent(in) :: j !< Spatial index.
1530  integer, intent(in) :: ish !< Start of index range.
1531  integer, intent(in) :: ieh !< End of index range.
1532  logical, dimension(SZI_(G)), intent(in) :: do_i_in !<
1533  !! A logical flag indicating which I values to work on.
1534  logical, intent(in), optional :: full_precision !<
1535  !! full_precision - A flag indicating how carefully to iterate. The
1536  !! default is .true. (more accurate).
1537  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout), optional :: vh_3d !<
1538  !! Volume flux through meridional faces = v*h*dx, H m2 s-1.
1539  ! Local variables
1540  real, dimension(SZI_(G),SZK_(G)) :: &
1541  vh_aux, & ! An auxiliary meridional volume flux, in H m s-1.
1542  dvhdv ! Partial derivative of vh with v, in H m.
1543  real, dimension(SZI_(G)) :: &
1544  vh_err, & ! Difference between vhbt and the summed vh, in H m2 s-1.
1545  vh_err_best, & ! The smallest value of vh_err found so far, in H m2 s-1.
1546  v_new, & ! The velocity with the correction added, in m s-1.
1547  dvhdv_tot,&! Summed partial derivative of vh with u, in H m.
1548  dv_min, & ! Min/max limits on dv correction based on CFL limits
1549  dv_max ! and previous iterations, in m s-1.
1550  real :: dv_prev ! The previous value of dv, in m s-1.
1551  real :: ddv ! The change in dv from the previous iteration, in m s-1.
1552  real :: tol_eta ! The tolerance for the current iteration, in m.
1553  real :: tol_vel ! The tolerance for velocity in the current iteration, m s-1.
1554  integer :: i, k, nz, itt, max_itts = 20
1555  logical :: full_prec, domore, do_i(szi_(g))
1556 
1557  nz = g%ke
1558  full_prec = .true. ; if (present(full_precision)) full_prec = full_precision
1559 
1560  vh_aux(:,:) = 0.0 ; dvhdv(:,:) = 0.0
1561 
1562  if (present(vh_3d)) then ; do k=1,nz ; do i=ish,ieh
1563  vh_aux(i,k) = vh_3d(i,j,k)
1564  enddo ; enddo ; endif
1565 
1566  do i=ish,ieh
1567  dv(i) = 0.0 ; do_i(i) = do_i_in(i)
1568  dv_max(i) = dv_max_cfl(i) ; dv_min(i) = dv_min_cfl(i)
1569  vh_err(i) = vh_tot_0(i) - vhbt(i) ; dvhdv_tot(i) = dvhdv_tot_0(i)
1570  vh_err_best(i) = abs(vh_err(i))
1571  enddo
1572 
1573  do itt=1,max_itts
1574  if (full_prec) then
1575  select case (itt)
1576  case (:1) ; tol_eta = 1e-6 * cs%tol_eta
1577  case (2) ; tol_eta = 1e-4 * cs%tol_eta
1578  case (3) ; tol_eta = 1e-2 * cs%tol_eta
1579  case default ; tol_eta = cs%tol_eta
1580  end select
1581  else
1582  tol_eta = cs%tol_eta_aux ; if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
1583  endif
1584  tol_vel = cs%tol_vel
1585 
1586  do i=ish,ieh
1587  if (vh_err(i) > 0.0) then ; dv_max(i) = dv(i)
1588  elseif (vh_err(i) < 0.0) then ; dv_min(i) = dv(i)
1589  else ; do_i(i) = .false. ; endif
1590  enddo
1591  domore = .false.
1592  do i=ish,ieh ; if (do_i(i)) then
1593  if ((dt*min(g%IareaT(i,j),g%IareaT(i,j+1))*abs(vh_err(i)) > tol_eta) .or.&
1594  (cs%better_iter .and. ((abs(vh_err(i)) > tol_vel * dvhdv_tot(i)) .or.&
1595  (abs(vh_err(i)) > vh_err_best(i))) )) then
1596  ! Use Newton's method, provided it stays bounded. Otherwise bisect
1597  ! the value with the appropriate bound.
1598  if (full_prec) then
1599  ddv = -vh_err(i) / dvhdv_tot(i)
1600  dv_prev = dv(i)
1601  dv(i) = dv(i) + ddv
1602  if (abs(ddv) < 1.0e-15*abs(dv(i))) then
1603  do_i(i) = .false. ! ddv is small enough to quit.
1604  elseif (ddv > 0.0) then
1605  if (dv(i) >= dv_max(i)) then
1606  dv(i) = 0.5*(dv_prev + dv_max(i))
1607  if (dv_max(i) - dv_prev < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1608  endif
1609  else ! dvv(i) < 0.0
1610  if (dv(i) <= dv_min(i)) then
1611  dv(i) = 0.5*(dv_prev + dv_min(i))
1612  if (dv_prev - dv_min(i) < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1613  endif
1614  endif
1615  else
1616  ! Use Newton's method, provided it stays bounded, just like above.
1617  dv(i) = dv(i) - vh_err(i) / dvhdv_tot(i)
1618  if ((dv(i) >= dv_max(i)) .or. (dv(i) <= dv_min(i))) &
1619  dv(i) = 0.5*(dv_max(i) + dv_min(i))
1620  endif
1621  if (do_i(i)) domore = .true.
1622  else
1623  do_i(i) = .false.
1624  endif
1625  endif ; enddo
1626  if (.not.domore) exit
1627 
1628  if ((itt < max_itts) .or. present(vh_3d)) then ; do k=1,nz
1629  do i=ish,ieh ; v_new(i) = v(i,j,k) + dv(i) * visc_rem(i,k) ; enddo
1630  call merid_flux_layer(v_new, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1631  vh_aux(:,k), dvhdv(:,k), visc_rem(:,k), &
1632  dt, g, j, ish, ieh, do_i, cs%vol_CFL)
1633  enddo ; endif
1634 
1635  if (itt < max_itts) then
1636  do i=ish,ieh
1637  vh_err(i) = -vhbt(i) ; dvhdv_tot(i) = 0.0
1638  enddo
1639  do k=1,nz ; do i=ish,ieh
1640  vh_err(i) = vh_err(i) + vh_aux(i,k)
1641  dvhdv_tot(i) = dvhdv_tot(i) + dvhdv(i,k)
1642  enddo ; enddo
1643  do i=ish,ieh
1644  vh_err_best(i) = min(vh_err_best(i), abs(vh_err(i)))
1645  enddo
1646  endif
1647  enddo ! itt-loop
1648  ! If there are any faces which have not converged to within the tolerance,
1649  ! so-be-it, or else use a final upwind correction?
1650  ! This never seems to happen with 20 iterations as max_itt.
1651 
1652  if (present(vh_3d)) then ; do k=1,nz ; do i=ish,ieh
1653  vh_3d(i,j,k) = vh_aux(i,k)
1654  enddo ; enddo ; endif
1655 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ meridional_mass_flux()

subroutine mom_continuity_ppm::meridional_mass_flux ( real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(inout)  h_in,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(out)  vh,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(continuity_ppm_cs), pointer  CS,
type(loop_bounds_type), intent(in)  LB,
real, dimension(szi_(g),szjb_(g)), intent(in), optional  vhbt,
type(ocean_obc_type), optional, pointer  OBC,
real, dimension( g %isd: g %ied, g %jsdb: g %jedb, g %ke), intent(in), optional  visc_rem_v,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(out), optional  v_cor,
real, dimension(szi_(g),szjb_(g)), intent(in), optional  vhbt_aux,
real, dimension(szi_(g),szjb_(g),szk_(g)), intent(out), optional  v_cor_aux,
type(bt_cont_type), optional, pointer  BT_cont 
)
private

Calculates the mass or volume fluxes through the meridional faces, and other related quantities.

Parameters
[in,out]gOcean's grid structure.
[in]gvOcean's vertical grid structure.
[in]vMeridional velocity, in m s-1.
[in,out]h_inLayer thickness used to calculate fluxes, in H.
[out]vhVolume flux through meridional faces = v*h*dx, H m2 s-1.
[in]dtTime increment in s.
csThis module's control structure.
[in]lbLoop bounds structure.
obcThis open boundary condition type specifies whether, where, and what open boundary conditions are used.
[in]visc_rem_vBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Nondimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]vhbtThe summed volume flux through meridional faces, H m2 s-1.
[in]vhbt_auxA second set of summed volume fluxes through meridional faces, in H m2 s-1.
[out]v_corThe meridional velocitiess (v with a barotropic correction) that give vhbt as the depth-integrated transport, m s-1.
[out]v_cor_auxThe meridional velocities (v with a barotropic correction) that give vhbt_aux as the depth-integrated transports, in m s-1.
bt_contA structure with elements that describe the effective

Definition at line 1055 of file MOM_continuity_PPM.F90.

References id_clock_correct, id_clock_update, merid_face_thickness(), merid_flux_layer(), meridional_flux_adjust(), ppm_reconstruction_y(), ratio_max(), and set_merid_bt_cont().

Referenced by continuity_ppm().

1055  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
1056  type(verticalgrid_type), intent(in) :: gv !< Ocean's vertical grid structure.
1057  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity, in m s-1.
1058  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h_in !< Layer thickness used to
1059  !! calculate fluxes, in H.
1060  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(out) :: vh !< Volume flux through meridional
1061  !! faces = v*h*dx, H m2 s-1.
1062  real, intent(in) :: dt !< Time increment in s.
1063  type(continuity_ppm_cs), pointer :: cs !< This module's control structure.
1064  type(loop_bounds_type), intent(in) :: lb !< Loop bounds structure.
1065  type(ocean_obc_type), pointer, optional :: obc !<
1066  !! This open boundary condition type specifies whether, where,
1067  !! and what open boundary conditions are used.
1068  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in), optional :: visc_rem_v !<
1069  !! Both the fraction of the momentum originally in a
1070  !! layer that remains after a time-step of viscosity,
1071  !! and the fraction of a time-step's worth of a
1072  !! barotropic acceleration that a layer experiences
1073  !! after viscosity is applied. Nondimensional between
1074  !! 0 (at the bottom) and 1 (far above the bottom).
1075  real, dimension(SZI_(G),SZJB_(G)), intent(in), optional :: vhbt !<
1076  !! The summed volume flux through meridional faces, H m2 s-1.
1077  real, dimension(SZI_(G),SZJB_(G)), intent(in), optional :: vhbt_aux !<
1078  !! A second set of summed volume fluxes through meridional
1079  !! faces, in H m2 s-1.
1080  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(out), optional :: v_cor !<
1081  !! The meridional velocitiess (v with a barotropic correction)
1082  !! that give vhbt as the depth-integrated transport, m s-1.
1083  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(out), optional :: v_cor_aux !<
1084  !! The meridional velocities (v with a barotropic correction)
1085  !! that give vhbt_aux as the depth-integrated transports, in m s-1.
1086  type(bt_cont_type), pointer, optional :: bt_cont !<
1087  !! A structure with elements that describe the effective
1088  ! Local variables
1089  real, dimension(SZI_(G),SZK_(G)) :: &
1090  dvhdv ! Partial derivative of vh with v, in m2.
1091  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1092  h_l, h_r ! Left and right face thicknesses, in m.
1093  real, dimension(SZI_(G)) :: &
1094  dv, & ! Corrective barotropic change in the velocity, in m s-1.
1095  dv_min_cfl, & ! Min/max limits on dv correction
1096  dv_max_cfl, & ! to avoid CFL violations
1097  dvhdv_tot_0, & ! Summed partial derivative of vh with v, in H m.
1098  vh_tot_0, & ! Summed transport with no barotropic correction in H m2 s-1.
1099  visc_rem_max ! The column maximum of visc_rem.
1100  logical, dimension(SZI_(G)) :: do_i
1101  real, dimension(SZI_(G),SZK_(G)) :: &
1102  visc_rem ! A 2-D copy of visc_rem_v or an array of 1's.
1103  real :: i_vrm ! 1.0 / visc_rem_max, nondim.
1104  real :: cfl_dt ! The maximum CFL ratio of the adjusted velocities divided by
1105  ! the time step, in s-1.
1106  real :: i_dt ! 1.0 / dt, in s-1.
1107  real :: dv_lim ! The velocity change that give a relative CFL of 1, in m s-1.
1108  real :: dy_n, dy_s ! Effective y-grid spacings to the north and south, in m.
1109  integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
1110  logical :: do_aux, local_specified_bc, use_visc_rem, set_bt_cont, any_simple_obc
1111  logical :: local_flather_obc, is_simple, local_open_bc
1112  type(obc_segment_type), pointer :: segment
1113 
1114  do_aux = (present(vhbt_aux) .and. present(v_cor_aux))
1115  use_visc_rem = present(visc_rem_v)
1116  local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
1117  local_open_bc = .false.
1118  if (present(bt_cont)) set_bt_cont = (associated(bt_cont))
1119  if (present(obc)) then ; if (associated(obc)) then ; if (obc%OBC_pe) then
1120  local_specified_bc = obc%specified_v_BCs_exist_globally
1121  local_flather_obc = obc%Flather_u_BCs_exist_globally .or. &
1122  obc%Flather_v_BCs_exist_globally
1123  local_open_bc = obc%open_v_BCs_exist_globally
1124  endif ; endif ; endif
1125  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1126 
1127  cfl_dt = cs%CFL_limit_adjust / dt
1128  i_dt = 1.0 / dt
1129  if (cs%aggress_adjust) cfl_dt = i_dt
1130 
1131  call cpu_clock_begin(id_clock_update)
1132 !$OMP parallel do default(none) shared(nz,ish,ieh,jsh,jeh,h_in,h_L,h_R,G,GV,LB,CS,visc_rem)
1133  do k=1,nz
1134  ! This sets h_L and h_R.
1135  if (cs%upwind_1st) then
1136  do j=jsh-1,jeh+1 ; do i=ish,ieh
1137  h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
1138  enddo ; enddo
1139  else
1140  call ppm_reconstruction_y(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
1141  2.0*gv%Angstrom, cs%monotonic, simple_2nd=cs%simple_2nd)
1142  endif
1143  do i=ish,ieh ; visc_rem(i,k) = 1.0 ; enddo
1144  enddo
1145  if (local_open_bc) then
1146  do n=1, obc%number_of_segments
1147  segment => obc%segment(n)
1148  if (.not. segment%on_pe .or. segment%specified) cycle
1149  if (segment%direction == obc_direction_n) then
1150  j=segment%HI%JsdB
1151  do k=1,nz ; do i=segment%HI%isd,segment%HI%ied
1152  h_in(i,j+1,k) = h_in(i,j,k)
1153  h_l(i,j+1,k) = h_in(i,j,k)
1154  h_r(i,j+1,k) = h_in(i,j,k)
1155  h_r(i,j,k) = h_in(i,j,k)
1156  enddo ; enddo
1157  elseif (segment%direction == obc_direction_s) then
1158  j=segment%HI%JsdB
1159  do k=1,nz ; do i=segment%HI%isd,segment%HI%ied
1160  h_in(i,j,k) = h_in(i,j+1,k)
1161  h_l(i,j,k) = h_in(i,j+1,k)
1162  h_r(i,j,k) = h_in(i,j+1,k)
1163  h_l(i,j+1,k) = h_in(i,j+1,k)
1164  enddo ; enddo
1165  endif
1166  enddo
1167  endif
1168  call cpu_clock_end(id_clock_update)
1169 
1170  call cpu_clock_begin(id_clock_correct)
1171 !$OMP parallel do default(none) shared(ish,ieh,jsh,jeh,nz,v,h_in,h_L,h_R,vh,use_visc_rem, &
1172 !$OMP visc_rem_v,dt,G,GV,CS,local_specified_BC,OBC,vhbt,do_aux, &
1173 !$OMP set_BT_cont,CFL_dt,I_dt,v_cor,vhbt_aux, &
1174 !$OMP v_cor_aux,BT_cont, local_Flather_OBC ) &
1175 !$OMP private(do_I,dvhdv,dv,dv_max_CFL,dv_min_CFL,vh_tot_0, &
1176 !$OMP dvhdv_tot_0,visc_rem_max,I_vrm,dv_lim,dy_N, &
1177 !$OMP is_simple, &
1178 !$OMP dy_S,any_simple_OBC ) &
1179 !$OMP firstprivate(visc_rem)
1180  do j=jsh-1,jeh
1181  do i=ish,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ; enddo
1182  ! This sets vh and dvhdv.
1183  do k=1,nz
1184  if (use_visc_rem) then ; do i=ish,ieh
1185  visc_rem(i,k) = visc_rem_v(i,j,k)
1186  visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
1187  enddo ; endif
1188  call merid_flux_layer(v(:,j,k), h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1189  vh(:,j,k), dvhdv(:,k), visc_rem(:,k), &
1190  dt, g, j, ish, ieh, do_i, cs%vol_CFL)
1191  if (local_specified_bc) then
1192  do i=ish,ieh
1193  if (obc%segment(obc%segnum_v(i,j))%specified) &
1194  vh(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_trans(i,j,k)
1195  enddo
1196  endif
1197  enddo ! k-loop
1198  if ((.not.use_visc_rem) .or. (.not.cs%use_visc_rem_max)) then ; do i=ish,ieh
1199  visc_rem_max(i) = 1.0
1200  enddo ; endif
1201 
1202  if (present(vhbt) .or. do_aux .or. set_bt_cont) then
1203  ! Set limits on dv that will keep the CFL number between -1 and 1.
1204  ! This should be adequate to keep the root bracketed in all cases.
1205  do i=ish,ieh
1206  i_vrm = 0.0
1207  if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
1208  if (cs%vol_CFL) then
1209  dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1210  dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1211  else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ; endif
1212  dv_max_cfl(i) = 2.0 * (cfl_dt * dy_s) * i_vrm
1213  dv_min_cfl(i) = -2.0 * (cfl_dt * dy_n) * i_vrm
1214  vh_tot_0(i) = 0.0 ; dvhdv_tot_0(i) = 0.0
1215  enddo
1216  do k=1,nz ; do i=ish,ieh
1217  dvhdv_tot_0(i) = dvhdv_tot_0(i) + dvhdv(i,k)
1218  vh_tot_0(i) = vh_tot_0(i) + vh(i,j,k)
1219  enddo ; enddo
1220 
1221  if (use_visc_rem) then
1222  if (cs%aggress_adjust) then
1223  do k=1,nz ; do i=ish,ieh
1224  if (cs%vol_CFL) then
1225  dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1226  dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1227  else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ; endif
1228  dv_lim = 0.499*((dy_s*i_dt - v(i,j,k)) + min(0.0,v(i,j-1,k)))
1229  if (dv_max_cfl(i) * visc_rem(i,k) > dv_lim) &
1230  dv_max_cfl(i) = dv_lim / visc_rem(i,k)
1231 
1232  dv_lim = 0.499*((-dy_n*cfl_dt - v(i,j,k)) + max(0.0,v(i,j+1,k)))
1233  if (dv_min_cfl(i) * visc_rem(i,k) < dv_lim) &
1234  dv_min_cfl(i) = dv_lim / visc_rem(i,k)
1235  enddo ; enddo
1236  else
1237  do k=1,nz ; do i=ish,ieh
1238  if (cs%vol_CFL) then
1239  dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1240  dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1241  else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ; endif
1242  if (dv_max_cfl(i) * visc_rem(i,k) > dy_s*cfl_dt - v(i,j,k)) &
1243  dv_max_cfl(i) = (dy_s*cfl_dt - v(i,j,k)) / visc_rem(i,k)
1244  if (dv_min_cfl(i) * visc_rem(i,k) < -dy_n*cfl_dt - v(i,j,k)) &
1245  dv_min_cfl(i) = -(dy_n*cfl_dt + v(i,j,k)) / visc_rem(i,k)
1246  enddo ; enddo
1247  endif
1248  else
1249  if (cs%aggress_adjust) then
1250  do k=1,nz ; do i=ish,ieh
1251  if (cs%vol_CFL) then
1252  dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1253  dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1254  else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ; endif
1255  dv_max_cfl(i) = min(dv_max_cfl(i), 0.499 * &
1256  ((dy_s*i_dt - v(i,j,k)) + min(0.0,v(i,j-1,k))) )
1257  dv_min_cfl(i) = max(dv_min_cfl(i), 0.499 * &
1258  ((-dy_n*i_dt - v(i,j,k)) + max(0.0,v(i,j+1,k))) )
1259  enddo ; enddo
1260  else
1261  do k=1,nz ; do i=ish,ieh
1262  if (cs%vol_CFL) then
1263  dy_s = ratio_max(g%areaT(i,j), g%dx_Cv(i,j), 1000.0*g%dyT(i,j))
1264  dy_n = ratio_max(g%areaT(i,j+1), g%dx_Cv(i,j), 1000.0*g%dyT(i,j+1))
1265  else ; dy_s = g%dyT(i,j) ; dy_n = g%dyT(i,j+1) ; endif
1266  dv_max_cfl(i) = min(dv_max_cfl(i), dy_s*cfl_dt - v(i,j,k))
1267  dv_min_cfl(i) = max(dv_min_cfl(i), -(dy_n*cfl_dt + v(i,j,k)))
1268  enddo ; enddo
1269  endif
1270  endif
1271  do i=ish,ieh
1272  dv_max_cfl(i) = max(dv_max_cfl(i),0.0)
1273  dv_min_cfl(i) = min(dv_min_cfl(i),0.0)
1274  enddo
1275 
1276  ! Up to this point, everything is shared between vhbt and vhbt_aux.
1277 
1278  any_simple_obc = .false.
1279  if (present(vhbt) .or. do_aux .or. set_bt_cont) then
1280  if (local_specified_bc .or. local_flather_obc) then ; do i=ish,ieh
1281  ! Avoid reconciling barotropic/baroclinic transports if transport is specified
1282  is_simple = obc%segment(obc%segnum_v(i,j))%specified
1283  do_i(i) = .not.(obc%segnum_v(i,j) /= obc_none .and. is_simple)
1284  any_simple_obc = any_simple_obc .or. is_simple
1285  enddo ; else ; do i=ish,ieh
1286  do_i(i) = .true.
1287  enddo ; endif
1288  endif
1289 
1290  if (present(vhbt)) then
1291  call meridional_flux_adjust(v, h_in, h_l, h_r, vhbt(:,j), vh_tot_0, &
1292  dvhdv_tot_0, dv, dv_max_cfl, dv_min_cfl, dt, g, &
1293  cs, visc_rem, j, ish, ieh, do_i, .true., vh)
1294 
1295  if (present(v_cor)) then ; do k=1,nz
1296  do i=ish,ieh ; v_cor(i,j,k) = v(i,j,k) + dv(i) * visc_rem(i,k) ; enddo
1297  if (local_specified_bc) then ; do i=ish,ieh
1298  if (obc%segment(obc%segnum_v(i,j))%specified) &
1299  v_cor(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1300  enddo ; endif
1301  enddo ; endif ! v-corrected
1302  endif
1303 
1304  if (do_aux) then
1305  call meridional_flux_adjust(v, h_in, h_l, h_r, vhbt_aux(:,j), vh_tot_0, &
1306  dvhdv_tot_0, dv, dv_max_cfl, dv_min_cfl, dt, g, &
1307  cs, visc_rem, j, ish, ieh, do_i, .false.)
1308 
1309  do k=1,nz
1310  do i=ish,ieh ; v_cor_aux(i,j,k) = v(i,j,k) + dv(i) * visc_rem(i,k) ; enddo
1311  if (local_specified_bc) then ; do i=ish,ieh
1312  if (obc%segment(obc%segnum_v(i,j))%specified) &
1313  v_cor_aux(i,j,k) = obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1314  enddo ; endif
1315  enddo
1316  endif ! do_aux
1317 
1318  if (set_bt_cont) then
1319  call set_merid_bt_cont(v, h_in, h_l, h_r, bt_cont, vh_tot_0, dvhdv_tot_0,&
1320  dv_max_cfl, dv_min_cfl, dt, g, cs, visc_rem, &
1321  visc_rem_max, j, ish, ieh, do_i)
1322  if (any_simple_obc) then
1323  do i=ish,ieh
1324  do_i(i) = (obc%segment(obc%segnum_v(i,j))%specified)
1325  if (do_i(i)) bt_cont%Fa_v_S0(i,j) = gv%H_subroundoff*g%dx_Cv(i,j)
1326  enddo
1327  do k=1,nz ; do i=ish,ieh ; if (do_i(i)) then
1328  if (abs(obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)) > 0.0) &
1329  bt_cont%Fa_v_S0(i,j) = bt_cont%Fa_v_S0(i,j) + &
1330  obc%segment(obc%segnum_v(i,j))%normal_trans(i,j,k) / &
1331  obc%segment(obc%segnum_v(i,j))%normal_vel(i,j,k)
1332  endif ; enddo ; enddo
1333  do i=ish,ieh ; if (do_i(i)) then
1334  bt_cont%Fa_v_N0(i,j) = bt_cont%Fa_v_S0(i,j)
1335  bt_cont%Fa_v_SS(i,j) = bt_cont%Fa_v_S0(i,j)
1336  bt_cont%Fa_v_NN(i,j) = bt_cont%Fa_v_S0(i,j)
1337  endif ; enddo
1338  endif
1339  endif ! set_BT_cont
1340 
1341  endif ! present(vhbt) or do_aux or set_BT_cont
1342  enddo ! j-loop
1343  call cpu_clock_end(id_clock_correct)
1344 
1345  if (set_bt_cont) then ; if (associated(bt_cont%h_v)) then
1346  if (present(v_cor)) then
1347  call merid_face_thickness(v_cor, h_in, h_l, h_r, bt_cont%h_v, dt, g, lb, &
1348  cs%vol_CFL, cs%marginal_faces, visc_rem_v)
1349  else
1350  call merid_face_thickness(v, h_in, h_l, h_r, bt_cont%h_v, dt, g, lb, &
1351  cs%vol_CFL, cs%marginal_faces, visc_rem_v)
1352  endif
1353  endif ; endif
1354 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ppm_limit_cw84()

subroutine mom_continuity_ppm::ppm_limit_cw84 ( real, dimension(szi_(g),szj_(g)), intent(in)  h_in,
real, dimension(szi_(g),szj_(g)), intent(inout)  h_L,
real, dimension(szi_(g),szj_(g)), intent(inout)  h_R,
type(ocean_grid_type), intent(in)  G,
integer, intent(in)  iis,
integer, intent(in)  iie,
integer, intent(in)  jis,
integer, intent(in)  jie 
)
private

This subroutine limits the left/right edge values of the PPM reconstruction according to the monotonic prescription of Colella and Woodward, 1984.

Parameters
[in]gOcean's grid structure.
[in]h_inLayer thickness, in H.
[in,out]h_lLeft thickness in the reconstruction, in H.
[in,out]h_rRight thickness in the reconstruction, in H.
[in]iisStart of i index range.
[in]iieEnd of i index range.
[in]jisStart of j index range.
[in]jieEnd of j index range.

Definition at line 2054 of file MOM_continuity_PPM.F90.

Referenced by ppm_reconstruction_x(), and ppm_reconstruction_y().

2054  type(ocean_grid_type), intent(in) :: g !< Ocean's grid structure.
2055  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness, in H.
2056  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_l !< Left thickness in the
2057  !! reconstruction, in H.
2058  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_r !< Right thickness in the
2059  !! reconstruction, in H.
2060  integer, intent(in) :: iis !< Start of i index range.
2061  integer, intent(in) :: iie !< End of i index range.
2062  integer, intent(in) :: jis !< Start of j index range.
2063  integer, intent(in) :: jie !< End of j index range.
2064 
2065  ! Local variables
2066  real :: h_i, rldiff, rldiff2, rlmean, funfac
2067  character(len=256) :: mesg
2068  integer :: i,j
2069 
2070  do j=jis,jie ; do i=iis,iie
2071  ! This limiter monotonizes the parabola following
2072  ! Colella and Woodward, 1984, Eq. 1.10
2073  h_i = h_in(i,j)
2074  if ( ( h_r(i,j) - h_i ) * ( h_i - h_l(i,j) ) <= 0. ) then
2075  h_l(i,j) = h_i ; h_r(i,j) = h_i
2076  else
2077  rldiff = h_r(i,j) - h_l(i,j) ! Difference of edge values
2078  rlmean = 0.5 * ( h_r(i,j) + h_l(i,j) ) ! Mean of edge values
2079  funfac = 6. * rldiff * ( h_i - rlmean ) ! Some funny factor
2080  rldiff2 = rldiff * rldiff ! Square of difference
2081  if ( funfac > rldiff2 ) h_l(i,j) = 3. * h_i - 2. * h_r(i,j)
2082  if ( funfac < -rldiff2 ) h_r(i,j) = 3. * h_i - 2. * h_l(i,j)
2083  endif
2084  enddo ; enddo
2085 
2086  return
Here is the caller graph for this function:

◆ ppm_limit_pos()

subroutine mom_continuity_ppm::ppm_limit_pos ( real, dimension(szi_(g),szj_(g)), intent(in)  h_in,
real, dimension(szi_(g),szj_(g)), intent(inout)  h_L,
real, dimension(szi_(g),szj_(g)), intent(inout)  h_R,
real, intent(in)  h_min,
type(ocean_grid_type), intent(in)  G,
integer, intent(in)  iis,
integer, intent(in)  iie,
integer, intent(in)  jis,
integer, intent(in)  jie 
)
private

This subroutine limits the left/right edge values of the PPM reconstruction to give a reconstruction that is positive-definite. Here this is reinterpreted as giving a constant thickness if the mean thickness is less than h_min, with a minimum of h_min otherwise.

Parameters
[in]gOcean's grid structure.
[in]h_inLayer thickness, in H.
[in,out]h_lLeft thickness in the reconstruction, in H.
[in,out]h_rRight thickness in the reconstruction, in H.
[in]h_minThe minimum thickness that can be obtained by a concave parabolic fit.
[in]iisStart of i index range.
[in]iieEnd of i index range.
[in]jisStart of j index range.
[in]jieEnd of j index range.

Definition at line 2011 of file MOM_continuity_PPM.F90.

Referenced by ppm_reconstruction_x(), and ppm_reconstruction_y().

2011  type(ocean_grid_type), intent(in) :: g !< Ocean's grid structure.
2012  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness, in H.
2013  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_l !< Left thickness in the
2014  !! reconstruction, in H.
2015  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_r !< Right thickness in the
2016  !! reconstruction, in H.
2017  real, intent(in) :: h_min !< The minimum thickness
2018  !! that can be obtained by a concave parabolic fit.
2019  integer, intent(in) :: iis !< Start of i index range.
2020  integer, intent(in) :: iie !< End of i index range.
2021  integer, intent(in) :: jis !< Start of j index range.
2022  integer, intent(in) :: jie !< End of j index range.
2023 
2024 ! Local variables
2025  real :: curv, dh, scale
2026  character(len=256) :: mesg
2027  integer :: i,j
2028 
2029  do j=jis,jie ; do i=iis,iie
2030  ! This limiter prevents undershooting minima within the domain with
2031  ! values less than h_min.
2032  curv = 3.0*(h_l(i,j) + h_r(i,j) - 2.0*h_in(i,j))
2033  if (curv > 0.0) then ! Only minima are limited.
2034  dh = h_r(i,j) - h_l(i,j)
2035  if (abs(dh) < curv) then ! The parabola's minimum is within the cell.
2036  if (h_in(i,j) <= h_min) then
2037  h_l(i,j) = h_in(i,j) ; h_r(i,j) = h_in(i,j)
2038  elseif (12.0*curv*(h_in(i,j) - h_min) < (curv**2 + 3.0*dh**2)) then
2039  ! The minimum value is h_in - (curv^2 + 3*dh^2)/(12*curv), and must
2040  ! be limited in this case. 0 < scale < 1.
2041  scale = 12.0*curv*(h_in(i,j) - h_min) / (curv**2 + 3.0*dh**2)
2042  h_l(i,j) = h_in(i,j) + scale*(h_l(i,j) - h_in(i,j))
2043  h_r(i,j) = h_in(i,j) + scale*(h_r(i,j) - h_in(i,j))
2044  endif
2045  endif
2046  endif
2047  enddo ; enddo
2048 
Here is the caller graph for this function:

◆ ppm_reconstruction_x()

subroutine mom_continuity_ppm::ppm_reconstruction_x ( real, dimension(szi_(g),szj_(g)), intent(in)  h_in,
real, dimension(szi_(g),szj_(g)), intent(out)  h_L,
real, dimension(szi_(g),szj_(g)), intent(out)  h_R,
type(ocean_grid_type), intent(in)  G,
type(loop_bounds_type), intent(in)  LB,
real, intent(in)  h_min,
logical, intent(in), optional  monotonic,
logical, intent(in), optional  simple_2nd 
)
private

Calculates left/right edge values for PPM reconstruction.

Parameters
[in]gOcean's grid structure.
[in]h_inLayer thickness, in H.
[out]h_lLeft thickness in the reconstruction, in H.
[out]h_rRight thickness in the reconstruction, in H.
[in]lbActive loop bounds structure.
[in]h_minThe minimum thickness that can be obtained by a concave parabolic fit.
[in]monotonicIf true, use the Colella & Woodward monotonic limiter. Otherwise use a simple positive-definite limiter.
[in]simple_2ndIf true, use the arithmetic mean thicknesses as the default edge values for a simple 2nd order scheme.

Definition at line 1828 of file MOM_continuity_PPM.F90.

References ppm_limit_cw84(), and ppm_limit_pos().

Referenced by zonal_mass_flux().

1828  type(ocean_grid_type), intent(in) :: g !< Ocean's grid structure.
1829  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness, in H.
1830  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_l !< Left thickness in the
1831  !! reconstruction, in H.
1832  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_r !< Right thickness in the
1833  !! reconstruction, in H.
1834  type(loop_bounds_type), intent(in) :: lb !< Active loop bounds structure.
1835  real, intent(in) :: h_min !< The minimum thickness
1836  !! that can be obtained by a concave parabolic fit.
1837  logical, optional, intent(in) :: monotonic !< If true, use the
1838  !! Colella & Woodward monotonic limiter.
1839  !! Otherwise use a simple positive-definite limiter.
1840  logical, optional, intent(in) :: simple_2nd !< If true, use the
1841  !! arithmetic mean thicknesses as the default edge values
1842  !! for a simple 2nd order scheme.
1843 
1844  ! Local variables with useful mnemonic names.
1845  real, dimension(SZI_(G),SZJ_(G)) :: slp ! The slopes.
1846  real, parameter :: onesixth = 1./6.
1847  real :: h_ip1, h_im1
1848  real :: dmx, dmn
1849  logical :: use_cw84, use_2nd
1850  character(len=256) :: mesg
1851  integer :: i, j, isl, iel, jsl, jel, stencil
1852 
1853  use_cw84 = .false. ; if (present(monotonic)) use_cw84 = monotonic
1854  use_2nd = .false. ; if (present(simple_2nd)) use_2nd = simple_2nd
1855  isl = lb%ish-1 ; iel = lb%ieh+1 ; jsl = lb%jsh ; jel = lb%jeh
1856 
1857  ! This is the stencil of the reconstruction, not the scheme overall.
1858  stencil = 2 ; if (use_2nd) stencil = 1
1859 
1860  if ((isl-stencil < g%isd) .or. (iel+stencil > g%ied)) then
1861  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", &
1862  & "x-halo that needs to be increased by ",i2,".")') &
1863  stencil + max(g%isd-isl,iel-g%ied)
1864  call mom_error(fatal,mesg)
1865  endif
1866  if ((jsl < g%jsd) .or. (jel > g%jed)) then
1867  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", &
1868  & "y-halo that needs to be increased by ",i2,".")') &
1869  max(g%jsd-jsl,jel-g%jed)
1870  call mom_error(fatal,mesg)
1871  endif
1872 
1873  if (use_2nd) then
1874  do j=jsl,jel ; do i=isl,iel
1875  h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1876  h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1877  h_l(i,j) = 0.5*( h_im1 + h_in(i,j) )
1878  h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) )
1879  enddo ; enddo
1880  else
1881  do j=jsl,jel ; do i=isl-1,iel+1
1882  if ((g%mask2dT(i-1,j) * g%mask2dT(i,j) * g%mask2dT(i+1,j)) == 0.0) then
1883  slp(i,j) = 0.0
1884  else
1885  ! This uses a simple 2nd order slope.
1886  slp(i,j) = 0.5 * (h_in(i+1,j) - h_in(i-1,j))
1887  ! Monotonic constraint, see Eq. B2 in Lin 1994, MWR (132)
1888  dmx = max(h_in(i+1,j), h_in(i-1,j), h_in(i,j)) - h_in(i,j)
1889  dmn = h_in(i,j) - min(h_in(i+1,j), h_in(i-1,j), h_in(i,j))
1890  slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1891  ! * (G%mask2dT(i-1,j) * G%mask2dT(i,j) * G%mask2dT(i+1,j))
1892  endif
1893  enddo; enddo
1894 
1895  do j=jsl,jel ; do i=isl,iel
1896  ! Neighboring values should take into account any boundaries. The 3
1897  ! following sets of expressions are equivalent.
1898  ! h_im1 = h_in(i-1,j,k) ; if (G%mask2dT(i-1,j) < 0.5) h_im1 = h_in(i,j)
1899  ! h_ip1 = h_in(i+1,j,k) ; if (G%mask2dT(i+1,j) < 0.5) h_ip1 = h_in(i,j)
1900  h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1901  h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1902  ! Left/right values following Eq. B2 in Lin 1994, MWR (132)
1903  h_l(i,j) = 0.5*( h_im1 + h_in(i,j) ) + onesixth*( slp(i-1,j) - slp(i,j) )
1904  h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i+1,j) )
1905  enddo; enddo
1906  endif
1907 
1908  if (use_cw84) then
1909  call ppm_limit_cw84(h_in, h_l, h_r, g, isl, iel, jsl, jel)
1910  else
1911  call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
1912  endif
1913 
1914  return
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ppm_reconstruction_y()

subroutine mom_continuity_ppm::ppm_reconstruction_y ( real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h_in,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(out)  h_L,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(out)  h_R,
type(ocean_grid_type), intent(in)  G,
type(loop_bounds_type), intent(in)  LB,
real, intent(in)  h_min,
logical, intent(in), optional  monotonic,
logical, intent(in), optional  simple_2nd 
)
private

Calculates left/right edge values for PPM reconstruction.

Parameters
[in]gOcean's grid structure.
[in]h_inLayer thickness, in H.
[out]h_lLeft thickness in the reconstruction, in H.
[out]h_rRight thickness in the reconstruction, in H.
[in]lbActive loop bounds structure.
[in]h_minThe minimum thickness that can be obtained by a concave parabolic fit.
[in]monotonicIf true, use the Colella & Woodward monotonic limiter. Otherwise use a simple positive-definite limiter.
[in]simple_2ndIf true, use the arithmetic mean thicknesses as the default edge values for a simple 2nd order scheme.

Definition at line 1919 of file MOM_continuity_PPM.F90.

References ppm_limit_cw84(), and ppm_limit_pos().

Referenced by meridional_mass_flux().

1919  type(ocean_grid_type), intent(in) :: g !< Ocean's grid structure.
1920  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness, in H.
1921  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_l !< Left thickness in the
1922  !! reconstruction, in H.
1923  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_r !< Right thickness in the
1924  !! reconstruction, in H.
1925  type(loop_bounds_type), intent(in) :: lb !< Active loop bounds structure.
1926  real, intent(in) :: h_min !< The minimum thickness
1927  !! that can be obtained by a concave parabolic fit.
1928  logical, optional, intent(in) :: monotonic !< If true, use the
1929  !! Colella & Woodward monotonic limiter.
1930  !! Otherwise use a simple positive-definite limiter.
1931  logical, optional, intent(in) :: simple_2nd !< If true, use the
1932  !! arithmetic mean thicknesses as the default edge values
1933  !! for a simple 2nd order scheme.
1934 
1935  ! Local variables with useful mnemonic names.
1936  real, dimension(SZI_(G),SZJ_(G)) :: slp ! The slopes.
1937  real, parameter :: onesixth = 1./6.
1938  real :: h_jp1, h_jm1
1939  real :: dmx, dmn
1940  logical :: use_cw84, use_2nd
1941  character(len=256) :: mesg
1942  integer :: i, j, isl, iel, jsl, jel, stencil
1943 
1944  use_cw84 = .false. ; if (present(monotonic)) use_cw84 = monotonic
1945  use_2nd = .false. ; if (present(simple_2nd)) use_2nd = simple_2nd
1946  isl = lb%ish ; iel = lb%ieh ; jsl = lb%jsh-1 ; jel = lb%jeh+1
1947 
1948  ! This is the stencil of the reconstruction, not the scheme overall.
1949  stencil = 2 ; if (use_2nd) stencil = 1
1950 
1951  if ((isl < g%isd) .or. (iel > g%ied)) then
1952  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", &
1953  & "x-halo that needs to be increased by ",i2,".")') &
1954  max(g%isd-isl,iel-g%ied)
1955  call mom_error(fatal,mesg)
1956  endif
1957  if ((jsl-stencil < g%jsd) .or. (jel+stencil > g%jed)) then
1958  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", &
1959  & "y-halo that needs to be increased by ",i2,".")') &
1960  stencil + max(g%jsd-jsl,jel-g%jed)
1961  call mom_error(fatal,mesg)
1962  endif
1963 
1964  if (use_2nd) then
1965  do j=jsl,jel ; do i=isl,iel
1966  h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
1967  h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
1968  h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) )
1969  h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) )
1970  enddo ; enddo
1971  else
1972  do j=jsl-1,jel+1 ; do i=isl,iel
1973  if ((g%mask2dT(i,j-1) * g%mask2dT(i,j) * g%mask2dT(i,j+1)) == 0.0) then
1974  slp(i,j) = 0.0
1975  else
1976  ! This uses a simple 2nd order slope.
1977  slp(i,j) = 0.5 * (h_in(i,j+1) - h_in(i,j-1))
1978  ! Monotonic constraint, see Eq. B2 in Lin 1994, MWR (132)
1979  dmx = max(h_in(i,j+1), h_in(i,j-1), h_in(i,j)) - h_in(i,j)
1980  dmn = h_in(i,j) - min(h_in(i,j+1), h_in(i,j-1), h_in(i,j))
1981  slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1982  ! * (G%mask2dT(i,j-1) * G%mask2dT(i,j) * G%mask2dT(i,j+1))
1983  endif
1984  enddo ; enddo
1985 
1986  do j=jsl,jel ; do i=isl,iel
1987  ! Neighboring values should take into account any boundaries. The 3
1988  ! following sets of expressions are equivalent.
1989  h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
1990  h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
1991  ! Left/right values following Eq. B2 in Lin 1994, MWR (132)
1992  h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) ) + onesixth*( slp(i,j-1) - slp(i,j) )
1993  h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i,j+1) )
1994  enddo ; enddo
1995  endif
1996 
1997  if (use_cw84) then
1998  call ppm_limit_cw84(h_in, h_l, h_r, g, isl, iel, jsl, jel)
1999  else
2000  call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
2001  endif
2002 
2003  return
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ratio_max()

real function mom_continuity_ppm::ratio_max ( real, intent(in)  a,
real, intent(in)  b,
real, intent(in)  maxrat 
)
private

Return the maximum ratio of a/b or maxrat.

Parameters
[in]aNumerator
[in]bDenominator
[in]maxratMaximum value of ratio.
Returns
Return value.

Definition at line 2091 of file MOM_continuity_PPM.F90.

Referenced by meridional_mass_flux(), and zonal_mass_flux().

2091  real, intent(in) :: a !< Numerator
2092  real, intent(in) :: b !< Denominator
2093  real, intent(in) :: maxrat !< Maximum value of ratio.
2094  real :: ratio !< Return value.
2095 
2096  if (abs(a) > abs(maxrat*b)) then
2097  ratio = maxrat
2098  else
2099  ratio = a / b
2100  endif
Here is the caller graph for this function:

◆ set_merid_bt_cont()

subroutine mom_continuity_ppm::set_merid_bt_cont ( real, dimension(szi_(g),szjb_(g),szk_(g)), intent(in)  v,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_in,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_L,
real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h_R,
type(bt_cont_type), intent(inout)  BT_cont,
real, dimension(szi_(g)), intent(in)  vh_tot_0,
real, dimension(szi_(g)), intent(in)  dvhdv_tot_0,
real, dimension(szi_(g)), intent(in)  dv_max_CFL,
real, dimension(szi_(g)), intent(in)  dv_min_CFL,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(continuity_ppm_cs), pointer  CS,
real, dimension( g %isd: g %ied, g %ke), intent(in)  visc_rem,
real, dimension(szi_(g)), intent(in)  visc_rem_max,
integer, intent(in)  j,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, dimension(szi_(g)), intent(in)  do_I 
)
private

Sets of a structure that describes the meridional barotropic volume or mass fluxes as a function of barotropic flow to agree closely with the sum of the layer's transports.

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity, in m s-1.
[in]h_inLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in,out]bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.
[in]vh_tot_0The summed transport with 0 adjustment, in H m2 s-1.
[in]dvhdv_tot_0The partial derivative of du_err with dv at 0 adjustment, in H m.
[in]dv_max_cflMaximum acceptable value of dv, in m s-1.
[in]dv_min_cflMinimum acceptable value of dv, in m s-1.
[in]dtTime increment in s.
csThis module's control structure.
[in]visc_remBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]visc_rem_maxMaximum allowable visc_rem.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_iA logical flag indicating which I values to work on.

Definition at line 1663 of file MOM_continuity_PPM.F90.

References merid_flux_layer(), and meridional_flux_adjust().

Referenced by meridional_mass_flux().

1663  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
1664  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity, in m s-1.
1665  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_in !< Layer thickness used to
1666  !! calculate fluxes, in H.
1667  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_l !< Left thickness in the
1668  !! reconstruction, in H.
1669  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_r !< Right thickness in the
1670  !! reconstruction, in H.
1671  type(bt_cont_type), intent(inout) :: bt_cont !<
1672  !! A structure with elements that describe the effective
1673  !! open face areas as a function of barotropic flow.
1674  real, dimension(SZI_(G)), intent(in) :: vh_tot_0 !<
1675  !! The summed transport with 0 adjustment, in H m2 s-1.
1676  real, dimension(SZI_(G)), intent(in) :: dvhdv_tot_0 !<
1677  !! The partial derivative of du_err with dv at 0 adjustment, in H m.
1678  real, dimension(SZI_(G)), intent(in) :: dv_max_cfl !< Maximum acceptable value
1679  !! of dv, in m s-1.
1680  real, dimension(SZI_(G)), intent(in) :: dv_min_cfl !< Minimum acceptable value
1681  !! of dv, in m s-1.
1682  real, intent(in) :: dt !< Time increment in s.
1683  type(continuity_ppm_cs), pointer :: cs !< This module's control structure.
1684  real, dimension(SZI_(G),SZK_(G)), intent(in) :: visc_rem !<
1685  !! Both the fraction of the momentum originally in a
1686  !! layer that remains after a time-step of viscosity,
1687  !! and the fraction of a time-step's worth of a
1688  !! barotropic acceleration that a layer experiences
1689  !! after viscosity is applied. Non-dimensional between
1690  !! 0 (at the bottom) and 1 (far above the bottom).
1691  real, dimension(SZI_(G)), intent(in) :: visc_rem_max !< Maximum allowable visc_rem.
1692  integer, intent(in) :: j !< Spatial index.
1693  integer, intent(in) :: ish !< Start of index range.
1694  integer, intent(in) :: ieh !< End of index range.
1695  logical, dimension(SZI_(G)), intent(in) :: do_i !<
1696  !! A logical flag indicating which I values to work on.
1697  ! Local variables
1698  real, dimension(SZI_(G)) :: &
1699  dv0, & ! The barotropic velocity increment that gives 0 transport, m s-1.
1700  dvl, dvr, & ! The barotropic velocity increments that give the southerly
1701  ! (dvL) and northerly (dvR) test velocities.
1702  zeros, & ! An array of full of 0's.
1703  dv_cfl, & ! The velocity increment that corresponds to CFL_min, in m s-1.
1704  v_l, v_r, & ! The southerly (v_L), northerly (v_R), and zero-barotropic
1705  v_0, & ! transport (v_0) layer test velocities, in m s-1.
1706  fa_marg_l, & ! The effective layer marginal face areas with the southerly
1707  fa_marg_r, & ! (_L), northerly (_R), and zero-barotropic (_0) test
1708  fa_marg_0, & ! velocities, in H m.
1709  vh_l, vh_r, & ! The layer transports with the southerly (_L), northerly (_R)
1710  vh_0, & ! and zero-barotropic (_0) test velocities, in H m2 s-1.
1711  famt_l, famt_r, & ! The summed effective marginal face areas for the 3
1712  famt_0, & ! test velocities, in H m.
1713  vhtot_l, & ! The summed transport with the southerly (vhtot_L) and
1714  vhtot_r ! and northerly (vhtot_R) test velocities, in H m2 s-1.
1715  real :: fa_0 ! The effective face area with 0 barotropic transport, in m H.
1716  real :: fa_avg ! The average effective face area, in m H, nominally given by
1717  ! the realized transport divided by the barotropic velocity.
1718  real :: visc_rem_lim ! The larger of visc_rem and min_visc_rem, ND. This
1719  ! limiting is necessary to keep the inverse of visc_rem
1720  ! from leading to large CFL numbers.
1721  real :: min_visc_rem ! The smallest permitted value for visc_rem that is used
1722  ! in finding the barotropic velocity that changes the
1723  ! flow direction. This is necessary to keep the inverse
1724  ! of visc_rem from leading to large CFL numbers.
1725  real :: cfl_min ! A minimal increment in the CFL to try to ensure that the
1726  ! flow is truly upwind, ND.
1727  real :: idt ! The inverse of the time step, in s-1.
1728  logical :: domore
1729  integer :: i, k, nz
1730 
1731  nz = g%ke ; idt = 1.0/dt
1732  min_visc_rem = 0.1 ; cfl_min = 1e-6
1733 
1734  ! Diagnose the zero-transport correction, dv0.
1735  do i=ish,ieh ; zeros(i) = 0.0 ; enddo
1736  call meridional_flux_adjust(v, h_in, h_l, h_r, zeros, vh_tot_0, &
1737  dvhdv_tot_0, dv0, dv_max_cfl, dv_min_cfl, dt, g, &
1738  cs, visc_rem, j, ish, ieh, do_i, .true.)
1739 
1740  ! Determine the southerly- and northerly- fluxes. Choose a sufficiently
1741  ! negative velocity correction for the northerly-flux, and a sufficiently
1742  ! positive correction for the southerly-flux.
1743  domore = .false.
1744  do i=ish,ieh ; if (do_i(i)) then
1745  domore = .true.
1746  dv_cfl(i) = (cfl_min * idt) * g%dyCv(i,j)
1747  dvr(i) = min(0.0,dv0(i) - dv_cfl(i))
1748  dvl(i) = max(0.0,dv0(i) + dv_cfl(i))
1749  famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
1750  vhtot_l(i) = 0.0 ; vhtot_r(i) = 0.0
1751  endif ; enddo
1752 
1753  if (.not.domore) then
1754  do k=1,nz ; do i=ish,ieh
1755  bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1756  bt_cont%vBT_SS(i,j) = 0.0
1757  bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1758  bt_cont%vBT_NN(i,j) = 0.0
1759  enddo ; enddo
1760  return
1761  endif
1762 
1763  do k=1,nz ; do i=ish,ieh ; if (do_i(i)) then
1764  visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
1765  if (visc_rem_lim > 0.0) then ! This is almost always true for ocean points.
1766  if (v(i,j,k) + dvr(i)*visc_rem_lim > -dv_cfl(i)*visc_rem(i,k)) &
1767  dvr(i) = -(v(i,j,k) + dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1768  if (v(i,j,k) + dvl(i)*visc_rem_lim < dv_cfl(i)*visc_rem(i,k)) &
1769  dvl(i) = -(v(i,j,k) - dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1770  endif
1771  endif ; enddo ; enddo
1772  do k=1,nz
1773  do i=ish,ieh ; if (do_i(i)) then
1774  v_l(i) = v(i,j,k) + dvl(i) * visc_rem(i,k)
1775  v_r(i) = v(i,j,k) + dvr(i) * visc_rem(i,k)
1776  v_0(i) = v(i,j,k) + dv0(i) * visc_rem(i,k)
1777  endif ; enddo
1778  call merid_flux_layer(v_0, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_0, &
1779  fa_marg_0, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1780  cs%vol_CFL)
1781  call merid_flux_layer(v_l, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_l, &
1782  fa_marg_l, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1783  cs%vol_CFL)
1784  call merid_flux_layer(v_r, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_r, &
1785  fa_marg_r, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1786  cs%vol_CFL)
1787  do i=ish,ieh ; if (do_i(i)) then
1788  famt_0(i) = famt_0(i) + fa_marg_0(i)
1789  famt_l(i) = famt_l(i) + fa_marg_l(i)
1790  famt_r(i) = famt_r(i) + fa_marg_r(i)
1791  vhtot_l(i) = vhtot_l(i) + vh_l(i)
1792  vhtot_r(i) = vhtot_r(i) + vh_r(i)
1793  endif ; enddo
1794  enddo
1795  do i=ish,ieh ; if (do_i(i)) then
1796  fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1797  if ((dvl(i) - dv0(i)) /= 0.0) &
1798  fa_avg = vhtot_l(i) / (dvl(i) - dv0(i))
1799  if (fa_avg > max(fa_0, famt_l(i))) then ; fa_avg = max(fa_0, famt_l(i))
1800  elseif (fa_avg < min(fa_0, famt_l(i))) then ; fa_0 = fa_avg ; endif
1801  bt_cont%FA_v_S0(i,j) = fa_0 ; bt_cont%FA_v_SS(i,j) = famt_l(i)
1802  if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0) then ; bt_cont%vBT_SS(i,j) = 0.0 ; else
1803  bt_cont%vBT_SS(i,j) = (1.5 * (dvl(i) - dv0(i))) * &
1804  ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1805  endif
1806 
1807  fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1808  if ((dvr(i) - dv0(i)) /= 0.0) &
1809  fa_avg = vhtot_r(i) / (dvr(i) - dv0(i))
1810  if (fa_avg > max(fa_0, famt_r(i))) then ; fa_avg = max(fa_0, famt_r(i))
1811  elseif (fa_avg < min(fa_0, famt_r(i))) then ; fa_0 = fa_avg ; endif
1812  bt_cont%FA_v_N0(i,j) = fa_0 ; bt_cont%FA_v_NN(i,j) = famt_r(i)
1813  if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0) then ; bt_cont%vBT_NN(i,j) = 0.0 ; else
1814  bt_cont%vBT_NN(i,j) = (1.5 * (dvr(i) - dv0(i))) * &
1815  ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1816  endif
1817  else
1818  bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1819  bt_cont%vBT_SS(i,j) = 0.0
1820  bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1821  bt_cont%vBT_NN(i,j) = 0.0
1822  endif ; enddo
1823 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_zonal_bt_cont()

subroutine mom_continuity_ppm::set_zonal_bt_cont ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  u,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_in,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_L,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_R,
type(bt_cont_type), intent(inout)  BT_cont,
real, dimension( g %isdb: g %iedb), intent(in)  uh_tot_0,
real, dimension( g %isdb: g %iedb), intent(in)  duhdu_tot_0,
real, dimension( g %isdb: g %iedb), intent(in)  du_max_CFL,
real, dimension( g %isdb: g %iedb), intent(in)  du_min_CFL,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(continuity_ppm_cs), pointer  CS,
real, dimension(szib_(g),szk_(g)), intent(in)  visc_rem,
real, dimension( g %isdb: g %iedb), intent(in)  visc_rem_max,
integer, intent(in)  j,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, dimension( g %isdb: g %iedb), intent(in)  do_I 
)
private

Sets a structure that describes the zonal barotropic volume or mass fluxes as a function of barotropic flow to agree closely with the sum of the layer's transports.

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity, in m s-1.
[in]h_inLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in,out]bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.
[in]uh_tot_0The summed transport with 0 adjustment, in H m2 s-1.
[in]duhdu_tot_0The partial derivative of du_err with du at 0 adjustment, in H m.
[in]du_max_cflMaximum acceptable value of du, in m s-1.
[in]du_min_cflMinimum acceptable value of du, in m s-1.
[in]dtTime increment in s.
csThis module's control structure.
[in]visc_remBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]visc_rem_maxMaximum allowable visc_rem.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_iA logical flag indicating which I values to work on.

Definition at line 886 of file MOM_continuity_PPM.F90.

References zonal_flux_adjust(), and zonal_flux_layer().

Referenced by zonal_mass_flux().

886  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
887  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Zonal velocity, in m s-1.
888  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_in !< Layer thickness used to
889  !! calculate fluxes, in H.
890  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_l !< Left thickness in the
891  !! reconstruction, in H.
892  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_r !< Right thickness in the
893  !! reconstruction, in H.
894  type(bt_cont_type), intent(inout) :: bt_cont !<
895  !! A structure with elements that describe the effective
896  !! open face areas as a function of barotropic flow.
897  real, dimension(SZIB_(G)), intent(in) :: uh_tot_0 !<
898  !! The summed transport with 0 adjustment, in H m2 s-1.
899  real, dimension(SZIB_(G)), intent(in) :: duhdu_tot_0 !<
900  !! The partial derivative of du_err with du at 0 adjustment, in H m.
901  real, dimension(SZIB_(G)), intent(in) :: du_max_cfl !< Maximum acceptable
902  !! value of du, in m s-1.
903  real, dimension(SZIB_(G)), intent(in) :: du_min_cfl !< Minimum acceptable
904  !! value of du, in m s-1.
905  real, intent(in) :: dt !< Time increment in s.
906  type(continuity_ppm_cs), pointer :: cs !< This module's control structure.
907  real, dimension(SZIB_(G),SZK_(G)), intent(in) :: visc_rem !<
908  !! Both the fraction of the momentum originally in a
909  !! layer that remains after a time-step of viscosity,
910  !! and the fraction of a time-step's worth of a
911  !! barotropic acceleration that a layer experiences
912  !! after viscosity is applied. Non-dimensional between
913  !! 0 (at the bottom) and 1 (far above the bottom).
914  real, dimension(SZIB_(G)), intent(in) :: visc_rem_max !< Maximum allowable visc_rem.
915  integer, intent(in) :: j !< Spatial index.
916  integer, intent(in) :: ish !< Start of index range.
917  integer, intent(in) :: ieh !< End of index range.
918  logical, dimension(SZIB_(G)), intent(in) :: do_i !<
919  !! A logical flag indicating which I values to work on.
920  ! Local variables
921  real, dimension(SZIB_(G)) :: &
922  du0, & ! The barotropic velocity increment that gives 0 transport, m s-1.
923  dul, dur, & ! The barotropic velocity increments that give the westerly
924  ! (duL) and easterly (duR) test velocities.
925  zeros, & ! An array of full of 0's.
926  du_cfl, & ! The velocity increment that corresponds to CFL_min, in m s-1.
927  u_l, u_r, & ! The westerly (u_L), easterly (u_R), and zero-barotropic
928  u_0, & ! transport (u_0) layer test velocities, in m s-1.
929  fa_marg_l, & ! The effective layer marginal face areas with the westerly
930  fa_marg_r, & ! (_L), easterly (_R), and zero-barotropic (_0) test
931  fa_marg_0, & ! velocities, in H m.
932  uh_l, uh_r, & ! The layer transports with the westerly (_L), easterly (_R),
933  uh_0, & ! and zero-barotropic (_0) test velocities, in H m2 s-1.
934  famt_l, famt_r, & ! The summed effective marginal face areas for the 3
935  famt_0, & ! test velocities, in H m.
936  uhtot_l, & ! The summed transport with the westerly (uhtot_L) and
937  uhtot_r ! and easterly (uhtot_R) test velocities, in H m2 s-1.
938  real :: fa_0 ! The effective face area with 0 barotropic transport, in m H.
939  real :: fa_avg ! The average effective face area, in m H, nominally given by
940  ! the realized transport divided by the barotropic velocity.
941  real :: visc_rem_lim ! The larger of visc_rem and min_visc_rem, ND. This
942  ! limiting is necessary to keep the inverse of visc_rem
943  ! from leading to large CFL numbers.
944  real :: min_visc_rem ! The smallest permitted value for visc_rem that is used
945  ! in finding the barotropic velocity that changes the
946  ! flow direction. This is necessary to keep the inverse
947  ! of visc_rem from leading to large CFL numbers.
948  real :: cfl_min ! A minimal increment in the CFL to try to ensure that the
949  ! flow is truly upwind, ND.
950  real :: idt ! The inverse of the time step, in s-1.
951  logical :: domore
952  integer :: i, k, nz
953 
954  nz = g%ke ; idt = 1.0/dt
955  min_visc_rem = 0.1 ; cfl_min = 1e-6
956 
957  ! Diagnose the zero-transport correction, du0.
958  do i=ish-1,ieh ; zeros(i) = 0.0 ; enddo
959  call zonal_flux_adjust(u, h_in, h_l, h_r, zeros, uh_tot_0, &
960  duhdu_tot_0, du0, du_max_cfl, du_min_cfl, dt, g, &
961  cs, visc_rem, j, ish, ieh, do_i, .true.)
962 
963  ! Determine the westerly- and easterly- fluxes. Choose a sufficiently
964  ! negative velocity correction for the easterly-flux, and a sufficiently
965  ! positive correction for the westerly-flux.
966  domore = .false.
967  do i=ish-1,ieh
968  if (do_i(i)) domore = .true.
969  du_cfl(i) = (cfl_min * idt) * g%dxCu(i,j)
970  dur(i) = min(0.0,du0(i) - du_cfl(i))
971  dul(i) = max(0.0,du0(i) + du_cfl(i))
972  famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
973  uhtot_l(i) = 0.0 ; uhtot_r(i) = 0.0
974  enddo
975 
976  if (.not.domore) then
977  do k=1,nz ; do i=ish-1,ieh
978  bt_cont%FA_u_W0(i,j) = 0.0 ; bt_cont%FA_u_WW(i,j) = 0.0
979  bt_cont%uBT_WW(i,j) = 0.0
980  bt_cont%FA_u_E0(i,j) = 0.0 ; bt_cont%FA_u_EE(i,j) = 0.0
981  bt_cont%uBT_EE(i,j) = 0.0
982  enddo ; enddo
983  return
984  endif
985 
986  do k=1,nz ; do i=ish-1,ieh ; if (do_i(i)) then
987  visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
988  if (visc_rem_lim > 0.0) then ! This is almost always true for ocean points.
989  if (u(i,j,k) + dur(i)*visc_rem_lim > -du_cfl(i)*visc_rem(i,k)) &
990  dur(i) = -(u(i,j,k) + du_cfl(i)*visc_rem(i,k)) / visc_rem_lim
991  if (u(i,j,k) + dul(i)*visc_rem_lim < du_cfl(i)*visc_rem(i,k)) &
992  dul(i) = -(u(i,j,k) - du_cfl(i)*visc_rem(i,k)) / visc_rem_lim
993  endif
994  endif ; enddo ; enddo
995 
996  do k=1,nz
997  do i=ish-1,ieh ; if (do_i(i)) then
998  u_l(i) = u(i,j,k) + dul(i) * visc_rem(i,k)
999  u_r(i) = u(i,j,k) + dur(i) * visc_rem(i,k)
1000  u_0(i) = u(i,j,k) + du0(i) * visc_rem(i,k)
1001  endif ; enddo
1002  call zonal_flux_layer(u_0, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_0, &
1003  fa_marg_0, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1004  cs%vol_CFL)
1005  call zonal_flux_layer(u_l, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_l, &
1006  fa_marg_l, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1007  cs%vol_CFL)
1008  call zonal_flux_layer(u_r, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), uh_r, &
1009  fa_marg_r, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1010  cs%vol_CFL)
1011  do i=ish-1,ieh ; if (do_i(i)) then
1012  famt_0(i) = famt_0(i) + fa_marg_0(i)
1013  famt_l(i) = famt_l(i) + fa_marg_l(i)
1014  famt_r(i) = famt_r(i) + fa_marg_r(i)
1015  uhtot_l(i) = uhtot_l(i) + uh_l(i)
1016  uhtot_r(i) = uhtot_r(i) + uh_r(i)
1017  endif ; enddo
1018  enddo
1019  do i=ish-1,ieh ; if (do_i(i)) then
1020  fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1021  if ((dul(i) - du0(i)) /= 0.0) &
1022  fa_avg = uhtot_l(i) / (dul(i) - du0(i))
1023  if (fa_avg > max(fa_0, famt_l(i))) then ; fa_avg = max(fa_0, famt_l(i))
1024  elseif (fa_avg < min(fa_0, famt_l(i))) then ; fa_0 = fa_avg ; endif
1025 
1026  bt_cont%FA_u_W0(i,j) = fa_0 ; bt_cont%FA_u_WW(i,j) = famt_l(i)
1027  if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0) then ; bt_cont%uBT_WW(i,j) = 0.0 ; else
1028  bt_cont%uBT_WW(i,j) = (1.5 * (dul(i) - du0(i))) * &
1029  ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1030  endif
1031 
1032  fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1033  if ((dur(i) - du0(i)) /= 0.0) &
1034  fa_avg = uhtot_r(i) / (dur(i) - du0(i))
1035  if (fa_avg > max(fa_0, famt_r(i))) then ; fa_avg = max(fa_0, famt_r(i))
1036  elseif (fa_avg < min(fa_0, famt_r(i))) then ; fa_0 = fa_avg ; endif
1037 
1038  bt_cont%FA_u_E0(i,j) = fa_0 ; bt_cont%FA_u_EE(i,j) = famt_r(i)
1039  if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0) then ; bt_cont%uBT_EE(i,j) = 0.0 ; else
1040  bt_cont%uBT_EE(i,j) = (1.5 * (dur(i) - du0(i))) * &
1041  ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1042  endif
1043  else
1044  bt_cont%FA_u_W0(i,j) = 0.0 ; bt_cont%FA_u_WW(i,j) = 0.0
1045  bt_cont%uBT_WW(i,j) = 0.0
1046  bt_cont%FA_u_E0(i,j) = 0.0 ; bt_cont%FA_u_EE(i,j) = 0.0
1047  bt_cont%uBT_EE(i,j) = 0.0
1048  endif ; enddo
1049 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ zonal_face_thickness()

subroutine mom_continuity_ppm::zonal_face_thickness ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  u,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_L,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_R,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(inout)  h_u,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(loop_bounds_type), intent(in)  LB,
logical, intent(in)  vol_CFL,
logical, intent(in)  marginal,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in), optional  visc_rem_u 
)
private

Sets the effective interface thickness at each zonal velocity point.

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity, in m s-1.
[in]hLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in,out]h_uThickness at zonal faces, in H.
[in]dtTime increment in s.
[in]lbLoop bounds structure.
[in]vol_cflIf true, rescale the ratio of face areas to the cell areas when estimating the CFL number.
[in]marginalIf true, report the marginal face thicknesses; otherwise report transport-averaged thicknesses.
[in]visc_rem_uBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).

Definition at line 644 of file MOM_continuity_PPM.F90.

Referenced by zonal_mass_flux().

644  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
645  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Zonal velocity, in m s-1.
646  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness used to
647  !! calculate fluxes, in H.
648  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_l !< Left thickness in the
649  !! reconstruction, in H.
650  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_r !< Right thickness in the
651  !! reconstruction, in H.
652  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: h_u !< Thickness at zonal faces,
653  !! in H.
654  real, intent(in) :: dt !< Time increment in s.
655  type(loop_bounds_type), intent(in) :: lb !< Loop bounds structure.
656  logical, intent(in) :: vol_cfl !<
657  !! If true, rescale the ratio of face areas to the cell
658  !! areas when estimating the CFL number.
659  logical, intent(in) :: marginal !<
660  !! If true, report the marginal face thicknesses; otherwise
661  !! report transport-averaged thicknesses.
662  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in), optional :: visc_rem_u !<
663  !! Both the fraction of the momentum originally in a
664  !! layer that remains after a time-step of viscosity,
665  !! and the fraction of a time-step's worth of a
666  !! barotropic acceleration that a layer experiences
667  !! after viscosity is applied. Non-dimensional between
668  !! 0 (at the bottom) and 1 (far above the bottom).
669  ! Local variables
670  real :: cfl ! The CFL number based on the local velocity and grid spacing, ND.
671  real :: curv_3 ! A measure of the thickness curvature over a grid length,
672  ! with the same units as h_in.
673  real :: h_avg ! The average thickness of a flux, in H.
674  real :: h_marg ! The marginal thickness of a flux, in H.
675  integer :: i, j, k, ish, ieh, jsh, jeh, nz
676  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
677 
678 !$OMP parallel default(none) shared(ish,ieh,jsh,jeh,nz,u,vol_CFL,dt,G, &
679 !$OMP h_L,h_R,h,h_u,visc_rem_u,marginal) &
680 !$OMP private(CFL,curv_3,h_marg,h_avg)
681 !$OMP do
682  do k=1,nz ; do j=jsh,jeh ; do i=ish-1,ieh
683  if (u(i,j,k) > 0.0) then
684  if (vol_cfl) then ; cfl = (u(i,j,k) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
685  else ; cfl = u(i,j,k) * dt * g%IdxT(i,j) ; endif
686  curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
687  h_avg = h_r(i,j,k) + cfl * (0.5*(h_l(i,j,k) - h_r(i,j,k)) + curv_3*(cfl - 1.5))
688  h_marg = h_r(i,j,k) + cfl * ((h_l(i,j,k) - h_r(i,j,k)) + 3.0*curv_3*(cfl - 1.0))
689  elseif (u(i,j,k) < 0.0) then
690  if (vol_cfl) then ; cfl = (-u(i,j,k)*dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
691  else ; cfl = -u(i,j,k) * dt * g%IdxT(i+1,j) ; endif
692  curv_3 = h_l(i+1,j,k) + h_r(i+1,j,k) - 2.0*h(i+1,j,k)
693  h_avg = h_l(i+1,j,k) + cfl * (0.5*(h_r(i+1,j,k)-h_l(i+1,j,k)) + curv_3*(cfl - 1.5))
694  h_marg = h_l(i+1,j,k) + cfl * ((h_r(i+1,j,k)-h_l(i+1,j,k)) + &
695  3.0*curv_3*(cfl - 1.0))
696  else
697  h_avg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
698  ! The choice to use the arithmetic mean here is somewhat arbitrariy, but
699  ! it should be noted that h_L(i+1,j,k) and h_R(i,j,k) are usually the same.
700  h_marg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
701  ! h_marg = (2.0 * h_L(i+1,j,k) * h_R(i,j,k)) / &
702  ! (h_L(i+1,j,k) + h_R(i,j,k) + GV%H_subroundoff)
703  endif
704 
705  if (marginal) then ; h_u(i,j,k) = h_marg
706  else ; h_u(i,j,k) = h_avg ; endif
707  enddo; enddo ; enddo
708  if (present(visc_rem_u)) then
709 !$OMP do
710  do k=1,nz ; do j=jsh,jeh ; do i=ish-1,ieh
711  h_u(i,j,k) = h_u(i,j,k) * visc_rem_u(i,j,k)
712  enddo ; enddo ; enddo
713  endif
714 !$OMP end parallel
715 
Here is the caller graph for this function:

◆ zonal_flux_adjust()

subroutine mom_continuity_ppm::zonal_flux_adjust ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  u,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_in,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_L,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(in)  h_R,
real, dimension(szib_(g)), intent(in), optional  uhbt,
real, dimension(szib_(g)), intent(in)  uh_tot_0,
real, dimension(szib_(g)), intent(in)  duhdu_tot_0,
real, dimension(szib_(g)), intent(out)  du,
real, dimension(szib_(g)), intent(in)  du_max_CFL,
real, dimension(szib_(g)), intent(in)  du_min_CFL,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(continuity_ppm_cs), pointer  CS,
real, dimension( g %isdb: g %iedb, g %ke), intent(in)  visc_rem,
integer, intent(in)  j,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, dimension( g %isdb: g %iedb), intent(in)  do_I_in,
logical, intent(in), optional  full_precision,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(inout), optional  uh_3d 
)
private

Returns the barotropic velocity adjustment that gives the desired barotropic (layer-summed) transport.

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity, in m s-1.
[in]h_inLayer thickness used to calculate fluxes, in H.
[in]h_lLeft thickness in the reconstruction, in H.
[in]h_rRight thickness in the reconstruction, in H.
[in]visc_remBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]uhbtThe summed volume flux through zonal faces, H m2 s-1.
[in]du_max_cflMaximum acceptable value of du, in m s-1.
[in]du_min_cflMinimum acceptable value of du, in m s-1.
[in]uh_tot_0The summed transport with 0 adjustment, in H m2 s-1.
[in]duhdu_tot_0The partial derivative of du_err with du at 0 adjustment, in H m.
[out]duThe barotropic velocity adjustment, in m s-1.
[in]dtTime increment in s.
csThis module's control structure.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_i_inA logical flag indicating which I values to work on.
[in]full_precisionA flag indicating how carefully to iterate. The default is .true. (more accurate).
[in,out]uh_3dVolume flux through zonal faces = u*h*dy, H m2 s-1.

Definition at line 723 of file MOM_continuity_PPM.F90.

References zonal_flux_layer().

Referenced by set_zonal_bt_cont(), and zonal_mass_flux().

723  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
724  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Zonal velocity, in m s-1.
725  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_in !< Layer thickness used to
726  !! calculate fluxes, in H.
727  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_l !< Left thickness in the
728  !! reconstruction, in H.
729  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_r !< Right thickness in the
730  !! reconstruction, in H.
731  real, dimension(SZIB_(G),SZK_(G)), intent(in) :: visc_rem !<
732  !! Both the fraction of the momentum originally in a
733  !! layer that remains after a time-step of viscosity,
734  !! and the fraction of a time-step's worth of a
735  !! barotropic acceleration that a layer experiences
736  !! after viscosity is applied. Non-dimensional between
737  !! 0 (at the bottom) and 1 (far above the bottom).
738  real, dimension(SZIB_(G)), intent(in), optional :: uhbt !<
739  !! The summed volume flux through zonal faces, H m2 s-1.
740  real, dimension(SZIB_(G)), intent(in) :: du_max_cfl !< Maximum acceptable
741  !! value of du, in m s-1.
742  real, dimension(SZIB_(G)), intent(in) :: du_min_cfl !< Minimum acceptable
743  !! value of du, in m s-1.
744  real, dimension(SZIB_(G)), intent(in) :: uh_tot_0 !<
745  !! The summed transport with 0 adjustment, in H m2 s-1.
746  real, dimension(SZIB_(G)), intent(in) :: duhdu_tot_0 !<
747  !! The partial derivative of du_err with du at 0 adjustment, in H m.
748  real, dimension(SZIB_(G)), intent(out) :: du !<
749  !! The barotropic velocity adjustment, in m s-1.
750  real, intent(in) :: dt !< Time increment in s.
751  type(continuity_ppm_cs), pointer :: cs !< This module's control structure.
752  integer, intent(in) :: j !< Spatial index.
753  integer, intent(in) :: ish !< Start of index range.
754  integer, intent(in) :: ieh !< End of index range.
755  logical, dimension(SZIB_(G)), intent(in) :: do_i_in !<
756  !! A logical flag indicating which I values to work on.
757  logical, intent(in), optional :: full_precision !<
758  !! A flag indicating how carefully to iterate. The
759  !! default is .true. (more accurate).
760  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout), optional :: uh_3d !<
761  !! Volume flux through zonal faces = u*h*dy, H m2 s-1.
762  ! Local variables
763  real, dimension(SZIB_(G),SZK_(G)) :: &
764  uh_aux, & ! An auxiliary zonal volume flux, in H m s-1.
765  duhdu ! Partial derivative of uh with u, in H m.
766  real, dimension(SZIB_(G)) :: &
767  uh_err, & ! Difference between uhbt and the summed uh, in H m2 s-1.
768  uh_err_best, & ! The smallest value of uh_err found so far, in H m2 s-1.
769  u_new, & ! The velocity with the correction added, in m s-1.
770  duhdu_tot,&! Summed partial derivative of uh with u, in H m.
771  du_min, & ! Min/max limits on du correction based on CFL limits
772  du_max ! and previous iterations, in m s-1.
773  real :: du_prev ! The previous value of du, in m s-1.
774  real :: ddu ! The change in du from the previous iteration, in m s-1.
775  real :: tol_eta ! The tolerance for the current iteration, in m.
776  real :: tol_vel ! The tolerance for velocity in the current iteration, m s-1.
777  integer :: i, k, nz, itt, max_itts = 20
778  logical :: full_prec, domore, do_i(szib_(g))
779 
780  nz = g%ke
781  full_prec = .true. ; if (present(full_precision)) full_prec = full_precision
782 
783  uh_aux(:,:) = 0.0 ; duhdu(:,:) = 0.0
784 
785  if (present(uh_3d)) then ; do k=1,nz ; do i=ish-1,ieh
786  uh_aux(i,k) = uh_3d(i,j,k)
787  enddo ; enddo ; endif
788 
789  do i=ish-1,ieh
790  du(i) = 0.0 ; do_i(i) = do_i_in(i)
791  du_max(i) = du_max_cfl(i) ; du_min(i) = du_min_cfl(i)
792  uh_err(i) = uh_tot_0(i) - uhbt(i) ; duhdu_tot(i) = duhdu_tot_0(i)
793  uh_err_best(i) = abs(uh_err(i))
794  enddo
795 
796  do itt=1,max_itts
797  if (full_prec) then
798  select case (itt)
799  case (:1) ; tol_eta = 1e-6 * cs%tol_eta
800  case (2) ; tol_eta = 1e-4 * cs%tol_eta
801  case (3) ; tol_eta = 1e-2 * cs%tol_eta
802  case default ; tol_eta = cs%tol_eta
803  end select
804  else
805  tol_eta = cs%tol_eta_aux ; if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
806  endif
807  tol_vel = cs%tol_vel
808 
809  do i=ish-1,ieh
810  if (uh_err(i) > 0.0) then ; du_max(i) = du(i)
811  elseif (uh_err(i) < 0.0) then ; du_min(i) = du(i)
812  else ; do_i(i) = .false. ; endif
813  enddo
814  domore = .false.
815  do i=ish-1,ieh ; if (do_i(i)) then
816  if ((dt*min(g%IareaT(i,j),g%IareaT(i+1,j))*abs(uh_err(i)) > tol_eta) .or.&
817  (cs%better_iter .and. ((abs(uh_err(i)) > tol_vel * duhdu_tot(i)) .or.&
818  (abs(uh_err(i)) > uh_err_best(i))) )) then
819  ! Use Newton's method, provided it stays bounded. Otherwise bisect
820  ! the value with the appropriate bound.
821  if (full_prec) then
822  ddu = -uh_err(i) / duhdu_tot(i)
823  du_prev = du(i)
824  du(i) = du(i) + ddu
825  if (abs(ddu) < 1.0e-15*abs(du(i))) then
826  do_i(i) = .false. ! ddu is small enough to quit.
827  elseif (ddu > 0.0) then
828  if (du(i) >= du_max(i)) then
829  du(i) = 0.5*(du_prev + du_max(i))
830  if (du_max(i) - du_prev < 1.0e-15*abs(du(i))) do_i(i) = .false.
831  endif
832  else ! ddu < 0.0
833  if (du(i) <= du_min(i)) then
834  du(i) = 0.5*(du_prev + du_min(i))
835  if (du_prev - du_min(i) < 1.0e-15*abs(du(i))) do_i(i) = .false.
836  endif
837  endif
838  else
839  ! Use Newton's method, provided it stays bounded, just like above.
840  du(i) = du(i) - uh_err(i) / duhdu_tot(i)
841  if ((du(i) >= du_max(i)) .or. (du(i) <= du_min(i))) &
842  du(i) = 0.5*(du_max(i) + du_min(i))
843  endif
844  if (do_i(i)) domore = .true.
845  else
846  do_i(i) = .false.
847  endif
848  endif ; enddo
849  if (.not.domore) exit
850 
851  if ((itt < max_itts) .or. present(uh_3d)) then ; do k=1,nz
852  do i=ish-1,ieh ; u_new(i) = u(i,j,k) + du(i) * visc_rem(i,k) ; enddo
853  call zonal_flux_layer(u_new, h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
854  uh_aux(:,k), duhdu(:,k), visc_rem(:,k), &
855  dt, g, j, ish, ieh, do_i, cs%vol_CFL)
856  enddo ; endif
857 
858  if (itt < max_itts) then
859  do i=ish-1,ieh
860  uh_err(i) = -uhbt(i) ; duhdu_tot(i) = 0.0
861  enddo
862  do k=1,nz ; do i=ish-1,ieh
863  uh_err(i) = uh_err(i) + uh_aux(i,k)
864  duhdu_tot(i) = duhdu_tot(i) + duhdu(i,k)
865  enddo ; enddo
866  do i=ish-1,ieh
867  uh_err_best(i) = min(uh_err_best(i), abs(uh_err(i)))
868  enddo
869  endif
870  enddo ! itt-loop
871  ! If there are any faces which have not converged to within the tolerance,
872  ! so-be-it, or else use a final upwind correction?
873  ! This never seems to happen with 20 iterations as max_itt.
874 
875  if (present(uh_3d)) then ; do k=1,nz ; do i=ish-1,ieh
876  uh_3d(i,j,k) = uh_aux(i,k)
877  enddo ; enddo ; endif
878 
Here is the call graph for this function:
Here is the caller graph for this function:

◆ zonal_flux_layer()

subroutine mom_continuity_ppm::zonal_flux_layer ( real, dimension( g %isdb: g %iedb), intent(in)  u,
real, dimension(szi_(g)), intent(in)  h,
real, dimension(szi_(g)), intent(in)  h_L,
real, dimension(szi_(g)), intent(in)  h_R,
real, dimension(szib_(g)), intent(inout)  uh,
real, dimension(szib_(g)), intent(inout)  duhdu,
real, dimension( g %isdb: g %iedb), intent(in)  visc_rem,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
integer, intent(in)  j,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, dimension(szib_(g)), intent(in)  do_I,
logical, intent(in)  vol_CFL 
)
private

Evaluates the zonal mass or volume fluxes in a layer.

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity, in m s-1.
[in]visc_remBoth the fraction of the momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]hLayer thickness, in H.
[in]h_lLeft thickness, in H.
[in]h_rRight thickness, in H.
[in,out]uhZonal mass or volume transport, in H m2 s-1.
[in,out]duhduPartial derivative of uh with u, in H m.
[in]dtTime increment in s.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_iWhich i values to work on.
[in]vol_cflIf true, rescale the ratio of face areas to the cell areas when estimating the CFL number.

Definition at line 588 of file MOM_continuity_PPM.F90.

Referenced by set_zonal_bt_cont(), zonal_flux_adjust(), and zonal_mass_flux().

588  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
589  real, dimension(SZIB_(G)), intent(in) :: u !< Zonal velocity, in m s-1.
590  real, dimension(SZIB_(G)), intent(in) :: visc_rem !< Both the fraction of the
591  !! momentum originally in a layer that remains after a time-step
592  !! of viscosity, and the fraction of a time-step's worth of a barotropic
593  !! acceleration that a layer experiences after viscosity is applied.
594  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
595  real, dimension(SZI_(G)), intent(in) :: h !< Layer thickness, in H.
596  real, dimension(SZI_(G)), intent(in) :: h_l !< Left thickness, in H.
597  real, dimension(SZI_(G)), intent(in) :: h_r !< Right thickness, in H.
598  real, dimension(SZIB_(G)), intent(inout) :: uh !< Zonal mass or volume
599  !! transport, in H m2 s-1.
600  real, dimension(SZIB_(G)), intent(inout) :: duhdu !< Partial derivative of uh
601  !! with u, in H m.
602  real, intent(in) :: dt !< Time increment in s.
603  integer, intent(in) :: j !< Spatial index.
604  integer, intent(in) :: ish !< Start of index range.
605  integer, intent(in) :: ieh !< End of index range.
606  logical, dimension(SZIB_(G)), intent(in) :: do_i !< Which i values to work on.
607  logical, intent(in) :: vol_cfl !< If true, rescale the
608  !! ratio of face areas to the cell areas when estimating the CFL number.
609  ! Local variables
610  real :: cfl ! The CFL number based on the local velocity and grid spacing, ND.
611  real :: curv_3 ! A measure of the thickness curvature over a grid length,
612  ! with the same units as h_in.
613  real :: h_marg ! The marginal thickness of a flux, in H.
614  integer :: i
615 
616  do i=ish-1,ieh ; if (do_i(i)) then
617  ! Set new values of uh and duhdu.
618  if (u(i) > 0.0) then
619  if (vol_cfl) then ; cfl = (u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
620  else ; cfl = u(i) * dt * g%IdxT(i,j) ; endif
621  curv_3 = h_l(i) + h_r(i) - 2.0*h(i)
622  uh(i) = g%dy_Cu(i,j) * u(i) * &
623  (h_r(i) + cfl * (0.5*(h_l(i) - h_r(i)) + curv_3*(cfl - 1.5)))
624  h_marg = h_r(i) + cfl * ((h_l(i) - h_r(i)) + 3.0*curv_3*(cfl - 1.0))
625  elseif (u(i) < 0.0) then
626  if (vol_cfl) then ; cfl = (-u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
627  else ; cfl = -u(i) * dt * g%IdxT(i+1,j) ; endif
628  curv_3 = h_l(i+1) + h_r(i+1) - 2.0*h(i+1)
629  uh(i) = g%dy_Cu(i,j) * u(i) * &
630  (h_l(i+1) + cfl * (0.5*(h_r(i+1)-h_l(i+1)) + curv_3*(cfl - 1.5)))
631  h_marg = h_l(i+1) + cfl * ((h_r(i+1)-h_l(i+1)) + 3.0*curv_3*(cfl - 1.0))
632  else
633  uh(i) = 0.0
634  h_marg = 0.5 * (h_l(i+1) + h_r(i))
635  endif
636  duhdu(i) = g%dy_Cu(i,j) * h_marg * visc_rem(i)
637  endif ; enddo
638 
Here is the caller graph for this function:

◆ zonal_mass_flux()

subroutine mom_continuity_ppm::zonal_mass_flux ( real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(in)  u,
real, dimension( g %isd: g %ied, g %jsd: g %jed, g %ke), intent(inout)  h_in,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(out)  uh,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(continuity_ppm_cs), pointer  CS,
type(loop_bounds_type), intent(in)  LB,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed), intent(in), optional  uhbt,
type(ocean_obc_type), optional, pointer  OBC,
real, dimension(szib_(g),szj_(g),szk_(g)), intent(in), optional  visc_rem_u,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(out), optional  u_cor,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed), intent(in), optional  uhbt_aux,
real, dimension( g %isdb: g %iedb, g %jsd: g %jed, g %ke), intent(out), optional  u_cor_aux,
type(bt_cont_type), optional, pointer  BT_cont 
)
private

Calculates the mass or volume fluxes through the zonal faces, and other related quantities.

Parameters
[in,out]gOcean's grid structure.
[in]gvOcean's vertical grid structure.
[in]uZonal velocity, in m s-1.
[in,out]h_inLayer thickness used to calculate fluxes, in H.
[out]uhVolume flux through zonal faces = u*h*dy, H m2 s-1.
[in]dtTime increment in s.
csThis module's control structure.
[in]lbLoop bounds structure.
obcOpen boundaries control structure.
[in]visc_rem_uThe fraction of zonal momentum originally in a layer that remains after a time-step of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that a layer experiences after viscosity is applied. Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
[in]uhbtThe summed volume flux through zonal faces, H m2 s-1.
[in]uhbt_auxA second set of summed volume fluxes through zonal faces, in H m2 s-1.
[out]u_corThe zonal velocitiess (u with a barotropic correction) that give uhbt as the depth-integrated transport, m s-1.
[out]u_cor_auxThe zonal velocities (u with a barotropic correction) that give uhbt_aux as the depth-integrated transports, in m s-1.
bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.

Definition at line 286 of file MOM_continuity_PPM.F90.

References id_clock_correct, id_clock_update, mom_open_boundary::obc_direction_e, mom_open_boundary::obc_direction_w, ppm_reconstruction_x(), ratio_max(), set_zonal_bt_cont(), zonal_face_thickness(), zonal_flux_adjust(), and zonal_flux_layer().

Referenced by continuity_ppm().

286  type(ocean_grid_type), intent(inout) :: g !< Ocean's grid structure.
287  type(verticalgrid_type), intent(in) :: gv !< Ocean's vertical grid structure.
288  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Zonal velocity, in m s-1.
289  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h_in !< Layer thickness used to
290  !! calculate fluxes, in H.
291  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(out) :: uh !< Volume flux through zonal
292  !! faces = u*h*dy, H m2 s-1.
293  real, intent(in) :: dt !< Time increment in s.
294  type(continuity_ppm_cs), pointer :: cs !< This module's control structure.
295  type(loop_bounds_type), intent(in) :: lb !< Loop bounds structure.
296  type(ocean_obc_type), pointer, optional :: obc !< Open boundaries control structure.
297  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in), optional :: visc_rem_u !<
298  !< The fraction of zonal momentum originally in a layer that remains after a time-step
299  !! of viscosity, and the fraction of a time-step's worth of a barotropic acceleration that
300  !! a layer experiences after viscosity is applied.
301  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
302  real, dimension(SZIB_(G),SZJ_(G)), intent(in), optional :: uhbt
303  !< The summed volume flux through zonal faces, H m2 s-1.
304  real, dimension(SZIB_(G),SZJ_(G)), intent(in), optional :: uhbt_aux
305  !< A second set of summed volume fluxes through zonal faces, in H m2 s-1.
306  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(out), optional :: u_cor
307  !< The zonal velocitiess (u with a barotropic correction)
308  !! that give uhbt as the depth-integrated transport, m s-1.
309  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(out), optional :: u_cor_aux
310  !< The zonal velocities (u with a barotropic correction)
311  !! that give uhbt_aux as the depth-integrated transports, in m s-1.
312  type(bt_cont_type), pointer, optional :: bt_cont !<
313  !< A structure with elements that describe the effective
314  !! open face areas as a function of barotropic flow.
315  ! Local variables
316  real, dimension(SZIB_(G),SZK_(G)) :: duhdu ! Partial derivative of uh with u, in H m.
317  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_l, h_r ! Left and right face thicknesses, in H.
318  real, dimension(SZIB_(G)) :: &
319  du, & ! Corrective barotropic change in the velocity, in m s-1.
320  du_min_cfl, & ! Min/max limits on du correction
321  du_max_cfl, & ! to avoid CFL violations
322  duhdu_tot_0, & ! Summed partial derivative of uh with u, in H m.
323  uh_tot_0, & ! Summed transport with no barotropic correction in H m2 s-1.
324  visc_rem_max ! The column maximum of visc_rem.
325  logical, dimension(SZIB_(G)) :: do_i
326  real, dimension(SZIB_(G),SZK_(G)) :: &
327  visc_rem ! A 2-D copy of visc_rem_u or an array of 1's.
328  real :: i_vrm ! 1.0 / visc_rem_max, nondim.
329  real :: cfl_dt ! The maximum CFL ratio of the adjusted velocities divided by
330  ! the time step, in s-1.
331  real :: i_dt ! 1.0 / dt, in s-1.
332  real :: du_lim ! The velocity change that give a relative CFL of 1, in m s-1.
333  real :: dx_e, dx_w ! Effective x-grid spacings to the east and west, in m.
334  integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
335  logical :: do_aux, local_specified_bc, use_visc_rem, set_bt_cont, any_simple_obc
336  logical :: local_flather_obc, local_open_bc, is_simple
337  type(obc_segment_type), pointer :: segment
338 
339  do_aux = (present(uhbt_aux) .and. present(u_cor_aux))
340  use_visc_rem = present(visc_rem_u)
341  local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
342  local_open_bc = .false.
343  if (present(bt_cont)) set_bt_cont = (associated(bt_cont))
344  if (present(obc)) then ; if (associated(obc)) then
345  local_specified_bc = obc%specified_u_BCs_exist_globally
346  local_flather_obc = obc%Flather_u_BCs_exist_globally .or. &
347  obc%Flather_v_BCs_exist_globally
348  local_open_bc = obc%open_u_BCs_exist_globally
349  endif ; endif
350  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
351 
352  cfl_dt = cs%CFL_limit_adjust / dt
353  i_dt = 1.0 / dt
354  if (cs%aggress_adjust) cfl_dt = i_dt
355 
356  call cpu_clock_begin(id_clock_update)
357 !$OMP parallel do default(none) shared(ish,ieh,jsh,jeh,nz,CS,h_L,h_in,h_R,G,GV,LB,visc_rem)
358  do k=1,nz
359  ! This sets h_L and h_R.
360  if (cs%upwind_1st) then
361  do j=jsh,jeh ; do i=ish-1,ieh+1
362  h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
363  enddo ; enddo
364  else
365  call ppm_reconstruction_x(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
366  2.0*gv%Angstrom, cs%monotonic, simple_2nd=cs%simple_2nd)
367  endif
368  do i=ish-1,ieh ; visc_rem(i,k) = 1.0 ; enddo
369  enddo
370  if (local_open_bc) then
371  do n=1, obc%number_of_segments
372  segment => obc%segment(n)
373  if (.not. segment%on_pe .or. segment%specified) cycle
374  if (segment%direction == obc_direction_e) then
375  i=segment%HI%IsdB
376  do k=1,nz ; do j=segment%HI%jsd,segment%HI%jed
377  h_in(i+1,j,k) = h_in(i,j,k)
378  h_l(i+1,j,k) = h_in(i,j,k)
379  h_r(i+1,j,k) = h_in(i,j,k)
380  h_r(i,j,k) = h_in(i,j,k)
381  enddo ; enddo
382  elseif (segment%direction == obc_direction_w) then
383  i=segment%HI%IsdB
384  do k=1,nz ; do j=segment%HI%jsd,segment%HI%jed
385  h_in(i,j,k) = h_in(i+1,j,k)
386  h_l(i,j,k) = h_in(i+1,j,k)
387  h_r(i,j,k) = h_in(i+1,j,k)
388  h_l(i+1,j,k) = h_in(i+1,j,k)
389  enddo ; enddo
390  endif
391  enddo
392  endif
393  call cpu_clock_end(id_clock_update)
394 
395  call cpu_clock_begin(id_clock_correct)
396 !$OMP parallel do default(none) shared(ish,ieh,jsh,jeh,nz,u,h_in,h_L,h_R,use_visc_rem,visc_rem_u, &
397 !$OMP uh,dt,G,GV,CS,local_specified_BC,OBC,uhbt,do_aux,set_BT_cont, &
398 !$OMP CFL_dt,I_dt,u_cor,uhbt_aux,u_cor_aux,BT_cont, local_Flather_OBC) &
399 !$OMP private(do_I,duhdu,du,du_max_CFL,du_min_CFL,uh_tot_0,duhdu_tot_0, &
400 !$OMP is_simple, &
401 !$OMP visc_rem_max, I_vrm, du_lim, dx_E, dx_W, any_simple_OBC ) &
402 !$OMP firstprivate(visc_rem)
403  do j=jsh,jeh
404  do i=ish-1,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ; enddo
405  ! Set uh and duhdu.
406  do k=1,nz
407  if (use_visc_rem) then ; do i=ish-1,ieh
408  visc_rem(i,k) = visc_rem_u(i,j,k)
409  visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
410  enddo ; endif
411  call zonal_flux_layer(u(:,j,k), h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
412  uh(:,j,k), duhdu(:,k), visc_rem(:,k), &
413  dt, g, j, ish, ieh, do_i, cs%vol_CFL)
414  if (local_specified_bc) then
415  do i=ish-1,ieh
416  if (obc%segment(obc%segnum_u(i,j))%specified) &
417  uh(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k)
418  enddo
419  endif
420  enddo
421 
422  if ((.not.use_visc_rem).or.(.not.cs%use_visc_rem_max)) then ; do i=ish-1,ieh
423  visc_rem_max(i) = 1.0
424  enddo ; endif
425 
426  if (present(uhbt) .or. do_aux .or. set_bt_cont) then
427  ! Set limits on du that will keep the CFL number between -1 and 1.
428  ! This should be adequate to keep the root bracketed in all cases.
429  do i=ish-1,ieh
430  i_vrm = 0.0
431  if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
432  if (cs%vol_CFL) then
433  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
434  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
435  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
436  du_max_cfl(i) = 2.0* (cfl_dt * dx_w) * i_vrm
437  du_min_cfl(i) = -2.0 * (cfl_dt * dx_e) * i_vrm
438  uh_tot_0(i) = 0.0 ; duhdu_tot_0(i) = 0.0
439  enddo
440  do k=1,nz ; do i=ish-1,ieh
441  duhdu_tot_0(i) = duhdu_tot_0(i) + duhdu(i,k)
442  uh_tot_0(i) = uh_tot_0(i) + uh(i,j,k)
443  enddo ; enddo
444  if (use_visc_rem) then
445  if (cs%aggress_adjust) then
446  do k=1,nz ; do i=ish-1,ieh
447  if (cs%vol_CFL) then
448  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
449  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
450  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
451 
452  du_lim = 0.499*((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k)))
453  if (du_max_cfl(i) * visc_rem(i,k) > du_lim) &
454  du_max_cfl(i) = du_lim / visc_rem(i,k)
455 
456  du_lim = 0.499*((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k)))
457  if (du_min_cfl(i) * visc_rem(i,k) < du_lim) &
458  du_min_cfl(i) = du_lim / visc_rem(i,k)
459  enddo ; enddo
460  else
461  do k=1,nz ; do i=ish-1,ieh
462  if (cs%vol_CFL) then
463  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
464  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
465  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
466 
467  if (du_max_cfl(i) * visc_rem(i,k) > dx_w*cfl_dt - u(i,j,k)) &
468  du_max_cfl(i) = (dx_w*cfl_dt - u(i,j,k)) / visc_rem(i,k)
469  if (du_min_cfl(i) * visc_rem(i,k) < -dx_e*cfl_dt - u(i,j,k)) &
470  du_min_cfl(i) = -(dx_e*cfl_dt + u(i,j,k)) / visc_rem(i,k)
471  enddo ; enddo
472  endif
473  else
474  if (cs%aggress_adjust) then
475  do k=1,nz ; do i=ish-1,ieh
476  if (cs%vol_CFL) then
477  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
478  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
479  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
480 
481  du_max_cfl(i) = min(du_max_cfl(i), 0.499 * &
482  ((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k))) )
483  du_min_cfl(i) = max(du_min_cfl(i), 0.499 * &
484  ((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k))) )
485  enddo ; enddo
486  else
487  do k=1,nz ; do i=ish-1,ieh
488  if (cs%vol_CFL) then
489  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
490  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
491  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
492 
493  du_max_cfl(i) = min(du_max_cfl(i), dx_w*cfl_dt - u(i,j,k))
494  du_min_cfl(i) = max(du_min_cfl(i), -(dx_e*cfl_dt + u(i,j,k)))
495  enddo ; enddo
496  endif
497  endif
498  do i=ish-1,ieh
499  du_max_cfl(i) = max(du_max_cfl(i),0.0)
500  du_min_cfl(i) = min(du_min_cfl(i),0.0)
501  enddo
502 
503  ! Up to this point, everything is shared between uhbt and uhbt_aux.
504 
505  any_simple_obc = .false.
506  if (present(uhbt) .or. do_aux .or. set_bt_cont) then
507  if (local_specified_bc .or. local_flather_obc) then ; do i=ish-1,ieh
508  ! Avoid reconciling barotropic/baroclinic transports if transport is specified
509  is_simple = obc%segment(obc%segnum_u(i,j))%specified
510  do_i(i) = .not.(obc%segnum_u(i,j) /= obc_none .and. is_simple)
511  any_simple_obc = any_simple_obc .or. is_simple
512  enddo ; else ; do i=ish-1,ieh
513  do_i(i) = .true.
514  enddo ; endif
515  endif
516 
517  if (present(uhbt)) then
518  call zonal_flux_adjust(u, h_in, h_l, h_r, uhbt(:,j), uh_tot_0, &
519  duhdu_tot_0, du, du_max_cfl, du_min_cfl, dt, g, &
520  cs, visc_rem, j, ish, ieh, do_i, .true., uh)
521 
522  if (present(u_cor)) then ; do k=1,nz
523  do i=ish-1,ieh ; u_cor(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ; enddo
524  if (local_specified_bc) then ; do i=ish-1,ieh
525  if (obc%segment(obc%segnum_u(i,j))%specified) &
526  u_cor(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
527  enddo ; endif
528  enddo ; endif ! u-corrected
529 
530  endif
531 
532  if (do_aux) then
533  call zonal_flux_adjust(u, h_in, h_l, h_r, uhbt_aux(:,j), uh_tot_0, &
534  duhdu_tot_0, du, du_max_cfl, du_min_cfl, dt, g, &
535  cs, visc_rem, j, ish, ieh, do_i, .false.)
536 
537  do k=1,nz
538  do i=ish-1,ieh ; u_cor_aux(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ; enddo
539  if (local_specified_bc) then ; do i=ish-1,ieh
540  if (obc%segment(obc%segnum_u(i,j))%specified) &
541  u_cor_aux(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
542  enddo ; endif
543  enddo
544  endif ! do_aux
545 
546  if (set_bt_cont) then
547  call set_zonal_bt_cont(u, h_in, h_l, h_r, bt_cont, uh_tot_0, duhdu_tot_0,&
548  du_max_cfl, du_min_cfl, dt, g, cs, visc_rem, &
549  visc_rem_max, j, ish, ieh, do_i)
550  if (any_simple_obc) then
551  do i=ish-1,ieh
552  do_i(i) = obc%segment(obc%segnum_u(i,j))%specified
553  if (do_i(i)) bt_cont%Fa_u_W0(i,j) = gv%H_subroundoff*g%dy_Cu(i,j)
554  enddo
555  do k=1,nz ; do i=ish-1,ieh ; if (do_i(i)) then
556  if (abs(obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)) > 0.0) &
557  bt_cont%Fa_u_W0(i,j) = bt_cont%Fa_u_W0(i,j) + &
558  obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k) / &
559  obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
560  endif ; enddo ; enddo
561  do i=ish-1,ieh ; if (do_i(i)) then
562  bt_cont%Fa_u_E0(i,j) = bt_cont%Fa_u_W0(i,j)
563  bt_cont%Fa_u_WW(i,j) = bt_cont%Fa_u_W0(i,j)
564  bt_cont%Fa_u_EE(i,j) = bt_cont%Fa_u_W0(i,j)
565  endif ; enddo
566  endif
567  endif ! set_BT_cont
568 
569  endif ! present(uhbt) or do_aux or set_BT_cont
570  enddo ! j-loop
571  call cpu_clock_end(id_clock_correct)
572 
573  if (set_bt_cont) then ; if (associated(bt_cont%h_u)) then
574  if (present(u_cor)) then
575  call zonal_face_thickness(u_cor, h_in, h_l, h_r, bt_cont%h_u, dt, g, lb, &
576  cs%vol_CFL, cs%marginal_faces, visc_rem_u)
577  else
578  call zonal_face_thickness(u, h_in, h_l, h_r, bt_cont%h_u, dt, g, lb, &
579  cs%vol_CFL, cs%marginal_faces, visc_rem_u)
580  endif
581  endif ; endif
582 
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ id_clock_correct

integer mom_continuity_ppm::id_clock_correct
private

◆ id_clock_update

integer mom_continuity_ppm::id_clock_update
private

Definition at line 22 of file MOM_continuity_PPM.F90.

Referenced by continuity_ppm(), continuity_ppm_init(), meridional_mass_flux(), and zonal_mass_flux().

22 integer :: id_clock_update, id_clock_correct