Fill the ocean_metrics_t slot per cfg%ocean%grid%grid_config,
then single-source the inverses + hvisc ratio bundle
(metrics_finalize). Must run BEFORE ocean_state_enter_data
(the host fill is what the GPU copyin captures). For
“spherical”, the &grid_nml dx/dy are reinterpreted as
dlon/dlat in degrees.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(config_t), | intent(in) | :: | cfg | |||
| type(ocean_state_t), | intent(inout) | :: | ocean_state | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in) | :: | compute_rank | |||
| integer, | intent(out), | optional | :: | ierr |
Non-zero on a grid/geometry configuration failure when present;
absent behaves as today ( |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | gc | ||||
| integer, | private | :: | local_ierr |
subroutine configure_ocean_metrics(cfg, ocean_state, grid, compute_rank, ierr) !! Fill the `ocean_metrics_t` slot per `cfg%ocean%grid%grid_config`, !! then single-source the inverses + hvisc ratio bundle !! (`metrics_finalize`). Must run BEFORE `ocean_state_enter_data` !! (the host fill is what the GPU copyin captures). For !! "spherical", the `&grid_nml dx`/`dy` are reinterpreted as !! dlon/dlat in degrees. type(config_t), intent(in) :: cfg type(ocean_state_t), intent(inout) :: ocean_state type(hgrid_t), intent(in) :: grid integer, intent(in) :: compute_rank integer, intent(out), optional :: ierr !! Non-zero on a grid/geometry configuration failure when present; !! absent behaves as today (`error stop`). integer :: gc, local_ierr gc = parse_grid_config(cfg%ocean%grid%grid_config) select case (gc) case (GRID_CONFIG_SPHERICAL) ! Validation the schema can't express (cross-knob domain check). if (cfg%ocean%grid%rad_earth <= 0.0_wp) then call fail("configure_ocean_metrics: spherical grid needs rad_earth > 0", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! Include ghost rows: the generator fills ghost rows beyond the physical ! edge by formula (see metrics_fill_spherical), so the most extreme ! latitude reached is lat_south - (nghost+0.5)*dlat (south ghost centre) ! and lat_south + (ny_phys+nghost+0.5)*dlat (north ghost centre). ! Near-pole sectors need tripolar treatment (M3 follow-up). if (cfg%ocean%grid%lat_south - (real(grid%nghost, wp) + 0.5_wp)*grid%dy < -90.0_wp .or. & cfg%ocean%grid%lat_south + real(grid%ny_phys + grid%nghost, wp)*grid%dy + & 0.5_wp*grid%dy > 90.0_wp) then call fail("configure_ocean_metrics: spherical domain (including ghost rows) "// & "exceeds |lat| <= 90. Near-pole sectors need tripolar treatment (M3).", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! grid%dx / grid%dy are dlon / dlat in DEGREES here. call metrics_fill_spherical(ocean_state%metrics, grid, & cfg%ocean%grid%lon_west, cfg%ocean%grid%lat_south, & grid%dx, grid%dy, cfg%ocean%grid%rad_earth) if (compute_rank == 0) then call logger%info("Grid config: spherical lon-lat sector") end if case (GRID_CONFIG_SUPERGRID) if (len_trim(cfg%ocean%grid%supergrid_file) == 0) then call fail("configure_ocean_metrics: grid_config='supergrid' "// & "requires supergrid_file to be set in &ocean_grid_nml", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! ierr threaded down ONLY when THIS routine's own ierr is ! present: otherwise metrics_fill_from_supergrid must keep ! reaching its own `error stop` (specific dimension-mismatch / ! NetCDF-failure text) rather than the generic wrapper message ! below (P0.1 review F2). ! ! The edge tags decide the ghost-metric topology (periodic-x wrap, ! tripolar fold) exactly as they do for the analytic tripolar; the ! reader cross-checks the fold against the file's own top row. if (present(ierr)) then call metrics_fill_from_supergrid(ocean_state%metrics, grid, & cfg%ocean%grid%supergrid_file, ierr=local_ierr, & periodic_x=tags_periodic_x(cfg), & north_fold=tags_north_fold(cfg)) if (local_ierr /= 0) then ierr = local_ierr return end if else call metrics_fill_from_supergrid(ocean_state%metrics, grid, & cfg%ocean%grid%supergrid_file, & periodic_x=tags_periodic_x(cfg), & north_fold=tags_north_fold(cfg)) end if if (compute_rank == 0) then call logger%info("Grid config: supergrid (mosaic) from "// & trim(cfg%ocean%grid%supergrid_file)) end if case (GRID_CONFIG_TRIPOLAR) ! Cross-knob domain checks the schema can't express. if (cfg%ocean%grid%rad_earth <= 0.0_wp) then call fail("configure_ocean_metrics: tripolar grid needs rad_earth > 0", ierr, OCEAN_STATUS_ERR_SETUP) return end if if (cfg%ocean%grid%phi_join <= cfg%ocean%grid%lat_south) then call fail("configure_ocean_metrics: tripolar phi_join must be "// & "north of lat_south (the cap sits above the lon-lat region)", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! Tripolar requires an east-west PERIODIC grid: the i-direction ! wraps the full 360 deg of pseudo-longitude and the north fold ! identifies the two halves of the top row. Without periodic-x ! the wrap + fold exchange (M4c) is ill-defined. if (trim(cfg%ocean%bc%west) /= "periodic" .or. & trim(cfg%ocean%bc%east) /= "periodic") then call fail("configure_ocean_metrics: grid_config='tripolar' requires "// & "periodic east-west BCs (&ocean_bc_nml west='periodic' east='periodic')", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! A tripolar grid MUST close the top with the north fold; otherwise ! the duplicated top-row DOFs are never reconciled and the cap ! diverges. (The reverse — fold tag requires a tripolar grid — is ! enforced by ocean_bc_validate_fold's periodic-w/e requirement plus ! this check.) if (trim(cfg%ocean%bc%north) /= "tripolar_fold") then call fail("configure_ocean_metrics: grid_config='tripolar' requires "// & "north='tripolar_fold' (&ocean_bc_nml north='tripolar_fold')", ierr, OCEAN_STATUS_ERR_SETUP) return end if ! grid%dx / grid%dy are dlon / dlat in DEGREES here (as spherical). call metrics_fill_tripolar(ocean_state%metrics, grid, & cfg%ocean%grid%lon_west, cfg%ocean%grid%lat_south, & grid%dx, grid%dy, cfg%ocean%grid%rad_earth, & cfg%ocean%grid%phi_join, cfg%ocean%grid%lon_pole) if (compute_rank == 0) then call logger%info("Grid config: tripolar (Murray 1996), phi_join="// & to_string(cfg%ocean%grid%phi_join)//" lon_pole="// & to_string(cfg%ocean%grid%lon_pole)) end if case default ! GRID_CONFIG_CARTESIAN call metrics_fill_cartesian(ocean_state%metrics, grid, grid%dx, grid%dy) end select call metrics_finalize(ocean_state%metrics) if (present(ierr)) ierr = OCEAN_STATUS_OK end subroutine configure_ocean_metrics