roms-tools 2.3.0__py3-none-any.whl → 2.5.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 -0
- roms_tools/__init__.py +2 -1
- roms_tools/analysis/roms_output.py +81 -98
- roms_tools/plot.py +4 -2
- roms_tools/setup/boundary_forcing.py +207 -208
- roms_tools/setup/datasets.py +149 -33
- roms_tools/setup/grid.py +35 -102
- roms_tools/setup/initial_conditions.py +179 -132
- roms_tools/setup/nesting.py +239 -86
- roms_tools/setup/river_forcing.py +266 -128
- roms_tools/setup/surface_forcing.py +137 -76
- roms_tools/setup/tides.py +10 -36
- roms_tools/setup/topography.py +25 -2
- roms_tools/setup/utils.py +52 -82
- roms_tools/tests/test_analysis/test_roms_output.py +233 -70
- roms_tools/tests/test_setup/test_boundary_forcing.py +283 -57
- 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/boundary_forcing.zarr/.zattrs +5 -3
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zmetadata +156 -121
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zarray +2 -2
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +2 -1
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/.zarray +2 -2
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/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 +4 -4
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +4 -4
- 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/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_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 +2 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zmetadata +6 -4
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Cs_r/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Cs_w/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/abs_time/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ocean_time/.zattrs +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/spC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/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 +56 -0
- 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/.zarray +22 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +56 -0
- 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/.zarray +22 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/0.0 +0 -0
- roms_tools/tests/test_setup/test_grid.py +0 -13
- roms_tools/tests/test_setup/test_initial_conditions.py +220 -66
- roms_tools/tests/test_setup/test_nesting.py +139 -118
- roms_tools/tests/test_setup/test_river_forcing.py +583 -293
- roms_tools/tests/test_setup/test_surface_forcing.py +149 -73
- roms_tools/tests/test_setup/test_tides.py +4 -16
- roms_tools/tests/test_setup/test_utils.py +1 -0
- roms_tools/tests/test_setup/test_validation.py +34 -2
- roms_tools/tests/{test_utils.py → test_tiling/test_partition.py} +1 -1
- roms_tools/tiling/partition.py +338 -0
- roms_tools/utils.py +66 -333
- roms_tools/vertical_coordinate.py +54 -133
- {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/METADATA +1 -1
- {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/RECORD +303 -290
- {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/WHEEL +1 -1
- {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/LICENSE +0 -0
- {roms_tools-2.3.0.dist-info → roms_tools-2.5.0.dist-info}/top_level.txt +0 -0
|
@@ -4,18 +4,19 @@ import logging
|
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
import cartopy.crs as ccrs
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from typing import Dict, Union, List
|
|
7
|
+
from typing import Dict, Union, List, Optional
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
import matplotlib.pyplot as plt
|
|
10
|
+
import matplotlib.cm as cm
|
|
10
11
|
from roms_tools import Grid
|
|
11
12
|
from roms_tools.plot import _get_projection, _add_field_to_ax
|
|
13
|
+
from roms_tools.utils import save_datasets
|
|
12
14
|
from roms_tools.setup.datasets import DaiRiverDataset
|
|
13
15
|
from roms_tools.setup.utils import (
|
|
14
16
|
get_target_coords,
|
|
15
17
|
gc_dist,
|
|
16
18
|
substitute_nans_by_fillvalue,
|
|
17
19
|
convert_to_roms_time,
|
|
18
|
-
save_datasets,
|
|
19
20
|
_to_yaml,
|
|
20
21
|
_from_yaml,
|
|
21
22
|
get_variable_metadata,
|
|
@@ -57,6 +58,24 @@ class RiverForcing:
|
|
|
57
58
|
Whether to include BGC tracers. Defaults to `False`.
|
|
58
59
|
model_reference_date : datetime, optional
|
|
59
60
|
Reference date for the model. Default is January 1, 2000.
|
|
61
|
+
indices : dict[str, list[tuple]], optional
|
|
62
|
+
A dictionary specifying the river indices for each river to be included in the river forcing. This parameter is optional. If not provided,
|
|
63
|
+
the river indices will be automatically determined based on the grid and the source dataset. If provided, it allows for explicit specification
|
|
64
|
+
of river locations. The dictionary structure consists of river names as keys, and each value is a list of tuples. Each tuple represents
|
|
65
|
+
a pair of indices corresponding to the `eta_rho` and `xi_rho` grid coordinates of the river.
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
indices = {
|
|
69
|
+
'Hvita(Olfusa)': [(8, 6), (7, 6)],
|
|
70
|
+
'Thjorsa': [(8, 6)],
|
|
71
|
+
'JkulsFjll': [(11, 12)],
|
|
72
|
+
'Lagarfljot': [(9, 13), (8, 13), (10, 13)],
|
|
73
|
+
'Bruara': [(8, 6)],
|
|
74
|
+
'Svarta': [(12, 9)]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
In the example, the dictionary provides the river names as keys, and the values are lists of tuples, where each tuple represents the
|
|
78
|
+
`(eta_rho, xi_rho)` indices for a river location.
|
|
60
79
|
|
|
61
80
|
Attributes
|
|
62
81
|
----------
|
|
@@ -64,6 +83,9 @@ class RiverForcing:
|
|
|
64
83
|
The xarray Dataset containing the river forcing data.
|
|
65
84
|
climatology : bool
|
|
66
85
|
Indicates whether the final river forcing is climatological.
|
|
86
|
+
Dict[str, Union[int, List[int]]]
|
|
87
|
+
A dictionary of river indices. If not provided during initialization, it will be automatically determined
|
|
88
|
+
based on the grid and the source dataset. The dictionary structure is the same as described in the `indices` parameter docstring.
|
|
67
89
|
"""
|
|
68
90
|
|
|
69
91
|
grid: Grid
|
|
@@ -73,39 +95,47 @@ class RiverForcing:
|
|
|
73
95
|
convert_to_climatology: str = "if_any_missing"
|
|
74
96
|
include_bgc: bool = False
|
|
75
97
|
model_reference_date: datetime = datetime(2000, 1, 1)
|
|
98
|
+
indices: Optional[Dict[str, Dict[str, Union[int, List[int]]]]] = None
|
|
76
99
|
|
|
77
100
|
ds: xr.Dataset = field(init=False, repr=False)
|
|
78
101
|
climatology: xr.Dataset = field(init=False, repr=False)
|
|
79
102
|
|
|
80
103
|
def __post_init__(self):
|
|
81
104
|
self._input_checks()
|
|
82
|
-
target_coords = get_target_coords(self.grid)
|
|
83
|
-
# maximum dx in grid
|
|
84
|
-
dx = (
|
|
85
|
-
np.sqrt((1 / self.grid.ds.pm) ** 2 + (1 / self.grid.ds.pn) ** 2) / 2
|
|
86
|
-
).max()
|
|
87
|
-
|
|
88
105
|
data = self._get_data()
|
|
89
106
|
|
|
90
|
-
|
|
91
|
-
|
|
107
|
+
if self.indices is None:
|
|
108
|
+
logging.info(
|
|
109
|
+
"No river indices provided. Identify all rivers within the ROMS domain and assign each of them to the nearest coastal point."
|
|
110
|
+
)
|
|
111
|
+
target_coords = get_target_coords(self.grid)
|
|
112
|
+
# maximum dx in grid
|
|
113
|
+
dx = (
|
|
114
|
+
np.sqrt((1 / self.grid.ds.pm) ** 2 + (1 / self.grid.ds.pn) ** 2) / 2
|
|
115
|
+
).max()
|
|
116
|
+
original_indices = data.extract_relevant_rivers(target_coords, dx)
|
|
117
|
+
if len(original_indices) == 0:
|
|
118
|
+
raise ValueError(
|
|
119
|
+
"No relevant rivers found. Consider increasing domain size or using a different river dataset."
|
|
120
|
+
)
|
|
121
|
+
object.__setattr__(self, "original_indices", original_indices)
|
|
122
|
+
updated_indices = self._move_rivers_to_closest_coast(target_coords, data)
|
|
123
|
+
object.__setattr__(self, "indices", updated_indices)
|
|
92
124
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
self.
|
|
125
|
+
else:
|
|
126
|
+
logging.info("Use provided river indices.")
|
|
127
|
+
object.__setattr__(self, "original_indices", self.indices)
|
|
128
|
+
check_river_locations_are_along_coast(self.grid.ds.mask_rho, self.indices)
|
|
129
|
+
data.extract_named_rivers(self.indices)
|
|
97
130
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
)
|
|
131
|
+
ds = self._create_river_forcing(data)
|
|
132
|
+
ds = self._write_indices_into_dataset(ds)
|
|
133
|
+
self._validate(ds)
|
|
102
134
|
|
|
103
|
-
|
|
135
|
+
for var_name in ds.data_vars:
|
|
136
|
+
ds[var_name] = substitute_nans_by_fillvalue(ds[var_name], fill_value=0.0)
|
|
104
137
|
|
|
105
|
-
|
|
106
|
-
raise ValueError(
|
|
107
|
-
"No relevant rivers found. Consider increasing domain size or using a different river dataset."
|
|
108
|
-
)
|
|
138
|
+
object.__setattr__(self, "ds", ds)
|
|
109
139
|
|
|
110
140
|
def _input_checks(self):
|
|
111
141
|
if self.source is None:
|
|
@@ -124,6 +154,63 @@ class RiverForcing:
|
|
|
124
154
|
{**self.source, "climatology": self.source.get("climatology", False)},
|
|
125
155
|
)
|
|
126
156
|
|
|
157
|
+
# Check if 'indices' is provided and has the correct format
|
|
158
|
+
if self.indices is not None:
|
|
159
|
+
if not isinstance(self.indices, dict):
|
|
160
|
+
raise ValueError("`indices` must be a dictionary.")
|
|
161
|
+
|
|
162
|
+
# Ensure the dictionary contains at least one river
|
|
163
|
+
if len(self.indices) == 0:
|
|
164
|
+
raise ValueError(
|
|
165
|
+
"The provided 'indices' dictionary must contain at least one river."
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
for river_name, river_data in self.indices.items():
|
|
169
|
+
if not isinstance(river_name, str):
|
|
170
|
+
raise ValueError(f"River name `{river_name}` must be a string.")
|
|
171
|
+
|
|
172
|
+
if not isinstance(river_data, list):
|
|
173
|
+
raise ValueError(
|
|
174
|
+
f"Data for river `{river_name}` must be a list of tuples."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Ensure each element in the list is a tuple of length 2
|
|
178
|
+
seen_tuples = set()
|
|
179
|
+
for idx_pair in river_data:
|
|
180
|
+
if not isinstance(idx_pair, tuple) or len(idx_pair) != 2:
|
|
181
|
+
raise ValueError(
|
|
182
|
+
f"Each item for river `{river_name}` must be a tuple of length 2 representing (eta_rho, xi_rho)."
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
eta_rho, xi_rho = idx_pair
|
|
186
|
+
|
|
187
|
+
# Ensure both eta_rho and xi_rho are integers
|
|
188
|
+
if not isinstance(eta_rho, int):
|
|
189
|
+
raise ValueError(
|
|
190
|
+
f"First element of tuple for river `{river_name}` must be an integer (eta_rho), but got {type(eta_rho)}."
|
|
191
|
+
)
|
|
192
|
+
if not isinstance(xi_rho, int):
|
|
193
|
+
raise ValueError(
|
|
194
|
+
f"Second element of tuple for river `{river_name}` must be an integer (xi_rho), but got {type(xi_rho)}."
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
# Check that eta_rho and xi_rho are within the valid range
|
|
198
|
+
if not (0 <= eta_rho < len(self.grid.ds.eta_rho)):
|
|
199
|
+
raise ValueError(
|
|
200
|
+
f"Value of eta_rho for river `{river_name}` ({eta_rho}) is out of valid range [0, {len(self.grid.ds.eta_rho)-1}]."
|
|
201
|
+
)
|
|
202
|
+
if not (0 <= xi_rho < len(self.grid.ds.xi_rho)):
|
|
203
|
+
raise ValueError(
|
|
204
|
+
f"Value of xi_rho for river `{river_name}` ({xi_rho}) is out of valid range [0, {len(self.grid.ds.xi_rho)-1}]."
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
# Check for duplicate tuples
|
|
208
|
+
if idx_pair in seen_tuples:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
f"Duplicate location {idx_pair} found for river `{river_name}`."
|
|
211
|
+
)
|
|
212
|
+
seen_tuples.add(idx_pair)
|
|
213
|
+
|
|
127
214
|
def _get_data(self):
|
|
128
215
|
|
|
129
216
|
data_dict = {
|
|
@@ -196,13 +283,19 @@ class RiverForcing:
|
|
|
196
283
|
river_volume = river_volume.rename(
|
|
197
284
|
{data.dim_names["time"]: "river_time", data.dim_names["station"]: "nriver"}
|
|
198
285
|
)
|
|
286
|
+
|
|
199
287
|
name = data.ds[data.var_names["name"]].rename(
|
|
200
288
|
{data.dim_names["station"]: "nriver"}
|
|
201
289
|
)
|
|
202
290
|
name.attrs["long_name"] = "River name"
|
|
203
291
|
river_volume.coords["river_name"] = name
|
|
292
|
+
|
|
204
293
|
ds["river_volume"] = river_volume
|
|
205
294
|
|
|
295
|
+
nriver = xr.DataArray(np.arange(1, len(ds.nriver) + 1), dims="nriver")
|
|
296
|
+
nriver.attrs["long_name"] = "River ID (1-based Fortran indexing)"
|
|
297
|
+
ds = ds.assign_coords({"nriver": nriver})
|
|
298
|
+
|
|
206
299
|
if self.include_bgc:
|
|
207
300
|
ntracers = 2 + 32
|
|
208
301
|
else:
|
|
@@ -271,15 +364,13 @@ class RiverForcing:
|
|
|
271
364
|
|
|
272
365
|
ds = ds.assign_coords({"river_time": time})
|
|
273
366
|
|
|
274
|
-
ds = ds.drop_vars("nriver")
|
|
275
|
-
|
|
276
367
|
return ds
|
|
277
368
|
|
|
278
369
|
def _move_rivers_to_closest_coast(self, target_coords, data):
|
|
279
370
|
"""Move river mouths to the closest coastal grid cell.
|
|
280
371
|
|
|
281
372
|
This method computes the closest coastal grid point to each river mouth
|
|
282
|
-
based on geographical distance.
|
|
373
|
+
based on geographical distance. It identifies the nearest grid point on the coast and returns the updated river mouth indices.
|
|
283
374
|
|
|
284
375
|
Parameters:
|
|
285
376
|
-----------
|
|
@@ -295,11 +386,11 @@ class RiverForcing:
|
|
|
295
386
|
- `var_names`: A dictionary of variable names in the dataset (e.g., longitude, latitude, station names).
|
|
296
387
|
- `dim_names`: A dictionary containing dimension names for the dataset (e.g., "station", "eta_rho", "xi_rho").
|
|
297
388
|
|
|
298
|
-
Returns
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
of
|
|
389
|
+
Returns
|
|
390
|
+
-------
|
|
391
|
+
indices : dict[str, list[tuple]]
|
|
392
|
+
A dictionary consisting of river names as keys, and each value is a list of tuples. Each tuple represents
|
|
393
|
+
a pair of indices corresponding to the `eta_rho` and `xi_rho` grid coordinates of the river.
|
|
303
394
|
"""
|
|
304
395
|
|
|
305
396
|
# Retrieve longitude and latitude of river mouths
|
|
@@ -332,62 +423,63 @@ class RiverForcing:
|
|
|
332
423
|
|
|
333
424
|
# Find the indices of the closest coastal grid cell to the river mouth
|
|
334
425
|
indices = np.where(dist_coast == dist_coast_min)
|
|
426
|
+
stations = indices[0]
|
|
427
|
+
eta_rho_values = indices[1]
|
|
428
|
+
xi_rho_values = indices[2]
|
|
335
429
|
names = (
|
|
336
430
|
data.ds[data.var_names["name"]]
|
|
337
|
-
.isel({data.dim_names["station"]:
|
|
431
|
+
.isel({data.dim_names["station"]: stations})
|
|
338
432
|
.values
|
|
339
433
|
)
|
|
340
|
-
|
|
341
434
|
# Return the indices in a dictionary format
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
self._write_indices_into_grid_file(indices)
|
|
349
|
-
object.__setattr__(self, "updated_indices", indices)
|
|
435
|
+
river_indices = {}
|
|
436
|
+
for i in range(len(stations)):
|
|
437
|
+
river_name = names[i]
|
|
438
|
+
river_indices[river_name] = [
|
|
439
|
+
(int(eta_rho_values[i]), int(xi_rho_values[i]))
|
|
440
|
+
] # list of tuples
|
|
350
441
|
|
|
351
|
-
|
|
352
|
-
"""Writes river location indices into the grid dataset as the "river_flux"
|
|
353
|
-
variable.
|
|
442
|
+
return river_indices
|
|
354
443
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
based on the provided `indices` and assigns it to the dataset. The `indices` dictionary
|
|
358
|
-
provides information about the river station locations and their corresponding grid
|
|
359
|
-
cell indices (eta_rho and xi_rho).
|
|
444
|
+
def _write_indices_into_dataset(self, ds):
|
|
445
|
+
"""Adds river location indices to the dataset as the "river_location" variable.
|
|
360
446
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
indices
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
This method modifies the grid's dataset in-place by adding the "river_flux" variable.
|
|
447
|
+
This method creates a new "river_location" variable
|
|
448
|
+
using river station indices from `self.indices` and assigns it to the dataset.
|
|
449
|
+
The indices specify the river station locations in terms of eta_rho and xi_rho grid cell indices.
|
|
450
|
+
|
|
451
|
+
Parameters
|
|
452
|
+
----------
|
|
453
|
+
ds : xarray.Dataset
|
|
454
|
+
The dataset to which the "river_location" variable will be added.
|
|
455
|
+
|
|
456
|
+
Returns
|
|
457
|
+
-------
|
|
458
|
+
xarray.Dataset
|
|
459
|
+
The modified dataset with the "river_location" variable added.
|
|
375
460
|
"""
|
|
376
461
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
462
|
+
river_locations = xr.zeros_like(self.grid.ds.h)
|
|
463
|
+
|
|
464
|
+
for nriver in ds.nriver:
|
|
465
|
+
river_name = str(ds.river_name.sel(nriver=nriver).values)
|
|
466
|
+
indices = self.indices[river_name]
|
|
467
|
+
fraction = 1.0 / len(indices)
|
|
468
|
+
|
|
469
|
+
for eta_index, xi_index in indices:
|
|
380
470
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
xi_index = indices["xi_rho"][i]
|
|
386
|
-
river_locations[eta_index, xi_index] = station + 2
|
|
471
|
+
river_locations[eta_index, xi_index] = (
|
|
472
|
+
nriver # assign unique nriver ID (Fortran-based indexing)
|
|
473
|
+
+ fraction # Fractional contribution for multiple grid points
|
|
474
|
+
)
|
|
387
475
|
|
|
388
|
-
river_locations.attrs["long_name"] = "River volume
|
|
476
|
+
river_locations.attrs["long_name"] = "River ID plus local volume fraction"
|
|
389
477
|
river_locations.attrs["units"] = "none"
|
|
390
|
-
|
|
478
|
+
ds["river_location"] = river_locations
|
|
479
|
+
|
|
480
|
+
ds = ds.drop_vars(["lat_rho", "lon_rho"])
|
|
481
|
+
|
|
482
|
+
return ds
|
|
391
483
|
|
|
392
484
|
def _validate(self, ds):
|
|
393
485
|
"""Validates the dataset by checking for NaN values in river forcing data.
|
|
@@ -467,26 +559,46 @@ class RiverForcing:
|
|
|
467
559
|
"color": "black",
|
|
468
560
|
} # Customize latitude label style
|
|
469
561
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
562
|
+
proj = ccrs.PlateCarree()
|
|
563
|
+
|
|
564
|
+
if len(self.indices) <= 10:
|
|
565
|
+
color_map = cm.get_cmap("tab10")
|
|
566
|
+
elif len(self.indices) <= 20:
|
|
567
|
+
color_map = cm.get_cmap("tab20")
|
|
568
|
+
else:
|
|
569
|
+
color_map = cm.get_cmap("tab20b")
|
|
570
|
+
# Create a dictionary of colors
|
|
571
|
+
colors = {name: color_map(i) for i, name in enumerate(self.indices.keys())}
|
|
572
|
+
|
|
573
|
+
for ax, indices in zip(axs, [self.original_indices, self.indices]):
|
|
574
|
+
added_labels = set()
|
|
575
|
+
for name in indices.keys():
|
|
576
|
+
for tuple in indices[name]:
|
|
577
|
+
eta_index = tuple[0]
|
|
578
|
+
xi_index = tuple[1]
|
|
579
|
+
|
|
580
|
+
# transform coordinates to projected space
|
|
581
|
+
transformed_lon, transformed_lat = trans.transform_point(
|
|
582
|
+
self.grid.ds.lon_rho[eta_index, xi_index],
|
|
583
|
+
self.grid.ds.lat_rho[eta_index, xi_index],
|
|
584
|
+
proj,
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
if name not in added_labels:
|
|
588
|
+
added_labels.add(name)
|
|
589
|
+
label = name
|
|
590
|
+
else:
|
|
591
|
+
label = "_None"
|
|
592
|
+
|
|
593
|
+
ax.plot(
|
|
594
|
+
transformed_lon,
|
|
595
|
+
transformed_lat,
|
|
596
|
+
marker="x",
|
|
597
|
+
markersize=8,
|
|
598
|
+
markeredgewidth=2,
|
|
599
|
+
label=label,
|
|
600
|
+
color=colors[name],
|
|
601
|
+
)
|
|
490
602
|
|
|
491
603
|
axs[0].set_title("Original river locations")
|
|
492
604
|
axs[1].set_title("Updated river locations")
|
|
@@ -592,37 +704,13 @@ class RiverForcing:
|
|
|
592
704
|
def save(
|
|
593
705
|
self,
|
|
594
706
|
filepath: Union[str, Path],
|
|
595
|
-
filepath_grid: Union[str, Path],
|
|
596
|
-
np_eta: int = None,
|
|
597
|
-
np_xi: int = None,
|
|
598
707
|
) -> None:
|
|
599
|
-
"""Save the river forcing
|
|
600
|
-
required because a new field `river_flux` has been added.
|
|
601
|
-
|
|
602
|
-
This method allows saving the river forcing and grid data either each as a single file or each partitioned into multiple files, based on the provided options. The dataset can be saved in two modes:
|
|
603
|
-
|
|
604
|
-
1. **Single File Mode (default)**:
|
|
605
|
-
- If both `np_eta` and `np_xi` are `None`, the entire dataset is saved as a single netCDF4 file.
|
|
606
|
-
- The file is named based on the provided `filepath`, with `.nc` automatically appended to the filename.
|
|
607
|
-
|
|
608
|
-
2. **Partitioned Mode**:
|
|
609
|
-
- If either `np_eta` or `np_xi` is specified, the dataset is partitioned spatially along the `eta` and `xi` axes into tiles.
|
|
610
|
-
- Each tile is saved as a separate netCDF4 file. Filenames will be modified with an index to represent each partition, e.g., `"filepath_YYYYMM.0.nc"`, `"filepath_YYYYMM.1.nc"`, etc.
|
|
708
|
+
"""Save the river forcing to netCDF4 file.
|
|
611
709
|
|
|
612
710
|
Parameters
|
|
613
711
|
----------
|
|
614
712
|
filepath : Union[str, Path]
|
|
615
|
-
The base path and filename for the output files.
|
|
616
|
-
If partitioning is used, additional indices will be appended to the filenames, e.g., `"filepath.0.nc"`, `"filepath.1.nc"`, etc.
|
|
617
|
-
|
|
618
|
-
filepath_grid : Union[str, Path]
|
|
619
|
-
The base path and filename for saving the grid file.
|
|
620
|
-
|
|
621
|
-
np_eta : int, optional
|
|
622
|
-
The number of partitions along the `eta` direction. If `None`, no spatial partitioning is performed along the `eta` axis.
|
|
623
|
-
|
|
624
|
-
np_xi : int, optional
|
|
625
|
-
The number of partitions along the `xi` direction. If `None`, no spatial partitioning is performed along the `xi` axis.
|
|
713
|
+
The base path and filename for the output files.
|
|
626
714
|
|
|
627
715
|
Returns
|
|
628
716
|
-------
|
|
@@ -632,20 +720,15 @@ class RiverForcing:
|
|
|
632
720
|
|
|
633
721
|
# Ensure filepath is a Path object
|
|
634
722
|
filepath = Path(filepath)
|
|
635
|
-
filepath_grid = Path(filepath_grid)
|
|
636
723
|
|
|
637
724
|
# Remove ".nc" suffix if present
|
|
638
725
|
if filepath.suffix == ".nc":
|
|
639
726
|
filepath = filepath.with_suffix("")
|
|
640
|
-
if filepath_grid.suffix == ".nc":
|
|
641
|
-
filepath_grid = filepath_grid.with_suffix("")
|
|
642
727
|
|
|
643
|
-
dataset_list = [self.ds
|
|
644
|
-
output_filenames = [str(filepath)
|
|
728
|
+
dataset_list = [self.ds]
|
|
729
|
+
output_filenames = [str(filepath)]
|
|
645
730
|
|
|
646
|
-
saved_filenames = save_datasets(
|
|
647
|
-
dataset_list, output_filenames, np_eta=np_eta, np_xi=np_xi
|
|
648
|
-
)
|
|
731
|
+
saved_filenames = save_datasets(dataset_list, output_filenames)
|
|
649
732
|
|
|
650
733
|
return saved_filenames
|
|
651
734
|
|
|
@@ -680,4 +763,59 @@ class RiverForcing:
|
|
|
680
763
|
grid = Grid.from_yaml(filepath)
|
|
681
764
|
params = _from_yaml(cls, filepath)
|
|
682
765
|
|
|
766
|
+
def convert_indices_format(indices):
|
|
767
|
+
# Remove the '_convention' key from the dictionary if present
|
|
768
|
+
indices = {
|
|
769
|
+
key: value for key, value in indices.items() if key != "_convention"
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
# Convert the string of indices into tuples
|
|
773
|
+
for river, index_list in indices.items():
|
|
774
|
+
# Split the string by ',' and convert to tuples of integers
|
|
775
|
+
indices[river] = [tuple(map(int, idx.split(","))) for idx in index_list]
|
|
776
|
+
|
|
777
|
+
return indices
|
|
778
|
+
|
|
779
|
+
params["indices"] = convert_indices_format(params["indices"])
|
|
780
|
+
|
|
683
781
|
return cls(grid=grid, **params)
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
def check_river_locations_are_along_coast(mask, indices):
|
|
785
|
+
"""Check if the river locations are along the coast.
|
|
786
|
+
|
|
787
|
+
This function checks if the river locations specified in the `indices` dictionary are located on coastal grid cells.
|
|
788
|
+
A coastal grid cell is defined as a land grid cell adjacent to an ocean grid cell.
|
|
789
|
+
|
|
790
|
+
Parameters
|
|
791
|
+
----------
|
|
792
|
+
mask : xarray.DataArray
|
|
793
|
+
A mask representing the land and ocean cells in the grid, where 1 represents ocean and 0 represents land.
|
|
794
|
+
|
|
795
|
+
indices : dict
|
|
796
|
+
A dictionary where the keys are river names, and the values are dictionaries containing the river's grid locations (`eta_rho` and `xi_rho`).
|
|
797
|
+
Each entry should have keys `"eta_rho"` and `"xi_rho"`, which are lists of grid cell indices representing river mouth locations.
|
|
798
|
+
|
|
799
|
+
Raises
|
|
800
|
+
------
|
|
801
|
+
ValueError
|
|
802
|
+
If any river is not located on the coast.
|
|
803
|
+
"""
|
|
804
|
+
|
|
805
|
+
faces = (
|
|
806
|
+
mask.shift(eta_rho=1)
|
|
807
|
+
+ mask.shift(eta_rho=-1)
|
|
808
|
+
+ mask.shift(xi_rho=1)
|
|
809
|
+
+ mask.shift(xi_rho=-1)
|
|
810
|
+
)
|
|
811
|
+
coast = (1 - mask) * (faces > 0)
|
|
812
|
+
|
|
813
|
+
for key, river_data in indices.items():
|
|
814
|
+
for idx_pair in river_data:
|
|
815
|
+
eta_rho, xi_rho = idx_pair
|
|
816
|
+
|
|
817
|
+
# Check if the river location is along the coast
|
|
818
|
+
if not coast[eta_rho, xi_rho]:
|
|
819
|
+
raise ValueError(
|
|
820
|
+
f"River `{key}` is not located on the coast at grid cell ({eta_rho}, {xi_rho})."
|
|
821
|
+
)
|