Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ on:
jobs:
call-changelog-check-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-changelog-check.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-changelog-check.yml@v0.20.0
2 changes: 1 addition & 1 deletion .github/workflows/labeled-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ on:
jobs:
call-labeled-pr-check-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-labeled-pr-check.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-labeled-pr-check.yml@v0.20.0
2 changes: 1 addition & 1 deletion .github/workflows/release-checklist-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ on:
jobs:
call-release-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-release-checklist-comment.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-release-checklist-comment.yml@v0.20.0
permissions:
pull-requests: write
secrets:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
call-release-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-release.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-release.yml@v0.20.0
with:
release_prefix: MultiRTC
release_branch: main
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ on: push
jobs:
call-secrets-analysis-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-secrets-analysis.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-secrets-analysis.yml@v0.20.0

call-ruff-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-ruff.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-ruff.yml@v0.20.0
2 changes: 1 addition & 1 deletion .github/workflows/tag-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
call-bump-version-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-bump-version.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-bump-version.yml@v0.20.0
with:
user: forrest-bot
email: ffwilliams2@alaska.edu
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-and-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ on:
jobs:
call-pytest-workflow:
# Docs: https://github.com/ASFHyP3/actions
uses: ASFHyP3/actions/.github/workflows/reusable-pytest.yml@v0.18.1
uses: ASFHyP3/actions/.github/workflows/reusable-pytest.yml@v0.20.0
with:
local_package_name: mulitrtc
python_versions: >-
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,5 @@ Sessionx.vim
tags
# Persistent undo
[._]*.un~
# Data
ale
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [PEP 440](https://www.python.org/dev/peps/pep-0440/)
and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.0]

### Added
* Support for Capella SICD SLC products

## [0.1.1]

### Added
Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
# MultiRTC

A python library for creating ISCE3-based RTCs from Sentinel-1 Burst and Umbra SICD SLC data.
A python library for creating ISCE3-based RTCs for multiple SAR data sources

**ALL CREDIT FOR THIS LIBRARY'S RTC ALGORITHM GOES TO GUSTAVO SHIROMA AND THE [JPL OPERA TEAM](https://www.jpl.nasa.gov/go/opera). THIS PLUGIN MERELY ALLOWS OTHERS TO USE THEIR ALGORITHM WITH MULTIPLE SENSORS.**
**ALL CREDIT FOR THIS LIBRARY'S RTC ALGORITHM GOES TO GUSTAVO SHIROMA AND THE JPL [OPERA](https://www.jpl.nasa.gov/go/opera/about-opera/) AND [ISCE3](https://github.com/isce-framework/isce3) TEAMS. THIS PLUGIN MERELY ALLOWS OTHERS TO USE THEIR ALGORITHM WITH MULTIPLE SENSORS.**

The RTC algorithm utilized by this library is described in [Shiroma et al., 2023](https://doi.org/10.1109/TGRS.2022.3147472).

## Usage
MultiRTC allows users to create RTC products from SLC data for multiple SAR sensor platforms. Currently this list includes:

- [Sentinel-1 burst SLCs](https://www.earthdata.nasa.gov/data/catalog/alaska-satellite-facility-distributed-active-archive-center-sentinel-1-bursts-version)
Full RTC:
- [Sentinel-1 Burst SLCs](https://www.earthdata.nasa.gov/data/catalog/alaska-satellite-facility-distributed-active-archive-center-sentinel-1-bursts-version)
- [Capella SICD SLCs](https://www.capellaspace.com/earth-observation/data)

Geocode Only:
- [UMBRA SICD SLCs](https://help.umbra.space/product-guide/umbra-products/umbra-product-specifications)

To create an RTC, use the `multirtc` CLI entrypoint using the following pattern:

```bash
multirtc PLATFORM SLC-GRANULE --resolution RESOLUTION --work-dir WORK-DIR
```
Where `PLATFORM` is the name of the satellite platform (currently `S1` or `UMBRA`), `SLC-GRANULE` is the name of the SLC granule, `RESOLUTION` is the desired output resolution of the RTC image in meters, and `WORK-DIR` is the name of the working directory to perform processing in. Inputs such as the SLC data, DEM, and external orbit information are stored in `WORK-DIR/input`, while the RTC image and associated outputs are stored in `WORK-DIR/output` once processing is complete. SLC data that is available in the [Alaska Satellite Facility's data archive](https://search.asf.alaska.edu/#/?maxResults=250) (such as Sentinel-1 burst SLCs) will be automatically downloaded to the input directory, but data not available in this archive (Umbra SICD SLCs) are required to be staged in the input directory prior to processing.
Where `PLATFORM` is the name of the satellite platform (currently `S1`, `CAPELLA` or `UMBRA`), `SLC-GRANULE` is the name of the SLC granule, `RESOLUTION` is the desired output resolution of the RTC image in meters, and `WORK-DIR` is the name of the working directory to perform processing in. Inputs such as the SLC data, DEM, and external orbit information are stored in `WORK-DIR/input`, while the RTC image and associated outputs are stored in `WORK-DIR/output` once processing is complete. SLC data that is available in the [Alaska Satellite Facility's data archive](https://search.asf.alaska.edu/#/?maxResults=250) (such as Sentinel-1 Burst SLCs) will be automatically downloaded to the input directory, but data not available in this archive (commercial datasets) are required to be staged in the input directory prior to processing.

Output RTC products are in Gamma0 radiometry.

### Current Umbra Implementation
Currently, the Umbra processor only supports basic geocoding and not full RTC processing. ISCE3's RTC algorithm is only designed to work with Range Migration Algorithm (RMA) focused SLC products, but Umbra creates their data using the Polar Format Algorithm (PFA). Using an [approach detailed by Piyush Agram](https://arxiv.org/abs/2503.07889v1) to adapt RMA approaches to the PFA image geometry, we have developed a workflow to geocode an Umbra SLC but there is more work to be done to implement full RTC processing. Since full RTC is not yet implemented, Umbra geocoded products are in Sigma0 radiometry.

### DEM options
Currently, only the NISAR DEM is supported. This is a roughly global Height Above Ellipsoid DEM sourced from the [COP-30 DEM](https://portal.opentopography.org/raster?opentopoID=OTSDEM.032021.4326.3). In the future, we hope to support a wider variety of automatically retrieved and user provided DEMs.
Currently, only the OPERA DEM is supported. This is a global Height Above Ellipsoid DEM sourced from the [COP-30 DEM](https://portal.opentopography.org/raster?opentopoID=OTSDEM.032021.4326.3). In the future, we hope to support a wider variety of automatically retrieved and user provided DEMs.

## Developer Setup
1. Ensure that conda is installed on your system (we recommend using [mambaforge](https://github.com/conda-forge/miniforge#mambaforge) to reduce setup times).
Expand Down
58 changes: 58 additions & 0 deletions src/multirtc/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from abc import ABC
from datetime import datetime
from pathlib import Path

import isce3
import numpy as np
from shapely.geometry import Point, Polygon


def to_isce_datetime(dt):
if isinstance(dt, datetime):
return isce3.core.DateTime(dt)
elif isinstance(dt, np.datetime64):
return isce3.core.DateTime(dt.item())
else:
raise ValueError(f'Unsupported datetime type: {type(dt)}. Expected datetime or np.datetime64.')


def from_isce_datetime(dt):
return datetime.fromisoformat(dt.isoformat())


class SlcTemplate(ABC):
required_attributes = {
'id': str,
'filepath': Path,
'footprint': Polygon,
'center': Point,
'lookside': str, # 'right' or 'left'
'wavelength': float,
'polarization': str,
'shape': tuple,
'range_pixel_spacing': float,
'reference_time': datetime,
'sensing_start': float,
'prf': float,
'orbit': object, # Replace with actual orbit type
'radar_grid': object, # Replace with actual radar grid type
'doppler_centroid_grid': object, # Replace with actual doppler centroid grid type
}

# I prefer this setup to enforce properties over forcing subclasses to have a bunch of @property statements
def __init_subclass__(cls):
super().__init_subclass__()
original_init = cls.__init__

def wrapped_init(self, *args, **kwargs):
original_init(self, *args, **kwargs)
for attr, expected_type in cls.required_attributes.items():
if not hasattr(self, attr):
raise NotImplementedError(f'{cls.__name__} must define self.{attr}')
if not isinstance(getattr(self, attr), expected_type):
raise TypeError(
f'{cls.__name__}.{attr} must be of type {expected_type.__name__},'
f'got {type(getattr(self, attr)).__name__}'
)

cls.__init__ = wrapped_init
Loading