Post-parse Cartesian domain sizing (MOM6 GRID_CONFIG=”cartesian” +
AXIS_UNITS / LENLON / LENLAT). When &ocean_grid_nml len_lon/len_lat
are set (> 0) on an ocean Cartesian grid, DERIVE the uniform
&grid_nml dx/dy (metres) from the domain extent, the physical cell
count (nx/ny = MOM6 NIGLOBAL/NJGLOBAL) and axis_units, exactly as
MOM6’s set_grid_metrics_cartesian:
degrees : dx = rad_earth · len_lon · π/180 / nx (arc length, no cos(lat))
km : dx = 1000 · len_lon / nx
meters : dx = len_lon / nx
and likewise dy from len_lat / ny. This runs BEFORE grid init, so the
metrics, barotropic CFL and Coriolis all see the derived metres.
Default (len_lon <= 0) leaves dx/dy untouched ⇒ bit-identical.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(config_t), | intent(inout) | :: | cfg |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | dx_scale | ||||
| real(kind=wp), | private | :: | dy_scale |
subroutine apply_cartesian_degrees(cfg) !! Post-parse Cartesian domain sizing (MOM6 GRID_CONFIG="cartesian" + !! AXIS_UNITS / LENLON / LENLAT). When `&ocean_grid_nml len_lon`/`len_lat` !! are set (> 0) on an ocean Cartesian grid, DERIVE the uniform !! `&grid_nml dx`/`dy` (metres) from the domain extent, the physical cell !! count (`nx`/`ny` = MOM6 NIGLOBAL/NJGLOBAL) and `axis_units`, exactly as !! MOM6's `set_grid_metrics_cartesian`: !! degrees : dx = rad_earth · len_lon · π/180 / nx (arc length, no cos(lat)) !! km : dx = 1000 · len_lon / nx !! meters : dx = len_lon / nx !! and likewise dy from len_lat / ny. This runs BEFORE grid init, so the !! metrics, barotropic CFL and Coriolis all see the derived metres. !! Default (len_lon <= 0) leaves `dx`/`dy` untouched ⇒ bit-identical. type(config_t), intent(inout) :: cfg real(wp) :: dx_scale, dy_scale ! Opt-in: only engage when the extent knobs are set. if (cfg%ocean%grid%len_lon <= 0.0_wp .and. cfg%ocean%grid%len_lat <= 0.0_wp) return if (trim(cfg%sim_type) /= "ocean") then call logger%error("len_lon/len_lat are &ocean_grid_nml knobs; "// & "set sim_type='ocean' to use them") return end if if (trim(cfg%ocean%grid%grid_config) /= "cartesian") then call logger%error("len_lon/len_lat (MOM6 LENLON/LENLAT) apply to "// & "grid_config='cartesian' only (got '"// & trim(cfg%ocean%grid%grid_config)//"'); the spherical/"// & "tripolar paths already read &grid_nml dx/dy as degrees") return end if if (cfg%ocean%grid%len_lon <= 0.0_wp .or. cfg%ocean%grid%len_lat <= 0.0_wp) then call logger%error("len_lon AND len_lat must both be > 0 to size the "// & "Cartesian domain (got len_lon="// & to_string(cfg%ocean%grid%len_lon)//", len_lat="// & to_string(cfg%ocean%grid%len_lat)//")") return end if ! Per-unit metres-per-degree/km/metre scale (applied to len/N below). select case (trim(cfg%ocean%grid%axis_units)) case ("meters", "meter", "m") dx_scale = 1.0_wp dy_scale = 1.0_wp case ("km", "kilometer", "kilometers") dx_scale = 1000.0_wp dy_scale = 1000.0_wp case ("degrees", "degree", "deg") ! Arc length on a sphere of radius rad_earth; NO cos(lat) — MOM6's ! Cartesian grid is a flat plane, unlike its spherical grid. dx_scale = cfg%ocean%grid%rad_earth*DEG2RAD dy_scale = cfg%ocean%grid%rad_earth*DEG2RAD case default call logger%error("Invalid axis_units = '"// & trim(cfg%ocean%grid%axis_units)// & "': must be meters/degrees/km") return end select cfg%dx = dx_scale*cfg%ocean%grid%len_lon/real(cfg%nx, wp) cfg%dy = dy_scale*cfg%ocean%grid%len_lat/real(cfg%ny, wp) call logger%info("Cartesian domain sized from extent (MOM6-style): len_lon="// & to_string(cfg%ocean%grid%len_lon)//", len_lat="// & to_string(cfg%ocean%grid%len_lat)//" "// & trim(cfg%ocean%grid%axis_units)//" over "// & to_string(cfg%nx)//"x"//to_string(cfg%ny)//" cells => dx="// & to_string(cfg%dx)//" m, dy="//to_string(cfg%dy)//" m") end subroutine apply_cartesian_degrees