rdb_ocean_metrics Module

ocean_metrics_t — the full 2D metric arrays the curvilinear ocean dyn-core reads. Coordinates are GENERATORS that fill these arrays; kernels consume the metrics only and never recompute 1/dx or dx*dy themselves.

Storage convention (mirrors the C-grid prognostic sizing exactly, nx = grid%nx_total, ny = grid%ny_total): * T (cell centre) arrays: (nx, ny) — like h_layer. * Cu (WEST u-face of T(i,j)) arrays: (nx+1, ny) — like u_face_x. * Cv (SOUTH v-face of T(i,j)) arrays: (nx, ny+1) — like v_face_y. * Bu (SW corner of T(i,j)) arrays: (nx+1, ny+1) — like f_corner. All staggers are filled INCLUDING ghost rows/columns — the metric formulae extend naturally and unfilled ghosts are a known EOS-blowup class of bug (formula bathymetry ghost-fill gotcha).

Inverses + the hvisc ratio bundle are single-sourced: computed ONCE in metrics_finalize from the arrays a generator wrote, via the Adcroft reciprocal (1/x with 0 -> 0). Kernels never recompute them: a round-trip 1/(1/dx) mismatch breaks the exact telescoping that continuity relies on (D4). areaT is load-bearing and dx*dy is dead: on supergrid / tripolar grids areaT /= dxT*dyT (D5), so areas are stored independently.

References: MOM6 grid architecture (MOM_dyn_horgrid / MOM_grid metric vocabulary, studied 2026-06-11); Adcroft reciprocal. This is an independent implementation — no source ported.


Uses

  • module~~rdb_ocean_metrics~~UsesGraph module~rdb_ocean_metrics rdb_ocean_metrics iso_fortran_env iso_fortran_env module~rdb_ocean_metrics->iso_fortran_env module~rdb_constants rdb_constants module~rdb_ocean_metrics->module~rdb_constants module~rdb_error_ring rdb_error_ring module~rdb_ocean_metrics->module~rdb_error_ring module~rdb_grid rdb_grid module~rdb_ocean_metrics->module~rdb_grid module~rdb_io_netcdf rdb_io_netcdf module~rdb_ocean_metrics->module~rdb_io_netcdf module~rdb_mem_report rdb_mem_report module~rdb_ocean_metrics->module~rdb_mem_report module~rdb_ocean_bipolar rdb_ocean_bipolar module~rdb_ocean_metrics->module~rdb_ocean_bipolar module~rdb_ocean_fold rdb_ocean_fold module~rdb_ocean_metrics->module~rdb_ocean_fold module~rdb_ocean_status rdb_ocean_status module~rdb_ocean_metrics->module~rdb_ocean_status netcdf netcdf module~rdb_ocean_metrics->netcdf pic_logger pic_logger module~rdb_ocean_metrics->pic_logger pic_strings pic_strings module~rdb_ocean_metrics->pic_strings pic_types pic_types module~rdb_constants->pic_types module~rdb_error_ring->pic_logger module~rdb_grid->module~rdb_constants module~rdb_io_netcdf->iso_fortran_env module~rdb_io_netcdf->module~rdb_constants module~rdb_io_netcdf->module~rdb_error_ring module~rdb_io_netcdf->netcdf module~rdb_io_netcdf->pic_logger module~rdb_io_netcdf->pic_strings iso_c_binding iso_c_binding module~rdb_io_netcdf->iso_c_binding module~rdb_mem_report->iso_fortran_env module~rdb_mem_report->module~rdb_constants module~rdb_mem_report->pic_logger module~rdb_mem_report->pic_strings module~rdb_ocean_bipolar->module~rdb_constants module~rdb_ocean_fold->module~rdb_constants

Used by

  • module~~rdb_ocean_metrics~~UsedByGraph module~rdb_ocean_metrics rdb_ocean_metrics module~rdb_barotropic_coupling rdb_barotropic_coupling module~rdb_barotropic_coupling->module~rdb_ocean_metrics module~rdb_coriolis_adv rdb_coriolis_adv module~rdb_barotropic_coupling->module~rdb_coriolis_adv module~rdb_ocean_bottom_drag rdb_ocean_bottom_drag module~rdb_barotropic_coupling->module~rdb_ocean_bottom_drag module~rdb_ocean_horizontal_viscosity rdb_ocean_horizontal_viscosity module~rdb_barotropic_coupling->module~rdb_ocean_horizontal_viscosity module~rdb_ocean_pressure_force rdb_ocean_pressure_force module~rdb_barotropic_coupling->module~rdb_ocean_pressure_force module~rdb_barotropic_substep rdb_barotropic_substep module~rdb_barotropic_substep->module~rdb_ocean_metrics module~rdb_ocean_fold_exchange rdb_ocean_fold_exchange module~rdb_barotropic_substep->module~rdb_ocean_fold_exchange module~rdb_ocean_halo rdb_ocean_halo module~rdb_barotropic_substep->module~rdb_ocean_halo module~rdb_continuity rdb_continuity module~rdb_continuity->module~rdb_ocean_metrics module~rdb_ocean_gm rdb_ocean_gm module~rdb_continuity->module~rdb_ocean_gm module~rdb_ocean_mle rdb_ocean_mle module~rdb_continuity->module~rdb_ocean_mle module~rdb_continuity->module~rdb_ocean_fold_exchange module~rdb_continuity->module~rdb_ocean_halo module~rdb_coriolis_adv->module~rdb_ocean_metrics module~rdb_ice_evp rdb_ice_evp module~rdb_ice_evp->module~rdb_ocean_metrics module~rdb_ice_evp->module~rdb_ocean_halo module~rdb_ice_init rdb_ice_init module~rdb_ice_init->module~rdb_ocean_metrics module~rdb_ice_ocean_coupler rdb_ice_ocean_coupler module~rdb_ice_ocean_coupler->module~rdb_ocean_metrics module~rdb_ice_transport rdb_ice_transport module~rdb_ice_transport->module~rdb_ocean_metrics module~rdb_ice_transport->module~rdb_continuity module~rdb_halo rdb_halo module~rdb_ice_transport->module~rdb_halo module~rdb_ice_transport->module~rdb_ocean_halo module~rdb_ocean_bottom_drag->module~rdb_ocean_metrics module~rdb_ocean_bt_wide rdb_ocean_bt_wide module~rdb_ocean_bt_wide->module~rdb_ocean_metrics module~rdb_ocean_bt_wide->module~rdb_barotropic_substep module~rdb_ocean_bt_wide->module~rdb_ocean_halo module~rdb_ocean_cavity_flux rdb_ocean_cavity_flux module~rdb_ocean_cavity_flux->module~rdb_ocean_metrics module~rdb_ocean_console_stats rdb_ocean_console_stats module~rdb_ocean_console_stats->module~rdb_ocean_metrics module~rdb_ocean_console_stats->module~rdb_halo module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_metrics module~rdb_ocean_dyn->module~rdb_barotropic_coupling module~rdb_ocean_dyn->module~rdb_barotropic_substep module~rdb_ocean_dyn->module~rdb_continuity module~rdb_ocean_dyn->module~rdb_coriolis_adv module~rdb_ocean_dyn->module~rdb_ocean_bottom_drag module~rdb_ocean_dyn->module~rdb_ocean_bt_wide module~rdb_ocean_dyn->module~rdb_ocean_cavity_flux module~rdb_ocean_dyn->module~rdb_ocean_console_stats module~rdb_ocean_dyn->module~rdb_ocean_gm module~rdb_ocean_hdiff_tracer rdb_ocean_hdiff_tracer module~rdb_ocean_dyn->module~rdb_ocean_hdiff_tracer module~rdb_ocean_dyn->module~rdb_ocean_horizontal_viscosity module~rdb_ocean_isopycnal_slopes rdb_ocean_isopycnal_slopes module~rdb_ocean_dyn->module~rdb_ocean_isopycnal_slopes module~rdb_ocean_ke_probe rdb_ocean_ke_probe module~rdb_ocean_dyn->module~rdb_ocean_ke_probe module~rdb_ocean_lateral_mix rdb_ocean_lateral_mix module~rdb_ocean_dyn->module~rdb_ocean_lateral_mix module~rdb_ocean_meke rdb_ocean_meke module~rdb_ocean_dyn->module~rdb_ocean_meke module~rdb_ocean_dyn->module~rdb_ocean_mle module~rdb_ocean_dyn->module~rdb_ocean_pressure_force module~rdb_ocean_redi rdb_ocean_redi module~rdb_ocean_dyn->module~rdb_ocean_redi module~rdb_ocean_varmix rdb_ocean_varmix module~rdb_ocean_dyn->module~rdb_ocean_varmix module~rdb_ocean_wave_speed rdb_ocean_wave_speed module~rdb_ocean_dyn->module~rdb_ocean_wave_speed module~rdb_ocean_bt_budget_probe rdb_ocean_bt_budget_probe module~rdb_ocean_dyn->module~rdb_ocean_bt_budget_probe module~rdb_ocean_dyn->module~rdb_ocean_halo module~rdb_ocean_engine rdb_ocean_engine module~rdb_ocean_engine->module~rdb_ocean_metrics module~rdb_ocean_engine->module~rdb_ice_evp module~rdb_ocean_engine->module~rdb_ice_init module~rdb_ocean_engine->module~rdb_ice_ocean_coupler module~rdb_ocean_engine->module~rdb_ice_transport module~rdb_ocean_engine->module~rdb_ocean_cavity_flux 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_stability_audit rdb_ocean_stability_audit module~rdb_ocean_engine->module~rdb_ocean_stability_audit module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_state module~rdb_config rdb_config module~rdb_ocean_engine->module~rdb_config module~rdb_ocean_diag_derived rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_diag_fills rdb_ocean_diag_fills module~rdb_ocean_engine->module~rdb_ocean_diag_fills module~rdb_decomp rdb_decomp module~rdb_ocean_engine->module~rdb_decomp module~rdb_ocean_data_forcing rdb_ocean_data_forcing module~rdb_ocean_engine->module~rdb_ocean_data_forcing module~rdb_ocean_data_input rdb_ocean_data_input module~rdb_ocean_engine->module~rdb_ocean_data_input module~rdb_state rdb_state module~rdb_ocean_engine->module~rdb_state module~rdb_ocean_engine->module~rdb_halo module~rdb_ocean_engine->module~rdb_ocean_fold_exchange module~rdb_ocean_engine->module~rdb_ocean_halo module~rdb_ocean_gm->module~rdb_ocean_metrics module~rdb_ocean_gm->module~rdb_ocean_isopycnal_slopes module~rdb_ocean_hdiff_tracer->module~rdb_ocean_metrics module~rdb_ocean_horizontal_viscosity->module~rdb_ocean_metrics module~rdb_ocean_horizontal_viscosity->module~rdb_ocean_lateral_mix module~rdb_ocean_isopycnal_slopes->module~rdb_ocean_metrics module~rdb_ocean_ke_probe->module~rdb_ocean_metrics module~rdb_ocean_ke_probe->module~rdb_coriolis_adv module~rdb_ocean_lateral_mix->module~rdb_ocean_metrics module~rdb_ocean_meke->module~rdb_ocean_metrics module~rdb_ocean_meke->module~rdb_ocean_gm module~rdb_ocean_meke->module~rdb_ocean_varmix module~rdb_ocean_meke->module~rdb_ocean_wave_speed module~rdb_ocean_mle->module~rdb_ocean_metrics module~rdb_ocean_pressure_force->module~rdb_ocean_metrics module~rdb_ocean_redi->module~rdb_ocean_metrics module~rdb_ocean_setup->module~rdb_ocean_metrics module~rdb_ocean_setup->module~rdb_coriolis_adv module~rdb_ocean_setup->module~rdb_ocean_bottom_drag module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_setup->module~rdb_ocean_horizontal_viscosity module~rdb_ocean_setup->module~rdb_ocean_lateral_mix module~rdb_ocean_setup->module~rdb_ocean_pressure_force module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_setup->module~rdb_config module~rdb_ocean_setup->module~rdb_decomp module~rdb_ocean_setup->module~rdb_halo module~rdb_ocean_setup->module~rdb_ocean_fold_exchange module~rdb_ocean_setup->module~rdb_ocean_halo module~rdb_ocean_stability_audit->module~rdb_ocean_metrics module~rdb_ocean_stability_audit->module~rdb_config module~rdb_ocean_state->module~rdb_ocean_metrics module~rdb_ocean_state->module~rdb_continuity module~rdb_ocean_state->module~rdb_coriolis_adv module~rdb_ocean_state->module~rdb_ocean_bottom_drag module~rdb_ocean_state->module~rdb_ocean_cavity_flux module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_ocean_state->module~rdb_ocean_gm module~rdb_ocean_state->module~rdb_ocean_hdiff_tracer module~rdb_ocean_state->module~rdb_ocean_horizontal_viscosity module~rdb_ocean_state->module~rdb_ocean_isopycnal_slopes module~rdb_ocean_state->module~rdb_ocean_lateral_mix module~rdb_ocean_state->module~rdb_ocean_meke module~rdb_ocean_state->module~rdb_ocean_mle module~rdb_ocean_state->module~rdb_ocean_pressure_force module~rdb_ocean_state->module~rdb_ocean_redi module~rdb_ocean_state->module~rdb_ocean_varmix module~rdb_ocean_state->module~rdb_ocean_wave_speed module~rdb_ocean_state->module~rdb_config module~rdb_ocean_state->module~rdb_decomp module~rdb_ocean_state->module~rdb_ocean_data_forcing module~rdb_ocean_state->module~rdb_ocean_data_input module~rdb_ocean_z_init rdb_ocean_z_init module~rdb_ocean_state->module~rdb_ocean_z_init module~rdb_ocean_restart_io rdb_ocean_restart_io module~rdb_ocean_state->module~rdb_ocean_restart_io module~rdb_ocean_varmix->module~rdb_ocean_metrics module~rdb_ocean_varmix->module~rdb_ocean_isopycnal_slopes module~rdb_ocean_varmix->module~rdb_ocean_wave_speed module~rdb_ocean_wave_speed->module~rdb_ocean_metrics module~rdb_config->module~rdb_ice_init module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_console_stats module~rdb_driver->module~rdb_ocean_dyn module~rdb_driver->module~rdb_ocean_engine module~rdb_driver->module~rdb_ocean_state module~rdb_driver->module~rdb_config module~rdb_driver->module~rdb_halo module~rdb_handle rdb_handle module~rdb_handle->module~rdb_ocean_engine module~rdb_handle->module~rdb_ocean_state module~rdb_handle->module~rdb_config 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_ocean_api->module~rdb_config module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_halo_width rdb_ocean_halo_width module~rdb_ocean_api->module~rdb_ocean_halo_width module~rdb_ocean_bt_budget_probe->module~rdb_coriolis_adv module~rdb_ocean_bt_budget_probe->module~rdb_ocean_bottom_drag module~rdb_ocean_bt_budget_probe->module~rdb_ocean_horizontal_viscosity module~rdb_ocean_bt_budget_probe->module~rdb_ocean_pressure_force 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 module~rdb_ocean_halo_width->module~rdb_coriolis_adv proc~validate_config validate_config proc~validate_config->module~rdb_coriolis_adv proc~validate_config->module~rdb_ocean_bottom_drag proc~validate_config->module~rdb_ocean_horizontal_viscosity proc~validate_config->module~rdb_ocean_lateral_mix proc~validate_config->module~rdb_ocean_pressure_force module~rdb_config_schema rdb_config_schema module~rdb_config_schema->module~rdb_config module~rdb_decomp->module~rdb_config module~rdb_ocean_data_forcing->module~rdb_config module~rdb_ocean_data_forcing->module~rdb_ocean_data_input module~rdb_ocean_data_input->module~rdb_config module~rdb_ocean_z_init->module~rdb_config module~rdb_state->module~rdb_config module~rdb_halo->module~rdb_decomp module~rdb_ocean_fold_exchange->module~rdb_decomp module~rdb_ocean_halo->module~rdb_decomp module~rdb_ocean_restart_io->module~rdb_decomp module~rdb_ocean_chksum rdb_ocean_chksum module~rdb_ocean_chksum->module~rdb_halo module~rdb_ocean_fold_apply rdb_ocean_fold_apply module~rdb_ocean_fold_apply->module~rdb_ocean_fold_exchange module~rdb_ocean_halo_state rdb_ocean_halo_state module~rdb_ocean_halo_state->module~rdb_ocean_halo proc~ocean_cavity_mass_step ocean_cavity_mass_step proc~ocean_cavity_mass_step->module~rdb_halo

Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: CORIOLIS_SCHEME_BETA_PLANE = 0

f = f_0 + beta*(y - y_ref), y from the Cartesian coordinate.

integer, public, parameter :: CORIOLIS_SCHEME_PLANETARY = 1

f = 2*omega*sin(geolat) at the respective stagger.

integer, public, parameter :: GRID_CONFIG_CARTESIAN = 0

Uniform Cartesian: every metric constant (bit-identity gate).

integer, public, parameter :: GRID_CONFIG_SPHERICAL = 1

Spherical lon-lat sector (analytic-derivative form).

integer, public, parameter :: GRID_CONFIG_SUPERGRID = 2

MOM6 supergrid (mosaic) NetCDF reader (v1 stub).

integer, public, parameter :: GRID_CONFIG_TRIPOLAR = 3

Analytic TRIPOLAR (Murray 1996): lon-lat below phi_join, bipolar Arctic cap above. See metrics_fill_tripolar.

real(kind=wp), private, parameter :: DEG2RAD = 3.14159265358979323846_wp/180.0_wp
real(kind=wp), private, parameter :: PI_WP = 3.14159265358979323846_wp

Degrees -> radians.


Derived Types

type, public ::  ocean_metrics_t

Components

Type Visibility Attributes Name Initial
real(kind=wp), public, allocatable :: angle_dx(:,:)

Grid ROTATION at T points (RADIANS), (nx,ny): the angle of the grid’s +i axis measured COUNTER-CLOCKWISE from true east — MOM6’s angle_dx convention (the mosaic stores it in degrees at every supergrid node; the T value is node (2i,2j)). It rotates a geographic (east, north) vector onto the grid axes:

Read more…
real(kind=wp), public, allocatable :: areaBu(:,:)

Bu-cell area (m^2), (nx+1,ny+1).

real(kind=wp), public, allocatable :: areaCu(:,:)

Cu-cell area (m^2), (nx+1,ny).

real(kind=wp), public, allocatable :: areaCv(:,:)

Cv-cell area (m^2), (nx,ny+1).

real(kind=wp), public, allocatable :: areaT(:,:)

T-cell area (m^2), (nx,ny).

real(kind=wp), public, allocatable :: cover_frac(:,:)

Ice-covered area fraction (nondimensional, [0,1]), same shape + gating as z_draft. v1 is BINARY, merge(1, 0, z_draft > 0); an area-blended calving front belongs to the melt work. Allocated alongside z_draft so the thermodynamic slice does not have to re-open this lifecycle.

real(kind=wp), public, allocatable :: dx2h(:,:)

dxT^2 at T (m^2), (nx,ny).

real(kind=wp), public, allocatable :: dx2q(:,:)

dxBu^2 at Bu (m^2), (nx+1,ny+1).

real(kind=wp), public, allocatable :: dxBu(:,:)

Corner (Bu) lengths (m), (nx+1,ny+1).

real(kind=wp), public, allocatable :: dxCu(:,:)

u-face (Cu) lengths (m), (nx+1,ny).

real(kind=wp), public, allocatable :: dxCv(:,:)

v-face (Cv) lengths (m), (nx,ny+1).

real(kind=wp), public, allocatable :: dxT(:,:)

Cell-centre (T) zonal/meridional grid lengths (m), (nx,ny).

real(kind=wp), public, allocatable :: dx_cv(:,:)

Open meridional width of the v-face for transport (m), (nx,ny+1). v1: filled = dxCv, separate array.

real(kind=wp), public, allocatable :: dx_cv_bt(:,:)

v-face twin, (nx,ny+1).

real(kind=wp), public, allocatable :: dx_dyBu(:,:)

dxBu/dyBu at Bu (dimensionless), (nx+1,ny+1).

real(kind=wp), public, allocatable :: dx_dyT(:,:)

dxT/dyT at T (dimensionless), (nx,ny).

real(kind=wp), public, allocatable :: dy2h(:,:)

dyT^2 at T (m^2), (nx,ny).

real(kind=wp), public, allocatable :: dy2q(:,:)

dyBu^2 at Bu (m^2), (nx+1,ny+1).

real(kind=wp), public, allocatable :: dyBu(:,:)

Corner (Bu) lengths (m), (nx+1,ny+1).

real(kind=wp), public, allocatable :: dyCu(:,:)

u-face (Cu) lengths (m), (nx+1,ny).

real(kind=wp), public, allocatable :: dyCv(:,:)

v-face (Cv) lengths (m), (nx,ny+1).

real(kind=wp), public, allocatable :: dyT(:,:)

Cell-centre (T) zonal/meridional grid lengths (m), (nx,ny).

real(kind=wp), public, allocatable :: dy_cu(:,:)

Open zonal width of the u-face for transport (m), (nx+1,ny). v1: filled = dyCu but a SEPARATE array, so the transport kernels read the right name once porous/partial cells arrive.

real(kind=wp), public, allocatable :: dy_cu_bt(:,:)

Open zonal u-face width the BAROTROPIC substep transports on (m), (nx+1,ny). ALWAYS full size and byte-equal to dy_cu unless porous barriers are on, in which case the per-step refresh scales it by the COLUMN-INTEGRATED open fraction (A(eta_top) - A(eta_bed)) / (eta_top - eta_bed), which is identically the THICKNESS-WEIGHTED MEAN of the per-layer fractions (both are the same integral of w over the column, so the identity is exact, not an approximation). Without it the barotropic solve would be porous-blind and the layer renormalisation (which drives sum_k flux_k = uhbt) would hand the blocked transport straight back.

Read more…
real(kind=wp), public, allocatable :: dy_dxBu(:,:)

dyBu/dxBu at Bu (dimensionless), (nx+1,ny+1).

real(kind=wp), public, allocatable :: dy_dxT(:,:)

dyT/dxT at T (dimensionless), (nx,ny). =1 on Cartesian.

real(kind=wp), public, allocatable :: geolatBu(:,:)

Latitude / longitude at Bu corners (degrees), (nx+1,ny+1).

real(kind=wp), public, allocatable :: geolatT(:,:)

Latitude / longitude at T points (degrees), (nx,ny).

real(kind=wp), public, allocatable :: geolonBu(:,:)

Latitude / longitude at Bu corners (degrees), (nx+1,ny+1).

real(kind=wp), public, allocatable :: geolonT(:,:)

Latitude / longitude at T points (degrees), (nx,ny).

real(kind=wp), public, allocatable :: iareaBu(:,:)

1/areaBu (1/m^2), (nx+1,ny+1).

real(kind=wp), public, allocatable :: iareaCu(:,:)

1/areaCu (1/m^2), (nx+1,ny).

real(kind=wp), public, allocatable :: iareaCv(:,:)

1/areaCv (1/m^2), (nx,ny+1).

real(kind=wp), public, allocatable :: iareaT(:,:)

1/areaT (1/m^2), (nx,ny).

real(kind=wp), public, allocatable :: idxCu(:,:)

1/dxCu, 1/dyCu (1/m), (nx+1,ny).

real(kind=wp), public, allocatable :: idxCv(:,:)

1/dxCv, 1/dyCv (1/m), (nx,ny+1).

real(kind=wp), public, allocatable :: idxT(:,:)

1/dxT, 1/dyT (1/m), (nx,ny).

real(kind=wp), public, allocatable :: idyCu(:,:)

1/dxCu, 1/dyCu (1/m), (nx+1,ny).

real(kind=wp), public, allocatable :: idyCv(:,:)

1/dxCv, 1/dyCv (1/m), (nx,ny+1).

real(kind=wp), public, allocatable :: idyT(:,:)

1/dxT, 1/dyT (1/m), (nx,ny).

logical, public :: is_init = .false.

True between init and destroy. Guard on this, never on allocated(...) (host pointer only; misses GPU mapping).

real(kind=wp), public, allocatable :: open_u(:,:,:)

u-face per-layer 0/1 OPEN mask, (nx+1,ny,nz) when use_closed_faces, (1,1,1) otherwise. 1 = the layer has water on BOTH sides of the face; 0 = it is an inert z_fixed filler on at least one side and the face is a z-LEVEL WALL for that layer (Adcroft, Hill & Marshall 1997; Losch 2008). STATIC — built once at configure by ocean_vcoord_closed_face_masks from the z_fixed target at η = 0, never refreshed (the bed and the draft are static and η is absorbed by the first live layer).

real(kind=wp), public, allocatable :: open_v(:,:,:)

v-face twin, (nx,ny+1,nz) when use_closed_faces, (1,1,1) otherwise.

Read more…
real(kind=wp), public, allocatable :: p_ice_ref(:,:)

Boussinesq-isostatic (flotation) ice load rho_ref*GRAVITY* z_draft (Pa, >= 0), same shape + gating as z_draft. Built ONCE at configure from the SAME product the FV_MOM6 surface BC forms (rho_ref*GRAVITY), which is what makes pa(nz+1) = rho_ref*g*eta_geo + p_ice_ref cancel to bit-zero at rest. Stored rather than recomputed so GRAVITY/rho_ref cannot drift between the two users. CONSUMED as the static half of multilayer_state_t%p_top = p_ice_ref + sf%p_surf — seeded in configure_ocean_cavity and rebuilt each outer step in ocean_dyn_step_split whenever the psurf seam makes sf%p_surf live. It is the load’s route into the PRESSURE (the FV_MOM6 pa(nz+1) top BC and the in-situ EOS); its route into the BAROTROPIC mode is the datum bt_H_ref = b - z_draft and nothing else, which is why it never joins sf%p_surf.

real(kind=wp), public, allocatable :: por_bed(:,:)

Static snapshot of the bottom topographic HEIGHT at cell centres (m, positive up — i.e. -barotropic%b, which is the positive-down reference depth), (nx,ny) when use_porous, (1,1) otherwise. The porous curve works in ABSOLUTE heights, so the recompute needs the bed on the same datum as por_d*; keeping a copy here makes the kernel self-contained (no barotropic-state argument threaded through the dynamics).

real(kind=wp), public, allocatable :: por_davg_u(:,:)

u-face along-face deepest / shallowest / mean topographic height (m, positive up), (nx+1,ny) when use_porous, (1,1) otherwise. Static — filled once at setup.

real(kind=wp), public, allocatable :: por_davg_v(:,:)

v-face twins, (nx,ny+1) when use_porous, (1,1) otherwise.

real(kind=wp), public, allocatable :: por_dmax_u(:,:)

u-face along-face deepest / shallowest / mean topographic height (m, positive up), (nx+1,ny) when use_porous, (1,1) otherwise. Static — filled once at setup.

real(kind=wp), public, allocatable :: por_dmax_v(:,:)

v-face twins, (nx,ny+1) when use_porous, (1,1) otherwise.

real(kind=wp), public, allocatable :: por_dmin_u(:,:)

u-face along-face deepest / shallowest / mean topographic height (m, positive up), (nx+1,ny) when use_porous, (1,1) otherwise. Static — filled once at setup.

real(kind=wp), public, allocatable :: por_dmin_v(:,:)

v-face twins, (nx,ny+1) when use_porous, (1,1) otherwise.

real(kind=wp), public, allocatable :: por_face_area_u(:,:,:)

u-face layer-averaged OPEN-AREA fraction (nondim, [0,1]), (nx+1,ny,nz) when use_porous, (1,1,1) otherwise. Recomputed every RK2 stage (interface-height dependent) and MULTIPLIED into dy_cu by the transport kernels.

real(kind=wp), public, allocatable :: por_face_area_v(:,:,:)

v-face twin, (nx,ny+1,nz) when use_porous, (1,1,1) otherwise.

integer, public :: porous_eta_interp = 0

Interface-at-velocity-point rule, a POROUS_ETA_* value (rdb_ocean_porous). 0 = MAX (the shallower interface).

real(kind=wp), public :: porous_mask_depth = 0.0_wp

Gate HEIGHT (m, positive up, <= 0): faces whose mean along-face height is at or above this stay fully open (MOM6 PORBAR_MASKING_DEPTH, sign-flipped to a height).

logical, public :: use_cavity = .false.

Master switch (&ocean_cavity_dyn_nml enable), latched in ocean_state_init_from_config BEFORE init so the allocation gate below can read it. OFF ⇒ z_draft / cover_frac / p_ice_ref stay at their (1,1) placeholder size, bt_H_ref latches the bed as it always did, and every path is byte-identical to a build without cavities.

logical, public :: use_closed_faces = .false.

Master switch (&vcoord_nml zfixed_closed_faces), latched by configure_ocean_closed_faces. OFF ⇒ open_u/open_v stay at their (1,1,1) placeholder size, no kernel branch is taken, byte-identical to a build without the feature.

logical, public :: use_porous = .false.

Master switch (&ocean_porous_nml enable). OFF ⇒ the por_face_area_* arrays stay at their (1,1,1) placeholder size and every transport kernel takes the un-narrowed dy_cu / dx_cv branch — byte-identical to a build without porous barriers.

real(kind=wp), public, allocatable :: wet_T(:,:)

T-cell wet (1) / land (0) mask, (nx,ny) — the HALO-VALID working copy of multilayer%wet_mask (periodic-wrapped + north-folded, R5a) that wet_u/wet_v/wet_q are derived from. Kept device-resident so the continuity + tracer PPM reconstruction can mirror a land neighbour’s thickness to the local cell (spec §14 C2 / MOM6’s reflected-coast PPM). All-wet domain ⇒ wet_T≡1 ⇒ mirror never triggers (no-op).

real(kind=wp), public, allocatable :: wet_q(:,:)

Corner (Bu) open mask, (nx+1,ny+1). Free-slip product of the 4 surrounding T-cells: wet_q(i,j) = wet_T(i-1,j-1)*wet_T(i,j-1)*wet_T(i-1,j)*wet_T(i,j). Consumed by the relative-vorticity / strain factor (CHUNK B).

real(kind=wp), public, allocatable :: wet_u(:,:)

u-face (Cu) open mask, (nx+1,ny). wet_u(i,j) = wet_T(i-1,j)*wet_T(i,j) — a u-face is open iff BOTH adjacent T-cells are wet. mass_flux_x(i,j) is the west face of cell (i,j) (continuity divergence reads flux(i+1)-flux(i)), so the i-1/i pairing matches dy_cu’s stagger exactly. A face of ZERO width (dy_cu = 0, the tripolar cap’s node-aligned pole columns) is closed too, wet neighbours or not — see metrics_apply_land_mask. All-wet domain without such faces ⇒ wet_u≡1 ⇒ masking is a literal no-op.

real(kind=wp), public, allocatable :: wet_v(:,:)

v-face (Cv) open mask, (nx,ny+1). wet_v(i,j) = wet_T(i,j-1)*wet_T(i,j), and 0 on a zero-width face (dx_cv = 0).

real(kind=wp), public, allocatable :: z_draft(:,:)

Prescribed STATIC ice-base depth (m, positive DOWN, >= 0), (nx_total, ny_total) INCLUDING ghosts when use_cavity, (1,1) otherwise. Filled by the formula setters in rdb_ocean_cavity immediately after the bathymetry, then carried through the SAME periodic/fold re-wrap + halo sequence barotropic%b gets (ordering is load-bearing: the draft must exist before the wet mask is seeded from b - z_draft). z_draft = 0 is open ocean — including beyond the calving front.

Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_metrics_bytes
procedure, public, non_overridable :: destroy => ocean_metrics_destroy
procedure, public, non_overridable :: enter_data => ocean_metrics_enter_data
procedure, public, non_overridable :: exit_data => ocean_metrics_exit_data
procedure, public, non_overridable :: init => ocean_metrics_init

Functions

public pure elemental function adcroft_recip(x) result(r)

Adcroft reciprocal: 1/x, but 0 -> 0 (zero-width faces give zero inverse, no NaN/Inf). Single source for every metric inverse (D4).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: x

Return Value real(kind=wp)

public pure function parse_coriolis_scheme(s) result(scheme_enum)

Map a &ocean_grid_nml coriolis_scheme string onto its enum.

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: s

Return Value integer

public pure function parse_grid_config(s) result(cfg_enum)

Map a &ocean_grid_nml grid_config string onto its enum. Unknown -> cartesian (the schema enum already validates the set; this is the canonical-name dispatch).

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: s

Return Value integer

public pure function supergrid_angle_dx_from_geography(sg_x, sg_y) result(angle_deg)

Grid rotation (DEGREES, counter-clockwise from true east — MOM6’s angle_dx sense) at every T node (2i, 2j) of a supergrid, from the node geography alone: the direction of the local +i axis is the chord from the cell’s west-face node (2i-1, 2j) to its east-face node (2i+1, 2j), projected onto a local east/north plane (dx_east = dlon*cos(lat), dy_north = dlat). Other nodes are left at zero (nothing reads them). Used where the mosaic has no angle_dx and by the analytic tripolar generator.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: sg_x(:,:)

Node longitude (degrees), (nxp, nyp).

real(kind=wp), intent(in) :: sg_y(:,:)

Node latitude (degrees), (nxp, nyp).

Return Value real(kind=wp), (size(sg_x,1),size(sg_x,2))

public pure function supergrid_top_row_folds(sg_x, sg_y) result(folds)

.true. iff the supergrid’s top node row is a TRIPOLAR FOLD LINE: every node m coincides geographically with its mirror nxp + 1 - m (MOM6’s fold pairing, T(i, nj+1) = T(ni+1-i, nj)). Points are compared as unit vectors on the sphere, so longitude is modulo 360 and irrelevant at the geographic pole (the OM_1deg fold row crosses 90N with its two copies stored at longitudes 180 deg apart). A lon-lat top row fails this everywhere except at the self-conjugate middle node, so the test cannot be passed by accident. Tolerance: a 1e-7 chord (~0.6 m on the Earth; MOM6 mosaics pair to round-off).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: sg_x(:,:)

Node longitude (degrees), (nxp, nyp).

real(kind=wp), intent(in) :: sg_y(:,:)

Node latitude (degrees), (nxp, nyp).

Return Value logical

private pure function great_circle(r, lat1, lon1, lat2, lon2) result(d)

Great-circle distance (m) between two geographic points (deg), via the haversine formula (numerically stable for short arcs).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: r
real(kind=wp), intent(in) :: lat1
real(kind=wp), intent(in) :: lon1
real(kind=wp), intent(in) :: lat2
real(kind=wp), intent(in) :: lon2

Return Value real(kind=wp)

private pure function ocean_metrics_bytes(this) result(nbytes)

Counted allocatable footprint of the grid metrics slot (0 when unallocated). One arr_bytes term per array — add a term here when a new allocatable joins the type.

Arguments

Type IntentOptional Attributes Name
class(ocean_metrics_t), intent(in) :: this

Return Value integer(kind=int64)

private pure function spherical_quad_area(r, lat1, lon1, lat2, lon2, lat3, lon3, lat4, lon4) result(area)

Area (m^2) of a spherical quadrilateral with the four corners (1,2,3,4 counter-clockwise) given in degrees, via L’Huilier’s theorem on the two triangles (1,2,3) and (1,3,4).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: r
real(kind=wp), intent(in) :: lat1
real(kind=wp), intent(in) :: lon1
real(kind=wp), intent(in) :: lat2
real(kind=wp), intent(in) :: lon2
real(kind=wp), intent(in) :: lat3
real(kind=wp), intent(in) :: lon3
real(kind=wp), intent(in) :: lat4
real(kind=wp), intent(in) :: lon4

Return Value real(kind=wp)

private pure function spherical_tri_area(r, lat1, lon1, lat2, lon2, lat3, lon3) result(area)

Area (m^2) of a spherical triangle (corners in degrees) via the spherical-excess form of L’Huilier’s theorem. Side lengths are angular (great-circle distance / r).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: r
real(kind=wp), intent(in) :: lat1
real(kind=wp), intent(in) :: lon1
real(kind=wp), intent(in) :: lat2
real(kind=wp), intent(in) :: lon2
real(kind=wp), intent(in) :: lat3
real(kind=wp), intent(in) :: lon3

Return Value real(kind=wp)

private function supergrid_io_ok(local_ierr, ierr, ncid) result(ok)

Translate a raw nc_check-style status (0 = ok) from one of the nc_* reader calls in metrics_fill_from_supergrid into the caller’s ierr contract: .true. on success; on failure, returns .false. with ierr = OCEAN_STATUS_ERR_IO when ierr is present (closing ncid first, when given, so a mid-read failure does not leak the file handle), or error stops with the SAME generic text nc_check itself would have used had the caller’s ierr never been threaded through — this is what keeps the legacy (no ierr) behaviour byte-identical while unblocking the ierr-present return path (F1/F2 of the P0.1 review).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: local_ierr
integer, intent(out), optional :: ierr
integer, intent(in), optional :: ncid

Return Value logical


Subroutines

public subroutine metrics_apply_land_mask(this, wet_mask, grid, periodic_x, periodic_y, north_fold, mask_wall_velocity, wall_west, wall_east, wall_south, wall_north)

Derive the static C-grid face / corner masks from the T-cell wet_mask and zero the face metrics at land faces, so every transport / gradient / circulation operator that rides those metrics couples across NO land face (MOM6 pre-masks the face LENGTHS; Adcroft & Hallberg 2006).

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
real(kind=wp), intent(in) :: wet_mask(:,:)

T-cell wet (1) / land (0) mask, (nx_total, ny_total).

type(hgrid_t), intent(in) :: grid
logical, intent(in) :: periodic_x

Boundary topology of wet_mask’s ghost halo (from the bc state) — selects the ghost wrap before deriving the masks.

logical, intent(in) :: periodic_y

Boundary topology of wet_mask’s ghost halo (from the bc state) — selects the ghost wrap before deriving the masks.

logical, intent(in) :: north_fold

Boundary topology of wet_mask’s ghost halo (from the bc state) — selects the ghost wrap before deriving the masks.

logical, intent(in), optional :: mask_wall_velocity

Opt-in solid-wall velocity masking (default absent ⇒ .false. ⇒ wall ghosts untouched ⇒ bit-identical to the legacy path).

logical, intent(in), optional :: wall_west

Per-edge solid-WALL flags (an edge that is NOT periodic, NOT north-fold, NOT open/OBC). Only consulted when mask_wall_velocity is .true.; each defaults to “wall” on any non-periodic / non-fold edge (the closed-default assumption).

logical, intent(in), optional :: wall_east

Per-edge solid-WALL flags (an edge that is NOT periodic, NOT north-fold, NOT open/OBC). Only consulted when mask_wall_velocity is .true.; each defaults to “wall” on any non-periodic / non-fold edge (the closed-default assumption).

logical, intent(in), optional :: wall_south

Per-edge solid-WALL flags (an edge that is NOT periodic, NOT north-fold, NOT open/OBC). Only consulted when mask_wall_velocity is .true.; each defaults to “wall” on any non-periodic / non-fold edge (the closed-default assumption).

logical, intent(in), optional :: wall_north

Per-edge solid-WALL flags (an edge that is NOT periodic, NOT north-fold, NOT open/OBC). Only consulted when mask_wall_velocity is .true.; each defaults to “wall” on any non-periodic / non-fold edge (the closed-default assumption).

public subroutine metrics_assemble_from_supergrid_arrays(this, grid, sg_x, sg_y, sg_dx, sg_dy, sg_area, periodic_x, sg_angle_dx)

Fill all model metric arrays from an in-memory MOM6-style supergrid (2x-refined corner geography + edge segments + sub-cell areas), using the even/odd index sums. This is the battle-tested assembly path the NetCDF reader used inline; the tripolar generator builds the supergrid analytically and feeds it here so tripolar metrics flow through identical index logic.

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: sg_x(:,:)
real(kind=wp), intent(in) :: sg_y(:,:)
real(kind=wp), intent(in) :: sg_dx(:,:)
real(kind=wp), intent(in) :: sg_dy(:,:)
real(kind=wp), intent(in) :: sg_area(:,:)
logical, intent(in), optional :: periodic_x

The i-direction is periodic (node column 2ni+1 IS column 1): build the seam-face Cu / Bu spans across the seam. Absent ⇒ .false. (extrapolated, byte-identical to the previous path).

real(kind=wp), intent(in), optional :: sg_angle_dx(:,:)

Supergrid-node grid rotation in DEGREES, (2ni+1, 2nj+1) (the mosaic’s angle_dx); the T value is node (2i, 2j). Absent ⇒ angle_dx stays zero (the axes are taken as east/north).

public subroutine metrics_closed_faces_alloc(this, grid, nz)

Grow the z-level closed-face masks from their (1,1,1) placeholder to full face size. Call ONLY when &vcoord_nml zfixed_closed_faces is on, at configure time — after init and BEFORE ocean_state_enter_data, so the device map captures the final shapes (a realloc after enter_data would leave the device pointing at freed host memory).

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
integer, intent(in) :: nz

Number of layers (multilayer%nz_ml).

public subroutine metrics_fill_cartesian(this, grid, dx, dy)

Uniform Cartesian: every length is constant, areaX = dx*dy. Geography is left at zero (a Cartesian beta-plane has no lat/lon — the Coriolis fill uses the Cartesian y coordinate, D7). Fills all ghost rows/columns (constants, trivially). Call metrics_finalize afterwards.

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: dx
real(kind=wp), intent(in) :: dy

public subroutine metrics_fill_coriolis(this, scheme, f_0, beta, y_ref, omega, grid, f_corner, f_centre)

Fill a corner array AND a centre array with the Coriolis parameter, from one of two schemes (D7). Does NOT touch any existing fill sites in coriolis_adv / EPBL / kappa-shear (that re-routing is M2d); this routine just exists + is tested.

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(in) :: this
integer, intent(in) :: scheme
real(kind=wp), intent(in) :: f_0
real(kind=wp), intent(in) :: beta
real(kind=wp), intent(in) :: y_ref
real(kind=wp), intent(in) :: omega
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(out) :: f_corner(:,:)

Coriolis at C-grid corners (1/s).

real(kind=wp), intent(out) :: f_centre(:,:)

|Coriolis| at cell centres (1/s).

public subroutine metrics_fill_from_supergrid(this, grid, supergrid_file, ierr, periodic_x, north_fold)

Load an MOM6 supergrid (mosaic) NetCDF file and fill all metric arrays. After this call the caller must invoke metrics_finalize to compute the inverses + hvisc ratio bundle.

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid

Grid metadata — supplies the tile (nx_phys, ny_phys, nghost, offsets) and the whole grid (nx_global, ny_global).

character(len=*), intent(in) :: supergrid_file

Path to the MOM6 mosaic supergrid NetCDF file.

integer, intent(out), optional :: ierr

Non-zero on a dimension mismatch, an unreadable/missing file, a topology mismatch, or a missing NetCDF build when present; absent behaves as today (error stop).

logical, intent(in), optional :: periodic_x

The run is periodic east-west. Absent ⇒ .false..

logical, intent(in), optional :: north_fold

The run closes the north edge with the tripolar fold. Absent ⇒ .false..

public subroutine metrics_fill_spherical(this, grid, lon_west, lat_south, dlon_deg, dlat_deg, rad_earth)

Spherical lon-lat sector. For each stagger, geolat/geolon are evaluated at THAT point’s own location; the metric lengths use the cos of that stagger’s own latitude (the consistency trick that keeps the C-grid metrics compatible, D6): dx = rad_earth * cos(lat) * dlon_rad dy = rad_earth * dlat_rad area = dx * dy (analytic-derivative form, NOT great-circle).

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: lon_west
real(kind=wp), intent(in) :: lat_south
real(kind=wp), intent(in) :: dlon_deg
real(kind=wp), intent(in) :: dlat_deg
real(kind=wp), intent(in) :: rad_earth

public subroutine metrics_fill_tripolar(this, grid, lon_west, lat_south, dlon_deg, dlat_deg, rad_earth, phi_join, lon_pole)

Fill every metric array for an analytic TRIPOLAR grid (Murray 1996): ordinary lon-lat for cell-corner latitude <= phi_join, and a conformal bipolar Arctic cap above (two grid poles at (phi_join, lon_pole) and (phi_join, lon_pole+180); see rdb_ocean_bipolar). The construction generates an in-memory MOM6-style supergrid (2x-refined corner geography, great-circle edge lengths, sub-cell areas) from the analytic map, then feeds the SAME metrics_assemble_from_supergrid_arrays index-sum path the NetCDF reader uses — so tripolar metrics flow through the battle-tested supergrid assembly. Call metrics_finalize after.

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: lon_west
real(kind=wp), intent(in) :: lat_south
real(kind=wp), intent(in) :: dlon_deg
real(kind=wp), intent(in) :: dlat_deg
real(kind=wp), intent(in) :: rad_earth
real(kind=wp), intent(in) :: phi_join
real(kind=wp), intent(in) :: lon_pole

public subroutine metrics_finalize(this)

Compute every stored inverse + the hvisc ratio bundle ONCE from the length/area arrays a generator already wrote, via the Adcroft reciprocal (D4). No kernel ever recomputes these.

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this

public subroutine metrics_fold_periodic_ghosts(this, grid, periodic_x, north_fold)

Tripolar ghost-metric fill (M4c): periodic-x wrap of the east/west ghost columns + north-fold of the north ghost rows, for EVERY metric + geography array. Replaces the constant extrapolation the supergrid assembler left on those edges. The ONE routine both the analytic tripolar generator and the MOM6 mosaic reader (metrics_fill_from_supergrid) use.

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
logical, intent(in), optional :: periodic_x

Wrap the east/west ghost columns. Absent ⇒ .true..

logical, intent(in), optional :: north_fold

Fold the north ghost rows. Absent ⇒ .true..

public subroutine metrics_porous_alloc(this, grid, nz)

Grow the porous-barrier arrays from their (1,1)/(1,1,1) placeholder size to full face size. Call ONLY when &ocean_porous_nml enable is on, at configure time — i.e. after init and BEFORE ocean_state_enter_data, so the device map captures the final shapes (a realloc after enter_data would leave the device pointing at freed host memory).

Read more…

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
integer, intent(in) :: nz

Number of layers (multilayer%nz_ml).

public subroutine tripolar_supergrid_arrays(grid, lon_west, lat_south, dlat_deg, rad_earth, phi_join, lon_pole, sg_x, sg_y, sg_dx, sg_dy, sg_area)

The in-memory MOM6-style supergrid of the analytic tripolar grid (node geography, great-circle edge lengths, spherical sub-cell areas) that metrics_fill_tripolar assembles. Public so a test can write the very same grid as a mosaic file and check that the NetCDF reader reproduces the generator’s metrics, ghosts included.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: lon_west
real(kind=wp), intent(in) :: lat_south
real(kind=wp), intent(in) :: dlat_deg
real(kind=wp), intent(in) :: rad_earth
real(kind=wp), intent(in) :: phi_join
real(kind=wp), intent(in) :: lon_pole
real(kind=wp), intent(out), allocatable :: sg_x(:,:)

Node longitude / latitude (degrees), (2ni+1, 2nj+1).

real(kind=wp), intent(out), allocatable :: sg_y(:,:)

Node longitude / latitude (degrees), (2ni+1, 2nj+1).

real(kind=wp), intent(out), allocatable :: sg_dx(:,:)

Along-i segment lengths (m), (2ni, 2nj+1).

real(kind=wp), intent(out), allocatable :: sg_dy(:,:)

Along-j segment lengths (m), (2ni+1, 2nj).

real(kind=wp), intent(out), allocatable :: sg_area(:,:)

Sub-cell areas (m^2), (2ni, 2nj).

private subroutine metrics_fill_tripolar_whole(this, grid, lon_west, lat_south, dlat_deg, rad_earth, phi_join, lon_pole)

The undecomposed tripolar build behind metrics_fill_tripolar: grid must hold the WHOLE grid (its local extents are the global ones), so the fold and the periodic seam are both local.

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: lon_west
real(kind=wp), intent(in) :: lat_south
real(kind=wp), intent(in) :: dlat_deg
real(kind=wp), intent(in) :: rad_earth
real(kind=wp), intent(in) :: phi_join
real(kind=wp), intent(in) :: lon_pole

private subroutine metrics_fold_north_cu_scalar(arr, grid)

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_fold_north_cv_scalar(arr, grid)

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_fold_north_faces(this, grid)

North fold of the face and corner metric arrays (the Cu / Cv / Bu part of metrics_fold_periodic_ghosts; the T arrays are folded there).

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid

private subroutine metrics_periodic_x_2d(arr, grid)

West/east ghost columns of a T-array (nx_total,ny_total) by periodic wrap (column i <= ng ← i+ni; i > ng+ni ← i-ni).

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_periodic_x_all(this, grid)

Periodic-x wrap of the east/west ghost columns of every metric, geography and rotation array (the first half of metrics_fold_periodic_ghosts).

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid

private subroutine metrics_periodic_x_bu(arr, grid)

Bu-array (nx_total+1,ny_total+1): face-type in x, same as Cu.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_periodic_x_cu(arr, grid)

Cu-array (nx_total+1,ny_total): faces 1..ni+1 physical at i=ng+1..ng+ni+1.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_periodic_x_cv(arr, grid)

Cv-array (nx_total,ny_total+1): centre-type in x, same as T.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_periodic_y_2d(arr, grid)

South/north ghost rows of a T-array by periodic wrap (the y analogue of metrics_periodic_x_2d). Only used by the land-mask ghost fill; the metric tripolar path wraps x only.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine metrics_window_2d(tile, whole, io, jo)

Copy a tile’s storage window (ghosts included) out of the undecomposed array: tile(i, j) = whole(i + io, j + jo). The stagger is carried by the shapes — a face/corner array is one wider on both sides, so the same offsets address it.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: tile(:,:)
real(kind=wp), intent(in) :: whole(:,:)
integer, intent(in) :: io

Global i / j offsets of the tile (grid%i/j_offset_global).

integer, intent(in) :: jo

Global i / j offsets of the tile (grid%i/j_offset_global).

private subroutine metrics_window_all(tile, whole, io, jo)

Cut a tile’s storage window (ghosts included) out of a larger assembled metric set, for every array the supergrid assembler and the fold/periodic ghost fill write: tile%X(i, j) = whole%X(i + io, j + jo). Shared by the decomposed tripolar generator (whole grid) and the decomposed supergrid reader (a full-width row band).

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: tile
type(ocean_metrics_t), intent(in) :: whole
integer, intent(in) :: io
integer, intent(in) :: jo

private subroutine ocean_metrics_destroy(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_metrics_t), intent(inout) :: this

private subroutine ocean_metrics_enter_data(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_metrics_t), intent(inout) :: this

private subroutine ocean_metrics_enter_data_impl(this)

Arrays-only attach. The parent ocean_state_t is mapped by the orchestrator BEFORE this runs.

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this

private subroutine ocean_metrics_exit_data(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_metrics_t), intent(inout) :: this

private subroutine ocean_metrics_exit_data_impl(this)

Arguments

Type IntentOptional Attributes Name
type(ocean_metrics_t), intent(inout) :: this

private subroutine ocean_metrics_init(this, grid)

Allocate + zero every metric array. Always allocates (configure runs after init, before enter_data); off-cost is ~24 (nx,ny)-class arrays (~2 MB at Tasman size).

Arguments

Type IntentOptional Attributes Name
class(ocean_metrics_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid

private subroutine supergrid_ghost_fill_2d(arr, grid)

Fill ghost rows/columns by constant extrapolation, for a T-point array (nx_total, ny_total). Interior = [ng+1, ng+ni] x [ng+1, ng+nj].

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine supergrid_ghost_fill_bu(arr, grid)

Ghost fill for Bu arrays (nx_total+1, ny_total+1). Physical i-range [ng+1, ng+ni+1], j-range [ng+1, ng+nj+1].

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine supergrid_ghost_fill_cu(arr, grid)

Ghost fill for Cu arrays (nx_total+1, ny_total). Physical i-range is [ng+1, ng+ni+1] (ni+1 faces), j-range [ng+1, ng+nj].

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private subroutine supergrid_ghost_fill_cv(arr, grid)

Ghost fill for Cv arrays (nx_total, ny_total+1). Physical i-range [ng+1, ng+ni], j-range [ng+1, ng+nj+1].

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(inout) :: arr(:,:)
type(hgrid_t), intent(in) :: grid

private pure subroutine tripolar_node_latlon(m, n, lon_west, lat_south, dlam, dlat_sg, phi_join, lat_top, lon_pole, lat, lon)

Geographic (lat, lon) of supergrid node (m,n). Below the join (lon-lat corner latitude <= phi_join) it is plain lon-lat; above, the bipolar cap map (s = fraction of the cap row span).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: m
integer, intent(in) :: n
real(kind=wp), intent(in) :: lon_west
real(kind=wp), intent(in) :: lat_south
real(kind=wp), intent(in) :: dlam
real(kind=wp), intent(in) :: dlat_sg
real(kind=wp), intent(in) :: phi_join
real(kind=wp), intent(in) :: lat_top
real(kind=wp), intent(in) :: lon_pole
real(kind=wp), intent(out) :: lat
real(kind=wp), intent(out) :: lon