roms-tools 2.3.0__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 +1 -0
- roms_tools/analysis/roms_output.py +10 -6
- roms_tools/setup/boundary_forcing.py +178 -193
- roms_tools/setup/datasets.py +58 -1
- roms_tools/setup/grid.py +31 -97
- roms_tools/setup/initial_conditions.py +172 -126
- roms_tools/setup/nesting.py +2 -23
- roms_tools/setup/river_forcing.py +34 -67
- roms_tools/setup/surface_forcing.py +111 -61
- roms_tools/setup/tides.py +7 -30
- roms_tools/setup/utils.py +24 -70
- roms_tools/tests/test_setup/test_boundary_forcing.py +220 -57
- 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_grid.py +0 -13
- roms_tools/tests/test_setup/test_initial_conditions.py +204 -66
- roms_tools/tests/test_setup/test_nesting.py +0 -16
- roms_tools/tests/test_setup/test_river_forcing.py +8 -36
- roms_tools/tests/test_setup/test_surface_forcing.py +102 -73
- roms_tools/tests/test_setup/test_tides.py +4 -16
- roms_tools/tests/test_setup/test_utils.py +1 -0
- roms_tools/tests/{test_utils.py → test_tiling/test_partition.py} +1 -1
- roms_tools/tiling/partition.py +338 -0
- roms_tools/utils.py +66 -333
- roms_tools/vertical_coordinate.py +54 -133
- {roms_tools-2.3.0.dist-info → roms_tools-2.4.0.dist-info}/METADATA +1 -1
- {roms_tools-2.3.0.dist-info → roms_tools-2.4.0.dist-info}/RECORD +143 -136
- {roms_tools-2.3.0.dist-info → roms_tools-2.4.0.dist-info}/LICENSE +0 -0
- {roms_tools-2.3.0.dist-info → roms_tools-2.4.0.dist-info}/WHEEL +0 -0
- {roms_tools-2.3.0.dist-info → roms_tools-2.4.0.dist-info}/top_level.txt +0 -0
roms_tools/utils.py
CHANGED
|
@@ -1,340 +1,8 @@
|
|
|
1
|
-
from numbers import Integral
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
1
|
import xarray as xr
|
|
5
|
-
from typing import Union
|
|
6
2
|
from pathlib import Path
|
|
7
3
|
import re
|
|
8
4
|
import glob
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def partition(
|
|
12
|
-
ds: xr.Dataset, np_eta: int = 1, np_xi: int = 1
|
|
13
|
-
) -> tuple[list[int], list[xr.Dataset]]:
|
|
14
|
-
"""Partition a ROMS (Regional Ocean Modeling System) dataset into smaller spatial
|
|
15
|
-
tiles.
|
|
16
|
-
|
|
17
|
-
This function divides the input dataset into `np_eta` by `np_xi` tiles, where each tile
|
|
18
|
-
represents a subdomain of the original dataset. The partitioning is performed along
|
|
19
|
-
the spatial dimensions `eta_rho`, `xi_rho`, `eta_v`, `xi_u`, `eta_psi`, `xi_psi`, `eta_coarse`, and `xi_coarse`,
|
|
20
|
-
depending on which dimensions are present in the dataset.
|
|
21
|
-
|
|
22
|
-
Parameters
|
|
23
|
-
----------
|
|
24
|
-
ds : xr.Dataset
|
|
25
|
-
The input ROMS dataset that is to be partitioned.
|
|
26
|
-
|
|
27
|
-
np_eta : int, optional
|
|
28
|
-
The number of partitions along the `eta` direction. Must be a positive integer. Default is 1.
|
|
29
|
-
|
|
30
|
-
np_xi : int, optional
|
|
31
|
-
The number of partitions along the `xi` direction. Must be a positive integer. Default is 1.
|
|
32
|
-
|
|
33
|
-
Returns
|
|
34
|
-
-------
|
|
35
|
-
tuple[list[int], list[xr.Dataset]]
|
|
36
|
-
A tuple containing two elements:
|
|
37
|
-
|
|
38
|
-
- A list of integers representing the file numbers associated with each partition.
|
|
39
|
-
- A list of `xarray.Dataset` objects, each representing a partitioned subdomain of the original dataset.
|
|
40
|
-
|
|
41
|
-
Raises
|
|
42
|
-
------
|
|
43
|
-
ValueError
|
|
44
|
-
If `np_eta` or `np_xi` is not a positive integer, or if the dataset cannot be evenly partitioned
|
|
45
|
-
into the specified number of tiles.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Example
|
|
49
|
-
-------
|
|
50
|
-
>>> partitioned_file_numbers, partitioned_datasets = partition(
|
|
51
|
-
... ds, np_eta=2, np_xi=3
|
|
52
|
-
... )
|
|
53
|
-
>>> print(partitioned_file_numbers)
|
|
54
|
-
[0, 1, 2, 3, 4, 5]
|
|
55
|
-
>>> print([ds.sizes for ds in partitioned_datasets])
|
|
56
|
-
[{'eta_rho': 50, 'xi_rho': 50}, {'eta_rho': 50, 'xi_rho': 50}, ...]
|
|
57
|
-
|
|
58
|
-
This example partitions the dataset into 2 tiles along the `eta` direction and 3 tiles
|
|
59
|
-
along the `xi` direction, resulting in a total of 6 partitions.
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
not isinstance(np_eta, Integral)
|
|
64
|
-
or np_eta < 1
|
|
65
|
-
or not isinstance(np_xi, Integral)
|
|
66
|
-
or np_xi < 1
|
|
67
|
-
):
|
|
68
|
-
raise ValueError("np_eta and np_xi must be positive integers")
|
|
69
|
-
|
|
70
|
-
partitionable_dims_maybe_present = [
|
|
71
|
-
"eta_rho",
|
|
72
|
-
"xi_rho",
|
|
73
|
-
"eta_v",
|
|
74
|
-
"xi_u",
|
|
75
|
-
"eta_psi",
|
|
76
|
-
"xi_psi",
|
|
77
|
-
"eta_coarse",
|
|
78
|
-
"xi_coarse",
|
|
79
|
-
]
|
|
80
|
-
dims_to_partition = [d for d in partitionable_dims_maybe_present if d in ds.dims]
|
|
81
|
-
|
|
82
|
-
# if eta is periodic there are no ghost cells along those dimensions
|
|
83
|
-
if "eta_v" in ds.sizes and ds.sizes["eta_rho"] == ds.sizes["eta_v"]:
|
|
84
|
-
# TODO how are we supposed to know if eta is periodic if eta_v doesn't appear? partit.F doesn't say...
|
|
85
|
-
n_eta_ghost_cells = 0
|
|
86
|
-
else:
|
|
87
|
-
n_eta_ghost_cells = 1
|
|
88
|
-
|
|
89
|
-
# if xi is periodic there are no ghost cells along those dimensions
|
|
90
|
-
if "xi_u" in ds.sizes and ds.sizes["xi_rho"] == ds.sizes["xi_u"]:
|
|
91
|
-
n_xi_ghost_cells = 0
|
|
92
|
-
else:
|
|
93
|
-
n_xi_ghost_cells = 1
|
|
94
|
-
|
|
95
|
-
def integer_division_or_raise(a: int, b: int, dimension: str) -> int:
|
|
96
|
-
"""Perform integer division and ensure that the division is exact.
|
|
97
|
-
|
|
98
|
-
Parameters
|
|
99
|
-
----------
|
|
100
|
-
a : int
|
|
101
|
-
The numerator for the division.
|
|
102
|
-
b : int
|
|
103
|
-
The denominator for the division.
|
|
104
|
-
dimension : str
|
|
105
|
-
The name of the dimension being partitioned, used for error reporting.
|
|
106
|
-
|
|
107
|
-
Returns
|
|
108
|
-
-------
|
|
109
|
-
int
|
|
110
|
-
The result of the integer division.
|
|
111
|
-
|
|
112
|
-
Raises
|
|
113
|
-
------
|
|
114
|
-
ValueError
|
|
115
|
-
If the division is not exact, indicating that the domain cannot be evenly divided
|
|
116
|
-
along the specified dimension.
|
|
117
|
-
"""
|
|
118
|
-
remainder = a % b
|
|
119
|
-
if remainder == 0:
|
|
120
|
-
return a // b
|
|
121
|
-
else:
|
|
122
|
-
raise ValueError(
|
|
123
|
-
f"Dimension '{dimension}' of size {a} cannot be evenly divided into {b} partitions."
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
if "eta_rho" in dims_to_partition:
|
|
127
|
-
eta_rho_domain_size = integer_division_or_raise(
|
|
128
|
-
ds.sizes["eta_rho"] - 2 * n_eta_ghost_cells, np_eta, "eta_rho"
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
if "xi_rho" in dims_to_partition:
|
|
132
|
-
xi_rho_domain_size = integer_division_or_raise(
|
|
133
|
-
ds.sizes["xi_rho"] - 2 * n_xi_ghost_cells, np_xi, "xi_rho"
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
if "eta_v" in dims_to_partition:
|
|
137
|
-
eta_v_domain_size = integer_division_or_raise(
|
|
138
|
-
ds.sizes["eta_v"] - 1 * n_eta_ghost_cells, np_eta, "eta_v"
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
if "xi_u" in dims_to_partition:
|
|
142
|
-
xi_u_domain_size = integer_division_or_raise(
|
|
143
|
-
ds.sizes["xi_u"] - 1 * n_xi_ghost_cells, np_xi, "xi_u"
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
if "eta_psi" in dims_to_partition:
|
|
147
|
-
eta_psi_domain_size = integer_division_or_raise(
|
|
148
|
-
ds.sizes["eta_psi"] - 3 * n_eta_ghost_cells, np_eta, "eta_psi"
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
if "xi_psi" in dims_to_partition:
|
|
152
|
-
xi_psi_domain_size = integer_division_or_raise(
|
|
153
|
-
ds.sizes["xi_psi"] - 3 * n_xi_ghost_cells, np_xi, "xi_psi"
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
if "eta_coarse" in dims_to_partition:
|
|
157
|
-
eta_coarse_domain_size = integer_division_or_raise(
|
|
158
|
-
ds.sizes["eta_coarse"] - 2 * n_eta_ghost_cells, np_eta, "eta_coarse"
|
|
159
|
-
)
|
|
160
|
-
if "xi_coarse" in dims_to_partition:
|
|
161
|
-
xi_coarse_domain_size = integer_division_or_raise(
|
|
162
|
-
ds.sizes["xi_coarse"] - 2 * n_xi_ghost_cells, np_xi, "xi_coarse"
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
# unpartitioned dimensions should have sizes unchanged
|
|
166
|
-
partitioned_sizes = {
|
|
167
|
-
dim: [size] for dim, size in ds.sizes.items() if dim in dims_to_partition
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
# TODO refactor to use two functions for odd- and even-length dimensions
|
|
171
|
-
if "eta_v" in dims_to_partition:
|
|
172
|
-
partitioned_sizes["eta_v"] = [eta_v_domain_size] * (np_eta - 1) + [
|
|
173
|
-
eta_v_domain_size + n_eta_ghost_cells
|
|
174
|
-
]
|
|
175
|
-
if "xi_u" in dims_to_partition:
|
|
176
|
-
partitioned_sizes["xi_u"] = [xi_u_domain_size] * (np_xi - 1) + [
|
|
177
|
-
xi_u_domain_size + n_xi_ghost_cells
|
|
178
|
-
]
|
|
179
|
-
|
|
180
|
-
if np_eta > 1:
|
|
181
|
-
if "eta_rho" in dims_to_partition:
|
|
182
|
-
partitioned_sizes["eta_rho"] = (
|
|
183
|
-
[eta_rho_domain_size + n_eta_ghost_cells]
|
|
184
|
-
+ [eta_rho_domain_size] * (np_eta - 2)
|
|
185
|
-
+ [eta_rho_domain_size + n_eta_ghost_cells]
|
|
186
|
-
)
|
|
187
|
-
if "eta_psi" in dims_to_partition:
|
|
188
|
-
partitioned_sizes["eta_psi"] = (
|
|
189
|
-
[n_eta_ghost_cells + eta_psi_domain_size]
|
|
190
|
-
+ [eta_psi_domain_size] * (np_eta - 2)
|
|
191
|
-
+ [eta_psi_domain_size + 2 * n_eta_ghost_cells]
|
|
192
|
-
)
|
|
193
|
-
if "eta_coarse" in dims_to_partition:
|
|
194
|
-
partitioned_sizes["eta_coarse"] = (
|
|
195
|
-
[eta_coarse_domain_size + n_eta_ghost_cells]
|
|
196
|
-
+ [eta_coarse_domain_size] * (np_eta - 2)
|
|
197
|
-
+ [eta_coarse_domain_size + n_eta_ghost_cells]
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
if np_xi > 1:
|
|
201
|
-
if "xi_rho" in dims_to_partition:
|
|
202
|
-
partitioned_sizes["xi_rho"] = (
|
|
203
|
-
[xi_rho_domain_size + n_xi_ghost_cells]
|
|
204
|
-
+ [xi_rho_domain_size] * (np_xi - 2)
|
|
205
|
-
+ [xi_rho_domain_size + n_xi_ghost_cells]
|
|
206
|
-
)
|
|
207
|
-
if "xi_psi" in dims_to_partition:
|
|
208
|
-
partitioned_sizes["xi_psi"] = (
|
|
209
|
-
[n_xi_ghost_cells + xi_psi_domain_size]
|
|
210
|
-
+ [xi_psi_domain_size] * (np_xi - 2)
|
|
211
|
-
+ [xi_psi_domain_size + 2 * n_xi_ghost_cells]
|
|
212
|
-
)
|
|
213
|
-
if "xi_coarse" in dims_to_partition:
|
|
214
|
-
partitioned_sizes["xi_coarse"] = (
|
|
215
|
-
[xi_coarse_domain_size + n_xi_ghost_cells]
|
|
216
|
-
+ [xi_coarse_domain_size] * (np_xi - 2)
|
|
217
|
-
+ [xi_coarse_domain_size + n_xi_ghost_cells]
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
def cumsum(pmf):
|
|
221
|
-
"""Implementation of cumsum which ensures the result starts with zero."""
|
|
222
|
-
cdf = np.empty(len(pmf) + 1, dtype=int)
|
|
223
|
-
cdf[0] = 0
|
|
224
|
-
np.cumsum(pmf, out=cdf[1:])
|
|
225
|
-
return cdf
|
|
226
|
-
|
|
227
|
-
file_numbers = []
|
|
228
|
-
partitioned_datasets = []
|
|
229
|
-
for i in range(np_eta):
|
|
230
|
-
for j in range(np_xi):
|
|
231
|
-
file_number = j + (i * np_xi)
|
|
232
|
-
file_numbers.append(file_number)
|
|
233
|
-
|
|
234
|
-
indexers = {}
|
|
235
|
-
|
|
236
|
-
if "eta_rho" in dims_to_partition:
|
|
237
|
-
eta_rho_partition_indices = cumsum(partitioned_sizes["eta_rho"])
|
|
238
|
-
indexers["eta_rho"] = slice(
|
|
239
|
-
int(eta_rho_partition_indices[i]),
|
|
240
|
-
int(eta_rho_partition_indices[i + 1]),
|
|
241
|
-
)
|
|
242
|
-
if "xi_rho" in dims_to_partition:
|
|
243
|
-
xi_rho_partition_indices = cumsum(partitioned_sizes["xi_rho"])
|
|
244
|
-
indexers["xi_rho"] = slice(
|
|
245
|
-
int(xi_rho_partition_indices[j]),
|
|
246
|
-
int(xi_rho_partition_indices[j + 1]),
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
if "eta_v" in dims_to_partition:
|
|
250
|
-
eta_v_partition_indices = cumsum(partitioned_sizes["eta_v"])
|
|
251
|
-
indexers["eta_v"] = slice(
|
|
252
|
-
int(eta_v_partition_indices[i]),
|
|
253
|
-
int(eta_v_partition_indices[i + 1]),
|
|
254
|
-
)
|
|
255
|
-
if "xi_u" in dims_to_partition:
|
|
256
|
-
xi_u_partition_indices = cumsum(partitioned_sizes["xi_u"])
|
|
257
|
-
indexers["xi_u"] = slice(
|
|
258
|
-
int(xi_u_partition_indices[j]), int(xi_u_partition_indices[j + 1])
|
|
259
|
-
)
|
|
260
|
-
if "eta_psi" in dims_to_partition:
|
|
261
|
-
eta_psi_partition_indices = cumsum(partitioned_sizes["eta_psi"])
|
|
262
|
-
indexers["eta_psi"] = slice(
|
|
263
|
-
int(eta_psi_partition_indices[i]),
|
|
264
|
-
int(eta_psi_partition_indices[i + 1]),
|
|
265
|
-
)
|
|
266
|
-
if "xi_psi" in dims_to_partition:
|
|
267
|
-
xi_psi_partition_indices = cumsum(partitioned_sizes["xi_psi"])
|
|
268
|
-
indexers["xi_psi"] = slice(
|
|
269
|
-
int(xi_psi_partition_indices[j]),
|
|
270
|
-
int(xi_psi_partition_indices[j + 1]),
|
|
271
|
-
)
|
|
272
|
-
|
|
273
|
-
if "eta_coarse" in dims_to_partition:
|
|
274
|
-
eta_coarse_partition_indices = cumsum(partitioned_sizes["eta_coarse"])
|
|
275
|
-
indexers["eta_coarse"] = slice(
|
|
276
|
-
int(eta_coarse_partition_indices[i]),
|
|
277
|
-
int(eta_coarse_partition_indices[i + 1]),
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
if "xi_coarse" in dims_to_partition:
|
|
281
|
-
xi_coarse_partition_indices = cumsum(partitioned_sizes["xi_coarse"])
|
|
282
|
-
indexers["xi_coarse"] = slice(
|
|
283
|
-
int(xi_coarse_partition_indices[j]),
|
|
284
|
-
int(xi_coarse_partition_indices[j + 1]),
|
|
285
|
-
)
|
|
286
|
-
|
|
287
|
-
partitioned_ds = ds.isel(**indexers)
|
|
288
|
-
|
|
289
|
-
partitioned_datasets.append(partitioned_ds)
|
|
290
|
-
|
|
291
|
-
return file_numbers, partitioned_datasets
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
def partition_netcdf(
|
|
295
|
-
filepath: Union[str, Path], np_eta: int = 1, np_xi: int = 1
|
|
296
|
-
) -> None:
|
|
297
|
-
"""Partition a ROMS NetCDF file into smaller spatial tiles and save them to disk.
|
|
298
|
-
|
|
299
|
-
This function divides the dataset in the specified NetCDF file into `np_eta` by `np_xi` tiles.
|
|
300
|
-
Each tile is saved as a separate NetCDF file.
|
|
301
|
-
|
|
302
|
-
Parameters
|
|
303
|
-
----------
|
|
304
|
-
filepath : Union[str, Path]
|
|
305
|
-
The path to the input NetCDF file.
|
|
306
|
-
|
|
307
|
-
np_eta : int, optional
|
|
308
|
-
The number of partitions along the `eta` direction. Must be a positive integer. Default is 1.
|
|
309
|
-
|
|
310
|
-
np_xi : int, optional
|
|
311
|
-
The number of partitions along the `xi` direction. Must be a positive integer. Default is 1.
|
|
312
|
-
|
|
313
|
-
Returns
|
|
314
|
-
-------
|
|
315
|
-
List[Path]
|
|
316
|
-
A list of Path objects for the filenames that were saved.
|
|
317
|
-
"""
|
|
318
|
-
|
|
319
|
-
# Ensure filepath is a Path object
|
|
320
|
-
filepath = Path(filepath)
|
|
321
|
-
|
|
322
|
-
# Open the dataset
|
|
323
|
-
ds = xr.open_dataset(filepath.with_suffix(".nc"))
|
|
324
|
-
|
|
325
|
-
# Partition the dataset
|
|
326
|
-
file_numbers, partitioned_datasets = partition(ds, np_eta=np_eta, np_xi=np_xi)
|
|
327
|
-
|
|
328
|
-
# Generate paths to the partitioned files
|
|
329
|
-
base_filepath = filepath.with_suffix("")
|
|
330
|
-
paths_to_partitioned_files = [
|
|
331
|
-
Path(f"{base_filepath}.{file_number}.nc") for file_number in file_numbers
|
|
332
|
-
]
|
|
333
|
-
|
|
334
|
-
# Save the partitioned datasets to files
|
|
335
|
-
xr.save_mfdataset(partitioned_datasets, paths_to_partitioned_files)
|
|
336
|
-
|
|
337
|
-
return paths_to_partitioned_files
|
|
5
|
+
import logging
|
|
338
6
|
|
|
339
7
|
|
|
340
8
|
def _load_data(
|
|
@@ -634,3 +302,68 @@ def transpose_dimensions(da: xr.DataArray) -> xr.DataArray:
|
|
|
634
302
|
transposed_da = da.transpose(*new_order)
|
|
635
303
|
|
|
636
304
|
return transposed_da
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def save_datasets(dataset_list, output_filenames, use_dask=False, verbose=True):
|
|
308
|
+
"""Save the list of datasets to netCDF4 files.
|
|
309
|
+
|
|
310
|
+
Parameters
|
|
311
|
+
----------
|
|
312
|
+
dataset_list : list
|
|
313
|
+
List of datasets to be saved.
|
|
314
|
+
output_filenames : list
|
|
315
|
+
List of filenames for the output files.
|
|
316
|
+
use_dask : bool, optional
|
|
317
|
+
Whether to use Dask diagnostics (e.g., progress bars) when saving the datasets, by default False.
|
|
318
|
+
verbose : bool, optional
|
|
319
|
+
Whether to log information about the files being written. If True, logs the output filenames.
|
|
320
|
+
Defaults to True.
|
|
321
|
+
|
|
322
|
+
Returns
|
|
323
|
+
-------
|
|
324
|
+
List[Path]
|
|
325
|
+
A list of Path objects for the filenames that were saved.
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
saved_filenames = []
|
|
329
|
+
|
|
330
|
+
output_filenames = [f"{filename}.nc" for filename in output_filenames]
|
|
331
|
+
if verbose:
|
|
332
|
+
logging.info(
|
|
333
|
+
"Writing the following NetCDF files:\n%s", "\n".join(output_filenames)
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
if use_dask:
|
|
337
|
+
from dask.diagnostics import ProgressBar
|
|
338
|
+
|
|
339
|
+
with ProgressBar():
|
|
340
|
+
xr.save_mfdataset(dataset_list, output_filenames)
|
|
341
|
+
else:
|
|
342
|
+
xr.save_mfdataset(dataset_list, output_filenames)
|
|
343
|
+
|
|
344
|
+
saved_filenames.extend(Path(f) for f in output_filenames)
|
|
345
|
+
|
|
346
|
+
return saved_filenames
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def get_dask_chunks(location, chunk_size):
|
|
350
|
+
"""Returns the appropriate Dask chunking dictionary based on grid location.
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
location : str
|
|
355
|
+
The grid location, one of "rho", "u", or "v".
|
|
356
|
+
chunk_size : int
|
|
357
|
+
The chunk size to apply.
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
dict
|
|
362
|
+
Dictionary specifying the chunking strategy.
|
|
363
|
+
"""
|
|
364
|
+
chunk_mapping = {
|
|
365
|
+
"rho": {"eta_rho": chunk_size, "xi_rho": chunk_size},
|
|
366
|
+
"u": {"eta_rho": chunk_size, "xi_u": chunk_size},
|
|
367
|
+
"v": {"eta_v": chunk_size, "xi_rho": chunk_size},
|
|
368
|
+
}
|
|
369
|
+
return chunk_mapping.get(location, {})
|
|
@@ -113,191 +113,112 @@ def compute_depth(zeta, h, hc, cs, sigma):
|
|
|
113
113
|
return z
|
|
114
114
|
|
|
115
115
|
|
|
116
|
-
def add_depth_coordinates_to_dataset(
|
|
117
|
-
ds: "xr.Dataset",
|
|
118
|
-
grid_ds: "xr.Dataset",
|
|
119
|
-
depth_type: str,
|
|
120
|
-
locations: list[str] = ["rho", "u", "v"],
|
|
121
|
-
) -> None:
|
|
122
|
-
"""Add computed vertical depth coordinates to a dataset for specified grid
|
|
123
|
-
locations.
|
|
124
|
-
|
|
125
|
-
This function computes vertical depth coordinates (layer or interface) and updates
|
|
126
|
-
the provided dataset with these coordinates for the specified grid locations. If
|
|
127
|
-
the dataset already contains depth coordinates for all specified locations, the function
|
|
128
|
-
does nothing.
|
|
129
|
-
|
|
130
|
-
Parameters
|
|
131
|
-
----------
|
|
132
|
-
ds : xr.Dataset
|
|
133
|
-
Target dataset to which computed depth coordinates will be added.
|
|
134
|
-
If the `zeta` variable is not present, static vertical coordinates are used.
|
|
135
|
-
|
|
136
|
-
grid_ds : xr.Dataset
|
|
137
|
-
Grid dataset containing bathymetry, stretching curves, and parameters.
|
|
138
|
-
|
|
139
|
-
depth_type : str
|
|
140
|
-
Type of depth coordinates to compute. Options are:
|
|
141
|
-
- "layer": Layer depth coordinates.
|
|
142
|
-
- "interface": Interface depth coordinates.
|
|
143
|
-
|
|
144
|
-
locations : list of str, optional
|
|
145
|
-
List of locations for which to compute depth coordinates. Default is ["rho", "u", "v"].
|
|
146
|
-
"""
|
|
147
|
-
required_vars = [f"{depth_type}_depth_{loc}" for loc in locations]
|
|
148
|
-
|
|
149
|
-
if all(var in ds for var in required_vars):
|
|
150
|
-
return # Depth coordinates already exist
|
|
151
|
-
|
|
152
|
-
# Compute or interpolate depth coordinates
|
|
153
|
-
if f"{depth_type}_depth_rho" in ds:
|
|
154
|
-
depth_rho = ds[f"{depth_type}_depth_rho"]
|
|
155
|
-
else:
|
|
156
|
-
h = grid_ds["h"]
|
|
157
|
-
zeta = ds.get("zeta", 0)
|
|
158
|
-
if depth_type == "layer":
|
|
159
|
-
Cs = grid_ds["Cs_r"]
|
|
160
|
-
sigma = grid_ds["sigma_r"]
|
|
161
|
-
elif depth_type == "interface":
|
|
162
|
-
Cs = grid_ds["Cs_w"]
|
|
163
|
-
sigma = grid_ds["sigma_w"]
|
|
164
|
-
depth_rho = compute_depth(zeta, h, grid_ds.attrs["hc"], Cs, sigma)
|
|
165
|
-
depth_rho.attrs.update(
|
|
166
|
-
{"long_name": f"{depth_type} depth at rho-points", "units": "m"}
|
|
167
|
-
)
|
|
168
|
-
ds[f"{depth_type}_depth_rho"] = depth_rho
|
|
169
|
-
|
|
170
|
-
# Interpolate depth to other locations
|
|
171
|
-
for loc in locations:
|
|
172
|
-
if loc == "rho":
|
|
173
|
-
continue
|
|
174
|
-
|
|
175
|
-
interp_func = (
|
|
176
|
-
interpolate_from_rho_to_u if loc == "u" else interpolate_from_rho_to_v
|
|
177
|
-
)
|
|
178
|
-
depth_loc = interp_func(depth_rho)
|
|
179
|
-
depth_loc.attrs.update(
|
|
180
|
-
{"long_name": f"{depth_type} depth at {loc}-points", "units": "m"}
|
|
181
|
-
)
|
|
182
|
-
ds[f"{depth_type}_depth_{loc}"] = depth_loc
|
|
183
|
-
|
|
184
|
-
|
|
185
116
|
def compute_depth_coordinates(
|
|
186
|
-
ds: "xr.Dataset",
|
|
187
117
|
grid_ds: "xr.Dataset",
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
118
|
+
zeta: xr.DataArray | float = 0,
|
|
119
|
+
depth_type: str = "layer",
|
|
120
|
+
location: str = "rho",
|
|
191
121
|
eta: int = None,
|
|
192
122
|
xi: int = None,
|
|
193
123
|
) -> "xr.DataArray":
|
|
194
|
-
"""Compute vertical depth coordinates
|
|
195
|
-
optional indices.
|
|
124
|
+
"""Compute vertical depth coordinates for a given ROMS grid location.
|
|
196
125
|
|
|
197
|
-
This function calculates
|
|
198
|
-
location (`rho`, `u`, or `v`). It
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
vertical coordinate calculations.
|
|
126
|
+
This function calculates depth coordinates (layer or interface) at a specified grid
|
|
127
|
+
location (`rho`, `u`, or `v`). It optimizes computations by slicing the bathymetry (`h`)
|
|
128
|
+
and free-surface elevation (`zeta`) before performing vertical coordinate calculations,
|
|
129
|
+
reducing memory usage and improving efficiency.
|
|
202
130
|
|
|
203
131
|
Parameters
|
|
204
132
|
----------
|
|
205
|
-
ds : xr.Dataset
|
|
206
|
-
Dataset containing optional `zeta` (free-surface elevation). If `zeta` is not present,
|
|
207
|
-
static vertical coordinates are computed.
|
|
208
|
-
|
|
209
133
|
grid_ds : xr.Dataset
|
|
210
|
-
|
|
211
|
-
parameters (`sigma`). The attributes
|
|
134
|
+
ROMS grid dataset containing bathymetry (`h`), stretching curves (`Cs`),
|
|
135
|
+
and sigma-layer parameters (`sigma`). The dataset's attributes should include
|
|
136
|
+
the critical depth parameter (`hc`).
|
|
212
137
|
|
|
213
|
-
|
|
138
|
+
zeta : xr.DataArray or float, optional
|
|
139
|
+
Free-surface elevation. If set to `0` (default), the static sea level is assumed.
|
|
140
|
+
|
|
141
|
+
depth_type : str, optional
|
|
214
142
|
Type of depth coordinates to compute:
|
|
215
|
-
- `"layer"
|
|
143
|
+
- `"layer"` (default): Depth at the center of vertical layers.
|
|
216
144
|
- `"interface"`: Depth at layer interfaces.
|
|
217
145
|
|
|
218
|
-
location : str
|
|
219
|
-
Grid location for
|
|
220
|
-
- `"rho"
|
|
221
|
-
- `"u"`: Depth at
|
|
222
|
-
- `"v"`: Depth at
|
|
223
|
-
|
|
224
|
-
s : int, optional
|
|
225
|
-
Vertical index to extract a single layer or interface slice. If not provided, all vertical
|
|
226
|
-
layers are included.
|
|
146
|
+
location : str, optional
|
|
147
|
+
Grid location for depth computation:
|
|
148
|
+
- `"rho"` (default): Depth at cell centers (rho points).
|
|
149
|
+
- `"u"`: Depth at eastward velocity points (u points).
|
|
150
|
+
- `"v"`: Depth at northward velocity points (v points).
|
|
227
151
|
|
|
228
152
|
eta : int, optional
|
|
229
|
-
Meridional (north-south) index to extract a slice. If not provided,
|
|
230
|
-
are included.
|
|
153
|
+
Meridional (north-south) index to extract a zonal slice. If not provided,
|
|
154
|
+
all meridional indices are included.
|
|
231
155
|
|
|
232
156
|
xi : int, optional
|
|
233
|
-
Zonal (east-west) index to extract a slice. If not provided,
|
|
157
|
+
Zonal (east-west) index to extract a meridional slice. If not provided,
|
|
158
|
+
all zonal indices are included.
|
|
234
159
|
|
|
235
160
|
Returns
|
|
236
161
|
-------
|
|
237
162
|
xr.DataArray
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
-
|
|
242
|
-
- Reduced dimensionality for specified slices (e.g., 2D for a single vertical slice).
|
|
163
|
+
Computed depth coordinates. The shape of the output depends on the given indices:
|
|
164
|
+
- Full 3D (or 4D if `zeta` includes time) depth field if no indices are specified.
|
|
165
|
+
- 2D (or 3D if `zeta` includes time) slice if either `eta` or `xi` are specified.
|
|
166
|
+
- 1D (or 2D if `zeta` includes time) slice if both `eta` and `xi` are specified.
|
|
243
167
|
|
|
244
168
|
Notes
|
|
245
169
|
-----
|
|
246
|
-
-
|
|
247
|
-
|
|
248
|
-
- Depth
|
|
249
|
-
necessary.
|
|
250
|
-
- If depth coordinates for the specified location and configuration already exist in `ds`,
|
|
251
|
-
they are not recomputed.
|
|
170
|
+
- The function first interpolates `h` and `zeta` to the specified grid location (`rho`, `u`, or `v`).
|
|
171
|
+
- Spatial slicing (`eta`, `xi`) is performed before depth computation to optimize efficiency.
|
|
172
|
+
- Depth calculations rely on the ROMS vertical stretching curves (`Cs`) and sigma-layers.
|
|
252
173
|
"""
|
|
253
174
|
|
|
175
|
+
# Select the appropriate depth computation parameters
|
|
176
|
+
if depth_type == "layer":
|
|
177
|
+
Cs = grid_ds["Cs_r"]
|
|
178
|
+
sigma = grid_ds["sigma_r"]
|
|
179
|
+
elif depth_type == "interface":
|
|
180
|
+
Cs = grid_ds["Cs_w"]
|
|
181
|
+
sigma = grid_ds["sigma_w"]
|
|
182
|
+
else:
|
|
183
|
+
raise ValueError(
|
|
184
|
+
f"Invalid depth_type: {depth_type}. Choose 'layer' or 'interface'."
|
|
185
|
+
)
|
|
186
|
+
|
|
254
187
|
h = grid_ds["h"]
|
|
255
|
-
zeta = ds.get("zeta", None)
|
|
256
188
|
|
|
257
189
|
# Interpolate h and zeta to the specified location
|
|
258
190
|
if location == "u":
|
|
259
191
|
h = interpolate_from_rho_to_u(h)
|
|
260
|
-
if zeta
|
|
192
|
+
if isinstance(zeta, xr.DataArray):
|
|
261
193
|
zeta = interpolate_from_rho_to_u(zeta)
|
|
262
194
|
elif location == "v":
|
|
263
195
|
h = interpolate_from_rho_to_v(h)
|
|
264
|
-
if zeta
|
|
196
|
+
if isinstance(zeta, xr.DataArray):
|
|
265
197
|
zeta = interpolate_from_rho_to_v(zeta)
|
|
266
198
|
|
|
267
|
-
# Slice spatially based on
|
|
199
|
+
# Slice spatially based on indices
|
|
268
200
|
if eta is not None:
|
|
269
201
|
if location == "v":
|
|
270
202
|
h = h.isel(eta_v=eta)
|
|
271
|
-
if zeta
|
|
203
|
+
if isinstance(zeta, xr.DataArray):
|
|
272
204
|
zeta = zeta.isel(eta_v=eta)
|
|
273
|
-
else: #
|
|
205
|
+
else: # Applies to "rho" or "u"
|
|
274
206
|
h = h.isel(eta_rho=eta)
|
|
275
|
-
if zeta
|
|
207
|
+
if isinstance(zeta, xr.DataArray):
|
|
276
208
|
zeta = zeta.isel(eta_rho=eta)
|
|
209
|
+
|
|
277
210
|
if xi is not None:
|
|
278
211
|
if location == "u":
|
|
279
212
|
h = h.isel(xi_u=xi)
|
|
280
|
-
if zeta
|
|
213
|
+
if isinstance(zeta, xr.DataArray):
|
|
281
214
|
zeta = zeta.isel(xi_u=xi)
|
|
282
|
-
else: #
|
|
215
|
+
else: # Applies to "rho" or "v"
|
|
283
216
|
h = h.isel(xi_rho=xi)
|
|
284
|
-
if zeta
|
|
217
|
+
if isinstance(zeta, xr.DataArray):
|
|
285
218
|
zeta = zeta.isel(xi_rho=xi)
|
|
286
219
|
|
|
287
|
-
# Compute depth
|
|
288
|
-
if depth_type == "layer":
|
|
289
|
-
Cs = grid_ds["Cs_r"]
|
|
290
|
-
sigma = grid_ds["sigma_r"]
|
|
291
|
-
elif depth_type == "interface":
|
|
292
|
-
Cs = grid_ds["Cs_w"]
|
|
293
|
-
sigma = grid_ds["sigma_w"]
|
|
294
220
|
depth = compute_depth(zeta, h, grid_ds.attrs["hc"], Cs, sigma)
|
|
295
221
|
|
|
296
|
-
# Slice vertically
|
|
297
|
-
if s is not None:
|
|
298
|
-
vertical_dim = "s_rho" if "s_rho" in depth.dims else "s_w"
|
|
299
|
-
depth = depth.isel({vertical_dim: s})
|
|
300
|
-
|
|
301
222
|
# Add metadata
|
|
302
223
|
depth.attrs.update(
|
|
303
224
|
{"long_name": f"{depth_type} depth at {location}-points", "units": "m"}
|