roms-tools 2.2.1__py3-none-any.whl → 2.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ci/environment.yml +1 -0
- roms_tools/__init__.py +2 -0
- roms_tools/analysis/roms_output.py +590 -0
- roms_tools/{setup/download.py → download.py} +3 -0
- roms_tools/{setup/plot.py → plot.py} +34 -28
- roms_tools/setup/boundary_forcing.py +199 -203
- roms_tools/setup/datasets.py +60 -136
- roms_tools/setup/grid.py +40 -67
- roms_tools/setup/initial_conditions.py +249 -247
- roms_tools/setup/nesting.py +6 -27
- roms_tools/setup/river_forcing.py +41 -76
- roms_tools/setup/surface_forcing.py +125 -75
- roms_tools/setup/tides.py +31 -51
- roms_tools/setup/topography.py +1 -1
- roms_tools/setup/utils.py +44 -224
- roms_tools/tests/test_analysis/test_roms_output.py +269 -0
- roms_tools/tests/{test_setup/test_regrid.py → test_regrid.py} +1 -1
- roms_tools/tests/test_setup/test_boundary_forcing.py +221 -58
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zattrs +5 -3
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/.zmetadata +156 -121
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zarray +2 -2
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/.zattrs +2 -1
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/abs_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/.zarray +2 -2
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/bry_time/0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/salt_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/temp_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/u_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_east/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_north/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_south/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/ubar_west/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_east/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_north/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_south/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/v_west/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_east/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_north/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_south/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/vbar_west/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_east/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_north/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_south/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zarray +4 -4
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/boundary_forcing.zarr/zeta_west/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zattrs +4 -4
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/.zmetadata +4 -4
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/angle_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/f/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/h/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lat_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/lon_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_coarse/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_rho/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_u/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/mask_v/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pm/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/grid_that_straddles_dateline.zarr/pn/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zattrs +2 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/.zmetadata +6 -4
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Cs_r/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/Cs_w/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NH4/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/NO3/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/PO4/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/abs_time/.zattrs +1 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/diatSi/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ocean_time/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spC/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spCaCO3/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/spFe/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/temp/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/u/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/ubar/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/v/0.0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/initial_conditions_with_bgc_from_climatology.zarr/vbar/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +30 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zarray +22 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_location/0.0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +30 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zarray +22 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/.zattrs +8 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_location/0.0 +0 -0
- roms_tools/tests/test_setup/test_datasets.py +1 -1
- roms_tools/tests/test_setup/test_grid.py +1 -14
- roms_tools/tests/test_setup/test_initial_conditions.py +205 -67
- roms_tools/tests/test_setup/test_nesting.py +0 -16
- roms_tools/tests/test_setup/test_river_forcing.py +9 -37
- roms_tools/tests/test_setup/test_surface_forcing.py +103 -74
- roms_tools/tests/test_setup/test_tides.py +5 -17
- roms_tools/tests/test_setup/test_topography.py +1 -1
- roms_tools/tests/test_setup/test_utils.py +57 -1
- roms_tools/tests/{test_utils.py → test_tiling/test_partition.py} +1 -1
- roms_tools/tiling/partition.py +338 -0
- roms_tools/utils.py +310 -276
- roms_tools/vertical_coordinate.py +227 -0
- {roms_tools-2.2.1.dist-info → roms_tools-2.4.0.dist-info}/METADATA +1 -1
- {roms_tools-2.2.1.dist-info → roms_tools-2.4.0.dist-info}/RECORD +151 -142
- roms_tools/setup/vertical_coordinate.py +0 -109
- /roms_tools/{setup/regrid.py → regrid.py} +0 -0
- {roms_tools-2.2.1.dist-info → roms_tools-2.4.0.dist-info}/LICENSE +0 -0
- {roms_tools-2.2.1.dist-info → roms_tools-2.4.0.dist-info}/WHEEL +0 -0
- {roms_tools-2.2.1.dist-info → roms_tools-2.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
from numbers import Integral
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import xarray as xr
|
|
5
|
+
from typing import Union
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from roms_tools.utils import save_datasets
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def partition(
|
|
11
|
+
ds: xr.Dataset, np_eta: int = 1, np_xi: int = 1
|
|
12
|
+
) -> tuple[list[int], list[xr.Dataset]]:
|
|
13
|
+
"""Partition a ROMS (Regional Ocean Modeling System) dataset into smaller spatial
|
|
14
|
+
tiles.
|
|
15
|
+
|
|
16
|
+
This function divides the input dataset into `np_eta` by `np_xi` tiles, where each tile
|
|
17
|
+
represents a subdomain of the original dataset. The partitioning is performed along
|
|
18
|
+
the spatial dimensions `eta_rho`, `xi_rho`, `eta_v`, `xi_u`, `eta_psi`, `xi_psi`, `eta_coarse`, and `xi_coarse`,
|
|
19
|
+
depending on which dimensions are present in the dataset.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
ds : xr.Dataset
|
|
24
|
+
The input ROMS dataset that is to be partitioned.
|
|
25
|
+
|
|
26
|
+
np_eta : int, optional
|
|
27
|
+
The number of partitions along the `eta` direction. Must be a positive integer. Default is 1.
|
|
28
|
+
|
|
29
|
+
np_xi : int, optional
|
|
30
|
+
The number of partitions along the `xi` direction. Must be a positive integer. Default is 1.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
tuple[list[int], list[xr.Dataset]]
|
|
35
|
+
A tuple containing two elements:
|
|
36
|
+
|
|
37
|
+
- A list of integers representing the file numbers associated with each partition.
|
|
38
|
+
- A list of `xarray.Dataset` objects, each representing a partitioned subdomain of the original dataset.
|
|
39
|
+
|
|
40
|
+
Raises
|
|
41
|
+
------
|
|
42
|
+
ValueError
|
|
43
|
+
If `np_eta` or `np_xi` is not a positive integer, or if the dataset cannot be evenly partitioned
|
|
44
|
+
into the specified number of tiles.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
Example
|
|
48
|
+
-------
|
|
49
|
+
>>> partitioned_file_numbers, partitioned_datasets = partition(
|
|
50
|
+
... ds, np_eta=2, np_xi=3
|
|
51
|
+
... )
|
|
52
|
+
>>> print(partitioned_file_numbers)
|
|
53
|
+
[0, 1, 2, 3, 4, 5]
|
|
54
|
+
>>> print([ds.sizes for ds in partitioned_datasets])
|
|
55
|
+
[{'eta_rho': 50, 'xi_rho': 50}, {'eta_rho': 50, 'xi_rho': 50}, ...]
|
|
56
|
+
|
|
57
|
+
This example partitions the dataset into 2 tiles along the `eta` direction and 3 tiles
|
|
58
|
+
along the `xi` direction, resulting in a total of 6 partitions.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
not isinstance(np_eta, Integral)
|
|
63
|
+
or np_eta < 1
|
|
64
|
+
or not isinstance(np_xi, Integral)
|
|
65
|
+
or np_xi < 1
|
|
66
|
+
):
|
|
67
|
+
raise ValueError("np_eta and np_xi must be positive integers")
|
|
68
|
+
|
|
69
|
+
partitionable_dims_maybe_present = [
|
|
70
|
+
"eta_rho",
|
|
71
|
+
"xi_rho",
|
|
72
|
+
"eta_v",
|
|
73
|
+
"xi_u",
|
|
74
|
+
"eta_psi",
|
|
75
|
+
"xi_psi",
|
|
76
|
+
"eta_coarse",
|
|
77
|
+
"xi_coarse",
|
|
78
|
+
]
|
|
79
|
+
dims_to_partition = [d for d in partitionable_dims_maybe_present if d in ds.dims]
|
|
80
|
+
|
|
81
|
+
# if eta is periodic there are no ghost cells along those dimensions
|
|
82
|
+
if "eta_v" in ds.sizes and ds.sizes["eta_rho"] == ds.sizes["eta_v"]:
|
|
83
|
+
# TODO how are we supposed to know if eta is periodic if eta_v doesn't appear? partit.F doesn't say...
|
|
84
|
+
n_eta_ghost_cells = 0
|
|
85
|
+
else:
|
|
86
|
+
n_eta_ghost_cells = 1
|
|
87
|
+
|
|
88
|
+
# if xi is periodic there are no ghost cells along those dimensions
|
|
89
|
+
if "xi_u" in ds.sizes and ds.sizes["xi_rho"] == ds.sizes["xi_u"]:
|
|
90
|
+
n_xi_ghost_cells = 0
|
|
91
|
+
else:
|
|
92
|
+
n_xi_ghost_cells = 1
|
|
93
|
+
|
|
94
|
+
def integer_division_or_raise(a: int, b: int, dimension: str) -> int:
|
|
95
|
+
"""Perform integer division and ensure that the division is exact.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
a : int
|
|
100
|
+
The numerator for the division.
|
|
101
|
+
b : int
|
|
102
|
+
The denominator for the division.
|
|
103
|
+
dimension : str
|
|
104
|
+
The name of the dimension being partitioned, used for error reporting.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
int
|
|
109
|
+
The result of the integer division.
|
|
110
|
+
|
|
111
|
+
Raises
|
|
112
|
+
------
|
|
113
|
+
ValueError
|
|
114
|
+
If the division is not exact, indicating that the domain cannot be evenly divided
|
|
115
|
+
along the specified dimension.
|
|
116
|
+
"""
|
|
117
|
+
remainder = a % b
|
|
118
|
+
if remainder == 0:
|
|
119
|
+
return a // b
|
|
120
|
+
else:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
f"Dimension '{dimension}' of size {a} cannot be evenly divided into {b} partitions."
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if "eta_rho" in dims_to_partition:
|
|
126
|
+
eta_rho_domain_size = integer_division_or_raise(
|
|
127
|
+
ds.sizes["eta_rho"] - 2 * n_eta_ghost_cells, np_eta, "eta_rho"
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if "xi_rho" in dims_to_partition:
|
|
131
|
+
xi_rho_domain_size = integer_division_or_raise(
|
|
132
|
+
ds.sizes["xi_rho"] - 2 * n_xi_ghost_cells, np_xi, "xi_rho"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
if "eta_v" in dims_to_partition:
|
|
136
|
+
eta_v_domain_size = integer_division_or_raise(
|
|
137
|
+
ds.sizes["eta_v"] - 1 * n_eta_ghost_cells, np_eta, "eta_v"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
if "xi_u" in dims_to_partition:
|
|
141
|
+
xi_u_domain_size = integer_division_or_raise(
|
|
142
|
+
ds.sizes["xi_u"] - 1 * n_xi_ghost_cells, np_xi, "xi_u"
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if "eta_psi" in dims_to_partition:
|
|
146
|
+
eta_psi_domain_size = integer_division_or_raise(
|
|
147
|
+
ds.sizes["eta_psi"] - 3 * n_eta_ghost_cells, np_eta, "eta_psi"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if "xi_psi" in dims_to_partition:
|
|
151
|
+
xi_psi_domain_size = integer_division_or_raise(
|
|
152
|
+
ds.sizes["xi_psi"] - 3 * n_xi_ghost_cells, np_xi, "xi_psi"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
if "eta_coarse" in dims_to_partition:
|
|
156
|
+
eta_coarse_domain_size = integer_division_or_raise(
|
|
157
|
+
ds.sizes["eta_coarse"] - 2 * n_eta_ghost_cells, np_eta, "eta_coarse"
|
|
158
|
+
)
|
|
159
|
+
if "xi_coarse" in dims_to_partition:
|
|
160
|
+
xi_coarse_domain_size = integer_division_or_raise(
|
|
161
|
+
ds.sizes["xi_coarse"] - 2 * n_xi_ghost_cells, np_xi, "xi_coarse"
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
# unpartitioned dimensions should have sizes unchanged
|
|
165
|
+
partitioned_sizes = {
|
|
166
|
+
dim: [size] for dim, size in ds.sizes.items() if dim in dims_to_partition
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
# TODO refactor to use two functions for odd- and even-length dimensions
|
|
170
|
+
if "eta_v" in dims_to_partition:
|
|
171
|
+
partitioned_sizes["eta_v"] = [eta_v_domain_size] * (np_eta - 1) + [
|
|
172
|
+
eta_v_domain_size + n_eta_ghost_cells
|
|
173
|
+
]
|
|
174
|
+
if "xi_u" in dims_to_partition:
|
|
175
|
+
partitioned_sizes["xi_u"] = [xi_u_domain_size] * (np_xi - 1) + [
|
|
176
|
+
xi_u_domain_size + n_xi_ghost_cells
|
|
177
|
+
]
|
|
178
|
+
|
|
179
|
+
if np_eta > 1:
|
|
180
|
+
if "eta_rho" in dims_to_partition:
|
|
181
|
+
partitioned_sizes["eta_rho"] = (
|
|
182
|
+
[eta_rho_domain_size + n_eta_ghost_cells]
|
|
183
|
+
+ [eta_rho_domain_size] * (np_eta - 2)
|
|
184
|
+
+ [eta_rho_domain_size + n_eta_ghost_cells]
|
|
185
|
+
)
|
|
186
|
+
if "eta_psi" in dims_to_partition:
|
|
187
|
+
partitioned_sizes["eta_psi"] = (
|
|
188
|
+
[n_eta_ghost_cells + eta_psi_domain_size]
|
|
189
|
+
+ [eta_psi_domain_size] * (np_eta - 2)
|
|
190
|
+
+ [eta_psi_domain_size + 2 * n_eta_ghost_cells]
|
|
191
|
+
)
|
|
192
|
+
if "eta_coarse" in dims_to_partition:
|
|
193
|
+
partitioned_sizes["eta_coarse"] = (
|
|
194
|
+
[eta_coarse_domain_size + n_eta_ghost_cells]
|
|
195
|
+
+ [eta_coarse_domain_size] * (np_eta - 2)
|
|
196
|
+
+ [eta_coarse_domain_size + n_eta_ghost_cells]
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
if np_xi > 1:
|
|
200
|
+
if "xi_rho" in dims_to_partition:
|
|
201
|
+
partitioned_sizes["xi_rho"] = (
|
|
202
|
+
[xi_rho_domain_size + n_xi_ghost_cells]
|
|
203
|
+
+ [xi_rho_domain_size] * (np_xi - 2)
|
|
204
|
+
+ [xi_rho_domain_size + n_xi_ghost_cells]
|
|
205
|
+
)
|
|
206
|
+
if "xi_psi" in dims_to_partition:
|
|
207
|
+
partitioned_sizes["xi_psi"] = (
|
|
208
|
+
[n_xi_ghost_cells + xi_psi_domain_size]
|
|
209
|
+
+ [xi_psi_domain_size] * (np_xi - 2)
|
|
210
|
+
+ [xi_psi_domain_size + 2 * n_xi_ghost_cells]
|
|
211
|
+
)
|
|
212
|
+
if "xi_coarse" in dims_to_partition:
|
|
213
|
+
partitioned_sizes["xi_coarse"] = (
|
|
214
|
+
[xi_coarse_domain_size + n_xi_ghost_cells]
|
|
215
|
+
+ [xi_coarse_domain_size] * (np_xi - 2)
|
|
216
|
+
+ [xi_coarse_domain_size + n_xi_ghost_cells]
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def cumsum(pmf):
|
|
220
|
+
"""Implementation of cumsum which ensures the result starts with zero."""
|
|
221
|
+
cdf = np.empty(len(pmf) + 1, dtype=int)
|
|
222
|
+
cdf[0] = 0
|
|
223
|
+
np.cumsum(pmf, out=cdf[1:])
|
|
224
|
+
return cdf
|
|
225
|
+
|
|
226
|
+
file_numbers = []
|
|
227
|
+
partitioned_datasets = []
|
|
228
|
+
for i in range(np_eta):
|
|
229
|
+
for j in range(np_xi):
|
|
230
|
+
file_number = j + (i * np_xi)
|
|
231
|
+
file_numbers.append(file_number)
|
|
232
|
+
|
|
233
|
+
indexers = {}
|
|
234
|
+
|
|
235
|
+
if "eta_rho" in dims_to_partition:
|
|
236
|
+
eta_rho_partition_indices = cumsum(partitioned_sizes["eta_rho"])
|
|
237
|
+
indexers["eta_rho"] = slice(
|
|
238
|
+
int(eta_rho_partition_indices[i]),
|
|
239
|
+
int(eta_rho_partition_indices[i + 1]),
|
|
240
|
+
)
|
|
241
|
+
if "xi_rho" in dims_to_partition:
|
|
242
|
+
xi_rho_partition_indices = cumsum(partitioned_sizes["xi_rho"])
|
|
243
|
+
indexers["xi_rho"] = slice(
|
|
244
|
+
int(xi_rho_partition_indices[j]),
|
|
245
|
+
int(xi_rho_partition_indices[j + 1]),
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
if "eta_v" in dims_to_partition:
|
|
249
|
+
eta_v_partition_indices = cumsum(partitioned_sizes["eta_v"])
|
|
250
|
+
indexers["eta_v"] = slice(
|
|
251
|
+
int(eta_v_partition_indices[i]),
|
|
252
|
+
int(eta_v_partition_indices[i + 1]),
|
|
253
|
+
)
|
|
254
|
+
if "xi_u" in dims_to_partition:
|
|
255
|
+
xi_u_partition_indices = cumsum(partitioned_sizes["xi_u"])
|
|
256
|
+
indexers["xi_u"] = slice(
|
|
257
|
+
int(xi_u_partition_indices[j]), int(xi_u_partition_indices[j + 1])
|
|
258
|
+
)
|
|
259
|
+
if "eta_psi" in dims_to_partition:
|
|
260
|
+
eta_psi_partition_indices = cumsum(partitioned_sizes["eta_psi"])
|
|
261
|
+
indexers["eta_psi"] = slice(
|
|
262
|
+
int(eta_psi_partition_indices[i]),
|
|
263
|
+
int(eta_psi_partition_indices[i + 1]),
|
|
264
|
+
)
|
|
265
|
+
if "xi_psi" in dims_to_partition:
|
|
266
|
+
xi_psi_partition_indices = cumsum(partitioned_sizes["xi_psi"])
|
|
267
|
+
indexers["xi_psi"] = slice(
|
|
268
|
+
int(xi_psi_partition_indices[j]),
|
|
269
|
+
int(xi_psi_partition_indices[j + 1]),
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
if "eta_coarse" in dims_to_partition:
|
|
273
|
+
eta_coarse_partition_indices = cumsum(partitioned_sizes["eta_coarse"])
|
|
274
|
+
indexers["eta_coarse"] = slice(
|
|
275
|
+
int(eta_coarse_partition_indices[i]),
|
|
276
|
+
int(eta_coarse_partition_indices[i + 1]),
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
if "xi_coarse" in dims_to_partition:
|
|
280
|
+
xi_coarse_partition_indices = cumsum(partitioned_sizes["xi_coarse"])
|
|
281
|
+
indexers["xi_coarse"] = slice(
|
|
282
|
+
int(xi_coarse_partition_indices[j]),
|
|
283
|
+
int(xi_coarse_partition_indices[j + 1]),
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
partitioned_ds = ds.isel(**indexers)
|
|
287
|
+
|
|
288
|
+
partitioned_datasets.append(partitioned_ds)
|
|
289
|
+
|
|
290
|
+
return file_numbers, partitioned_datasets
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def partition_netcdf(
|
|
294
|
+
filepath: Union[str, Path], np_eta: int = 1, np_xi: int = 1
|
|
295
|
+
) -> None:
|
|
296
|
+
"""Partition a ROMS NetCDF file into smaller spatial tiles and save them to disk.
|
|
297
|
+
|
|
298
|
+
This function divides the dataset in the specified NetCDF file into `np_eta` by `np_xi` tiles.
|
|
299
|
+
Each tile is saved as a separate NetCDF file.
|
|
300
|
+
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
filepath : Union[str, Path]
|
|
304
|
+
The path to the input NetCDF file.
|
|
305
|
+
|
|
306
|
+
np_eta : int, optional
|
|
307
|
+
The number of partitions along the `eta` direction. Must be a positive integer. Default is 1.
|
|
308
|
+
|
|
309
|
+
np_xi : int, optional
|
|
310
|
+
The number of partitions along the `xi` direction. Must be a positive integer. Default is 1.
|
|
311
|
+
|
|
312
|
+
Returns
|
|
313
|
+
-------
|
|
314
|
+
List[Path]
|
|
315
|
+
A list of Path objects for the filenames that were saved.
|
|
316
|
+
"""
|
|
317
|
+
|
|
318
|
+
# Ensure filepath is a Path object
|
|
319
|
+
filepath = Path(filepath)
|
|
320
|
+
|
|
321
|
+
# Open the dataset
|
|
322
|
+
ds = xr.open_dataset(filepath.with_suffix(".nc"))
|
|
323
|
+
|
|
324
|
+
# Partition the dataset
|
|
325
|
+
file_numbers, partitioned_datasets = partition(ds, np_eta=np_eta, np_xi=np_xi)
|
|
326
|
+
|
|
327
|
+
# Generate paths to the partitioned files
|
|
328
|
+
base_filepath = filepath.with_suffix("")
|
|
329
|
+
paths_to_partitioned_files = [
|
|
330
|
+
Path(f"{base_filepath}.{file_number}") for file_number in file_numbers
|
|
331
|
+
]
|
|
332
|
+
|
|
333
|
+
# Save the partitioned datasets to files
|
|
334
|
+
saved_filenames = save_datasets(
|
|
335
|
+
partitioned_datasets, paths_to_partitioned_files, verbose=False
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
return saved_filenames
|