pyTMD 3.0.2__tar.gz → 3.0.3__tar.gz
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.
- {pytmd-3.0.2/pyTMD.egg-info → pytmd-3.0.3}/PKG-INFO +2 -2
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/reduce_otis.py +7 -7
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/ATLAS.py +15 -9
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/FES.py +9 -7
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/GOT.py +16 -5
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/OTIS.py +20 -15
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/dataset.py +45 -2
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/model.py +38 -8
- {pytmd-3.0.2 → pytmd-3.0.3/pyTMD.egg-info}/PKG-INFO +2 -2
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD.egg-info/requires.txt +1 -1
- {pytmd-3.0.2 → pytmd-3.0.3}/pyproject.toml +3 -3
- {pytmd-3.0.2 → pytmd-3.0.3}/LICENSE +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/MANIFEST.in +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/README.md +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/__init__.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/astro.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/compute.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/constituents.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/ct1971_tab6.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/cte1973_tab.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/d1921_tab.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/database.json +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/doodson.json +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/hw1995_tab.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/re14_tab3.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/t1987_tab.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/tab5.2e.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/tab5.3a.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/tab5.3b.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/data/w1990_tab.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/__init__.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_arcticdata.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_aviso_fes.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_box_tpxo.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_gsfc_got.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_iers_opole.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_jpl_ssd.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/datasets/fetch_test_data.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/ellipse.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/interpolate.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/IERS.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/NOAA.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/io/__init__.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/math.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/predict.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/solve/__init__.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/solve/constants.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/spatial.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/tools.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/utilities.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD/version.py +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD.egg-info/SOURCES.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD.egg-info/dependency_links.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD.egg-info/entry_points.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/pyTMD.egg-info/top_level.txt +0 -0
- {pytmd-3.0.2 → pytmd-3.0.3}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyTMD
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.3
|
|
4
4
|
Summary: Python-based tidal prediction software for estimating ocean, load, solid Earth and pole tides
|
|
5
5
|
Author: Tyler Sutterley
|
|
6
6
|
Author-email: tsutterl@uw.edu
|
|
@@ -58,7 +58,7 @@ Requires-Dist: scipy>=1.10.1
|
|
|
58
58
|
Requires-Dist: timescale>=0.0.8
|
|
59
59
|
Requires-Dist: xarray
|
|
60
60
|
Provides-Extra: doc
|
|
61
|
-
Requires-Dist: docutils; extra == "doc"
|
|
61
|
+
Requires-Dist: docutils>=0.17; extra == "doc"
|
|
62
62
|
Requires-Dist: graphviz; extra == "doc"
|
|
63
63
|
Requires-Dist: ipympl; extra == "doc"
|
|
64
64
|
Requires-Dist: myst-nb; extra == "doc"
|
|
@@ -114,10 +114,10 @@ def reduce_otis(
|
|
|
114
114
|
m["u"].model_file
|
|
115
115
|
)
|
|
116
116
|
# combine local solutions with global solution
|
|
117
|
-
dsg = dsg.compact.combine_local(dtg)
|
|
118
|
-
dsz = dsz.compact.combine_local(dtz)
|
|
119
|
-
dsu = dsu.compact.combine_local(dtu)
|
|
120
|
-
dsv = dsv.compact.combine_local(dtv)
|
|
117
|
+
dsg = dsg.tmd.compact.combine_local(dtg)
|
|
118
|
+
dsz = dsz.tmd.compact.combine_local(dtz)
|
|
119
|
+
dsu = dsu.tmd.compact.combine_local(dtu)
|
|
120
|
+
dsv = dsv.tmd.compact.combine_local(dtv)
|
|
121
121
|
else:
|
|
122
122
|
# if reading a pure global solution
|
|
123
123
|
dsg = pyTMD.io.OTIS.open_otis_grid(m["z"].grid_file)
|
|
@@ -140,9 +140,9 @@ def reduce_otis(
|
|
|
140
140
|
new_elevation_file = _unique_filename(m["z"].model_file)
|
|
141
141
|
new_transport_file = _unique_filename(m["u"].model_file)
|
|
142
142
|
# output reduced datasets to file
|
|
143
|
-
dtree.otis.to_grid(new_grid_file)
|
|
144
|
-
dtree.otis.to_elevation(new_elevation_file)
|
|
145
|
-
dtree.otis.to_transport(new_transport_file)
|
|
143
|
+
dtree.tmd.otis.to_grid(new_grid_file)
|
|
144
|
+
dtree.tmd.otis.to_elevation(new_elevation_file)
|
|
145
|
+
dtree.tmd.otis.to_transport(new_transport_file)
|
|
146
146
|
# change the permissions level to mode
|
|
147
147
|
new_grid_file.chmod(mode=mode)
|
|
148
148
|
new_elevation_file.chmod(mode=mode)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
3
|
ATLAS.py
|
|
4
|
-
Written by Tyler Sutterley (
|
|
4
|
+
Written by Tyler Sutterley (02/2026)
|
|
5
5
|
|
|
6
6
|
Reads netCDF4 ATLAS tidal solutions provided by Oregon State University
|
|
7
7
|
|
|
@@ -10,6 +10,8 @@ PYTHON DEPENDENCIES:
|
|
|
10
10
|
https://docs.xarray.dev/en/stable/
|
|
11
11
|
|
|
12
12
|
UPDATE HISTORY:
|
|
13
|
+
Updated 02/2026: make dataset and datatree accessors for ATLAS
|
|
14
|
+
be subaccessors from dataset module
|
|
13
15
|
Updated 12/2025: no longer subclassing pathlib.Path for working directories
|
|
14
16
|
added option to change the output datatype when writing netCDF files
|
|
15
17
|
Updated 11/2025: near-complete rewrite of program to use xarray
|
|
@@ -63,6 +65,10 @@ import datetime
|
|
|
63
65
|
import xarray as xr
|
|
64
66
|
import pyTMD.version
|
|
65
67
|
import pyTMD.utilities
|
|
68
|
+
from .dataset import (
|
|
69
|
+
register_dataset_subaccessor,
|
|
70
|
+
register_datatree_subaccessor,
|
|
71
|
+
)
|
|
66
72
|
|
|
67
73
|
# attempt imports
|
|
68
74
|
dask = pyTMD.utilities.import_dependency("dask")
|
|
@@ -295,11 +301,10 @@ def open_atlas_dataset(
|
|
|
295
301
|
|
|
296
302
|
|
|
297
303
|
# PURPOSE: ATLAS-netcdf utilities for xarray Datasets
|
|
298
|
-
@
|
|
304
|
+
@register_dataset_subaccessor("atlas")
|
|
299
305
|
class ATLASDataset:
|
|
300
306
|
"""
|
|
301
|
-
|
|
302
|
-
tidal models
|
|
307
|
+
``xarray.Dataset`` utilities for ATLAS-netcdf tidal models
|
|
303
308
|
"""
|
|
304
309
|
|
|
305
310
|
def __init__(self, ds):
|
|
@@ -462,11 +467,10 @@ class ATLASDataset:
|
|
|
462
467
|
|
|
463
468
|
|
|
464
469
|
# PURPOSE: ATLAS-netcdf utilities for xarray DataTrees
|
|
465
|
-
@
|
|
470
|
+
@register_datatree_subaccessor("atlas")
|
|
466
471
|
class ATLASDataTree:
|
|
467
472
|
"""
|
|
468
|
-
|
|
469
|
-
tidal models
|
|
473
|
+
``xarray.DataTree`` utilities for ATLAS-netcdf tidal models
|
|
470
474
|
"""
|
|
471
475
|
|
|
472
476
|
def __init__(self, dtree):
|
|
@@ -500,6 +504,8 @@ class ATLASDataTree:
|
|
|
500
504
|
ds = self._dtree[group].to_dataset()
|
|
501
505
|
# write in append mode to add group to same grid and directory
|
|
502
506
|
# output grid file
|
|
503
|
-
ds.
|
|
507
|
+
ATLASDataset(ds).to_grid(grid_file, group=group, mode="a", **kwargs)
|
|
504
508
|
# output constituent files
|
|
505
|
-
ds.
|
|
509
|
+
ATLASDataset(ds).to_netcdf(
|
|
510
|
+
directory, group=group, mode="a", **kwargs
|
|
511
|
+
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
3
|
FES.py
|
|
4
|
-
Written by Tyler Sutterley (
|
|
4
|
+
Written by Tyler Sutterley (02/2026)
|
|
5
5
|
|
|
6
6
|
Reads ascii and netCDF4 files for FES tidal solutions provided by AVISO
|
|
7
7
|
https://www.aviso.altimetry.fr/data/products/auxiliary-products/
|
|
@@ -15,6 +15,7 @@ PYTHON DEPENDENCIES:
|
|
|
15
15
|
https://docs.xarray.dev/en/stable/
|
|
16
16
|
|
|
17
17
|
UPDATE HISTORY:
|
|
18
|
+
Updated 02/2026: make dataset accessor for FES be a subaccessor from dataset
|
|
18
19
|
Updated 12/2025: no longer subclassing pathlib.Path for working directories
|
|
19
20
|
Updated 11/2025: near-complete rewrite of program to use xarray
|
|
20
21
|
Updated 10/2025: simplify ascii read function to use masked_equal
|
|
@@ -71,6 +72,7 @@ import numpy as np
|
|
|
71
72
|
import xarray as xr
|
|
72
73
|
import pyTMD.constituents
|
|
73
74
|
import pyTMD.utilities
|
|
75
|
+
from .dataset import register_dataset_subaccessor
|
|
74
76
|
|
|
75
77
|
# attempt imports
|
|
76
78
|
dask = pyTMD.utilities.import_dependency("dask")
|
|
@@ -311,14 +313,14 @@ def open_fes_netcdf(
|
|
|
311
313
|
if "Ha" in tmp.variables:
|
|
312
314
|
# FES2012 variable names
|
|
313
315
|
mapping_coords = dict(lon="x", lat="y")
|
|
314
|
-
mapping_amp = dict(z="Ha"
|
|
315
|
-
mapping_ph = dict(z="Hg"
|
|
316
|
-
elif
|
|
316
|
+
mapping_amp = dict(z="Ha")
|
|
317
|
+
mapping_ph = dict(z="Hg")
|
|
318
|
+
elif any([v in tmp.variables for v in ["amplitude", "Ua", "Va"]]):
|
|
317
319
|
# FES2014/2022 variable names
|
|
318
320
|
mapping_coords = dict(lon="x", lat="y")
|
|
319
321
|
mapping_amp = dict(z="amplitude", u="Ua", v="Va")
|
|
320
322
|
mapping_ph = dict(z="phase", u="Ug", v="Vg")
|
|
321
|
-
elif
|
|
323
|
+
elif any([v in tmp.variables for v in ["AMPL", "UAMP", "VAMP"]]):
|
|
322
324
|
# HAMTIDE11 variable names
|
|
323
325
|
mapping_coords = dict(LON="x", LAT="y")
|
|
324
326
|
mapping_amp = dict(z="AMPL", u="UAMP", v="VAMP")
|
|
@@ -344,9 +346,9 @@ def open_fes_netcdf(
|
|
|
344
346
|
|
|
345
347
|
|
|
346
348
|
# PURPOSE: FES utilities for xarray Datasets
|
|
347
|
-
@
|
|
349
|
+
@register_dataset_subaccessor("fes")
|
|
348
350
|
class FESDataset:
|
|
349
|
-
"""
|
|
351
|
+
"""``xarray.Dataset`` utilities for FES tidal models"""
|
|
350
352
|
|
|
351
353
|
def __init__(self, ds):
|
|
352
354
|
self._ds = ds
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
3
|
GOT.py
|
|
4
|
-
Written by Tyler Sutterley (
|
|
4
|
+
Written by Tyler Sutterley (02/2026)
|
|
5
5
|
|
|
6
6
|
Reads ascii and netCDF4 files from Richard Ray's Goddard Ocean Tide (GOT) model
|
|
7
7
|
https://earth.gsfc.nasa.gov/geo/data/ocean-tide-models
|
|
@@ -14,6 +14,8 @@ PYTHON DEPENDENCIES:
|
|
|
14
14
|
https://docs.xarray.dev/en/stable/
|
|
15
15
|
|
|
16
16
|
UPDATE HISTORY:
|
|
17
|
+
Updated 02/2026: make dataset accessor for GOT be a subaccessor from dataset
|
|
18
|
+
some models have units in the second line of the header text
|
|
17
19
|
Updated 12/2025: no longer subclassing pathlib.Path for working directories
|
|
18
20
|
added function to write to output GOT-formatted ascii files
|
|
19
21
|
fixed writing of output constituents to match GOT attribute format
|
|
@@ -74,6 +76,7 @@ import xarray as xr
|
|
|
74
76
|
import pyTMD.version
|
|
75
77
|
import pyTMD.constituents
|
|
76
78
|
import pyTMD.utilities
|
|
79
|
+
from .dataset import register_dataset_subaccessor
|
|
77
80
|
|
|
78
81
|
# attempt imports
|
|
79
82
|
dask = pyTMD.utilities.import_dependency("dask")
|
|
@@ -208,8 +211,16 @@ def open_got_ascii(
|
|
|
208
211
|
# parse header text
|
|
209
212
|
# constituent identifier
|
|
210
213
|
cons = pyTMD.constituents._parse_name(file_contents[0])
|
|
211
|
-
# get units
|
|
212
|
-
|
|
214
|
+
# get units from header if available
|
|
215
|
+
rx = re.compile(r"\((\w+m)\)", re.IGNORECASE)
|
|
216
|
+
# GOT headers from Richard Ray have units on the first line
|
|
217
|
+
# some other models have units on the second line
|
|
218
|
+
if rx.search(file_contents[0]):
|
|
219
|
+
units = rx.findall(file_contents[0], re.IGNORECASE)
|
|
220
|
+
elif rx.search(file_contents[1]):
|
|
221
|
+
units = rx.findall(file_contents[1], re.IGNORECASE)
|
|
222
|
+
else:
|
|
223
|
+
units = None
|
|
213
224
|
# grid dimensions
|
|
214
225
|
nlat, nlon = np.array(file_contents[2].split(), dtype=int)
|
|
215
226
|
# longitude range
|
|
@@ -331,9 +342,9 @@ def open_got_netcdf(
|
|
|
331
342
|
|
|
332
343
|
|
|
333
344
|
# PURPOSE: GOT utilities for xarray Datasets
|
|
334
|
-
@
|
|
345
|
+
@register_dataset_subaccessor("got")
|
|
335
346
|
class GOTDataset:
|
|
336
|
-
"""
|
|
347
|
+
"""``xarray.Dataset`` utilities for GOT tidal models"""
|
|
337
348
|
|
|
338
349
|
def __init__(self, ds):
|
|
339
350
|
self._ds = ds
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
3
|
OTIS.py
|
|
4
|
-
Written by Tyler Sutterley (
|
|
4
|
+
Written by Tyler Sutterley (02/2026)
|
|
5
5
|
|
|
6
6
|
Reads OTIS format tidal solutions provided by Oregon State University and ESR
|
|
7
7
|
http://volkov.oce.orst.edu/tides/region.html
|
|
@@ -19,6 +19,8 @@ PYTHON DEPENDENCIES:
|
|
|
19
19
|
https://docs.xarray.dev/en/stable/
|
|
20
20
|
|
|
21
21
|
UPDATE HISTORY:
|
|
22
|
+
Updated 02/2026: make dataset and datatree accessors for OTIS
|
|
23
|
+
be subaccessors from dataset module
|
|
22
24
|
Updated 01/2026: check if flexure variable exists in TMD3 files
|
|
23
25
|
Updated 12/2025: no longer subclassing pathlib.Path for working directories
|
|
24
26
|
Updated 11/2025: near-complete rewrite of program to use xarray
|
|
@@ -102,6 +104,10 @@ import warnings
|
|
|
102
104
|
import numpy as np
|
|
103
105
|
import xarray as xr
|
|
104
106
|
import pyTMD.utilities
|
|
107
|
+
from .dataset import (
|
|
108
|
+
register_dataset_subaccessor,
|
|
109
|
+
register_datatree_subaccessor,
|
|
110
|
+
)
|
|
105
111
|
|
|
106
112
|
# attempt imports
|
|
107
113
|
dask = pyTMD.utilities.import_dependency("dask")
|
|
@@ -126,7 +132,7 @@ __all__ = [
|
|
|
126
132
|
"write_raw_binary",
|
|
127
133
|
"OTISDataset",
|
|
128
134
|
"OTISDataTree",
|
|
129
|
-
"
|
|
135
|
+
"CompactDataset",
|
|
130
136
|
]
|
|
131
137
|
|
|
132
138
|
# variable attributes
|
|
@@ -373,7 +379,7 @@ def open_otis_dataset(
|
|
|
373
379
|
# transports are returned as (u,v)
|
|
374
380
|
ds2 = open_otis_transport(model_file, **kwargs)[1]
|
|
375
381
|
# merge datasets
|
|
376
|
-
ds = ds1.
|
|
382
|
+
ds = OTISDataset(ds1).merge(ds2, group=group)
|
|
377
383
|
# add attributes
|
|
378
384
|
ds.attrs["group"] = group.upper() if group in ("u", "v") else group
|
|
379
385
|
# return xarray dataset
|
|
@@ -421,22 +427,22 @@ def open_atlas_dataset(
|
|
|
421
427
|
crs = kwargs.get("crs", 4326)
|
|
422
428
|
# open grid file
|
|
423
429
|
dsg, dtg = open_atlas_grid(grid_file, use_mmap=use_mmap)
|
|
424
|
-
ds1 = dsg.
|
|
430
|
+
ds1 = CompactDataset(dsg).combine_local(dtg, chunks=chunks)
|
|
425
431
|
# add attributes
|
|
426
432
|
ds1.attrs["crs"] = pyproj.CRS.from_user_input(crs).to_dict()
|
|
427
433
|
# open model file(s)
|
|
428
434
|
if group == "z":
|
|
429
435
|
# elevations are returned as (z, localz)
|
|
430
436
|
dsh, dth = open_atlas_elevation(model_file, use_mmap=use_mmap)
|
|
431
|
-
ds2 = dsh.
|
|
437
|
+
ds2 = CompactDataset(dsh).combine_local(dth, chunks=chunks)
|
|
432
438
|
elif group in ("u", "U"):
|
|
433
439
|
# transports are returned as (u, v, localu, localv)
|
|
434
440
|
dsu, dtu, dsv, dtv = open_atlas_transport(model_file, use_mmap=use_mmap)
|
|
435
|
-
ds2 = dsu.
|
|
441
|
+
ds2 = CompactDataset(dsu).combine_local(dtu, chunks=chunks)
|
|
436
442
|
elif group in ("v", "V"):
|
|
437
443
|
# transports are returned as (u, v, localu, localv)
|
|
438
444
|
dsu, dtu, dsv, dtv = open_atlas_transport(model_file, use_mmap=use_mmap)
|
|
439
|
-
ds2 = dsv.
|
|
445
|
+
ds2 = CompactDataset(dsv).combine_local(dtv, chunks=chunks)
|
|
440
446
|
# merge datasets
|
|
441
447
|
ds = xr.merge([ds1, ds2], compat="override")
|
|
442
448
|
# add attributes
|
|
@@ -1836,9 +1842,9 @@ def write_raw_binary(
|
|
|
1836
1842
|
|
|
1837
1843
|
|
|
1838
1844
|
# PURPOSE: OTIS utilities for xarray Datasets
|
|
1839
|
-
@
|
|
1845
|
+
@register_dataset_subaccessor("otis")
|
|
1840
1846
|
class OTISDataset:
|
|
1841
|
-
"""
|
|
1847
|
+
"""``xarray.Dataset`` utilities for OTIS tidal models"""
|
|
1842
1848
|
|
|
1843
1849
|
def __init__(self, ds):
|
|
1844
1850
|
# initialize dataset
|
|
@@ -1913,9 +1919,9 @@ class OTISDataset:
|
|
|
1913
1919
|
|
|
1914
1920
|
|
|
1915
1921
|
# PURPOSE: OTIS utilities for xarray datatrees
|
|
1916
|
-
@
|
|
1922
|
+
@register_datatree_subaccessor("otis")
|
|
1917
1923
|
class OTISDataTree:
|
|
1918
|
-
"""
|
|
1924
|
+
"""``xarray.DataTree`` utilities for OTIS tidal models"""
|
|
1919
1925
|
|
|
1920
1926
|
def __init__(self, dtree):
|
|
1921
1927
|
# initialize datatree
|
|
@@ -2144,11 +2150,10 @@ class OTISDataTree:
|
|
|
2144
2150
|
|
|
2145
2151
|
|
|
2146
2152
|
# PURPOSE: ATLAS-compact utilities for xarray Datasets
|
|
2147
|
-
@
|
|
2148
|
-
class
|
|
2153
|
+
@register_datatree_subaccessor("compact")
|
|
2154
|
+
class CompactDataset:
|
|
2149
2155
|
"""
|
|
2150
|
-
|
|
2151
|
-
tidal models
|
|
2156
|
+
``xarray.Dataset`` utilities for ATLAS-compact tidal models
|
|
2152
2157
|
"""
|
|
2153
2158
|
|
|
2154
2159
|
def __init__(self, ds, spacing: float | list[float] = 1.0 / 30.0):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
3
|
dataset.py
|
|
4
|
-
Written by Tyler Sutterley (
|
|
4
|
+
Written by Tyler Sutterley (02/2026)
|
|
5
5
|
An xarray.Dataset extension for tidal model data
|
|
6
6
|
|
|
7
7
|
PYTHON DEPENDENCIES:
|
|
@@ -17,6 +17,7 @@ PYTHON DEPENDENCIES:
|
|
|
17
17
|
https://docs.xarray.dev/en/stable/
|
|
18
18
|
|
|
19
19
|
UPDATE HISTORY:
|
|
20
|
+
Updated 02/2026: create subaccessor registration functions
|
|
20
21
|
Updated 01/2026: handle scalar inputs for coordinate transformations
|
|
21
22
|
Updated 12/2025: add coords functions to transform coordinates
|
|
22
23
|
set units attribute for amplitude and phase data arrays
|
|
@@ -40,7 +41,16 @@ import xarray as xr
|
|
|
40
41
|
# suppress warnings
|
|
41
42
|
warnings.filterwarnings("ignore", category=UserWarning)
|
|
42
43
|
|
|
43
|
-
__all__ = [
|
|
44
|
+
__all__ = [
|
|
45
|
+
"DataTree",
|
|
46
|
+
"Dataset",
|
|
47
|
+
"DataArray",
|
|
48
|
+
"register_datatree_subaccessor",
|
|
49
|
+
"register_dataset_subaccessor",
|
|
50
|
+
"register_dataarray_subaccessor",
|
|
51
|
+
"_transform",
|
|
52
|
+
"_coords",
|
|
53
|
+
]
|
|
44
54
|
|
|
45
55
|
# pint unit registry
|
|
46
56
|
__ureg__ = pint.UnitRegistry()
|
|
@@ -916,6 +926,39 @@ class DataArray:
|
|
|
916
926
|
raise ValueError(f"Unknown unit group: {self.units}")
|
|
917
927
|
|
|
918
928
|
|
|
929
|
+
def register_datatree_subaccessor(name):
|
|
930
|
+
"""Register a subaccessor on ``DataTree`` objects
|
|
931
|
+
|
|
932
|
+
Parameters
|
|
933
|
+
----------
|
|
934
|
+
name: str
|
|
935
|
+
subaccessor name
|
|
936
|
+
"""
|
|
937
|
+
return xr.core.extensions._register_accessor(name, DataTree)
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
def register_dataset_subaccessor(name):
|
|
941
|
+
"""Register a subaccessor on ``Dataset`` objects
|
|
942
|
+
|
|
943
|
+
Parameters
|
|
944
|
+
----------
|
|
945
|
+
name: str
|
|
946
|
+
subaccessor name
|
|
947
|
+
"""
|
|
948
|
+
return xr.core.extensions._register_accessor(name, Dataset)
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
def register_dataarray_subaccessor(name):
|
|
952
|
+
"""Register a subaccessor on ``DataArray`` objects
|
|
953
|
+
|
|
954
|
+
Parameters
|
|
955
|
+
----------
|
|
956
|
+
name: str
|
|
957
|
+
subaccessor name
|
|
958
|
+
"""
|
|
959
|
+
return xr.core.extensions._register_accessor(name, DataArray)
|
|
960
|
+
|
|
961
|
+
|
|
919
962
|
def _transform(
|
|
920
963
|
i1: np.ndarray,
|
|
921
964
|
i2: np.ndarray,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
"""
|
|
3
3
|
model.py
|
|
4
|
-
Written by Tyler Sutterley (
|
|
4
|
+
Written by Tyler Sutterley (02/2026)
|
|
5
5
|
Retrieves tide model parameters for named tide models and
|
|
6
6
|
from model definition files
|
|
7
7
|
|
|
@@ -13,6 +13,8 @@ PYTHON DEPENDENCIES:
|
|
|
13
13
|
https://docs.xarray.dev/en/stable/
|
|
14
14
|
|
|
15
15
|
UPDATE HISTORY:
|
|
16
|
+
Updated 02/2026: add HTML representation for model objects using xarray
|
|
17
|
+
set tidal constituent units (if unset) in a loop
|
|
16
18
|
Updated 11/2025: use default cache directory if directory is None
|
|
17
19
|
added crs property for model coordinate reference system
|
|
18
20
|
refactor to use new simpler (flattened) database format
|
|
@@ -121,14 +123,14 @@ class DataBase:
|
|
|
121
123
|
"""Returns the items of the model database"""
|
|
122
124
|
return self.__dict__.items()
|
|
123
125
|
|
|
124
|
-
def __repr__(self):
|
|
125
|
-
"""Representation of the ``DataBase`` object"""
|
|
126
|
-
return str(self.__dict__)
|
|
127
|
-
|
|
128
126
|
def __str__(self):
|
|
129
127
|
"""String representation of the ``DataBase`` object"""
|
|
130
128
|
return str(self.__dict__)
|
|
131
129
|
|
|
130
|
+
def __repr__(self):
|
|
131
|
+
"""Representation of the ``DataBase`` object"""
|
|
132
|
+
return self.__str__()
|
|
133
|
+
|
|
132
134
|
def get(self, key, default=None):
|
|
133
135
|
if not hasattr(self, key) or getattr(self, key) is None:
|
|
134
136
|
return default
|
|
@@ -218,6 +220,7 @@ class model:
|
|
|
218
220
|
self.format = None
|
|
219
221
|
self.name = None
|
|
220
222
|
self.verify = copy.copy(kwargs["verify"])
|
|
223
|
+
self.__parameters__ = {}
|
|
221
224
|
|
|
222
225
|
def from_database(self, m: str, group: tuple = ("z", "u", "v")):
|
|
223
226
|
"""
|
|
@@ -833,11 +836,10 @@ class model:
|
|
|
833
836
|
ds.attrs["source"] = self.name
|
|
834
837
|
# add coordinate reference system to Dataset
|
|
835
838
|
ds.attrs["crs"] = self.crs.to_dict()
|
|
836
|
-
# list of constituents
|
|
837
|
-
c = ds.tmd.constituents
|
|
838
839
|
# set units attribute if not already set
|
|
839
840
|
# (uses value defined in the model database)
|
|
840
|
-
|
|
841
|
+
for c in ds.tmd.constituents:
|
|
842
|
+
ds[c].attrs["units"] = ds[c].attrs.get("units", self[group].units)
|
|
841
843
|
# convert to default units
|
|
842
844
|
if kwargs["use_default_units"]:
|
|
843
845
|
ds = ds.tmd.to_default_units()
|
|
@@ -873,6 +875,34 @@ class model:
|
|
|
873
875
|
properties.append(f" name: {self.name}")
|
|
874
876
|
return "\n".join(properties)
|
|
875
877
|
|
|
878
|
+
def __repr__(self):
|
|
879
|
+
"""Representation of the ``io.model`` object"""
|
|
880
|
+
return self.__str__()
|
|
881
|
+
|
|
882
|
+
def _repr_html_(self):
|
|
883
|
+
"""HTML representation of the ``io.model`` object"""
|
|
884
|
+
header = "pyTMD.io.model"
|
|
885
|
+
header_components = [f"<div class='xr-obj-type'>{header}</div>"]
|
|
886
|
+
sections = []
|
|
887
|
+
data_vars = [k for k in ("z", "u", "v") if k in self.__parameters__]
|
|
888
|
+
parameters = {
|
|
889
|
+
k: v for k, v in self.__parameters__.items() if k not in data_vars
|
|
890
|
+
}
|
|
891
|
+
sections.append(xr.core.formatting_html.attr_section(parameters))
|
|
892
|
+
for v in data_vars:
|
|
893
|
+
sections.append(
|
|
894
|
+
xr.core.formatting_html._mapping_section(
|
|
895
|
+
mapping=self.__parameters__[v],
|
|
896
|
+
name=f"{v}-Attributes",
|
|
897
|
+
details_func=xr.core.formatting_html.summarize_attrs,
|
|
898
|
+
max_items_collapse=0,
|
|
899
|
+
expand_option_name="display_expand_attrs",
|
|
900
|
+
)
|
|
901
|
+
)
|
|
902
|
+
return xr.core.formatting_html._obj_repr(
|
|
903
|
+
self, header_components, sections
|
|
904
|
+
)
|
|
905
|
+
|
|
876
906
|
def get(self, key, default=None):
|
|
877
907
|
return getattr(self, key, default) or default
|
|
878
908
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyTMD
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.3
|
|
4
4
|
Summary: Python-based tidal prediction software for estimating ocean, load, solid Earth and pole tides
|
|
5
5
|
Author: Tyler Sutterley
|
|
6
6
|
Author-email: tsutterl@uw.edu
|
|
@@ -58,7 +58,7 @@ Requires-Dist: scipy>=1.10.1
|
|
|
58
58
|
Requires-Dist: timescale>=0.0.8
|
|
59
59
|
Requires-Dist: xarray
|
|
60
60
|
Provides-Extra: doc
|
|
61
|
-
Requires-Dist: docutils; extra == "doc"
|
|
61
|
+
Requires-Dist: docutils>=0.17; extra == "doc"
|
|
62
62
|
Requires-Dist: graphviz; extra == "doc"
|
|
63
63
|
Requires-Dist: ipympl; extra == "doc"
|
|
64
64
|
Requires-Dist: myst-nb; extra == "doc"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyTMD"
|
|
7
|
-
version = "3.0.
|
|
7
|
+
version = "3.0.3"
|
|
8
8
|
description = "Python-based tidal prediction software for estimating ocean, load, solid Earth and pole tides"
|
|
9
9
|
keywords = [
|
|
10
10
|
"Ocean Tides",
|
|
@@ -59,7 +59,7 @@ Repository = "https://github.com/pyTMD/pyTMD"
|
|
|
59
59
|
Issues = "https://github.com/pyTMD/pyTMD/issues"
|
|
60
60
|
|
|
61
61
|
[project.optional-dependencies]
|
|
62
|
-
doc = ["docutils", "graphviz", "ipympl", "myst-nb", "numpydoc", "sphinx", "sphinx-argparse>=0.4", "sphinxcontrib-bibtex", "sphinx-design", "sphinx_rtd_theme"]
|
|
62
|
+
doc = ["docutils>=0.17", "graphviz", "ipympl", "myst-nb", "numpydoc", "sphinx", "sphinx-argparse>=0.4", "sphinxcontrib-bibtex", "sphinx-design", "sphinx_rtd_theme"]
|
|
63
63
|
all = ["cartopy", "ipyleaflet", "ipywidgets", "jplephem", "jupyterlab", "matplotlib", "notebook", "pandas"]
|
|
64
64
|
aws = ["dask", "obstore", "pandas", "pyarrow", "s3fs", "zarr>=3"]
|
|
65
65
|
dev = ["dask", "flake8", "gh", "oct2py", "pytest>=4.6", "pytest-cov", "pytest-xdist"]
|
|
@@ -230,7 +230,7 @@ pytest-cov = "*"
|
|
|
230
230
|
pytest-xdist = "*"
|
|
231
231
|
|
|
232
232
|
[tool.pixi.feature.doc.dependencies]
|
|
233
|
-
docutils = "
|
|
233
|
+
docutils = ">=0.17"
|
|
234
234
|
graphviz = "*"
|
|
235
235
|
ipympl = "*"
|
|
236
236
|
myst-nb = "*"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|