roms-tools 1.6.2__py3-none-any.whl → 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ci/environment.yml +1 -1
- roms_tools/__init__.py +1 -0
- roms_tools/_version.py +1 -1
- roms_tools/setup/boundary_forcing.py +266 -256
- roms_tools/setup/datasets.py +986 -231
- roms_tools/setup/download.py +41 -15
- roms_tools/setup/grid.py +561 -512
- roms_tools/setup/initial_conditions.py +162 -106
- roms_tools/setup/mask.py +69 -0
- roms_tools/setup/plot.py +81 -23
- roms_tools/setup/regrid.py +4 -2
- roms_tools/setup/river_forcing.py +589 -0
- roms_tools/setup/surface_forcing.py +21 -130
- roms_tools/setup/tides.py +15 -79
- roms_tools/setup/topography.py +92 -128
- roms_tools/setup/utils.py +307 -25
- roms_tools/setup/vertical_coordinate.py +5 -16
- roms_tools/tests/test_setup/test_boundary_forcing.py +10 -7
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zmetadata +157 -130
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/abs_time/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/bry_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/month/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/month/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/month/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +39 -12
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/abs_time/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/month/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/month/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/month/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +0 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +56 -201
- roms_tools/tests/test_setup/test_data/grid.zarr/Cs_r/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/Cs_w/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/{interface_depth_rho → sigma_r}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_r/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_r/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/{interface_depth_u → sigma_w}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/sigma_w/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +1 -2
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +58 -203
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/Cs_r/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/Cs_w/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/{grid.zarr/interface_depth_v → grid_that_straddles_dateline.zarr/sigma_r}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_r/0 +0 -0
- roms_tools/tests/test_setup/test_data/{grid.zarr/layer_depth_rho → grid_that_straddles_dateline.zarr/sigma_w}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/sigma_w/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/.zattrs +3 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/.zgroup +3 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/.zmetadata +214 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/abs_time/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/abs_time/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/abs_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/month/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/month/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/month/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_name/.zarray +24 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_name/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_name/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_time/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_time/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/{grid.zarr/layer_depth_v → river_forcing.zarr/river_tracer}/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_tracer/.zattrs +10 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_tracer/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_volume/.zarray +22 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_volume/.zattrs +9 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/river_volume/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/{grid.zarr/layer_depth_u → river_forcing.zarr/tracer_name}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/tracer_name/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing.zarr/tracer_name/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zgroup +3 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +185 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/abs_time/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/abs_time/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/abs_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_name/.zarray +24 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_name/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_name/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_time/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_time/.zattrs +7 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/{grid_that_straddles_dateline.zarr/interface_depth_v → river_forcing_no_climatology.zarr/river_tracer}/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/.zattrs +10 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_volume/.zarray +22 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_volume/.zattrs +9 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_volume/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/{grid_that_straddles_dateline.zarr/interface_depth_u → river_forcing_no_climatology.zarr/tracer_name}/.zarray +2 -6
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_name/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_name/0 +0 -0
- roms_tools/tests/test_setup/test_grid.py +110 -12
- roms_tools/tests/test_setup/test_initial_conditions.py +2 -3
- roms_tools/tests/test_setup/test_river_forcing.py +367 -0
- roms_tools/tests/test_setup/test_surface_forcing.py +2 -24
- roms_tools/tests/test_setup/test_tides.py +2 -3
- roms_tools/tests/test_setup/test_topography.py +106 -1
- roms_tools/tests/test_setup/test_validation.py +4 -0
- roms_tools/utils.py +12 -10
- {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/LICENSE +1 -1
- {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/METADATA +6 -5
- {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/RECORD +254 -225
- {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/WHEEL +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/interface_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid.zarr/layer_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/interface_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_rho/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_u/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/.zarray +0 -24
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/.zattrs +0 -9
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/layer_depth_v/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_vertical_coordinate.py +0 -91
- {roms_tools-1.6.2.dist-info → roms_tools-2.0.0.dist-info}/top_level.txt +0 -0
roms_tools/setup/topography.py
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import logging
|
|
1
3
|
import xarray as xr
|
|
2
4
|
import numpy as np
|
|
3
5
|
import gcm_filters
|
|
4
|
-
from
|
|
5
|
-
from scipy.ndimage import label
|
|
6
|
-
from roms_tools.setup.download import fetch_topo
|
|
7
|
-
from roms_tools.setup.utils import interpolate_from_rho_to_u, interpolate_from_rho_to_v
|
|
6
|
+
from roms_tools.setup.utils import handle_boundaries
|
|
8
7
|
import warnings
|
|
9
8
|
from itertools import count
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
from roms_tools.setup.datasets import ETOPO5Dataset, SRTM15Dataset
|
|
10
|
+
from roms_tools.setup.regrid import LateralRegrid
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _add_topography(
|
|
14
|
+
ds,
|
|
15
|
+
target_coords,
|
|
16
|
+
topography_source,
|
|
17
|
+
hmin,
|
|
18
|
+
smooth_factor=8.0,
|
|
19
|
+
rmax=0.2,
|
|
20
|
+
verbose=False,
|
|
14
21
|
) -> xr.Dataset:
|
|
15
|
-
"""Adds topography
|
|
16
|
-
topography source.
|
|
17
|
-
|
|
18
|
-
This function performs the following operations:
|
|
19
|
-
1. Interpolates topography data onto the desired grid.
|
|
20
|
-
2. Applies a mask based on ocean depth.
|
|
21
|
-
3. Smooths the topography globally to reduce grid-scale instabilities.
|
|
22
|
-
4. Fills enclosed basins with land.
|
|
23
|
-
5. Smooths the topography locally to ensure the steepness ratio satisfies the rmax criterion.
|
|
24
|
-
6. Adds topography metadata.
|
|
22
|
+
"""Adds topography to the dataset based on the provided topography source.
|
|
25
23
|
|
|
26
24
|
Parameters
|
|
27
25
|
----------
|
|
28
26
|
ds : xr.Dataset
|
|
29
|
-
The dataset to which topography
|
|
30
|
-
topography_source : str
|
|
31
|
-
|
|
27
|
+
The dataset to which topography will be added.
|
|
28
|
+
topography_source : Dict[str, Union[str, Path]], optional
|
|
29
|
+
Dictionary specifying the source of the topography data:
|
|
30
|
+
|
|
31
|
+
- "name" (str): The name of the topography data source (e.g., "SRTM15").
|
|
32
|
+
- "path" (Union[str, Path, List[Union[str, Path]]]): The path to the raw data file. Can be a string or a Path object.
|
|
33
|
+
|
|
34
|
+
The default is "ETOPO5", which does not require a path.
|
|
32
35
|
hmin : float
|
|
33
36
|
The minimum allowable depth for the topography.
|
|
34
37
|
smooth_factor : float, optional
|
|
@@ -39,81 +42,93 @@ def _add_topography_and_mask(
|
|
|
39
42
|
The maximum allowable steepness ratio for the topography smoothing.
|
|
40
43
|
This parameter controls the local smoothing of the topography. Smaller values result in
|
|
41
44
|
smoother topography, while larger values preserve more detail. The default is 0.2.
|
|
45
|
+
verbose: bool, optional
|
|
46
|
+
Indicates whether to print topography generation steps with timing. Defaults to False.
|
|
42
47
|
|
|
43
48
|
Returns
|
|
44
49
|
-------
|
|
45
50
|
xr.Dataset
|
|
46
|
-
|
|
51
|
+
Updated dataset with added topography and metadata.
|
|
47
52
|
"""
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
if verbose:
|
|
55
|
+
start_time = time.time()
|
|
56
|
+
data = _get_topography_data(topography_source)
|
|
57
|
+
if verbose:
|
|
58
|
+
logging.info(
|
|
59
|
+
f"Reading the topography data: {time.time() - start_time:.3f} seconds"
|
|
60
|
+
)
|
|
51
61
|
|
|
52
62
|
# interpolate topography onto desired grid
|
|
53
|
-
hraw = _make_raw_topography(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# Mask is obtained by finding locations where ocean depth is positive
|
|
57
|
-
mask = xr.where(hraw > 0, 1.0, 0.0)
|
|
63
|
+
hraw = _make_raw_topography(data, target_coords, verbose=verbose)
|
|
64
|
+
nan_check(hraw)
|
|
58
65
|
|
|
59
66
|
# smooth topography domain-wide with Gaussian kernel to avoid grid scale instabilities
|
|
67
|
+
if verbose:
|
|
68
|
+
start_time = time.time()
|
|
60
69
|
hraw = _smooth_topography_globally(hraw, smooth_factor)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
# adjust mask boundaries by copying values from adjacent cells
|
|
66
|
-
mask = _handle_boundaries(mask)
|
|
67
|
-
|
|
68
|
-
ds["mask_rho"] = xr.DataArray(mask.astype(np.int32), dims=("eta_rho", "xi_rho"))
|
|
69
|
-
ds["mask_rho"].attrs = {
|
|
70
|
-
"long_name": "Mask at rho-points",
|
|
71
|
-
"units": "land/water (0/1)",
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
ds = _add_velocity_masks(ds)
|
|
70
|
+
if verbose:
|
|
71
|
+
logging.info(
|
|
72
|
+
f"Smoothing the topography globally: {time.time() - start_time:.3f} seconds"
|
|
73
|
+
)
|
|
75
74
|
|
|
76
75
|
# smooth topography locally to satisfy r < rmax
|
|
76
|
+
if verbose:
|
|
77
|
+
start_time = time.time()
|
|
78
|
+
# inserting hraw * mask_rho into this function eliminates any inconsistencies between
|
|
79
|
+
# the land according to the topography and the land according to the mask; land points
|
|
80
|
+
# will always be set to hmin
|
|
77
81
|
ds["h"] = _smooth_topography_locally(hraw * ds["mask_rho"], hmin, rmax)
|
|
78
82
|
ds["h"].attrs = {
|
|
79
|
-
"long_name": "
|
|
83
|
+
"long_name": "Bathymetry at rho-points",
|
|
80
84
|
"units": "meter",
|
|
81
85
|
}
|
|
86
|
+
if verbose:
|
|
87
|
+
logging.info(
|
|
88
|
+
f"Smoothing the topography locally: {time.time() - start_time:.3f} seconds"
|
|
89
|
+
)
|
|
82
90
|
|
|
83
91
|
ds = _add_topography_metadata(ds, topography_source, smooth_factor, hmin, rmax)
|
|
84
92
|
|
|
85
93
|
return ds
|
|
86
94
|
|
|
87
95
|
|
|
88
|
-
def
|
|
89
|
-
"""Given a grid of (lon, lat) points, fetch the topography file and interpolate
|
|
90
|
-
height values onto the desired grid."""
|
|
96
|
+
def _get_topography_data(source):
|
|
91
97
|
|
|
92
|
-
|
|
98
|
+
kwargs = {"use_dask": False}
|
|
93
99
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
105
|
-
topo_concatenated = xr.concat(
|
|
106
|
-
[-topo_ds["topo"], -topo_ds["topo"], -topo_ds["topo"]], dim="lon"
|
|
100
|
+
if source["name"] == "ETOPO5":
|
|
101
|
+
if "path" in source.keys():
|
|
102
|
+
kwargs["filename"] = source["path"]
|
|
103
|
+
data = ETOPO5Dataset(**kwargs)
|
|
104
|
+
elif source["name"] == "SRTM15":
|
|
105
|
+
kwargs["filename"] = source["path"]
|
|
106
|
+
data = SRTM15Dataset(**kwargs)
|
|
107
|
+
else:
|
|
108
|
+
raise ValueError(
|
|
109
|
+
'Only "ETOPO5" and "SRTM15" are valid options for topography_source["name"].'
|
|
107
110
|
)
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
return data
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _make_raw_topography(
|
|
116
|
+
data, target_coords, method="linear", verbose=False
|
|
117
|
+
) -> xr.DataArray:
|
|
118
|
+
|
|
119
|
+
data.choose_subdomain(target_coords, buffer_points=3, verbose=verbose)
|
|
120
|
+
|
|
121
|
+
if verbose:
|
|
122
|
+
start_time = time.time()
|
|
123
|
+
lateral_regrid = LateralRegrid(target_coords, data.dim_names)
|
|
124
|
+
hraw = lateral_regrid.apply(data.ds[data.var_names["topo"]], method=method)
|
|
125
|
+
if verbose:
|
|
126
|
+
logging.info(
|
|
127
|
+
f"Regridding the topography: {time.time() - start_time:.3f} seconds"
|
|
113
128
|
)
|
|
114
129
|
|
|
115
|
-
#
|
|
116
|
-
hraw =
|
|
130
|
+
# flip sign so that bathmetry is positive
|
|
131
|
+
hraw = -hraw
|
|
117
132
|
|
|
118
133
|
return hraw
|
|
119
134
|
|
|
@@ -148,28 +163,6 @@ def _smooth_topography_globally(hraw, factor) -> xr.DataArray:
|
|
|
148
163
|
return hsmooth
|
|
149
164
|
|
|
150
165
|
|
|
151
|
-
def _fill_enclosed_basins(mask) -> np.ndarray:
|
|
152
|
-
"""Fills in enclosed basins with land."""
|
|
153
|
-
|
|
154
|
-
# Label connected regions in the mask
|
|
155
|
-
reg, nreg = label(mask)
|
|
156
|
-
# Find the largest region
|
|
157
|
-
lint = 0
|
|
158
|
-
lreg = 0
|
|
159
|
-
for ireg in range(nreg):
|
|
160
|
-
int_ = np.sum(reg == ireg)
|
|
161
|
-
if int_ > lint and mask[reg == ireg].sum() > 0:
|
|
162
|
-
lreg = ireg
|
|
163
|
-
lint = int_
|
|
164
|
-
|
|
165
|
-
# Remove regions other than the largest one
|
|
166
|
-
for ireg in range(nreg):
|
|
167
|
-
if ireg != lreg:
|
|
168
|
-
mask[reg == ireg] = 0
|
|
169
|
-
|
|
170
|
-
return mask
|
|
171
|
-
|
|
172
|
-
|
|
173
166
|
def _smooth_topography_locally(h, hmin=5, rmax=0.2):
|
|
174
167
|
"""Smoothes topography locally to satisfy r < rmax."""
|
|
175
168
|
# Compute rmax_log
|
|
@@ -232,7 +225,7 @@ def _smooth_topography_locally(h, hmin=5, rmax=0.2):
|
|
|
232
225
|
)
|
|
233
226
|
|
|
234
227
|
# No gradient at the domain boundaries
|
|
235
|
-
h_log =
|
|
228
|
+
h_log = handle_boundaries(h_log)
|
|
236
229
|
|
|
237
230
|
# Update h
|
|
238
231
|
h = hmin * np.exp(h_log)
|
|
@@ -248,29 +241,6 @@ def _smooth_topography_locally(h, hmin=5, rmax=0.2):
|
|
|
248
241
|
return h
|
|
249
242
|
|
|
250
243
|
|
|
251
|
-
def _handle_boundaries(field):
|
|
252
|
-
"""Adjust the boundaries of a 2D field by copying values from adjacent cells.
|
|
253
|
-
|
|
254
|
-
Parameters
|
|
255
|
-
----------
|
|
256
|
-
field : numpy.ndarray or xarray.DataArray
|
|
257
|
-
A 2D array representing a field (e.g., topography or mask) whose boundary values
|
|
258
|
-
need to be adjusted.
|
|
259
|
-
|
|
260
|
-
Returns
|
|
261
|
-
-------
|
|
262
|
-
field : numpy.ndarray or xarray.DataArray
|
|
263
|
-
The input field with adjusted boundary values.
|
|
264
|
-
"""
|
|
265
|
-
|
|
266
|
-
field[0, :] = field[1, :]
|
|
267
|
-
field[-1, :] = field[-2, :]
|
|
268
|
-
field[:, 0] = field[:, 1]
|
|
269
|
-
field[:, -1] = field[:, -2]
|
|
270
|
-
|
|
271
|
-
return field
|
|
272
|
-
|
|
273
|
-
|
|
274
244
|
def _compute_rfactor(h):
|
|
275
245
|
"""Computes slope parameter (or r-factor) r = |Delta h| / 2h in both horizontal grid
|
|
276
246
|
directions."""
|
|
@@ -286,23 +256,17 @@ def _compute_rfactor(h):
|
|
|
286
256
|
|
|
287
257
|
|
|
288
258
|
def _add_topography_metadata(ds, topography_source, smooth_factor, hmin, rmax):
|
|
289
|
-
ds.attrs["topography_source"] = topography_source
|
|
259
|
+
ds.attrs["topography_source"] = topography_source["name"]
|
|
290
260
|
ds.attrs["hmin"] = hmin
|
|
291
261
|
|
|
292
262
|
return ds
|
|
293
263
|
|
|
294
264
|
|
|
295
|
-
def
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
)
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
).astype(np.int32)
|
|
304
|
-
|
|
305
|
-
ds["mask_u"].attrs = {"long_name": "Mask at u-points", "units": "land/water (0/1)"}
|
|
306
|
-
ds["mask_v"].attrs = {"long_name": "Mask at v-points", "units": "land/water (0/1)"}
|
|
307
|
-
|
|
308
|
-
return ds
|
|
265
|
+
def nan_check(hraw):
|
|
266
|
+
error_message = (
|
|
267
|
+
"NaN values found in regridded topography. This likely occurs because the ROMS grid, including "
|
|
268
|
+
"a small safety margin for interpolation, is not fully contained within the topography dataset's longitude/latitude range. Please ensure that the "
|
|
269
|
+
"dataset covers the entire area required by the ROMS grid."
|
|
270
|
+
)
|
|
271
|
+
if hraw.isnull().any().values:
|
|
272
|
+
raise ValueError(error_message)
|
roms_tools/setup/utils.py
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import xarray as xr
|
|
2
2
|
import numpy as np
|
|
3
|
-
from typing import Union
|
|
3
|
+
from typing import Union, Any, Dict, Type
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import cftime
|
|
6
6
|
from roms_tools.utils import partition
|
|
7
7
|
from pathlib import Path
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from dataclasses import fields, asdict
|
|
10
|
+
import importlib.metadata
|
|
11
|
+
import yaml
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
def nan_check(field, mask, error_message=None) -> None:
|
|
@@ -37,7 +41,7 @@ def nan_check(field, mask, error_message=None) -> None:
|
|
|
37
41
|
da = xr.where(mask == 1, field, 0)
|
|
38
42
|
if error_message is None:
|
|
39
43
|
error_message = (
|
|
40
|
-
"NaN values found in
|
|
44
|
+
"NaN values found in regridded field. This likely occurs because the ROMS grid, including "
|
|
41
45
|
"a small safety margin for interpolation, is not fully contained within the dataset's longitude/latitude range. Please ensure that the "
|
|
42
46
|
"dataset covers the entire area required by the ROMS grid."
|
|
43
47
|
)
|
|
@@ -103,10 +107,10 @@ def interpolate_from_rho_to_u(field, method="additive"):
|
|
|
103
107
|
else:
|
|
104
108
|
raise NotImplementedError(f"Unsupported method '{method}' specified.")
|
|
105
109
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
vars_to_drop = ["lat_rho", "lon_rho", "eta_rho", "xi_rho"]
|
|
111
|
+
for var in vars_to_drop:
|
|
112
|
+
if var in field_interpolated.coords:
|
|
113
|
+
field_interpolated = field_interpolated.drop_vars(var)
|
|
110
114
|
|
|
111
115
|
field_interpolated = field_interpolated.swap_dims({"xi_rho": "xi_u"})
|
|
112
116
|
|
|
@@ -151,10 +155,10 @@ def interpolate_from_rho_to_v(field, method="additive"):
|
|
|
151
155
|
else:
|
|
152
156
|
raise NotImplementedError(f"Unsupported method '{method}' specified.")
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
vars_to_drop = ["lat_rho", "lon_rho", "eta_rho", "xi_rho"]
|
|
159
|
+
for var in vars_to_drop:
|
|
160
|
+
if var in field_interpolated.coords:
|
|
161
|
+
field_interpolated = field_interpolated.drop_vars(var)
|
|
158
162
|
|
|
159
163
|
field_interpolated = field_interpolated.swap_dims({"eta_rho": "eta_v"})
|
|
160
164
|
|
|
@@ -729,27 +733,27 @@ def get_target_coords(grid, use_coarse_grid=False):
|
|
|
729
733
|
"""
|
|
730
734
|
# Select grid variables based on whether the coarse grid is used
|
|
731
735
|
if use_coarse_grid:
|
|
732
|
-
lat
|
|
733
|
-
|
|
734
|
-
grid.ds.lon_coarse.rename({"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}),
|
|
735
|
-
grid.ds.angle_coarse.rename(
|
|
736
|
-
{"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
|
|
737
|
-
),
|
|
738
|
-
grid.ds.mask_coarse.rename(
|
|
739
|
-
{"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
|
|
740
|
-
),
|
|
736
|
+
lat = grid.ds.lat_coarse.rename(
|
|
737
|
+
{"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
|
|
741
738
|
)
|
|
739
|
+
lon = grid.ds.lon_coarse.rename(
|
|
740
|
+
{"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
|
|
741
|
+
)
|
|
742
|
+
angle = grid.ds.angle_coarse.rename(
|
|
743
|
+
{"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"}
|
|
744
|
+
)
|
|
745
|
+
mask = grid.ds.get("mask_coarse")
|
|
746
|
+
if mask is not None:
|
|
747
|
+
mask = mask.rename({"eta_coarse": "eta_rho", "xi_coarse": "xi_rho"})
|
|
742
748
|
|
|
743
749
|
lat_psi = grid.ds.get("lat_psi_coarse")
|
|
744
750
|
lon_psi = grid.ds.get("lon_psi_coarse")
|
|
745
751
|
|
|
746
752
|
else:
|
|
747
|
-
lat
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
grid.ds.mask_rho,
|
|
752
|
-
)
|
|
753
|
+
lat = grid.ds.lat_rho
|
|
754
|
+
lon = grid.ds.lon_rho
|
|
755
|
+
angle = grid.ds.angle
|
|
756
|
+
mask = grid.ds.get("mask_rho")
|
|
753
757
|
lat_psi = grid.ds.get("lat_psi")
|
|
754
758
|
lon_psi = grid.ds.get("lon_psi")
|
|
755
759
|
|
|
@@ -921,3 +925,281 @@ def get_vector_pairs(variable_info):
|
|
|
921
925
|
processed.update([var_name, vector_pair])
|
|
922
926
|
|
|
923
927
|
return vector_pairs
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
def gc_dist(lon1, lat1, lon2, lat2):
|
|
931
|
+
"""Calculate the great circle distance between two points on the Earth's surface.
|
|
932
|
+
Latitude and longitude must be provided in degrees (they will be converted to
|
|
933
|
+
radians).
|
|
934
|
+
|
|
935
|
+
The function uses the Haversine formula to compute the shortest distance
|
|
936
|
+
along the surface of a sphere (Earth), assuming the Earth is a perfect sphere.
|
|
937
|
+
|
|
938
|
+
Parameters
|
|
939
|
+
----------
|
|
940
|
+
lon1, lat1 : float
|
|
941
|
+
Longitude and latitude of the first point in degrees.
|
|
942
|
+
lon2, lat2 : float
|
|
943
|
+
Longitude and latitude of the second point in degrees.
|
|
944
|
+
|
|
945
|
+
Returns
|
|
946
|
+
-------
|
|
947
|
+
dis : float
|
|
948
|
+
The great circle distance between the two points in meters.
|
|
949
|
+
This is the shortest distance along the surface of a sphere (Earth).
|
|
950
|
+
|
|
951
|
+
Notes
|
|
952
|
+
-----
|
|
953
|
+
The radius of the Earth is taken to be 6371315 meters.
|
|
954
|
+
"""
|
|
955
|
+
# Convert degrees to radians
|
|
956
|
+
d2r = np.pi / 180
|
|
957
|
+
lon1 = lon1 * d2r
|
|
958
|
+
lat1 = lat1 * d2r
|
|
959
|
+
lon2 = lon2 * d2r
|
|
960
|
+
lat2 = lat2 * d2r
|
|
961
|
+
|
|
962
|
+
# Difference in latitudes and longitudes
|
|
963
|
+
dlat = lat2 - lat1
|
|
964
|
+
dlon = lon2 - lon1
|
|
965
|
+
|
|
966
|
+
# Haversine formula
|
|
967
|
+
dang = 2 * np.arcsin(
|
|
968
|
+
np.sqrt(
|
|
969
|
+
np.sin(dlat / 2) ** 2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2) ** 2
|
|
970
|
+
)
|
|
971
|
+
)
|
|
972
|
+
|
|
973
|
+
# Radius of the Earth in meters
|
|
974
|
+
r_earth = 6371315.0
|
|
975
|
+
|
|
976
|
+
# Distance in meters
|
|
977
|
+
dis = r_earth * dang
|
|
978
|
+
|
|
979
|
+
return dis
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
def convert_to_roms_time(ds, model_reference_date, climatology, time_name="time"):
|
|
983
|
+
|
|
984
|
+
if climatology:
|
|
985
|
+
ds.attrs["climatology"] = str(True)
|
|
986
|
+
month = xr.DataArray(range(1, 13), dims=time_name)
|
|
987
|
+
month.attrs["long_name"] = "Month index (1-12)"
|
|
988
|
+
ds = ds.assign_coords({"month": month})
|
|
989
|
+
# Preserve absolute time coordinate for readability
|
|
990
|
+
abs_time = np.datetime64(model_reference_date) + ds[time_name]
|
|
991
|
+
# Convert to pandas TimedeltaIndex
|
|
992
|
+
timedelta_index = pd.to_timedelta(ds[time_name].values)
|
|
993
|
+
|
|
994
|
+
# Determine the start of the year for the base_datetime
|
|
995
|
+
start_of_year = datetime(model_reference_date.year, 1, 1)
|
|
996
|
+
|
|
997
|
+
# Calculate the offset from midnight of the new year
|
|
998
|
+
offset = model_reference_date - start_of_year
|
|
999
|
+
|
|
1000
|
+
# Convert the timedelta to nanoseconds first, then to days
|
|
1001
|
+
time = xr.DataArray(
|
|
1002
|
+
(timedelta_index - offset).view("int64") / 3600 / 24 * 1e-9,
|
|
1003
|
+
dims=time_name,
|
|
1004
|
+
)
|
|
1005
|
+
time.attrs["cycle_length"] = 365.25
|
|
1006
|
+
|
|
1007
|
+
else:
|
|
1008
|
+
# Preserve absolute time coordinate for readability
|
|
1009
|
+
abs_time = ds[time_name]
|
|
1010
|
+
|
|
1011
|
+
time = (
|
|
1012
|
+
(ds[time_name] - np.datetime64(model_reference_date)).astype("float64")
|
|
1013
|
+
/ 3600
|
|
1014
|
+
/ 24
|
|
1015
|
+
* 1e-9
|
|
1016
|
+
)
|
|
1017
|
+
|
|
1018
|
+
attrs = [key for key in abs_time.attrs]
|
|
1019
|
+
for attr in attrs:
|
|
1020
|
+
del abs_time.attrs[attr]
|
|
1021
|
+
abs_time.attrs["long_name"] = "absolute time"
|
|
1022
|
+
ds = ds.assign_coords({"abs_time": abs_time})
|
|
1023
|
+
|
|
1024
|
+
time.attrs["long_name"] = f"relative time: days since {str(model_reference_date)}"
|
|
1025
|
+
time.encoding["units"] = "days"
|
|
1026
|
+
time.attrs["units"] = "days"
|
|
1027
|
+
ds.encoding["unlimited_dims"] = "time"
|
|
1028
|
+
|
|
1029
|
+
return ds, time
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
def _to_yaml(forcing_object, filepath: Union[str, Path]) -> None:
|
|
1033
|
+
"""Serialize a forcing object (including its grid) into a YAML file.
|
|
1034
|
+
|
|
1035
|
+
This function serializes a dataclass object (forcing_object) and its associated
|
|
1036
|
+
`grid` attribute into a YAML file. It includes additional metadata, such as
|
|
1037
|
+
the version of the `roms-tools` package, and omits fields like `grid` and `ds`
|
|
1038
|
+
that are not serializable or meant to be excluded.
|
|
1039
|
+
|
|
1040
|
+
The function also converts datetime fields to ISO format strings for proper
|
|
1041
|
+
serialization.
|
|
1042
|
+
|
|
1043
|
+
Parameters
|
|
1044
|
+
----------
|
|
1045
|
+
forcing_object : object
|
|
1046
|
+
The object that contains the forcing data, typically a dataclass with attributes
|
|
1047
|
+
such as `grid`, `start_time`, `end_time`, etc.
|
|
1048
|
+
filepath : Union[str, Path]
|
|
1049
|
+
The path where the serialized YAML file will be saved.
|
|
1050
|
+
|
|
1051
|
+
Returns
|
|
1052
|
+
-------
|
|
1053
|
+
None
|
|
1054
|
+
The function writes the serialized data directly to a YAML file at the specified path.
|
|
1055
|
+
"""
|
|
1056
|
+
|
|
1057
|
+
# Convert the filepath to a Path object
|
|
1058
|
+
filepath = Path(filepath)
|
|
1059
|
+
|
|
1060
|
+
# Step 1: Serialize Grid data
|
|
1061
|
+
# Convert the grid attribute to a dictionary and remove non-serializable fields
|
|
1062
|
+
grid_data = asdict(forcing_object.grid)
|
|
1063
|
+
grid_data.pop("ds", None) # Remove 'ds' attribute (non-serializable)
|
|
1064
|
+
grid_data.pop("straddle", None)
|
|
1065
|
+
grid_data.pop("verbose", None)
|
|
1066
|
+
grid_yaml_data = {"Grid": grid_data}
|
|
1067
|
+
|
|
1068
|
+
# Step 2: Get ROMS Tools version
|
|
1069
|
+
# Fetch the version of the 'roms-tools' package for inclusion in the YAML header
|
|
1070
|
+
try:
|
|
1071
|
+
roms_tools_version = importlib.metadata.version("roms-tools")
|
|
1072
|
+
except importlib.metadata.PackageNotFoundError:
|
|
1073
|
+
roms_tools_version = "unknown"
|
|
1074
|
+
|
|
1075
|
+
# Create YAML header with version information
|
|
1076
|
+
header = f"---\nroms_tools_version: {roms_tools_version}\n---\n"
|
|
1077
|
+
|
|
1078
|
+
# Step 3: Prepare Forcing Data
|
|
1079
|
+
# Prepare the forcing object fields, excluding 'grid' and 'ds'
|
|
1080
|
+
forcing_data = {}
|
|
1081
|
+
field_names = [field.name for field in fields(forcing_object)]
|
|
1082
|
+
filtered_field_names = [
|
|
1083
|
+
param
|
|
1084
|
+
for param in field_names
|
|
1085
|
+
if param not in ("grid", "ds", "use_dask", "climatology")
|
|
1086
|
+
]
|
|
1087
|
+
|
|
1088
|
+
for field_name in filtered_field_names:
|
|
1089
|
+
# Retrieve the value of each field using getattr
|
|
1090
|
+
value = getattr(forcing_object, field_name)
|
|
1091
|
+
|
|
1092
|
+
# If the field is a datetime object, convert it to ISO format
|
|
1093
|
+
if isinstance(value, datetime):
|
|
1094
|
+
value = value.isoformat()
|
|
1095
|
+
|
|
1096
|
+
# Add the field and its value to the forcing_data dictionary
|
|
1097
|
+
forcing_data[field_name] = value
|
|
1098
|
+
|
|
1099
|
+
# Step 4: Combine Grid and Forcing Data
|
|
1100
|
+
# Combine grid and forcing data into a single dictionary for the final YAML content
|
|
1101
|
+
yaml_data = {
|
|
1102
|
+
**grid_yaml_data, # Add the grid data to the final YAML structure
|
|
1103
|
+
forcing_object.__class__.__name__: forcing_data, # Include the serialized forcing object data
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
# Step 5: Write to YAML file
|
|
1107
|
+
with filepath.open("w") as file:
|
|
1108
|
+
# Write the header first
|
|
1109
|
+
file.write(header)
|
|
1110
|
+
# Write the serialized YAML data
|
|
1111
|
+
yaml.dump(yaml_data, file, default_flow_style=False, sort_keys=False)
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
def _from_yaml(forcing_object: Type, filepath: Union[str, Path]) -> Dict[str, Any]:
|
|
1115
|
+
"""Extract the configuration data for a given forcing object from a YAML file.
|
|
1116
|
+
|
|
1117
|
+
This function reads a YAML file, searches for the configuration data associated
|
|
1118
|
+
with the class name of the forcing object, and returns the configuration data
|
|
1119
|
+
as a dictionary. The dictionary contains the forcing parameters extracted from
|
|
1120
|
+
the YAML file, with any date fields converted from ISO format.
|
|
1121
|
+
|
|
1122
|
+
Parameters
|
|
1123
|
+
----------
|
|
1124
|
+
filepath : Union[str, Path]
|
|
1125
|
+
The path to the YAML file from which the parameters will be read.
|
|
1126
|
+
forcing_object : Type
|
|
1127
|
+
The class type (e.g., TidalForcing) whose configuration data is to be loaded
|
|
1128
|
+
from the YAML file. The class name is used to locate the relevant data in
|
|
1129
|
+
the YAML structure.
|
|
1130
|
+
|
|
1131
|
+
Returns
|
|
1132
|
+
-------
|
|
1133
|
+
dict
|
|
1134
|
+
A dictionary containing the forcing parameters extracted from the YAML file.
|
|
1135
|
+
This dictionary contains key-value pairs where the keys are the parameter
|
|
1136
|
+
names, and the values are the corresponding values from the YAML file.
|
|
1137
|
+
Any date fields are converted from ISO format if necessary.
|
|
1138
|
+
|
|
1139
|
+
Raises
|
|
1140
|
+
------
|
|
1141
|
+
ValueError
|
|
1142
|
+
If no configuration for the specified class name is found in the YAML file.
|
|
1143
|
+
"""
|
|
1144
|
+
|
|
1145
|
+
# Read the entire file content
|
|
1146
|
+
with filepath.open("r") as file:
|
|
1147
|
+
file_content = file.read()
|
|
1148
|
+
|
|
1149
|
+
# Split the content into YAML documents
|
|
1150
|
+
documents = list(yaml.safe_load_all(file_content))
|
|
1151
|
+
|
|
1152
|
+
forcing_data = None
|
|
1153
|
+
forcing_object_name = forcing_object.__name__
|
|
1154
|
+
|
|
1155
|
+
# Process the YAML documents to find the forcing data for the given object
|
|
1156
|
+
for doc in documents:
|
|
1157
|
+
if doc is None:
|
|
1158
|
+
continue
|
|
1159
|
+
if forcing_object_name in doc:
|
|
1160
|
+
forcing_data = doc[forcing_object_name]
|
|
1161
|
+
break
|
|
1162
|
+
|
|
1163
|
+
if forcing_data is None:
|
|
1164
|
+
raise ValueError(
|
|
1165
|
+
f"No {forcing_object_name} configuration found in the YAML file."
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
# Convert any date fields from ISO format if necessary
|
|
1169
|
+
for key, value in forcing_data.items():
|
|
1170
|
+
forcing_data[key] = _convert_from_iso_format(value)
|
|
1171
|
+
|
|
1172
|
+
# Return the forcing data as a dictionary
|
|
1173
|
+
return forcing_data
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
def _convert_from_iso_format(value):
|
|
1177
|
+
try:
|
|
1178
|
+
# Return the parsed datetime object if successful
|
|
1179
|
+
return datetime.fromisoformat(str(value))
|
|
1180
|
+
except ValueError:
|
|
1181
|
+
# Return None or raise an exception if parsing fails
|
|
1182
|
+
return value
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
def handle_boundaries(field):
|
|
1186
|
+
"""Adjust the boundaries of a 2D field by copying values from adjacent cells.
|
|
1187
|
+
|
|
1188
|
+
Parameters
|
|
1189
|
+
----------
|
|
1190
|
+
field : numpy.ndarray or xarray.DataArray
|
|
1191
|
+
A 2D array representing a field (e.g., topography or mask) whose boundary values
|
|
1192
|
+
need to be adjusted.
|
|
1193
|
+
|
|
1194
|
+
Returns
|
|
1195
|
+
-------
|
|
1196
|
+
field : numpy.ndarray or xarray.DataArray
|
|
1197
|
+
The input field with adjusted boundary values.
|
|
1198
|
+
"""
|
|
1199
|
+
|
|
1200
|
+
field[0, :] = field[1, :]
|
|
1201
|
+
field[-1, :] = field[-2, :]
|
|
1202
|
+
field[:, 0] = field[:, 1]
|
|
1203
|
+
field[:, -1] = field[:, -2]
|
|
1204
|
+
|
|
1205
|
+
return field
|