rdb_ocean_obc_baroclinic Module

Open-boundary baroclinic schemes for the ocean dyn-core.

  • ocean_obc_apply_baroclinic — per-layer normal velocity at open faces. Two radiation schemes via bc%radiation_scheme: 0 (default, “anomaly”): Flather mean + zero-gradient baroclinic anomaly (bit-identical to prior behaviour). 1 (“orlanski”): per-layer implicit-upwind radiation (Orlanski 1976) with running-mean phase speed rx + optional inflow/outflow nudging toward clamped_u/v (Marchesiello et al. 2001). The continuity renorm at the wall still forces per-layer mass fluxes to sum to the BT transport, so mass/eta consistency holds regardless of scheme. RESTART CAVEAT: rx/u_prev are NOT restart-registered; a restart cold-starts the Orlanski scheme with rx = 0 / u_prev = 0.

  • ocean_obc_fill_ghosts — fills h_layer and tracer hTr open-edge ghosts (zero-gradient h, upwind-aware hTr), called before continuity_tracer_step_split.

  • ocean_obc_update_reservoirs — evolves per-edge reservoir concentrations tres toward interior/external values via implicit backward-Euler (Marchesiello et al. 2001). Called after continuity_tracer_step_split while mass_flux_* still hold the stage’s wall-face fluxes. No-op unless res_lscale_out/in > 0; when active, ocean_obc_fill_ghosts uses the reservoir value.

GPU rules: explicit-shape dummies; do concurrent j-outer/i-inner; depth-mean via sequential k-loop in the DC body (nz small); no per-step allocation; per-tracer loops OUTSIDE the DC kernels (outer-shim); never deref bc%… inside a DC body (pass rx/u_prev/tres arrays as dummies).


Uses

  • module~~rdb_ocean_obc_baroclinic~~UsesGraph module~rdb_ocean_obc_baroclinic rdb_ocean_obc_baroclinic module~rdb_barotropic_workstate rdb_barotropic_workstate module~rdb_ocean_obc_baroclinic->module~rdb_barotropic_workstate module~rdb_constants rdb_constants module~rdb_ocean_obc_baroclinic->module~rdb_constants module~rdb_grid rdb_grid module~rdb_ocean_obc_baroclinic->module~rdb_grid module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_obc_baroclinic->module~rdb_multilayer_state module~rdb_ocean_boundary_types rdb_ocean_boundary_types module~rdb_ocean_obc_baroclinic->module~rdb_ocean_boundary_types module~rdb_barotropic_workstate->module~rdb_constants module~rdb_barotropic_workstate->module~rdb_grid iso_fortran_env iso_fortran_env module~rdb_barotropic_workstate->iso_fortran_env module~rdb_mem_report rdb_mem_report module~rdb_barotropic_workstate->module~rdb_mem_report pic_types pic_types module~rdb_constants->pic_types module~rdb_grid->module~rdb_constants module~rdb_multilayer_state->module~rdb_constants module~rdb_multilayer_state->module~rdb_grid module~rdb_multilayer_state->iso_fortran_env module~rdb_efp rdb_efp module~rdb_multilayer_state->module~rdb_efp module~rdb_error_ring rdb_error_ring module~rdb_multilayer_state->module~rdb_error_ring module~rdb_multilayer_state->module~rdb_mem_report module~rdb_tracer rdb_tracer module~rdb_multilayer_state->module~rdb_tracer pic_logger pic_logger module~rdb_multilayer_state->pic_logger module~rdb_ocean_boundary_types->module~rdb_constants module~rdb_ocean_boundary_types->module~rdb_grid module~rdb_ocean_boundary_types->iso_fortran_env module~rdb_ocean_boundary_types->module~rdb_mem_report module~rdb_ocean_status rdb_ocean_status module~rdb_ocean_boundary_types->module~rdb_ocean_status module~rdb_ocean_tide_astro rdb_ocean_tide_astro module~rdb_ocean_boundary_types->module~rdb_ocean_tide_astro pic_ascii pic_ascii module~rdb_ocean_boundary_types->pic_ascii module~rdb_ocean_boundary_types->pic_logger module~rdb_efp->iso_fortran_env ieee_arithmetic ieee_arithmetic module~rdb_efp->ieee_arithmetic module~rdb_error_ring->pic_logger module~rdb_mem_report->module~rdb_constants module~rdb_mem_report->iso_fortran_env module~rdb_mem_report->pic_logger pic_strings pic_strings module~rdb_mem_report->pic_strings module~rdb_ocean_tide_astro->module~rdb_constants module~rdb_ocean_tide_astro->iso_fortran_env module~rdb_tracer->module~rdb_constants module~rdb_tracer->module~rdb_grid module~rdb_tracer->iso_fortran_env module~rdb_tracer->module~rdb_mem_report

Used by

  • module~~rdb_ocean_obc_baroclinic~~UsedByGraph module~rdb_ocean_obc_baroclinic rdb_ocean_obc_baroclinic module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_obc_baroclinic module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_dyn module~rdb_ocean_engine rdb_ocean_engine module~rdb_driver->module~rdb_ocean_engine module~rdb_ocean_state rdb_ocean_state module~rdb_driver->module~rdb_ocean_state module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_ocean_dyn module~rdb_ocean_api->module~rdb_ocean_engine module~rdb_handle rdb_handle module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_diag_derived rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_diag_fills rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_engine->module~rdb_ocean_dyn module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_diag_fills module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_handle->module~rdb_ocean_engine module~rdb_handle->module~rdb_ocean_state module~rdb_ocean_diag_derived->module~rdb_ocean_state module~rdb_ocean_diag_derived->module~rdb_ocean_diag_fills module~rdb_ocean_diag_fills->module~rdb_ocean_state

Variables

Type Visibility Attributes Name Initial
integer, private, parameter :: RAD_ANOMALY = 0

BT-mean + zero-gradient anomaly

integer, private, parameter :: RAD_ORLANSKI = 1

Orlanski 1976 per-layer radiation

real(kind=wp), private, parameter :: RES_H_MIN = 1.0e-6_wp

Functions

public pure function ocean_obc_any_open_edge(bc) result(res)

True when ANY edge TAG of the domain needs the baroclinic open-edge treatment. Reads the global tags only (never has_*), so every rank gets the same answer: callers use it to gate a COLLECTIVE seam exchange after ocean_obc_apply_baroclinic.

Arguments

Type IntentOptional Attributes Name
type(ocean_bc_state_t), intent(in) :: bc

Return Value logical

private pure function get_clamped_tracer(arr, it) result(val)

Safe accessor: return clamped_tracer(it) or 0 if unallocated/out of range.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in), allocatable :: arr(:)
integer, intent(in) :: it

Return Value real(kind=wp)

private pure function is_open_ish(bc_type) result(res)

Returns .true. for edge types that need baroclinic velocity treatment.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: bc_type

Return Value logical

private pure function is_radiating(bc_type) result(res)

Returns .true. for Flather-class edges (not CLAMPED).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: bc_type

Return Value logical

private pure function open_ghost_fill_edge(bc_type) result(res)

Edge types that receive the open zero-gradient ghost fill (velocity here, η in the barotropic substep — kept identical on purpose). OPEN / TIDAL / CHAPMAN / CLAMPED; NOT NESTED (barotropic-wall path).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: bc_type

Return Value logical


Subroutines

public subroutine ocean_obc_apply_baroclinic(grid, bc, bt_work, ms, dt)

Set per-layer normal velocity at open-ish faces after apply_bt_correction. Scheme via bc%radiation_scheme: RAD_ANOMALY (0, default): Flather mean + zero-gradient anomaly. RAD_ORLANSKI (1): per-layer implicit-upwind radiation (Orlanski 1976), running-mean phase speed rx; u_prev snapshot refreshed at END so cold-start (u_prev=0) sees rx=0 for a quiescent IC. Optional nudging (Marchesiello et al. 2001) composes AFTER either scheme when the selected tau > 0, toward the edge clamped_u/v: tau_in when incoming (dhdt·dhdx ≤ 0 Orlanski; outward vel ≤ 0 anomaly), else tau_out. CLAMPED: u_layer(wall) = clamped_u, all layers. No-op when no edge is open-ish.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_bc_state_t), intent(inout) :: bc
type(barotropic_workstate_t), intent(in) :: bt_work
type(multilayer_state_t), intent(inout) :: ms
real(kind=wp), intent(in) :: dt

Outer baroclinic timestep (seconds). Needed for nudging and Orlanski rx.

public subroutine ocean_obc_fill_ghosts(grid, bc, ms)

Fill h_layer and tracer hTr ghosts at open-ish edges. h_layer: zero-gradient (copy adjacent interior column). Tracer hTr per (j,k): outflow ⇒ ghost := interior (zero-gradient); inflow ⇒ ghost hTr := clamped_tracer(it) * h_ghost. Inflow criterion uses the per-layer wall-face velocity sign (outward-normal convention): west inflow u_wall>0, east u_wall<0, south v_wall>0, north v_wall<0. No-op when no edge is open-ish. Per-tracer loop outside the DCs.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_bc_state_t), intent(in) :: bc
type(multilayer_state_t), intent(inout) :: ms

public subroutine ocean_obc_refill_ghost_ssh(grid, bc, ms, bt_H_ref)

Re-establish a zero-gradient free surface in the open-edge GHOST columns, called at the END of the outer step (after the ALE remap) so the diagnostic manager sees a consistent halo.

Read more…

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_bc_state_t), intent(in) :: bc
type(multilayer_state_t), intent(inout) :: ms
real(kind=wp), intent(in) :: bt_H_ref(grid%nx_total,grid%ny_total)

Mode-split reference column depth (== seeded bathymetry b).

public subroutine ocean_obc_update_reservoirs(grid, bc, ms, dt)

Evolve per-edge reservoir concentrations tres one timestep. Called after continuity_tracer_step_split while ms%mass_flux_{x,y}_layer still hold the stage’s wall-face fluxes. Per open-ish edge (with allocated tres_*), per (j|i, k, tracer): u_n = sign_edge * mass_flux(wall) / max(h_int, h_min) (outward normal) Implicit backward-Euler (Marchesiello et al. 2001): c_out = max(0,u_n)dt/L_out, c_in = max(0,-u_n)dt/L_in (0 if L==0) tres = (tres + c_outT_int + c_inT_data)/(1 + c_out + c_in) Degenerate L_out==0 & u_n>0 ⇒ tres = T_int (L_in==0 & u_n<0 ⇒ T_data). T_int = hTr(int)/max(h(int),h_min); T_data = clamped_tracer(it). No-op when both length scales are zero (default path).

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_bc_state_t), intent(inout) :: bc
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in) :: dt

private pure subroutine apply_clamped_meridional_north(v_layer, nx_total, ny_total, nz, j_n, i0, i1, clamp_v)

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: clamp_v

private pure subroutine apply_clamped_meridional_south(v_layer, nx_total, ny_total, nz, j_s, i0, i1, clamp_v)

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: clamp_v

private pure subroutine apply_clamped_zonal_east(u_layer, nx_total, ny_total, nz, i_e, j0, j1, clamp_u)

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: clamp_u

private pure subroutine apply_clamped_zonal_west(u_layer, nx_total, ny_total, nz, i_w, j0, j1, clamp_u)

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: clamp_u

private pure subroutine apply_meridional_baroclinic(v_layer, h_layer, vbt_end, nx_total, ny_total, nz, i0, i1, j_s, j_n, bc_s, bc_n, clamp_v_s, clamp_v_n)

Set south and north wall-face per-layer v. Mirror of apply_zonal_baroclinic for the y-direction.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)

v_face_y_layer, shape (nx_total, ny_total+1, nz).

real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: vbt_end(nx_total,ny_total+1)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i0

first / last physical i-cell

integer, intent(in) :: i1

first / last physical i-cell

integer, intent(in) :: j_s

south / north physical wall-face indices

integer, intent(in) :: j_n

south / north physical wall-face indices

integer, intent(in) :: bc_s
integer, intent(in) :: bc_n
real(kind=wp), intent(in) :: clamp_v_s
real(kind=wp), intent(in) :: clamp_v_n

private pure subroutine apply_nudge_meridional_north(v_layer, nx_total, ny_total, nz, j_n, i0, i1, tau_in, tau_out, dt, v_data)

Post-anomaly nudging for the north edge. “Incoming” at north = v_wall < 0 ⟹ tau_in.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: v_data

private pure subroutine apply_nudge_meridional_south(v_layer, nx_total, ny_total, nz, j_s, i0, i1, tau_in, tau_out, dt, v_data)

Post-anomaly nudging for the south edge. “Incoming” at south = v_wall > 0 ⟹ tau_in.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: v_data

private pure subroutine apply_nudge_zonal_east(u_layer, nx_total, ny_total, nz, i_e, j0, j1, tau_in, tau_out, dt, u_data)

Post-anomaly nudging for the east edge. “Incoming” at east = u_wall < 0 (westward, into domain) ⟹ tau_in.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: u_data

private pure subroutine apply_nudge_zonal_west(u_layer, nx_total, ny_total, nz, i_w, j0, j1, tau_in, tau_out, dt, u_data)

Post-anomaly nudging for the west edge. “Incoming” at west = u_wall > 0 (eastward, into domain) ⟹ tau_in.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: u_data

private pure subroutine apply_orlanski_east(u_layer, rx, u_prev, nx_total, ny_total, nz, i_e, j0, j1, rx_max, gamma_u, tau_in, tau_out, dt, u_data)

Orlanski radiation for the east open edge (Orlanski 1976). Interior face index I = i_e-1 (1st), I-1 = i_e-2 (2nd). Outward normal = +x. dhdx = u(i_e-1) - u(i_e-2) (eastward gradient).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: rx(ny_total,nz)
real(kind=wp), intent(in) :: u_prev(ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: rx_max
real(kind=wp), intent(in) :: gamma_u
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: u_data

private pure subroutine apply_orlanski_north(v_layer, rx, v_prev, nx_total, ny_total, nz, j_n, i0, i1, rx_max, gamma_u, tau_in, tau_out, dt, v_data)

Orlanski radiation for the north open edge (Orlanski 1976). Interior face J = j_n-1 (1st), J-1 = j_n-2 (2nd). Outward normal = +y. dhdx = v(j_n-1) - v(j_n-2) (northward gradient).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
real(kind=wp), intent(inout) :: rx(nx_total,nz)
real(kind=wp), intent(in) :: v_prev(nx_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: rx_max
real(kind=wp), intent(in) :: gamma_u
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: v_data

private pure subroutine apply_orlanski_south(v_layer, rx, v_prev, nx_total, ny_total, nz, j_s, i0, i1, rx_max, gamma_u, tau_in, tau_out, dt, v_data)

Orlanski radiation for the south open edge (Orlanski 1976). Interior face J = j_s+1 (1st), J-1 = j_s+2 (2nd). Outward normal = -y. dhdx = v(j_s+1) - v(j_s+2) (southward gradient).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
real(kind=wp), intent(inout) :: rx(nx_total,nz)
real(kind=wp), intent(in) :: v_prev(nx_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: rx_max
real(kind=wp), intent(in) :: gamma_u
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: v_data

private pure subroutine apply_orlanski_west(u_layer, rx, u_prev, nx_total, ny_total, nz, i_w, j0, j1, rx_max, gamma_u, tau_in, tau_out, dt, u_data)

Orlanski radiation for the west open edge (Orlanski 1976). Interior face index I = i_w+1 (1st), I-1 = i_w+2 (2nd). Outward normal = -x. dhdx = u(i_w+1) - u(i_w+2) (westward gradient). rx updated in-place; u_prev NOT updated here (done by the caller after all edges are set).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: rx(ny_total,nz)
real(kind=wp), intent(in) :: u_prev(ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: rx_max
real(kind=wp), intent(in) :: gamma_u
real(kind=wp), intent(in) :: tau_in
real(kind=wp), intent(in) :: tau_out
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: u_data

private pure subroutine apply_zonal_baroclinic(u_layer, h_layer, ubt_end, nx_total, ny_total, nz, i_w, i_e, j0, j1, bc_w, bc_e, clamp_u_w, clamp_u_e)

Set west and east wall-face per-layer u to Flather mean + zero-gradient baroclinic anomaly (radiating edges) or uniform clamped_u (CLAMPED edge). Explicit-shape dummies; one do concurrent per edge (j outer, k inner).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)

u_face_x_layer, shape (nx_total+1, ny_total, nz).

real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: ubt_end(nx_total+1,ny_total)

bt_ubt_end, shape (nx_total+1, ny_total).

integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w

west / east physical wall-face indices

integer, intent(in) :: i_e

west / east physical wall-face indices

integer, intent(in) :: j0

first / last physical j-cell

integer, intent(in) :: j1

first / last physical j-cell

integer, intent(in) :: bc_w
integer, intent(in) :: bc_e
real(kind=wp), intent(in) :: clamp_u_w
real(kind=wp), intent(in) :: clamp_u_e

private pure subroutine fill_ghost_east_res(hTr, h_layer, tres_e, nx_total, ny_total, nz, i_e, j0, j1, nghost, it, n_tr)

Reservoir-based ghost fill, east edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: tres_e(ny_total,nz,n_tr)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1
integer, intent(in) :: nghost
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine fill_ghost_east_sign(hTr, h_layer, u_layer, nx_total, ny_total, nz, i_e, j0, j1, nghost, clamped_tr_e)

Sign-switch ghost fill for the east edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1
integer, intent(in) :: nghost
real(kind=wp), intent(in) :: clamped_tr_e

private pure subroutine fill_ghost_north_res(hTr, h_layer, tres_n, nx_total, ny_total, nz, j_n, i0, i1, nghost, it, n_tr)

Reservoir-based ghost fill, north edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: tres_n(nx_total,nz,n_tr)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1
integer, intent(in) :: nghost
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine fill_ghost_north_sign(hTr, h_layer, v_layer, nx_total, ny_total, nz, j_n, i0, i1, nghost, clamped_tr_n)

Sign-switch ghost fill for the north edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1
integer, intent(in) :: nghost
real(kind=wp), intent(in) :: clamped_tr_n

private pure subroutine fill_ghost_south_res(hTr, h_layer, tres_s, nx_total, ny_total, nz, j_s, i0, i1, nghost, it, n_tr)

Reservoir-based ghost fill, south edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: tres_s(nx_total,nz,n_tr)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1
integer, intent(in) :: nghost
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine fill_ghost_south_sign(hTr, h_layer, v_layer, nx_total, ny_total, nz, j_s, i0, i1, nghost, clamped_tr_s)

Sign-switch ghost fill for the south edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1
integer, intent(in) :: nghost
real(kind=wp), intent(in) :: clamped_tr_s

private pure subroutine fill_ghost_west_res(hTr, h_layer, tres_w, nx_total, ny_total, nz, i_w, j0, j1, nghost, it, n_tr)

Reservoir-based ghost fill, west edge. hTr_ghost = tres_w(j, k, it) * h_ghost — unconditional.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: tres_w(ny_total,nz,n_tr)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1
integer, intent(in) :: nghost
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine fill_ghost_west_sign(hTr, h_layer, u_layer, nx_total, ny_total, nz, i_w, j0, j1, nghost, clamped_tr_w)

Sign-switch ghost fill for the west edge.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1
integer, intent(in) :: nghost
real(kind=wp), intent(in) :: clamped_tr_w

private pure subroutine fill_h_layer_ghosts(h_layer, nx_total, ny_total, nz, i_w, i_e, j_s, j_n, nghost, bc_w, bc_e, bc_s, bc_n)

Zero-gradient fill of h_layer ghosts at open-ish edges.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: h_layer(nx_total,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: i_e
integer, intent(in) :: j_s
integer, intent(in) :: j_n
integer, intent(in) :: nghost
integer, intent(in) :: bc_w
integer, intent(in) :: bc_e
integer, intent(in) :: bc_s
integer, intent(in) :: bc_n

private pure subroutine fill_tracer_ghosts_meridional(hTr, h_layer, v_layer, nx_total, ny_total, nz, i_w, i_e, j_s, j_n, nghost, bc_s, bc_n, clamped_tr_s, clamped_tr_n)

Upwind-aware tracer ghost fill for south and north open edges.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: i_e
integer, intent(in) :: j_s
integer, intent(in) :: j_n
integer, intent(in) :: nghost
integer, intent(in) :: bc_s
integer, intent(in) :: bc_n
real(kind=wp), intent(in) :: clamped_tr_s
real(kind=wp), intent(in) :: clamped_tr_n

private pure subroutine fill_tracer_ghosts_zerograd(hTr, h_layer, nx_total, ny_total, nz, i_w, i_e, j_s, j_n, nghost, bc_w, bc_e, bc_s, bc_n)

Zero-gradient CONCENTRATION fill of a tracer’s hTr ghosts at open-ish edges over the FULL cross-extent (ghost×ghost corners included): hTr_ghost = (hTr_int / h_int) * h_ghost. Runs BEFORE the upwind-aware per-edge fill, so corners keep this zero-gradient value (no corner T/S blow-up under inflow). Same gating/corner coverage as fill_h_layer_ghosts.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: i_e
integer, intent(in) :: j_s
integer, intent(in) :: j_n
integer, intent(in) :: nghost
integer, intent(in) :: bc_w
integer, intent(in) :: bc_e
integer, intent(in) :: bc_s
integer, intent(in) :: bc_n

private pure subroutine fill_tracer_ghosts_zonal(hTr, h_layer, u_layer, nx_total, ny_total, nz, i_w, i_e, j_s, j_n, nghost, bc_w, bc_e, clamped_tr_w, clamped_tr_e)

Upwind-aware tracer ghost fill for west and east open edges. West inflow : u(i_w,j,k) > 0 → ghost = clamped_tr * h_ghost West outflow : u(i_w,j,k) <= 0 → ghost = interior (zero-gradient) East inflow : u(i_e,j,k) < 0 East outflow : u(i_e,j,k) >= 0

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: u_layer(nx_total+1,ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: i_e
integer, intent(in) :: j_s
integer, intent(in) :: j_n
integer, intent(in) :: nghost
integer, intent(in) :: bc_w
integer, intent(in) :: bc_e
real(kind=wp), intent(in) :: clamped_tr_w
real(kind=wp), intent(in) :: clamped_tr_e

private pure subroutine fill_uv_layer_ghosts(u_layer, v_layer, nx_total, ny_total, nz, nghost, nx_phys, ny_phys, bc_w, bc_e, bc_s, bc_n)

Zero-gradient fill of per-layer face velocities into the OPEN-edge ghost region, corners included. u_layer (nx_total+1, ny_total, nz); v_layer (nx_total, ny_total+1, nz). x-pass over the full cross extent; y-pass clipped to the physical span unless the adjacent x-edge is open. Gated on open-ish tags ⇒ WALL/PERIODIC ⇒ no DC ⇒ bit-identical.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: u_layer(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: v_layer(nx_total,ny_total+1,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: nghost
integer, intent(in) :: nx_phys
integer, intent(in) :: ny_phys
integer, intent(in) :: bc_w
integer, intent(in) :: bc_e
integer, intent(in) :: bc_s
integer, intent(in) :: bc_n

private pure subroutine refill_h_ghost_scaled(h_layer, bt_H_ref, nx_total, ny_total, nz, i_w, i_e, j_s, j_n, nghost, bc_w, bc_e, bc_s, bc_n)

Overwrite open-edge h_layer ghost columns with the nearest interior column scaled so Σ_k h_ghost = bt_H_ref(ghost) + η_interior (η_interior = Σ_k h_int − bt_H_ref(int)). x-pass (west/east) over the full j extent (covers corner rows); y-pass (south/north) over the full i extent, reading the already x-filled corner columns — same corner-coverage order as fill_h_layer_ghosts.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: bt_H_ref(nx_total,ny_total)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: i_e
integer, intent(in) :: j_s
integer, intent(in) :: j_n
integer, intent(in) :: nghost
integer, intent(in) :: bc_w
integer, intent(in) :: bc_e
integer, intent(in) :: bc_s
integer, intent(in) :: bc_n

private pure subroutine snapshot_u_prev_east(u_layer, u_prev, nx_total, ny_total, nz, i_e, j0, j1)

Snapshot u at the first interior face (i_e-1) into u_prev_east.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: u_layer(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: u_prev(ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1

private pure subroutine snapshot_u_prev_west(u_layer, u_prev, nx_total, ny_total, nz, i_w, j0, j1)

Snapshot u at the first interior face (i_w+1) into u_prev_west.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: u_layer(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: u_prev(ny_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1

private pure subroutine snapshot_v_prev_north(v_layer, v_prev, nx_total, ny_total, nz, j_n, i0, i1)

Snapshot v at the first interior face (j_n-1) into u_prev_north.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: v_layer(nx_total,ny_total+1,nz)
real(kind=wp), intent(inout) :: v_prev(nx_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1

private pure subroutine snapshot_v_prev_south(v_layer, v_prev, nx_total, ny_total, nz, j_s, i0, i1)

Snapshot v at the first interior face (j_s+1) into u_prev_south.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: v_layer(nx_total,ny_total+1,nz)
real(kind=wp), intent(inout) :: v_prev(nx_total,nz)
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1

private pure subroutine update_reservoir_meridional_north(hTr, h_layer, mass_flux_y, tres_n, T_data, nx_total, ny_total, nz, j_n, i0, i1, L_out, L_in, dt, it, n_tr)

Update reservoir for the north open edge. Wall-face index = j_n+1; interior cell = j_n. Outward normal = +y: u_n = +mass_flux_y(i,j_n+1,k)/max(h,hmin).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: mass_flux_y(nx_total,ny_total+1,nz)
real(kind=wp), intent(inout) :: tres_n(nx_total,nz,n_tr)
real(kind=wp), intent(in) :: T_data
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_n
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: L_out
real(kind=wp), intent(in) :: L_in
real(kind=wp), intent(in) :: dt
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine update_reservoir_meridional_south(hTr, h_layer, mass_flux_y, tres_s, T_data, nx_total, ny_total, nz, j_s, i0, i1, L_out, L_in, dt, it, n_tr)

Update reservoir for the south open edge. Wall-face index = j_s; interior cell = j_s. Outward normal = -y: u_n = -mass_flux_y(i,j_s,k)/max(h,hmin).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: mass_flux_y(nx_total,ny_total+1,nz)
real(kind=wp), intent(inout) :: tres_s(nx_total,nz,n_tr)
real(kind=wp), intent(in) :: T_data
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: j_s
integer, intent(in) :: i0
integer, intent(in) :: i1
real(kind=wp), intent(in) :: L_out
real(kind=wp), intent(in) :: L_in
real(kind=wp), intent(in) :: dt
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine update_reservoir_zonal_east(hTr, h_layer, mass_flux_x, tres_e, T_data, nx_total, ny_total, nz, i_e, j0, j1, L_out, L_in, dt, it, n_tr)

Update reservoir for the east open edge. Wall-face index for mass flux = i_e+1 (east face of the last physical cell i_e). Interior cell = i_e. Outward normal at east = +x: u_n = +mass_flux_x(i_e+1,j,k)/max(h,hmin).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: mass_flux_x(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: tres_e(ny_total,nz,n_tr)
real(kind=wp), intent(in) :: T_data
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_e
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: L_out
real(kind=wp), intent(in) :: L_in
real(kind=wp), intent(in) :: dt
integer, intent(in) :: it
integer, intent(in) :: n_tr

private pure subroutine update_reservoir_zonal_west(hTr, h_layer, mass_flux_x, tres_w, T_data, nx_total, ny_total, nz, i_w, j0, j1, L_out, L_in, dt, it, n_tr)

Update reservoir for the west open edge. Wall-face/interior cell = i_w. Outward normal = -x: u_n = -mass_flux_x(i_w,j,k)/max(h,hmin).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: hTr(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: h_layer(nx_total,ny_total,nz)
real(kind=wp), intent(in) :: mass_flux_x(nx_total+1,ny_total,nz)
real(kind=wp), intent(inout) :: tres_w(ny_total,nz,n_tr)
real(kind=wp), intent(in) :: T_data
integer, intent(in) :: nx_total
integer, intent(in) :: ny_total
integer, intent(in) :: nz
integer, intent(in) :: i_w
integer, intent(in) :: j0
integer, intent(in) :: j1
real(kind=wp), intent(in) :: L_out
real(kind=wp), intent(in) :: L_in
real(kind=wp), intent(in) :: dt
integer, intent(in) :: it
integer, intent(in) :: n_tr