Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
jobs:
deploy:

runs-on: ubuntu-20.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion doc/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: icesat2-docs
channels:
- conda-forge
dependencies:
- docutils<0.18
- docutils
- fontconfig
- freetype
- future
Expand Down
6 changes: 3 additions & 3 deletions doc/make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ if "%SPHINXBUILD%" == "" (
set SOURCEDIR=source
set BUILDDIR=build

if "%1" == "" goto help

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
Expand All @@ -21,10 +19,12 @@ if errorlevel 9009 (
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
echo.https://www.sphinx-doc.org/
exit /b 1
)

if "%1" == "" goto help

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

Expand Down
Binary file modified doc/source/_assets/ASAS_product_chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 37 additions & 34 deletions doc/source/_assets/ASAS_product_chart.tex
Original file line number Diff line number Diff line change
Expand Up @@ -56,49 +56,51 @@
\node (ppd)[ext, below of=atl02, xshift=-1cm]{\textbf{PPD}};
\node (pod)[ext, below of=atl02, xshift=1cm]{\textbf{POD}};
% Level 2 products
\node (atl03)[l2, below of=ppd, xshift=1cm]{\textbf{ATL03}\\Geolocated\\Photons};
\node (atl03)[l2, below of=ppd, xshift=1cm]{\textbf{ATL03 (+QL)}\\Geolocated\\Photons};
\node (atl04)[l2, right of=atl02, xshift=3.5cm]{\textbf{ATL04}\\Normalized\\Backscatter\\Profiles};
% connection coordinates for single arrow out of ATL03
\node(A)[shape=coordinate, below=0.5cm of atl03] {};
\node (B)[shape=coordinate, left=1.375cm of A] {};
\node (C)[shape=coordinate, left=2.75cm of B] {};
\node (D)[shape=coordinate, left=2.75cm of C] {};
\node (E)[shape=coordinate, right=1.375cm of A] {};
\node (F)[shape=coordinate, right=2.75cm of E] {};
\node (E)[shape=coordinate, left=3.00cm of D] {};
\node (F)[shape=coordinate, right=1.375cm of A] {};
\node (G)[shape=coordinate, right=2.75cm of F] {};
\node (H)[shape=coordinate, right=2.75cm of G] {};
\node (I)[shape=coordinate, right=2.75cm of H] {};
% Level 3a products
\node (atl06)[l3a, below=0.5cm of D]{\textbf{ATL06}\\Land Ice\\Height};
\node (atl07)[l3a, below=0.5cm of C]{\textbf{ATL07}\\Sea Ice\\Height};
\node (atl10)[l3a, below=0.5cm of B]{\textbf{ATL10}\\Sea Ice\\Freeboard};
\node (atl08)[l3a, below=0.5cm of E]{\textbf{ATL08}\\Land/Vegetation\\Height};
\node (atl10)[l3a, below=0.5cm of E]{\textbf{ATL10 (+QL)}\\Sea Ice\\Freeboard};
\node (atl07)[l3a, below=0.5cm of D]{\textbf{ATL07 (+QL)}\\Sea Ice\\Height};
\node (atl06)[l3a, below=0.5cm of C]{\textbf{ATL06}\\Land Ice\\Height};
\node (atl08)[l3a, below=0.5cm of B]{\textbf{ATL08 (+QL)}\\Land/Vegetation\\Height};
\node (atl12)[l3a, below=0.5cm of F]{\textbf{ATL12}\\Ocean Surface\\Height};
\node (atl13)[l3a, below=0.5cm of G]{\textbf{ATL13}\\Inland Water\\Height};
\node (atl13)[l3a, below=0.5cm of G]{\textbf{ATL13 (+QL)}\\Inland Surface\\Water Data};
\node (atl24)[l3a, dashed, below=0.5cm of H]{\textbf{ATL24}\\Bathymetric\\Elevation};
\node (atl09)[l3a, right of=atl03, xshift=3.5cm]{\textbf{ATL09}\\Calibrated\\Backscatter\\Profiles};
\node (atl25)[l3a, dashed, below=0.5cm of I]{\textbf{ATL25}\\Lake Ice\\Height};
\node (atl09)[l3a, right of=atl03, xshift=3.5cm]{\textbf{ATL09 (+QL)}\\Calibrated\\Backscatter\\Profiles};
% connection coordinates for single arrow out of ATL09
\node (I)[shape=coordinate, below=0.5cm of atl09] {};
\node (J)[shape=coordinate, right=5.5cm of atl09] {};
\node (J)[shape=coordinate, below=0.5cm of atl09] {};
\node (K)[shape=coordinate, right=5.5cm of atl09] {};
% Level 3b products
\node (atl11)[l3b, below=0.5cm of atl06]{\textbf{ATL11}\\Land Ice Height\\Time Series};
\node (atl14)[l3b, below=0.5cm of atl11, xshift=-3cm]{\textbf{ATL14}\\Gridded Land\\ Ice Height};
\node (atl15)[l3b, below=0.5cm of atl11, xshift=0cm]{\textbf{ATL15}\\Gridded Land\\ Ice Height Change};
\node (atl14)[l3b, below=0.5cm of atl11, xshift=-1.5cm]{\textbf{ATL14}\\Gridded Land\\ Ice Height};
\node (atl15)[l3b, below=0.5cm of atl11, xshift=1.5cm]{\textbf{ATL15}\\Gridded Land\\ Ice Height Change};
\node (atl20)[l3b, below=0.5cm of atl10, xshift=-1.5cm]{\textbf{ATL20}\\Gridded Sea\\ Ice Freeboard};
\node (atl21)[l3b, below=0.5cm of atl20, xshift=0cm]{\textbf{ATL21}\\Gridded Polar Sea\\ Surface Height};
\node (atl21)[l3b, below=0.5cm of atl10, xshift=1.5cm]{\textbf{ATL21}\\Gridded Polar Sea\\ Surface Height};
\node (atl18)[l3b, dashed, below=0.5cm of atl08, xshift=0cm]{\textbf{ATL18}\\Gridded Land\\ and Vegetation\\Height};
\node (atl19)[l3b, below=0.5cm of atl12]{\textbf{ATL19}\\Gridded Ocean\\Topography};
\node (atl23)[l3b, dashed, below=0.5cm of atl19]{\textbf{ATL23}\\3-Month Gridded\\Ocean Topography};
\node (atl22)[l3b, below=0.5cm of atl13]{\textbf{ATL22}\\Mean Inland\\Water Height};
\node (atl16)[l3b, below=4.65cm of J]{\textbf{ATL16}\\Weekly Gridded\\Atmosphere};
\node (atl23)[l3b, below=0.5cm of atl19]{\textbf{ATL23}\\3-Month Gridded\\Ocean Topography};
\node (atl22)[l3b, below=0.5cm of atl13]{\textbf{ATL22}\\Mean Inland\\ Water Data};
\node (atl16)[l3b, below=4.65cm of K]{\textbf{ATL16}\\Weekly Gridded\\Atmosphere};
\node (atl17)[l3b, below=0.5cm of atl16]{\textbf{ATL17}\\Monthly Gridded\\Atmosphere};
% Legend
\node (legend)[right=16cm of atl00, yshift=1cm, minimum height=0cm, minimum width=2.75cm]{\textbf{Legend}};
\node (level0)[l0, below=-0.1cm of legend, minimum height=0.75cm, minimum width=2.75cm]{\textbf{Level 0}};
\node (level1)[l1, below=0.1cm of level0, minimum height=0.75cm, minimum width=2.75cm]{\textbf{Level 1}};
\node (level2)[l2, below=0.1cm of level1, minimum height=0.75cm, minimum width=2.75cm]{\textbf{Level 2}};
\node (level3a)[l3a, below=0.1cm of level2, minimum height=0.75cm, minimum width=2.75cm]{\textbf{Level 3a}};
\node (level3b)[l3b, below=0.1cm of level3a, minimum height=0.75cm, minimum width=2.75cm]{\textbf{Level 3b}};
\node (extern)[ext, below=0.1cm of level3b, minimum height=0.75cm, minimum width=2.75cm]{\textbf{External}};
\node (legend)[right=16cm of atl00, yshift=1cm, minimum height=0cm, minimum width=3cm]{\textbf{Legend}};
\node (level0)[l0, below=-0.1cm of legend, minimum height=0.75cm, minimum width=3cm]{\textbf{Level 0}};
\node (level1)[l1, below=0.1cm of level0, minimum height=0.75cm, minimum width=3cm]{\textbf{Level 1}};
\node (level2)[l2, below=0.1cm of level1, minimum height=0.75cm, minimum width=3cm]{\textbf{Level 2}};
\node (level3a)[l3a, below=0.1cm of level2, minimum height=0.75cm, minimum width=3cm]{\textbf{Level 3a}};
\node (level3b)[l3b, below=0.1cm of level3a, minimum height=0.75cm, minimum width=3cm]{\textbf{Level 3b}};
\node (extern)[ext, below=0.1cm of level3b, minimum height=0.75cm, minimum width=3cm]{\textbf{External}};
% draw arrows between nodes
\draw[line width=0.3mm,-Latex](atl00) -- (atl01);
\draw[line width=0.3mm,-Latex](atl01) -- (atl02);
Expand All @@ -110,24 +112,25 @@
\draw[line width=0.3mm,-Latex](atl02) -- (atl04);
\draw[line width=0.3mm,-Latex](atl04) -- (atl09);
\draw[line width=0.3mm,-](atl03.south) -- (A.north);
\draw[line width=0.3mm,-](atl09.south) -- (I.north);
\draw[line width=0.3mm,-](atl09.east) -- (J.west);
\draw[line width=0.3mm,-](atl09.south) -- (J.north);
\draw[line width=0.3mm,-](atl09.east) -- (K.west);
\draw[line width=0.3mm,-](A.west) -- (D.east);
\draw[line width=0.3mm,-](A.east) -- (H.west);
\draw[line width=0.3mm,-Latex](D.south) -- (atl06.north);
\draw[line width=0.3mm,-Latex](C.south) -- (atl07.north);
\draw[line width=0.3mm,-Latex](B.south) -- (atl10.north);
\draw[line width=0.3mm,-Latex](E.south) -- (atl08.north);
\draw[line width=0.3mm,-](A.east) -- (I.west);
% \draw[line width=0.3mm,-Latex](E.south) -- (atl10.north);
\draw[line width=0.3mm,-Latex](D.south) -- (atl07.north);
\draw[line width=0.3mm,-Latex](C.south) -- (atl06.north);
\draw[line width=0.3mm,-Latex](B.south) -- (atl08.north);
\draw[line width=0.3mm,-Latex](F.south) -- (atl12.north);
\draw[line width=0.3mm,-Latex](G.south) -- (atl13.north);
\draw[line width=0.3mm,-Latex](H.south) -- (atl24.north);
\draw[line width=0.3mm,-Latex](J.south) -- (atl16.north);
\draw[line width=0.3mm,-Latex](I.south) -- (atl25.north);
\draw[line width=0.3mm,-Latex](K.south) -- (atl16.north);
\draw[line width=0.3mm,-Latex](atl06) -- (atl11);
\draw[line width=0.3mm,-Latex](atl11) -- (atl14);
\draw[line width=0.3mm,-Latex](atl11) -- (atl15);
\draw[line width=0.3mm,-Latex](atl07) -- (atl20);
\draw[line width=0.3mm,-Latex](atl07) -- (atl10);
\draw[line width=0.3mm,-Latex](atl10) -- (atl20);
\draw[line width=0.3mm,-Latex](atl20) -- (atl21);
\draw[line width=0.3mm,-Latex](atl10) -- (atl21);
\draw[line width=0.3mm,-Latex](atl08) -- (atl18);
\draw[line width=0.3mm,-Latex](atl12) -- (atl19);
\draw[line width=0.3mm,-Latex](atl19) -- (atl23);
Expand Down
2 changes: 1 addition & 1 deletion doc/source/api_reference/spatial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ spatial

Utilities for reading and operating on spatial data

- Can read netCDF4, HDF5 or geotiff files
- Can read netCDF4, HDF5, or (cloud optimized) geotiff files

Calling Sequence
================
Expand Down
2 changes: 1 addition & 1 deletion icesat2_toolkit/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ def attributes_encoder(self, attr):
if isinstance(attr, (np.int_, np.intc, np.intp, np.int8, np.int16, np.int32,
np.int64, np.uint8, np.uint16, np.uint32, np.uint64)):
return int(attr)
elif isinstance(attr, (np.float_, np.float16, np.float32, np.float64)):
elif isinstance(attr, (np.float16, np.float32, np.float64)):
return float(attr)
elif isinstance(attr, (np.ndarray)):
if not isinstance(attr[0], (object)):
Expand Down
9 changes: 5 additions & 4 deletions icesat2_toolkit/fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
from icesat2_toolkit.utilities import import_dependency

# attempt imports
neighbors = import_dependency('sklearn.neighbors')
sklearn = import_dependency('sklearn')
sklearn.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 @@ -526,7 +527,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 = neighbors.KernelDensity(bandwidth=dz, kernel='gaussian')
kde = sklearn.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 @@ -654,7 +655,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 = neighbors.KernelDensity(bandwidth=dz,kernel='gaussian')
kde = sklearn.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 @@ -989,7 +990,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 = neighbors.KernelDensity(bandwidth=dt,kernel='gaussian')
kde = sklearn.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
16 changes: 14 additions & 2 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 (05/2024)
ATL03.py (10/2025)
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,7 @@
https://www.h5py.org/

UPDATE HISTORY:
Updated 10/2025: orbit_info group may now contain sub-groups
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
Expand Down Expand Up @@ -166,6 +167,12 @@ def read_granule(FILENAME, ATTRIBUTES=False, KEEP=False, **kwargs):
IS2_atl03_attrs['orbit_info'] = {}
for key,val in fileID['orbit_info'].items():
IS2_atl03_mds['orbit_info'][key] = val[:]
if isinstance(val, h5py.Dataset):
IS2_atl03_mds['orbit_info'][key] = val[:]
elif isinstance(val, h5py.Group):
IS2_atl03_mds['orbit_info'][key] = {}
for k,v in val.items():
IS2_atl03_mds['orbit_info'][key][k] = v[:]
# Getting attributes of group and included variables
if ATTRIBUTES:
# Global Group Attributes
Expand Down Expand Up @@ -463,7 +470,12 @@ def read_main(FILENAME, ATTRIBUTES=False, KEEP=False, **kwargs):
IS2_atl03_mds['orbit_info'] = {}
IS2_atl03_attrs['orbit_info'] = {}
for key,val in fileID['orbit_info'].items():
IS2_atl03_mds['orbit_info'][key] = val[:]
if isinstance(val, h5py.Dataset):
IS2_atl03_mds['orbit_info'][key] = val[:]
elif isinstance(val, h5py.Group):
IS2_atl03_mds['orbit_info'][key] = {}
for k,v in val.items():
IS2_atl03_mds['orbit_info'][key][k] = v[:]
# Getting attributes of group and included variables
if ATTRIBUTES:
# Global Group Attributes
Expand Down
10 changes: 8 additions & 2 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 (05/2024)
ATL06.py (10/2025)
Read ICESat-2 ATL06 (Land Ice Along-Track Height Product) data files

OPTIONS:
Expand All @@ -16,6 +16,7 @@
https://www.h5py.org/

UPDATE HISTORY:
Updated 10/2025: orbit_info group may now contain sub-groups
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
Expand Down Expand Up @@ -191,7 +192,12 @@ def read_granule(FILENAME, ATTRIBUTES=False, HISTOGRAM=False,
# ICESat-2 orbit_info Group
IS2_atl06_mds['orbit_info'] = {}
for key,val in fileID['orbit_info'].items():
IS2_atl06_mds['orbit_info'][key] = val[:]
if isinstance(val, h5py.Dataset):
IS2_atl06_mds['orbit_info'][key] = val[:]
elif isinstance(val, h5py.Group):
IS2_atl06_mds['orbit_info'][key] = {}
for k,v in val.items():
IS2_atl06_mds['orbit_info'][key][k] = v[:]
# ICESat-2 quality_assessment Group
IS2_atl06_mds['quality_assessment'] = {}
for key,val in fileID['quality_assessment'].items():
Expand Down
10 changes: 8 additions & 2 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 (05/2024)
ATL07.py (10/2025)
Read ICESat-2 ATL07 (Sea Ice Height) data files

PYTHON DEPENDENCIES:
Expand All @@ -11,6 +11,7 @@
https://www.h5py.org/

UPDATE HISTORY:
Updated 10/2025: orbit_info group may now contain sub-groups
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
Expand Down Expand Up @@ -135,7 +136,12 @@ def read_granule(FILENAME, ATTRIBUTES=False, KEEP=False, **kwargs):
# ICESat-2 orbit_info Group
IS2_atl07_mds['orbit_info'] = {}
for key,val in fileID['orbit_info'].items():
IS2_atl07_mds['orbit_info'][key] = val[:]
if isinstance(val, h5py.Dataset):
IS2_atl07_mds['orbit_info'][key] = val[:]
elif isinstance(val, h5py.Group):
IS2_atl07_mds['orbit_info'][key] = {}
for k,v in val.items():
IS2_atl07_mds['orbit_info'][key][k] = v[:]
# ICESat-2 quality_assessment Group
IS2_atl07_mds['quality_assessment'] = {}
for key,val in fileID['quality_assessment'].items():
Expand Down
10 changes: 8 additions & 2 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 (05/2024)
ATL10.py (10/2025)
Read ICESat-2 ATL10 (Sea Ice Freeboard) data files

PYTHON DEPENDENCIES:
Expand All @@ -11,6 +11,7 @@
https://www.h5py.org/

UPDATE HISTORY:
Updated 10/2025: orbit_info group may now contain sub-groups
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
Expand Down Expand Up @@ -133,7 +134,12 @@ def read_granule(FILENAME, ATTRIBUTES=False, KEEP=False, **kwargs):
# ICESat-2 orbit_info Group
IS2_atl10_mds['orbit_info'] = {}
for key,val in fileID['orbit_info'].items():
IS2_atl10_mds['orbit_info'][key] = val[:]
if isinstance(val, h5py.Dataset):
IS2_atl10_mds['orbit_info'][key] = val[:]
elif isinstance(val, h5py.Group):
IS2_atl10_mds['orbit_info'][key] = {}
for k,v in val.items():
IS2_atl10_mds['orbit_info'][key][k] = v[:]
# ICESat-2 quality_assessment Group
IS2_atl10_mds['quality_assessment'] = {}
for key,val in fileID['quality_assessment'].items():
Expand Down
10 changes: 8 additions & 2 deletions icesat2_toolkit/io/ATL11.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python
u"""
ATL11.py (05/2024)
ATL11.py (10/2025)
Read ICESat-2 ATL11 (Annual Land Ice Height) data files

OPTIONS:
Expand All @@ -18,6 +18,7 @@
https://www.h5py.org/

UPDATE HISTORY:
Updated 10/2025: orbit_info group may now contain sub-groups
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
Expand Down Expand Up @@ -173,7 +174,12 @@ def read_granule(FILENAME, GROUPS=['cycle_stats'], ATTRIBUTES=False,
# ICESat-2 orbit_info Group
IS2_atl11_mds['orbit_info'] = {}
for key,val in fileID['orbit_info'].items():
IS2_atl11_mds['orbit_info'][key] = val[:]
if isinstance(val, h5py.Dataset):
IS2_atl11_mds['orbit_info'][key] = val[:]
elif isinstance(val, h5py.Group):
IS2_atl11_mds['orbit_info'][key] = {}
for k,v in val.items():
IS2_atl11_mds['orbit_info'][key][k] = v[:]

# ICESat-2 quality_assessment Group
IS2_atl11_mds['quality_assessment'] = {}
Expand Down
Loading
Loading