Skip to content

Commit

Permalink
Replace Orbit.load_from_h5 binding with pure Python "load_orbit_from_…
Browse files Browse the repository at this point in the history
…h5_group" (#1318)

* Migrate orbit deserialization to pure Python

* Replace all usage of Orbit.load_from_h5 with load_orbit_from_h5_group

* Add docstring to Orbit.set_interp_method

* Add docstring to load_orbit_from_h5_group

* Factor ISO date parsing to separate function

* Use public isce3.core imports
  • Loading branch information
Ryan T Burns authored and GitHub Enterprise committed May 25, 2023
1 parent a9ba4ac commit a3d49bf
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 6 deletions.
19 changes: 19 additions & 0 deletions python/extensions/pybind_isce3/core/Orbit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,24 @@ void addbinding(py::class_<Orbit> & pyOrbit)
isce3.core.Orbit
Orbit object with data containing start & end times)",
py::arg("start"), py::arg("end"), py::arg("npad") = 0)
.def("set_interp_method", [](Orbit& self, const std::string& method) {
if (method == "Hermite") {
self.interpMethod(OrbitInterpMethod::Hermite);
} else if (method == "Legendre") {
self.interpMethod(OrbitInterpMethod::Legendre);
} else {
throw std::invalid_argument("unexpected orbit interpolation method '" + method + "'");
}
}, R"(
Set interpolation method.
Parameters
----------
method : {'Hermite', 'Legendre'}
The method for interpolating orbit state vectors (cubic
Hermite spline interpolation or eighth-order Legendre
polynomial interpolation).
)",
py::arg("method"))
;
}
1 change: 1 addition & 0 deletions python/packages/isce3/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
from .poly2d import fit_bivariate_polynomial
from . import rdr_geo_block_generator
from .block_param_generator import BlockParam
from .serialization import load_orbit_from_h5_group
69 changes: 69 additions & 0 deletions python/packages/isce3/core/serialization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from __future__ import annotations
from isce3.core import DateTime, Orbit, StateVector, TimeDelta
import h5py

def parse_iso_date(iso_date: str) -> DateTime:
"""
Parse ISO date string to DateTime
This is a direct translation from C++ code in isce3,
and could probably be made more robust/intuitive.
"""
utc_ref = ""
pos_iso = iso_date.rfind('-')
if pos_iso != -1:
utc_ref = iso_date[pos_iso - 7:]
# remove any trailing whitespace
utc_ref = utc_ref.rstrip(' ')
return DateTime(utc_ref)

def load_orbit_from_h5_group(group: h5py.Group) -> Orbit:
"""
Load orbit data from a group in an HDF5 file.
The organization of orbit data in the group is assumed to conform to
NISAR product specifications.
Parameters
----------
group : h5py.Group
The HDF5 group containing the orbit metadata.
Returns
-------
orbit : Orbit
The orbit data.
"""
time = group['time']
pos = group['position']
vel = group['velocity']

if time.ndim != 1 or pos.ndim != 2 or vel.ndim != 2:
raise ValueError("unexpected orbit state vector dims")

if pos.shape[1] != 3 or vel.shape[1] != 3:
raise ValueError("unexpected orbit position/velocity vector size")

size = time.shape[0];
if pos.shape[0] != size or vel.shape[0] != size:
raise ValueError("mismatched orbit state vector component sizes")

# get reference epoch
unit_attr = time.attrs['units']
# result may be str or bytes, convert to str if needed
if type(unit_attr) is not str:
unit_attr = unit_attr.decode('utf-8')
epoch = parse_iso_date(unit_attr)

# convert to state vectors
statevecs = [StateVector(epoch + TimeDelta(time[i]), pos[i], vel[i])
for i in range(size)]

# construct Orbit object
result = Orbit(statevecs, epoch)

# set interpolation method, if specified
if 'interpMethod' in group.keys():
result.set_interp_method(group['interpMethod'][()])

return result
2 changes: 1 addition & 1 deletion python/packages/nisar/products/readers/Base/Base.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def getOrbit(self):
'''
with h5py.File(self.filename, 'r', libver='latest', swmr=True) as fid:
orbitPath = os.path.join(self.MetadataPath, 'orbit')
return isce3.core.Orbit.load_from_h5(fid[orbitPath])
return isce3.core.load_orbit_from_h5_group(fid[orbitPath])

@pyre.export
def getAttitude(self):
Expand Down
2 changes: 1 addition & 1 deletion python/packages/nisar/products/readers/Raw/Raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def TelemetryPath(self):
def getOrbit(self):
path = f"{self.TelemetryPath}/orbit"
with h5py.File(self.filename, 'r', libver='latest', swmr=True) as f:
orbit = isce3.core.Orbit.load_from_h5(f[path])
orbit = isce3.core.load_orbit_from_h5_group(f[path])
return orbit

def getAttitude(self):
Expand Down
4 changes: 2 additions & 2 deletions tests/python/extensions/pybind/core/orbit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import numpy.testing as npt

def load_h5():
from isce3.ext.isce3.core import Orbit
from isce3.core import load_orbit_from_h5_group
from iscetest import data
from os import path
import h5py
f = h5py.File(path.join(data, "envisat.h5"), 'r')
return Orbit.load_from_h5(f["/science/LSAR/SLC/metadata/orbit"])
return load_orbit_from_h5_group(f["/science/LSAR/SLC/metadata/orbit"])

o = load_h5();

Expand Down
3 changes: 2 additions & 1 deletion tests/python/extensions/pybind/focus/backproject.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import numpy as np
import numpy.testing as npt
import isce3.ext.isce3 as isce
from isce3.core import load_orbit_from_h5_group
from iscetest import data as test_data_dir
from pathlib import Path
import json
Expand All @@ -20,7 +21,7 @@ def load_h5(filename):
signal_data = f["data"][()]

# load orbit
orbit = isce.core.Orbit.load_from_h5(f["orbit"])
orbit = load_orbit_from_h5_group(f["orbit"])

# load Doppler
doppler = isce.core.LUT2d.load_from_h5(f["doppler"], "doppler")
Expand Down
3 changes: 2 additions & 1 deletion tests/python/extensions/pybind/geometry/bbox.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import iscetest
import pathlib
import isce3.ext.isce3 as isce
from isce3.core import load_orbit_from_h5_group
from nisar.products.readers import SLC


Expand All @@ -11,7 +12,7 @@ def load_orbit():
import h5py
with h5py.File(path_slc, "r") as h5:
g = h5["/science/LSAR/SLC/metadata/orbit"]
orbit = isce.core.Orbit.load_from_h5(g)
orbit = load_orbit_from_h5_group(g)
return orbit


Expand Down

0 comments on commit a3d49bf

Please sign in to comment.