roms-tools 2.4.0__py3-none-any.whl → 2.6.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-with-xesmf.yml +16 -0
- roms_tools/__init__.py +1 -1
- roms_tools/analysis/roms_output.py +339 -234
- roms_tools/analysis/utils.py +137 -0
- roms_tools/plot.py +353 -214
- roms_tools/regrid.py +154 -9
- roms_tools/setup/boundary_forcing.py +51 -37
- roms_tools/setup/datasets.py +129 -74
- roms_tools/setup/grid.py +32 -33
- roms_tools/setup/initial_conditions.py +30 -37
- roms_tools/setup/nesting.py +238 -64
- roms_tools/setup/river_forcing.py +256 -86
- roms_tools/setup/surface_forcing.py +40 -28
- roms_tools/setup/tides.py +10 -13
- roms_tools/setup/topography.py +27 -4
- roms_tools/setup/utils.py +28 -12
- roms_tools/tests/test_analysis/test_roms_output.py +299 -80
- roms_tools/tests/test_regrid.py +85 -2
- roms_tools/tests/test_setup/test_boundary_forcing.py +63 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zattrs +3 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/.zmetadata +3 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zattrs +2 -2
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +8 -7
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/abs_time/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/dust_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/iron_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nhy_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/nox_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_air_alt/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/pco2_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zattrs +2 -2
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +2 -2
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/dust/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/iron/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nhy/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/nox/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/pco2_air_alt/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/.zmetadata +2 -2
- roms_tools/tests/test_setup/test_data/grid.zarr/angle/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/angle_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/f/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/h/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid.zarr/h/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/lat_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/lat_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/lat_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/lat_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/pm/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +1 -1
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/f/0.0 +0 -0
- 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/lat_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pm/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pn/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zmetadata +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zeta/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +27 -1
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/nriver/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +27 -1
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/nriver/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zattrs +1 -1
- roms_tools/tests/test_setup/test_initial_conditions.py +16 -0
- roms_tools/tests/test_setup/test_nesting.py +141 -104
- roms_tools/tests/test_setup/test_river_forcing.py +580 -266
- roms_tools/tests/test_setup/test_surface_forcing.py +47 -0
- roms_tools/tests/test_setup/test_validation.py +34 -2
- roms_tools/utils.py +11 -7
- roms_tools/vertical_coordinate.py +1 -0
- {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/METADATA +22 -11
- {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/RECORD +214 -206
- {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/WHEEL +1 -1
- {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info/licenses}/LICENSE +0 -0
- {roms_tools-2.4.0.dist-info → roms_tools-2.6.0.dist-info}/top_level.txt +0 -0
roms_tools/setup/datasets.py
CHANGED
|
@@ -25,7 +25,7 @@ from roms_tools.setup.fill import LateralFill
|
|
|
25
25
|
# lat-lon datasets
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
@dataclass(
|
|
28
|
+
@dataclass(kw_only=True)
|
|
29
29
|
class Dataset:
|
|
30
30
|
"""Represents forcing data on original grid.
|
|
31
31
|
|
|
@@ -35,10 +35,11 @@ class Dataset:
|
|
|
35
35
|
The path to the data file(s). Can be a single string (with or without wildcards), a single Path object,
|
|
36
36
|
or a list of strings or Path objects containing multiple files.
|
|
37
37
|
start_time : Optional[datetime], optional
|
|
38
|
-
|
|
38
|
+
Start time for selecting relevant data. If not provided, no time-based filtering is applied.
|
|
39
39
|
end_time : Optional[datetime], optional
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
End time for selecting relevant data. If not provided, the dataset selects the time entry
|
|
41
|
+
closest to `start_time` within the range `[start_time, start_time + 24 hours]`.
|
|
42
|
+
If `start_time` is also not provided, no time-based filtering is applied.
|
|
42
43
|
dim_names: Dict[str, str], optional
|
|
43
44
|
Dictionary specifying the names of dimensions in the dataset.
|
|
44
45
|
var_names: Dict[str, str]
|
|
@@ -131,8 +132,8 @@ class Dataset:
|
|
|
131
132
|
self.infer_horizontal_resolution(ds)
|
|
132
133
|
|
|
133
134
|
# Check whether the data covers the entire globe
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
self.is_global = self.check_if_global(ds)
|
|
136
|
+
self.ds = ds
|
|
136
137
|
|
|
137
138
|
if self.apply_post_processing:
|
|
138
139
|
self.post_process()
|
|
@@ -353,7 +354,7 @@ class Dataset:
|
|
|
353
354
|
resolution = np.mean([lat_resolution, lon_resolution])
|
|
354
355
|
|
|
355
356
|
# Set the computed resolution as an attribute
|
|
356
|
-
|
|
357
|
+
self.resolution = resolution
|
|
357
358
|
|
|
358
359
|
def compute_minimal_grid_spacing(self, ds: xr.Dataset):
|
|
359
360
|
"""Compute the minimal grid spacing in a dataset based on latitude and longitude
|
|
@@ -510,6 +511,25 @@ class Dataset:
|
|
|
510
511
|
"""
|
|
511
512
|
pass
|
|
512
513
|
|
|
514
|
+
def convert_to_float64(self) -> None:
|
|
515
|
+
"""Convert all data variables in the dataset to float64.
|
|
516
|
+
|
|
517
|
+
This method updates the dataset by converting all of its data variables to the
|
|
518
|
+
`float64` data type, ensuring consistency for numerical operations that require
|
|
519
|
+
high precision. The dataset is modified in place.
|
|
520
|
+
|
|
521
|
+
Parameters
|
|
522
|
+
----------
|
|
523
|
+
None
|
|
524
|
+
|
|
525
|
+
Returns
|
|
526
|
+
-------
|
|
527
|
+
None
|
|
528
|
+
This method modifies the dataset in place and does not return anything.
|
|
529
|
+
"""
|
|
530
|
+
ds = self.ds.astype({var: "float64" for var in self.ds.data_vars})
|
|
531
|
+
self.ds = ds
|
|
532
|
+
|
|
513
533
|
def choose_subdomain(
|
|
514
534
|
self,
|
|
515
535
|
target_coords,
|
|
@@ -651,7 +671,7 @@ class Dataset:
|
|
|
651
671
|
if return_copy:
|
|
652
672
|
return Dataset.from_ds(self, subdomain)
|
|
653
673
|
else:
|
|
654
|
-
|
|
674
|
+
self.ds = subdomain
|
|
655
675
|
|
|
656
676
|
def apply_lateral_fill(self):
|
|
657
677
|
"""Apply lateral fill to variables using the dataset's mask and grid dimensions.
|
|
@@ -737,7 +757,7 @@ class Dataset:
|
|
|
737
757
|
dataset = cls.__new__(cls)
|
|
738
758
|
|
|
739
759
|
# Directly set the provided dataset as the 'ds' attribute
|
|
740
|
-
|
|
760
|
+
dataset.ds = ds
|
|
741
761
|
|
|
742
762
|
# Copy all other attributes from the original data instance
|
|
743
763
|
for attr in vars(original_dataset):
|
|
@@ -747,7 +767,7 @@ class Dataset:
|
|
|
747
767
|
return dataset
|
|
748
768
|
|
|
749
769
|
|
|
750
|
-
@dataclass(
|
|
770
|
+
@dataclass(kw_only=True)
|
|
751
771
|
class TPXODataset(Dataset):
|
|
752
772
|
"""Represents tidal data on the original grid from the TPXO dataset.
|
|
753
773
|
|
|
@@ -838,15 +858,11 @@ class TPXODataset(Dataset):
|
|
|
838
858
|
{"nx": "longitude", "ny": "latitude", self.dim_names["ntides"]: "ntides"}
|
|
839
859
|
)
|
|
840
860
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
"
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
"longitude": "longitude",
|
|
847
|
-
"ntides": "ntides",
|
|
848
|
-
},
|
|
849
|
-
)
|
|
861
|
+
self.dim_names = {
|
|
862
|
+
"latitude": "latitude",
|
|
863
|
+
"longitude": "longitude",
|
|
864
|
+
"ntides": "ntides",
|
|
865
|
+
}
|
|
850
866
|
|
|
851
867
|
return ds
|
|
852
868
|
|
|
@@ -889,15 +905,15 @@ class TPXODataset(Dataset):
|
|
|
889
905
|
ds["mask"] = mask
|
|
890
906
|
ds = ds.drop_vars(["depth"])
|
|
891
907
|
|
|
892
|
-
|
|
908
|
+
self.ds = ds
|
|
893
909
|
|
|
894
910
|
# Remove "depth" from var_names
|
|
895
911
|
updated_var_names = {**self.var_names} # Create a copy of the dictionary
|
|
896
912
|
updated_var_names.pop("depth", None) # Remove "depth" if it exists
|
|
897
|
-
|
|
913
|
+
self.var_names = updated_var_names
|
|
898
914
|
|
|
899
915
|
|
|
900
|
-
@dataclass(
|
|
916
|
+
@dataclass(kw_only=True)
|
|
901
917
|
class GLORYSDataset(Dataset):
|
|
902
918
|
"""Represents GLORYS data on original grid.
|
|
903
919
|
|
|
@@ -976,7 +992,7 @@ class GLORYSDataset(Dataset):
|
|
|
976
992
|
self.ds["mask_vel"] = mask_vel
|
|
977
993
|
|
|
978
994
|
|
|
979
|
-
@dataclass(
|
|
995
|
+
@dataclass(kw_only=True)
|
|
980
996
|
class CESMDataset(Dataset):
|
|
981
997
|
"""Represents CESM data on original grid.
|
|
982
998
|
|
|
@@ -1057,12 +1073,12 @@ class CESMDataset(Dataset):
|
|
|
1057
1073
|
# Update dimension names
|
|
1058
1074
|
updated_dim_names = self.dim_names.copy()
|
|
1059
1075
|
updated_dim_names["time"] = "time"
|
|
1060
|
-
|
|
1076
|
+
self.dim_names = updated_dim_names
|
|
1061
1077
|
|
|
1062
1078
|
return ds
|
|
1063
1079
|
|
|
1064
1080
|
|
|
1065
|
-
@dataclass(
|
|
1081
|
+
@dataclass(kw_only=True)
|
|
1066
1082
|
class CESMBGCDataset(CESMDataset):
|
|
1067
1083
|
"""Represents CESM BGC data on original grid.
|
|
1068
1084
|
|
|
@@ -1164,12 +1180,12 @@ class CESMBGCDataset(CESMDataset):
|
|
|
1164
1180
|
if "z_t_150m" in ds.variables:
|
|
1165
1181
|
ds = ds.drop_vars("z_t_150m")
|
|
1166
1182
|
# update dataset
|
|
1167
|
-
|
|
1183
|
+
self.ds = ds
|
|
1168
1184
|
|
|
1169
1185
|
# Update dim_names with "depth": "depth" key-value pair
|
|
1170
1186
|
updated_dim_names = self.dim_names.copy()
|
|
1171
1187
|
updated_dim_names["depth"] = "depth"
|
|
1172
|
-
|
|
1188
|
+
self.dim_names = updated_dim_names
|
|
1173
1189
|
|
|
1174
1190
|
mask = xr.where(
|
|
1175
1191
|
self.ds[self.var_names["PO4"]]
|
|
@@ -1182,7 +1198,7 @@ class CESMBGCDataset(CESMDataset):
|
|
|
1182
1198
|
self.ds["mask"] = mask
|
|
1183
1199
|
|
|
1184
1200
|
|
|
1185
|
-
@dataclass(
|
|
1201
|
+
@dataclass(kw_only=True)
|
|
1186
1202
|
class CESMBGCSurfaceForcingDataset(CESMDataset):
|
|
1187
1203
|
"""Represents CESM BGC surface forcing data on original grid.
|
|
1188
1204
|
|
|
@@ -1238,7 +1254,7 @@ class CESMBGCSurfaceForcingDataset(CESMDataset):
|
|
|
1238
1254
|
|
|
1239
1255
|
if "z_t" in self.ds.variables:
|
|
1240
1256
|
ds = self.ds.drop_vars("z_t")
|
|
1241
|
-
|
|
1257
|
+
self.ds = ds
|
|
1242
1258
|
|
|
1243
1259
|
mask = xr.where(
|
|
1244
1260
|
self.ds[self.var_names["pco2_air"]]
|
|
@@ -1251,7 +1267,7 @@ class CESMBGCSurfaceForcingDataset(CESMDataset):
|
|
|
1251
1267
|
self.ds["mask"] = mask
|
|
1252
1268
|
|
|
1253
1269
|
|
|
1254
|
-
@dataclass(
|
|
1270
|
+
@dataclass(kw_only=True)
|
|
1255
1271
|
class ERA5Dataset(Dataset):
|
|
1256
1272
|
"""Represents ERA5 data on original grid.
|
|
1257
1273
|
|
|
@@ -1351,27 +1367,27 @@ class ERA5Dataset(Dataset):
|
|
|
1351
1367
|
ds["qair"].attrs["long_name"] = "Absolute humidity at 2m"
|
|
1352
1368
|
ds["qair"].attrs["units"] = "kg/kg"
|
|
1353
1369
|
ds = ds.drop_vars([self.var_names["d2m"]])
|
|
1354
|
-
|
|
1370
|
+
self.ds = ds
|
|
1355
1371
|
|
|
1356
1372
|
# Update var_names dictionary
|
|
1357
1373
|
var_names = {**self.var_names, "qair": "qair"}
|
|
1358
1374
|
var_names.pop("d2m")
|
|
1359
|
-
|
|
1375
|
+
self.var_names = var_names
|
|
1360
1376
|
|
|
1361
1377
|
if "mask" in self.var_names.keys():
|
|
1362
1378
|
ds = self.ds
|
|
1363
1379
|
mask = xr.where(self.ds[self.var_names["mask"]].isel(time=0).isnull(), 0, 1)
|
|
1364
1380
|
ds["mask"] = mask
|
|
1365
1381
|
ds = ds.drop_vars([self.var_names["mask"]])
|
|
1366
|
-
|
|
1382
|
+
self.ds = ds
|
|
1367
1383
|
|
|
1368
1384
|
# Remove mask from var_names dictionary
|
|
1369
1385
|
var_names = self.var_names
|
|
1370
1386
|
var_names.pop("mask")
|
|
1371
|
-
|
|
1387
|
+
self.var_names = var_names
|
|
1372
1388
|
|
|
1373
1389
|
|
|
1374
|
-
@dataclass(
|
|
1390
|
+
@dataclass(kw_only=True)
|
|
1375
1391
|
class ERA5Correction(Dataset):
|
|
1376
1392
|
"""Global dataset to correct ERA5 radiation. The dataset contains multiplicative
|
|
1377
1393
|
correction factors for the ERA5 shortwave radiation, obtained by comparing the
|
|
@@ -1473,10 +1489,10 @@ class ERA5Correction(Dataset):
|
|
|
1473
1489
|
raise ValueError(
|
|
1474
1490
|
"The correction dataset does not contain all specified longitude values."
|
|
1475
1491
|
)
|
|
1476
|
-
|
|
1492
|
+
self.ds = subdomain
|
|
1477
1493
|
|
|
1478
1494
|
|
|
1479
|
-
@dataclass(
|
|
1495
|
+
@dataclass(kw_only=True)
|
|
1480
1496
|
class ETOPO5Dataset(Dataset):
|
|
1481
1497
|
"""Represents topography data on the original grid from the ETOPO5 dataset.
|
|
1482
1498
|
|
|
@@ -1533,7 +1549,7 @@ class ETOPO5Dataset(Dataset):
|
|
|
1533
1549
|
return ds
|
|
1534
1550
|
|
|
1535
1551
|
|
|
1536
|
-
@dataclass(
|
|
1552
|
+
@dataclass(kw_only=True)
|
|
1537
1553
|
class SRTM15Dataset(Dataset):
|
|
1538
1554
|
"""Represents topography data on the original grid from the SRTM15 dataset.
|
|
1539
1555
|
|
|
@@ -1569,7 +1585,7 @@ class SRTM15Dataset(Dataset):
|
|
|
1569
1585
|
|
|
1570
1586
|
|
|
1571
1587
|
# river datasets
|
|
1572
|
-
@dataclass(
|
|
1588
|
+
@dataclass(kw_only=True)
|
|
1573
1589
|
class RiverDataset:
|
|
1574
1590
|
"""Represents river data.
|
|
1575
1591
|
|
|
@@ -1627,7 +1643,7 @@ class RiverDataset:
|
|
|
1627
1643
|
|
|
1628
1644
|
# Select relevant times
|
|
1629
1645
|
ds = self.add_time_info(ds)
|
|
1630
|
-
|
|
1646
|
+
self.ds = ds
|
|
1631
1647
|
|
|
1632
1648
|
def load_data(self) -> xr.Dataset:
|
|
1633
1649
|
"""Load dataset from the specified file.
|
|
@@ -1765,13 +1781,13 @@ class RiverDataset:
|
|
|
1765
1781
|
|
|
1766
1782
|
ds = assign_dates_to_climatology(self.ds, "month")
|
|
1767
1783
|
ds = ds.swap_dims({"month": "time"})
|
|
1768
|
-
|
|
1784
|
+
self.ds = ds
|
|
1769
1785
|
|
|
1770
1786
|
updated_dim_names = {**self.dim_names}
|
|
1771
1787
|
updated_dim_names["time"] = "time"
|
|
1772
|
-
|
|
1788
|
+
self.dim_names = updated_dim_names
|
|
1773
1789
|
|
|
1774
|
-
|
|
1790
|
+
self.climatology = True
|
|
1775
1791
|
|
|
1776
1792
|
def sort_by_river_volume(self, ds: xr.Dataset) -> xr.Dataset:
|
|
1777
1793
|
"""Sorts the dataset by river volume in descending order (largest rivers first),
|
|
@@ -1843,15 +1859,10 @@ class RiverDataset:
|
|
|
1843
1859
|
|
|
1844
1860
|
Returns
|
|
1845
1861
|
-------
|
|
1846
|
-
indices : dict
|
|
1862
|
+
indices : dict[str, list[tuple]]
|
|
1847
1863
|
A dictionary containing the indices of the rivers that are within the threshold distance from
|
|
1848
|
-
the target coordinates. The dictionary keys
|
|
1849
|
-
|
|
1850
|
-
The indices of the rivers that satisfy the distance threshold.
|
|
1851
|
-
- "eta_rho" : numpy.ndarray
|
|
1852
|
-
The indices of the `eta_rho` dimension corresponding to the selected stations.
|
|
1853
|
-
- "xi_rho" : numpy.ndarray
|
|
1854
|
-
The indices of the `xi_rho` dimension corresponding to the selected stations.
|
|
1864
|
+
the target coordinates. The dictionary structure consists of river names as keys, and each value is a list of tuples. Each tuple represents
|
|
1865
|
+
a pair of indices corresponding to the `eta_rho` and `xi_rho` grid coordinates of the river.
|
|
1855
1866
|
"""
|
|
1856
1867
|
|
|
1857
1868
|
# Retrieve longitude and latitude of river mouths
|
|
@@ -1878,33 +1889,78 @@ class RiverDataset:
|
|
|
1878
1889
|
|
|
1879
1890
|
# Find the indices of the closest grid cell to the river mouth
|
|
1880
1891
|
indices = np.where(dist == dist_min)
|
|
1892
|
+
stations = indices[0]
|
|
1893
|
+
eta_rho_values = indices[1]
|
|
1894
|
+
xi_rho_values = indices[2]
|
|
1881
1895
|
names = (
|
|
1882
|
-
|
|
1883
|
-
.isel({self.dim_names["station"]:
|
|
1896
|
+
ds[self.var_names["name"]]
|
|
1897
|
+
.isel({self.dim_names["station"]: stations})
|
|
1884
1898
|
.values
|
|
1885
1899
|
)
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
}
|
|
1900
|
+
river_indices = {}
|
|
1901
|
+
for i in range(len(stations)):
|
|
1902
|
+
river_name = names[i]
|
|
1903
|
+
river_indices[river_name] = [
|
|
1904
|
+
(int(eta_rho_values[i]), int(xi_rho_values[i]))
|
|
1905
|
+
] # list of tuples
|
|
1893
1906
|
else:
|
|
1894
1907
|
ds = xr.Dataset()
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1908
|
+
river_indices = {}
|
|
1909
|
+
|
|
1910
|
+
self.ds = ds
|
|
1911
|
+
|
|
1912
|
+
return river_indices
|
|
1913
|
+
|
|
1914
|
+
def extract_named_rivers(self, indices):
|
|
1915
|
+
"""Extracts a subset of the dataset based on the provided river names in the
|
|
1916
|
+
indices dictionary.
|
|
1917
|
+
|
|
1918
|
+
This method filters the dataset to include only the rivers specified in the `indices` dictionary.
|
|
1919
|
+
The resulting subset is stored in the `ds` attribute of the class.
|
|
1901
1920
|
|
|
1902
|
-
|
|
1921
|
+
Parameters
|
|
1922
|
+
----------
|
|
1923
|
+
indices : dict
|
|
1924
|
+
A dictionary where the keys are river names (strings) and the values are dictionaries
|
|
1925
|
+
containing river-related data (e.g., river indices, coordinates).
|
|
1926
|
+
|
|
1927
|
+
Returns
|
|
1928
|
+
-------
|
|
1929
|
+
None
|
|
1930
|
+
The method modifies the `self.ds` attribute in place, setting it to the filtered dataset
|
|
1931
|
+
containing only the data related to the specified rivers.
|
|
1932
|
+
|
|
1933
|
+
Raises
|
|
1934
|
+
------
|
|
1935
|
+
ValueError
|
|
1936
|
+
- If `indices` is not a dictionary.
|
|
1937
|
+
- If any of the requested river names are not found in the dataset.
|
|
1938
|
+
"""
|
|
1939
|
+
|
|
1940
|
+
if not isinstance(indices, dict):
|
|
1941
|
+
raise ValueError("`indices` must be a dictionary.")
|
|
1903
1942
|
|
|
1904
|
-
|
|
1943
|
+
river_names = list(indices.keys())
|
|
1944
|
+
|
|
1945
|
+
# Ensure the dataset is filtered based on the provided river names
|
|
1946
|
+
ds_filtered = self.ds.where(
|
|
1947
|
+
self.ds[self.var_names["name"]].isin(river_names), drop=True
|
|
1948
|
+
)
|
|
1949
|
+
|
|
1950
|
+
# Check that all requested rivers exist in the dataset
|
|
1951
|
+
filtered_river_names = set(ds_filtered[self.var_names["name"]].values)
|
|
1952
|
+
missing_rivers = set(river_names) - filtered_river_names
|
|
1953
|
+
|
|
1954
|
+
if missing_rivers:
|
|
1955
|
+
raise ValueError(
|
|
1956
|
+
f"The following rivers were not found in the dataset: {missing_rivers}"
|
|
1957
|
+
)
|
|
1958
|
+
|
|
1959
|
+
# Set the filtered dataset as the new `ds`
|
|
1960
|
+
self.ds = ds_filtered
|
|
1905
1961
|
|
|
1906
1962
|
|
|
1907
|
-
@dataclass(
|
|
1963
|
+
@dataclass(kw_only=True)
|
|
1908
1964
|
class DaiRiverDataset(RiverDataset):
|
|
1909
1965
|
"""Represents river data from the Dai river dataset.
|
|
1910
1966
|
|
|
@@ -2050,7 +2106,7 @@ def _check_dataset(
|
|
|
2050
2106
|
|
|
2051
2107
|
|
|
2052
2108
|
def _select_relevant_times(
|
|
2053
|
-
ds, time_dim, start_time
|
|
2109
|
+
ds, time_dim, start_time, end_time=None, climatology=False
|
|
2054
2110
|
) -> xr.Dataset:
|
|
2055
2111
|
"""Select a subset of the dataset based on the specified time range.
|
|
2056
2112
|
|
|
@@ -2067,11 +2123,10 @@ def _select_relevant_times(
|
|
|
2067
2123
|
The input dataset to be filtered. Must contain a time dimension.
|
|
2068
2124
|
time_dim: str
|
|
2069
2125
|
Name of time dimension.
|
|
2070
|
-
start_time :
|
|
2071
|
-
The start time for selecting relevant data.
|
|
2126
|
+
start_time : datetime
|
|
2127
|
+
The start time for selecting relevant data.
|
|
2072
2128
|
end_time : Optional[datetime], optional
|
|
2073
|
-
The end time for selecting relevant data. If not provided, only data at the start_time is selected if start_time is provided
|
|
2074
|
-
or no filtering is applied if start_time is not provided.
|
|
2129
|
+
The end time for selecting relevant data. If not provided, only data at the start_time is selected if start_time is provided.
|
|
2075
2130
|
climatology : bool
|
|
2076
2131
|
Indicates whether the dataset is climatological. Defaults to False.
|
|
2077
2132
|
|
roms_tools/setup/grid.py
CHANGED
|
@@ -18,12 +18,13 @@ from roms_tools.setup.utils import (
|
|
|
18
18
|
interpolate_from_rho_to_v,
|
|
19
19
|
get_target_coords,
|
|
20
20
|
gc_dist,
|
|
21
|
+
_pop_grid_data,
|
|
21
22
|
)
|
|
22
23
|
from roms_tools.setup.utils import extract_single_value
|
|
23
24
|
from pathlib import Path
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
@dataclass(
|
|
27
|
+
@dataclass(kw_only=True)
|
|
27
28
|
class Grid:
|
|
28
29
|
"""A single ROMS grid, used for creating, plotting, and then saving a new ROMS
|
|
29
30
|
domain grid.
|
|
@@ -112,7 +113,7 @@ class Grid:
|
|
|
112
113
|
# Coarsen the dataset if needed
|
|
113
114
|
self._coarsen()
|
|
114
115
|
|
|
115
|
-
# Topography
|
|
116
|
+
# Topography
|
|
116
117
|
self.update_topography(
|
|
117
118
|
topography_source=self.topography_source,
|
|
118
119
|
hmin=self.hmin,
|
|
@@ -130,7 +131,7 @@ class Grid:
|
|
|
130
131
|
|
|
131
132
|
def _input_checks(self):
|
|
132
133
|
if self.topography_source is None:
|
|
133
|
-
|
|
134
|
+
self.topography_source = {"name": "ETOPO5"}
|
|
134
135
|
|
|
135
136
|
if "name" not in self.topography_source:
|
|
136
137
|
raise ValueError(
|
|
@@ -156,7 +157,7 @@ class Grid:
|
|
|
156
157
|
"========================================================================================================"
|
|
157
158
|
)
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
self.ds = ds
|
|
160
161
|
|
|
161
162
|
def update_topography(
|
|
162
163
|
self, topography_source=None, hmin=None, verbose=False
|
|
@@ -205,7 +206,7 @@ class Grid:
|
|
|
205
206
|
f"=== Generating the topography using {topography_source['name']} data and hmin = {hmin} meters ==="
|
|
206
207
|
)
|
|
207
208
|
|
|
208
|
-
# Add topography
|
|
209
|
+
# Add topography to the dataset
|
|
209
210
|
ds = _add_topography(
|
|
210
211
|
ds=self.ds,
|
|
211
212
|
target_coords=target_coords,
|
|
@@ -222,9 +223,9 @@ class Grid:
|
|
|
222
223
|
)
|
|
223
224
|
|
|
224
225
|
# Update the grid's dataset and related attributes
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
self.ds = ds
|
|
227
|
+
self.topography_source = topography_source
|
|
228
|
+
self.hmin = hmin
|
|
228
229
|
|
|
229
230
|
def update_vertical_coordinate(
|
|
230
231
|
self, N=None, theta_s=None, theta_b=None, hc=None, verbose=False
|
|
@@ -320,11 +321,11 @@ class Grid:
|
|
|
320
321
|
"========================================================================================================"
|
|
321
322
|
)
|
|
322
323
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
324
|
+
self.ds = ds
|
|
325
|
+
self.theta_s = theta_s
|
|
326
|
+
self.theta_b = theta_b
|
|
327
|
+
self.hc = hc
|
|
328
|
+
self.N = N
|
|
328
329
|
|
|
329
330
|
def _straddle(self) -> None:
|
|
330
331
|
"""Check if the Greenwich meridian goes through the domain.
|
|
@@ -341,9 +342,9 @@ class Grid:
|
|
|
341
342
|
np.abs(self.ds.lon_rho.diff("xi_rho")).max() > 300
|
|
342
343
|
or np.abs(self.ds.lon_rho.diff("eta_rho")).max() > 300
|
|
343
344
|
):
|
|
344
|
-
|
|
345
|
+
self.straddle = True
|
|
345
346
|
else:
|
|
346
|
-
|
|
347
|
+
self.straddle = False
|
|
347
348
|
|
|
348
349
|
def _coarsen(self):
|
|
349
350
|
"""Update the grid by adding grid variables that are coarsened versions of the
|
|
@@ -390,7 +391,7 @@ class Grid:
|
|
|
390
391
|
ds[coarse_var].attrs["long_name"] = f"{long_name} on coarsened grid"
|
|
391
392
|
ds[coarse_var].attrs["units"] = ds[fine_var].attrs["units"]
|
|
392
393
|
|
|
393
|
-
|
|
394
|
+
self.ds = ds
|
|
394
395
|
|
|
395
396
|
def plot(
|
|
396
397
|
self, bathymetry: bool = True, title: str = None, with_dim_names: bool = False
|
|
@@ -460,7 +461,7 @@ class Grid:
|
|
|
460
461
|
xi : int, optional
|
|
461
462
|
The xi-index to plot. Default is None.
|
|
462
463
|
ax : matplotlib.axes.Axes, optional
|
|
463
|
-
The axes to plot on. If None, a new figure is created. Note that this argument does not work for horizontal plots
|
|
464
|
+
The axes to plot on. If None, a new figure is created. Note that this argument does not work for 2D horizontal plots.
|
|
464
465
|
|
|
465
466
|
Returns
|
|
466
467
|
-------
|
|
@@ -580,14 +581,14 @@ class Grid:
|
|
|
580
581
|
grid = cls.__new__(cls)
|
|
581
582
|
|
|
582
583
|
# Set the dataset for the grid instance
|
|
583
|
-
|
|
584
|
+
grid.ds = ds
|
|
584
585
|
|
|
585
586
|
# Check if the Greenwich meridian goes through the domain.
|
|
586
587
|
grid._straddle()
|
|
587
588
|
|
|
588
589
|
if not all(coord in grid.ds for coord in ["lat_u", "lon_u", "lat_v", "lon_v"]):
|
|
589
590
|
ds = _add_lat_lon_at_velocity_points(grid.ds, grid.straddle)
|
|
590
|
-
|
|
591
|
+
grid.ds = ds
|
|
591
592
|
|
|
592
593
|
# Coarsen the grid if necessary
|
|
593
594
|
if not all(
|
|
@@ -605,7 +606,7 @@ class Grid:
|
|
|
605
606
|
for var in ["lat_rho", "lon_rho", "lat_coarse", "lon_coarse"]:
|
|
606
607
|
if var not in ds.coords:
|
|
607
608
|
ds = grid.ds.set_coords(var)
|
|
608
|
-
|
|
609
|
+
grid.ds = ds
|
|
609
610
|
|
|
610
611
|
# Update vertical coordinate if necessary
|
|
611
612
|
if not all(var in grid.ds for var in ["Cs_r", "Cs_w"]):
|
|
@@ -619,14 +620,14 @@ class Grid:
|
|
|
619
620
|
N=N, theta_s=theta_s, theta_b=theta_b, hc=hc, verbose=True
|
|
620
621
|
)
|
|
621
622
|
else:
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
623
|
+
grid.theta_s = ds.attrs["theta_s"].item()
|
|
624
|
+
grid.theta_b = ds.attrs["theta_b"].item()
|
|
625
|
+
grid.hc = ds.attrs["hc"].item()
|
|
626
|
+
grid.N = len(ds.s_rho)
|
|
626
627
|
|
|
627
628
|
# Manually set the remaining attributes by extracting parameters from dataset
|
|
628
|
-
|
|
629
|
-
|
|
629
|
+
grid.nx = ds.sizes["xi_rho"] - 2
|
|
630
|
+
grid.ny = ds.sizes["eta_rho"] - 2
|
|
630
631
|
if "center_lon" in ds.attrs:
|
|
631
632
|
center_lon = ds.attrs["center_lon"]
|
|
632
633
|
elif "tra_lon" in ds:
|
|
@@ -636,7 +637,7 @@ class Grid:
|
|
|
636
637
|
"Missing grid information: 'center_lon' attribute or 'tra_lon' variable "
|
|
637
638
|
"must be present in the dataset."
|
|
638
639
|
)
|
|
639
|
-
|
|
640
|
+
grid.center_lon = center_lon
|
|
640
641
|
if "center_lat" in ds.attrs:
|
|
641
642
|
center_lat = ds.attrs["center_lat"]
|
|
642
643
|
elif "tra_lat" in ds:
|
|
@@ -646,7 +647,7 @@ class Grid:
|
|
|
646
647
|
"Missing grid information: 'center_lat' attribute or 'tra_lat' variable "
|
|
647
648
|
"must be present in the dataset."
|
|
648
649
|
)
|
|
649
|
-
|
|
650
|
+
grid.center_lat = center_lat
|
|
650
651
|
if "rot" in ds.attrs:
|
|
651
652
|
rot = ds.attrs["rot"]
|
|
652
653
|
elif "rotate" in ds:
|
|
@@ -656,7 +657,7 @@ class Grid:
|
|
|
656
657
|
"Missing grid information: 'rot' attribute or 'rotate' variable "
|
|
657
658
|
"must be present in the dataset."
|
|
658
659
|
)
|
|
659
|
-
|
|
660
|
+
grid.rot = rot
|
|
660
661
|
|
|
661
662
|
for attr in [
|
|
662
663
|
"size_x",
|
|
@@ -688,9 +689,7 @@ class Grid:
|
|
|
688
689
|
filepath = Path(filepath)
|
|
689
690
|
|
|
690
691
|
data = asdict(self)
|
|
691
|
-
data
|
|
692
|
-
data.pop("straddle", None)
|
|
693
|
-
data.pop("verbose", None)
|
|
692
|
+
data = _pop_grid_data(data)
|
|
694
693
|
|
|
695
694
|
# Include the version of roms-tools
|
|
696
695
|
try:
|
|
@@ -849,7 +848,7 @@ class Grid:
|
|
|
849
848
|
"========================================================================================================"
|
|
850
849
|
)
|
|
851
850
|
|
|
852
|
-
|
|
851
|
+
self.ds = ds
|
|
853
852
|
|
|
854
853
|
def _add_global_metadata(self, ds):
|
|
855
854
|
"""Add global metadata and attributes to the dataset.
|