From a24b68a926a0e0e3acd67dc5048f26f9b0b76fd2 Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Mon, 27 Jun 2022 10:57:39 -0700 Subject: [PATCH 1/4] stackSentinel: fix indentation bug + group argparse + fix the indentation bug in selectNeighborPairsIonosphere() + create more subgroups in createParser() as below for improved readability: - area of interest - dates of interest - coregistration - interferogram formation - phase unwrapping - ionosphere --- contrib/stack/topsStack/stackSentinel.py | 123 ++++++++++++----------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/contrib/stack/topsStack/stackSentinel.py b/contrib/stack/topsStack/stackSentinel.py index 866b2ebf..fc500c5d 100755 --- a/contrib/stack/topsStack/stackSentinel.py +++ b/contrib/stack/topsStack/stackSentinel.py @@ -85,11 +85,12 @@ def __call__(self, parser, args, values, option_string=None): def createParser(): - parser = argparse.ArgumentParser(description='Preparing the directory structure and config files for stack processing of Sentinel data') + parser = argparse.ArgumentParser(description='Preparing the directory structure and config files for stack processing of Sentinel-1 TOPS data') parser.add_argument('-H','--hh', nargs=0, action=customArgparseAction, help='Display detailed help information.') + # input directories parser.add_argument('-s', '--slc_directory', dest='slc_dirname', type=str, required=True, help='Directory with all Sentinel SLCs') @@ -105,77 +106,87 @@ def createParser(): parser.add_argument('-d', '--dem', dest='dem', type=str, required=True, help='Path of the DEM file') - parser.add_argument('-m', '--reference_date', dest='reference_date', type=str, default=None, - help='Directory with reference acquisition') + parser.add_argument('-p', '--polarization', dest='polarization', type=str, default='vv', + help='SAR data polarization (default: %(default)s).') - parser.add_argument('-c','--num_connections', dest='num_connections', type=str, default = '1', - help='number of interferograms between each date and subsequent dates (default: %(default)s).') + parser.add_argument('-W', '--workflow', dest='workflow', type=str, default='interferogram', + choices=['slc', 'correlation', 'interferogram', 'offset'], + help='The InSAR processing workflow (default: %(default)s).') - parser.add_argument('-n', '--swath_num', dest='swath_num', type=str, default='1 2 3', - help="A list of swaths to be processed. -- Default : '1 2 3'") + # area of interest + aoi = parser.add_argument_group('Area of interest') + aoi.add_argument('-n', '--swath_num', dest='swath_num', type=str, default='1 2 3', + help="A list of swaths to be processed. -- Default : '1 2 3'") - parser.add_argument('-b', '--bbox', dest='bbox', type=str, default=None, - help="Lat/Lon Bounding SNWE. -- Example : '19 20 -99.5 -98.5' -- Default : common overlap between stack") + aoi.add_argument('-b', '--bbox', dest='bbox', type=str, default=None, + help="Lat/Lon Bounding SNWE. -- Example : '19 20 -99.5 -98.5' -- Default : common overlap between stack") - parser.add_argument('-x', '--exclude_dates', dest='exclude_dates', type=str, default=None, - help="List of the dates to be excluded for processing. -- Example : '20141007,20141031' (default: %(default)s).") + # dates of interest + doi = parser.add_argument_group('Dates of interest') + doi.add_argument('-x', '--exclude_dates', dest='exclude_dates', type=str, default=None, + help="List of the dates to be excluded for processing. -- Example : '20141007,20141031' (default: %(default)s).") - parser.add_argument('-i', '--include_dates', dest='include_dates', type=str, default=None, - help="List of the dates to be included for processing. -- Example : '20141007,20141031' (default: %(default)s).") + doi.add_argument('-i', '--include_dates', dest='include_dates', type=str, default=None, + help="List of the dates to be included for processing. -- Example : '20141007,20141031' (default: %(default)s).") - parser.add_argument('--start_date', dest='startDate', type=str, default=None, - help='Start date for stack processing. Acquisitions before start date are ignored. ' - 'format should be YYYY-MM-DD e.g., 2015-01-23') + doi.add_argument('--start_date', dest='startDate', type=str, default=None, + help='Start date for stack processing. Acquisitions before start date are ignored. ' + 'format should be YYYY-MM-DD e.g., 2015-01-23') - parser.add_argument('--stop_date', dest='stopDate', type=str, default=None, - help='Stop date for stack processing. Acquisitions after stop date are ignored. ' - 'format should be YYYY-MM-DD e.g., 2017-02-26') + doi.add_argument('--stop_date', dest='stopDate', type=str, default=None, + help='Stop date for stack processing. Acquisitions after stop date are ignored. ' + 'format should be YYYY-MM-DD e.g., 2017-02-26') - parser.add_argument('-z', '--azimuth_looks', dest='azimuthLooks', type=str, default='3', - help='Number of looks in azimuth for interferogram multi-looking (default: %(default)s).') + # coregistration + coreg = parser.add_argument_group('Coregistration options', 'Configurations for stack coregistartion of SLCs') + coreg.add_argument('-C', '--coregistration', dest='coregistration', type=str, default='NESD', choices=['geometry', 'NESD'], + help='Coregistration options (default: %(default)s).') - parser.add_argument('-r', '--range_looks', dest='rangeLooks', type=str, default='9', - help='Number of looks in range for interferogram multi-looking (default: %(default)s).') + coreg.add_argument('-m', '--reference_date', dest='reference_date', type=str, default=None, + help='Directory with reference acquisition') - parser.add_argument('-f', '--filter_strength', dest='filtStrength', type=str, default='0.5', - help='Filter strength for interferogram filtering (default: %(default)s).') + coreg.add_argument('--snr_misreg_threshold', dest='snrThreshold', type=str, default='10', + help='SNR threshold for estimating range misregistration using cross correlation (default: %(default)s).') + + coreg.add_argument('-e', '--esd_coherence_threshold', dest='esdCoherenceThreshold', type=str, default='0.85', + help='Coherence threshold for estimating azimuth misregistration using enhanced spectral diversity (default: %(default)s).') - parser.add_argument('--snr_misreg_threshold', dest='snrThreshold', type=str, default='10', - help='SNR threshold for estimating range misregistration using cross correlation (default: %(default)s).') + coreg.add_argument('-O','--num_overlap_connections', dest='num_overlap_connections', type=str, default = '3', + help='number of overlap interferograms between each date and subsequent dates used for NESD computation ' + '(for azimuth offsets misregistration) (default: %(default)s).') - parser.add_argument('-p', '--polarization', dest='polarization', type=str, default='vv', - help='SAR data polarization (default: %(default)s).') - - parser.add_argument('-C', '--coregistration', dest='coregistration', type=str, default='NESD', choices=['geometry', 'NESD'], - help='Coregistration options (default: %(default)s).') + # interferogram formation + ifgram = parser.add_argument_group('Interferogram options', 'Configurations for interferogram generation') + ifgram.add_argument('-c','--num_connections', dest='num_connections', type=str, default = '1', + help='number of interferograms between each date and subsequent dates (default: %(default)s).') - parser.add_argument('-O','--num_overlap_connections', dest='num_overlap_connections', type=str, default = '3', - help='number of overlap interferograms between each date and subsequent dates used for NESD computation ' - '(for azimuth offsets misregistration) (default: %(default)s).') + ifgram.add_argument('-z', '--azimuth_looks', dest='azimuthLooks', type=str, default='3', + help='Number of looks in azimuth for interferogram multi-looking (default: %(default)s).') - parser.add_argument('-e', '--esd_coherence_threshold', dest='esdCoherenceThreshold', type=str, default='0.85', - help='Coherence threshold for estimating azimuth misregistration using enhanced spectral diversity (default: %(default)s).') + ifgram.add_argument('-r', '--range_looks', dest='rangeLooks', type=str, default='9', + help='Number of looks in range for interferogram multi-looking (default: %(default)s).') - parser.add_argument('-W', '--workflow', dest='workflow', type=str, default='interferogram', - choices=['slc', 'correlation', 'interferogram', 'offset'], - help='The InSAR processing workflow (default: %(default)s).') + ifgram.add_argument('-f', '--filter_strength', dest='filtStrength', type=str, default='0.5', + help='Filter strength for interferogram filtering (default: %(default)s).') - # unwrap - parser.add_argument('-u', '--unw_method', dest='unwMethod', type=str, default='snaphu', choices=['icu', 'snaphu'], + # phase unwrap + unwrap = parser.add_argument_group('Phase unwrapping options', 'Configurations for phase unwrapping') + unwrap.add_argument('-u', '--unw_method', dest='unwMethod', type=str, default='snaphu', choices=['icu', 'snaphu'], help='Unwrapping method (default: %(default)s).') - parser.add_argument('-rmFilter', '--rmFilter', dest='rmFilter', action='store_true', default=False, + unwrap.add_argument('-rmFilter', '--rmFilter', dest='rmFilter', action='store_true', default=False, help='Make an extra unwrap file in which filtering effect is removed') # ionospheric correction - parser.add_argument('--param_ion', dest='param_ion', type=str, default=None, - help='ionosphere estimation parameter file. if provided, will do ionosphere estimation.') + iono = parser.add_argument_group('Ionosphere options', 'Configurations for ionospheric delay estimation') + iono.add_argument('--param_ion', dest='param_ion', type=str, default=None, + help='ionosphere estimation parameter file. if provided, will do ionosphere estimation.') - parser.add_argument('--num_connections_ion', dest='num_connections_ion', type=str, default = '3', - help='number of interferograms between each date and subsequent dates for ionosphere estimation (default: %(default)s).') + iono.add_argument('--num_connections_ion', dest='num_connections_ion', type=str, default = '3', + help='number of interferograms between each date and subsequent dates for ionosphere estimation (default: %(default)s).') # computing - compute = parser.add_argument_group('Computing options') + compute = parser.add_argument_group('Computing options', 'Configurations for computing environment and resource') compute.add_argument('-useGPU', '--useGPU', dest='useGPU',action='store_true', default=False, help='Allow App to use GPU when available') @@ -187,11 +198,11 @@ def createParser(): compute.add_argument('-t', '--text_cmd', dest='text_cmd', type=str, default='', help="text command to be added to the beginning of each line of the run files (default: '%(default)s'). " - "Example : 'source ~/.bash_profile;'") + "Example: 'source ~/.bash_profile;'") compute.add_argument('-V', '--virtual_merge', dest='virtualMerge', type=str, default=None, choices=['True', 'False'], - help='Use virtual files for the merged SLCs and geometry files.\n' - 'Default: True for correlation / interferogram workflow\n' + help='Use virtual files for the merged SLCs and geometry files. ' + 'Default: True for correlation / interferogram workflow, ' ' False for slc / offset workflow') return parser @@ -416,7 +427,7 @@ def get_dates(inps): if len(dateList)<1: print('*************************************') print('Error:') - print('No acquisition forfills the temporal range and bbox requirement.') + print('No acquisition fulfills the temporal range and bbox requirement.') sys.exit(1) inps.reference_date = dateList[0] print ("The reference date was not chosen. The first date is considered as reference date.") @@ -538,10 +549,10 @@ def selectNeighborPairsIonosphere(safe_dict, num_connections): for k in range(ndate_unique-1): cnt = 0 for pair in pairs_diff_starting_ranges_0: - if (pair[0] in starting_ranges_unique_dates[k] and pair[1] in starting_ranges_unique_dates[k+1]) or \ - (pair[1] in starting_ranges_unique_dates[k] and pair[0] in starting_ranges_unique_dates[k+1]): - pairs_diff_starting_ranges.append(pair) - cnt += 1 + if ((pair[0] in starting_ranges_unique_dates[k] and pair[1] in starting_ranges_unique_dates[k+1]) + or (pair[1] in starting_ranges_unique_dates[k] and pair[0] in starting_ranges_unique_dates[k+1])): + pairs_diff_starting_ranges.append(pair) + cnt += 1 if cnt >= num_connections: break From 881704cca31a4bcbf639ee467f936c733e9cc1fc Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Wed, 28 Sep 2022 20:38:49 -0700 Subject: [PATCH 2/4] README: update link/command to download AUX_CAL file --- contrib/stack/topsStack/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/stack/topsStack/README.md b/contrib/stack/topsStack/README.md index e9cd243a..54b6ac7f 100644 --- a/contrib/stack/topsStack/README.md +++ b/contrib/stack/topsStack/README.md @@ -34,10 +34,10 @@ In all workflows, coregistration (-C option) can be done using only geometry (se The following calibration auxliary (AUX_CAL) file is used for **antenna pattern correction** to compensate the range phase offset of SAFE products with **IPF verison 002.36** (mainly for images acquired before March 2015). If all your SAFE products are from another IPF version, then no AUX files are needed. Check [ESA document](https://earth.esa.int/documents/247904/1653440/Sentinel-1-IPF_EAP_Phase_correction) for details. -Run the command below to download the AUX_CAL file once and store it somewhere (_i.e._ ~/aux/aux_cal) so that you can use it all the time, for `stackSentinel.py -a` or `auxiliary data directory` in `topsApp.py`. +The AUX_CAL file is available on [Sentinel-1 Mission Performance Center](https://sar-mpc.eu/ipf-adf/aux_cal/?sentinel1__mission=S1A&validity_start=2014&validity_start=2014-09&adf__active=True). We recommend download it using the web brower or the `wget` command below, and store it somewhere (_i.e._ ~/aux/aux_cal) so that you can use it all the time, for `stackSentinel.py -a` or `auxiliary data directory` in `topsApp.py`. ``` -wget https://qc.sentinel1.groupcls.com/product/S1A/AUX_CAL/2014/09/08/S1A_AUX_CAL_V20140908T000000_G20190626T100201.SAFE.TGZ +wget https://sar-mpc.eu/download/ca97845e-1314-4817-91d8-f39afbeff74d/ -O S1A_AUX_CAL_V20140908T000000_G20190626T100201.SAFE.zip ``` #### 1. Create your project folder somewhere #### From 5ab2acb6494985f7560a59254d9b16e434008dd6 Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Fri, 21 Jan 2022 14:36:25 -0800 Subject: [PATCH 3/4] geo2rdr/resamp*/gen*Igram: indentation adjustment + replace offensive var names Update generateIgram.py mas --> reference slv --> secondary --- contrib/stack/topsStack/generateIgram.py | 77 ++++---- contrib/stack/topsStack/geo2rdr.py | 107 ++++++------ contrib/stack/topsStack/resamp_withCarrier.py | 164 +++++++++--------- 3 files changed, 169 insertions(+), 179 deletions(-) diff --git a/contrib/stack/topsStack/generateIgram.py b/contrib/stack/topsStack/generateIgram.py index f0524b26..7a031485 100755 --- a/contrib/stack/topsStack/generateIgram.py +++ b/contrib/stack/topsStack/generateIgram.py @@ -3,17 +3,18 @@ # Author: Piyush Agram # Heresh Fattahi: Adopted for stack +import os +import argparse +import copy +import numpy as np +from osgeo import gdal + import isce import isceobj -import numpy as np from isceobj.Util.Poly2D import Poly2D -import argparse -import os -import copy from isceobj.Sensor.TOPS import createTOPSSwathSLCProduct from mroipac.correlation.correlation import Correlation import s1a_isce_utils as ut -from osgeo import gdal def createParser(): @@ -49,25 +50,24 @@ def cmdLineParse(iargs = None): return parser.parse_args(args=iargs) -def multiply(masname, slvname, outname, rngname1, rngname2, fact, referenceFrame, - flatten=False): +def multiply(referencename, secondaryname, outname, rngname1, rngname2, fact, referenceFrame, flatten=False): print('multiply') - masImg = isceobj.createSlcImage() - masImg.load( masname + '.xml') + referenceImg = isceobj.createSlcImage() + referenceImg.load(referencename + '.xml') - width = masImg.getWidth() - length = masImg.getLength() + width = referenceImg.getWidth() + length = referenceImg.getLength() - ds = gdal.Open(masname + '.vrt', gdal.GA_ReadOnly) + ds = gdal.Open(referencename + '.vrt', gdal.GA_ReadOnly) reference = ds.GetRasterBand(1).ReadAsArray() ds = None - ds = gdal.Open(slvname + '.vrt', gdal.GA_ReadOnly) + ds = gdal.Open(secondaryname + '.vrt', gdal.GA_ReadOnly) secondary = ds.GetRasterBand(1).ReadAsArray() ds = None - print('read') - #reference = np.memmap(masname, dtype=np.complex64, mode='r', shape=(length,width)) - #secondary = np.memmap(slvname, dtype=np.complex64, mode='r', shape=(length, width)) + print('read') + #reference = np.memmap(referencename, dtype=np.complex64, mode='r', shape=(length,width)) + #secondary = np.memmap(secondaryname, dtype=np.complex64, mode='r', shape=(length, width)) if os.path.exists(rngname1): rng1 = np.memmap(rngname1, dtype=np.float32, mode='r', shape=(length,width)) @@ -137,7 +137,7 @@ def main(iargs=None): os.makedirs(ifgdir, exist_ok=True) - ####Load relevant products + ####Load relevant products if inps.overlap: topReference = ut.loadProduct(os.path.join(inps.reference , 'overlap','IW{0}_top.xml'.format(swath))) botReference = ut.loadProduct(os.path.join(inps.reference ,'overlap', 'IW{0}_bottom.xml'.format(swath))) @@ -189,25 +189,21 @@ def main(iargs=None): secondaryname = os.path.splitext(secondaryname)[0] + inps.secondary_suffix + os.path.splitext(secondaryname)[1] if inps.overlap: - rdict = { 'rangeOff1' : os.path.join(inps.reference, 'overlap', IWstr, 'range_top_%02d_%02d.off'%(ii,ii+1)), - 'rangeOff2' : os.path.join(inps.secondary, 'overlap', IWstr, 'range_top_%02d_%02d.off'%(ii,ii+1)), - 'azimuthOff': os.path.join(inps.secondary, 'overlap', IWstr, 'azimuth_top_%02d_%02d.off'%(ii,ii+1))} - + rdict = {'rangeOff1' : os.path.join(inps.reference, 'overlap', IWstr, 'range_top_%02d_%02d.off'%(ii,ii+1)), + 'rangeOff2' : os.path.join(inps.secondary, 'overlap', IWstr, 'range_top_%02d_%02d.off'%(ii,ii+1)), + 'azimuthOff': os.path.join(inps.secondary, 'overlap', IWstr, 'azimuth_top_%02d_%02d.off'%(ii,ii+1))} intname = os.path.join(ifgdir, '%s_top_%02d_%02d.int'%(inps.intprefix,ii,ii+1)) - - else: - rdict = {'rangeOff1' : os.path.join(inps.reference, IWstr, 'range_%02d.off'%(ii)), - 'rangeOff2' : os.path.join(inps.secondary, IWstr, 'range_%02d.off'%(ii)), - 'azimuthOff1': os.path.join(inps.secondary, IWstr, 'azimuth_%02d.off'%(ii))} - + else: + rdict = {'rangeOff1' : os.path.join(inps.reference, IWstr, 'range_%02d.off'%(ii)), + 'rangeOff2' : os.path.join(inps.secondary, IWstr, 'range_%02d.off'%(ii)), + 'azimuthOff1': os.path.join(inps.secondary, IWstr, 'azimuth_%02d.off'%(ii))} intname = os.path.join(ifgdir, '%s_%02d.int'%(inps.intprefix,ii)) - ut.adjustCommonValidRegion(reference,secondary) fact = 4 * np.pi * secondary.rangePixelSize / secondary.radarWavelength intimage = multiply(referencename, secondaryname, intname, - rdict['rangeOff1'], rdict['rangeOff2'], fact, reference, flatten=inps.flatten) + rdict['rangeOff1'], rdict['rangeOff2'], fact, reference, flatten=inps.flatten) burst = copy.deepcopy(reference) burst.image = intimage @@ -220,28 +216,24 @@ def main(iargs=None): reference = botReference.bursts[ii-minReference] secondary = botCoreg.bursts[ii-minSecondary] - - referencename = reference.image.filename + referencename = reference.image.filename secondaryname = secondary.image.filename -# rdict = {'rangeOff' : os.path.join(coregdir, 'range_bot_%02d_%02d.off'%(ii,ii+1)), -# 'azimuthOff': os.path.join(coregdir, 'azimuth_bot_%02d_%02d.off'%(ii,ii+1))} - - rdict = { 'rangeOff1' : os.path.join(inps.reference, 'overlap', IWstr, 'range_bot_%02d_%02d.off'%(ii,ii+1)), - 'rangeOff2' : os.path.join(inps.secondary, 'overlap', IWstr, 'range_bot_%02d_%02d.off'%(ii,ii+1)), - 'azimuthOff': os.path.join(inps.secondary, 'overlap', IWstr, 'azimuth_bot_%02d_%02d.off'%(ii,ii+1))} - + #rdict = {'rangeOff' : os.path.join(coregdir, 'range_bot_%02d_%02d.off'%(ii,ii+1)), + # 'azimuthOff': os.path.join(coregdir, 'azimuth_bot_%02d_%02d.off'%(ii,ii+1))} + rdict = {'rangeOff1' : os.path.join(inps.reference, 'overlap', IWstr, 'range_bot_%02d_%02d.off'%(ii,ii+1)), + 'rangeOff2' : os.path.join(inps.secondary, 'overlap', IWstr, 'range_bot_%02d_%02d.off'%(ii,ii+1)), + 'azimuthOff': os.path.join(inps.secondary, 'overlap', IWstr, 'azimuth_bot_%02d_%02d.off'%(ii,ii+1))} print ('rdict: ', rdict) ut.adjustCommonValidRegion(reference,secondary) intname = os.path.join(ifgdir, '%s_bot_%02d_%02d.int'%(inps.intprefix,ii,ii+1)) fact = 4 * np.pi * secondary.rangePixelSize / secondary.radarWavelength - #intimage = multiply(referencename, secondaryname, intname, - # rdict['rangeOff'], fact, reference, flatten=True) - + #intimage = multiply(referencename, secondaryname, intname, + # rdict['rangeOff'], fact, reference, flatten=True) intimage = multiply(referencename, secondaryname, intname, - rdict['rangeOff1'], rdict['rangeOff2'], fact, reference, flatten=inps.flatten) + rdict['rangeOff1'], rdict['rangeOff2'], fact, reference, flatten=inps.flatten) burst = copy.deepcopy(reference) burst.burstNumber = ii @@ -254,7 +246,6 @@ def main(iargs=None): topIfg.reference = topCoreg.reference else: topIfg.reference = topReference.reference - print('Type: ',type(topIfg.reference)) if inps.overlap: diff --git a/contrib/stack/topsStack/geo2rdr.py b/contrib/stack/topsStack/geo2rdr.py index 23c972fe..18bb5b1c 100644 --- a/contrib/stack/topsStack/geo2rdr.py +++ b/contrib/stack/topsStack/geo2rdr.py @@ -1,36 +1,45 @@ #!/usr/bin/env python3 -import numpy as np -import argparse + import os +import sys +import argparse +import datetime +import numpy as np + import isce import isceobj -import datetime -import sys import s1a_isce_utils as ut + def createParser(): parser = argparse.ArgumentParser( description='Generate offset field between two Sentinel swaths') + + # inputs parser.add_argument('-m', '--reference', type=str, dest='reference', required=True, help='Directory with the reference image') parser.add_argument('-s', '--secondary', type=str, dest='secondary', required=True, help='Directory with the secondary image') parser.add_argument('-g', '--geom_referenceDir', type=str, dest='geom_referenceDir', default='geom_reference', help='Directory for geometry files of the reference') - parser.add_argument('-c', '--coregSLCdir', type=str, dest='coregdir', default='coreg_secondarys', - help='Directory with coregistered SLC data') parser.add_argument('-a', '--azimuth_misreg', type=str, dest='misreg_az', default='', help='A text file that contains zimuth misregistration in subpixels') parser.add_argument('-r', '--range_misreg', type=str, dest='misreg_rng', default='', help='A text file that contains range misregistration in meters') + parser.add_argument('-useGPU', '--useGPU', dest='useGPU',action='store_true', default=False, + help='Allow App to use GPU when available') + + # outputs + parser.add_argument('-c', '--coregSLCdir', type=str, dest='coregdir', default='coreg_secondarys', + help='Directory with coregistered SLC data, to store the generated azimuth/range_*.off files.') parser.add_argument('-v', '--overlap', dest='overlap', action='store_true', default=False, help='Flatten the interferograms with offsets if needed') parser.add_argument('-o', '--overlap_dir', type=str, dest='overlapDir', default='overlap', help='overlap directory name') - parser.add_argument('-useGPU', '--useGPU', dest='useGPU',action='store_true', default=False, - help='Allow App to use GPU when available') + return parser + def cmdLineParse(iargs=None): ''' Command line parser. @@ -38,6 +47,7 @@ def cmdLineParse(iargs=None): parser = createParser() return parser.parse_args(args=iargs) + def runGeo2rdrCPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): from zerodop.geo2rdr import createGeo2rdr from isceobj.Planet.Planet import Planet @@ -96,12 +106,12 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): from zerodop.GPUgeo2rdr.GPUgeo2rdr import PyGeo2rdr from isceobj.Planet.Planet import Planet from iscesys import DateTimeUtil as DTU - + latImage = isceobj.createImage() latImage.load(rdict['lat'] + '.xml') latImage.setAccessMode('READ') latImage.createImage() - + lonImage = isceobj.createImage() lonImage.load(rdict['lon'] + '.xml') lonImage.setAccessMode('READ') @@ -120,7 +130,7 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): #####Run Geo2rdr planet = Planet(pname='Earth') grdr = PyGeo2rdr() - + grdr.setRangePixelSpacing(info.rangePixelSize) grdr.setPRF(1.0 / info.azimuthTimeInterval) grdr.setRadarWavelength(info.radarWavelength) @@ -134,7 +144,7 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): grdr.setOrbitVector(count, td, pos[0], pos[1], pos[2], vel[0], vel[1], vel[2]) count += 1 - + grdr.setOrbitMethod(0) grdr.setWidth(info.numberOfSamples) grdr.setLength(info.numberOfLines) @@ -146,11 +156,11 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): grdr.setEllipsoidEccentricitySquared(planet.ellipsoid.e2) grdr.createPoly(0, 0., 1.) grdr.setPolyCoeff(0, 0.) - + grdr.setDemLength(demImage.getLength()) grdr.setDemWidth(demImage.getWidth()) grdr.setBistaticFlag(0) - + rangeOffsetImage = isceobj.createImage() rangeOffsetImage.setFilename(rdict['rangeOffName']) rangeOffsetImage.setAccessMode('write') @@ -158,7 +168,7 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): rangeOffsetImage.setCaster('write', 'DOUBLE') rangeOffsetImage.setWidth(demImage.width) rangeOffsetImage.createImage() - + azimuthOffsetImage = isceobj.createImage() azimuthOffsetImage.setFilename(rdict['azOffName']) azimuthOffsetImage.setAccessMode('write') @@ -166,7 +176,7 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): azimuthOffsetImage.setCaster('write', 'DOUBLE') azimuthOffsetImage.setWidth(demImage.width) azimuthOffsetImage.createImage() - + grdr.setLatAccessor(latImage.getImagePointer()) grdr.setLonAccessor(lonImage.getImagePointer()) grdr.setHgtAccessor(demImage.getImagePointer()) @@ -174,24 +184,24 @@ def runGeo2rdrGPU(info, rdict, misreg_az=0.0, misreg_rg=0.0): grdr.setRgAccessor(0) grdr.setAzOffAccessor(azimuthOffsetImage.getImagePointer()) grdr.setRgOffAccessor(rangeOffsetImage.getImagePointer()) - + grdr.geo2rdr() - + rangeOffsetImage.finalizeImage() rangeOffsetImage.renderHdr() - + azimuthOffsetImage.finalizeImage() azimuthOffsetImage.renderHdr() latImage.finalizeImage() lonImage.finalizeImage() demImage.finalizeImage() - + return - pass + def main(iargs=None): ''' - Estimate offsets for the overlap regions of the bursts. + Estimate offsets for (the overlap regions of) the bursts. ''' inps = cmdLineParse(iargs) @@ -203,7 +213,7 @@ def main(iargs=None): run_GPU = True except: pass - + if inps.useGPU and not run_GPU: print("GPU mode requested but no GPU ISCE code found") @@ -214,24 +224,22 @@ def main(iargs=None): else: print('CPU mode') runGeo2rdr = runGeo2rdrCPU - + referenceSwathList = ut.getSwathList(inps.reference) secondarySwathList = ut.getSwathList(inps.secondary) - - swathList = list(sorted(set(referenceSwathList+secondarySwathList))) + swathList = list(sorted(set(referenceSwathList + secondarySwathList))) for swath in swathList: ##Load secondary metadata secondary = ut.loadProduct(os.path.join(inps.secondary, 'IW{0}.xml'.format(swath))) reference = ut.loadProduct(os.path.join(inps.reference, 'IW{0}.xml'.format(swath))) - + ### output directory if inps.overlap: outdir = os.path.join(inps.coregdir, inps.overlapDir, 'IW{0}'.format(swath)) else: outdir = os.path.join(inps.coregdir, 'IW{0}'.format(swath)) - os.makedirs(outdir, exist_ok=True) if os.path.exists(str(inps.misreg_az)): @@ -239,7 +247,7 @@ def main(iargs=None): misreg_az = float(f.readline()) else: misreg_az = 0.0 - + if os.path.exists(str(inps.misreg_rng)): with open(inps.misreg_rng, 'r') as f: misreg_rg = float(f.readline()) @@ -252,51 +260,45 @@ def main(iargs=None): if inps.overlap: maxBurst = maxBurst - 1 geomDir = os.path.join(inps.geom_referenceDir, inps.overlapDir, 'IW{0}'.format(swath)) - else: geomDir = os.path.join(inps.geom_referenceDir, 'IW{0}'.format(swath)) - - + secondaryBurstStart = minBurst + burstoffset - + for mBurst in range(minBurst, maxBurst): - ###Corresponding secondary burst sBurst = secondaryBurstStart + (mBurst - minBurst) burstTop = secondary.bursts[sBurst] if inps.overlap: burstBot = secondary.bursts[sBurst+1] - + print('Overlap pair {0}: Burst {1} of reference matched with Burst {2} of secondary'.format(mBurst-minBurst, mBurst, sBurst)) if inps.overlap: ####Generate offsets for top burst rdict = {'lat': os.path.join(geomDir,'lat_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), - 'lon': os.path.join(geomDir,'lon_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), - 'hgt': os.path.join(geomDir,'hgt_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), - 'rangeOffName': os.path.join(outdir, 'range_top_%02d_%02d.off'%(mBurst+1,mBurst+2)), - 'azOffName': os.path.join(outdir, 'azimuth_top_%02d_%02d.off'%(mBurst+1,mBurst+2))} - + 'lon': os.path.join(geomDir,'lon_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), + 'hgt': os.path.join(geomDir,'hgt_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), + 'rangeOffName': os.path.join(outdir, 'range_top_%02d_%02d.off'%(mBurst+1,mBurst+2)), + 'azOffName': os.path.join(outdir, 'azimuth_top_%02d_%02d.off'%(mBurst+1,mBurst+2))} runGeo2rdr(burstTop, rdict, misreg_az=misreg_az, misreg_rg=misreg_rg) - + print('Overlap pair {0}: Burst {1} of reference matched with Burst {2} of secondary'.format(mBurst-minBurst, mBurst+1, sBurst+1)) ####Generate offsets for bottom burst rdict = {'lat': os.path.join(geomDir,'lat_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), - 'lon': os.path.join(geomDir, 'lon_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), - 'hgt': os.path.join(geomDir, 'hgt_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), - 'rangeOffName': os.path.join(outdir, 'range_bot_%02d_%02d.off'%(mBurst+1,mBurst+2)), - 'azOffName': os.path.join(outdir, 'azimuth_bot_%02d_%02d.off'%(mBurst+1,mBurst+2))} - + 'lon': os.path.join(geomDir, 'lon_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), + 'hgt': os.path.join(geomDir, 'hgt_%02d_%02d.rdr'%(mBurst+1,mBurst+2)), + 'rangeOffName': os.path.join(outdir, 'range_bot_%02d_%02d.off'%(mBurst+1,mBurst+2)), + 'azOffName': os.path.join(outdir, 'azimuth_bot_%02d_%02d.off'%(mBurst+1,mBurst+2))} runGeo2rdr(burstBot, rdict, misreg_az=misreg_az, misreg_rg=misreg_rg) else: print('Burst {1} of reference matched with Burst {2} of secondary'.format(mBurst-minBurst, mBurst, sBurst)) ####Generate offsets for top burst rdict = {'lat': os.path.join(geomDir,'lat_%02d.rdr'%(mBurst+1)), - 'lon': os.path.join(geomDir,'lon_%02d.rdr'%(mBurst+1)), - 'hgt': os.path.join(geomDir,'hgt_%02d.rdr'%(mBurst+1)), - 'rangeOffName': os.path.join(outdir, 'range_%02d.off'%(mBurst+1)), - 'azOffName': os.path.join(outdir, 'azimuth_%02d.off'%(mBurst+1))} - + 'lon': os.path.join(geomDir,'lon_%02d.rdr'%(mBurst+1)), + 'hgt': os.path.join(geomDir,'hgt_%02d.rdr'%(mBurst+1)), + 'rangeOffName': os.path.join(outdir, 'range_%02d.off'%(mBurst+1)), + 'azOffName': os.path.join(outdir, 'azimuth_%02d.off'%(mBurst+1))} runGeo2rdr(burstTop, rdict, misreg_az=misreg_az, misreg_rg=misreg_rg) @@ -307,6 +309,3 @@ def main(iargs=None): ''' # Main Driver main() - - - diff --git a/contrib/stack/topsStack/resamp_withCarrier.py b/contrib/stack/topsStack/resamp_withCarrier.py index 046c1c63..c572bd3b 100755 --- a/contrib/stack/topsStack/resamp_withCarrier.py +++ b/contrib/stack/topsStack/resamp_withCarrier.py @@ -1,30 +1,35 @@ #!/usr/bin/env python3 + +import os +import argparse +import copy +import numpy as np + import isce import isceobj import stdproc -from stdproc.stdproc import crossmul -import numpy as np from isceobj.Util.Poly2D import Poly2D -import argparse -import os -import copy -import s1a_isce_utils as ut from isceobj.Sensor.TOPS import createTOPSSwathSLCProduct +from stdproc.stdproc import crossmul +import s1a_isce_utils as ut def createParser(): parser = argparse.ArgumentParser( description='Resampling burst by burst SLCs ') + # inputs parser.add_argument('-m', '--reference', dest='reference', type=str, required=True, help='Directory with reference acquisition') parser.add_argument('-s', '--secondary', dest='secondary', type=str, required=True, help='Directory with secondary acquisition') + # output parser.add_argument('-o', '--coregdir', dest='coreg', type=str, default='coreg_secondary', help='Directory with coregistered SLCs and IFGs') + # additional setups parser.add_argument('-a', '--azimuth_misreg', dest='misreg_az', type=str, default=0.0, help='File name with the azimuth misregistration') @@ -42,11 +47,13 @@ def createParser(): return parser + def cmdLineParse(iargs = None): parser = createParser() return parser.parse_args(args=iargs) -def resampSecondary(mas, slv, rdict, outname, flatten): + +def resampSecondary(ref, sec, rdict, outname, flatten): ''' Resample burst by burst. ''' @@ -65,13 +72,13 @@ def resampSecondary(mas, slv, rdict, outname, flatten): aziImg.setAccessMode('READ') inimg = isceobj.createSlcImage() - inimg.load(slv.image.filename + '.xml') + inimg.load(sec.image.filename + '.xml') inimg.setAccessMode('READ') rObj = stdproc.createResamp_slc() - rObj.slantRangePixelSpacing = slv.rangePixelSize - rObj.radarWavelength = slv.radarWavelength + rObj.slantRangePixelSpacing = sec.rangePixelSize + rObj.radarWavelength = sec.radarWavelength rObj.azimuthCarrierPoly = azcarrpoly rObj.dopplerPoly = dpoly @@ -79,8 +86,8 @@ def resampSecondary(mas, slv, rdict, outname, flatten): rObj.rangeOffsetsPoly = rgpoly rObj.imageIn = inimg - width = mas.numberOfSamples - length = mas.numberOfLines + width = ref.numberOfSamples + length = ref.numberOfLines imgOut = isceobj.createSlcImage() imgOut.setWidth(width) imgOut.filename = outname @@ -98,6 +105,7 @@ def resampSecondary(mas, slv, rdict, outname, flatten): imgOut.renderVRT() return imgOut + def main(iargs=None): ''' Create coregistered overlap secondarys. @@ -105,11 +113,10 @@ def main(iargs=None): inps = cmdLineParse(iargs) referenceSwathList = ut.getSwathList(inps.reference) secondarySwathList = ut.getSwathList(inps.secondary) - - swathList = list(sorted(set(referenceSwathList+secondarySwathList))) + swathList = list(sorted(set(referenceSwathList + secondarySwathList))) for swath in swathList: - + ####Load secondary metadata reference = ut.loadProduct( os.path.join(inps.reference , 'IW{0}.xml'.format(swath))) secondary = ut.loadProduct( os.path.join(inps.secondary , 'IW{0}.xml'.format(swath))) @@ -117,7 +124,6 @@ def main(iargs=None): referenceTop = ut.loadProduct(os.path.join(inps.reference, inps.overlapDir , 'IW{0}_top.xml'.format(swath))) referenceBottom = ut.loadProduct(os.path.join(inps.reference, inps.overlapDir , 'IW{0}_bottom.xml'.format(swath))) - dt = secondary.bursts[0].azimuthTimeInterval dr = secondary.bursts[0].rangePixelSize @@ -133,6 +139,7 @@ def main(iargs=None): else: misreg_rg = 0.0 + ###Output directory for coregistered SLCs if not inps.overlap: outdir = os.path.join(inps.coreg,'IW{0}'.format(swath)) @@ -142,32 +149,32 @@ def main(iargs=None): offdir = os.path.join(inps.coreg, inps.overlapDir, 'IW{0}'.format(swath)) os.makedirs(outdir, exist_ok=True) - + ####Indices w.r.t reference burstoffset, minBurst, maxBurst = reference.getCommonBurstLimits(secondary) secondaryBurstStart = minBurst + burstoffset secondaryBurstEnd = maxBurst - + relShifts = ut.getRelativeShifts(reference, secondary, minBurst, maxBurst, secondaryBurstStart) + print('Shifts: ', relShifts) if inps.overlap: maxBurst = maxBurst - 1 ###For overlaps - - print('Shifts: ', relShifts) - - ####Can corporate known misregistration here - + + + ####Can corporate known misregistration here + apoly = Poly2D() apoly.initPoly(rangeOrder=0,azimuthOrder=0,coeffs=[[0.]]) - + rpoly = Poly2D() rpoly.initPoly(rangeOrder=0,azimuthOrder=0,coeffs=[[0.]]) - + #topCoreg = createTOPSSwathSLCProduct() topCoreg = ut.coregSwathSLCProduct() topCoreg.configure() - if inps.overlap: + if inps.overlap: botCoreg = ut.coregSwathSLCProduct() botCoreg.configure() @@ -181,100 +188,95 @@ def main(iargs=None): topBurst = reference.bursts[ii] - slvBurst = secondary.bursts[jj] + secBurst = secondary.bursts[jj] #####Top burst processing try: offset = relShifts[jj] except: raise Exception('Trying to access shift for secondary burst index {0}, which may not overlap with reference'.format(jj)) - - if inps.overlap: + + if inps.overlap: outname = os.path.join(outdir, 'burst_top_%02d_%02d.slc'%(ii+1,ii+2)) - + ####Setup initial polynomials ### If no misregs are given, these are zero ### If provided, can be used for resampling without running to geo2rdr again for fast results rdict = {'azpoly' : apoly, - 'rgpoly' : rpoly, - 'rangeOff' : os.path.join(offdir, 'range_top_%02d_%02d.off'%(ii+1,ii+2)), - 'azimuthOff': os.path.join(offdir, 'azimuth_top_%02d_%02d.off'%(ii+1,ii+2))} - - - ###For future - should account for azimuth and range misreg here .. ignoring for now. - azCarrPoly, dpoly = secondary.estimateAzimuthCarrierPolynomials(slvBurst, offset = -1.0 * offset) - + 'rgpoly' : rpoly, + 'rangeOff' : os.path.join(offdir, 'range_top_%02d_%02d.off'%(ii+1,ii+2)), + 'azimuthOff': os.path.join(offdir, 'azimuth_top_%02d_%02d.off'%(ii+1,ii+2))} + + + ###For future - should account for azimuth and range misreg here .. ignoring for now. + azCarrPoly, dpoly = secondary.estimateAzimuthCarrierPolynomials(secBurst, offset = -1.0 * offset) rdict['carrPoly'] = azCarrPoly rdict['doppPoly'] = dpoly - - outimg = resampSecondary(topBurst, slvBurst, rdict, outname, (not inps.noflat)) - + + outimg = resampSecondary(topBurst, secBurst, rdict, outname, (not inps.noflat)) + copyBurst = copy.deepcopy(topBurst) ut.adjustValidSampleLine(copyBurst) copyBurst.image.filename = outimg.filename print('After: ', copyBurst.firstValidLine, copyBurst.numValidLines) topCoreg.bursts.append(copyBurst) - ####################################################### + ####################################################### + - - slvBurst = secondary.bursts[jj+1] + secBurst = secondary.bursts[jj+1] outname = os.path.join(outdir, 'burst_bot_%02d_%02d.slc'%(ii+1,ii+2)) - - ####Setup initial polynomials - ### If no misregs are given, these are zero - ### If provided, can be used for resampling without running to geo2rdr again for fast results + + ####Setup initial polynomials + ### If no misregs are given, these are zero + ### If provided, can be used for resampling without running to geo2rdr again for fast results rdict = {'azpoly' : apoly, - 'rgpoly' : rpoly, - 'rangeOff' : os.path.join(offdir, 'range_bot_%02d_%02d.off'%(ii+1,ii+2)), - 'azimuthOff': os.path.join(offdir, 'azimuth_bot_%02d_%02d.off'%(ii+1,ii+2))} - - azCarrPoly, dpoly = secondary.estimateAzimuthCarrierPolynomials(slvBurst, offset = -1.0 * offset) - + 'rgpoly' : rpoly, + 'rangeOff' : os.path.join(offdir, 'range_bot_%02d_%02d.off'%(ii+1,ii+2)), + 'azimuthOff': os.path.join(offdir, 'azimuth_bot_%02d_%02d.off'%(ii+1,ii+2))} + + azCarrPoly, dpoly = secondary.estimateAzimuthCarrierPolynomials(secBurst, offset = -1.0 * offset) rdict['carrPoly'] = azCarrPoly rdict['doppPoly'] = dpoly - - outimg = resampSecondary(botBurst, slvBurst, rdict, outname, (not inps.noflat)) - + + outimg = resampSecondary(botBurst, secBurst, rdict, outname, (not inps.noflat)) + copyBurst = copy.deepcopy(botBurst) ut.adjustValidSampleLine(copyBurst) copyBurst.image.filename = outimg.filename print('After: ', copyBurst.firstValidLine, copyBurst.numValidLines) botCoreg.bursts.append(copyBurst) - ####################################################### + ####################################################### else: - outname = os.path.join(outdir, 'burst_%02d.slc'%(ii+1)) - - ####Setup initial polynomials - ### If no misregs are given, these are zero - ### If provided, can be used for resampling without running to geo2rdr again for fast results + + ####Setup initial polynomials + ### If no misregs are given, these are zero + ### If provided, can be used for resampling without running to geo2rdr again for fast results rdict = {'azpoly' : apoly, - 'rgpoly' : rpoly, - 'rangeOff' : os.path.join(offdir, 'range_%02d.off'%(ii+1)), - 'azimuthOff': os.path.join(offdir, 'azimuth_%02d.off'%(ii+1))} - - - ###For future - should account for azimuth and range misreg here .. ignoring for now. - azCarrPoly, dpoly = secondary.estimateAzimuthCarrierPolynomials(slvBurst, offset = -1.0 * offset) - + 'rgpoly' : rpoly, + 'rangeOff' : os.path.join(offdir, 'range_%02d.off'%(ii+1)), + 'azimuthOff': os.path.join(offdir, 'azimuth_%02d.off'%(ii+1))} + + + ###For future - should account for azimuth and range misreg here .. ignoring for now. + azCarrPoly, dpoly = secondary.estimateAzimuthCarrierPolynomials(secBurst, offset = -1.0 * offset) rdict['carrPoly'] = azCarrPoly rdict['doppPoly'] = dpoly - - outimg = resampSecondary(topBurst, slvBurst, rdict, outname, (not inps.noflat)) - minAz, maxAz, minRg, maxRg = ut.getValidLines(slvBurst, rdict, outname, + + outimg = resampSecondary(topBurst, secBurst, rdict, outname, (not inps.noflat)) + minAz, maxAz, minRg, maxRg = ut.getValidLines(secBurst, rdict, outname, misreg_az = misreg_az - offset, misreg_rng = misreg_rg) - + copyBurst = copy.deepcopy(topBurst) - ut.adjustValidSampleLine_V2(copyBurst, slvBurst, minAz=minAz, maxAz=maxAz, - minRng=minRg, maxRng=maxRg) + ut.adjustValidSampleLine_V2(copyBurst, secBurst, minAz=minAz, maxAz=maxAz, minRng=minRg, maxRng=maxRg) copyBurst.image.filename = outimg.filename print('After: ', copyBurst.firstValidLine, copyBurst.numValidLines) topCoreg.bursts.append(copyBurst) - ####################################################### - + + ####################################################### topCoreg.numberOfBursts = len(topCoreg.bursts) topCoreg.source = ut.asBaseClass(secondary) @@ -290,12 +292,10 @@ def main(iargs=None): topCoreg.reference = reference ut.saveProduct(topCoreg, outdir + '.xml') + if __name__ == '__main__': ''' Main driver. ''' # Main Driver main() - - - From 734c2dc9ca51ed3c0a9c0d5df87a24f7d1c19f93 Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Sat, 31 Dec 2022 00:25:00 -0800 Subject: [PATCH 4/4] README: fix typo + add Liang et al. (2019) for S1 iono reference --- contrib/stack/README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/contrib/stack/README.md b/contrib/stack/README.md index 7303de7f..56750bb2 100644 --- a/contrib/stack/README.md +++ b/contrib/stack/README.md @@ -16,7 +16,7 @@ To use a stack processor you need to: The stack processors do not show up in the install directory of your isce software. They can be found in the isce source directory. Thus, extra path setup is needed. -2.1 Add the following path to your `${PYTHON_PATH}` environment vavriable: +2.1 Add the following path to your `${PYTHONPATH}` environment vavriable: ```bash export ISCE_STACK={full_path_to_your_contrib/stack} @@ -53,24 +53,27 @@ Users who use the stack processors may refer to the following literatures: For TOPS stack processing: -+ H. Fattahi, P. Agram, and M. Simons, “A network-based enhanced spectral diversity approach for TOPS time-series analysis,” IEEE Trans. Geosci. Remote Sens., vol. 55, no. 2, pp. 777–786, Feb. 2017. (https://ieeexplore.ieee.org/abstract/document/7637021/) ++ Fattahi, H., Agram, P., & Simons, M. (2017). A Network-Based Enhanced Spectral Diversity Approach for TOPS Time-Series Analysis. _IEEE Trans. Geosci. Remote Sens., 55_(2), 777-786, doi: [10.1109/TGRS.2016.2614925](https://doi.org/10.1109/TGRS.2016.2614925) + +1. Ionospheric correction + ++ Liang, C., Agram, P., Simons, M., & Fielding, E. J. (2019). Ionospheric Correction of InSAR Time Series Analysis of C-band Sentinel-1 TOPS Data. _IEEE Trans. Geosci. Remote Sens., 59_(9), 6755-6773, doi: [10.1109/TGRS.2019.2908494](https://doi.org/10.1109/TGRS.2019.2908494). For StripMap stack processor and ionospheric phase estimation: -+ H. Fattahi, M. Simons, and P. Agram, "InSAR Time-Series Estimation of the Ionospheric Phase Delay: An Extension of the Split Range-Spectrum Technique", IEEE Trans. Geosci. Remote Sens., vol. 55, no. 10, 5984-5996, 2017. (https://ieeexplore.ieee.org/abstract/document/7987747/) ++ Fattahi, H., Simons, M., & Agram, P. (2017). InSAR Time-Series Estimation of the Ionospheric Phase Delay: An Extension of the Split Range-Spectrum Technique. _IEEE Trans. Geosci. Remote Sens., 55_(10), 5984-5996, doi: [10.1109/TGRS.2017.2718566](https://doi.org/10.1109/TGRS.2017.2718566) For ALOS and ALOS-2 stack processing: 1. ScanSAR or multi-mode InSAR processing -+ C. Liang and E. J. Fielding, "Interferometry with ALOS-2 full-aperture ScanSAR data," IEEE Transactions on Geoscience and Remote Sensing, vol. 55, no. 5, pp. 2739-2750, May 2017. ++ Liang, C., & Fielding, E. J. (2017). Interferometry With ALOS-2 Full-Aperture ScanSAR Data. _IEEE Trans. Geosci. Remote Sens., 55_(5), 2739-2750, doi: [10.1109/TGRS.2017.2653190](https://doi.org/10.1109/TGRS.2017.2653190) 2. Ionospheric correction, burst-by-burst ScanSAR processing, and burst-mode spectral diversity (SD) or multi-aperture InSAR (MAI) processing -+ C. Liang and E. J. Fielding, "Measuring azimuth deformation with L-band ALOS-2 ScanSAR interferometry," IEEE Transactions on Geoscience and Remote Sensing, vol. 55, no. 5, pp. 2725-2738, May 2017. ++ Liang, C., & Fielding, E. J. (2017). Measuring Azimuth Deformation With L-Band ALOS-2 ScanSAR Interferometry. _IEEE Trans. Geosci. Remote Sens., 55_(5), 2725-2738, doi: [10.1109/TGRS.2017.2653186](https://doi.org/10.1109/TGRS.2017.2653186) 3. Ionospheric correction -+ C. Liang, Z. Liu, E. J. Fielding, and R. Bürgmann, "InSAR time series analysis of L-band wide-swath SAR data acquired by ALOS-2," IEEE Transactions on Geoscience and Remote Sensing, vol. 56, no. 8, pp. 4492-4506, Aug. 2018. - ++ Liang, C., Liu, Z., Fielding, E. J., & Bürgmann, R. (2018). InSAR Time Series Analysis of L-Band Wide-Swath SAR Data Acquired by ALOS-2. _IEEE Trans. Geosci. Remote Sens., 56_(8), 4492-4506, doi: [10.1109/TGRS.2018.2821150](https://doi.org/10.1109/TGRS.2018.2821150)