roms-tools 1.5.0__py3-none-any.whl → 1.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.
- roms_tools/_version.py +1 -1
- roms_tools/setup/boundary_forcing.py +226 -85
- roms_tools/setup/datasets.py +169 -39
- roms_tools/setup/fill.py +0 -36
- roms_tools/setup/initial_conditions.py +90 -69
- roms_tools/setup/regrid.py +43 -98
- roms_tools/setup/surface_forcing.py +68 -67
- roms_tools/setup/tides.py +60 -45
- roms_tools/setup/utils.py +25 -53
- roms_tools/tests/test_setup/test_boundary_forcing.py +42 -32
- 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing.zarr/.zmetadata +1 -1
- 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/iron/0.0.0 +0 -0
- 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/nox/0.0.0 +0 -0
- 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_from_climatology.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/bgc_surface_forcing_from_climatology.zarr/.zmetadata +1 -1
- 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/.zmetadata +7 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +3 -0
- 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_south/0.0.0 +0 -0
- 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_south/0.0.0 +0 -0
- 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/0.0.0 +0 -0
- 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/0.0.0 +0 -0
- 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/0.0 +0 -0
- 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/0.0 +0 -0
- 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/0.0.0 +0 -0
- 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/0.0.0 +0 -0
- 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/0.0 +0 -0
- 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/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +1 -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/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +1 -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/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/.zmetadata +1 -1
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/Tair/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/lwrad/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/qair/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/rain/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/swrad/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/uwnd/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/coarse_surface_forcing.zarr/vwnd/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/.zmetadata +1 -1
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/Tair/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/lwrad/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/qair/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/rain/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/swrad/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/uwnd/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/corrected_surface_forcing.zarr/vwnd/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK_ALT_CO2/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC_ALT_CO2/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOCr/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DON/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DONr/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOP/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOPr/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Fe/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Lig/0.0.0.0 +0 -0
- 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/O2/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/SiO3/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatChl/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatFe/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatP/0.0.0.0 +0 -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/diazC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazChl/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazFe/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazP/0.0.0.0 +0 -0
- 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/spChl/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/spP/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/initial_conditions_with_bgc_from_climatology.zarr/zooC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/.zmetadata +1 -1
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/Tair/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/lwrad/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/qair/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/rain/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/swrad/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/uwnd/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/surface_forcing.zarr/vwnd/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zmetadata +4 -2
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/omega/.zattrs +3 -1
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_datasets.py +79 -21
- roms_tools/tests/test_setup/test_fill.py +18 -105
- roms_tools/tests/test_setup/test_initial_conditions.py +21 -21
- roms_tools/tests/test_setup/test_regrid.py +2 -8
- roms_tools/tests/test_setup/test_surface_forcing.py +3 -3
- roms_tools/tests/test_setup/test_tides.py +1 -1
- {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/METADATA +12 -3
- {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/RECORD +238 -238
- {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/WHEEL +1 -1
- {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/LICENSE +0 -0
- {roms_tools-1.5.0.dist-info → roms_tools-1.6.0.dist-info}/top_level.txt +0 -0
roms_tools/setup/datasets.py
CHANGED
|
@@ -12,8 +12,10 @@ from roms_tools.setup.utils import (
|
|
|
12
12
|
interpolate_from_climatology,
|
|
13
13
|
get_time_type,
|
|
14
14
|
convert_cftime_to_datetime,
|
|
15
|
+
one_dim_fill,
|
|
15
16
|
)
|
|
16
17
|
from roms_tools.setup.download import download_correction_data
|
|
18
|
+
from roms_tools.setup.fill import LateralFill
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
@dataclass(frozen=True, kw_only=True)
|
|
@@ -117,6 +119,8 @@ class Dataset:
|
|
|
117
119
|
# Make sure that depth is ascending
|
|
118
120
|
ds = self.ensure_dimension_is_ascending(ds, dim="depth")
|
|
119
121
|
|
|
122
|
+
self.infer_horizontal_resolution(ds)
|
|
123
|
+
|
|
120
124
|
# Check whether the data covers the entire globe
|
|
121
125
|
object.__setattr__(self, "is_global", self.check_if_global(ds))
|
|
122
126
|
|
|
@@ -487,6 +491,34 @@ class Dataset:
|
|
|
487
491
|
|
|
488
492
|
return ds
|
|
489
493
|
|
|
494
|
+
def infer_horizontal_resolution(self, ds: xr.Dataset):
|
|
495
|
+
"""Estimate and set the average horizontal resolution of a dataset based on
|
|
496
|
+
latitude and longitude spacing.
|
|
497
|
+
|
|
498
|
+
Parameters
|
|
499
|
+
----------
|
|
500
|
+
ds : xr.Dataset
|
|
501
|
+
Dataset containing latitude and longitude dimensions.
|
|
502
|
+
|
|
503
|
+
Sets
|
|
504
|
+
----
|
|
505
|
+
resolution : float
|
|
506
|
+
The average horizontal resolution, derived from the mean spacing
|
|
507
|
+
between points in latitude and longitude.
|
|
508
|
+
"""
|
|
509
|
+
lat_dim = self.dim_names["latitude"]
|
|
510
|
+
lon_dim = self.dim_names["longitude"]
|
|
511
|
+
|
|
512
|
+
# Calculate mean difference along latitude and longitude
|
|
513
|
+
lat_resolution = ds[lat_dim].diff(dim=lat_dim).mean(dim=lat_dim)
|
|
514
|
+
lon_resolution = ds[lon_dim].diff(dim=lon_dim).mean(dim=lon_dim)
|
|
515
|
+
|
|
516
|
+
# Compute the average horizontal resolution
|
|
517
|
+
resolution = np.mean([lat_resolution, lon_resolution])
|
|
518
|
+
|
|
519
|
+
# Set the computed resolution as an attribute
|
|
520
|
+
object.__setattr__(self, "resolution", resolution)
|
|
521
|
+
|
|
490
522
|
def check_if_global(self, ds) -> bool:
|
|
491
523
|
"""Checks if the dataset covers the entire globe in the longitude dimension.
|
|
492
524
|
|
|
@@ -569,40 +601,31 @@ class Dataset:
|
|
|
569
601
|
"""
|
|
570
602
|
pass
|
|
571
603
|
|
|
572
|
-
def choose_subdomain(
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
longitude conversions to accommodate different longitude ranges.
|
|
604
|
+
def choose_subdomain(self, target_coords, buffer_points=20, return_copy=False):
|
|
605
|
+
"""Selects a subdomain from the xarray Dataset based on specified target
|
|
606
|
+
coordinates, extending the selection by a defined buffer. Adjusts longitude
|
|
607
|
+
ranges as necessary to accommodate the dataset's expected range and handles
|
|
608
|
+
potential discontinuities.
|
|
578
609
|
|
|
579
610
|
Parameters
|
|
580
611
|
----------
|
|
581
|
-
|
|
582
|
-
A
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
straddle : bool
|
|
588
|
-
If True, target longitudes are expected in the range [-180, 180].
|
|
589
|
-
If False, target longitudes are expected in the range [0, 360].
|
|
612
|
+
target_coords : dict
|
|
613
|
+
A dictionary containing the target latitude and longitude coordinates, typically
|
|
614
|
+
with keys "lat", "lon", and "straddle".
|
|
615
|
+
buffer_points : int
|
|
616
|
+
The number of grid points to extend beyond the specified latitude and longitude
|
|
617
|
+
ranges when selecting the subdomain. Defaults to 20.
|
|
590
618
|
return_subdomain : bool, optional
|
|
591
|
-
If True, returns the subset of the original dataset
|
|
592
|
-
Defaults to False.
|
|
619
|
+
If True, returns the subset of the original dataset representing the chosen
|
|
620
|
+
subdomain. If False, assigns the subset to `self.ds`. Defaults to False.
|
|
593
621
|
|
|
594
622
|
Returns
|
|
595
623
|
-------
|
|
596
624
|
xr.Dataset or None
|
|
597
|
-
|
|
598
|
-
including an extended area
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
Notes
|
|
602
|
-
-----
|
|
603
|
-
This method adjusts the longitude range if necessary to ensure it matches the expected range for the dataset.
|
|
604
|
-
It also handles longitude discontinuities that can occur when converting to different longitude ranges.
|
|
605
|
-
This is important for avoiding artifacts in the interpolation process.
|
|
625
|
+
Returns the subset of the original dataset as an xarray Dataset if
|
|
626
|
+
`return_subdomain` is True, including an extended area covering additional
|
|
627
|
+
grid points beyond the specified ranges. Returns None if `return_subdomain`
|
|
628
|
+
is False, as the subset is assigned to `self.ds`.
|
|
606
629
|
|
|
607
630
|
Raises
|
|
608
631
|
------
|
|
@@ -610,13 +633,17 @@ class Dataset:
|
|
|
610
633
|
If the selected latitude or longitude range does not intersect with the dataset.
|
|
611
634
|
"""
|
|
612
635
|
|
|
613
|
-
lat_min
|
|
614
|
-
|
|
636
|
+
lat_min = target_coords["lat"].min().values
|
|
637
|
+
lat_max = target_coords["lat"].max().values
|
|
638
|
+
lon_min = target_coords["lon"].min().values
|
|
639
|
+
lon_max = target_coords["lon"].max().values
|
|
640
|
+
|
|
641
|
+
margin = self.resolution * buffer_points
|
|
615
642
|
|
|
616
643
|
if not self.is_global:
|
|
617
644
|
# Adjust longitude range if needed to match the expected range
|
|
618
645
|
lon = self.ds[self.dim_names["longitude"]]
|
|
619
|
-
if not straddle:
|
|
646
|
+
if not target_coords["straddle"]:
|
|
620
647
|
if lon.min() < -180:
|
|
621
648
|
if lon_max + margin > 0:
|
|
622
649
|
lon_min -= 360
|
|
@@ -626,7 +653,7 @@ class Dataset:
|
|
|
626
653
|
lon_min -= 360
|
|
627
654
|
lon_max -= 360
|
|
628
655
|
|
|
629
|
-
if straddle:
|
|
656
|
+
if target_coords["straddle"]:
|
|
630
657
|
if lon.max() > 360:
|
|
631
658
|
if lon_min - margin < 180:
|
|
632
659
|
lon_min += 360
|
|
@@ -637,6 +664,7 @@ class Dataset:
|
|
|
637
664
|
lon_max += 360
|
|
638
665
|
|
|
639
666
|
# Select the subdomain
|
|
667
|
+
|
|
640
668
|
subdomain = self.ds.sel(
|
|
641
669
|
**{
|
|
642
670
|
self.dim_names["latitude"]: slice(lat_min - margin, lat_max + margin),
|
|
@@ -655,16 +683,109 @@ class Dataset:
|
|
|
655
683
|
|
|
656
684
|
# Adjust longitudes to expected range if needed
|
|
657
685
|
lon = subdomain[self.dim_names["longitude"]]
|
|
658
|
-
if straddle:
|
|
686
|
+
if target_coords["straddle"]:
|
|
659
687
|
subdomain[self.dim_names["longitude"]] = xr.where(lon > 180, lon - 360, lon)
|
|
660
688
|
else:
|
|
661
689
|
subdomain[self.dim_names["longitude"]] = xr.where(lon < 0, lon + 360, lon)
|
|
662
690
|
|
|
663
|
-
if
|
|
664
|
-
return subdomain
|
|
691
|
+
if return_copy:
|
|
692
|
+
return Dataset.from_ds(self, subdomain)
|
|
665
693
|
else:
|
|
666
694
|
object.__setattr__(self, "ds", subdomain)
|
|
667
695
|
|
|
696
|
+
def apply_lateral_fill(self):
|
|
697
|
+
"""Apply lateral fill to variables using the dataset's mask and grid dimensions.
|
|
698
|
+
|
|
699
|
+
This method fills masked values in `self.ds` using `LateralFill` based on
|
|
700
|
+
the horizontal grid dimensions. A separate mask (`mask_vel`) is used for
|
|
701
|
+
velocity variables (e.g., `u`, `v`) if available in the dataset.
|
|
702
|
+
|
|
703
|
+
Notes
|
|
704
|
+
-----
|
|
705
|
+
Looping over `self.ds.data_vars` instead of `self.var_names` ensures that each
|
|
706
|
+
dataset variable is filled only once, even if multiple entries in `self.var_names`
|
|
707
|
+
point to the same variable in the dataset.
|
|
708
|
+
"""
|
|
709
|
+
lateral_fill = LateralFill(
|
|
710
|
+
self.ds["mask"],
|
|
711
|
+
[self.dim_names["latitude"], self.dim_names["longitude"]],
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
separate_fill_for_velocities = False
|
|
715
|
+
if "mask_vel" in self.ds.data_vars:
|
|
716
|
+
lateral_fill_vel = LateralFill(
|
|
717
|
+
self.ds["mask_vel"],
|
|
718
|
+
[self.dim_names["latitude"], self.dim_names["longitude"]],
|
|
719
|
+
)
|
|
720
|
+
separate_fill_for_velocities = True
|
|
721
|
+
|
|
722
|
+
for var_name in self.ds.data_vars:
|
|
723
|
+
if var_name.startswith("mask"):
|
|
724
|
+
# Skip variables that are mask types
|
|
725
|
+
continue
|
|
726
|
+
elif (
|
|
727
|
+
separate_fill_for_velocities
|
|
728
|
+
and "u" in self.var_names
|
|
729
|
+
and "v" in self.var_names
|
|
730
|
+
and var_name in [self.var_names["u"], self.var_names["v"]]
|
|
731
|
+
):
|
|
732
|
+
# Apply lateral fill with velocity mask for velocity variables if present
|
|
733
|
+
self.ds[var_name] = lateral_fill_vel.apply(self.ds[var_name])
|
|
734
|
+
else:
|
|
735
|
+
# Apply standard lateral fill for other variables
|
|
736
|
+
self.ds[var_name] = lateral_fill.apply(self.ds[var_name])
|
|
737
|
+
|
|
738
|
+
def extrapolate_deepest_to_bottom(self):
|
|
739
|
+
"""Extrapolate deepest non-NaN values to fill bottom NaNs along the depth
|
|
740
|
+
dimension.
|
|
741
|
+
|
|
742
|
+
For each variable with a depth dimension, fills missing values at the bottom by
|
|
743
|
+
propagating the deepest available data downward.
|
|
744
|
+
"""
|
|
745
|
+
|
|
746
|
+
if "depth" in self.dim_names:
|
|
747
|
+
for var_name in self.ds.data_vars:
|
|
748
|
+
if self.dim_names["depth"] in self.ds[var_name].dims:
|
|
749
|
+
self.ds[var_name] = one_dim_fill(
|
|
750
|
+
self.ds[var_name], self.dim_names["depth"], direction="forward"
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
@classmethod
|
|
754
|
+
def from_ds(cls, original_dataset: "Dataset", ds: xr.Dataset) -> "Dataset":
|
|
755
|
+
"""Substitute the internal dataset of a Dataset object with a new xarray
|
|
756
|
+
Dataset.
|
|
757
|
+
|
|
758
|
+
This method creates a new Dataset instance, bypassing the usual `__init__`
|
|
759
|
+
and `__post_init__` processes. It allows for the direct assignment of the
|
|
760
|
+
provided xarray Dataset (`ds`) to the new instance's `ds` attribute. All
|
|
761
|
+
other attributes from the original dataset instance are copied to the new one.
|
|
762
|
+
|
|
763
|
+
Parameters
|
|
764
|
+
----------
|
|
765
|
+
original_dataset : Dataset
|
|
766
|
+
The original Dataset instance from which attributes will be copied.
|
|
767
|
+
ds : xarray.Dataset
|
|
768
|
+
The new xarray Dataset to assign to the `ds` attribute of the new instance.
|
|
769
|
+
|
|
770
|
+
Returns
|
|
771
|
+
-------
|
|
772
|
+
Dataset
|
|
773
|
+
A new Dataset instance with the `ds` attribute set to the provided dataset
|
|
774
|
+
and other attributes copied from the original instance.
|
|
775
|
+
"""
|
|
776
|
+
# Create a new Dataset instance without calling __init__ or __post_init__
|
|
777
|
+
dataset = cls.__new__(cls)
|
|
778
|
+
|
|
779
|
+
# Directly set the provided dataset as the 'ds' attribute
|
|
780
|
+
object.__setattr__(dataset, "ds", ds)
|
|
781
|
+
|
|
782
|
+
# Copy all other attributes from the original data instance
|
|
783
|
+
for attr in vars(original_dataset):
|
|
784
|
+
if attr != "ds":
|
|
785
|
+
object.__setattr__(dataset, attr, getattr(original_dataset, attr))
|
|
786
|
+
|
|
787
|
+
return dataset
|
|
788
|
+
|
|
668
789
|
|
|
669
790
|
@dataclass(frozen=True, kw_only=True)
|
|
670
791
|
class TPXODataset(Dataset):
|
|
@@ -803,9 +924,12 @@ class TPXODataset(Dataset):
|
|
|
803
924
|
"""
|
|
804
925
|
|
|
805
926
|
if "depth" in self.var_names.keys():
|
|
927
|
+
ds = self.ds
|
|
806
928
|
mask = xr.where(self.ds["depth"] > 0, 1, 0)
|
|
929
|
+
ds["mask"] = mask
|
|
930
|
+
ds = ds.drop_vars(["depth"])
|
|
807
931
|
|
|
808
|
-
self
|
|
932
|
+
object.__setattr__(self, "ds", ds)
|
|
809
933
|
|
|
810
934
|
# Remove "depth" from var_names
|
|
811
935
|
updated_var_names = {**self.var_names} # Create a copy of the dictionary
|
|
@@ -1261,9 +1385,13 @@ class ERA5Dataset(Dataset):
|
|
|
1261
1385
|
)
|
|
1262
1386
|
)
|
|
1263
1387
|
cff = cff * qair
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1388
|
+
|
|
1389
|
+
ds = self.ds
|
|
1390
|
+
ds["qair"] = 0.62197 * (cff / (patm - 0.378 * cff))
|
|
1391
|
+
ds["qair"].attrs["long_name"] = "Absolute humidity at 2m"
|
|
1392
|
+
ds["qair"].attrs["units"] = "kg/kg"
|
|
1393
|
+
ds = ds.drop_vars([self.var_names["d2m"]])
|
|
1394
|
+
object.__setattr__(self, "ds", ds)
|
|
1267
1395
|
|
|
1268
1396
|
# Update var_names dictionary
|
|
1269
1397
|
var_names = {**self.var_names, "qair": "qair"}
|
|
@@ -1271,9 +1399,11 @@ class ERA5Dataset(Dataset):
|
|
|
1271
1399
|
object.__setattr__(self, "var_names", var_names)
|
|
1272
1400
|
|
|
1273
1401
|
if "mask" in self.var_names.keys():
|
|
1402
|
+
ds = self.ds
|
|
1274
1403
|
mask = xr.where(self.ds[self.var_names["mask"]].isel(time=0).isnull(), 0, 1)
|
|
1275
|
-
|
|
1276
|
-
self.
|
|
1404
|
+
ds["mask"] = mask
|
|
1405
|
+
ds = ds.drop_vars([self.var_names["mask"]])
|
|
1406
|
+
object.__setattr__(self, "ds", ds)
|
|
1277
1407
|
|
|
1278
1408
|
# Remove mask from var_names dictionary
|
|
1279
1409
|
var_names = self.var_names
|
roms_tools/setup/fill.py
CHANGED
|
@@ -301,39 +301,3 @@ def stencil_grid_mod(S, grid, msk, dtype=None, format=None):
|
|
|
301
301
|
data[4, i + diags[4]] = 0
|
|
302
302
|
|
|
303
303
|
return sparse.dia_matrix((data, diags), shape=(N_v, N_v)).asformat(format)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
def _lateral_fill(data_vars, data):
|
|
307
|
-
"""Wrapper function to apply lateral fill to variables using the dataset's mask and
|
|
308
|
-
grid dimensions.
|
|
309
|
-
|
|
310
|
-
Parameters
|
|
311
|
-
----------
|
|
312
|
-
data_vars : dict of str : xarray.DataArray
|
|
313
|
-
Dictionary of variables to be filled.
|
|
314
|
-
data : Dataset
|
|
315
|
-
Dataset containing the mask and grid dimensions.
|
|
316
|
-
|
|
317
|
-
Returns
|
|
318
|
-
-------
|
|
319
|
-
dict of str : xarray.DataArray
|
|
320
|
-
Dictionary of filled variables.
|
|
321
|
-
"""
|
|
322
|
-
lateral_fill = LateralFill(
|
|
323
|
-
data.ds["mask"],
|
|
324
|
-
[data.dim_names["latitude"], data.dim_names["longitude"]],
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
if "mask_vel" in data.ds.data_vars:
|
|
328
|
-
lateral_fill_vel = LateralFill(
|
|
329
|
-
data.ds["mask_vel"],
|
|
330
|
-
[data.dim_names["latitude"], data.dim_names["longitude"]],
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
for var in data.var_names:
|
|
334
|
-
if var in ["u", "v"]:
|
|
335
|
-
data_vars[var] = lateral_fill_vel.apply(data_vars[var])
|
|
336
|
-
else:
|
|
337
|
-
data_vars[var] = lateral_fill.apply(data_vars[var])
|
|
338
|
-
|
|
339
|
-
return data_vars
|
|
@@ -15,11 +15,9 @@ from roms_tools.setup.utils import (
|
|
|
15
15
|
get_target_coords,
|
|
16
16
|
rotate_velocities,
|
|
17
17
|
compute_barotropic_velocity,
|
|
18
|
-
_extrapolate_deepest_to_bottom,
|
|
19
18
|
transpose_dimensions,
|
|
20
19
|
)
|
|
21
|
-
from roms_tools.setup.
|
|
22
|
-
from roms_tools.setup.regrid import _lateral_regrid, _vertical_regrid
|
|
20
|
+
from roms_tools.setup.regrid import LateralRegrid, VerticalRegrid
|
|
23
21
|
from roms_tools.setup.plot import _plot, _section_plot, _profile_plot, _line_plot
|
|
24
22
|
import matplotlib.pyplot as plt
|
|
25
23
|
from pathlib import Path
|
|
@@ -92,31 +90,31 @@ class InitialConditions:
|
|
|
92
90
|
|
|
93
91
|
self._input_checks()
|
|
94
92
|
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
processed_fields = {}
|
|
94
|
+
processed_fields = self._process_data(processed_fields, type="physics")
|
|
97
95
|
|
|
98
96
|
if self.bgc_source is not None:
|
|
99
|
-
|
|
97
|
+
processed_fields = self._process_data(processed_fields, type="bgc")
|
|
100
98
|
|
|
101
|
-
for
|
|
102
|
-
|
|
99
|
+
for var_name in processed_fields.keys():
|
|
100
|
+
processed_fields[var_name] = transpose_dimensions(
|
|
101
|
+
processed_fields[var_name]
|
|
102
|
+
)
|
|
103
103
|
|
|
104
104
|
d_meta = get_variable_metadata()
|
|
105
|
-
ds = self._write_into_dataset(
|
|
105
|
+
ds = self._write_into_dataset(processed_fields, d_meta)
|
|
106
106
|
|
|
107
107
|
ds = self._add_global_metadata(ds)
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
# NaN values at wet points indicate that the raw data did not cover the domain, and the following will raise a ValueError
|
|
111
|
-
nan_check(ds["zeta"].squeeze(), self.grid.ds.mask_rho)
|
|
109
|
+
self._validate(ds)
|
|
112
110
|
|
|
113
111
|
# substitute NaNs over land by a fill value to avoid blow-up of ROMS
|
|
114
|
-
for
|
|
115
|
-
ds[
|
|
112
|
+
for var_name in ds.data_vars:
|
|
113
|
+
ds[var_name] = substitute_nans_by_fillvalue(ds[var_name])
|
|
116
114
|
|
|
117
115
|
object.__setattr__(self, "ds", ds)
|
|
118
116
|
|
|
119
|
-
def _process_data(self,
|
|
117
|
+
def _process_data(self, processed_fields, type="physics"):
|
|
120
118
|
|
|
121
119
|
target_coords = get_target_coords(self.grid)
|
|
122
120
|
|
|
@@ -126,35 +124,29 @@ class InitialConditions:
|
|
|
126
124
|
data = self._get_bgc_data()
|
|
127
125
|
|
|
128
126
|
data.choose_subdomain(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
target_coords["lat"].max().values,
|
|
132
|
-
],
|
|
133
|
-
longitude_range=[
|
|
134
|
-
target_coords["lon"].min().values,
|
|
135
|
-
target_coords["lon"].max().values,
|
|
136
|
-
],
|
|
137
|
-
margin=2,
|
|
138
|
-
straddle=target_coords["straddle"],
|
|
127
|
+
target_coords,
|
|
128
|
+
buffer_points=20, # lateral fill needs good buffer from data margin
|
|
139
129
|
)
|
|
140
130
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
data_vars = _extrapolate_deepest_to_bottom(data_vars, data)
|
|
131
|
+
data.extrapolate_deepest_to_bottom()
|
|
132
|
+
data.apply_lateral_fill()
|
|
144
133
|
|
|
145
|
-
|
|
134
|
+
variable_info = self._set_variable_info(data, type=type)
|
|
135
|
+
var_names = variable_info.keys()
|
|
146
136
|
|
|
147
137
|
# lateral regridding
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
138
|
+
lateral_regrid = LateralRegrid(target_coords, data.dim_names)
|
|
139
|
+
for var_name in var_names:
|
|
140
|
+
if var_name in data.var_names.keys():
|
|
141
|
+
processed_fields[var_name] = lateral_regrid.apply(
|
|
142
|
+
data.ds[data.var_names[var_name]]
|
|
143
|
+
)
|
|
152
144
|
|
|
153
145
|
# rotation of velocities and interpolation to u/v points
|
|
154
146
|
if "u" in variable_info and "v" in variable_info:
|
|
155
|
-
(
|
|
156
|
-
|
|
157
|
-
|
|
147
|
+
(processed_fields["u"], processed_fields["v"],) = rotate_velocities(
|
|
148
|
+
processed_fields["u"],
|
|
149
|
+
processed_fields["v"],
|
|
158
150
|
target_coords["angle"],
|
|
159
151
|
interpolate=True,
|
|
160
152
|
)
|
|
@@ -167,28 +159,32 @@ class InitialConditions:
|
|
|
167
159
|
if info["location"] == location and info["is_3d"]
|
|
168
160
|
]
|
|
169
161
|
if len(var_names) > 0:
|
|
170
|
-
|
|
171
|
-
data,
|
|
162
|
+
vertical_regrid = VerticalRegrid(
|
|
172
163
|
self.grid.ds[f"layer_depth_{location}"],
|
|
173
|
-
|
|
174
|
-
var_names,
|
|
164
|
+
data.ds[data.dim_names["depth"]],
|
|
175
165
|
)
|
|
166
|
+
for var_name in var_names:
|
|
167
|
+
if var_name in processed_fields:
|
|
168
|
+
processed_fields[var_name] = vertical_regrid.apply(
|
|
169
|
+
processed_fields[var_name]
|
|
170
|
+
)
|
|
176
171
|
|
|
177
172
|
# compute barotropic velocities
|
|
178
173
|
if "u" in variable_info and "v" in variable_info:
|
|
179
|
-
for
|
|
180
|
-
|
|
181
|
-
|
|
174
|
+
for var_name in ["u", "v"]:
|
|
175
|
+
processed_fields[f"{var_name}bar"] = compute_barotropic_velocity(
|
|
176
|
+
processed_fields[var_name],
|
|
177
|
+
self.grid.ds[f"interface_depth_{var_name}"],
|
|
182
178
|
)
|
|
183
179
|
|
|
184
180
|
if type == "bgc":
|
|
185
181
|
# Ensure time coordinate matches that of physical variables
|
|
186
|
-
for
|
|
187
|
-
|
|
188
|
-
{"time":
|
|
182
|
+
for var_name in variable_info.keys():
|
|
183
|
+
processed_fields[var_name] = processed_fields[var_name].assign_coords(
|
|
184
|
+
{"time": processed_fields["temp"]["time"]}
|
|
189
185
|
)
|
|
190
186
|
|
|
191
|
-
return
|
|
187
|
+
return processed_fields
|
|
192
188
|
|
|
193
189
|
def _input_checks(self):
|
|
194
190
|
|
|
@@ -314,24 +310,26 @@ class InitialConditions:
|
|
|
314
310
|
}
|
|
315
311
|
elif type == "bgc":
|
|
316
312
|
variable_info = {}
|
|
317
|
-
for
|
|
318
|
-
variable_info[
|
|
313
|
+
for var_name in data.var_names.keys():
|
|
314
|
+
variable_info[var_name] = default_info
|
|
319
315
|
|
|
320
316
|
return variable_info
|
|
321
317
|
|
|
322
|
-
def _write_into_dataset(self,
|
|
318
|
+
def _write_into_dataset(self, processed_fields, d_meta):
|
|
323
319
|
|
|
324
320
|
# save in new dataset
|
|
325
321
|
ds = xr.Dataset()
|
|
326
322
|
|
|
327
|
-
for
|
|
328
|
-
ds[
|
|
329
|
-
ds[
|
|
330
|
-
ds[
|
|
323
|
+
for var_name in processed_fields.keys():
|
|
324
|
+
ds[var_name] = processed_fields[var_name].astype(np.float32)
|
|
325
|
+
ds[var_name].attrs["long_name"] = d_meta[var_name]["long_name"]
|
|
326
|
+
ds[var_name].attrs["units"] = d_meta[var_name]["units"]
|
|
331
327
|
|
|
332
328
|
# initialize vertical velocity to zero
|
|
333
329
|
ds["w"] = xr.zeros_like(
|
|
334
|
-
self.grid.ds["interface_depth_rho"].expand_dims(
|
|
330
|
+
self.grid.ds["interface_depth_rho"].expand_dims(
|
|
331
|
+
time=processed_fields["u"].time
|
|
332
|
+
)
|
|
335
333
|
).astype(np.float32)
|
|
336
334
|
ds["w"].attrs["long_name"] = d_meta["w"]["long_name"]
|
|
337
335
|
ds["w"].attrs["units"] = d_meta["w"]["units"]
|
|
@@ -351,7 +349,7 @@ class InitialConditions:
|
|
|
351
349
|
"layer_depth_v",
|
|
352
350
|
"interface_depth_v",
|
|
353
351
|
]
|
|
354
|
-
existing_vars = [
|
|
352
|
+
existing_vars = [var_name for var_name in variables_to_drop if var_name in ds]
|
|
355
353
|
ds = ds.drop_vars(existing_vars)
|
|
356
354
|
|
|
357
355
|
ds["Cs_r"] = self.grid.ds["Cs_r"]
|
|
@@ -375,6 +373,29 @@ class InitialConditions:
|
|
|
375
373
|
|
|
376
374
|
return ds
|
|
377
375
|
|
|
376
|
+
def _validate(self, ds):
|
|
377
|
+
"""Validates the dataset by checking for NaN values in SSH at wet points, which
|
|
378
|
+
would indicate missing raw data coverage over the target domain.
|
|
379
|
+
|
|
380
|
+
Parameters
|
|
381
|
+
----------
|
|
382
|
+
ds : xarray.Dataset
|
|
383
|
+
The dataset to validate.
|
|
384
|
+
|
|
385
|
+
Raises
|
|
386
|
+
------
|
|
387
|
+
ValueError
|
|
388
|
+
If NaN values are found in any of the specified variables at wet points,
|
|
389
|
+
indicating incomplete data coverage.
|
|
390
|
+
|
|
391
|
+
Notes
|
|
392
|
+
-----
|
|
393
|
+
This check is only applied to the 2D variable SSH to improve performance.
|
|
394
|
+
"""
|
|
395
|
+
|
|
396
|
+
ds["zeta"].load()
|
|
397
|
+
nan_check(ds["zeta"].squeeze(), self.grid.ds.mask_rho)
|
|
398
|
+
|
|
378
399
|
def _add_global_metadata(self, ds):
|
|
379
400
|
|
|
380
401
|
ds.attrs["title"] = "ROMS initial conditions file created by ROMS-Tools"
|
|
@@ -398,7 +419,7 @@ class InitialConditions:
|
|
|
398
419
|
|
|
399
420
|
def plot(
|
|
400
421
|
self,
|
|
401
|
-
|
|
422
|
+
var_name,
|
|
402
423
|
s=None,
|
|
403
424
|
eta=None,
|
|
404
425
|
xi=None,
|
|
@@ -409,7 +430,7 @@ class InitialConditions:
|
|
|
409
430
|
|
|
410
431
|
Parameters
|
|
411
432
|
----------
|
|
412
|
-
|
|
433
|
+
var_name : str
|
|
413
434
|
The name of the initial conditions field to plot. Options include:
|
|
414
435
|
|
|
415
436
|
- "temp": Potential temperature.
|
|
@@ -480,25 +501,25 @@ class InitialConditions:
|
|
|
480
501
|
Raises
|
|
481
502
|
------
|
|
482
503
|
ValueError
|
|
483
|
-
If the specified `
|
|
484
|
-
If the field specified by `
|
|
485
|
-
If the field specified by `
|
|
504
|
+
If the specified `var_name` is not one of the valid options.
|
|
505
|
+
If the field specified by `var_name` is 3D and none of `s`, `eta`, or `xi` are specified.
|
|
506
|
+
If the field specified by `var_name` is 2D and both `eta` and `xi` are specified.
|
|
486
507
|
"""
|
|
487
508
|
|
|
488
|
-
if len(self.ds[
|
|
509
|
+
if len(self.ds[var_name].squeeze().dims) == 3 and not any(
|
|
489
510
|
[s is not None, eta is not None, xi is not None]
|
|
490
511
|
):
|
|
491
512
|
raise ValueError(
|
|
492
513
|
"For 3D fields, at least one of s, eta, or xi must be specified."
|
|
493
514
|
)
|
|
494
515
|
|
|
495
|
-
if len(self.ds[
|
|
516
|
+
if len(self.ds[var_name].squeeze().dims) == 2 and all(
|
|
496
517
|
[eta is not None, xi is not None]
|
|
497
518
|
):
|
|
498
519
|
raise ValueError("For 2D fields, specify either eta or xi, not both.")
|
|
499
520
|
|
|
500
|
-
self.ds[
|
|
501
|
-
field = self.ds[
|
|
521
|
+
self.ds[var_name].load()
|
|
522
|
+
field = self.ds[var_name].squeeze()
|
|
502
523
|
|
|
503
524
|
if all(dim in field.dims for dim in ["eta_rho", "xi_rho"]):
|
|
504
525
|
interface_depth = self.grid.ds.interface_depth_rho
|
|
@@ -553,7 +574,7 @@ class InitialConditions:
|
|
|
553
574
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
554
575
|
else:
|
|
555
576
|
raise ValueError(
|
|
556
|
-
f"None of the expected dimensions (eta_rho, eta_v) found in ds[{
|
|
577
|
+
f"None of the expected dimensions (eta_rho, eta_v) found in ds[{var_name}]."
|
|
557
578
|
)
|
|
558
579
|
if xi is not None:
|
|
559
580
|
if "xi_rho" in field.dims:
|
|
@@ -572,18 +593,18 @@ class InitialConditions:
|
|
|
572
593
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
573
594
|
else:
|
|
574
595
|
raise ValueError(
|
|
575
|
-
f"None of the expected dimensions (xi_rho, xi_u) found in ds[{
|
|
596
|
+
f"None of the expected dimensions (xi_rho, xi_u) found in ds[{var_name}]."
|
|
576
597
|
)
|
|
577
598
|
|
|
578
599
|
# chose colorbar
|
|
579
|
-
if
|
|
600
|
+
if var_name in ["u", "v", "w", "ubar", "vbar", "zeta"]:
|
|
580
601
|
vmax = max(field.max().values, -field.min().values)
|
|
581
602
|
vmin = -vmax
|
|
582
603
|
cmap = plt.colormaps.get_cmap("RdBu_r")
|
|
583
604
|
else:
|
|
584
605
|
vmax = field.max().values
|
|
585
606
|
vmin = field.min().values
|
|
586
|
-
if
|
|
607
|
+
if var_name in ["temp", "salt"]:
|
|
587
608
|
cmap = plt.colormaps.get_cmap("YlOrRd")
|
|
588
609
|
else:
|
|
589
610
|
cmap = plt.colormaps.get_cmap("YlGn")
|