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...
 
integer id_clock_update
 CPU time clock IDs.
 
integer id_clock_correct
 CPU time clock IDs.
 
subroutine, public continuity_ppm (u, v, hin, h, uh, vh, dt, G, GV, US, 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, US, 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, OBC)
 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, OBC)
 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, OBC)
 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, US, 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, US, 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, OBC)
 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, OBC)
 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, OBC)
 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, US, 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, OBC)
 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, OBC)
 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...
 

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(in)  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(unit_scale_type), intent(in)  US,
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 [m s-1].
[in]vMeridional velocity [m s-1].
[in]hinInitial layer thickness [H ~> m or kg m-2].
[in,out]hFinal layer thickness [H ~> m or kg m-2].
[out]uhZonal volume flux, u*h*dy [H m2 s-1 ~> m3 s-1 or kg s-1].
[out]vhMeridional volume flux, v*h*dx [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]dtTime increment [s].
[in]gvVertical grid structure.
[in]usA dimensional unit scaling type
[in]uhbtThe summed volume flux through zonal faces
[in]vhbtThe summed volume flux through meridional faces
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 [m s-1].
[out]v_corThe meridional velocities that give vhbt as the depth-integrated transport [m s-1].
[in]uhbt_auxA second set of summed volume fluxes through zonal faces [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]vhbt_auxA second set of summed volume fluxes through meridional faces [H m2 s-1 ~> m3 s-1 or kg s-1].
[out]u_cor_auxThe zonal velocities that give uhbt_aux as the depth-integrated transports [m s-1].
[out]v_cor_auxThe meridional velocities that give vhbt_aux as the depth-integrated transports [m s-1].
bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.

Definition at line 79 of file MOM_continuity_PPM.F90.

79  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
80  type(continuity_PPM_CS), pointer :: CS !< Module's control structure.
81  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
82  intent(in) :: u !< Zonal velocity [m s-1].
83  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
84  intent(in) :: v !< Meridional velocity [m s-1].
85  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
86  intent(in) :: hin !< Initial layer thickness [H ~> m or kg m-2].
87  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
88  intent(inout) :: h !< Final layer thickness [H ~> m or kg m-2].
89  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
90  intent(out) :: uh !< Zonal volume flux, u*h*dy [H m2 s-1 ~> m3 s-1 or kg s-1].
91  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
92  intent(out) :: vh !< Meridional volume flux, v*h*dx [H m2 s-1 ~> m3 s-1 or kg s-1].
93  real, intent(in) :: dt !< Time increment [s].
94  type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure.
95  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
96  real, dimension(SZIB_(G),SZJ_(G)), &
97  optional, intent(in) :: uhbt !< The summed volume flux through zonal faces
98  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
99  real, dimension(SZI_(G),SZJB_(G)), &
100  optional, intent(in) :: vhbt !< The summed volume flux through meridional faces
101  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
102  type(ocean_OBC_type), &
103  optional, pointer :: OBC !< Open boundaries control structure.
104  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
105  optional, intent(in) :: visc_rem_u
106  !< The fraction of zonal momentum originally
107  !! in a layer that remains after a time-step of viscosity, and the
108  !! fraction of a time-step's worth of a barotropic acceleration that
109  !! a layer experiences after viscosity is applied.
110  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
111  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
112  optional, intent(in) :: visc_rem_v
113  !< The fraction of meridional momentum originally
114  !! in a layer that remains after a time-step of viscosity, and the
115  !! fraction of a time-step's worth of a barotropic acceleration that
116  !! a layer experiences after viscosity is applied.
117  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
118  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
119  optional, intent(out) :: u_cor
120  !< The zonal velocities that give uhbt as the depth-integrated transport [m s-1].
121  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
122  optional, intent(out) :: v_cor
123  !< The meridional velocities that give vhbt as the depth-integrated transport [m s-1].
124  real, dimension(SZIB_(G),SZJ_(G)), &
125  optional, intent(in) :: uhbt_aux
126  !< A second set of summed volume fluxes through zonal faces
127  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
128  real, dimension(SZI_(G),SZJB_(G)), &
129  optional, intent(in) :: vhbt_aux
130  !< A second set of summed volume fluxes through meridional faces
131  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
132  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
133  optional, intent(out) :: u_cor_aux
134  !< The zonal velocities that give uhbt_aux as the depth-integrated
135  !! transports [m s-1].
136  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
137  optional, intent(out) :: v_cor_aux
138  !< The meridional velocities that give vhbt_aux as the depth-integrated
139  !! transports [m s-1].
140  type(BT_cont_type), optional, pointer :: BT_cont !< A structure with elements that describe
141  !! the effective open face areas as a function of barotropic flow.
142 
143  ! Local variables
144  real :: h_min ! The minimum layer thickness [H ~> m or kg m-2]. h_min could be 0.
145  type(loop_bounds_type) :: LB
146  integer :: is, ie, js, je, nz, stencil
147  integer :: i, j, k
148 
149  logical :: x_first
150  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
151 
152  h_min = gv%Angstrom_H
153 
154  if (.not.associated(cs)) call mom_error(fatal, &
155  "MOM_continuity_PPM: Module must be initialized before it is used.")
156  x_first = (mod(g%first_direction,2) == 0)
157 
158  if (present(visc_rem_u) .neqv. present(visc_rem_v)) call mom_error(fatal, &
159  "MOM_continuity_PPM: Either both visc_rem_u and visc_rem_v or neither"// &
160  " one must be present in call to continuity_PPM.")
161 
162  stencil = 3 ; if (cs%simple_2nd) stencil = 2 ; if (cs%upwind_1st) stencil = 1
163 
164  if (x_first) then
165  ! First, advect zonally.
166  lb%ish = g%isc ; lb%ieh = g%iec
167  lb%jsh = g%jsc-stencil ; lb%jeh = g%jec+stencil
168  call zonal_mass_flux(u, hin, uh, dt, g, gv, us, cs, lb, uhbt, obc, visc_rem_u, &
169  u_cor, uhbt_aux, u_cor_aux, bt_cont)
170 
171  call cpu_clock_begin(id_clock_update)
172  !$OMP parallel do default(shared)
173  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
174  h(i,j,k) = hin(i,j,k) - dt* g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
175  ! Uncomment this line to prevent underflow.
176  ! if (h(i,j,k) < h_min) h(i,j,k) = h_min
177  enddo ; enddo ; enddo
178  call cpu_clock_end(id_clock_update)
179 
180  lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
181 
182  ! Now advect meridionally, using the updated thicknesses to determine
183  ! the fluxes.
184  call meridional_mass_flux(v, h, vh, dt, g, gv, us, cs, lb, vhbt, obc, visc_rem_v, &
185  v_cor, vhbt_aux, v_cor_aux, bt_cont)
186 
187  call cpu_clock_begin(id_clock_update)
188  !$OMP parallel do default(shared)
189  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
190  h(i,j,k) = h(i,j,k) - dt*g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
191  ! This line prevents underflow.
192  if (h(i,j,k) < h_min) h(i,j,k) = h_min
193  enddo ; enddo ; enddo
194  call cpu_clock_end(id_clock_update)
195 
196  else ! .not. x_first
197  ! First, advect meridionally, so set the loop bounds accordingly.
198  lb%ish = g%isc-stencil ; lb%ieh = g%iec+stencil
199  lb%jsh = g%jsc ; lb%jeh = g%jec
200 
201  call meridional_mass_flux(v, hin, vh, dt, g, gv, us, cs, lb, vhbt, obc, visc_rem_v, &
202  v_cor, vhbt_aux, v_cor_aux, bt_cont)
203 
204  call cpu_clock_begin(id_clock_update)
205  !$OMP parallel do default(shared)
206  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
207  h(i,j,k) = hin(i,j,k) - dt*g%IareaT(i,j) * (vh(i,j,k) - vh(i,j-1,k))
208  enddo ; enddo ; enddo
209  call cpu_clock_end(id_clock_update)
210 
211  ! Now advect zonally, using the updated thicknesses to determine
212  ! the fluxes.
213  lb%ish = g%isc ; lb%ieh = g%iec ; lb%jsh = g%jsc ; lb%jeh = g%jec
214  call zonal_mass_flux(u, h, uh, dt, g, gv, us, cs, lb, uhbt, obc, visc_rem_u, &
215  u_cor, uhbt_aux, u_cor_aux, bt_cont)
216 
217  call cpu_clock_begin(id_clock_update)
218  !$OMP parallel do default(shared)
219  do k=1,nz ; do j=lb%jsh,lb%jeh ; do i=lb%ish,lb%ieh
220  h(i,j,k) = h(i,j,k) - dt* g%IareaT(i,j) * (uh(i,j,k) - uh(i-1,j,k))
221  ! This line prevents underflow.
222  if (h(i,j,k) < h_min) h(i,j,k) = h_min
223  enddo ; enddo ; enddo
224  call cpu_clock_end(id_clock_update)
225 
226  endif
227 

◆ 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 2347 of file MOM_continuity_PPM.F90.

2347  type(continuity_PPM_CS), pointer :: CS !< Module's control structure.
2348  deallocate(cs)

◆ 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 [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 2245 of file MOM_continuity_PPM.F90.

2245  type(time_type), target, intent(in) :: Time !< Time increment [s].
2246  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2247  type(verticalGrid_type), intent(in) :: GV !< Vertical grid structure.
2248  type(param_file_type), intent(in) :: param_file !< A structure indicating
2249  !! the open file to parse for model parameter values.
2250  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to
2251  !! regulate diagnostic output.
2252  type(continuity_PPM_CS), pointer :: CS !< Module's control structure.
2253 !> This include declares and sets the variable "version".
2254 #include "version_variable.h"
2255  real :: tol_eta_m ! An unscaled version of tol_eta [m].
2256  character(len=40) :: mdl = "MOM_continuity_PPM" ! This module's name.
2257 
2258  if (associated(cs)) then
2259  call mom_error(warning, "continuity_PPM_init called with associated control structure.")
2260  return
2261  endif
2262  allocate(cs)
2263 
2264 ! Read all relevant parameters and write them to the model log.
2265  call log_version(param_file, mdl, version, "")
2266  call get_param(param_file, mdl, "MONOTONIC_CONTINUITY", cs%monotonic, &
2267  "If true, CONTINUITY_PPM uses the Colella and Woodward "//&
2268  "monotonic limiter. The default (false) is to use a "//&
2269  "simple positive definite limiter.", default=.false.)
2270  call get_param(param_file, mdl, "SIMPLE_2ND_PPM_CONTINUITY", cs%simple_2nd, &
2271  "If true, CONTINUITY_PPM uses a simple 2nd order "//&
2272  "(arithmetic mean) interpolation of the edge values. "//&
2273  "This may give better PV conservation properties. While "//&
2274  "it formally reduces the accuracy of the continuity "//&
2275  "solver itself in the strongly advective limit, it does "//&
2276  "not reduce the overall order of accuracy of the dynamic "//&
2277  "core.", default=.false.)
2278  call get_param(param_file, mdl, "UPWIND_1ST_CONTINUITY", cs%upwind_1st, &
2279  "If true, CONTINUITY_PPM becomes a 1st-order upwind "//&
2280  "continuity solver. This scheme is highly diffusive "//&
2281  "but may be useful for debugging or in single-column "//&
2282  "mode where its minimal stencil is useful.", default=.false.)
2283  call get_param(param_file, mdl, "ETA_TOLERANCE", cs%tol_eta, &
2284  "The tolerance for the differences between the "//&
2285  "barotropic and baroclinic estimates of the sea surface "//&
2286  "height due to the fluxes through each face. The total "//&
2287  "tolerance for SSH is 4 times this value. The default "//&
2288  "is 0.5*NK*ANGSTROM, and this should not be set less "//&
2289  "than about 10^-15*MAXIMUM_DEPTH.", units="m", scale=gv%m_to_H, &
2290  default=0.5*g%ke*gv%Angstrom_m, unscaled=tol_eta_m)
2291 
2292  call get_param(param_file, mdl, "ETA_TOLERANCE_AUX", cs%tol_eta_aux, &
2293  "The tolerance for free-surface height discrepancies "//&
2294  "between the barotropic solution and the sum of the "//&
2295  "layer thicknesses when calculating the auxiliary "//&
2296  "corrected velocities. By default, this is the same as "//&
2297  "ETA_TOLERANCE, but can be made larger for efficiency.", &
2298  units="m", default=tol_eta_m, scale=gv%m_to_H)
2299  call get_param(param_file, mdl, "VELOCITY_TOLERANCE", cs%tol_vel, &
2300  "The tolerance for barotropic velocity discrepancies "//&
2301  "between the barotropic solution and the sum of the "//&
2302  "layer thicknesses.", units="m s-1", default=3.0e8) ! The speed of light is the default.
2303 
2304  call get_param(param_file, mdl, "CONT_PPM_AGGRESS_ADJUST", cs%aggress_adjust,&
2305  "If true, allow the adjusted velocities to have a "//&
2306  "relative CFL change up to 0.5.", default=.false.)
2307  cs%vol_CFL = cs%aggress_adjust
2308  call get_param(param_file, mdl, "CONT_PPM_VOLUME_BASED_CFL", cs%vol_CFL, &
2309  "If true, use the ratio of the open face lengths to the "//&
2310  "tracer cell areas when estimating CFL numbers. The "//&
2311  "default is set by CONT_PPM_AGGRESS_ADJUST.", &
2312  default=cs%aggress_adjust, do_not_read=cs%aggress_adjust)
2313  call get_param(param_file, mdl, "CONTINUITY_CFL_LIMIT", cs%CFL_limit_adjust, &
2314  "The maximum CFL of the adjusted velocities.", units="nondim", &
2315  default=0.5)
2316  call get_param(param_file, mdl, "CONT_PPM_BETTER_ITER", cs%better_iter, &
2317  "If true, stop corrective iterations using a velocity "//&
2318  "based criterion and only stop if the iteration is "//&
2319  "better than all predecessors.", default=.true.)
2320  call get_param(param_file, mdl, "CONT_PPM_USE_VISC_REM_MAX", &
2321  cs%use_visc_rem_max, &
2322  "If true, use more appropriate limiting bounds for "//&
2323  "corrections in strongly viscous columns.", default=.true.)
2324  call get_param(param_file, mdl, "CONT_PPM_MARGINAL_FACE_AREAS", cs%marginal_faces, &
2325  "If true, use the marginal face areas from the continuity "//&
2326  "solver for use as the weights in the barotropic solver. "//&
2327  "Otherwise use the transport averaged areas.", default=.true.)
2328 
2329  cs%diag => diag
2330 
2331  id_clock_update = cpu_clock_id('(Ocean continuity update)', grain=clock_routine)
2332  id_clock_correct = cpu_clock_id('(Ocean continuity correction)', grain=clock_routine)
2333 

◆ 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 2338 of file MOM_continuity_PPM.F90.

2338  type(continuity_PPM_CS), pointer :: CS !< Module's control structure.
2339  integer :: stencil !< The continuity solver stencil size with the current settings.
2340 
2341  stencil = 3 ; if (cs%simple_2nd) stencil = 2 ; if (cs%upwind_1st) stencil = 1
2342 

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

Sets the effective interface thickness at each meridional velocity point.

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity [m s-1].
[in]hLayer thickness used to calculate fluxes, [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction, [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction, [H ~> m or kg m-2].
[in,out]h_vThickness at meridional faces, [H ~> m or kg m-2].
[in]dtTime increment [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).
obcOpen boundaries control structure.

Definition at line 1444 of file MOM_continuity_PPM.F90.

1444  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
1445  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity [m s-1].
1446  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness used to calculate fluxes,
1447  !! [H ~> m or kg m-2].
1448  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_L !< Left thickness in the reconstruction,
1449  !! [H ~> m or kg m-2].
1450  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_R !< Right thickness in the reconstruction,
1451  !! [H ~> m or kg m-2].
1452  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: h_v !< Thickness at meridional faces,
1453  !! [H ~> m or kg m-2].
1454  real, intent(in) :: dt !< Time increment [s].
1455  type(loop_bounds_type), intent(in) :: LB !< Loop bounds structure.
1456  logical, intent(in) :: vol_CFL !< If true, rescale the ratio
1457  !! of face areas to the cell areas when estimating the CFL number.
1458  logical, intent(in) :: marginal !< If true, report the marginal
1459  !! face thicknesses; otherwise report transport-averaged thicknesses.
1460  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), optional, intent(in) :: visc_rem_v !< Both the fraction
1461  !! of the momentum originally in a layer that remains after a time-step of
1462  !! viscosity, and the fraction of a time-step's worth of a barotropic
1463  !! acceleration that a layer experiences after viscosity is applied.
1464  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
1465  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
1466 
1467  ! Local variables
1468  real :: CFL ! The CFL number based on the local velocity and grid spacing [nondim]
1469  real :: curv_3 ! A measure of the thickness curvature over a grid length,
1470  ! with the same units as h_in.
1471  real :: h_avg ! The average thickness of a flux [H ~> m or kg m-2].
1472  real :: h_marg ! The marginal thickness of a flux [H ~> m or kg m-2].
1473  logical :: local_open_BC
1474  integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
1475  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
1476 
1477  !$OMP parallel do default(shared) private(CFL,curv_3,h_marg,h_avg)
1478  do k=1,nz ; do j=jsh-1,jeh ; do i=ish,ieh
1479  if (v(i,j,k) > 0.0) then
1480  if (vol_cfl) then ; cfl = (v(i,j,k) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1481  else ; cfl = v(i,j,k) * dt * g%IdyT(i,j) ; endif
1482  curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
1483  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))
1484  h_marg = h_r(i,j,k) + cfl * ((h_l(i,j,k) - h_r(i,j,k)) + &
1485  3.0*curv_3*(cfl - 1.0))
1486  elseif (v(i,j,k) < 0.0) then
1487  if (vol_cfl) then ; cfl = (-v(i,j,k)*dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1488  else ; cfl = -v(i,j,k) * dt * g%IdyT(i,j+1) ; endif
1489  curv_3 = h_l(i,j+1,k) + h_r(i,j+1,k) - 2.0*h(i,j+1,k)
1490  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))
1491  h_marg = h_l(i,j+1,k) + cfl * ((h_r(i,j+1,k)-h_l(i,j+1,k)) + &
1492  3.0*curv_3*(cfl - 1.0))
1493  else
1494  h_avg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1495  ! The choice to use the arithmetic mean here is somewhat arbitrariy, but
1496  ! it should be noted that h_L(i+1,j,k) and h_R(i,j,k) are usually the same.
1497  h_marg = 0.5 * (h_l(i,j+1,k) + h_r(i,j,k))
1498  ! h_marg = (2.0 * h_L(i,j+1,k) * h_R(i,j,k)) / &
1499  ! (h_L(i,j+1,k) + h_R(i,j,k) + GV%H_subroundoff)
1500  endif
1501 
1502  if (marginal) then ; h_v(i,j,k) = h_marg
1503  else ; h_v(i,j,k) = h_avg ; endif
1504  enddo ; enddo ; enddo
1505 
1506  if (present(visc_rem_v)) then
1507  !$OMP parallel do default(shared)
1508  do k=1,nz ; do j=jsh-1,jeh ; do i=ish,ieh
1509  h_v(i,j,k) = h_v(i,j,k) * visc_rem_v(i,j,k)
1510  enddo ; enddo ; enddo
1511  endif
1512 
1513  local_open_bc = .false.
1514  if (present(obc)) then ; if (associated(obc)) then
1515  local_open_bc = obc%open_u_BCs_exist_globally
1516  endif ; endif
1517  if (local_open_bc) then
1518  do n = 1, obc%number_of_segments
1519  if (obc%segment(n)%open .and. obc%segment(n)%is_N_or_S) then
1520  j = obc%segment(n)%HI%JsdB
1521  if (obc%segment(n)%direction == obc_direction_n) then
1522  if (present(visc_rem_v)) then ; do k=1,nz
1523  do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1524  h_v(i,j,k) = h(i,j,k) * visc_rem_v(i,j,k)
1525  enddo
1526  enddo ; else ; do k=1,nz
1527  do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1528  h_v(i,j,k) = h(i,j,k)
1529  enddo
1530  enddo ; endif
1531  else
1532  if (present(visc_rem_v)) then ; do k=1,nz
1533  do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1534  h_v(i,j,k) = h(i,j+1,k) * visc_rem_v(i,j,k)
1535  enddo
1536  enddo ; else ; do k=1,nz
1537  do i = obc%segment(n)%HI%isd, obc%segment(n)%HI%ied
1538  h_v(i,j,k) = h(i,j+1,k)
1539  enddo
1540  enddo ; endif
1541  endif
1542  endif
1543  enddo
1544  endif
1545 

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

Evaluates the meridional mass or volume fluxes in a layer.

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity [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, [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction [H ~> m or kg m-2].
[in,out]vhMeridional mass or volume transport [H m2 s-1 ~> m3 s-1 or kg s-1].
[in,out]dvhdvPartial derivative of vh with v [H m ~> m2 or kg m-1].
[in]dtTime increment [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.
obcOpen boundaries control structure.

Definition at line 1364 of file MOM_continuity_PPM.F90.

1364  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
1365  real, dimension(SZI_(G)), intent(in) :: v !< Meridional velocity [m s-1].
1366  real, dimension(SZI_(G)), intent(in) :: visc_rem !< Both the fraction of the
1367  !! momentum originally in a layer that remains after a time-step
1368  !! of viscosity, and the fraction of a time-step's worth of a barotropic
1369  !! acceleration that a layer experiences after viscosity is applied.
1370  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
1371  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h !< Layer thickness used to calculate fluxes,
1372  !! [H ~> m or kg m-2].
1373  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_L !< Left thickness in the reconstruction
1374  !! [H ~> m or kg m-2].
1375  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_R !< Right thickness in the reconstruction
1376  !! [H ~> m or kg m-2].
1377  real, dimension(SZI_(G)), intent(inout) :: vh !< Meridional mass or volume transport
1378  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
1379  real, dimension(SZI_(G)), intent(inout) :: dvhdv !< Partial derivative of vh with v
1380  !! [H m ~> m2 or kg m-1].
1381  real, intent(in) :: dt !< Time increment [s].
1382  integer, intent(in) :: j !< Spatial index.
1383  integer, intent(in) :: ish !< Start of index range.
1384  integer, intent(in) :: ieh !< End of index range.
1385  logical, dimension(SZI_(G)), intent(in) :: do_I !< Which i values to work on.
1386  logical, intent(in) :: vol_CFL !< If true, rescale the
1387  !! ratio of face areas to the cell areas when estimating the CFL number.
1388  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
1389  ! Local variables
1390  real :: CFL ! The CFL number based on the local velocity and grid spacing [nondim]
1391  real :: curv_3 ! A measure of the thickness curvature over a grid length,
1392  ! with the same units as h, i.e. [H ~> m or kg m-2].
1393  real :: h_marg ! The marginal thickness of a flux [H ~> m or kg m-2].
1394  integer :: i
1395  logical :: local_open_BC
1396 
1397  local_open_bc = .false.
1398  if (present(obc)) then ; if (associated(obc)) then
1399  local_open_bc = obc%open_u_BCs_exist_globally
1400  endif ; endif
1401 
1402  do i=ish,ieh ; if (do_i(i)) then
1403  if (v(i) > 0.0) then
1404  if (vol_cfl) then ; cfl = (v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1405  else ; cfl = v(i) * dt * g%IdyT(i,j) ; endif
1406  curv_3 = h_l(i,j) + h_r(i,j) - 2.0*h(i,j)
1407  vh(i) = g%dx_Cv(i,j) * v(i) * ( h_r(i,j) + cfl * &
1408  (0.5*(h_l(i,j) - h_r(i,j)) + curv_3*(cfl - 1.5)) )
1409  h_marg = h_r(i,j) + cfl * ((h_l(i,j) - h_r(i,j)) + &
1410  3.0*curv_3*(cfl - 1.0))
1411  elseif (v(i) < 0.0) then
1412  if (vol_cfl) then ; cfl = (-v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1413  else ; cfl = -v(i) * dt * g%IdyT(i,j+1) ; endif
1414  curv_3 = h_l(i,j+1) + h_r(i,j+1) - 2.0*h(i,j+1)
1415  vh(i) = g%dx_Cv(i,j) * v(i) * ( h_l(i,j+1) + cfl * &
1416  (0.5*(h_r(i,j+1)-h_l(i,j+1)) + curv_3*(cfl - 1.5)) )
1417  h_marg = h_l(i,j+1) + cfl * ((h_r(i,j+1)-h_l(i,j+1)) + &
1418  3.0*curv_3*(cfl - 1.0))
1419  else
1420  vh(i) = 0.0
1421  h_marg = 0.5 * (h_l(i,j+1) + h_r(i,j))
1422  endif
1423  dvhdv(i) = g%dx_Cv(i,j) * h_marg * visc_rem(i)
1424  endif ; enddo
1425 
1426  if (local_open_bc) then
1427  do i=ish,ieh ; if (do_i(i)) then
1428  if (obc%segment(obc%segnum_v(i,j))%open) then
1429  if (obc%segment(obc%segnum_v(i,j))%direction == obc_direction_n) then
1430  vh(i) = g%dx_Cv(i,j) * v(i) * h(i,j)
1431  dvhdv(i) = g%dx_Cv(i,j) * h(i,j) * visc_rem(i)
1432  else
1433  vh(i) = g%dx_Cv(i,j) * v(i) * h(i,j+1)
1434  dvhdv(i) = g%dx_Cv(i,j) * h(i,j+1) * visc_rem(i)
1435  endif
1436  endif
1437  endif ; enddo
1438  endif

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

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

Parameters
[in,out]gOcean's grid structure.
[in]vMeridional velocity [m s-1].
[in]h_inLayer thickness used to calculate fluxes [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction [H ~> m or kg m-2].
[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
[in]dv_max_cflMaximum acceptable value of dv [m s-1].
[in]dv_min_cflMinimum acceptable value of dv [m s-1].
[in]vh_tot_0The summed transport with 0 adjustment [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]dvhdv_tot_0The partial derivative of dv_err with dv at 0 adjustment [H m ~> m2 or kg m-1].
[out]dvThe barotropic velocity adjustment [m s-1].
[in]dtTime increment [s].
csThis module's control structure.
[in]jSpatial index.
[in]ishStart of index range.
[in]iehEnd of index range.
[in]do_i_inA 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]vh_3dVolume flux through meridional
obcOpen boundaries control structure.

Definition at line 1552 of file MOM_continuity_PPM.F90.

1552  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
1553  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1554  intent(in) :: v !< Meridional velocity [m s-1].
1555  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1556  intent(in) :: h_in !< Layer thickness used to calculate fluxes [H ~> m or kg m-2].
1557  real, dimension(SZI_(G),SZJ_(G),SZK_(G)),&
1558  intent(in) :: h_L !< Left thickness in the reconstruction [H ~> m or kg m-2].
1559  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
1560  intent(in) :: h_R !< Right thickness in the reconstruction [H ~> m or kg m-2].
1561  real, dimension(SZI_(G),SZK_(G)), intent(in) :: visc_rem
1562  !< Both the fraction of the momentum originally
1563  !! in a layer that remains after a time-step of viscosity, and the
1564  !! fraction of a time-step's worth of a barotropic acceleration that
1565  !! a layer experiences after viscosity is applied. Non-dimensional
1566  !! between 0 (at the bottom) and 1 (far above the bottom).
1567  real, dimension(SZI_(G)), &
1568  optional, intent(in) :: vhbt !< The summed volume flux through meridional faces
1569  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
1570  real, dimension(SZI_(G)), intent(in) :: dv_max_CFL !< Maximum acceptable value of dv [m s-1].
1571  real, dimension(SZI_(G)), intent(in) :: dv_min_CFL !< Minimum acceptable value of dv [m s-1].
1572  real, dimension(SZI_(G)), intent(in) :: vh_tot_0 !< The summed transport with 0 adjustment
1573  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
1574  real, dimension(SZI_(G)), intent(in) :: dvhdv_tot_0 !< The partial derivative of dv_err with
1575  !! dv at 0 adjustment [H m ~> m2 or kg m-1].
1576  real, dimension(SZI_(G)), intent(out) :: dv !< The barotropic velocity adjustment [m s-1].
1577  real, intent(in) :: dt !< Time increment [s].
1578  type(continuity_PPM_CS), pointer :: CS !< This module's control structure.
1579  integer, intent(in) :: j !< Spatial index.
1580  integer, intent(in) :: ish !< Start of index range.
1581  integer, intent(in) :: ieh !< End of index range.
1582  logical, dimension(SZI_(G)), &
1583  intent(in) :: do_I_in !< A flag indicating which I values to work on.
1584  logical, optional, intent(in) :: full_precision !< A flag indicating how carefully to
1585  !! iterate. The default is .true. (more accurate).
1586  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
1587  optional, intent(inout) :: vh_3d !< Volume flux through meridional
1588  !! faces = v*h*dx [H m2 s-1 ~> m3 s-1 or kg s-1].
1589  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
1590  ! Local variables
1591  real, dimension(SZI_(G),SZK_(G)) :: &
1592  vh_aux, & ! An auxiliary meridional volume flux [H m s-1 ~> m2 s-1 or kg m-1 s-1].
1593  dvhdv ! Partial derivative of vh with v [H m ~> m2 or kg m-1].
1594  real, dimension(SZI_(G)) :: &
1595  vh_err, & ! Difference between vhbt and the summed vh [H m2 s-1 ~> m3 s-1 or kg s-1].
1596  vh_err_best, & ! The smallest value of vh_err found so far [H m2 s-1 ~> m3 s-1 or kg s-1].
1597  v_new, & ! The velocity with the correction added [m s-1].
1598  dvhdv_tot,&! Summed partial derivative of vh with u [H m ~> m2 or kg m-1].
1599  dv_min, & ! Min/max limits on dv correction based on CFL limits
1600  dv_max ! and previous iterations [m s-1].
1601  real :: dv_prev ! The previous value of dv [m s-1].
1602  real :: ddv ! The change in dv from the previous iteration [m s-1].
1603  real :: tol_eta ! The tolerance for the current iteration [H ~> m or kg m-2].
1604  real :: tol_vel ! The tolerance for velocity in the current iteration [m s-1].
1605  integer :: i, k, nz, itt, max_itts = 20
1606  logical :: full_prec, domore, do_I(SZI_(G))
1607 
1608  nz = g%ke
1609  full_prec = .true. ; if (present(full_precision)) full_prec = full_precision
1610 
1611  vh_aux(:,:) = 0.0 ; dvhdv(:,:) = 0.0
1612 
1613  if (present(vh_3d)) then ; do k=1,nz ; do i=ish,ieh
1614  vh_aux(i,k) = vh_3d(i,j,k)
1615  enddo ; enddo ; endif
1616 
1617  do i=ish,ieh
1618  dv(i) = 0.0 ; do_i(i) = do_i_in(i)
1619  dv_max(i) = dv_max_cfl(i) ; dv_min(i) = dv_min_cfl(i)
1620  vh_err(i) = vh_tot_0(i) - vhbt(i) ; dvhdv_tot(i) = dvhdv_tot_0(i)
1621  vh_err_best(i) = abs(vh_err(i))
1622  enddo
1623 
1624  do itt=1,max_itts
1625  if (full_prec) then
1626  select case (itt)
1627  case (:1) ; tol_eta = 1e-6 * cs%tol_eta
1628  case (2) ; tol_eta = 1e-4 * cs%tol_eta
1629  case (3) ; tol_eta = 1e-2 * cs%tol_eta
1630  case default ; tol_eta = cs%tol_eta
1631  end select
1632  else
1633  tol_eta = cs%tol_eta_aux ; if (itt<=1) tol_eta = 1e-6 * cs%tol_eta_aux
1634  endif
1635  tol_vel = cs%tol_vel
1636 
1637  do i=ish,ieh
1638  if (vh_err(i) > 0.0) then ; dv_max(i) = dv(i)
1639  elseif (vh_err(i) < 0.0) then ; dv_min(i) = dv(i)
1640  else ; do_i(i) = .false. ; endif
1641  enddo
1642  domore = .false.
1643  do i=ish,ieh ; if (do_i(i)) then
1644  if ((dt*min(g%IareaT(i,j),g%IareaT(i,j+1))*abs(vh_err(i)) > tol_eta) .or.&
1645  (cs%better_iter .and. ((abs(vh_err(i)) > tol_vel * dvhdv_tot(i)) .or.&
1646  (abs(vh_err(i)) > vh_err_best(i))) )) then
1647  ! Use Newton's method, provided it stays bounded. Otherwise bisect
1648  ! the value with the appropriate bound.
1649  if (full_prec) then
1650  ddv = -vh_err(i) / dvhdv_tot(i)
1651  dv_prev = dv(i)
1652  dv(i) = dv(i) + ddv
1653  if (abs(ddv) < 1.0e-15*abs(dv(i))) then
1654  do_i(i) = .false. ! ddv is small enough to quit.
1655  elseif (ddv > 0.0) then
1656  if (dv(i) >= dv_max(i)) then
1657  dv(i) = 0.5*(dv_prev + dv_max(i))
1658  if (dv_max(i) - dv_prev < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1659  endif
1660  else ! dvv(i) < 0.0
1661  if (dv(i) <= dv_min(i)) then
1662  dv(i) = 0.5*(dv_prev + dv_min(i))
1663  if (dv_prev - dv_min(i) < 1.0e-15*abs(dv(i))) do_i(i) = .false.
1664  endif
1665  endif
1666  else
1667  ! Use Newton's method, provided it stays bounded, just like above.
1668  dv(i) = dv(i) - vh_err(i) / dvhdv_tot(i)
1669  if ((dv(i) >= dv_max(i)) .or. (dv(i) <= dv_min(i))) &
1670  dv(i) = 0.5*(dv_max(i) + dv_min(i))
1671  endif
1672  if (do_i(i)) domore = .true.
1673  else
1674  do_i(i) = .false.
1675  endif
1676  endif ; enddo
1677  if (.not.domore) exit
1678 
1679  if ((itt < max_itts) .or. present(vh_3d)) then ; do k=1,nz
1680  do i=ish,ieh ; v_new(i) = v(i,j,k) + dv(i) * visc_rem(i,k) ; enddo
1681  call merid_flux_layer(v_new, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), &
1682  vh_aux(:,k), dvhdv(:,k), visc_rem(:,k), &
1683  dt, g, j, ish, ieh, do_i, cs%vol_CFL, obc)
1684  enddo ; endif
1685 
1686  if (itt < max_itts) then
1687  do i=ish,ieh
1688  vh_err(i) = -vhbt(i) ; dvhdv_tot(i) = 0.0
1689  enddo
1690  do k=1,nz ; do i=ish,ieh
1691  vh_err(i) = vh_err(i) + vh_aux(i,k)
1692  dvhdv_tot(i) = dvhdv_tot(i) + dvhdv(i,k)
1693  enddo ; enddo
1694  do i=ish,ieh
1695  vh_err_best(i) = min(vh_err_best(i), abs(vh_err(i)))
1696  enddo
1697  endif
1698  enddo ! itt-loop
1699  ! If there are any faces which have not converged to within the tolerance,
1700  ! so-be-it, or else use a final upwind correction?
1701  ! This never seems to happen with 20 iterations as max_itt.
1702 
1703  if (present(vh_3d)) then ; do k=1,nz ; do i=ish,ieh
1704  vh_3d(i,j,k) = vh_aux(i,k)
1705  enddo ; enddo ; endif
1706 

◆ 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(in)  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(unit_scale_type), intent(in)  US,
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 [m s-1].
[in]h_inLayer thickness used to calculate fluxes [H ~> m or kg m-2].
[out]vhVolume flux through meridional faces = v*h*dx [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]dtTime increment [s].
[in]usA dimensional unit scaling type
csThis module's control structure.
[in]lbLoop bounds structure.
obcOpen boundary condition type specifies whether, where, and what open boundary conditions are used.
[in]visc_rem_vBoth the fraction of the momentum
[in]vhbtThe summed volume flux through meridional faces [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]vhbt_auxA second set of summed volume fluxes through meridional faces [H m2 s-1 ~> m3 s-1 or kg 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 [m s-1].
bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.

Definition at line 1056 of file MOM_continuity_PPM.F90.

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

◆ 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 [H ~> m or kg m-2].
[in,out]h_lLeft thickness in the reconstruction, [H ~> m or kg m-2].
[in,out]h_rRight thickness in the reconstruction, [H ~> m or kg m-2].
[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 2194 of file MOM_continuity_PPM.F90.

2194  type(ocean_grid_type), intent(in) :: G !< Ocean's grid structure.
2195  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness [H ~> m or kg m-2].
2196  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_L !< Left thickness in the reconstruction,
2197  !! [H ~> m or kg m-2].
2198  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_R !< Right thickness in the reconstruction,
2199  !! [H ~> m or kg m-2].
2200  integer, intent(in) :: iis !< Start of i index range.
2201  integer, intent(in) :: iie !< End of i index range.
2202  integer, intent(in) :: jis !< Start of j index range.
2203  integer, intent(in) :: jie !< End of j index range.
2204 
2205  ! Local variables
2206  real :: h_i, RLdiff, RLdiff2, RLmean, FunFac
2207  character(len=256) :: mesg
2208  integer :: i,j
2209 
2210  do j=jis,jie ; do i=iis,iie
2211  ! This limiter monotonizes the parabola following
2212  ! Colella and Woodward, 1984, Eq. 1.10
2213  h_i = h_in(i,j)
2214  if ( ( h_r(i,j) - h_i ) * ( h_i - h_l(i,j) ) <= 0. ) then
2215  h_l(i,j) = h_i ; h_r(i,j) = h_i
2216  else
2217  rldiff = h_r(i,j) - h_l(i,j) ! Difference of edge values
2218  rlmean = 0.5 * ( h_r(i,j) + h_l(i,j) ) ! Mean of edge values
2219  funfac = 6. * rldiff * ( h_i - rlmean ) ! Some funny factor
2220  rldiff2 = rldiff * rldiff ! Square of difference
2221  if ( funfac > rldiff2 ) h_l(i,j) = 3. * h_i - 2. * h_r(i,j)
2222  if ( funfac < -rldiff2 ) h_r(i,j) = 3. * h_i - 2. * h_l(i,j)
2223  endif
2224  enddo ; enddo
2225 
2226  return

◆ 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 [H ~> m or kg m-2].
[in,out]h_lLeft thickness in the reconstruction [H ~> m or kg m-2].
[in,out]h_rRight thickness in the reconstruction [H ~> m or kg m-2].
[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 2153 of file MOM_continuity_PPM.F90.

2153  type(ocean_grid_type), intent(in) :: G !< Ocean's grid structure.
2154  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness [H ~> m or kg m-2].
2155  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_L !< Left thickness in the reconstruction [H ~> m or kg m-2].
2156  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_R !< Right thickness in the reconstruction [H ~> m or kg m-2].
2157  real, intent(in) :: h_min !< The minimum thickness
2158  !! that can be obtained by a concave parabolic fit.
2159  integer, intent(in) :: iis !< Start of i index range.
2160  integer, intent(in) :: iie !< End of i index range.
2161  integer, intent(in) :: jis !< Start of j index range.
2162  integer, intent(in) :: jie !< End of j index range.
2163 
2164 ! Local variables
2165  real :: curv, dh, scale
2166  character(len=256) :: mesg
2167  integer :: i,j
2168 
2169  do j=jis,jie ; do i=iis,iie
2170  ! This limiter prevents undershooting minima within the domain with
2171  ! values less than h_min.
2172  curv = 3.0*(h_l(i,j) + h_r(i,j) - 2.0*h_in(i,j))
2173  if (curv > 0.0) then ! Only minima are limited.
2174  dh = h_r(i,j) - h_l(i,j)
2175  if (abs(dh) < curv) then ! The parabola's minimum is within the cell.
2176  if (h_in(i,j) <= h_min) then
2177  h_l(i,j) = h_in(i,j) ; h_r(i,j) = h_in(i,j)
2178  elseif (12.0*curv*(h_in(i,j) - h_min) < (curv**2 + 3.0*dh**2)) then
2179  ! The minimum value is h_in - (curv^2 + 3*dh^2)/(12*curv), and must
2180  ! be limited in this case. 0 < scale < 1.
2181  scale = 12.0*curv*(h_in(i,j) - h_min) / (curv**2 + 3.0*dh**2)
2182  h_l(i,j) = h_in(i,j) + scale*(h_l(i,j) - h_in(i,j))
2183  h_r(i,j) = h_in(i,j) + scale*(h_r(i,j) - h_in(i,j))
2184  endif
2185  endif
2186  endif
2187  enddo ; enddo
2188 

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

Calculates left/right edge values for PPM reconstruction.

Parameters
[in]gOcean's grid structure.
[in]h_inLayer thickness [H ~> m or kg m-2].
[out]h_lLeft thickness in the reconstruction, [H ~> m or kg m-2].
[out]h_rRight thickness in the reconstruction, [H ~> m or kg m-2].
[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.
obcOpen boundaries control structure.

Definition at line 1874 of file MOM_continuity_PPM.F90.

1874  type(ocean_grid_type), intent(in) :: G !< Ocean's grid structure.
1875  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness [H ~> m or kg m-2].
1876  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_L !< Left thickness in the reconstruction,
1877  !! [H ~> m or kg m-2].
1878  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_R !< Right thickness in the reconstruction,
1879  !! [H ~> m or kg m-2].
1880  type(loop_bounds_type), intent(in) :: LB !< Active loop bounds structure.
1881  real, intent(in) :: h_min !< The minimum thickness
1882  !! that can be obtained by a concave parabolic fit.
1883  logical, optional, intent(in) :: monotonic !< If true, use the
1884  !! Colella & Woodward monotonic limiter.
1885  !! Otherwise use a simple positive-definite limiter.
1886  logical, optional, intent(in) :: simple_2nd !< If true, use the
1887  !! arithmetic mean thicknesses as the default edge values
1888  !! for a simple 2nd order scheme.
1889  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
1890 
1891  ! Local variables with useful mnemonic names.
1892  real, dimension(SZI_(G),SZJ_(G)) :: slp ! The slopes.
1893  real, parameter :: oneSixth = 1./6.
1894  real :: h_ip1, h_im1
1895  real :: dMx, dMn
1896  logical :: use_CW84, use_2nd
1897  character(len=256) :: mesg
1898  integer :: i, j, isl, iel, jsl, jel, n, stencil
1899  logical :: local_open_BC
1900  type(OBC_segment_type), pointer :: segment => null()
1901 
1902  use_cw84 = .false. ; if (present(monotonic)) use_cw84 = monotonic
1903  use_2nd = .false. ; if (present(simple_2nd)) use_2nd = simple_2nd
1904 
1905  local_open_bc = .false.
1906  if (present(obc)) then ; if (associated(obc)) then
1907  local_open_bc = obc%open_u_BCs_exist_globally
1908  endif ; endif
1909 
1910  isl = lb%ish-1 ; iel = lb%ieh+1 ; jsl = lb%jsh ; jel = lb%jeh
1911 
1912  ! This is the stencil of the reconstruction, not the scheme overall.
1913  stencil = 2 ; if (use_2nd) stencil = 1
1914 
1915  if ((isl-stencil < g%isd) .or. (iel+stencil > g%ied)) then
1916  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", &
1917  & "x-halo that needs to be increased by ",i2,".")') &
1918  stencil + max(g%isd-isl,iel-g%ied)
1919  call mom_error(fatal,mesg)
1920  endif
1921  if ((jsl < g%jsd) .or. (jel > g%jed)) then
1922  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_x called with a ", &
1923  & "y-halo that needs to be increased by ",i2,".")') &
1924  max(g%jsd-jsl,jel-g%jed)
1925  call mom_error(fatal,mesg)
1926  endif
1927 
1928  if (use_2nd) then
1929  do j=jsl,jel ; do i=isl,iel
1930  h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1931  h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1932  h_l(i,j) = 0.5*( h_im1 + h_in(i,j) )
1933  h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) )
1934  enddo ; enddo
1935  else
1936  do j=jsl,jel ; do i=isl-1,iel+1
1937  if ((g%mask2dT(i-1,j) * g%mask2dT(i,j) * g%mask2dT(i+1,j)) == 0.0) then
1938  slp(i,j) = 0.0
1939  else
1940  ! This uses a simple 2nd order slope.
1941  slp(i,j) = 0.5 * (h_in(i+1,j) - h_in(i-1,j))
1942  ! Monotonic constraint, see Eq. B2 in Lin 1994, MWR (132)
1943  dmx = max(h_in(i+1,j), h_in(i-1,j), h_in(i,j)) - h_in(i,j)
1944  dmn = h_in(i,j) - min(h_in(i+1,j), h_in(i-1,j), h_in(i,j))
1945  slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1946  ! * (G%mask2dT(i-1,j) * G%mask2dT(i,j) * G%mask2dT(i+1,j))
1947  endif
1948  enddo ; enddo
1949 
1950  if (local_open_bc) then
1951  do n=1, obc%number_of_segments
1952  segment => obc%segment(n)
1953  if (.not. segment%on_pe) cycle
1954  if (segment%direction == obc_direction_e .or. &
1955  segment%direction == obc_direction_w) then
1956  i=segment%HI%IsdB
1957  do j=segment%HI%jsd,segment%HI%jed
1958  slp(i+1,j) = 0.0
1959  slp(i,j) = 0.0
1960  enddo
1961  endif
1962  enddo
1963  endif
1964 
1965  do j=jsl,jel ; do i=isl,iel
1966  ! Neighboring values should take into account any boundaries. The 3
1967  ! following sets of expressions are equivalent.
1968  ! h_im1 = h_in(i-1,j,k) ; if (G%mask2dT(i-1,j) < 0.5) h_im1 = h_in(i,j)
1969  ! h_ip1 = h_in(i+1,j,k) ; if (G%mask2dT(i+1,j) < 0.5) h_ip1 = h_in(i,j)
1970  h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1971  h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1972  ! Left/right values following Eq. B2 in Lin 1994, MWR (132)
1973  h_l(i,j) = 0.5*( h_im1 + h_in(i,j) ) + onesixth*( slp(i-1,j) - slp(i,j) )
1974  h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i+1,j) )
1975  enddo ; enddo
1976  endif
1977 
1978  if (local_open_bc) then
1979  do n=1, obc%number_of_segments
1980  segment => obc%segment(n)
1981  if (.not. segment%on_pe) cycle
1982  if (segment%direction == obc_direction_e) then
1983  i=segment%HI%IsdB
1984  do j=segment%HI%jsd,segment%HI%jed
1985  h_l(i+1,j) = h_in(i,j)
1986  h_r(i+1,j) = h_in(i,j)
1987  h_l(i,j) = h_in(i,j)
1988  h_r(i,j) = h_in(i,j)
1989  enddo
1990  elseif (segment%direction == obc_direction_w) then
1991  i=segment%HI%IsdB
1992  do j=segment%HI%jsd,segment%HI%jed
1993  h_l(i,j) = h_in(i+1,j)
1994  h_r(i,j) = h_in(i+1,j)
1995  h_l(i+1,j) = h_in(i+1,j)
1996  h_r(i+1,j) = h_in(i+1,j)
1997  enddo
1998  endif
1999  enddo
2000  endif
2001 
2002  if (use_cw84) then
2003  call ppm_limit_cw84(h_in, h_l, h_r, g, isl, iel, jsl, jel)
2004  else
2005  call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
2006  endif
2007 
2008  return

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

Calculates left/right edge values for PPM reconstruction.

Parameters
[in]gOcean's grid structure.
[in]h_inLayer thickness [H ~> m or kg m-2].
[out]h_lLeft thickness in the reconstruction, [H ~> m or kg m-2].
[out]h_rRight thickness in the reconstruction, [H ~> m or kg m-2].
[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.
obcOpen boundaries control structure.

Definition at line 2013 of file MOM_continuity_PPM.F90.

2013  type(ocean_grid_type), intent(in) :: G !< Ocean's grid structure.
2014  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Layer thickness [H ~> m or kg m-2].
2015  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_L !< Left thickness in the reconstruction,
2016  !! [H ~> m or kg m-2].
2017  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_R !< Right thickness in the reconstruction,
2018  !! [H ~> m or kg m-2].
2019  type(loop_bounds_type), intent(in) :: LB !< Active loop bounds structure.
2020  real, intent(in) :: h_min !< The minimum thickness
2021  !! that can be obtained by a concave parabolic fit.
2022  logical, optional, intent(in) :: monotonic !< If true, use the
2023  !! Colella & Woodward monotonic limiter.
2024  !! Otherwise use a simple positive-definite limiter.
2025  logical, optional, intent(in) :: simple_2nd !< If true, use the
2026  !! arithmetic mean thicknesses as the default edge values
2027  !! for a simple 2nd order scheme.
2028  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
2029 
2030  ! Local variables with useful mnemonic names.
2031  real, dimension(SZI_(G),SZJ_(G)) :: slp ! The slopes.
2032  real, parameter :: oneSixth = 1./6.
2033  real :: h_jp1, h_jm1
2034  real :: dMx, dMn
2035  logical :: use_CW84, use_2nd
2036  character(len=256) :: mesg
2037  integer :: i, j, isl, iel, jsl, jel, n, stencil
2038  logical :: local_open_BC
2039  type(OBC_segment_type), pointer :: segment => null()
2040 
2041  use_cw84 = .false. ; if (present(monotonic)) use_cw84 = monotonic
2042  use_2nd = .false. ; if (present(simple_2nd)) use_2nd = simple_2nd
2043 
2044  local_open_bc = .false.
2045  if (present(obc)) then ; if (associated(obc)) then
2046  local_open_bc = obc%open_u_BCs_exist_globally
2047  endif ; endif
2048 
2049  isl = lb%ish ; iel = lb%ieh ; jsl = lb%jsh-1 ; jel = lb%jeh+1
2050 
2051  ! This is the stencil of the reconstruction, not the scheme overall.
2052  stencil = 2 ; if (use_2nd) stencil = 1
2053 
2054  if ((isl < g%isd) .or. (iel > g%ied)) then
2055  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", &
2056  & "x-halo that needs to be increased by ",i2,".")') &
2057  max(g%isd-isl,iel-g%ied)
2058  call mom_error(fatal,mesg)
2059  endif
2060  if ((jsl-stencil < g%jsd) .or. (jel+stencil > g%jed)) then
2061  write(mesg,'("In MOM_continuity_PPM, PPM_reconstruction_y called with a ", &
2062  & "y-halo that needs to be increased by ",i2,".")') &
2063  stencil + max(g%jsd-jsl,jel-g%jed)
2064  call mom_error(fatal,mesg)
2065  endif
2066 
2067  if (use_2nd) then
2068  do j=jsl,jel ; do i=isl,iel
2069  h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
2070  h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
2071  h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) )
2072  h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) )
2073  enddo ; enddo
2074  else
2075  do j=jsl-1,jel+1 ; do i=isl,iel
2076  if ((g%mask2dT(i,j-1) * g%mask2dT(i,j) * g%mask2dT(i,j+1)) == 0.0) then
2077  slp(i,j) = 0.0
2078  else
2079  ! This uses a simple 2nd order slope.
2080  slp(i,j) = 0.5 * (h_in(i,j+1) - h_in(i,j-1))
2081  ! Monotonic constraint, see Eq. B2 in Lin 1994, MWR (132)
2082  dmx = max(h_in(i,j+1), h_in(i,j-1), h_in(i,j)) - h_in(i,j)
2083  dmn = h_in(i,j) - min(h_in(i,j+1), h_in(i,j-1), h_in(i,j))
2084  slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
2085  ! * (G%mask2dT(i,j-1) * G%mask2dT(i,j) * G%mask2dT(i,j+1))
2086  endif
2087  enddo ; enddo
2088 
2089  if (local_open_bc) then
2090  do n=1, obc%number_of_segments
2091  segment => obc%segment(n)
2092  if (.not. segment%on_pe) cycle
2093  if (segment%direction == obc_direction_s .or. &
2094  segment%direction == obc_direction_n) then
2095  j=segment%HI%JsdB
2096  do i=segment%HI%isd,segment%HI%ied
2097  slp(i,j+1) = 0.0
2098  slp(i,j) = 0.0
2099  enddo
2100  endif
2101  enddo
2102  endif
2103 
2104  do j=jsl,jel ; do i=isl,iel
2105  ! Neighboring values should take into account any boundaries. The 3
2106  ! following sets of expressions are equivalent.
2107  h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
2108  h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
2109  ! Left/right values following Eq. B2 in Lin 1994, MWR (132)
2110  h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) ) + onesixth*( slp(i,j-1) - slp(i,j) )
2111  h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i,j+1) )
2112  enddo ; enddo
2113  endif
2114 
2115  if (local_open_bc) then
2116  do n=1, obc%number_of_segments
2117  segment => obc%segment(n)
2118  if (.not. segment%on_pe) cycle
2119  if (segment%direction == obc_direction_n) then
2120  j=segment%HI%JsdB
2121  do i=segment%HI%isd,segment%HI%ied
2122  h_l(i,j+1) = h_in(i,j)
2123  h_r(i,j+1) = h_in(i,j)
2124  h_l(i,j) = h_in(i,j)
2125  h_r(i,j) = h_in(i,j)
2126  enddo
2127  elseif (segment%direction == obc_direction_s) then
2128  j=segment%HI%JsdB
2129  do i=segment%HI%isd,segment%HI%ied
2130  h_l(i,j) = h_in(i,j+1)
2131  h_r(i,j) = h_in(i,j+1)
2132  h_l(i,j+1) = h_in(i,j+1)
2133  h_r(i,j+1) = h_in(i,j+1)
2134  enddo
2135  endif
2136  enddo
2137  endif
2138 
2139  if (use_cw84) then
2140  call ppm_limit_cw84(h_in, h_l, h_r, g, isl, iel, jsl, jel)
2141  else
2142  call ppm_limit_pos(h_in, h_l, h_r, h_min, g, isl, iel, jsl, jel)
2143  endif
2144 
2145  return

◆ 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 2231 of file MOM_continuity_PPM.F90.

2231  real, intent(in) :: a !< Numerator
2232  real, intent(in) :: b !< Denominator
2233  real, intent(in) :: maxrat !< Maximum value of ratio.
2234  real :: ratio !< Return value.
2235 
2236  if (abs(a) > abs(maxrat*b)) then
2237  ratio = maxrat
2238  else
2239  ratio = a / b
2240  endif

◆ 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(unit_scale_type), intent(in)  US,
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 [m s-1].
[in]h_inLayer thickness used to calculate fluxes, [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction, [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction, [H ~> m or kg m-2].
[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 [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]dvhdv_tot_0The partial derivative of du_err with dv at 0 adjustment [H m ~> m2 or kg m-1].
[in]dv_max_cflMaximum acceptable value of dv [m s-1].
[in]dv_min_cflMinimum acceptable value of dv [m s-1].
[in]dtTime increment [s].
[in]usA dimensional unit scaling type
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 1714 of file MOM_continuity_PPM.F90.

1714  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
1715  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Meridional velocity [m s-1].
1716  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_in !< Layer thickness used to calculate fluxes,
1717  !! [H ~> m or kg m-2].
1718  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_L !< Left thickness in the reconstruction,
1719  !! [H ~> m or kg m-2].
1720  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_R !< Right thickness in the reconstruction,
1721  !! [H ~> m or kg m-2].
1722  type(BT_cont_type), intent(inout) :: BT_cont !< A structure with elements
1723  !! that describe the effective open face areas as a function of barotropic flow.
1724  real, dimension(SZI_(G)), intent(in) :: vh_tot_0 !< The summed transport
1725  !! with 0 adjustment [H m2 s-1 ~> m3 s-1 or kg s-1].
1726  real, dimension(SZI_(G)), intent(in) :: dvhdv_tot_0 !< The partial derivative
1727  !! of du_err with dv at 0 adjustment [H m ~> m2 or kg m-1].
1728  real, dimension(SZI_(G)), intent(in) :: dv_max_CFL !< Maximum acceptable value of dv [m s-1].
1729  real, dimension(SZI_(G)), intent(in) :: dv_min_CFL !< Minimum acceptable value of dv [m s-1].
1730  real, intent(in) :: dt !< Time increment [s].
1731  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1732  type(continuity_PPM_CS), pointer :: CS !< This module's control structure.
1733  real, dimension(SZI_(G),SZK_(G)), intent(in) :: visc_rem !< Both the fraction of the
1734  !! momentum originally in a layer that remains after a time-step
1735  !! of viscosity, and the fraction of a time-step's worth of a barotropic
1736  !! acceleration that a layer experiences after viscosity is applied.
1737  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
1738  real, dimension(SZI_(G)), intent(in) :: visc_rem_max !< Maximum allowable visc_rem.
1739  integer, intent(in) :: j !< Spatial index.
1740  integer, intent(in) :: ish !< Start of index range.
1741  integer, intent(in) :: ieh !< End of index range.
1742  logical, dimension(SZI_(G)), intent(in) :: do_I !< A logical flag indicating
1743  !! which I values to work on.
1744  ! Local variables
1745  real, dimension(SZI_(G)) :: &
1746  dv0, & ! The barotropic velocity increment that gives 0 transport [m s-1].
1747  dvL, dvR, & ! The barotropic velocity increments that give the southerly
1748  ! (dvL) and northerly (dvR) test velocities.
1749  zeros, & ! An array of full of 0's.
1750  dv_cfl, & ! The velocity increment that corresponds to CFL_min [m s-1].
1751  v_l, v_r, & ! The southerly (v_L), northerly (v_R), and zero-barotropic
1752  v_0, & ! transport (v_0) layer test velocities [m s-1].
1753  fa_marg_l, & ! The effective layer marginal face areas with the southerly
1754  fa_marg_r, & ! (_L), northerly (_R), and zero-barotropic (_0) test
1755  fa_marg_0, & ! velocities [H m ~> m2 or kg m-1].
1756  vh_l, vh_r, & ! The layer transports with the southerly (_L), northerly (_R)
1757  vh_0, & ! and zero-barotropic (_0) test velocities [H m2 s-1 ~> m3 s-1 or kg s-1].
1758  famt_l, famt_r, & ! The summed effective marginal face areas for the 3
1759  famt_0, & ! test velocities [H m ~> m2 or kg m-1].
1760  vhtot_l, & ! The summed transport with the southerly (vhtot_L) and
1761  vhtot_r ! and northerly (vhtot_R) test velocities [H m2 s-1 ~> m3 s-1 or kg s-1].
1762  real :: FA_0 ! The effective face area with 0 barotropic transport [H m ~> m2 or kg m-1].
1763  real :: FA_avg ! The average effective face area [H m ~> m2 or kg m-1], nominally given by
1764  ! the realized transport divided by the barotropic velocity.
1765  real :: visc_rem_lim ! The larger of visc_rem and min_visc_rem [nondim] This
1766  ! limiting is necessary to keep the inverse of visc_rem
1767  ! from leading to large CFL numbers.
1768  real :: min_visc_rem ! The smallest permitted value for visc_rem that is used
1769  ! in finding the barotropic velocity that changes the
1770  ! flow direction. This is necessary to keep the inverse
1771  ! of visc_rem from leading to large CFL numbers.
1772  real :: CFL_min ! A minimal increment in the CFL to try to ensure that the
1773  ! flow is truly upwind [nondim]
1774  real :: Idt ! The inverse of the time step [s-1].
1775  logical :: domore
1776  integer :: i, k, nz
1777 
1778  nz = g%ke ; idt = 1.0/dt
1779  min_visc_rem = 0.1 ; cfl_min = 1e-6
1780 
1781  ! Diagnose the zero-transport correction, dv0.
1782  do i=ish,ieh ; zeros(i) = 0.0 ; enddo
1783  call meridional_flux_adjust(v, h_in, h_l, h_r, zeros, vh_tot_0, &
1784  dvhdv_tot_0, dv0, dv_max_cfl, dv_min_cfl, dt, g, &
1785  cs, visc_rem, j, ish, ieh, do_i, .true.)
1786 
1787  ! Determine the southerly- and northerly- fluxes. Choose a sufficiently
1788  ! negative velocity correction for the northerly-flux, and a sufficiently
1789  ! positive correction for the southerly-flux.
1790  domore = .false.
1791  do i=ish,ieh ; if (do_i(i)) then
1792  domore = .true.
1793  dv_cfl(i) = (cfl_min * idt) * g%dyCv(i,j)
1794  dvr(i) = min(0.0,dv0(i) - dv_cfl(i))
1795  dvl(i) = max(0.0,dv0(i) + dv_cfl(i))
1796  famt_l(i) = 0.0 ; famt_r(i) = 0.0 ; famt_0(i) = 0.0
1797  vhtot_l(i) = 0.0 ; vhtot_r(i) = 0.0
1798  endif ; enddo
1799 
1800  if (.not.domore) then
1801  do k=1,nz ; do i=ish,ieh
1802  bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1803  bt_cont%vBT_SS(i,j) = 0.0
1804  bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1805  bt_cont%vBT_NN(i,j) = 0.0
1806  enddo ; enddo
1807  return
1808  endif
1809 
1810  do k=1,nz ; do i=ish,ieh ; if (do_i(i)) then
1811  visc_rem_lim = max(visc_rem(i,k), min_visc_rem*visc_rem_max(i))
1812  if (visc_rem_lim > 0.0) then ! This is almost always true for ocean points.
1813  if (v(i,j,k) + dvr(i)*visc_rem_lim > -dv_cfl(i)*visc_rem(i,k)) &
1814  dvr(i) = -(v(i,j,k) + dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1815  if (v(i,j,k) + dvl(i)*visc_rem_lim < dv_cfl(i)*visc_rem(i,k)) &
1816  dvl(i) = -(v(i,j,k) - dv_cfl(i)*visc_rem(i,k)) / visc_rem_lim
1817  endif
1818  endif ; enddo ; enddo
1819  do k=1,nz
1820  do i=ish,ieh ; if (do_i(i)) then
1821  v_l(i) = v(i,j,k) + dvl(i) * visc_rem(i,k)
1822  v_r(i) = v(i,j,k) + dvr(i) * visc_rem(i,k)
1823  v_0(i) = v(i,j,k) + dv0(i) * visc_rem(i,k)
1824  endif ; enddo
1825  call merid_flux_layer(v_0, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_0, &
1826  fa_marg_0, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1827  cs%vol_CFL)
1828  call merid_flux_layer(v_l, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_l, &
1829  fa_marg_l, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1830  cs%vol_CFL)
1831  call merid_flux_layer(v_r, h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), vh_r, &
1832  fa_marg_r, visc_rem(:,k), dt, g, j, ish, ieh, do_i, &
1833  cs%vol_CFL)
1834  do i=ish,ieh ; if (do_i(i)) then
1835  famt_0(i) = famt_0(i) + fa_marg_0(i)
1836  famt_l(i) = famt_l(i) + fa_marg_l(i)
1837  famt_r(i) = famt_r(i) + fa_marg_r(i)
1838  vhtot_l(i) = vhtot_l(i) + vh_l(i)
1839  vhtot_r(i) = vhtot_r(i) + vh_r(i)
1840  endif ; enddo
1841  enddo
1842  do i=ish,ieh ; if (do_i(i)) then
1843  fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1844  if ((dvl(i) - dv0(i)) /= 0.0) &
1845  fa_avg = vhtot_l(i) / (dvl(i) - dv0(i))
1846  if (fa_avg > max(fa_0, famt_l(i))) then ; fa_avg = max(fa_0, famt_l(i))
1847  elseif (fa_avg < min(fa_0, famt_l(i))) then ; fa_0 = fa_avg ; endif
1848  bt_cont%FA_v_S0(i,j) = us%m_to_L*fa_0 ; bt_cont%FA_v_SS(i,j) = us%m_to_L*famt_l(i)
1849  if (abs(fa_0-famt_l(i)) <= 1e-12*fa_0) then ; bt_cont%vBT_SS(i,j) = 0.0 ; else
1850  bt_cont%vBT_SS(i,j) = us%m_s_to_L_T*(1.5 * (dvl(i) - dv0(i))) * &
1851  ((famt_l(i) - fa_avg) / (famt_l(i) - fa_0))
1852  endif
1853 
1854  fa_0 = famt_0(i) ; fa_avg = famt_0(i)
1855  if ((dvr(i) - dv0(i)) /= 0.0) &
1856  fa_avg = vhtot_r(i) / (dvr(i) - dv0(i))
1857  if (fa_avg > max(fa_0, famt_r(i))) then ; fa_avg = max(fa_0, famt_r(i))
1858  elseif (fa_avg < min(fa_0, famt_r(i))) then ; fa_0 = fa_avg ; endif
1859  bt_cont%FA_v_N0(i,j) = us%m_to_L*fa_0 ; bt_cont%FA_v_NN(i,j) = us%m_to_L*famt_r(i)
1860  if (abs(famt_r(i) - fa_0) <= 1e-12*fa_0) then ; bt_cont%vBT_NN(i,j) = 0.0 ; else
1861  bt_cont%vBT_NN(i,j) = us%m_s_to_L_T*(1.5 * (dvr(i) - dv0(i))) * &
1862  ((famt_r(i) - fa_avg) / (famt_r(i) - fa_0))
1863  endif
1864  else
1865  bt_cont%FA_v_S0(i,j) = 0.0 ; bt_cont%FA_v_SS(i,j) = 0.0
1866  bt_cont%FA_v_N0(i,j) = 0.0 ; bt_cont%FA_v_NN(i,j) = 0.0
1867  bt_cont%vBT_SS(i,j) = 0.0 ; bt_cont%vBT_NN(i,j) = 0.0
1868  endif ; enddo
1869 

◆ 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(unit_scale_type), intent(in)  US,
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 [m s-1].
[in]h_inLayer thickness used to calculate fluxes [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction [H ~> m or kg m-2].
[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 [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]duhdu_tot_0The partial derivative of du_err with du at 0 adjustment [H m ~> m2 or kg m-1].
[in]du_max_cflMaximum acceptable value of du [m s-1].
[in]du_min_cflMinimum acceptable value of du [m s-1].
[in]dtTime increment [s].
[in]usA dimensional unit scaling type
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 891 of file MOM_continuity_PPM.F90.

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

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

Sets the effective interface thickness at each zonal velocity point.

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity [m s-1].
[in]hLayer thickness used to calculate fluxes [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction [H ~> m or kg m-2].
[in,out]h_uThickness at zonal faces [H ~> m or kg m-2].
[in]dtTime increment [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).
obcOpen boundaries control structure.

Definition at line 621 of file MOM_continuity_PPM.F90.

621  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
622  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Zonal velocity [m s-1].
623  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thickness used to
624  !! calculate fluxes [H ~> m or kg m-2].
625  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_L !< Left thickness in the
626  !! reconstruction [H ~> m or kg m-2].
627  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_R !< Right thickness in the
628  !! reconstruction [H ~> m or kg m-2].
629  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: h_u !< Thickness at zonal faces [H ~> m or kg m-2].
630  real, intent(in) :: dt !< Time increment [s].
631  type(loop_bounds_type), intent(in) :: LB !< Loop bounds structure.
632  logical, intent(in) :: vol_CFL !< If true, rescale the ratio
633  !! of face areas to the cell areas when estimating the CFL number.
634  logical, intent(in) :: marginal !< If true, report the
635  !! marginal face thicknesses; otherwise report transport-averaged thicknesses.
636  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
637  optional, intent(in) :: visc_rem_u
638  !< Both the fraction of the momentum originally in a layer that remains after
639  !! a time-step of viscosity, and the fraction of a time-step's worth of a
640  !! barotropic acceleration that a layer experiences after viscosity is applied.
641  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
642  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
643 
644  ! Local variables
645  real :: CFL ! The CFL number based on the local velocity and grid spacing [nondim]
646  real :: curv_3 ! A measure of the thickness curvature over a grid length,
647  ! with the same units as h_in.
648  real :: h_avg ! The average thickness of a flux [H ~> m or kg m-2].
649  real :: h_marg ! The marginal thickness of a flux [H ~> m or kg m-2].
650  logical :: local_open_BC
651  integer :: i, j, k, ish, ieh, jsh, jeh, nz, n
652  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
653 
654  !$OMP parallel do default(shared) private(CFL,curv_3,h_marg,h_avg)
655  do k=1,nz ; do j=jsh,jeh ; do i=ish-1,ieh
656  if (u(i,j,k) > 0.0) then
657  if (vol_cfl) then ; cfl = (u(i,j,k) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
658  else ; cfl = u(i,j,k) * dt * g%IdxT(i,j) ; endif
659  curv_3 = h_l(i,j,k) + h_r(i,j,k) - 2.0*h(i,j,k)
660  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))
661  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))
662  elseif (u(i,j,k) < 0.0) then
663  if (vol_cfl) then ; cfl = (-u(i,j,k)*dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
664  else ; cfl = -u(i,j,k) * dt * g%IdxT(i+1,j) ; endif
665  curv_3 = h_l(i+1,j,k) + h_r(i+1,j,k) - 2.0*h(i+1,j,k)
666  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))
667  h_marg = h_l(i+1,j,k) + cfl * ((h_r(i+1,j,k)-h_l(i+1,j,k)) + &
668  3.0*curv_3*(cfl - 1.0))
669  else
670  h_avg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
671  ! The choice to use the arithmetic mean here is somewhat arbitrariy, but
672  ! it should be noted that h_L(i+1,j,k) and h_R(i,j,k) are usually the same.
673  h_marg = 0.5 * (h_l(i+1,j,k) + h_r(i,j,k))
674  ! h_marg = (2.0 * h_L(i+1,j,k) * h_R(i,j,k)) / &
675  ! (h_L(i+1,j,k) + h_R(i,j,k) + GV%H_subroundoff)
676  endif
677 
678  if (marginal) then ; h_u(i,j,k) = h_marg
679  else ; h_u(i,j,k) = h_avg ; endif
680  enddo ; enddo ; enddo
681  if (present(visc_rem_u)) then
682  !$OMP parallel do default(shared)
683  do k=1,nz ; do j=jsh,jeh ; do i=ish-1,ieh
684  h_u(i,j,k) = h_u(i,j,k) * visc_rem_u(i,j,k)
685  enddo ; enddo ; enddo
686  endif
687 
688  local_open_bc = .false.
689  if (present(obc)) then ; if (associated(obc)) then
690  local_open_bc = obc%open_u_BCs_exist_globally
691  endif ; endif
692  if (local_open_bc) then
693  do n = 1, obc%number_of_segments
694  if (obc%segment(n)%open .and. obc%segment(n)%is_E_or_W) then
695  i = obc%segment(n)%HI%IsdB
696  if (obc%segment(n)%direction == obc_direction_e) then
697  if (present(visc_rem_u)) then ; do k=1,nz
698  do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
699  h_u(i,j,k) = h(i,j,k) * visc_rem_u(i,j,k)
700  enddo
701  enddo ; else ; do k=1,nz
702  do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
703  h_u(i,j,k) = h(i,j,k)
704  enddo
705  enddo ; endif
706  else
707  if (present(visc_rem_u)) then ; do k=1,nz
708  do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
709  h_u(i,j,k) = h(i+1,j,k) * visc_rem_u(i,j,k)
710  enddo
711  enddo ; else ; do k=1,nz
712  do j = obc%segment(n)%HI%jsd, obc%segment(n)%HI%jed
713  h_u(i,j,k) = h(i+1,j,k)
714  enddo
715  enddo ; endif
716  endif
717  endif
718  enddo
719  endif
720 

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

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

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity [m s-1].
[in]h_inLayer thickness used to calculate fluxes [H ~> m or kg m-2].
[in]h_lLeft thickness in the reconstruction [H ~> m or kg m-2].
[in]h_rRight thickness in the reconstruction [H ~> m or kg m-2].
[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 ~> m3 s-1 or kg s-1].
[in]du_max_cflMaximum acceptable value of du [m s-1].
[in]du_min_cflMinimum acceptable value of du [m s-1].
[in]uh_tot_0The summed transport with 0 adjustment [H m2 s-1 ~> m3 s-1 or kg s-1].
[in]duhdu_tot_0The partial derivative of du_err with du at 0 adjustment [H m ~> m2 or kg m-1].
[out]duThe barotropic velocity adjustment [m s-1].
[in]dtTime increment [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 ~> m3 s-1 or kg s-1].
obcOpen boundaries control structure.

Definition at line 728 of file MOM_continuity_PPM.F90.

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

◆ 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,
type(ocean_obc_type), optional, pointer  OBC 
)
private

Evaluates the zonal mass or volume fluxes in a layer.

Parameters
[in,out]gOcean's grid structure.
[in]uZonal velocity [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 [H ~> m or kg m-2].
[in]h_lLeft thickness [H ~> m or kg m-2].
[in]h_rRight thickness [H ~> m or kg m-2].
[in,out]uhZonal mass or volume transport [H m2 s-1 ~> m3 s-1 or kg s-1].
[in,out]duhduPartial derivative of uh with u [H m ~> m2 or kg m-1].
[in]dtTime increment [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.
obcOpen boundaries control structure.

Definition at line 545 of file MOM_continuity_PPM.F90.

545  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
546  real, dimension(SZIB_(G)), intent(in) :: u !< Zonal velocity [m s-1].
547  real, dimension(SZIB_(G)), intent(in) :: visc_rem !< Both the fraction of the
548  !! momentum originally in a layer that remains after a time-step
549  !! of viscosity, and the fraction of a time-step's worth of a barotropic
550  !! acceleration that a layer experiences after viscosity is applied.
551  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
552  real, dimension(SZI_(G)), intent(in) :: h !< Layer thickness [H ~> m or kg m-2].
553  real, dimension(SZI_(G)), intent(in) :: h_L !< Left thickness [H ~> m or kg m-2].
554  real, dimension(SZI_(G)), intent(in) :: h_R !< Right thickness [H ~> m or kg m-2].
555  real, dimension(SZIB_(G)), intent(inout) :: uh !< Zonal mass or volume
556  !! transport [H m2 s-1 ~> m3 s-1 or kg s-1].
557  real, dimension(SZIB_(G)), intent(inout) :: duhdu !< Partial derivative of uh
558  !! with u [H m ~> m2 or kg m-1].
559  real, intent(in) :: dt !< Time increment [s].
560  integer, intent(in) :: j !< Spatial index.
561  integer, intent(in) :: ish !< Start of index range.
562  integer, intent(in) :: ieh !< End of index range.
563  logical, dimension(SZIB_(G)), intent(in) :: do_I !< Which i values to work on.
564  logical, intent(in) :: vol_CFL !< If true, rescale the
565  !! ratio of face areas to the cell areas when estimating the CFL number.
566  type(ocean_OBC_type), optional, pointer :: OBC !< Open boundaries control structure.
567  ! Local variables
568  real :: CFL ! The CFL number based on the local velocity and grid spacing [nondim]
569  real :: curv_3 ! A measure of the thickness curvature over a grid length,
570  ! with the same units as h_in.
571  real :: h_marg ! The marginal thickness of a flux [H ~> m or kg m-2].
572  integer :: i
573  logical :: local_open_BC
574 
575  local_open_bc = .false.
576  if (present(obc)) then ; if (associated(obc)) then
577  local_open_bc = obc%open_u_BCs_exist_globally
578  endif ; endif
579 
580  do i=ish-1,ieh ; if (do_i(i)) then
581  ! Set new values of uh and duhdu.
582  if (u(i) > 0.0) then
583  if (vol_cfl) then ; cfl = (u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
584  else ; cfl = u(i) * dt * g%IdxT(i,j) ; endif
585  curv_3 = h_l(i) + h_r(i) - 2.0*h(i)
586  uh(i) = g%dy_Cu(i,j) * u(i) * &
587  (h_r(i) + cfl * (0.5*(h_l(i) - h_r(i)) + curv_3*(cfl - 1.5)))
588  h_marg = h_r(i) + cfl * ((h_l(i) - h_r(i)) + 3.0*curv_3*(cfl - 1.0))
589  elseif (u(i) < 0.0) then
590  if (vol_cfl) then ; cfl = (-u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
591  else ; cfl = -u(i) * dt * g%IdxT(i+1,j) ; endif
592  curv_3 = h_l(i+1) + h_r(i+1) - 2.0*h(i+1)
593  uh(i) = g%dy_Cu(i,j) * u(i) * &
594  (h_l(i+1) + cfl * (0.5*(h_r(i+1)-h_l(i+1)) + curv_3*(cfl - 1.5)))
595  h_marg = h_l(i+1) + cfl * ((h_r(i+1)-h_l(i+1)) + 3.0*curv_3*(cfl - 1.0))
596  else
597  uh(i) = 0.0
598  h_marg = 0.5 * (h_l(i+1) + h_r(i))
599  endif
600  duhdu(i) = g%dy_Cu(i,j) * h_marg * visc_rem(i)
601  endif ; enddo
602 
603  if (local_open_bc) then
604  do i=ish-1,ieh ; if (do_i(i)) then
605  if (obc%segment(obc%segnum_u(i,j))%open) then
606  if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_e) then
607  uh(i) = g%dy_Cu(i,j) * u(i) * h(i)
608  duhdu(i) = g%dy_Cu(i,j) * h(i) * visc_rem(i)
609  else
610  uh(i) = g%dy_Cu(i,j) * u(i) * h(i+1)
611  duhdu(i) = g%dy_Cu(i,j) * h(i+1) * visc_rem(i)
612  endif
613  endif
614  endif ; enddo
615  endif

◆ 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(in)  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(unit_scale_type), intent(in)  US,
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 [m s-1].
[in]h_inLayer thickness used to calculate fluxes [H ~> m or kg m-2].
[out]uhVolume flux through zonal faces = u*h*dy
[in]dtTime increment [s].
[in]usA dimensional unit scaling type
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
[in]uhbt_auxA second set of summed volume fluxes through zonal faces [H m2 s-1 ~> m3 s-1 or kg 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 [m s-1].
bt_contA structure with elements that describe the effective open face areas as a function of barotropic flow.

Definition at line 233 of file MOM_continuity_PPM.F90.

233  type(ocean_grid_type), intent(inout) :: G !< Ocean's grid structure.
234  type(verticalGrid_type), intent(in) :: GV !< Ocean's vertical grid structure.
235  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
236  intent(in) :: u !< Zonal velocity [m s-1].
237  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
238  intent(in) :: h_in !< Layer thickness used to calculate fluxes [H ~> m or kg m-2].
239  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
240  intent(out) :: uh !< Volume flux through zonal faces = u*h*dy
241  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
242  real, intent(in) :: dt !< Time increment [s].
243  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
244  type(continuity_PPM_CS), pointer :: CS !< This module's control structure.
245  type(loop_bounds_type), intent(in) :: LB !< Loop bounds structure.
246  type(ocean_OBC_type), &
247  optional, pointer :: OBC !< Open boundaries control structure.
248  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
249  optional, intent(in) :: visc_rem_u
250  !< The fraction of zonal momentum originally in a layer that remains after a
251  !! time-step of viscosity, and the fraction of a time-step's worth of a barotropic
252  !! acceleration that a layer experiences after viscosity is applied.
253  !! Non-dimensional between 0 (at the bottom) and 1 (far above the bottom).
254  real, dimension(SZIB_(G),SZJ_(G)), &
255  optional, intent(in) :: uhbt !< The summed volume flux through zonal faces
256  !! [H m2 s-1 ~> m3 s-1 or kg s-1].
257  real, dimension(SZIB_(G),SZJ_(G)), &
258  optional, intent(in) :: uhbt_aux
259  !< A second set of summed volume fluxes through zonal faces [H m2 s-1 ~> m3 s-1 or kg s-1].
260  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
261  optional, intent(out) :: u_cor
262  !< The zonal velocitiess (u with a barotropic correction)
263  !! that give uhbt as the depth-integrated transport, m s-1.
264  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
265  optional, intent(out) :: u_cor_aux
266  !< The zonal velocities (u with a barotropic correction)
267  !! that give uhbt_aux as the depth-integrated transports [m s-1].
268  type(BT_cont_type), optional, pointer :: BT_cont !< A structure with elements that describe the
269  !! effective open face areas as a function of barotropic flow.
270 
271  ! Local variables
272  real, dimension(SZIB_(G),SZK_(G)) :: duhdu ! Partial derivative of uh with u [H m ~> m2 or kg m-1].
273  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_L, h_R ! Left and right face thicknesses [H ~> m or kg m-2].
274  real, dimension(SZIB_(G)) :: &
275  du, & ! Corrective barotropic change in the velocity [m s-1].
276  du_min_CFL, & ! Min/max limits on du correction
277  du_max_CFL, & ! to avoid CFL violations
278  duhdu_tot_0, & ! Summed partial derivative of uh with u [H m ~> m2 or kg m-1].
279  uh_tot_0, & ! Summed transport with no barotropic correction [H m2 s-1 ~> m3 s-1 or kg s-1].
280  visc_rem_max ! The column maximum of visc_rem.
281  logical, dimension(SZIB_(G)) :: do_I
282  real, dimension(SZIB_(G),SZK_(G)) :: &
283  visc_rem ! A 2-D copy of visc_rem_u or an array of 1's.
284  real, dimension(SZIB_(G)) :: FAuI ! A list of sums of zonal face areas [H m ~> m2 or kg m-1].
285  real :: FA_u ! A sum of zonal face areas [H m ~> m2 or kg m-1].
286  real :: I_vrm ! 1.0 / visc_rem_max, nondim.
287  real :: CFL_dt ! The maximum CFL ratio of the adjusted velocities divided by
288  ! the time step [s-1].
289  real :: I_dt ! 1.0 / dt [s-1].
290  real :: du_lim ! The velocity change that give a relative CFL of 1 [m s-1].
291  real :: dx_E, dx_W ! Effective x-grid spacings to the east and west [m].
292  integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
293  logical :: do_aux, local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
294  logical :: local_Flather_OBC, local_open_BC, is_simple
295  type(OBC_segment_type), pointer :: segment => null()
296 
297  do_aux = (present(uhbt_aux) .and. present(u_cor_aux))
298  use_visc_rem = present(visc_rem_u)
299  local_specified_bc = .false. ; set_bt_cont = .false. ; local_flather_obc = .false.
300  local_open_bc = .false.
301  if (present(bt_cont)) set_bt_cont = (associated(bt_cont))
302  if (present(obc)) then ; if (associated(obc)) then
303  local_specified_bc = obc%specified_u_BCs_exist_globally
304  local_flather_obc = obc%Flather_u_BCs_exist_globally
305  local_open_bc = obc%open_u_BCs_exist_globally
306  endif ; endif
307  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh ; nz = g%ke
308 
309  cfl_dt = cs%CFL_limit_adjust / dt
310  i_dt = 1.0 / dt
311  if (cs%aggress_adjust) cfl_dt = i_dt
312 
313  call cpu_clock_begin(id_clock_update)
314 !$OMP parallel do default(none) shared(ish,ieh,jsh,jeh,nz,CS,h_L,h_in,h_R,G,GV,LB,visc_rem,OBC)
315  do k=1,nz
316  ! This sets h_L and h_R.
317  if (cs%upwind_1st) then
318  do j=jsh,jeh ; do i=ish-1,ieh+1
319  h_l(i,j,k) = h_in(i,j,k) ; h_r(i,j,k) = h_in(i,j,k)
320  enddo ; enddo
321  else
322  call ppm_reconstruction_x(h_in(:,:,k), h_l(:,:,k), h_r(:,:,k), g, lb, &
323  2.0*gv%Angstrom_H, cs%monotonic, simple_2nd=cs%simple_2nd, obc=obc)
324  endif
325  do i=ish-1,ieh ; visc_rem(i,k) = 1.0 ; enddo
326  enddo
327  call cpu_clock_end(id_clock_update)
328 
329  call cpu_clock_begin(id_clock_correct)
330 !$OMP parallel do default(none) shared(ish,ieh,jsh,jeh,nz,u,h_in,h_L,h_R,use_visc_rem,visc_rem_u, &
331 !$OMP uh,dt,G,GV,CS,local_specified_BC,OBC,uhbt,do_aux,set_BT_cont, &
332 !$OMP CFL_dt,I_dt,u_cor,uhbt_aux,u_cor_aux,BT_cont, local_Flather_OBC) &
333 !$OMP private(do_I,duhdu,du,du_max_CFL,du_min_CFL,uh_tot_0,duhdu_tot_0, &
334 !$OMP is_simple,FAuI,visc_rem_max,I_vrm,du_lim,dx_E,dx_W,any_simple_OBC ) &
335 !$OMP firstprivate(visc_rem)
336  do j=jsh,jeh
337  do i=ish-1,ieh ; do_i(i) = .true. ; visc_rem_max(i) = 0.0 ; enddo
338  ! Set uh and duhdu.
339  do k=1,nz
340  if (use_visc_rem) then ; do i=ish-1,ieh
341  visc_rem(i,k) = visc_rem_u(i,j,k)
342  visc_rem_max(i) = max(visc_rem_max(i), visc_rem(i,k))
343  enddo ; endif
344  call zonal_flux_layer(u(:,j,k), h_in(:,j,k), h_l(:,j,k), h_r(:,j,k), &
345  uh(:,j,k), duhdu(:,k), visc_rem(:,k), &
346  dt, g, j, ish, ieh, do_i, cs%vol_CFL, obc)
347  if (local_specified_bc) then
348  do i=ish-1,ieh
349  if (obc%segment(obc%segnum_u(i,j))%specified) &
350  uh(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k)
351  enddo
352  endif
353  enddo
354 
355  if ((.not.use_visc_rem).or.(.not.cs%use_visc_rem_max)) then ; do i=ish-1,ieh
356  visc_rem_max(i) = 1.0
357  enddo ; endif
358 
359  if (present(uhbt) .or. do_aux .or. set_bt_cont) then
360  ! Set limits on du that will keep the CFL number between -1 and 1.
361  ! This should be adequate to keep the root bracketed in all cases.
362  do i=ish-1,ieh
363  i_vrm = 0.0
364  if (visc_rem_max(i) > 0.0) i_vrm = 1.0 / visc_rem_max(i)
365  if (cs%vol_CFL) then
366  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
367  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
368  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
369  du_max_cfl(i) = 2.0* (cfl_dt * dx_w) * i_vrm
370  du_min_cfl(i) = -2.0 * (cfl_dt * dx_e) * i_vrm
371  uh_tot_0(i) = 0.0 ; duhdu_tot_0(i) = 0.0
372  enddo
373  do k=1,nz ; do i=ish-1,ieh
374  duhdu_tot_0(i) = duhdu_tot_0(i) + duhdu(i,k)
375  uh_tot_0(i) = uh_tot_0(i) + uh(i,j,k)
376  enddo ; enddo
377  if (use_visc_rem) then
378  if (cs%aggress_adjust) then
379  do k=1,nz ; do i=ish-1,ieh
380  if (cs%vol_CFL) then
381  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
382  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
383  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
384 
385  du_lim = 0.499*((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k)))
386  if (du_max_cfl(i) * visc_rem(i,k) > du_lim) &
387  du_max_cfl(i) = du_lim / visc_rem(i,k)
388 
389  du_lim = 0.499*((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k)))
390  if (du_min_cfl(i) * visc_rem(i,k) < du_lim) &
391  du_min_cfl(i) = du_lim / visc_rem(i,k)
392  enddo ; enddo
393  else
394  do k=1,nz ; do i=ish-1,ieh
395  if (cs%vol_CFL) then
396  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
397  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
398  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
399 
400  if (du_max_cfl(i) * visc_rem(i,k) > dx_w*cfl_dt - u(i,j,k)) &
401  du_max_cfl(i) = (dx_w*cfl_dt - u(i,j,k)) / visc_rem(i,k)
402  if (du_min_cfl(i) * visc_rem(i,k) < -dx_e*cfl_dt - u(i,j,k)) &
403  du_min_cfl(i) = -(dx_e*cfl_dt + u(i,j,k)) / visc_rem(i,k)
404  enddo ; enddo
405  endif
406  else
407  if (cs%aggress_adjust) then
408  do k=1,nz ; do i=ish-1,ieh
409  if (cs%vol_CFL) then
410  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
411  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
412  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
413 
414  du_max_cfl(i) = min(du_max_cfl(i), 0.499 * &
415  ((dx_w*i_dt - u(i,j,k)) + min(0.0,u(i-1,j,k))) )
416  du_min_cfl(i) = max(du_min_cfl(i), 0.499 * &
417  ((-dx_e*i_dt - u(i,j,k)) + max(0.0,u(i+1,j,k))) )
418  enddo ; enddo
419  else
420  do k=1,nz ; do i=ish-1,ieh
421  if (cs%vol_CFL) then
422  dx_w = ratio_max(g%areaT(i,j), g%dy_Cu(i,j), 1000.0*g%dxT(i,j))
423  dx_e = ratio_max(g%areaT(i+1,j), g%dy_Cu(i,j), 1000.0*g%dxT(i+1,j))
424  else ; dx_w = g%dxT(i,j) ; dx_e = g%dxT(i+1,j) ; endif
425 
426  du_max_cfl(i) = min(du_max_cfl(i), dx_w*cfl_dt - u(i,j,k))
427  du_min_cfl(i) = max(du_min_cfl(i), -(dx_e*cfl_dt + u(i,j,k)))
428  enddo ; enddo
429  endif
430  endif
431  do i=ish-1,ieh
432  du_max_cfl(i) = max(du_max_cfl(i),0.0)
433  du_min_cfl(i) = min(du_min_cfl(i),0.0)
434  enddo
435 
436  ! Up to this point, everything is shared between uhbt and uhbt_aux.
437 
438  any_simple_obc = .false.
439  if (present(uhbt) .or. do_aux .or. set_bt_cont) then
440  if (local_specified_bc .or. local_flather_obc) then ; do i=ish-1,ieh
441  ! Avoid reconciling barotropic/baroclinic transports if transport is specified
442  is_simple = obc%segment(obc%segnum_u(i,j))%specified
443  do_i(i) = .not.(obc%segnum_u(i,j) /= obc_none .and. is_simple)
444  any_simple_obc = any_simple_obc .or. is_simple
445  enddo ; else ; do i=ish-1,ieh
446  do_i(i) = .true.
447  enddo ; endif
448  endif
449 
450  if (present(uhbt)) then
451  call zonal_flux_adjust(u, h_in, h_l, h_r, uhbt(:,j), uh_tot_0, &
452  duhdu_tot_0, du, du_max_cfl, du_min_cfl, dt, g, &
453  cs, visc_rem, j, ish, ieh, do_i, .true., uh, obc=obc)
454 
455  if (present(u_cor)) then ; do k=1,nz
456  do i=ish-1,ieh ; u_cor(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ; enddo
457  if (local_specified_bc) then ; do i=ish-1,ieh
458  if (obc%segment(obc%segnum_u(i,j))%specified) &
459  u_cor(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
460  enddo ; endif
461  enddo ; endif ! u-corrected
462 
463  endif
464 
465  if (do_aux) then
466  call zonal_flux_adjust(u, h_in, h_l, h_r, uhbt_aux(:,j), uh_tot_0, &
467  duhdu_tot_0, du, du_max_cfl, du_min_cfl, dt, g, &
468  cs, visc_rem, j, ish, ieh, do_i, .false., obc=obc)
469 
470  do k=1,nz
471  do i=ish-1,ieh ; u_cor_aux(i,j,k) = u(i,j,k) + du(i) * visc_rem(i,k) ; enddo
472  if (local_specified_bc) then ; do i=ish-1,ieh
473  if (obc%segment(obc%segnum_u(i,j))%specified) &
474  u_cor_aux(i,j,k) = obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
475  enddo ; endif
476  enddo
477  endif ! do_aux
478 
479  if (set_bt_cont) then
480  call set_zonal_bt_cont(u, h_in, h_l, h_r, bt_cont, uh_tot_0, duhdu_tot_0,&
481  du_max_cfl, du_min_cfl, dt, g, us, cs, visc_rem, &
482  visc_rem_max, j, ish, ieh, do_i)
483  if (any_simple_obc) then
484  do i=ish-1,ieh
485  do_i(i) = obc%segment(obc%segnum_u(i,j))%specified
486  if (do_i(i)) faui(i) = gv%H_subroundoff*g%dy_Cu(i,j)
487  enddo
488  do k=1,nz ; do i=ish-1,ieh ; if (do_i(i)) then
489  if ((abs(obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)) > 0.0) .and. &
490  (obc%segment(obc%segnum_u(i,j))%specified)) &
491  faui(i) = faui(i) + obc%segment(obc%segnum_u(i,j))%normal_trans(i,j,k) / &
492  obc%segment(obc%segnum_u(i,j))%normal_vel(i,j,k)
493  endif ; enddo ; enddo
494  do i=ish-1,ieh ; if (do_i(i)) then
495  bt_cont%FA_u_W0(i,j) = us%m_to_L*faui(i) ; bt_cont%FA_u_E0(i,j) = us%m_to_L*faui(i)
496  bt_cont%FA_u_WW(i,j) = us%m_to_L*faui(i) ; bt_cont%FA_u_EE(i,j) = us%m_to_L*faui(i)
497  bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
498  endif ; enddo
499  endif
500  endif ! set_BT_cont
501 
502  endif ! present(uhbt) or do_aux or set_BT_cont
503  enddo ! j-loop
504  if (local_open_bc .and. set_bt_cont) then
505  do n = 1, obc%number_of_segments
506  if (obc%segment(n)%open .and. obc%segment(n)%is_E_or_W) then
507  i = obc%segment(n)%HI%IsdB
508  if (obc%segment(n)%direction == obc_direction_e) then
509  do j = obc%segment(n)%HI%Jsd, obc%segment(n)%HI%Jed
510  fa_u = 0.0
511  do k=1,nz ; fa_u = fa_u + h_in(i,j,k)*us%m_to_L*g%dy_Cu(i,j) ; enddo
512  bt_cont%FA_u_W0(i,j) = fa_u ; bt_cont%FA_u_E0(i,j) = fa_u
513  bt_cont%FA_u_WW(i,j) = fa_u ; bt_cont%FA_u_EE(i,j) = fa_u
514  bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
515  enddo
516  else
517  do j = obc%segment(n)%HI%Jsd, obc%segment(n)%HI%Jed
518  fa_u = 0.0
519  do k=1,nz ; fa_u = fa_u + h_in(i+1,j,k)*us%m_to_L*g%dy_Cu(i,j) ; enddo
520  bt_cont%FA_u_W0(i,j) = fa_u ; bt_cont%FA_u_E0(i,j) = fa_u
521  bt_cont%FA_u_WW(i,j) = fa_u ; bt_cont%FA_u_EE(i,j) = fa_u
522  bt_cont%uBT_WW(i,j) = 0.0 ; bt_cont%uBT_EE(i,j) = 0.0
523  enddo
524  endif
525  endif
526  enddo
527  endif
528  call cpu_clock_end(id_clock_correct)
529 
530  if (set_bt_cont) then ; if (allocated(bt_cont%h_u)) then
531  if (present(u_cor)) then
532  call zonal_face_thickness(u_cor, h_in, h_l, h_r, bt_cont%h_u, dt, g, lb, &
533  cs%vol_CFL, cs%marginal_faces, visc_rem_u, obc)
534  else
535  call zonal_face_thickness(u, h_in, h_l, h_r, bt_cont%h_u, dt, g, lb, &
536  cs%vol_CFL, cs%marginal_faces, visc_rem_u, obc)
537  endif
538  endif ; endif
539