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 Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ ENV PATH=/opt/conda/bin:${PATH}
ARG MINTPY_HOME=/home/mambauser/tools/MintPy
COPY --chown=mambauser:mambauser . ${MINTPY_HOME}/

ARG PYTHON_VERSION="3.9"
ARG PYTHON_VERSION="3.11"
RUN micromamba install -y -n base -c conda-forge python=${PYTHON_VERSION} \
jupyterlab ipympl gdal">=3" isce2 -f ${MINTPY_HOME}/requirements.txt && \
python -m pip install --no-cache-dir ${MINTPY_HOME} && \
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Language](https://img.shields.io/badge/python-3.8%2B-blue.svg?style=flat-square)](https://www.python.org/)
[![Language](https://img.shields.io/badge/python-3.10%2B-blue.svg?style=flat-square)](https://www.python.org/)
[![Docs Status](https://readthedocs.org/projects/mintpy/badge/?version=latest&style=flat-square)](https://mintpy.readthedocs.io/?badge=latest)
[![CircleCI](https://img.shields.io/circleci/build/github/insarlab/MintPy.svg?logo=circleci&label=tests&style=flat-square)](https://circleci.com/gh/insarlab/MintPy)
[![Docker Status](https://img.shields.io/github/actions/workflow/status/insarlab/MintPy/build-docker.yml?label=docker&style=flat-square&logo=docker&logoColor=white)](https://github.com/insarlab/MintPy/pkgs/container/mintpy)
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Issues = "https://github.com/insarlab/MintPy/issues"
"timeseries2velocity.py" = "mintpy.cli.timeseries2velocity:main"
"timeseries_rms.py" = "mintpy.cli.timeseries_rms:main"
"tropo_gacos.py" = "mintpy.cli.tropo_gacos:main"
"tropo_opera.py" = "mintpy.cli.tropo_opera:main"
"tropo_phase_elevation.py" = "mintpy.cli.tropo_phase_elevation:main"
"tropo_pyaps3.py" = "mintpy.cli.tropo_pyaps3:main"
"tsview.py" = "mintpy.cli.tsview:main"
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pip
argcomplete
asf_search>=12.0.0
cartopy
cvxopt
dask>=1.0
dask-jobqueue>=0.3
fsspec[http]
h5py
joblib
lxml
Expand Down
8 changes: 8 additions & 0 deletions src/mintpy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,13 @@ def get_tropo_gacos_parser(subparsers=None):
return parser


def get_tropo_opera_parser(subparsers=None):
from mintpy.cli import tropo_opera
parser = tropo_opera.create_parser(subparsers)
parser.set_defaults(func=tropo_opera.main)
return parser


def get_tropo_phase_elevation_parser(subparsers=None):
from mintpy.cli import tropo_phase_elevation
parser = tropo_phase_elevation.create_parser(subparsers)
Expand Down Expand Up @@ -629,6 +636,7 @@ def get_parser():
get_s1ab_range_bias_parser(sp)
get_solid_earth_tides_parser(sp)
get_tropo_gacos_parser(sp)
get_tropo_opera_parser(sp)
get_tropo_phase_elevation_parser(sp)
get_tropo_pyaps3_parser(sp)
get_unwrap_error_bridging_parser(sp)
Expand Down
110 changes: 110 additions & 0 deletions src/mintpy/cli/tropo_opera.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env python3
############################################################
# Program is part of MintPy #
# Copyright (c) 2013, Zhang Yunjun, Heresh Fattahi #
# Author: David Bekaert, March 2026 #
############################################################


import os
import sys

from mintpy.utils.arg_utils import create_argument_parser

############################################################################
REFERENCE = """references:
Bekaert, D. et al., OPERA L4 Tropospheric Zenith Delay products
derived from ECMWF HRES model (https://www.earthdata.nasa.gov/data/catalog/asf-opera-l4-tropo-zenith-v1-1).
"""

DIR_DEMO = """--dir ./OPERA
Path to the directory for downloading and storing OPERA tropospheric delay
products. Files are automatically downloaded from ASF on demand.
"""

EXAMPLE = """example:
tropo_opera.py -f timeseries.h5 -g inputs/geometryRadar.h5 --dir ./OPERA
tropo_opera.py -f geo/geo_timeseries.h5 -g geo/geo_geometryRadar.h5 --dir ./OPERA
"""


def create_parser(subparsers=None):
synopsis = 'Tropospheric correction using OPERA Zenith Tropospheric Delays from ECMWF HRES data (https://www.earthdata.nasa.gov/data/catalog/asf-opera-l4-tropo-zenith-v1-1)'
epilog = REFERENCE + '\n' + DIR_DEMO + '\n' + EXAMPLE
name = __name__.split('.')[-1]
parser = create_argument_parser(
name, synopsis=synopsis, description=synopsis, epilog=epilog, subparsers=subparsers)
parser.add_argument('-f', '--file', dest='dis_file', required=True,
help='timeseries HDF5 file, i.e. timeseries.h5')
parser.add_argument('-g', '--geom', dest='geom_file', required=True,
help='geometry file.')
parser.add_argument('--dir','--opera-dir', dest='opera_dir', default='./OPERA',
help='directory to store downloaded OPERA delays data (default: %(default)s).')
parser.add_argument('-o', dest='cor_dis_file',
help='Output file name for tropospheric corrected timeseries.')

return parser


def cmd_line_parse(iargs=None):
"""Command line parser."""
# parse
parser = create_parser()
inps = parser.parse_args(args=iargs)

# import
from mintpy.utils import readfile

# check: --opera-dir (use absolute path)
inps.opera_dir = os.path.abspath(inps.opera_dir)
print('Use OPERA products at directory:', inps.opera_dir)

# check: exsitence of input files
for fname in [inps.dis_file, inps.geom_file]:
if fname and not os.path.isfile(fname):
raise FileNotFoundError(f'input file not exist: {fname}')

# check: processors & coordinates of input files
atr1 = readfile.read_attribute(inps.dis_file)
atr2 = readfile.read_attribute(inps.geom_file)
coord1 = 'geo' if 'Y_FIRST' in atr1.keys() else 'radar'
coord2 = 'geo' if 'Y_FIRST' in atr2.keys() else 'radar'
proc = atr1.get('PROCESSOR', 'isce')

# check: radar-coord product from gamma and roipac is not supported
if coord1 == 'radar' and proc in ['gamma', 'roipac']:
msg = f'Radar-coded file from {proc} is NOT supported!'
msg += '\n Try to geocode the time-series and geometry files and re-run with them instead.'
raise ValueError(msg)

# check: coordinate system must be consistent btw. displacement and geometry files
if coord1 != coord2:
n = max(len(os.path.basename(i)) for i in [inps.dis_file, inps.geom_file])
msg = 'Input time-series and geometry file are NOT in the same coordinate!'
msg += f'\n file {os.path.basename(inps.dis_file):<{n}} coordinate: {coord1}'
msg += f'\n file {os.path.basename(inps.geom_file):<{n}} coordinate: {coord2}'
raise ValueError(msg)

# default: output tropo and corrected displacement file names
inps.tropo_file = os.path.join(os.path.dirname(inps.geom_file), 'OPERA.h5')
if not inps.cor_dis_file:
inps.cor_dis_file = inps.dis_file.split('.')[0] + '_OPERA.h5'

return inps


############################################################################
def main(iargs=None):
# parse
inps = cmd_line_parse(iargs)

# import
from mintpy.tropo_opera import run_tropo_opera

# run
run_tropo_opera(inps)


############################################################################
if __name__ == '__main__':
main(sys.argv[1:])
7 changes: 6 additions & 1 deletion src/mintpy/defaults/smallbaselineApp.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ mintpy.ionosphericDelay.excludeDate12 = auto #[20080520_20090817 / no], auto fo
## NARR - NARR from NOAA [need to install PyAPS from Caltech/EarthDef; recommended for N America]
## c. gacos - use GACOS with the iterative tropospheric decomposition model (Yu et al., 2018, JGR)
## need to manually download GACOS products at http://www.gacos.net for all acquisitions before running this step
mintpy.troposphericDelay.method = auto #[pyaps / height_correlation / gacos / no], auto for pyaps
## d. opera - use OPERA L4 tropospheric zenith delay products
mintpy.troposphericDelay.method = auto #[pyaps / height_correlation / gacos / opera / no], auto for pyaps

## Notes for pyaps:
## a. GAM data latency: with the most recent SAR data, there will be GAM data missing, the correction
Expand All @@ -249,6 +250,10 @@ mintpy.troposphericDelay.minCorrelation = auto #[0.0-1.0], auto for 0
## Set the path below to directory that contains the downloaded *.ztd* files
mintpy.troposphericDelay.gacosDir = auto # [path2directory], auto for "./GACOS"

## Notes for opera:
## Set the path below to directory that contains downloaded OPERA *.nc files
mintpy.troposphericDelay.operaDir = auto # [path2directory], auto for "./OPERA"


########## 9. deramp (optional)
## Estimate and remove a phase ramp for each acquisition based on the reliable pixels.
Expand Down
3 changes: 3 additions & 0 deletions src/mintpy/defaults/smallbaselineApp_auto.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ mintpy.troposphericDelay.minCorrelation = 0
## gacos
mintpy.troposphericDelay.gacosDir = ./GACOS

## opera
mintpy.troposphericDelay.operaDir = ./OPERA


########## deramp
mintpy.deramp = no
Expand Down
13 changes: 13 additions & 0 deletions src/mintpy/smallbaselineApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,9 @@ def get_timeseries_filename(template, work_dir='./'):
elif method == 'gacos':
fname1 = f'{os.path.splitext(fname0)[0]}_GACOS.h5'

elif method == 'opera':
fname1 = f'{os.path.splitext(fname0)[0]}_OPERA.h5'

elif method == 'pyaps':
fname1 = f'{os.path.splitext(fname0)[0]}_{model}.h5'

Expand Down Expand Up @@ -648,6 +651,16 @@ def get_dataset_size(fname):
import mintpy.cli.tropo_phase_elevation
mintpy.cli.tropo_phase_elevation.main(iargs)

# OPERA ZTD products derived from ECMWF HRES data and available through the ASF DAAC
elif method == 'opera':
opera_dir = self.template['mintpy.troposphericDelay.operaDir']
iargs = ['-f', in_file, '-g', geom_file, '-o', out_file, '--dir', opera_dir]
print('tropospheric delay correction with OPERA ZTD products')
print('\ntropo_opera.py', ' '.join(iargs))
if ut.run_or_skip(out_file=out_file, in_file=in_file) == 'run':
import mintpy.cli.tropo_opera
mintpy.cli.tropo_opera.main(iargs)

# Weather re-analysis data with iterative tropospheric decomposition (GACOS)
# Yu et al. (2018, JGR)
elif method == 'gacos':
Expand Down
Loading