Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: can read from netCDF4 or HDF5 variable groups #249

Merged
merged 1 commit into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions pyTMD/io/OTIS.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ def read_otis_elevation(
input_file: str or pathlib.Path
input elevation file
ic: int
index of consituent
index of constituent

Returns
-------
Expand Down Expand Up @@ -1183,7 +1183,7 @@ def read_atlas_elevation(
input_file: str or pathlib.Path
input ATLAS elevation file
ic: int
index of consituent
index of constituent
constituent: str
tidal constituent ID

Expand Down Expand Up @@ -1282,7 +1282,7 @@ def read_otis_transport(
input_file: str or pathlib.Path
input transport file
ic: int
index of consituent
index of constituent

Returns
-------
Expand Down Expand Up @@ -1340,7 +1340,7 @@ def read_atlas_transport(
input_file: str or pathlib.Path
input ATLAS transport file
ic: int
index of consituent
index of constituent
constituent: str
tidal constituent ID

Expand Down Expand Up @@ -1652,7 +1652,7 @@ def read_netcdf_file(
input_file: str or pathlib.Path
input transport file
ic: int
index of consituent
index of constituent
variable: str or NoneType, default None
Tidal variable to read

Expand Down
31 changes: 21 additions & 10 deletions pyTMD/spatial.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
u"""
spatial.py
Written by Tyler Sutterley (09/2023)
Written by Tyler Sutterley (10/2023)

Utilities for reading, writing and operating on spatial data

Expand All @@ -22,6 +22,7 @@
constants.py: calculate reference parameters for common ellipsoids

UPDATE HISTORY:
Updated 10/2023: can read from netCDF4 or HDF5 variable groups
Updated 09/2023: add function to invert field mapping keys and values
use datetime64[ns] for parsing dates from ascii files
Updated 08/2023: remove possible crs variables from output fields list
Expand Down Expand Up @@ -304,6 +305,8 @@
full path of input netCDF4 file
compression: str or NoneType, default None
file compression type
group: str or NoneType, default None
netCDF4 variable group
timename: str, default 'time'
name for time-dimension variable
xname: str, default 'lon'
Expand All @@ -317,6 +320,7 @@
"""
# set default keyword arguments
kwargs.setdefault('compression', None)
kwargs.setdefault('group', None)
kwargs.setdefault('timename', 'time')
kwargs.setdefault('xname', 'lon')
kwargs.setdefault('yname', 'lat')
Expand Down Expand Up @@ -359,19 +363,21 @@
kwargs['field_mapping']['data'] = copy.copy(kwargs['varname'])
if kwargs['timename'] is not None:
kwargs['field_mapping']['time'] = copy.copy(kwargs['timename'])
# check if reading from root group or sub-group
group = fileID.groups[kwargs['group']] if kwargs['group'] else fileID
# for each variable
for key, nc in kwargs['field_mapping'].items():
# Getting the data from each NetCDF variable
dinput[key] = fileID.variables[nc][:]
dinput[key] = group.variables[nc][:]
# get attributes for the included variables
dinput['attributes'][key] = {}
for attr in attributes_list:
# try getting the attribute
try:
ncattr, = [s for s in fileID.variables[nc].ncattrs()
ncattr, = [s for s in group.variables[nc].ncattrs()
if re.match(attr, s, re.I)]
dinput['attributes'][key][attr] = \
fileID.variables[nc].getncattr(ncattr)
group.variables[nc].getncattr(ncattr)
except (ValueError, AttributeError):
pass
# get projection information if there is a grid_mapping attribute
Expand All @@ -380,9 +386,9 @@
grid_mapping = dinput['attributes']['data']['grid_mapping']
# get coordinate reference system attributes
dinput['attributes']['crs'] = {}
for att_name in fileID[grid_mapping].ncattrs():
for att_name in group[grid_mapping].ncattrs():
dinput['attributes']['crs'][att_name] = \
fileID.variables[grid_mapping].getncattr(att_name)
group.variables[grid_mapping].getncattr(att_name)
# get the spatial projection reference information from wkt
# and overwrite the file-level projection attribute (if existing)
srs = osgeo.osr.SpatialReference()
Expand All @@ -408,6 +414,8 @@
full path of input HDF5 file
compression: str or NoneType, default None
file compression type
group: str or NoneType, default None
netCDF4 variable group
timename: str, default 'time'
name for time-dimension variable
xname: str, default 'lon'
Expand All @@ -421,6 +429,7 @@
"""
# set default keyword arguments
kwargs.setdefault('compression', None)
kwargs.setdefault('group', None)
kwargs.setdefault('timename', 'time')
kwargs.setdefault('xname', 'lon')
kwargs.setdefault('yname', 'lat')
Expand Down Expand Up @@ -468,16 +477,18 @@
kwargs['field_mapping']['data'] = copy.copy(kwargs['varname'])
if kwargs['timename'] is not None:
kwargs['field_mapping']['time'] = copy.copy(kwargs['timename'])
# check if reading from root group or sub-group
group = fileID[kwargs['group']] if kwargs['group'] else fileID
# for each variable
for key, h5 in kwargs['field_mapping'].items():
# Getting the data from each HDF5 variable
dinput[key] = np.copy(fileID[h5][:])
dinput[key] = np.copy(group[h5][:])
# get attributes for the included variables
dinput['attributes'][key] = {}
for attr in attributes_list:
# try getting the attribute
try:
dinput['attributes'][key][attr] = fileID[h5].attrs[attr]
dinput['attributes'][key][attr] = group[h5].attrs[attr]
except (KeyError, AttributeError):
pass
# get projection information if there is a grid_mapping attribute
Expand All @@ -486,7 +497,7 @@
grid_mapping = dinput['attributes']['data']['grid_mapping']
# get coordinate reference system attributes
dinput['attributes']['crs'] = {}
for att_name, att_val in fileID[grid_mapping].attrs.items():
for att_name, att_val in group[grid_mapping].attrs.items():
dinput['attributes']['crs'][att_name] = att_val
# get the spatial projection reference information from wkt
# and overwrite the file-level projection attribute (if existing)
Expand Down Expand Up @@ -1090,7 +1101,7 @@
.. [1] J. Meeus, *Astronomical Algorithms*, 2nd edition, 477 pp., (1998).
"""
if (len(phi1) != len(h1)):
raise ValueError('phi and h have incompatable dimensions')
raise ValueError('phi and h have incompatible dimensions')

Check warning on line 1104 in pyTMD/spatial.py

View check run for this annotation

Codecov / codecov/patch

pyTMD/spatial.py#L1104

Added line #L1104 was not covered by tests
# semiminor axis of input and output ellipsoid
b1 = (1.0 - f1)*a1
b2 = (1.0 - f2)*a2
Expand Down
2 changes: 1 addition & 1 deletion pyTMD/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,7 @@ def get_leap_seconds(truncate: bool = True):
# convert from time of 2nd leap second to time of 1st leap second
leap_GPS = convert_delta_time(leap_UTC + TAI_UTC - TAI_GPS - 1,
epoch1=_ntp_epoch, epoch2=_gps_epoch)
# return the GPS times of leap second occurance
# return the GPS times of leap second occurrence
if truncate:
return leap_GPS[leap_GPS >= 0].astype(np.float64)
else:
Expand Down