roms-tools 3.1.2__py3-none-any.whl → 3.3.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/__init__.py +3 -0
- roms_tools/analysis/cdr_analysis.py +203 -0
- roms_tools/analysis/cdr_ensemble.py +198 -0
- roms_tools/analysis/roms_output.py +80 -46
- roms_tools/data/grids/GLORYS_global_grid.nc +0 -0
- roms_tools/download.py +4 -0
- roms_tools/plot.py +113 -51
- roms_tools/setup/boundary_forcing.py +45 -20
- roms_tools/setup/cdr_forcing.py +122 -8
- roms_tools/setup/cdr_release.py +161 -8
- roms_tools/setup/grid.py +150 -141
- roms_tools/setup/initial_conditions.py +113 -48
- roms_tools/setup/{datasets.py → lat_lon_datasets.py} +443 -938
- roms_tools/setup/mask.py +63 -7
- roms_tools/setup/nesting.py +314 -117
- roms_tools/setup/river_datasets.py +527 -0
- roms_tools/setup/river_forcing.py +46 -20
- roms_tools/setup/surface_forcing.py +7 -9
- roms_tools/setup/tides.py +2 -3
- roms_tools/setup/topography.py +8 -10
- roms_tools/setup/utils.py +396 -23
- roms_tools/tests/test_analysis/test_cdr_analysis.py +144 -0
- roms_tools/tests/test_analysis/test_cdr_ensemble.py +202 -0
- roms_tools/tests/test_analysis/test_roms_output.py +61 -3
- roms_tools/tests/test_setup/test_boundary_forcing.py +54 -52
- roms_tools/tests/test_setup/test_cdr_forcing.py +54 -0
- roms_tools/tests/test_setup/test_cdr_release.py +118 -1
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_ALT_CO2_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/ALK_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_ALT_CO2_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DIC_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOC_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOCr_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DON_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DONr_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOP_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/DOPr_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Fe_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/Lig_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NH4_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/NO3_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/O2_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/PO4_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/SiO3_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatC_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatChl_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatFe_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatP_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diatSi_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazC_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazChl_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazFe_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/diazP_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spC_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spCaCO3_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spChl_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spFe_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/spP_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zarr.json +406 -406
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/bgc_boundary_forcing_from_climatology.zarr/zooC_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zarr.json +182 -182
- roms_tools/tests/test_setup/test_data/grid.zarr/h/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid.zarr/zarr.json +191 -191
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/c/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/zarr.json +210 -210
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ALK_ALT_CO2/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DIC_ALT_CO2/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOCr/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DON/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DONr/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/DOPr/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Fe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Lig/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/O2/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/SiO3/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatChl/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatFe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazChl/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazFe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diazP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/salt/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spChl/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spP/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zarr.json +182 -182
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/zooC/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/salt/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/temp/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/u/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/ubar/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/v/c/0/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/vbar/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_unified_bgc_from_climatology.zarr/zarr.json +187 -187
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/c/0/0/0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/zarr.json +66 -66
- roms_tools/tests/test_setup/test_grid.py +236 -115
- roms_tools/tests/test_setup/test_initial_conditions.py +94 -41
- roms_tools/tests/test_setup/{test_datasets.py → test_lat_lon_datasets.py} +409 -100
- roms_tools/tests/test_setup/test_nesting.py +119 -31
- roms_tools/tests/test_setup/test_river_datasets.py +48 -0
- roms_tools/tests/test_setup/test_surface_forcing.py +2 -1
- roms_tools/tests/test_setup/test_utils.py +92 -2
- roms_tools/tests/test_setup/utils.py +71 -0
- roms_tools/tests/test_tiling/test_join.py +241 -0
- roms_tools/tests/test_utils.py +139 -17
- roms_tools/tiling/join.py +189 -0
- roms_tools/utils.py +131 -99
- {roms_tools-3.1.2.dist-info → roms_tools-3.3.0.dist-info}/METADATA +12 -2
- {roms_tools-3.1.2.dist-info → roms_tools-3.3.0.dist-info}/RECORD +221 -211
- {roms_tools-3.1.2.dist-info → roms_tools-3.3.0.dist-info}/WHEEL +0 -0
- {roms_tools-3.1.2.dist-info → roms_tools-3.3.0.dist-info}/licenses/LICENSE +0 -0
- {roms_tools-3.1.2.dist-info → roms_tools-3.3.0.dist-info}/top_level.txt +0 -0
roms_tools/setup/cdr_release.py
CHANGED
|
@@ -5,6 +5,8 @@ from datetime import datetime
|
|
|
5
5
|
from enum import StrEnum, auto
|
|
6
6
|
from typing import Annotated, Literal
|
|
7
7
|
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
8
10
|
from annotated_types import Ge, Le
|
|
9
11
|
from pydantic import (
|
|
10
12
|
BaseModel,
|
|
@@ -16,10 +18,17 @@ from pydantic import (
|
|
|
16
18
|
)
|
|
17
19
|
from pydantic_core.core_schema import ValidationInfo
|
|
18
20
|
|
|
19
|
-
from roms_tools.setup.utils import
|
|
21
|
+
from roms_tools.setup.utils import (
|
|
22
|
+
convert_to_relative_days,
|
|
23
|
+
get_tracer_defaults,
|
|
24
|
+
get_tracer_metadata_dict,
|
|
25
|
+
)
|
|
20
26
|
|
|
21
27
|
NonNegativeFloat = Annotated[float, Ge(0)]
|
|
22
28
|
|
|
29
|
+
# Show all columns when printing a DataFrame
|
|
30
|
+
pd.set_option("display.max_columns", None)
|
|
31
|
+
|
|
23
32
|
|
|
24
33
|
@dataclass
|
|
25
34
|
class ValueArray(ABC):
|
|
@@ -272,10 +281,68 @@ class Release(BaseModel):
|
|
|
272
281
|
if self.times[-1] < end_time:
|
|
273
282
|
self.times.append(end_time)
|
|
274
283
|
|
|
275
|
-
@
|
|
276
|
-
def get_tracer_metadata():
|
|
284
|
+
@classmethod
|
|
285
|
+
def get_tracer_metadata(cls):
|
|
277
286
|
return {}
|
|
278
287
|
|
|
288
|
+
@classmethod
|
|
289
|
+
def get_metadata(cls):
|
|
290
|
+
return pd.DataFrame(cls.get_tracer_metadata())
|
|
291
|
+
|
|
292
|
+
def _compute_integrated_tracers(
|
|
293
|
+
self,
|
|
294
|
+
roms_time_stamps: np.ndarray,
|
|
295
|
+
model_reference_date: datetime,
|
|
296
|
+
tracer_series_dict: dict[str, np.ndarray],
|
|
297
|
+
) -> dict[str, float]:
|
|
298
|
+
"""
|
|
299
|
+
Compute time-integrated tracer quantities over ROMS time steps using a left-hold rule.
|
|
300
|
+
|
|
301
|
+
This method performs a left-hold (stepwise constant) integration of tracer fluxes
|
|
302
|
+
over the intervals defined by the ROMS time stamps. It first interpolates the
|
|
303
|
+
tracer time series from the release schedule onto the ROMS time stamps, then
|
|
304
|
+
multiplies the value at the start of each interval by the duration of that interval.
|
|
305
|
+
|
|
306
|
+
Parameters
|
|
307
|
+
----------
|
|
308
|
+
roms_time_stamps : np.ndarray
|
|
309
|
+
1D array of ROMS model time stamps in seconds since `model_reference_date`.
|
|
310
|
+
Must be strictly increasing and contain at least two entries.
|
|
311
|
+
model_reference_date : datetime
|
|
312
|
+
Reference datetime of the ROMS model calendar, used to compute relative times
|
|
313
|
+
for interpolation.
|
|
314
|
+
tracer_series_dict : dict[str, np.ndarray]
|
|
315
|
+
Dictionary mapping tracer names to 1D arrays of tracer flux values at the
|
|
316
|
+
release schedule times (`self.times`). Each array must have the same length
|
|
317
|
+
as `self.times`.
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
dict[str, float]
|
|
322
|
+
Dictionary mapping each tracer name to its integrated quantity over the
|
|
323
|
+
ROMS time period. Integration is performed using the left-hold rule,
|
|
324
|
+
ignoring the last release point because it defines the end of the final interval.
|
|
325
|
+
|
|
326
|
+
Raises
|
|
327
|
+
------
|
|
328
|
+
ValueError
|
|
329
|
+
If `roms_time_stamps` has fewer than two entries, since at least one interval
|
|
330
|
+
is required for integration.
|
|
331
|
+
"""
|
|
332
|
+
if len(roms_time_stamps) < 2:
|
|
333
|
+
raise ValueError("Need at least two ROMS time stamps to define intervals.")
|
|
334
|
+
|
|
335
|
+
dt = np.diff(roms_time_stamps)
|
|
336
|
+
results = {}
|
|
337
|
+
for tracer, series in tracer_series_dict.items():
|
|
338
|
+
interp_values = np.interp(
|
|
339
|
+
roms_time_stamps,
|
|
340
|
+
convert_to_relative_days(self.times, model_reference_date) * 3600 * 24,
|
|
341
|
+
series,
|
|
342
|
+
)
|
|
343
|
+
results[tracer] = np.sum(interp_values[:-1] * dt)
|
|
344
|
+
return results
|
|
345
|
+
|
|
279
346
|
|
|
280
347
|
class VolumeRelease(Release):
|
|
281
348
|
"""Represents a CDR release with volume flux and tracer concentrations.
|
|
@@ -389,9 +456,11 @@ class VolumeRelease(Release):
|
|
|
389
456
|
num_times = len(self.times)
|
|
390
457
|
|
|
391
458
|
for tracer_concentrations in self.tracer_concentrations.values():
|
|
392
|
-
tracer_concentrations
|
|
459
|
+
if isinstance(tracer_concentrations, Concentration):
|
|
460
|
+
tracer_concentrations.check_length(num_times)
|
|
393
461
|
|
|
394
|
-
self.volume_fluxes
|
|
462
|
+
if isinstance(self.volume_fluxes, Flux):
|
|
463
|
+
self.volume_fluxes.check_length(num_times)
|
|
395
464
|
|
|
396
465
|
return self
|
|
397
466
|
|
|
@@ -410,7 +479,52 @@ class VolumeRelease(Release):
|
|
|
410
479
|
@staticmethod
|
|
411
480
|
def get_tracer_metadata():
|
|
412
481
|
"""Returns long names and expected units for the tracer concentrations."""
|
|
413
|
-
return get_tracer_metadata_dict(include_bgc=True,
|
|
482
|
+
return get_tracer_metadata_dict(include_bgc=True, unit_type="concentration")
|
|
483
|
+
|
|
484
|
+
def _do_accounting(
|
|
485
|
+
self,
|
|
486
|
+
roms_time_stamps: np.ndarray,
|
|
487
|
+
model_reference_date: datetime,
|
|
488
|
+
) -> dict[str, float]:
|
|
489
|
+
"""
|
|
490
|
+
Compute time-integrated tracer quantities over ROMS time steps.
|
|
491
|
+
|
|
492
|
+
This method interpolates tracer flux time series from the CDR schedule
|
|
493
|
+
onto the provided ROMS time stamps (in seconds since model reference date),
|
|
494
|
+
then applies a "left-hold" rule: the interpolated value at t₀ is applied
|
|
495
|
+
across the full interval [t₀, t₁).
|
|
496
|
+
|
|
497
|
+
Parameters
|
|
498
|
+
----------
|
|
499
|
+
roms_time_stamps : np.ndarray
|
|
500
|
+
1D array of ROMS time stamps (seconds since `model_reference_date`).
|
|
501
|
+
Must be strictly increasing.
|
|
502
|
+
model_reference_date : datetime
|
|
503
|
+
Reference date of the ROMS model calendar.
|
|
504
|
+
|
|
505
|
+
Returns
|
|
506
|
+
-------
|
|
507
|
+
dict[str, float]
|
|
508
|
+
Dictionary mapping tracer names to the total integrated quantity over
|
|
509
|
+
the entire ROMS time period. Each value is the sum of the interpolated
|
|
510
|
+
tracer fluxes multiplied by the corresponding ROMS time step durations.
|
|
511
|
+
"""
|
|
512
|
+
tracer_series_dict = {}
|
|
513
|
+
volume_array = (
|
|
514
|
+
np.asarray(self.volume_fluxes.values)
|
|
515
|
+
if isinstance(self.volume_fluxes, Flux)
|
|
516
|
+
else np.asarray(self.volume_fluxes)
|
|
517
|
+
)
|
|
518
|
+
for tracer, conc in self.tracer_concentrations.items():
|
|
519
|
+
tracer_array = (
|
|
520
|
+
np.asarray(conc.values)
|
|
521
|
+
if isinstance(conc, Concentration)
|
|
522
|
+
else np.asarray(conc)
|
|
523
|
+
)
|
|
524
|
+
tracer_series_dict[tracer] = volume_array * tracer_array
|
|
525
|
+
return self._compute_integrated_tracers(
|
|
526
|
+
roms_time_stamps, model_reference_date, tracer_series_dict
|
|
527
|
+
)
|
|
414
528
|
|
|
415
529
|
@model_serializer(mode="wrap")
|
|
416
530
|
def _simplified_dump(self, pydantic_serializer) -> dict:
|
|
@@ -503,7 +617,8 @@ class TracerPerturbation(Release):
|
|
|
503
617
|
def _check_tracer_flux_lengths(self):
|
|
504
618
|
num_times = len(self.times)
|
|
505
619
|
for flux in self.tracer_fluxes.values():
|
|
506
|
-
flux
|
|
620
|
+
if isinstance(flux, Flux):
|
|
621
|
+
flux.check_length(num_times)
|
|
507
622
|
return self
|
|
508
623
|
|
|
509
624
|
def _extend_to_endpoints(self, start_time, end_time):
|
|
@@ -520,7 +635,45 @@ class TracerPerturbation(Release):
|
|
|
520
635
|
@staticmethod
|
|
521
636
|
def get_tracer_metadata():
|
|
522
637
|
"""Returns long names and expected units for the tracer fluxes."""
|
|
523
|
-
return get_tracer_metadata_dict(include_bgc=True,
|
|
638
|
+
return get_tracer_metadata_dict(include_bgc=True, unit_type="flux")
|
|
639
|
+
|
|
640
|
+
def _do_accounting(
|
|
641
|
+
self,
|
|
642
|
+
roms_time_stamps: np.ndarray,
|
|
643
|
+
model_reference_date: datetime,
|
|
644
|
+
) -> dict[str, float]:
|
|
645
|
+
"""
|
|
646
|
+
Compute time-integrated tracer quantities over ROMS time steps.
|
|
647
|
+
|
|
648
|
+
This method interpolates tracer flux time series from the CDR schedule
|
|
649
|
+
onto the provided ROMS time stamps (in days since model reference date),
|
|
650
|
+
then applies a "left-hold" rule: the interpolated value at t₀ is applied
|
|
651
|
+
across the full interval [t₀, t₁).
|
|
652
|
+
|
|
653
|
+
Parameters
|
|
654
|
+
----------
|
|
655
|
+
roms_time_stamps : np.ndarray
|
|
656
|
+
1D array of ROMS time stamps (days since `model_reference_date`).
|
|
657
|
+
Must be strictly increasing.
|
|
658
|
+
model_reference_date : datetime
|
|
659
|
+
Reference date of the ROMS model calendar.
|
|
660
|
+
|
|
661
|
+
Returns
|
|
662
|
+
-------
|
|
663
|
+
dict[str, float]
|
|
664
|
+
Dictionary mapping tracer names to the total integrated quantity over
|
|
665
|
+
the entire ROMS time period. Each value is the sum of the interpolated
|
|
666
|
+
tracer fluxes multiplied by the corresponding ROMS time step durations.
|
|
667
|
+
"""
|
|
668
|
+
tracer_series_dict = {
|
|
669
|
+
tracer: np.asarray(flux.values)
|
|
670
|
+
if isinstance(flux, Flux)
|
|
671
|
+
else np.asarray(flux)
|
|
672
|
+
for tracer, flux in self.tracer_fluxes.items()
|
|
673
|
+
}
|
|
674
|
+
return self._compute_integrated_tracers(
|
|
675
|
+
roms_time_stamps, model_reference_date, tracer_series_dict
|
|
676
|
+
)
|
|
524
677
|
|
|
525
678
|
@model_serializer(mode="wrap")
|
|
526
679
|
def _simplified_dump(self, pydantic_serializer) -> dict:
|
roms_tools/setup/grid.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import importlib.metadata
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
|
-
import time
|
|
5
4
|
from dataclasses import asdict, dataclass, field
|
|
6
5
|
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
import xarray as xr
|
|
@@ -12,9 +12,10 @@ from matplotlib.axes import Axes
|
|
|
12
12
|
|
|
13
13
|
from roms_tools.constants import MAXIMUM_GRID_SIZE, R_EARTH
|
|
14
14
|
from roms_tools.plot import plot
|
|
15
|
-
from roms_tools.setup.mask import
|
|
16
|
-
from roms_tools.setup.topography import
|
|
15
|
+
from roms_tools.setup.mask import add_mask, add_velocity_masks
|
|
16
|
+
from roms_tools.setup.topography import add_topography
|
|
17
17
|
from roms_tools.setup.utils import (
|
|
18
|
+
Timed,
|
|
18
19
|
extract_single_value,
|
|
19
20
|
gc_dist,
|
|
20
21
|
get_target_coords,
|
|
@@ -64,6 +65,8 @@ class Grid:
|
|
|
64
65
|
- "path" (Union[str, Path, List[Union[str, Path]]]): The path to the raw data file. Can be a string or a Path object.
|
|
65
66
|
|
|
66
67
|
The default is "ETOPO5", which does not require a path.
|
|
68
|
+
mask_shapefile: str | Path | None, optional
|
|
69
|
+
Path to a custom shapefile to use to determine the land mask; if None, use NaturalEarth 10m.
|
|
67
70
|
hmin : float, optional
|
|
68
71
|
The minimum ocean depth (in meters). The default is 5.0.
|
|
69
72
|
N : int, optional
|
|
@@ -106,8 +109,10 @@ class Grid:
|
|
|
106
109
|
"""The bottom control parameter."""
|
|
107
110
|
hc: float = 300.0
|
|
108
111
|
"""The critical depth (in meters)."""
|
|
109
|
-
topography_source: dict[str, str | Path | list[str | Path]] = None
|
|
112
|
+
topography_source: dict[str, str | Path | list[str | Path]] | None = None
|
|
110
113
|
"""Dictionary specifying the source of the topography data."""
|
|
114
|
+
mask_shapefile: str | Path | None = None
|
|
115
|
+
"""Path to a custom shapefile to use to determine the landmask; if None, use NaturalEarth 10m."""
|
|
111
116
|
hmin: float = 5.0
|
|
112
117
|
"""The minimum ocean depth (in meters)."""
|
|
113
118
|
verbose: bool = False
|
|
@@ -129,7 +134,7 @@ class Grid:
|
|
|
129
134
|
self._straddle()
|
|
130
135
|
|
|
131
136
|
# Mask
|
|
132
|
-
self.
|
|
137
|
+
self.update_mask(mask_shapefile=self.mask_shapefile, verbose=self.verbose)
|
|
133
138
|
|
|
134
139
|
# Coarsen the dataset if needed
|
|
135
140
|
self._coarsen()
|
|
@@ -165,28 +170,50 @@ class Grid:
|
|
|
165
170
|
"`topography_source` must include a 'path' key when the 'name' is not 'ETOPO5'."
|
|
166
171
|
)
|
|
167
172
|
|
|
168
|
-
def
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
+
def update_mask(
|
|
174
|
+
self, mask_shapefile: str | Path | None = None, verbose: bool = False
|
|
175
|
+
) -> None:
|
|
176
|
+
"""
|
|
177
|
+
Update the land mask of the current grid dataset.
|
|
173
178
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
+
This method generates a land mask based on the provided coastline
|
|
180
|
+
shapefile, fills enclosed basins with lands and updates the dataset
|
|
181
|
+
stored in `self.ds`. If no shapefile is provided, a default dataset (Natural
|
|
182
|
+
Earth 10m) is used. The operation is optionally timed and logged.
|
|
179
183
|
|
|
180
|
-
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
mask_shapefile : str or Path, optional
|
|
187
|
+
Path to a coastal shapefile to derive the land mask. If `None`,
|
|
188
|
+
the default Natural Earth 10m coastline dataset is used.
|
|
189
|
+
verbose : bool, default False
|
|
190
|
+
If True, prints timing and progress information.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
None
|
|
195
|
+
Updates the `self.ds` attribute in place with the new mask.
|
|
196
|
+
|
|
197
|
+
"""
|
|
198
|
+
with Timed("=== Deriving the mask from coastlines ===", verbose=verbose):
|
|
199
|
+
ds = add_mask(self.ds, shapefile=mask_shapefile)
|
|
200
|
+
self.ds = ds
|
|
201
|
+
self.mask_shapefile = mask_shapefile
|
|
181
202
|
|
|
182
203
|
def update_topography(
|
|
183
|
-
self,
|
|
204
|
+
self,
|
|
205
|
+
topography_source: dict | None = None,
|
|
206
|
+
hmin: float | None = None,
|
|
207
|
+
verbose: bool = False,
|
|
184
208
|
) -> None:
|
|
185
209
|
"""Update the grid dataset with processed topography.
|
|
186
210
|
|
|
187
|
-
This method performs
|
|
188
|
-
|
|
189
|
-
|
|
211
|
+
This method performs the following operations:
|
|
212
|
+
|
|
213
|
+
1. Regrids the topography from the specified source.
|
|
214
|
+
2. Applies domain-wide and local smoothing.
|
|
215
|
+
3. Enforces the minimum depth constraint ``hmin``.
|
|
216
|
+
4. Updates the internal dataset (``self.ds``) with the processed bathymetry.
|
|
190
217
|
|
|
191
218
|
Parameters
|
|
192
219
|
----------
|
|
@@ -215,36 +242,27 @@ class Grid:
|
|
|
215
242
|
topography_source = topography_source or self.topography_source
|
|
216
243
|
hmin = hmin or self.hmin
|
|
217
244
|
|
|
245
|
+
name = topography_source["name"] # type: ignore[index]
|
|
246
|
+
|
|
218
247
|
# Extract target coordinates for processing
|
|
219
248
|
target_coords = get_target_coords(self)
|
|
220
249
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
start_time = time.time()
|
|
224
|
-
logging.info(
|
|
225
|
-
f"=== Generating the topography using {topography_source['name']} data and hmin = {hmin} meters ==="
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
# Add topography to the dataset
|
|
229
|
-
ds = _add_topography(
|
|
230
|
-
ds=self.ds,
|
|
231
|
-
target_coords=target_coords,
|
|
232
|
-
topography_source=topography_source,
|
|
233
|
-
hmin=hmin,
|
|
250
|
+
with Timed(
|
|
251
|
+
f"=== Generating the topography using {name} data and hmin = {hmin} meters ===",
|
|
234
252
|
verbose=verbose,
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
253
|
+
):
|
|
254
|
+
ds = add_topography(
|
|
255
|
+
ds=self.ds,
|
|
256
|
+
target_coords=target_coords,
|
|
257
|
+
topography_source=topography_source,
|
|
258
|
+
hmin=hmin,
|
|
259
|
+
verbose=verbose,
|
|
242
260
|
)
|
|
243
261
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
262
|
+
# Update the grid's dataset and related attributes
|
|
263
|
+
self.ds = ds
|
|
264
|
+
self.topography_source = topography_source
|
|
265
|
+
self.hmin = hmin
|
|
248
266
|
|
|
249
267
|
def update_vertical_coordinate(
|
|
250
268
|
self, N=None, theta_s=None, theta_b=None, hc=None, verbose=False
|
|
@@ -281,69 +299,61 @@ class Grid:
|
|
|
281
299
|
theta_b = theta_b or self.theta_b
|
|
282
300
|
hc = hc or self.hc
|
|
283
301
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
302
|
+
with Timed(
|
|
303
|
+
f"=== Preparing the vertical coordinate system using N = {N}, theta_s = {theta_s}, theta_b = {theta_b}, hc = {hc} ===",
|
|
304
|
+
verbose=verbose,
|
|
305
|
+
):
|
|
306
|
+
ds = self.ds
|
|
307
|
+
# need to drop vertical coordinates because they could cause conflict if N changed
|
|
308
|
+
vars_to_drop = [
|
|
309
|
+
"layer_depth_rho",
|
|
310
|
+
"layer_depth_u",
|
|
311
|
+
"layer_depth_v",
|
|
312
|
+
"interface_depth_rho",
|
|
313
|
+
"interface_depth_u",
|
|
314
|
+
"interface_depth_v",
|
|
315
|
+
"sigma_r",
|
|
316
|
+
"sigma_w",
|
|
317
|
+
"Cs_w",
|
|
318
|
+
"Cs_r",
|
|
319
|
+
]
|
|
289
320
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
"layer_depth_rho",
|
|
294
|
-
"layer_depth_u",
|
|
295
|
-
"layer_depth_v",
|
|
296
|
-
"interface_depth_rho",
|
|
297
|
-
"interface_depth_u",
|
|
298
|
-
"interface_depth_v",
|
|
299
|
-
"sigma_r",
|
|
300
|
-
"sigma_w",
|
|
301
|
-
"Cs_w",
|
|
302
|
-
"Cs_r",
|
|
303
|
-
]
|
|
304
|
-
|
|
305
|
-
for var in vars_to_drop:
|
|
306
|
-
if var in ds.variables:
|
|
307
|
-
ds = ds.drop_vars(var)
|
|
308
|
-
|
|
309
|
-
cs_r, sigma_r = sigma_stretch(theta_s, theta_b, N, "r")
|
|
310
|
-
cs_w, sigma_w = sigma_stretch(theta_s, theta_b, N, "w")
|
|
311
|
-
|
|
312
|
-
ds["sigma_r"] = sigma_r.astype(np.float32)
|
|
313
|
-
ds["sigma_r"].attrs["long_name"] = (
|
|
314
|
-
"Fractional vertical stretching coordinate at rho-points"
|
|
315
|
-
)
|
|
316
|
-
ds["sigma_r"].attrs["units"] = "nondimensional"
|
|
321
|
+
for var in vars_to_drop:
|
|
322
|
+
if var in ds.variables:
|
|
323
|
+
ds = ds.drop_vars(var)
|
|
317
324
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
ds["Cs_r"].attrs["units"] = "nondimensional"
|
|
325
|
+
cs_r, sigma_r = sigma_stretch(theta_s, theta_b, N, "r")
|
|
326
|
+
cs_w, sigma_w = sigma_stretch(theta_s, theta_b, N, "w")
|
|
321
327
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
ds["Cs_w"] = cs_w.astype(np.float32)
|
|
329
|
-
ds["Cs_w"].attrs["long_name"] = "Vertical stretching function at w-points"
|
|
330
|
-
ds["Cs_w"].attrs["units"] = "nondimensional"
|
|
328
|
+
ds["sigma_r"] = sigma_r.astype(np.float32)
|
|
329
|
+
ds["sigma_r"].attrs["long_name"] = (
|
|
330
|
+
"Fractional vertical stretching coordinate at rho-points"
|
|
331
|
+
)
|
|
332
|
+
ds["sigma_r"].attrs["units"] = "nondimensional"
|
|
331
333
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
334
|
+
ds["Cs_r"] = cs_r.astype(np.float32)
|
|
335
|
+
ds["Cs_r"].attrs["long_name"] = "Vertical stretching function at rho-points"
|
|
336
|
+
ds["Cs_r"].attrs["units"] = "nondimensional"
|
|
335
337
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
"========================================================================================================"
|
|
338
|
+
ds["sigma_w"] = sigma_w.astype(np.float32)
|
|
339
|
+
ds["sigma_w"].attrs["long_name"] = (
|
|
340
|
+
"Fractional vertical stretching coordinate at w-points"
|
|
340
341
|
)
|
|
342
|
+
ds["sigma_w"].attrs["units"] = "nondimensional"
|
|
341
343
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
344
|
+
ds["Cs_w"] = cs_w.astype(np.float32)
|
|
345
|
+
ds["Cs_w"].attrs["long_name"] = "Vertical stretching function at w-points"
|
|
346
|
+
ds["Cs_w"].attrs["units"] = "nondimensional"
|
|
347
|
+
|
|
348
|
+
ds.attrs["theta_s"] = np.float32(theta_s)
|
|
349
|
+
ds.attrs["theta_b"] = np.float32(theta_b)
|
|
350
|
+
ds.attrs["hc"] = np.float32(hc)
|
|
351
|
+
|
|
352
|
+
self.ds = ds
|
|
353
|
+
self.theta_s = theta_s
|
|
354
|
+
self.theta_b = theta_b
|
|
355
|
+
self.hc = hc
|
|
356
|
+
self.N = N
|
|
347
357
|
|
|
348
358
|
def _straddle(self) -> None:
|
|
349
359
|
"""Check if the Greenwich meridian goes through the domain.
|
|
@@ -603,7 +613,7 @@ class Grid:
|
|
|
603
613
|
ds = xr.open_dataset(filepath)
|
|
604
614
|
|
|
605
615
|
if not all(mask in ds for mask in ["mask_u", "mask_v"]):
|
|
606
|
-
ds =
|
|
616
|
+
ds = add_velocity_masks(ds)
|
|
607
617
|
|
|
608
618
|
# Create a new Grid instance without calling __init__ and __post_init__
|
|
609
619
|
grid = cls.__new__(cls)
|
|
@@ -758,24 +768,30 @@ class Grid:
|
|
|
758
768
|
"hmin",
|
|
759
769
|
]:
|
|
760
770
|
if attr in ds.attrs:
|
|
761
|
-
|
|
771
|
+
value = float(ds.attrs[attr])
|
|
762
772
|
else:
|
|
763
|
-
|
|
773
|
+
value = None
|
|
764
774
|
|
|
765
|
-
object.__setattr__(grid, attr,
|
|
775
|
+
object.__setattr__(grid, attr, value)
|
|
766
776
|
|
|
767
777
|
if "topography_source_name" in ds.attrs:
|
|
768
778
|
if "topography_source_path" in ds.attrs:
|
|
769
|
-
|
|
779
|
+
topo_source = {
|
|
770
780
|
"name": ds.attrs["topography_source_name"],
|
|
771
781
|
"path": ds.attrs["topography_source_path"],
|
|
772
782
|
}
|
|
773
783
|
else:
|
|
774
|
-
|
|
784
|
+
topo_source = {"name": ds.attrs["topography_source_name"]}
|
|
775
785
|
else:
|
|
776
|
-
|
|
786
|
+
topo_source = None
|
|
787
|
+
grid.topography_source = topo_source
|
|
777
788
|
|
|
778
|
-
|
|
789
|
+
if "mask_shapefile" in ds.attrs:
|
|
790
|
+
mask_shapefile = ds.attrs["mask_shapefile"]
|
|
791
|
+
else:
|
|
792
|
+
mask_shapefile = None
|
|
793
|
+
|
|
794
|
+
grid.mask_shapefile = mask_shapefile
|
|
779
795
|
|
|
780
796
|
return grid
|
|
781
797
|
|
|
@@ -796,10 +812,7 @@ class Grid:
|
|
|
796
812
|
|
|
797
813
|
@classmethod
|
|
798
814
|
def from_yaml(
|
|
799
|
-
cls,
|
|
800
|
-
filepath: str | Path,
|
|
801
|
-
section_name: str = "Grid",
|
|
802
|
-
verbose: bool = False,
|
|
815
|
+
cls, filepath: str | Path, verbose: bool = False, **kwargs: Any
|
|
803
816
|
) -> "Grid":
|
|
804
817
|
"""Create an instance of the class from a YAML file.
|
|
805
818
|
|
|
@@ -807,10 +820,13 @@ class Grid:
|
|
|
807
820
|
----------
|
|
808
821
|
filepath : Union[str, Path]
|
|
809
822
|
The path to the YAML file from which the parameters will be read.
|
|
810
|
-
section_name : str, optional
|
|
811
|
-
The name of the YAML section containing the grid configuration. Defaults to "Grid".
|
|
812
823
|
verbose : bool, optional
|
|
813
824
|
Indicates whether to print grid generation steps with timing. Defaults to False.
|
|
825
|
+
**kwargs : Any
|
|
826
|
+
Additional keyword arguments:
|
|
827
|
+
|
|
828
|
+
- section_name : str, optional (default: "Grid")
|
|
829
|
+
The name of the YAML section containing the grid configuration.
|
|
814
830
|
|
|
815
831
|
Returns
|
|
816
832
|
-------
|
|
@@ -828,6 +844,8 @@ class Grid:
|
|
|
828
844
|
Issues a warning if the ROMS-Tools version in the YAML header does not match the
|
|
829
845
|
currently installed version.
|
|
830
846
|
"""
|
|
847
|
+
section_name: str = kwargs.pop("section_name", None) or "Grid"
|
|
848
|
+
|
|
831
849
|
filepath = Path(filepath)
|
|
832
850
|
# Read the entire file content
|
|
833
851
|
with filepath.open("r") as file:
|
|
@@ -881,7 +899,7 @@ class Grid:
|
|
|
881
899
|
attr_str = ", ".join(f"{k}={v!r}" for k, v in attr_dict.items())
|
|
882
900
|
return f"{cls_name}({attr_str})"
|
|
883
901
|
|
|
884
|
-
def _create_horizontal_grid(self) -> xr.Dataset
|
|
902
|
+
def _create_horizontal_grid(self) -> xr.Dataset:
|
|
885
903
|
"""Create the horizontal grid based on a Mercator projection and store it in the
|
|
886
904
|
'ds' attribute.
|
|
887
905
|
|
|
@@ -899,41 +917,32 @@ class Grid:
|
|
|
899
917
|
- Longitude values are adjusted to fall within the range [0, 360].
|
|
900
918
|
- Grid rotation and translation are applied based on the specified parameters.
|
|
901
919
|
"""
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
logging.info("=== Creating the horizontal grid ===")
|
|
905
|
-
|
|
906
|
-
self._raise_if_domain_size_too_large()
|
|
920
|
+
with Timed("=== Creating the horizontal grid ===", verbose=self.verbose):
|
|
921
|
+
self._raise_if_domain_size_too_large()
|
|
907
922
|
|
|
908
|
-
|
|
923
|
+
coords = self._make_initial_lon_lat_ds()
|
|
909
924
|
|
|
910
|
-
|
|
911
|
-
|
|
925
|
+
# rotate coordinate system
|
|
926
|
+
coords = _rotate(coords, self.rot)
|
|
912
927
|
|
|
913
|
-
|
|
914
|
-
|
|
928
|
+
# translate coordinate system
|
|
929
|
+
coords = _translate(coords, self.center_lat, self.center_lon)
|
|
915
930
|
|
|
916
|
-
|
|
917
|
-
|
|
931
|
+
# compute 1/dx and 1/dy
|
|
932
|
+
coords["pm"], coords["pn"] = _compute_coordinate_metrics(coords)
|
|
918
933
|
|
|
919
|
-
|
|
920
|
-
|
|
934
|
+
# compute angle of local grid positive x-axis relative to east
|
|
935
|
+
coords["angle"] = _compute_angle(coords)
|
|
921
936
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
937
|
+
# make sure lons are in [0, 360] range
|
|
938
|
+
for lon in ["lon", "lonu", "lonv", "lonq"]:
|
|
939
|
+
coords[lon][coords[lon] < 0] = coords[lon][coords[lon] < 0] + 2 * np.pi
|
|
925
940
|
|
|
926
|
-
|
|
941
|
+
ds = self._create_grid_ds(coords)
|
|
927
942
|
|
|
928
|
-
|
|
943
|
+
ds = self._add_global_metadata(ds)
|
|
929
944
|
|
|
930
|
-
|
|
931
|
-
logging.info(f"Total time: {time.time() - start_time:.3f} seconds")
|
|
932
|
-
logging.info(
|
|
933
|
-
"========================================================================================================"
|
|
934
|
-
)
|
|
935
|
-
|
|
936
|
-
self.ds = ds
|
|
945
|
+
self.ds = ds
|
|
937
946
|
|
|
938
947
|
def _add_global_metadata(self, ds):
|
|
939
948
|
"""Add global metadata and attributes to the dataset.
|