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
|
@@ -7,6 +7,11 @@ from datetime import datetime
|
|
|
7
7
|
from roms_tools import Grid, ROMSOutput
|
|
8
8
|
from roms_tools.download import download_test_data
|
|
9
9
|
|
|
10
|
+
try:
|
|
11
|
+
import xesmf # type: ignore
|
|
12
|
+
except ImportError:
|
|
13
|
+
xesmf = None
|
|
14
|
+
|
|
10
15
|
|
|
11
16
|
@pytest.fixture
|
|
12
17
|
def roms_output_from_restart_file(use_dask):
|
|
@@ -18,28 +23,36 @@ def roms_output_from_restart_file(use_dask):
|
|
|
18
23
|
return ROMSOutput(
|
|
19
24
|
grid=grid,
|
|
20
25
|
path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
|
|
21
|
-
type="restart",
|
|
22
26
|
use_dask=use_dask,
|
|
23
27
|
)
|
|
24
28
|
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
assert isinstance(roms_output_from_restart_file.ds, xr.Dataset)
|
|
29
|
-
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def roms_output_from_restart_file_adjusted_for_zeta(use_dask):
|
|
30
32
|
|
|
31
|
-
def test_load_model_output_directory(use_dask):
|
|
32
33
|
fname_grid = Path(download_test_data("epac25km_grd.nc"))
|
|
33
34
|
grid = Grid.from_file(fname_grid)
|
|
34
35
|
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
# Single file
|
|
37
|
+
return ROMSOutput(
|
|
38
|
+
grid=grid,
|
|
39
|
+
path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
|
|
40
|
+
adjust_depth_for_sea_surface_height=True,
|
|
41
|
+
use_dask=use_dask,
|
|
42
|
+
)
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
|
|
45
|
+
@pytest.mark.parametrize(
|
|
46
|
+
"roms_output_fixture",
|
|
47
|
+
[
|
|
48
|
+
"roms_output_from_restart_file",
|
|
49
|
+
"roms_output_from_restart_file_adjusted_for_zeta",
|
|
50
|
+
],
|
|
51
|
+
)
|
|
52
|
+
def test_load_model_output_file(roms_output_fixture, use_dask, request):
|
|
53
|
+
roms_output = request.getfixturevalue(roms_output_fixture)
|
|
54
|
+
|
|
55
|
+
assert isinstance(roms_output.ds, xr.Dataset)
|
|
43
56
|
|
|
44
57
|
|
|
45
58
|
def test_load_model_output_file_list(use_dask):
|
|
@@ -49,24 +62,23 @@ def test_load_model_output_file_list(use_dask):
|
|
|
49
62
|
# List of files
|
|
50
63
|
file1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
51
64
|
file2 = Path(download_test_data("eastpac25km_rst.19980126000000.nc"))
|
|
52
|
-
output = ROMSOutput(
|
|
53
|
-
grid=grid, path=[file1, file2], type="restart", use_dask=use_dask
|
|
54
|
-
)
|
|
65
|
+
output = ROMSOutput(grid=grid, path=[file1, file2], use_dask=use_dask)
|
|
55
66
|
assert isinstance(output.ds, xr.Dataset)
|
|
56
67
|
|
|
57
68
|
|
|
58
|
-
def
|
|
69
|
+
def test_load_model_output_with_wildcard(use_dask):
|
|
59
70
|
fname_grid = Path(download_test_data("epac25km_grd.nc"))
|
|
60
71
|
grid = Grid.from_file(fname_grid)
|
|
61
72
|
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
# Download at least two files, so these will be found within the pooch directory
|
|
74
|
+
Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
75
|
+
Path(download_test_data("eastpac25km_rst.19980126000000.nc"))
|
|
76
|
+
directory = Path(
|
|
77
|
+
os.path.dirname(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
output = ROMSOutput(grid=grid, path=directory / "*rst*.nc", use_dask=use_dask)
|
|
81
|
+
assert isinstance(output.ds, xr.Dataset)
|
|
70
82
|
|
|
71
83
|
|
|
72
84
|
def test_invalid_path(use_dask):
|
|
@@ -78,16 +90,6 @@ def test_invalid_path(use_dask):
|
|
|
78
90
|
ROMSOutput(
|
|
79
91
|
grid=grid,
|
|
80
92
|
path=Path("/path/to/nonexistent/file.nc"),
|
|
81
|
-
type="restart",
|
|
82
|
-
use_dask=use_dask,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
# Non-existent directory
|
|
86
|
-
with pytest.raises(FileNotFoundError):
|
|
87
|
-
ROMSOutput(
|
|
88
|
-
grid=grid,
|
|
89
|
-
path=Path("/path/to/nonexistent/directory"),
|
|
90
|
-
type="restart",
|
|
91
93
|
use_dask=use_dask,
|
|
92
94
|
)
|
|
93
95
|
|
|
@@ -99,7 +101,6 @@ def test_set_correct_model_reference_date(use_dask):
|
|
|
99
101
|
output = ROMSOutput(
|
|
100
102
|
grid=grid,
|
|
101
103
|
path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
|
|
102
|
-
type="restart",
|
|
103
104
|
use_dask=use_dask,
|
|
104
105
|
)
|
|
105
106
|
assert output.model_reference_date == datetime(1995, 1, 1)
|
|
@@ -117,7 +118,6 @@ def test_model_reference_date_mismatch(use_dask):
|
|
|
117
118
|
ROMSOutput(
|
|
118
119
|
grid=grid,
|
|
119
120
|
path=Path(download_test_data("eastpac25km_rst.19980106000000.nc")),
|
|
120
|
-
type="restart",
|
|
121
121
|
model_reference_date=model_ref_date,
|
|
122
122
|
use_dask=use_dask,
|
|
123
123
|
)
|
|
@@ -138,7 +138,7 @@ def test_model_reference_date_no_metadata(use_dask, tmp_path, caplog):
|
|
|
138
138
|
expected_exception,
|
|
139
139
|
match="Model reference date could not be inferred from the metadata",
|
|
140
140
|
):
|
|
141
|
-
ROMSOutput(grid=grid, path=fname_mod,
|
|
141
|
+
ROMSOutput(grid=grid, path=fname_mod, use_dask=use_dask)
|
|
142
142
|
|
|
143
143
|
# Test case 2: When a model reference date is explicitly set, verify the warning
|
|
144
144
|
with caplog.at_level(logging.WARNING):
|
|
@@ -146,7 +146,6 @@ def test_model_reference_date_no_metadata(use_dask, tmp_path, caplog):
|
|
|
146
146
|
grid=grid,
|
|
147
147
|
path=fname_mod,
|
|
148
148
|
model_reference_date=datetime(1995, 1, 1),
|
|
149
|
-
type="restart",
|
|
150
149
|
use_dask=use_dask,
|
|
151
150
|
)
|
|
152
151
|
|
|
@@ -175,20 +174,53 @@ def test_model_reference_date_no_metadata(use_dask, tmp_path, caplog):
|
|
|
175
174
|
def test_compute_depth_coordinates(use_dask):
|
|
176
175
|
fname_grid = Path(download_test_data("epac25km_grd.nc"))
|
|
177
176
|
grid = Grid.from_file(fname_grid)
|
|
177
|
+
fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
178
|
+
|
|
179
|
+
for adjust_depth_for_sea_surface_height in [True, False]:
|
|
180
|
+
output = ROMSOutput(
|
|
181
|
+
grid=grid,
|
|
182
|
+
path=fname_restart1,
|
|
183
|
+
use_dask=use_dask,
|
|
184
|
+
adjust_depth_for_sea_surface_height=adjust_depth_for_sea_surface_height,
|
|
185
|
+
)
|
|
178
186
|
|
|
187
|
+
# Before calling get_vertical_coordinates, check if the dataset doesn't already have depth coordinates
|
|
188
|
+
assert "layer_depth_rho" not in output.ds_depth_coords.data_vars
|
|
189
|
+
|
|
190
|
+
# Call the method to get vertical coordinates
|
|
191
|
+
output._get_depth_coordinates(depth_type="layer")
|
|
192
|
+
|
|
193
|
+
# Check if the depth coordinates were added
|
|
194
|
+
assert "layer_depth_rho" in output.ds_depth_coords.data_vars
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_missing_zeta_gets_raised(use_dask):
|
|
198
|
+
"""Test that a ValueError is raised when `zeta` is missing from the dataset and
|
|
199
|
+
`adjust_depth_for_sea_surface_height` is enabled."""
|
|
200
|
+
# Load the grid
|
|
201
|
+
fname_grid = Path(download_test_data("epac25km_grd.nc"))
|
|
202
|
+
grid = Grid.from_file(fname_grid)
|
|
203
|
+
|
|
204
|
+
# Load the ROMS output
|
|
179
205
|
fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
180
|
-
|
|
181
|
-
grid=grid,
|
|
206
|
+
roms_output = ROMSOutput(
|
|
207
|
+
grid=grid,
|
|
208
|
+
path=fname_restart1,
|
|
209
|
+
use_dask=use_dask,
|
|
210
|
+
adjust_depth_for_sea_surface_height=True,
|
|
182
211
|
)
|
|
183
212
|
|
|
184
|
-
#
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
output.compute_depth_coordinates(depth_type="layer")
|
|
213
|
+
# Remove `zeta` from the dataset
|
|
214
|
+
object.__setattr__(
|
|
215
|
+
roms_output, "ds", roms_output.ds.drop_vars("zeta", errors="ignore")
|
|
216
|
+
)
|
|
189
217
|
|
|
190
|
-
#
|
|
191
|
-
|
|
218
|
+
# Expect ValueError when calling `_get_depth_coordinates`
|
|
219
|
+
with pytest.raises(
|
|
220
|
+
ValueError,
|
|
221
|
+
match="`zeta` is required in provided ROMS output when `adjust_depth_for_sea_surface_height` is enabled.",
|
|
222
|
+
):
|
|
223
|
+
roms_output._get_depth_coordinates()
|
|
192
224
|
|
|
193
225
|
|
|
194
226
|
def test_check_vertical_coordinate_mismatch(use_dask):
|
|
@@ -196,9 +228,7 @@ def test_check_vertical_coordinate_mismatch(use_dask):
|
|
|
196
228
|
grid = Grid.from_file(fname_grid)
|
|
197
229
|
|
|
198
230
|
fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
199
|
-
output = ROMSOutput(
|
|
200
|
-
grid=grid, path=fname_restart1, type="restart", use_dask=use_dask
|
|
201
|
-
)
|
|
231
|
+
output = ROMSOutput(grid=grid, path=fname_restart1, use_dask=use_dask)
|
|
202
232
|
|
|
203
233
|
# create a mock dataset with inconsistent vertical coordinate parameters
|
|
204
234
|
ds_mock = output.ds.copy()
|
|
@@ -226,44 +256,233 @@ def test_that_coordinates_are_added(use_dask):
|
|
|
226
256
|
grid = Grid.from_file(fname_grid)
|
|
227
257
|
|
|
228
258
|
fname_restart1 = Path(download_test_data("eastpac25km_rst.19980106000000.nc"))
|
|
229
|
-
output = ROMSOutput(
|
|
230
|
-
grid=grid, path=fname_restart1, type="restart", use_dask=use_dask
|
|
231
|
-
)
|
|
259
|
+
output = ROMSOutput(grid=grid, path=fname_restart1, use_dask=use_dask)
|
|
232
260
|
|
|
233
261
|
assert "abs_time" in output.ds.coords
|
|
234
262
|
assert "lat_rho" in output.ds.coords
|
|
235
263
|
assert "lon_rho" in output.ds.coords
|
|
236
264
|
|
|
237
265
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
266
|
+
@pytest.mark.parametrize(
|
|
267
|
+
"roms_output_fixture",
|
|
268
|
+
[
|
|
269
|
+
"roms_output_from_restart_file",
|
|
270
|
+
"roms_output_from_restart_file_adjusted_for_zeta",
|
|
271
|
+
],
|
|
272
|
+
)
|
|
273
|
+
def test_plot_on_native_model_grid(roms_output_fixture, use_dask, request):
|
|
274
|
+
roms_output = request.getfixturevalue(roms_output_fixture)
|
|
275
|
+
|
|
276
|
+
for include_boundary in [False, True]:
|
|
277
|
+
for depth_contours in [False, True]:
|
|
278
|
+
|
|
279
|
+
# 3D fields
|
|
280
|
+
for var_name in ["temp", "u", "v"]:
|
|
281
|
+
kwargs = {
|
|
282
|
+
"include_boundary": include_boundary,
|
|
283
|
+
"depth_contours": depth_contours,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
roms_output.plot(var_name, time=1, s=-1, **kwargs)
|
|
287
|
+
roms_output.plot(var_name, time=1, depth=1000, **kwargs)
|
|
288
|
+
|
|
289
|
+
roms_output.plot(var_name, time=1, eta=1, **kwargs)
|
|
290
|
+
roms_output.plot(var_name, time=1, xi=1, **kwargs)
|
|
291
|
+
|
|
292
|
+
roms_output.plot(
|
|
293
|
+
var_name,
|
|
294
|
+
time=1,
|
|
295
|
+
eta=1,
|
|
296
|
+
xi=1,
|
|
297
|
+
**kwargs,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
roms_output.plot(
|
|
301
|
+
var_name,
|
|
302
|
+
time=1,
|
|
303
|
+
s=-1,
|
|
304
|
+
eta=1,
|
|
305
|
+
**kwargs,
|
|
306
|
+
)
|
|
307
|
+
roms_output.plot(
|
|
308
|
+
var_name,
|
|
309
|
+
time=1,
|
|
310
|
+
depth=1000,
|
|
311
|
+
eta=1,
|
|
312
|
+
**kwargs,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
roms_output.plot(
|
|
316
|
+
var_name,
|
|
317
|
+
time=1,
|
|
318
|
+
s=-1,
|
|
319
|
+
xi=1,
|
|
320
|
+
**kwargs,
|
|
321
|
+
)
|
|
322
|
+
roms_output.plot(
|
|
323
|
+
var_name,
|
|
324
|
+
time=1,
|
|
325
|
+
depth=1000,
|
|
326
|
+
xi=1,
|
|
327
|
+
**kwargs,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# 2D fields
|
|
331
|
+
roms_output.plot("zeta", time=1, **kwargs)
|
|
332
|
+
roms_output.plot("zeta", time=1, eta=1, **kwargs)
|
|
333
|
+
roms_output.plot("zeta", time=1, xi=1, **kwargs)
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
@pytest.mark.parametrize(
|
|
337
|
+
"roms_output_fixture",
|
|
338
|
+
[
|
|
339
|
+
"roms_output_from_restart_file",
|
|
340
|
+
"roms_output_from_restart_file_adjusted_for_zeta",
|
|
341
|
+
],
|
|
342
|
+
)
|
|
343
|
+
@pytest.mark.skipif(xesmf is None, reason="xesmf required")
|
|
344
|
+
def test_plot_on_lat_lon(roms_output_fixture, use_dask, request):
|
|
345
|
+
roms_output = request.getfixturevalue(roms_output_fixture)
|
|
346
|
+
|
|
347
|
+
for include_boundary in [False, True]:
|
|
348
|
+
for depth_contours in [False, True]:
|
|
349
|
+
|
|
350
|
+
# 3D fields
|
|
351
|
+
for var_name in ["temp", "u", "v"]:
|
|
352
|
+
kwargs = {
|
|
353
|
+
"include_boundary": include_boundary,
|
|
354
|
+
"depth_contours": depth_contours,
|
|
355
|
+
}
|
|
356
|
+
roms_output.plot(
|
|
357
|
+
var_name,
|
|
358
|
+
time=1,
|
|
359
|
+
lat=9,
|
|
360
|
+
lon=-128,
|
|
361
|
+
**kwargs,
|
|
362
|
+
)
|
|
363
|
+
roms_output.plot(
|
|
364
|
+
var_name,
|
|
365
|
+
time=1,
|
|
366
|
+
lat=9,
|
|
367
|
+
**kwargs,
|
|
368
|
+
)
|
|
369
|
+
roms_output.plot(
|
|
370
|
+
var_name,
|
|
371
|
+
time=1,
|
|
372
|
+
lat=9,
|
|
373
|
+
s=-1,
|
|
374
|
+
**kwargs,
|
|
375
|
+
)
|
|
376
|
+
roms_output.plot(
|
|
377
|
+
var_name,
|
|
378
|
+
time=1,
|
|
379
|
+
lat=9,
|
|
380
|
+
depth=1000,
|
|
381
|
+
**kwargs,
|
|
382
|
+
)
|
|
383
|
+
roms_output.plot(
|
|
384
|
+
var_name,
|
|
385
|
+
time=1,
|
|
386
|
+
lon=-128,
|
|
387
|
+
**kwargs,
|
|
388
|
+
)
|
|
389
|
+
roms_output.plot(
|
|
390
|
+
var_name,
|
|
391
|
+
time=1,
|
|
392
|
+
lon=-128,
|
|
393
|
+
s=-1,
|
|
394
|
+
**kwargs,
|
|
395
|
+
)
|
|
396
|
+
roms_output.plot(
|
|
397
|
+
var_name,
|
|
398
|
+
time=1,
|
|
399
|
+
lon=-128,
|
|
400
|
+
depth=1000,
|
|
401
|
+
**kwargs,
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# 2D fields
|
|
405
|
+
roms_output.plot("zeta", time=1, lat=9, **kwargs)
|
|
406
|
+
roms_output.plot("zeta", time=1, lon=-128, **kwargs)
|
|
259
407
|
|
|
260
408
|
|
|
261
409
|
def test_plot_errors(roms_output_from_restart_file, use_dask):
|
|
410
|
+
"""Test error conditions for the ROMSOutput.plot() method."""
|
|
411
|
+
|
|
412
|
+
# Invalid time index
|
|
262
413
|
with pytest.raises(ValueError, match="Invalid time index"):
|
|
263
414
|
roms_output_from_restart_file.plot("temp", time=10, s=-1)
|
|
264
|
-
|
|
265
|
-
|
|
415
|
+
|
|
416
|
+
with pytest.raises(
|
|
417
|
+
ValueError,
|
|
418
|
+
match="Conflicting input: You cannot specify both 's' and 'depth' at the same time.",
|
|
419
|
+
):
|
|
420
|
+
roms_output_from_restart_file.plot("temp", time=0, s=-1, depth=10)
|
|
421
|
+
|
|
422
|
+
# Ambiguous input: Too many dimensions specified for 3D fields
|
|
266
423
|
with pytest.raises(ValueError, match="Ambiguous input"):
|
|
267
|
-
roms_output_from_restart_file.plot("temp", time=
|
|
268
|
-
|
|
269
|
-
|
|
424
|
+
roms_output_from_restart_file.plot("temp", time=1, s=-1, eta=0, xi=0)
|
|
425
|
+
|
|
426
|
+
# Vertical dimension specified for 2D fields
|
|
427
|
+
with pytest.raises(
|
|
428
|
+
ValueError, match="Vertical dimension 's' should be None for 2D fields"
|
|
429
|
+
):
|
|
430
|
+
roms_output_from_restart_file.plot("zeta", time=1, s=-1)
|
|
431
|
+
with pytest.raises(
|
|
432
|
+
ValueError, match="Vertical dimension 'depth' should be None for 2D fields"
|
|
433
|
+
):
|
|
434
|
+
roms_output_from_restart_file.plot("zeta", time=1, depth=100)
|
|
435
|
+
|
|
436
|
+
# Conflicting input: Both eta and xi specified for 2D fields
|
|
437
|
+
with pytest.raises(
|
|
438
|
+
ValueError,
|
|
439
|
+
match="Conflicting input: For 2D fields, specify only one dimension, either 'eta' or 'xi', not both.",
|
|
440
|
+
):
|
|
441
|
+
roms_output_from_restart_file.plot("zeta", time=1, eta=0, xi=0)
|
|
442
|
+
# Conflicting input: Both lat and lon specified for 2D fields
|
|
443
|
+
with pytest.raises(
|
|
444
|
+
ValueError,
|
|
445
|
+
match="Conflicting input: For 2D fields, specify only one dimension, either 'lat' or 'lon', not both.",
|
|
446
|
+
):
|
|
447
|
+
roms_output_from_restart_file.plot("zeta", time=1, lat=0, lon=0)
|
|
448
|
+
|
|
449
|
+
# Conflicting input: lat or lon provided with eta or xi
|
|
450
|
+
with pytest.raises(
|
|
451
|
+
ValueError,
|
|
452
|
+
match="Conflicting input: You cannot specify 'lat' or 'lon' simultaneously with 'eta' or 'xi'.",
|
|
453
|
+
):
|
|
454
|
+
roms_output_from_restart_file.plot("temp", time=1, lat=10, lon=20, eta=5)
|
|
455
|
+
|
|
456
|
+
# Invalid eta index out of bounds
|
|
457
|
+
with pytest.raises(ValueError, match="Invalid eta index"):
|
|
458
|
+
roms_output_from_restart_file.plot("temp", time=1, eta=999)
|
|
459
|
+
|
|
460
|
+
# Invalid xi index out of bounds
|
|
461
|
+
with pytest.raises(ValueError, match="Invalid eta index"):
|
|
462
|
+
roms_output_from_restart_file.plot("temp", time=1, xi=999)
|
|
463
|
+
|
|
464
|
+
# Boundary exclusion error for eta
|
|
465
|
+
with pytest.raises(ValueError, match="Invalid eta index.*boundary.*excluded"):
|
|
466
|
+
roms_output_from_restart_file.plot(
|
|
467
|
+
"temp", time=1, eta=0, include_boundary=False
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
# Boundary exclusion error for xi
|
|
471
|
+
with pytest.raises(ValueError, match="Invalid xi index.*boundary.*excluded"):
|
|
472
|
+
roms_output_from_restart_file.plot("temp", time=1, xi=0, include_boundary=False)
|
|
473
|
+
|
|
474
|
+
# No dimension specified for 3D field
|
|
475
|
+
with pytest.raises(
|
|
476
|
+
ValueError,
|
|
477
|
+
match="Invalid input: For 3D fields, you must specify at least one of the dimensions",
|
|
478
|
+
):
|
|
479
|
+
roms_output_from_restart_file.plot("temp", time=1)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def test_figure_gets_saved(roms_output_from_restart_file, tmp_path):
|
|
483
|
+
|
|
484
|
+
filename = tmp_path / "figure.png"
|
|
485
|
+
roms_output_from_restart_file.plot("temp", time=0, depth=1000, save_path=filename)
|
|
486
|
+
|
|
487
|
+
assert filename.exists()
|
|
488
|
+
filename.unlink()
|
roms_tools/tests/test_regrid.py
CHANGED
|
@@ -1,9 +1,92 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
import numpy as np
|
|
3
3
|
import xarray as xr
|
|
4
|
-
from roms_tools.regrid import
|
|
4
|
+
from roms_tools.regrid import VerticalRegridToROMS
|
|
5
5
|
|
|
6
|
+
try:
|
|
7
|
+
import xesmf # type: ignore
|
|
8
|
+
except ImportError:
|
|
9
|
+
xesmf = None
|
|
6
10
|
|
|
11
|
+
from roms_tools.regrid import LateralRegridFromROMS
|
|
12
|
+
|
|
13
|
+
# Lateral regridding
|
|
14
|
+
@pytest.mark.skipif(xesmf is None, reason="xesmf required")
|
|
15
|
+
def test_lateral_regrid_with_curvilinear_grid():
|
|
16
|
+
"""Test that LateralRegridFromROMS regrids data correctly from a curvilinear ROMS
|
|
17
|
+
grid."""
|
|
18
|
+
|
|
19
|
+
# Define ROMS curvilinear grid dimensions
|
|
20
|
+
eta_rho, xi_rho = 10, 20
|
|
21
|
+
|
|
22
|
+
# Create a mock ROMS grid with curvilinear coordinates
|
|
23
|
+
lat_rho = np.linspace(-10, 10, eta_rho).reshape(-1, 1) * np.ones((1, xi_rho))
|
|
24
|
+
lon_rho = np.linspace(120, 140, xi_rho).reshape(1, -1) * np.ones((eta_rho, 1))
|
|
25
|
+
|
|
26
|
+
ds_in = xr.Dataset(
|
|
27
|
+
{
|
|
28
|
+
"temp": (("eta_rho", "xi_rho"), np.random.rand(eta_rho, xi_rho)),
|
|
29
|
+
},
|
|
30
|
+
coords={
|
|
31
|
+
"lat": (("eta_rho", "xi_rho"), lat_rho),
|
|
32
|
+
"lon": (("eta_rho", "xi_rho"), lon_rho),
|
|
33
|
+
},
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Define target latitude and longitude coordinates
|
|
37
|
+
target_coords = {
|
|
38
|
+
"lat": np.linspace(-5, 5, 5),
|
|
39
|
+
"lon": np.linspace(125, 135, 10),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Instantiate the regridder
|
|
43
|
+
regridder = LateralRegridFromROMS(ds_in, target_coords, method="bilinear")
|
|
44
|
+
|
|
45
|
+
# Apply the regridding to the input data
|
|
46
|
+
regridded_da = regridder.apply(ds_in["temp"])
|
|
47
|
+
|
|
48
|
+
# Assertions to verify that the output is as expected
|
|
49
|
+
assert isinstance(regridded_da, xr.DataArray)
|
|
50
|
+
assert regridded_da.shape == (5, 10)
|
|
51
|
+
assert np.allclose(regridded_da.coords["lat"], target_coords["lat"])
|
|
52
|
+
assert np.allclose(regridded_da.coords["lon"], target_coords["lon"])
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@pytest.mark.skipif(xesmf is not None, reason="xesmf has to be missing")
|
|
56
|
+
def test_lateral_regrid_import_error():
|
|
57
|
+
"""Test that LateralRegridFromROMS raises ImportError when xesmf is missing."""
|
|
58
|
+
|
|
59
|
+
# Define mock ROMS curvilinear grid dimensions
|
|
60
|
+
eta_rho, xi_rho = 10, 20
|
|
61
|
+
|
|
62
|
+
# Create a mock ROMS grid with curvilinear coordinates
|
|
63
|
+
lat_rho = np.linspace(-10, 10, eta_rho).reshape(-1, 1) * np.ones((1, xi_rho))
|
|
64
|
+
lon_rho = np.linspace(120, 140, xi_rho).reshape(1, -1) * np.ones((eta_rho, 1))
|
|
65
|
+
|
|
66
|
+
ds_in = xr.Dataset(
|
|
67
|
+
{
|
|
68
|
+
"temp": (("eta_rho", "xi_rho"), np.random.rand(eta_rho, xi_rho)),
|
|
69
|
+
},
|
|
70
|
+
coords={
|
|
71
|
+
"lat": (("eta_rho", "xi_rho"), lat_rho),
|
|
72
|
+
"lon": (("eta_rho", "xi_rho"), lon_rho),
|
|
73
|
+
},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Define target latitude and longitude coordinates
|
|
77
|
+
target_coords = {
|
|
78
|
+
"lat": np.linspace(-5, 5, 5),
|
|
79
|
+
"lon": np.linspace(125, 135, 10),
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Check that ImportError is raised when xesmf is missing
|
|
83
|
+
with pytest.raises(
|
|
84
|
+
ImportError, match="xesmf is required for this regridding task.*"
|
|
85
|
+
):
|
|
86
|
+
LateralRegridFromROMS(ds_in, target_coords, method="bilinear")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# Vertical regridding
|
|
7
90
|
def vertical_regridder(depth_values, layer_depth_rho_values):
|
|
8
91
|
class DataContainer:
|
|
9
92
|
"""Mock class for holding data and dimension names."""
|
|
@@ -21,7 +104,7 @@ def vertical_regridder(depth_values, layer_depth_rho_values):
|
|
|
21
104
|
target_depth = xr.DataArray(data=layer_depth_rho_values, dims=["s_rho"])
|
|
22
105
|
source_depth = xr.DataArray(data=depth_values, dims=["depth"])
|
|
23
106
|
|
|
24
|
-
return
|
|
107
|
+
return VerticalRegridToROMS(target_depth, source_depth)
|
|
25
108
|
|
|
26
109
|
|
|
27
110
|
@pytest.mark.parametrize(
|
|
@@ -139,6 +139,69 @@ def test_unsuccessful_boundary_forcing_creation_with_1d_fill(use_dask):
|
|
|
139
139
|
)
|
|
140
140
|
|
|
141
141
|
|
|
142
|
+
def test_start_time_end_time_error(use_dask):
|
|
143
|
+
"""Test error when start_time and end_time are not both provided or both None."""
|
|
144
|
+
# Case 1: Only start_time provided
|
|
145
|
+
with pytest.raises(
|
|
146
|
+
ValueError, match="Both `start_time` and `end_time` must be provided together"
|
|
147
|
+
):
|
|
148
|
+
BoundaryForcing(
|
|
149
|
+
grid=None,
|
|
150
|
+
start_time=datetime(2022, 1, 1),
|
|
151
|
+
end_time=None, # end_time is None, should raise an error
|
|
152
|
+
source={"name": "GLORYS", "path": "glorys_data.nc"},
|
|
153
|
+
use_dask=use_dask,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Case 2: Only end_time provided
|
|
157
|
+
with pytest.raises(
|
|
158
|
+
ValueError, match="Both `start_time` and `end_time` must be provided together"
|
|
159
|
+
):
|
|
160
|
+
BoundaryForcing(
|
|
161
|
+
grid=None,
|
|
162
|
+
start_time=None, # start_time is None, should raise an error
|
|
163
|
+
end_time=datetime(2022, 1, 2),
|
|
164
|
+
source={"name": "GLORYS", "path": "glorys_data.nc"},
|
|
165
|
+
use_dask=use_dask,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_start_time_end_time_warning(use_dask, caplog):
|
|
170
|
+
"""Test that a warning is triggered when both start_time and end_time are None."""
|
|
171
|
+
# Catching the warning during test
|
|
172
|
+
grid = Grid(
|
|
173
|
+
nx=3,
|
|
174
|
+
ny=3,
|
|
175
|
+
size_x=400,
|
|
176
|
+
size_y=400,
|
|
177
|
+
center_lon=-8,
|
|
178
|
+
center_lat=58,
|
|
179
|
+
rot=0,
|
|
180
|
+
N=3, # number of vertical levels
|
|
181
|
+
theta_s=5.0, # surface control parameter
|
|
182
|
+
theta_b=2.0, # bottom control parameter
|
|
183
|
+
hc=250.0, # critical depth
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
fname1 = Path(download_test_data("GLORYS_NA_20120101.nc"))
|
|
187
|
+
fname2 = Path(download_test_data("GLORYS_NA_20121231.nc"))
|
|
188
|
+
|
|
189
|
+
with caplog.at_level(logging.INFO):
|
|
190
|
+
BoundaryForcing(
|
|
191
|
+
grid=grid,
|
|
192
|
+
start_time=None,
|
|
193
|
+
end_time=None,
|
|
194
|
+
source={"name": "GLORYS", "path": [fname1, fname2]},
|
|
195
|
+
use_dask=use_dask,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Verify the warning message in the log
|
|
199
|
+
assert (
|
|
200
|
+
"Both `start_time` and `end_time` are None. No time filtering will be applied to the source data."
|
|
201
|
+
in caplog.text
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
|
|
142
205
|
def test_boundary_divided_by_land_warning(caplog, use_dask):
|
|
143
206
|
|
|
144
207
|
# Iceland intersects the western boundary of the following grid
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
+
"adjust_depth_for_sea_surface_height": "False",
|
|
3
|
+
"apply_2d_horizontal_fill": "True",
|
|
2
4
|
"climatology": "True",
|
|
3
5
|
"end_time": "2021-06-30 00:00:00",
|
|
4
6
|
"hc": 250.0,
|
|
5
7
|
"model_reference_date": "2000-01-01 00:00:00",
|
|
6
|
-
"roms_tools_version": "
|
|
8
|
+
"roms_tools_version": "2.1.1.dev3+gef240eb.d20250116",
|
|
7
9
|
"source": "CESM_REGRIDDED",
|
|
8
10
|
"start_time": "2021-06-29 00:00:00",
|
|
9
11
|
"theta_b": 2.0,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"metadata": {
|
|
3
3
|
".zattrs": {
|
|
4
|
+
"adjust_depth_for_sea_surface_height": "False",
|
|
5
|
+
"apply_2d_horizontal_fill": "True",
|
|
4
6
|
"climatology": "True",
|
|
5
7
|
"end_time": "2021-06-30 00:00:00",
|
|
6
8
|
"hc": 250.0,
|
|
7
9
|
"model_reference_date": "2000-01-01 00:00:00",
|
|
8
|
-
"roms_tools_version": "
|
|
10
|
+
"roms_tools_version": "2.1.1.dev3+gef240eb.d20250116",
|
|
9
11
|
"source": "CESM_REGRIDDED",
|
|
10
12
|
"start_time": "2021-06-29 00:00:00",
|
|
11
13
|
"theta_b": 2.0,
|