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
roms_tools/setup/datasets.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import time
|
|
2
|
-
import re
|
|
3
2
|
import xarray as xr
|
|
4
3
|
from dataclasses import dataclass, field
|
|
5
|
-
import glob
|
|
6
4
|
from datetime import datetime, timedelta
|
|
7
5
|
import numpy as np
|
|
8
6
|
from typing import Dict, Optional, Union, List
|
|
9
7
|
from pathlib import Path
|
|
10
8
|
import logging
|
|
9
|
+
from roms_tools.utils import _load_data
|
|
11
10
|
from roms_tools.setup.utils import (
|
|
12
11
|
assign_dates_to_climatology,
|
|
13
12
|
interpolate_from_climatology,
|
|
@@ -16,7 +15,7 @@ from roms_tools.setup.utils import (
|
|
|
16
15
|
one_dim_fill,
|
|
17
16
|
gc_dist,
|
|
18
17
|
)
|
|
19
|
-
from roms_tools.
|
|
18
|
+
from roms_tools.download import (
|
|
20
19
|
download_correction_data,
|
|
21
20
|
download_topo,
|
|
22
21
|
download_river_data,
|
|
@@ -356,6 +355,47 @@ class Dataset:
|
|
|
356
355
|
# Set the computed resolution as an attribute
|
|
357
356
|
object.__setattr__(self, "resolution", resolution)
|
|
358
357
|
|
|
358
|
+
def compute_minimal_grid_spacing(self, ds: xr.Dataset):
|
|
359
|
+
"""Compute the minimal grid spacing in a dataset based on latitude and longitude
|
|
360
|
+
spacing, considering Earth's radius.
|
|
361
|
+
|
|
362
|
+
Parameters
|
|
363
|
+
----------
|
|
364
|
+
ds : xr.Dataset
|
|
365
|
+
Dataset containing latitude and longitude dimensions.
|
|
366
|
+
|
|
367
|
+
Returns
|
|
368
|
+
-------
|
|
369
|
+
minimal_spacing : float
|
|
370
|
+
The smallest horizontal grid spacing derived from the latitude
|
|
371
|
+
and longitude differences, in meters.
|
|
372
|
+
"""
|
|
373
|
+
|
|
374
|
+
r_earth = 6371315.0
|
|
375
|
+
lat_dim = self.dim_names["latitude"]
|
|
376
|
+
lon_dim = self.dim_names["longitude"]
|
|
377
|
+
|
|
378
|
+
# Get latitude and longitude values from the dataset
|
|
379
|
+
latitudes = ds[lat_dim].values
|
|
380
|
+
longitudes = ds[lon_dim].values
|
|
381
|
+
|
|
382
|
+
# Compute differences along latitude and longitude
|
|
383
|
+
lat_diff = np.abs(np.diff(latitudes)).min() # Minimal latitude spacing
|
|
384
|
+
lon_diff = np.abs(np.diff(longitudes)).min() # Minimal longitude spacing
|
|
385
|
+
|
|
386
|
+
# Latitude spacing is constant at all longitudes
|
|
387
|
+
min_lat_spacing = (2 * np.pi * r_earth * lat_diff) / 360
|
|
388
|
+
|
|
389
|
+
# Longitude spacing varies with latitude
|
|
390
|
+
min_lon_spacing = (
|
|
391
|
+
2 * np.pi * r_earth * lon_diff * np.cos(np.radians(latitudes.min()))
|
|
392
|
+
) / 360
|
|
393
|
+
|
|
394
|
+
# The minimal spacing is the smaller of the two
|
|
395
|
+
minimal_spacing = min(min_lat_spacing, min_lon_spacing)
|
|
396
|
+
|
|
397
|
+
return minimal_spacing
|
|
398
|
+
|
|
359
399
|
def check_if_global(self, ds) -> bool:
|
|
360
400
|
"""Checks if the dataset covers the entire globe in the longitude dimension.
|
|
361
401
|
|
|
@@ -471,7 +511,12 @@ class Dataset:
|
|
|
471
511
|
pass
|
|
472
512
|
|
|
473
513
|
def choose_subdomain(
|
|
474
|
-
self,
|
|
514
|
+
self,
|
|
515
|
+
target_coords,
|
|
516
|
+
buffer_points=20,
|
|
517
|
+
return_copy=False,
|
|
518
|
+
return_coords_only=False,
|
|
519
|
+
verbose=False,
|
|
475
520
|
):
|
|
476
521
|
"""Selects a subdomain from the xarray Dataset based on specified target
|
|
477
522
|
coordinates, extending the selection by a defined buffer. Adjusts longitude
|
|
@@ -489,6 +534,9 @@ class Dataset:
|
|
|
489
534
|
return_subdomain : bool, optional
|
|
490
535
|
If True, returns the subset of the original dataset representing the chosen
|
|
491
536
|
subdomain. If False, assigns the subset to `self.ds`. Defaults to False.
|
|
537
|
+
return_coords_only : bool, optional
|
|
538
|
+
If True, returns a new xarray.Dataset containing only the latitude and longitude
|
|
539
|
+
of the subdomain. Defaults to False.
|
|
492
540
|
verbose : bool, optional
|
|
493
541
|
If True, print message if dataset is concatenated along longitude dimension.
|
|
494
542
|
Defaults to False.
|
|
@@ -593,6 +641,13 @@ class Dataset:
|
|
|
593
641
|
else:
|
|
594
642
|
subdomain[self.dim_names["longitude"]] = xr.where(lon < 0, lon + 360, lon)
|
|
595
643
|
|
|
644
|
+
if return_coords_only:
|
|
645
|
+
# Create and return a dataset with only latitudes and longitudes
|
|
646
|
+
coords_ds = subdomain[
|
|
647
|
+
[self.dim_names["latitude"], self.dim_names["longitude"]]
|
|
648
|
+
]
|
|
649
|
+
return coords_ds
|
|
650
|
+
|
|
596
651
|
if return_copy:
|
|
597
652
|
return Dataset.from_ds(self, subdomain)
|
|
598
653
|
else:
|
|
@@ -1945,138 +2000,6 @@ class DaiRiverDataset(RiverDataset):
|
|
|
1945
2000
|
# shared functions
|
|
1946
2001
|
|
|
1947
2002
|
|
|
1948
|
-
def _load_data(filename, dim_names, use_dask, decode_times=True):
|
|
1949
|
-
"""Load dataset from the specified file.
|
|
1950
|
-
|
|
1951
|
-
Parameters
|
|
1952
|
-
----------
|
|
1953
|
-
filename : Union[str, Path, List[Union[str, Path]]]
|
|
1954
|
-
The path to the data file(s). Can be a single string (with or without wildcards), a single Path object,
|
|
1955
|
-
or a list of strings or Path objects containing multiple files.
|
|
1956
|
-
dim_names: Dict[str, str], optional
|
|
1957
|
-
Dictionary specifying the names of dimensions in the dataset.
|
|
1958
|
-
use_dask: bool
|
|
1959
|
-
Indicates whether to use dask for chunking. If True, data is loaded with dask; if False, data is loaded eagerly. Defaults to False.
|
|
1960
|
-
decode_times: bool, optional
|
|
1961
|
-
If True, decode times encoded in the standard NetCDF datetime format into datetime objects. Otherwise, leave them encoded as numbers.
|
|
1962
|
-
Defaults to True.
|
|
1963
|
-
|
|
1964
|
-
Returns
|
|
1965
|
-
-------
|
|
1966
|
-
ds : xr.Dataset
|
|
1967
|
-
The loaded xarray Dataset containing the forcing data.
|
|
1968
|
-
|
|
1969
|
-
Raises
|
|
1970
|
-
------
|
|
1971
|
-
FileNotFoundError
|
|
1972
|
-
If the specified file does not exist.
|
|
1973
|
-
ValueError
|
|
1974
|
-
If a list of files is provided but dim_names["time"] is not available or use_dask=False.
|
|
1975
|
-
"""
|
|
1976
|
-
|
|
1977
|
-
# Precompile the regex for matching wildcard characters
|
|
1978
|
-
wildcard_regex = re.compile(r"[\*\?\[\]]")
|
|
1979
|
-
|
|
1980
|
-
# Convert Path objects to strings
|
|
1981
|
-
if isinstance(filename, (str, Path)):
|
|
1982
|
-
filename_str = str(filename)
|
|
1983
|
-
elif isinstance(filename, list):
|
|
1984
|
-
filename_str = [str(f) for f in filename]
|
|
1985
|
-
else:
|
|
1986
|
-
raise ValueError("filename must be a string, Path, or a list of strings/Paths.")
|
|
1987
|
-
# Handle the case when filename is a string
|
|
1988
|
-
contains_wildcard = False
|
|
1989
|
-
if isinstance(filename_str, str):
|
|
1990
|
-
contains_wildcard = bool(wildcard_regex.search(filename_str))
|
|
1991
|
-
if contains_wildcard:
|
|
1992
|
-
matching_files = glob.glob(filename_str)
|
|
1993
|
-
if not matching_files:
|
|
1994
|
-
raise FileNotFoundError(
|
|
1995
|
-
f"No files found matching the pattern '{filename_str}'."
|
|
1996
|
-
)
|
|
1997
|
-
else:
|
|
1998
|
-
matching_files = [filename_str]
|
|
1999
|
-
|
|
2000
|
-
# Handle the case when filename is a list
|
|
2001
|
-
elif isinstance(filename_str, list):
|
|
2002
|
-
contains_wildcard = any(wildcard_regex.search(f) for f in filename_str)
|
|
2003
|
-
if contains_wildcard:
|
|
2004
|
-
matching_files = []
|
|
2005
|
-
for f in filename_str:
|
|
2006
|
-
files = glob.glob(f)
|
|
2007
|
-
if not files:
|
|
2008
|
-
raise FileNotFoundError(
|
|
2009
|
-
f"No files found matching the pattern '{f}'."
|
|
2010
|
-
)
|
|
2011
|
-
matching_files.extend(files)
|
|
2012
|
-
else:
|
|
2013
|
-
matching_files = filename_str
|
|
2014
|
-
|
|
2015
|
-
# Check if time dimension is available when multiple files are provided
|
|
2016
|
-
if isinstance(filename_str, list) and "time" not in dim_names:
|
|
2017
|
-
raise ValueError(
|
|
2018
|
-
"A list of files is provided, but time dimension is not available. "
|
|
2019
|
-
"A time dimension must be available to concatenate the files."
|
|
2020
|
-
)
|
|
2021
|
-
|
|
2022
|
-
# Determine the kwargs for combining datasets
|
|
2023
|
-
if contains_wildcard or len(matching_files) == 1:
|
|
2024
|
-
# If there is a wildcard or just one file, use by_coords
|
|
2025
|
-
kwargs = {"combine": "by_coords"}
|
|
2026
|
-
else:
|
|
2027
|
-
# Otherwise, use nested combine based on time
|
|
2028
|
-
kwargs = {"combine": "nested", "concat_dim": dim_names["time"]}
|
|
2029
|
-
|
|
2030
|
-
# Base kwargs used for dataset combination
|
|
2031
|
-
combine_kwargs = {
|
|
2032
|
-
"coords": "minimal",
|
|
2033
|
-
"compat": "override",
|
|
2034
|
-
"combine_attrs": "override",
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
if use_dask:
|
|
2038
|
-
|
|
2039
|
-
chunks = {
|
|
2040
|
-
dim_names["latitude"]: -1,
|
|
2041
|
-
dim_names["longitude"]: -1,
|
|
2042
|
-
}
|
|
2043
|
-
if "depth" in dim_names:
|
|
2044
|
-
chunks[dim_names["depth"]] = -1
|
|
2045
|
-
if "time" in dim_names:
|
|
2046
|
-
chunks[dim_names["time"]] = 1
|
|
2047
|
-
|
|
2048
|
-
ds = xr.open_mfdataset(
|
|
2049
|
-
matching_files,
|
|
2050
|
-
decode_times=decode_times,
|
|
2051
|
-
chunks=chunks,
|
|
2052
|
-
**combine_kwargs,
|
|
2053
|
-
**kwargs,
|
|
2054
|
-
)
|
|
2055
|
-
|
|
2056
|
-
# Rechunk the dataset along the tidal constituent dimension ("ntides") after loading
|
|
2057
|
-
# because the original dataset does not have a chunk size of 1 along this dimension.
|
|
2058
|
-
if "ntides" in dim_names:
|
|
2059
|
-
ds = ds.chunk({dim_names["ntides"]: 1})
|
|
2060
|
-
|
|
2061
|
-
else:
|
|
2062
|
-
ds_list = []
|
|
2063
|
-
for file in matching_files:
|
|
2064
|
-
ds = xr.open_dataset(file, decode_times=decode_times, chunks=None)
|
|
2065
|
-
ds_list.append(ds)
|
|
2066
|
-
|
|
2067
|
-
if kwargs["combine"] == "by_coords":
|
|
2068
|
-
ds = xr.combine_by_coords(ds_list, **combine_kwargs)
|
|
2069
|
-
elif kwargs["combine"] == "nested":
|
|
2070
|
-
ds = xr.combine_nested(
|
|
2071
|
-
ds_list, concat_dim=kwargs["concat_dim"], **combine_kwargs
|
|
2072
|
-
)
|
|
2073
|
-
|
|
2074
|
-
if "time" in dim_names and dim_names["time"] not in ds.dims:
|
|
2075
|
-
ds = ds.expand_dims(dim_names["time"])
|
|
2076
|
-
|
|
2077
|
-
return ds
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
2003
|
def _check_dataset(
|
|
2081
2004
|
ds: xr.Dataset,
|
|
2082
2005
|
dim_names: Dict[str, str],
|
|
@@ -2191,6 +2114,7 @@ def _select_relevant_times(
|
|
|
2191
2114
|
)
|
|
2192
2115
|
if not end_time:
|
|
2193
2116
|
# Interpolate from climatology for initial conditions
|
|
2117
|
+
ds["time"] = ds["time"].dt.days
|
|
2194
2118
|
ds = interpolate_from_climatology(ds, time_dim, start_time)
|
|
2195
2119
|
else:
|
|
2196
2120
|
time_type = get_time_type(ds[time_dim])
|
roms_tools/setup/grid.py
CHANGED
|
@@ -8,17 +8,18 @@ import matplotlib.pyplot as plt
|
|
|
8
8
|
import yaml
|
|
9
9
|
import importlib.metadata
|
|
10
10
|
from typing import Dict, Union, List
|
|
11
|
+
from roms_tools.utils import save_datasets
|
|
11
12
|
from roms_tools.setup.topography import _add_topography
|
|
12
13
|
from roms_tools.setup.mask import _add_mask, _add_velocity_masks
|
|
13
|
-
from roms_tools.
|
|
14
|
+
from roms_tools.vertical_coordinate import compute_depth_coordinates, sigma_stretch
|
|
15
|
+
from roms_tools.plot import _plot, _section_plot
|
|
14
16
|
from roms_tools.setup.utils import (
|
|
15
17
|
interpolate_from_rho_to_u,
|
|
16
18
|
interpolate_from_rho_to_v,
|
|
17
19
|
get_target_coords,
|
|
18
20
|
gc_dist,
|
|
19
21
|
)
|
|
20
|
-
from roms_tools.setup.
|
|
21
|
-
from roms_tools.setup.utils import extract_single_value, save_datasets
|
|
22
|
+
from roms_tools.setup.utils import extract_single_value
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
|
|
24
25
|
|
|
@@ -392,14 +393,14 @@ class Grid:
|
|
|
392
393
|
object.__setattr__(self, "ds", ds)
|
|
393
394
|
|
|
394
395
|
def plot(
|
|
395
|
-
self, bathymetry: bool =
|
|
396
|
+
self, bathymetry: bool = True, title: str = None, with_dim_names: bool = False
|
|
396
397
|
) -> None:
|
|
397
398
|
"""Plot the grid.
|
|
398
399
|
|
|
399
400
|
Parameters
|
|
400
401
|
----------
|
|
401
402
|
bathymetry : bool, optional
|
|
402
|
-
Whether or not to plot the bathymetry. Default is
|
|
403
|
+
Whether or not to plot the bathymetry. Default is True.
|
|
403
404
|
title : str, optional
|
|
404
405
|
The title of the plot. If not provided, it will be set to a default.
|
|
405
406
|
with_dim_names : bool, optional
|
|
@@ -412,13 +413,16 @@ class Grid:
|
|
|
412
413
|
This method does not return any value. It generates and displays a plot.
|
|
413
414
|
"""
|
|
414
415
|
|
|
416
|
+
field = self.ds.h.where(self.ds.mask_rho)
|
|
417
|
+
lat_deg = self.ds.lat_rho
|
|
418
|
+
lon_deg = self.ds.lon_rho
|
|
419
|
+
if self.straddle:
|
|
420
|
+
lon_deg = xr.where(lon_deg > 180, lon_deg - 360, lon_deg)
|
|
421
|
+
field = field.assign_coords({"lon": lon_deg, "lat": lat_deg})
|
|
422
|
+
|
|
415
423
|
if bathymetry:
|
|
416
424
|
if title is None:
|
|
417
425
|
title = "ROMS grid and bathymetry"
|
|
418
|
-
field = self.ds.h.where(self.ds.mask_rho)
|
|
419
|
-
field = field.assign_coords(
|
|
420
|
-
{"lon": self.ds.lon_rho, "lat": self.ds.lat_rho}
|
|
421
|
-
)
|
|
422
426
|
|
|
423
427
|
vmax = field.max().values
|
|
424
428
|
vmin = field.min().values
|
|
@@ -427,9 +431,7 @@ class Grid:
|
|
|
427
431
|
kwargs = {"vmax": vmax, "vmin": vmin, "cmap": cmap}
|
|
428
432
|
|
|
429
433
|
_plot(
|
|
430
|
-
self.ds,
|
|
431
434
|
field=field,
|
|
432
|
-
straddle=self.straddle,
|
|
433
435
|
title=title,
|
|
434
436
|
with_dim_names=with_dim_names,
|
|
435
437
|
kwargs=kwargs,
|
|
@@ -438,10 +440,7 @@ class Grid:
|
|
|
438
440
|
if title is None:
|
|
439
441
|
title = "ROMS grid"
|
|
440
442
|
_plot(
|
|
441
|
-
|
|
442
|
-
straddle=self.straddle,
|
|
443
|
-
title=title,
|
|
444
|
-
with_dim_names=with_dim_names,
|
|
443
|
+
field=field, title=title, with_dim_names=with_dim_names, plot_data=False
|
|
445
444
|
)
|
|
446
445
|
|
|
447
446
|
def plot_vertical_coordinate(
|
|
@@ -474,54 +473,48 @@ class Grid:
|
|
|
474
473
|
If not exactly one of s, eta, xi is specified.
|
|
475
474
|
"""
|
|
476
475
|
|
|
477
|
-
title = "Layer depth at rho-points"
|
|
478
|
-
|
|
479
476
|
if sum(s is not None for s in [s, eta, xi]) != 1:
|
|
480
477
|
raise ValueError("Exactly one of s, eta, or xi must be specified.")
|
|
481
478
|
|
|
482
|
-
|
|
483
|
-
|
|
479
|
+
depth = compute_depth_coordinates(
|
|
480
|
+
self.ds, zeta=0, depth_type="layer", location="rho", eta=eta, xi=xi
|
|
481
|
+
)
|
|
484
482
|
|
|
485
|
-
|
|
483
|
+
title = "Layer depth at rho-points"
|
|
486
484
|
if eta is not None:
|
|
487
|
-
title = title + f", eta_rho = {
|
|
488
|
-
h = h.isel(eta_rho=eta)
|
|
485
|
+
title = title + f", eta_rho = {self.ds.eta_rho[eta].item()}"
|
|
489
486
|
if xi is not None:
|
|
490
|
-
title = title + f", xi_rho = {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
layer_depth = compute_depth(0, h, self.hc, self.ds.Cs_r, self.ds.sigma_r)
|
|
495
|
-
title = title + f", s_rho = {layer_depth.s_rho[s].item()}"
|
|
496
|
-
layer_depth = layer_depth.isel(s_rho=s)
|
|
497
|
-
|
|
498
|
-
layer_depth.attrs["long_name"] = "Layer depth"
|
|
499
|
-
layer_depth.attrs["units"] = "m"
|
|
487
|
+
title = title + f", xi_rho = {self.ds.xi_rho[xi].item()}"
|
|
488
|
+
if s is not None:
|
|
489
|
+
title = title + f", s_rho = {depth.s_rho[s].item()}"
|
|
490
|
+
depth = depth.isel(s_rho=s)
|
|
500
491
|
|
|
501
|
-
vmax =
|
|
502
|
-
vmin =
|
|
492
|
+
vmax = depth.max().values
|
|
493
|
+
vmin = depth.min().values
|
|
503
494
|
cmap = plt.colormaps.get_cmap("YlGnBu")
|
|
504
495
|
cmap.set_bad(color="gray")
|
|
505
496
|
kwargs = {"vmax": vmax, "vmin": vmin, "cmap": cmap}
|
|
506
497
|
|
|
498
|
+
lat_deg = self.ds.lat_rho
|
|
499
|
+
lon_deg = self.ds.lon_rho
|
|
500
|
+
if self.straddle:
|
|
501
|
+
lon_deg = xr.where(lon_deg > 180, lon_deg - 360, lon_deg)
|
|
502
|
+
depth = depth.assign_coords({"lon": lon_deg, "lat": lat_deg})
|
|
503
|
+
|
|
507
504
|
_plot(
|
|
508
|
-
self.ds,
|
|
509
|
-
field=layer_depth.where(self.ds.mask_rho),
|
|
510
|
-
straddle=self.straddle,
|
|
505
|
+
field=depth.where(self.ds.mask_rho),
|
|
511
506
|
depth_contours=False,
|
|
512
507
|
title=title,
|
|
513
508
|
kwargs=kwargs,
|
|
514
509
|
)
|
|
515
510
|
else:
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
interface_depth = compute_depth(
|
|
523
|
-
0, h, self.hc, self.ds.Cs_w, self.ds.sigma_w
|
|
511
|
+
field = xr.zeros_like(depth)
|
|
512
|
+
field = field.assign_coords({"layer_depth": depth})
|
|
513
|
+
|
|
514
|
+
interface_depth = compute_depth_coordinates(
|
|
515
|
+
self.ds, zeta=0, depth_type="interface", eta=eta, xi=xi
|
|
524
516
|
)
|
|
517
|
+
|
|
525
518
|
cmap = plt.colormaps.get_cmap("YlGnBu")
|
|
526
519
|
cmap.set_bad(color="gray")
|
|
527
520
|
kwargs = {"vmax": 0.0, "vmin": 0.0, "cmap": cmap, "add_colorbar": False}
|
|
@@ -533,31 +526,13 @@ class Grid:
|
|
|
533
526
|
kwargs=kwargs,
|
|
534
527
|
)
|
|
535
528
|
|
|
536
|
-
def save(
|
|
537
|
-
self, filepath: Union[str, Path], np_eta: int = None, np_xi: int = None
|
|
538
|
-
) -> None:
|
|
529
|
+
def save(self, filepath: Union[str, Path]) -> None:
|
|
539
530
|
"""Save the grid information to a netCDF4 file.
|
|
540
531
|
|
|
541
|
-
This method supports saving the dataset in two modes:
|
|
542
|
-
|
|
543
|
-
1. **Single File Mode (default)**:
|
|
544
|
-
|
|
545
|
-
If both `np_eta` and `np_xi` are `None`, the entire dataset is saved as a single netCDF4 file
|
|
546
|
-
with the base filename specified by `filepath.nc`.
|
|
547
|
-
|
|
548
|
-
2. **Partitioned Mode**:
|
|
549
|
-
|
|
550
|
-
- If either `np_eta` or `np_xi` is specified, the dataset is divided into spatial tiles along the eta-axis and xi-axis.
|
|
551
|
-
- Each spatial tile is saved as a separate netCDF4 file.
|
|
552
|
-
|
|
553
532
|
Parameters
|
|
554
533
|
----------
|
|
555
534
|
filepath : Union[str, Path]
|
|
556
535
|
The base path or filename where the dataset should be saved.
|
|
557
|
-
np_eta : int, optional
|
|
558
|
-
The number of partitions along the `eta` direction. If `None`, no spatial partitioning is performed.
|
|
559
|
-
np_xi : int, optional
|
|
560
|
-
The number of partitions along the `xi` direction. If `None`, no spatial partitioning is performed.
|
|
561
536
|
|
|
562
537
|
Returns
|
|
563
538
|
-------
|
|
@@ -575,9 +550,7 @@ class Grid:
|
|
|
575
550
|
dataset_list = [self.ds.load()]
|
|
576
551
|
output_filenames = [str(filepath)]
|
|
577
552
|
|
|
578
|
-
saved_filenames = save_datasets(
|
|
579
|
-
dataset_list, output_filenames, np_eta=np_eta, np_xi=np_xi
|
|
580
|
-
)
|
|
553
|
+
saved_filenames = save_datasets(dataset_list, output_filenames)
|
|
581
554
|
|
|
582
555
|
return saved_filenames
|
|
583
556
|
|