Skip to content

Commit

Permalink
feat: check if input filename is an open HDF5 file object (#89)
Browse files Browse the repository at this point in the history
* feat: check if input filename is an open HDF5 file object

* refactor: use wrapper to importlib for optional dependencies

* Update environment.yml
  • Loading branch information
tsutterley authored May 7, 2024
1 parent 089102f commit cb43fd0
Show file tree
Hide file tree
Showing 34 changed files with 393 additions and 481 deletions.
1 change: 1 addition & 0 deletions doc/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies:
- scp
- sphinx
- sphinx_rtd_theme
- timescale
- pip:
- sphinx-argparse>=0.4
- ..
Expand Down
2 changes: 2 additions & 0 deletions doc/source/api_reference/utilities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ General Methods

.. autofunction:: icesat2_toolkit.utilities.get_data_path

.. autofunction:: icesat2_toolkit.utilities.import_dependency

.. autofunction:: icesat2_toolkit.utilities.get_hash

.. autofunction:: icesat2_toolkit.utilities.get_git_revision_hash
Expand Down
19 changes: 6 additions & 13 deletions icesat2_toolkit/convert.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
convert.py
Written by Tyler Sutterley (03/2024)
Written by Tyler Sutterley (05/2024)
Utilities for converting ICESat-2 HDF5 files into different formats
PYTHON DEPENDENCIES:
Expand All @@ -17,6 +17,7 @@
https://pandas.pydata.org/
UPDATE HISTORY:
Updated 05/2024: use wrapper to importlib for optional dependencies
Updated 03/2024: use pathlib to define and operate on paths
Updated 12/2022: place some imports behind try/except statements
Updated 06/2022: place zarr and pandas imports behind try/except statements
Expand All @@ -35,20 +36,12 @@
import itertools
import posixpath
import numpy as np
from icesat2_toolkit.utilities import import_dependency

# attempt imports
try:
import h5py
except ModuleNotFoundError:
warnings.warn("h5py not available", ImportWarning)
try:
import pandas
except ModuleNotFoundError:
warnings.warn("pandas not available", ImportWarning)
try:
import zarr
except ModuleNotFoundError:
warnings.warn("zarr not available", ImportWarning)
h5py = import_dependency('h5py')
pandas = import_dependency('pandas')
zarr = import_dependency('zarr')

class convert():
np.seterr(invalid='ignore')
Expand Down
3 changes: 2 additions & 1 deletion icesat2_toolkit/convert_delta_time.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
u"""
convert_delta_time.py (04/2022)
convert_delta_time.py (04/2024)
Converts time from delta seconds into Julian and year-decimal
INPUTS:
Expand All @@ -21,6 +21,7 @@
https://pypi.org/project/timescale/
UPDATE HISTORY:
Updated 04/2024: use timescale for temporal operations
Updated 04/2022: updated docstrings to numpy documentation format
Updated 01/2021: time utilities for converting times from JD and to decimal
Updated 08/2020: time utilities for counting leap seconds and JD conversion
Expand Down
15 changes: 7 additions & 8 deletions icesat2_toolkit/fit.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
u"""
fit.py
Written by Tyler Sutterley (12/2021)
Written by Tyler Sutterley (05/2024)
Utilities for calculating average fits from ATL03 Geolocated Photon Data
PYTHON DEPENDENCIES:
Expand All @@ -15,6 +15,7 @@
https://github.com/scikit-learn/scikit-learn
UPDATE HISTORY:
Updated 05/2024: use wrapper to importlib for optional dependencies
Updated 12/2022: place some imports behind try/except statements
Updated 04/2022: updated docstrings to numpy documentation format
Written 05/2021
Expand All @@ -26,12 +27,10 @@
import scipy.stats
import scipy.signal
import scipy.optimize
from icesat2_toolkit.utilities import import_dependency

# attempt imports
try:
import sklearn.neighbors
except (AttributeError, ImportError, ModuleNotFoundError) as exc:
warnings.warn("scikit-learn not available", ImportWarning)
neighbors = import_dependency('sklearn.neighbors')

# PURPOSE: compress complete list of valid indices into a set of ranges
def compress_list(i,n):
Expand Down Expand Up @@ -527,7 +526,7 @@ def reduce_histogram_fit(x, y, z, ind, dt, FIT_TYPE='gaussian',
# using kernel density functions from scikit-learn neighbors
# gaussian kernels will reflect more accurate distributions of the data
# with less sensitivity to sampling width than histograms (tophat kernels)
kde = sklearn.neighbors.KernelDensity(bandwidth=dz,kernel='gaussian')
kde = neighbors.KernelDensity(bandwidth=dz, kernel='gaussian')
kde.fit(z[:,None])
# kde score_samples outputs are normalized log density functions
hist = np.exp(kde.score_samples(z_full[:,None]) + np.log(n_max*dz))
Expand Down Expand Up @@ -655,7 +654,7 @@ def reduce_histogram_fit(x, y, z, ind, dt, FIT_TYPE='gaussian',
# using kernel density functions from scikit-learn neighbors
# gaussian kernels will reflect more accurate distributions of the data
# with less sensitivity to sampling width than histograms (tophat kernels)
kde = sklearn.neighbors.KernelDensity(bandwidth=dz,kernel='gaussian')
kde = neighbors.KernelDensity(bandwidth=dz,kernel='gaussian')
kde.fit(z_filt[:,None])
# kde score_samples outputs are normalized log density functions
hist = np.exp(kde.score_samples(z_full[:,None]) + np.log(nz*dz))
Expand Down Expand Up @@ -990,7 +989,7 @@ def calc_first_photon_bias(temporal_residuals,n_pulses,n_pixels,dead_time,dt,
# using kernel density functions from scikit-learn neighbors
# gaussian kernels will reflect more accurate distributions of the data
# with less sensitivity to sampling width than histograms (tophat kernels)
kde = sklearn.neighbors.KernelDensity(bandwidth=dt,kernel='gaussian')
kde = neighbors.KernelDensity(bandwidth=dt,kernel='gaussian')
kde.fit(temporal_residuals[:,None])
# kde score_samples outputs are normalized log density functions
hist = np.exp(kde.score_samples(t_full[:,None]) + np.log(cnt*dt))
Expand Down
20 changes: 15 additions & 5 deletions icesat2_toolkit/io/ATL03.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
u"""
ATL03.py (03/2024)
ATL03.py (05/2024)
Read ICESat-2 ATL03 and ATL09 data files to calculate average segment surfaces
ATL03 datasets: Global Geolocated Photons
ATL09 datasets: Atmospheric Characteristics
Expand All @@ -15,6 +15,8 @@
https://www.h5py.org/
UPDATE HISTORY:
Updated 05/2024: use wrapper to importlib for optional dependencies
check if input filename is an open HDF5 file object
Updated 03/2024: use pathlib to define and operate on paths
Updated 11/2023: drop DIMENSION_LIST, CLASS and NAME attributes
Updated 12/2022: place some imports behind try/except statements
Expand All @@ -41,12 +43,10 @@
import warnings
import numpy as np
import scipy.interpolate
from icesat2_toolkit.utilities import import_dependency

# attempt imports
try:
import h5py
except ModuleNotFoundError:
warnings.warn("h5py not available", ImportWarning)
h5py = import_dependency('h5py')

# PURPOSE: read ICESat-2 ATL03 HDF5 data files
def read_granule(FILENAME, ATTRIBUTES=False, **kwargs):
Expand All @@ -72,6 +72,8 @@ def read_granule(FILENAME, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -299,6 +301,8 @@ def interpolate_ATL09(FILENAME, pfl, dtime, ATTRIBUTES=True, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -368,6 +372,8 @@ def find_beams(FILENAME, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -414,6 +420,8 @@ def read_main(FILENAME, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -586,6 +594,8 @@ def read_beam(FILENAME, gtx, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down
16 changes: 11 additions & 5 deletions icesat2_toolkit/io/ATL06.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
u"""
ATL06.py (03/2024)
ATL06.py (05/2024)
Read ICESat-2 ATL06 (Land Ice Along-Track Height Product) data files
OPTIONS:
Expand All @@ -16,6 +16,8 @@
https://www.h5py.org/
UPDATE HISTORY:
Updated 05/2024: use wrapper to importlib for optional dependencies
check if input filename is an open HDF5 file object
Updated 03/2024: use pathlib to define and operate on paths
Updated 11/2023: drop DIMENSION_LIST, CLASS and NAME attributes
Updated 05/2023: extract more ancillary data from ATL06 files
Expand All @@ -39,12 +41,10 @@
import pathlib
import warnings
import numpy as np
from icesat2_toolkit.utilities import import_dependency

# attempt imports
try:
import h5py
except ModuleNotFoundError:
warnings.warn("h5py not available", ImportWarning)
h5py = import_dependency('h5py')

# PURPOSE: read ICESat-2 ATL06 HDF5 data files
def read_granule(FILENAME, ATTRIBUTES=False, HISTOGRAM=False,
Expand Down Expand Up @@ -75,6 +75,8 @@ def read_granule(FILENAME, ATTRIBUTES=False, HISTOGRAM=False,
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -287,6 +289,8 @@ def find_beams(FILENAME, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -342,6 +346,8 @@ def read_beam(FILENAME, gtx, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down
16 changes: 11 additions & 5 deletions icesat2_toolkit/io/ATL07.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
u"""
ATL07.py (03/2024)
ATL07.py (05/2024)
Read ICESat-2 ATL07 (Sea Ice Height) data files
PYTHON DEPENDENCIES:
Expand All @@ -11,6 +11,8 @@
https://www.h5py.org/
UPDATE HISTORY:
Updated 05/2024: use wrapper to importlib for optional dependencies
check if input filename is an open HDF5 file object
Updated 03/2024: use pathlib to define and operate on paths
Updated 11/2023: drop DIMENSION_LIST, CLASS and NAME attributes
Updated 05/2023: extract more ancillary data from ATL07 files
Expand All @@ -32,12 +34,10 @@
import pathlib
import warnings
import numpy as np
from icesat2_toolkit.utilities import import_dependency

# attempt imports
try:
import h5py
except ModuleNotFoundError:
warnings.warn("h5py not available", ImportWarning)
h5py = import_dependency('h5py')

# PURPOSE: read ICESat-2 ATL07 HDF5 data files
def read_granule(FILENAME, ATTRIBUTES=False, **kwargs):
Expand All @@ -63,6 +63,8 @@ def read_granule(FILENAME, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -230,6 +232,8 @@ def find_beams(FILENAME, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -280,6 +284,8 @@ def read_beam(FILENAME, gtx, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down
16 changes: 11 additions & 5 deletions icesat2_toolkit/io/ATL10.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
u"""
ATL10.py (03/2024)
ATL10.py (05/2024)
Read ICESat-2 ATL10 (Sea Ice Freeboard) data files
PYTHON DEPENDENCIES:
Expand All @@ -11,6 +11,8 @@
https://www.h5py.org/
UPDATE HISTORY:
Updated 05/2024: use wrapper to importlib for optional dependencies
check if input filename is an open HDF5 file object
Updated 03/2024: use pathlib to define and operate on paths
Updated 11/2023: drop DIMENSION_LIST, CLASS and NAME attributes
Updated 05/2023: extract more ancillary data from ATL10 files
Expand All @@ -27,12 +29,10 @@
import pathlib
import warnings
import numpy as np
from icesat2_toolkit.utilities import import_dependency

# attempt imports
try:
import h5py
except ModuleNotFoundError:
warnings.warn("h5py not available", ImportWarning)
h5py = import_dependency('h5py')

# PURPOSE: read ICESat-2 ATL10 HDF5 data files
def read_granule(FILENAME, ATTRIBUTES=False, **kwargs):
Expand All @@ -58,6 +58,8 @@ def read_granule(FILENAME, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -228,6 +230,8 @@ def find_beams(FILENAME, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down Expand Up @@ -279,6 +283,8 @@ def read_beam(FILENAME, gtx, ATTRIBUTES=False, **kwargs):
# Open the HDF5 file for reading
if isinstance(FILENAME, io.IOBase):
fileID = h5py.File(FILENAME, 'r')
elif isinstance(FILENAME, h5py.File):
fileID = FILENAME
else:
FILENAME = pathlib.Path(FILENAME).expanduser().absolute()
fileID = h5py.File(FILENAME, 'r')
Expand Down
Loading

0 comments on commit cb43fd0

Please sign in to comment.