From f7f0113603cdc898af9bf088a8df2a4ff83629a3 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Thu, 25 May 2023 11:42:54 -0800 Subject: [PATCH 01/12] Apply nasa-jpl/autoRIFT#78 --- hyp3_autorift/vend/testGeogrid_ISCE.py | 61 ++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/hyp3_autorift/vend/testGeogrid_ISCE.py b/hyp3_autorift/vend/testGeogrid_ISCE.py index e79a7fe2..ddf55859 100755 --- a/hyp3_autorift/vend/testGeogrid_ISCE.py +++ b/hyp3_autorift/vend/testGeogrid_ISCE.py @@ -68,6 +68,10 @@ def cmdLineParse(): help='Input stable surface mask') parser.add_argument('-fo', '--flag_optical', dest='optical_flag', type=bool, required=False, default=0, help='flag for reading optical data (e.g. Landsat): use 1 for on and 0 (default) for off') + parser.add_argument('-b', '--buffer', dest='buffer', type=bool, required=False, default=0, + help='buffer to add to the starting/end range accounting for all passes from the same relative orbit') + parser.add_argument('-p', '--parse', dest='parse', action='store_true', + default=False, help='Parse the SAFE zip file to get radar image and orbit metadata; no need to run ISCE') return parser.parse_args() @@ -114,7 +118,7 @@ def getMergedOrbit(product): return orb -def loadMetadata(indir): +def loadMetadata(indir,buffer=0): ''' Input file. ''' @@ -136,12 +140,57 @@ def loadMetadata(indir): info.prf = 1.0 / frames[0].bursts[0].azimuthTimeInterval info.rangePixelSize = frames[0].bursts[0].rangePixelSize info.lookSide = -1 + + info.startingRange -= buffer * info.rangePixelSize + info.farRange += buffer * info.rangePixelSize + info.numberOfLines = int( np.round( (info.sensingStop - info.sensingStart).total_seconds() * info.prf)) + 1 - info.numberOfSamples = int( np.round( (info.farRange - info.startingRange)/info.rangePixelSize)) + 1 + info.numberOfSamples = int( np.round( (info.farRange - info.startingRange)/info.rangePixelSize)) + 1 + 2 * buffer info.orbit = getMergedOrbit(frames) return info +def loadParsedata(indir,buffer=0): + ''' + Input file. + ''' + import os + import numpy as np + import isce + from isceobj.Sensor.TOPS.Sentinel1 import Sentinel1 + + + frames = [] + for swath in range(1,4): + rdr=Sentinel1() + rdr.configure() +# rdr.safe=['./S1A_IW_SLC__1SDH_20180401T100057_20180401T100124_021272_024972_8CAF.zip'] + rdr.safe=[indir] + rdr.output='reference' + rdr.orbitDir='/Users/yanglei/orbit/S1A/precise' + rdr.auxDir='/Users/yanglei/orbit/S1A/aux' + rdr.swathNumber=swath + rdr.polarization='hh' + rdr.parse() + frames.append(rdr.product) + + info = Dummy() + info.sensingStart = min([x.sensingStart for x in frames]) + info.sensingStop = max([x.sensingStop for x in frames]) + info.startingRange = min([x.startingRange for x in frames]) + info.farRange = max([x.farRange for x in frames]) + info.prf = 1.0 / frames[0].bursts[0].azimuthTimeInterval + info.rangePixelSize = frames[0].bursts[0].rangePixelSize + info.lookSide = -1 + + info.startingRange -= buffer * info.rangePixelSize + info.farRange += buffer * info.rangePixelSize + + info.numberOfLines = int( np.round( (info.sensingStop - info.sensingStart).total_seconds() * info.prf)) + 1 + info.numberOfSamples = int( np.round( (info.farRange - info.startingRange)/info.rangePixelSize)) + 1 + 2 * buffer + info.orbit = getMergedOrbit(frames) + + return info def coregisterLoadMetadataOptical(indir_m, indir_s, **kwargs): ''' @@ -390,8 +439,12 @@ def main(): metadata_m, metadata_s = coregisterLoadMetadataOptical(inps.indir_m, inps.indir_s) runGeogridOptical(metadata_m, metadata_s, inps.demfile, inps.dhdxfile, inps.dhdyfile, inps.vxfile, inps.vyfile, inps.srxfile, inps.sryfile, inps.csminxfile, inps.csminyfile, inps.csmaxxfile, inps.csmaxyfile, inps.ssmfile) else: - metadata_m = loadMetadata(inps.indir_m) - metadata_s = loadMetadata(inps.indir_s) + if inps.parse: + metadata_m = loadParsedata(inps.indir_m,inps.buffer) + metadata_s = loadParsedata(inps.indir_s,inps.buffer) + else: + metadata_m = loadMetadata(inps.indir_m,inps.buffer) + metadata_s = loadMetadata(inps.indir_s,inps.buffer) runGeogrid(metadata_m, metadata_s, inps.demfile, inps.dhdxfile, inps.dhdyfile, inps.vxfile, inps.vyfile, inps.srxfile, inps.sryfile, inps.csminxfile, inps.csminyfile, inps.csmaxxfile, inps.csmaxyfile, inps.ssmfile) From 5af781ee241f83fd17c8e23de231c55ded4225a5 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Thu, 25 May 2023 17:13:33 -0800 Subject: [PATCH 02/12] Initial workflow that runs through --- hyp3_autorift/__main__.py | 64 +++++++------------------ hyp3_autorift/process.py | 58 ++++++++++++++++++----- hyp3_autorift/s1_correction.py | 65 ++++++++++++++++++++++++++ hyp3_autorift/vend/testGeogrid_ISCE.py | 6 +-- setup.py | 4 +- 5 files changed, 133 insertions(+), 64 deletions(-) create mode 100644 hyp3_autorift/s1_correction.py diff --git a/hyp3_autorift/__main__.py b/hyp3_autorift/__main__.py index 022f9f13..01f98008 100644 --- a/hyp3_autorift/__main__.py +++ b/hyp3_autorift/__main__.py @@ -2,63 +2,33 @@ AutoRIFT processing for HyP3 """ -import os -from argparse import ArgumentParser - -from hyp3lib.aws import upload_file_to_s3 -from hyp3lib.fetch import write_credentials_to_netrc_file -from hyp3lib.image import create_thumbnail - -from hyp3_autorift.process import DEFAULT_PARAMETER_FILE, get_datetime, process - - -def check_earthdata_credentials(username, password): - if username is None: - username = os.getenv('EARTHDATA_USERNAME') - if password is None: - password = os.getenv('EARTHDATA_PASSWORD') - - return username, password +import argparse +import os +import sys +from importlib.metadata import entry_points def main(): - parser = ArgumentParser() - parser.add_argument('--username', help='NASA Earthdata Login username for fetching Sentinel-1 scenes') - parser.add_argument('--password', help='NASA Earthdata Login password for fetching Sentinel-1 scenes') - parser.add_argument('--bucket', help='AWS bucket to upload product files to') - parser.add_argument('--bucket-prefix', default='', help='AWS prefix (location in bucket) to add to product files') - parser.add_argument('--parameter-file', default=DEFAULT_PARAMETER_FILE, - help='Shapefile for determining the correct search parameters by ' - 'geographic location. ' - 'Path to shapefile must be understood by GDAL') - parser.add_argument('--naming-scheme', default='ITS_LIVE_OD', choices=['ITS_LIVE_OD', 'ITS_LIVE_PROD', 'ASF'], - help='Naming scheme to use for product files') - parser.add_argument('--omp-num-threads', type=int, help='The number of OpenMP threads to use for parallel regions') - parser.add_argument('granules', type=str.split, nargs='+', - help='Granule pair to process') - args = parser.parse_args() - username, password = check_earthdata_credentials(args.username, args.password) + parser = argparse.ArgumentParser(prefix_chars='+', formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument( + '++process', choices=['hyp3_autorift', 's1_correction'], default='hyp3_autorift', + help='Select the console_script entrypoint to use' # console_script entrypoints are specified in `setup.py` + ) + parser.add_argument('++omp-num-threads', type=int, help='The number of OpenMP threads to use for parallel regions') - args.granules = [item for sublist in args.granules for item in sublist] - if len(args.granules) != 2: - parser.error('Must provide exactly two granules') + args, unknowns = parser.parse_known_args() if args.omp_num_threads: os.environ['OMP_NUM_THREADS'] = str(args.omp_num_threads) - if username and password: - write_credentials_to_netrc_file(username, password) - - g1, g2 = sorted(args.granules, key=get_datetime) - - product_file, browse_file = process(g1, g2, parameter_file=args.parameter_file, naming_scheme=args.naming_scheme) + eps = entry_points()['console_scripts'] + (process_entry_point,) = {process for process in eps if process.name == args.process} - if args.bucket: - upload_file_to_s3(product_file, args.bucket, args.bucket_prefix) - upload_file_to_s3(browse_file, args.bucket, args.bucket_prefix) - thumbnail_file = create_thumbnail(browse_file) - upload_file_to_s3(thumbnail_file, args.bucket, args.bucket_prefix) + sys.argv = [args.process, *unknowns] + sys.exit( + process_entry_point.load()() + ) if __name__ == '__main__': diff --git a/hyp3_autorift/process.py b/hyp3_autorift/process.py index ddb03830..6e9c8d57 100644 --- a/hyp3_autorift/process.py +++ b/hyp3_autorift/process.py @@ -17,8 +17,10 @@ import botocore.exceptions import numpy as np import requests -from hyp3lib.fetch import download_file +from hyp3lib.aws import upload_file_to_s3 +from hyp3lib.fetch import download_file, write_credentials_to_netrc_file from hyp3lib.get_orb import downloadSentinelOrbitFile +from hyp3lib.image import create_thumbnail from hyp3lib.scene import get_download_url from netCDF4 import Dataset from osgeo import gdal @@ -331,7 +333,7 @@ def process(reference: str, secondary: str, parameter_file: str = DEFAULT_PARAME secondary_path = None reference_metadata = None secondary_metadata = None - reference_zero_path = None + rcdeference_zero_path = None secondary_zero_path = None reference_state_vec = None secondary_state_vec = None @@ -492,20 +494,52 @@ def process(reference: str, secondary: str, parameter_file: str = DEFAULT_PARAME return product_file, browse_file +def check_earthdata_credentials(username, password): + if username is None: + username = os.getenv('EARTHDATA_USERNAME') + + if password is None: + password = os.getenv('EARTHDATA_PASSWORD') + + return username, password + + def main(): - """Main entrypoint""" parser = argparse.ArgumentParser( - prog=os.path.basename(__file__), - description=__doc__, + formatter_class=argparse.ArgumentDefaultsHelpFormatter ) - parser.add_argument('reference', type=os.path.abspath, - help='Reference Sentinel-1, Sentinel-2, or Landsat-8 Collection 2 scene') - parser.add_argument('secondary', type=os.path.abspath, - help='Secondary Sentinel-1, Sentinel-2, or Landsat-8 Collection 2 scene') + parser.add_argument('--username', help='NASA Earthdata Login username for fetching Sentinel-1 scenes') + parser.add_argument('--password', help='NASA Earthdata Login password for fetching Sentinel-1 scenes') + parser.add_argument('--bucket', help='AWS bucket to upload product files to') + parser.add_argument('--bucket-prefix', default='', help='AWS prefix (location in bucket) to add to product files') + parser.add_argument('--parameter-file', default=DEFAULT_PARAMETER_FILE, + help='Shapefile for determining the correct search parameters by geographic location. ' + 'Path to shapefile must be understood by GDAL') + parser.add_argument('--naming-scheme', default='ITS_LIVE_OD', choices=['ITS_LIVE_OD', 'ITS_LIVE_PROD', 'ASF'], + help='Naming scheme to use for product files') + parser.add_argument('--omp-num-threads', type=int, help='The number of OpenMP threads to use for parallel regions') + parser.add_argument('granules', type=str.split, nargs='+', + help='Granule pair to process') args = parser.parse_args() + username, password = check_earthdata_credentials(args.username, args.password) + + args.granules = [item for sublist in args.granules for item in sublist] + if len(args.granules) != 2: + parser.error('Must provide exactly two granules') + + if args.omp_num_threads: + os.environ['OMP_NUM_THREADS'] = str(args.omp_num_threads) + + if username and password: + write_credentials_to_netrc_file(username, password) + + g1, g2 = sorted(args.granules, key=get_datetime) - process(**args.__dict__) + product_file, browse_file = process(g1, g2, parameter_file=args.parameter_file, naming_scheme=args.naming_scheme) + if args.bucket: + upload_file_to_s3(product_file, args.bucket, args.bucket_prefix) + upload_file_to_s3(browse_file, args.bucket, args.bucket_prefix) + thumbnail_file = create_thumbnail(browse_file) + upload_file_to_s3(thumbnail_file, args.bucket, args.bucket_prefix) -if __name__ == "__main__": - main() diff --git a/hyp3_autorift/s1_correction.py b/hyp3_autorift/s1_correction.py new file mode 100644 index 00000000..bc5ea33a --- /dev/null +++ b/hyp3_autorift/s1_correction.py @@ -0,0 +1,65 @@ +import argparse +import logging +from pathlib import Path + +from hyp3lib.aws import upload_file_to_s3 +from hyp3lib.fetch import download_file, write_credentials_to_netrc_file +from hyp3lib.get_orb import downloadSentinelOrbitFile +from hyp3lib.scene import get_download_url + +from hyp3_autorift import geometry, io +from hyp3_autorift.process import DEFAULT_PARAMETER_FILE, check_earthdata_credentials, get_s1_primary_polarization +from hyp3_autorift.vend.testGeogrid_ISCE import loadParsedata, runGeogrid +log = logging.getLogger(__name__) + + +def generate_correction_data(scene: str, buffer: int = 0, parameter_file: str = DEFAULT_PARAMETER_FILE): + scene_path = Path(f'{scene}.zip') + if not scene_path.exists(): + scene_url = get_download_url(scene) + scene_path = download_file(scene_url, chunk_size=5242880) + + orbits = Path('Orbits').resolve() + orbits.mkdir(parents=True, exist_ok=True) + state_vec, oribit_provider = downloadSentinelOrbitFile(scene, directory=str(orbits)) + log.info(f'Downloaded orbit file {state_vec} from {oribit_provider}') + + polarization = get_s1_primary_polarization(scene) + lat_limits, lon_limits = geometry.bounding_box(f'{scene}.zip', polarization=polarization, orbits=orbits) + + scene_poly = geometry.polygon_from_bbox(x_limits=lat_limits, y_limits=lon_limits) + parameter_info = io.find_jpl_parameter_info(scene_poly, parameter_file) + + isce_dem = geometry.prep_isce_dem(parameter_info['geogrid']['dem'], lat_limits, lon_limits) + io.format_tops_xml(scene, scene, polarization, isce_dem, orbits) + + scene_meta = loadParsedata(str(scene_path), orbit_dir=orbits, aux_dir=orbits, buffer=buffer) + geogrid_info = runGeogrid(scene_meta, scene_meta, epsg=parameter_info['epsg'], **parameter_info['geogrid']) + + return geogrid_info + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument('--username', help='NASA Earthdata Login username for fetching Sentinel-1 scenes') + parser.add_argument('--password', help='NASA Earthdata Login password for fetching Sentinel-1 scenes') + parser.add_argument('--bucket', help='AWS bucket to upload product files to') + parser.add_argument('--bucket-prefix', default='', help='AWS prefix (location in bucket) to add to product files') + parser.add_argument('--buffer', type=int, default=0, help='Number of pixels to buffer each edge of the input scene') + parser.add_argument('--parameter-file', default=DEFAULT_PARAMETER_FILE, + help='Shapefile for determining the correct search parameters by geographic location. ' + 'Path to shapefile must be understood by GDAL') + parser.add_argument('granule', help='Reference granule to process') + args = parser.parse_args() + + username, password = check_earthdata_credentials(args.username, args.password) + if username and password: + write_credentials_to_netrc_file(username, password) + + _ = generate_correction_data(args.granule, buffer=args.buffer) + + if args.bucket: + for geotiff in Path.cwd().glob('*.tif'): + upload_file_to_s3(geotiff, args.bucket, args.bucket_prefix) diff --git a/hyp3_autorift/vend/testGeogrid_ISCE.py b/hyp3_autorift/vend/testGeogrid_ISCE.py index ddf55859..a20f7a95 100755 --- a/hyp3_autorift/vend/testGeogrid_ISCE.py +++ b/hyp3_autorift/vend/testGeogrid_ISCE.py @@ -150,7 +150,7 @@ def loadMetadata(indir,buffer=0): return info -def loadParsedata(indir,buffer=0): +def loadParsedata(indir, orbit_dir, aux_dir, buffer=0): ''' Input file. ''' @@ -167,8 +167,8 @@ def loadParsedata(indir,buffer=0): # rdr.safe=['./S1A_IW_SLC__1SDH_20180401T100057_20180401T100124_021272_024972_8CAF.zip'] rdr.safe=[indir] rdr.output='reference' - rdr.orbitDir='/Users/yanglei/orbit/S1A/precise' - rdr.auxDir='/Users/yanglei/orbit/S1A/aux' + rdr.orbitDir=orbit_dir + rdr.auxDir=aux_dir rdr.swathNumber=swath rdr.polarization='hh' rdr.parse() diff --git a/setup.py b/setup.py index 14a0524c..d923cc8f 100644 --- a/setup.py +++ b/setup.py @@ -62,8 +62,8 @@ packages=find_packages(), entry_points={'console_scripts': [ - 'hyp3_autorift = hyp3_autorift.__main__:main', - 'autorift_proc_pair = hyp3_autorift.process:main', + 'hyp3_autorift = hyp3_autorift.process:main', + 's1_correction = hyp3_autorift.s1_correction:main' ] }, From 3f1d1441ea01f6a98c03ec45e3952ee03baca5cb Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 26 May 2023 11:43:48 -0800 Subject: [PATCH 03/12] Move opt-num-threads to __main__ --- hyp3_autorift/process.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hyp3_autorift/process.py b/hyp3_autorift/process.py index 6e9c8d57..308318d8 100644 --- a/hyp3_autorift/process.py +++ b/hyp3_autorift/process.py @@ -517,7 +517,6 @@ def main(): 'Path to shapefile must be understood by GDAL') parser.add_argument('--naming-scheme', default='ITS_LIVE_OD', choices=['ITS_LIVE_OD', 'ITS_LIVE_PROD', 'ASF'], help='Naming scheme to use for product files') - parser.add_argument('--omp-num-threads', type=int, help='The number of OpenMP threads to use for parallel regions') parser.add_argument('granules', type=str.split, nargs='+', help='Granule pair to process') args = parser.parse_args() @@ -527,9 +526,6 @@ def main(): if len(args.granules) != 2: parser.error('Must provide exactly two granules') - if args.omp_num_threads: - os.environ['OMP_NUM_THREADS'] = str(args.omp_num_threads) - if username and password: write_credentials_to_netrc_file(username, password) From cdcc2420b0e421ec813aad3166df64c171c0ef0f Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 26 May 2023 11:48:16 -0800 Subject: [PATCH 04/12] move earthdata login handling to __main__ --- hyp3_autorift/__main__.py | 12 ++++++++++++ hyp3_autorift/process.py | 8 +------- hyp3_autorift/s1_correction.py | 10 ++-------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/hyp3_autorift/__main__.py b/hyp3_autorift/__main__.py index 01f98008..b49e65bf 100644 --- a/hyp3_autorift/__main__.py +++ b/hyp3_autorift/__main__.py @@ -6,7 +6,11 @@ import argparse import os import sys +import warnings from importlib.metadata import entry_points +from pathlib import Path + +from hyp3lib.fetch import write_credentials_to_netrc_file def main(): @@ -22,6 +26,14 @@ def main(): if args.omp_num_threads: os.environ['OMP_NUM_THREADS'] = str(args.omp_num_threads) + username = os.getenv('EARTHDATA_USERNAME') + password = os.getenv('EARTHDATA_PASSWORD') + if username and password: + write_credentials_to_netrc_file(username, password, append=False) + + if not (Path.home() / '.netrc').exists(): + warnings.warn('Earthdata credentials must be present as environment variables, or in your netrc.', UserWarning) + eps = entry_points()['console_scripts'] (process_entry_point,) = {process for process in eps if process.name == args.process} diff --git a/hyp3_autorift/process.py b/hyp3_autorift/process.py index 308318d8..c5c7ab4c 100644 --- a/hyp3_autorift/process.py +++ b/hyp3_autorift/process.py @@ -18,7 +18,7 @@ import numpy as np import requests from hyp3lib.aws import upload_file_to_s3 -from hyp3lib.fetch import download_file, write_credentials_to_netrc_file +from hyp3lib.fetch import download_file from hyp3lib.get_orb import downloadSentinelOrbitFile from hyp3lib.image import create_thumbnail from hyp3lib.scene import get_download_url @@ -508,8 +508,6 @@ def main(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter ) - parser.add_argument('--username', help='NASA Earthdata Login username for fetching Sentinel-1 scenes') - parser.add_argument('--password', help='NASA Earthdata Login password for fetching Sentinel-1 scenes') parser.add_argument('--bucket', help='AWS bucket to upload product files to') parser.add_argument('--bucket-prefix', default='', help='AWS prefix (location in bucket) to add to product files') parser.add_argument('--parameter-file', default=DEFAULT_PARAMETER_FILE, @@ -520,15 +518,11 @@ def main(): parser.add_argument('granules', type=str.split, nargs='+', help='Granule pair to process') args = parser.parse_args() - username, password = check_earthdata_credentials(args.username, args.password) args.granules = [item for sublist in args.granules for item in sublist] if len(args.granules) != 2: parser.error('Must provide exactly two granules') - if username and password: - write_credentials_to_netrc_file(username, password) - g1, g2 = sorted(args.granules, key=get_datetime) product_file, browse_file = process(g1, g2, parameter_file=args.parameter_file, naming_scheme=args.naming_scheme) diff --git a/hyp3_autorift/s1_correction.py b/hyp3_autorift/s1_correction.py index bc5ea33a..7c5bdced 100644 --- a/hyp3_autorift/s1_correction.py +++ b/hyp3_autorift/s1_correction.py @@ -3,12 +3,12 @@ from pathlib import Path from hyp3lib.aws import upload_file_to_s3 -from hyp3lib.fetch import download_file, write_credentials_to_netrc_file +from hyp3lib.fetch import download_file from hyp3lib.get_orb import downloadSentinelOrbitFile from hyp3lib.scene import get_download_url from hyp3_autorift import geometry, io -from hyp3_autorift.process import DEFAULT_PARAMETER_FILE, check_earthdata_credentials, get_s1_primary_polarization +from hyp3_autorift.process import DEFAULT_PARAMETER_FILE, get_s1_primary_polarization from hyp3_autorift.vend.testGeogrid_ISCE import loadParsedata, runGeogrid log = logging.getLogger(__name__) @@ -43,8 +43,6 @@ def main(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter ) - parser.add_argument('--username', help='NASA Earthdata Login username for fetching Sentinel-1 scenes') - parser.add_argument('--password', help='NASA Earthdata Login password for fetching Sentinel-1 scenes') parser.add_argument('--bucket', help='AWS bucket to upload product files to') parser.add_argument('--bucket-prefix', default='', help='AWS prefix (location in bucket) to add to product files') parser.add_argument('--buffer', type=int, default=0, help='Number of pixels to buffer each edge of the input scene') @@ -54,10 +52,6 @@ def main(): parser.add_argument('granule', help='Reference granule to process') args = parser.parse_args() - username, password = check_earthdata_credentials(args.username, args.password) - if username and password: - write_credentials_to_netrc_file(username, password) - _ = generate_correction_data(args.granule, buffer=args.buffer) if args.bucket: From fe5b4f67ca843aee08070895deea8b6fe542f9ed Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 26 May 2023 11:51:17 -0800 Subject: [PATCH 05/12] fix lint,typos --- hyp3_autorift/process.py | 3 +- hyp3_autorift/vend/nasa-jpl_autorift_78.diff | 98 ++++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 hyp3_autorift/vend/nasa-jpl_autorift_78.diff diff --git a/hyp3_autorift/process.py b/hyp3_autorift/process.py index c5c7ab4c..159c4652 100644 --- a/hyp3_autorift/process.py +++ b/hyp3_autorift/process.py @@ -333,7 +333,7 @@ def process(reference: str, secondary: str, parameter_file: str = DEFAULT_PARAME secondary_path = None reference_metadata = None secondary_metadata = None - rcdeference_zero_path = None + reference_zero_path = None secondary_zero_path = None reference_state_vec = None secondary_state_vec = None @@ -532,4 +532,3 @@ def main(): upload_file_to_s3(browse_file, args.bucket, args.bucket_prefix) thumbnail_file = create_thumbnail(browse_file) upload_file_to_s3(thumbnail_file, args.bucket, args.bucket_prefix) - diff --git a/hyp3_autorift/vend/nasa-jpl_autorift_78.diff b/hyp3_autorift/vend/nasa-jpl_autorift_78.diff new file mode 100644 index 00000000..67800c13 --- /dev/null +++ b/hyp3_autorift/vend/nasa-jpl_autorift_78.diff @@ -0,0 +1,98 @@ +diff --git a/testGeogrid_ISCE.py b/testGeogrid_ISCE.py +index 22ecdcf..bc9cb06 100755 +--- a/testGeogrid_ISCE.py ++++ b/testGeogrid_ISCE.py +@@ -67,6 +67,10 @@ def cmdLineParse(): + help='Input stable surface mask') + parser.add_argument('-fo', '--flag_optical', dest='optical_flag', type=bool, required=False, default=0, + help='flag for reading optical data (e.g. Landsat): use 1 for on and 0 (default) for off') ++ parser.add_argument('-b', '--buffer', dest='buffer', type=bool, required=False, default=0, ++ help='buffer to add to the starting/end range accounting for all passes from the same relative orbit') ++ parser.add_argument('-p', '--parse', dest='parse', action='store_true', ++ default=False, help='Parse the SAFE zip file to get radar image and orbit metadata; no need to run ISCE') + + return parser.parse_args() + +@@ -113,7 +117,7 @@ def getMergedOrbit(product): + return orb + + +-def loadMetadata(indir): ++def loadMetadata(indir,buffer=0): + ''' + Input file. + ''' +@@ -135,12 +139,57 @@ def loadMetadata(indir): + info.prf = 1.0 / frames[0].bursts[0].azimuthTimeInterval + info.rangePixelSize = frames[0].bursts[0].rangePixelSize + info.lookSide = -1 ++ ++ info.startingRange -= buffer * info.rangePixelSize ++ info.farRange += buffer * info.rangePixelSize ++ + info.numberOfLines = int( np.round( (info.sensingStop - info.sensingStart).total_seconds() * info.prf)) + 1 +- info.numberOfSamples = int( np.round( (info.farRange - info.startingRange)/info.rangePixelSize)) + 1 ++ info.numberOfSamples = int( np.round( (info.farRange - info.startingRange)/info.rangePixelSize)) + 1 + 2 * buffer + info.orbit = getMergedOrbit(frames) + + return info + ++def loadParsedata(indir,buffer=0): ++ ''' ++ Input file. ++ ''' ++ import os ++ import numpy as np ++ import isce ++ from isceobj.Sensor.TOPS.Sentinel1 import Sentinel1 ++ ++ ++ frames = [] ++ for swath in range(1,4): ++ rdr=Sentinel1() ++ rdr.configure() ++# rdr.safe=['./S1A_IW_SLC__1SDH_20180401T100057_20180401T100124_021272_024972_8CAF.zip'] ++ rdr.safe=[indir] ++ rdr.output='reference' ++ rdr.orbitDir='/Users/yanglei/orbit/S1A/precise' ++ rdr.auxDir='/Users/yanglei/orbit/S1A/aux' ++ rdr.swathNumber=swath ++ rdr.polarization='hh' ++ rdr.parse() ++ frames.append(rdr.product) ++ ++ info = Dummy() ++ info.sensingStart = min([x.sensingStart for x in frames]) ++ info.sensingStop = max([x.sensingStop for x in frames]) ++ info.startingRange = min([x.startingRange for x in frames]) ++ info.farRange = max([x.farRange for x in frames]) ++ info.prf = 1.0 / frames[0].bursts[0].azimuthTimeInterval ++ info.rangePixelSize = frames[0].bursts[0].rangePixelSize ++ info.lookSide = -1 ++ ++ info.startingRange -= buffer * info.rangePixelSize ++ info.farRange += buffer * info.rangePixelSize ++ ++ info.numberOfLines = int( np.round( (info.sensingStop - info.sensingStart).total_seconds() * info.prf)) + 1 ++ info.numberOfSamples = int( np.round( (info.farRange - info.startingRange)/info.rangePixelSize)) + 1 + 2 * buffer ++ info.orbit = getMergedOrbit(frames) ++ ++ return info + + def coregisterLoadMetadataOptical(indir_m, indir_s): + ''' +@@ -383,8 +432,12 @@ def main(): + metadata_m, metadata_s = coregisterLoadMetadataOptical(inps.indir_m, inps.indir_s) + runGeogridOptical(metadata_m, metadata_s, inps.demfile, inps.dhdxfile, inps.dhdyfile, inps.vxfile, inps.vyfile, inps.srxfile, inps.sryfile, inps.csminxfile, inps.csminyfile, inps.csmaxxfile, inps.csmaxyfile, inps.ssmfile) + else: +- metadata_m = loadMetadata(inps.indir_m) +- metadata_s = loadMetadata(inps.indir_s) ++ if inps.parse: ++ metadata_m = loadParsedata(inps.indir_m,inps.buffer) ++ metadata_s = loadParsedata(inps.indir_s,inps.buffer) ++ else: ++ metadata_m = loadMetadata(inps.indir_m,inps.buffer) ++ metadata_s = loadMetadata(inps.indir_s,inps.buffer) + runGeogrid(metadata_m, metadata_s, inps.demfile, inps.dhdxfile, inps.dhdyfile, inps.vxfile, inps.vyfile, inps.srxfile, inps.sryfile, inps.csminxfile, inps.csminyfile, inps.csmaxxfile, inps.csmaxyfile, inps.ssmfile) + + From 392c30a15a8cdf898f55f37614663ca90d0e587f Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 26 May 2023 11:55:57 -0800 Subject: [PATCH 06/12] fix tests --- tests/test_entrypoints.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_entrypoints.py b/tests/test_entrypoints.py index 41e2147f..fa5a1834 100644 --- a/tests/test_entrypoints.py +++ b/tests/test_entrypoints.py @@ -4,5 +4,5 @@ def test_hyp3_autorift(script_runner): def test_autorift_proc_pair(script_runner): - ret = script_runner.run('autorift_proc_pair', '-h') + ret = script_runner.run('s1_correction', '-h') assert ret.success From 81a91a255589f8647b5809895160031f1b609c24 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 26 May 2023 11:57:14 -0800 Subject: [PATCH 07/12] drop unused fn --- hyp3_autorift/process.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/hyp3_autorift/process.py b/hyp3_autorift/process.py index 159c4652..0138d688 100644 --- a/hyp3_autorift/process.py +++ b/hyp3_autorift/process.py @@ -494,16 +494,6 @@ def process(reference: str, secondary: str, parameter_file: str = DEFAULT_PARAME return product_file, browse_file -def check_earthdata_credentials(username, password): - if username is None: - username = os.getenv('EARTHDATA_USERNAME') - - if password is None: - password = os.getenv('EARTHDATA_PASSWORD') - - return username, password - - def main(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter From 538ca5c8cba66dbc617aa7fdb9717449f531df09 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 26 May 2023 11:58:51 -0800 Subject: [PATCH 08/12] lint --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d923cc8f..5fd55996 100644 --- a/setup.py +++ b/setup.py @@ -63,7 +63,7 @@ entry_points={'console_scripts': [ 'hyp3_autorift = hyp3_autorift.process:main', - 's1_correction = hyp3_autorift.s1_correction:main' + 's1_correction = hyp3_autorift.s1_correction:main', ] }, From 09e882e0d07b79e4186eb8397761189cf4b360df Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 9 Jun 2023 17:33:55 -0800 Subject: [PATCH 09/12] Use reference as secondary but with a fixed (false) dt to preven divide by zero errors --- hyp3_autorift/s1_correction.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hyp3_autorift/s1_correction.py b/hyp3_autorift/s1_correction.py index 7c5bdced..aea57113 100644 --- a/hyp3_autorift/s1_correction.py +++ b/hyp3_autorift/s1_correction.py @@ -1,5 +1,7 @@ import argparse +import copy import logging +from datetime import timedelta from pathlib import Path from hyp3lib.aws import upload_file_to_s3 @@ -33,8 +35,14 @@ def generate_correction_data(scene: str, buffer: int = 0, parameter_file: str = isce_dem = geometry.prep_isce_dem(parameter_info['geogrid']['dem'], lat_limits, lon_limits) io.format_tops_xml(scene, scene, polarization, isce_dem, orbits) - scene_meta = loadParsedata(str(scene_path), orbit_dir=orbits, aux_dir=orbits, buffer=buffer) - geogrid_info = runGeogrid(scene_meta, scene_meta, epsg=parameter_info['epsg'], **parameter_info['geogrid']) + reference_meta = loadParsedata(str(scene_path), orbit_dir=orbits, aux_dir=orbits, buffer=buffer) + + secondary_meta = copy.deepcopy(reference_meta) + spoof_dt = timedelta(days=1) + secondary_meta.sensingStart += spoof_dt + secondary_meta.sensingStop += spoof_dt + + geogrid_info = runGeogrid(reference_meta, secondary_meta, epsg=parameter_info['epsg'], **parameter_info['geogrid']) return geogrid_info From fe047d30298b43588abe5f7df2ec8e37f3f92a37 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 9 Jun 2023 19:38:38 -0800 Subject: [PATCH 10/12] state changes for release --- CHANGELOG.md | 16 ++++++++++++++++ ...autorift_78.diff => CHANGES-UPSTREAM-78.diff} | 0 2 files changed, 16 insertions(+) rename hyp3_autorift/vend/{nasa-jpl_autorift_78.diff => CHANGES-UPSTREAM-78.diff} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0ace898..b8e8ac45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ 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.11.0] + +### Added +* `hyp3_autorift`'s main entrypoint now accepts `++process` arguments to support multiple workflows + * `++process hyp3_autorift` (default) will run the same autoRIFT pair processing workflow + * `++process s1_correction` will run a Geogrid-only workflow to create the GeoTIFFs necessary to correct a + scale-projection issue in polar-sterographic products generated from Sentinel-1 pairs that were created using + HyP3 autoRIFT versions < 0.9.0, which was released November 2, 2022 + +### Changed +* Patch [nasa-jpl/autorift#78](hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff) was applied from upstream to support the + Sentinel-1 correction workflow + +### Removed +* The unused `autorift_proc_pair` console script entrypoint was removed + ## [0.10.5] ### Fixed diff --git a/hyp3_autorift/vend/nasa-jpl_autorift_78.diff b/hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff similarity index 100% rename from hyp3_autorift/vend/nasa-jpl_autorift_78.diff rename to hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff From 0b0876e0367b3fa5b69c1ed9c05f7aa347caa059 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 9 Jun 2023 19:39:53 -0800 Subject: [PATCH 11/12] cleanup changes diff --- hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff b/hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff index 67800c13..2a13dc87 100644 --- a/hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff +++ b/hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff @@ -1,7 +1,6 @@ -diff --git a/testGeogrid_ISCE.py b/testGeogrid_ISCE.py -index 22ecdcf..bc9cb06 100755 ---- a/testGeogrid_ISCE.py -+++ b/testGeogrid_ISCE.py +diff --git testGeogrid_ISCE.py testGeogrid_ISCE.py +--- testGeogrid_ISCE.py ++++ testGeogrid_ISCE.py @@ -67,6 +67,10 @@ def cmdLineParse(): help='Input stable surface mask') parser.add_argument('-fo', '--flag_optical', dest='optical_flag', type=bool, required=False, default=0, From 12baaece4dd13791b8e2a5482648c1e3a55df235 Mon Sep 17 00:00:00 2001 From: Joseph H Kennedy Date: Fri, 9 Jun 2023 19:46:10 -0800 Subject: [PATCH 12/12] finish stating changes for release --- CHANGELOG.md | 6 +++--- hyp3_autorift/vend/README.md | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e8ac45..a97425b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,9 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added * `hyp3_autorift`'s main entrypoint now accepts `++process` arguments to support multiple workflows * `++process hyp3_autorift` (default) will run the same autoRIFT pair processing workflow - * `++process s1_correction` will run a Geogrid-only workflow to create the GeoTIFFs necessary to correct a - scale-projection issue in polar-sterographic products generated from Sentinel-1 pairs that were created using - HyP3 autoRIFT versions < 0.9.0, which was released November 2, 2022 + * `++process s1_correction` will run a Geogrid-only workflow to create the GeoTIFFs necessary for correcting the + scale-projection issue in polar-sterographic products generated from Sentinel-1 pairs that were created using HyP3 + autoRIFT versions < 0.9.0, which was released November 2, 2022 ### Changed * Patch [nasa-jpl/autorift#78](hyp3_autorift/vend/CHANGES-UPSTREAM-78.diff) was applied from upstream to support the diff --git a/hyp3_autorift/vend/README.md b/hyp3_autorift/vend/README.md index 5bbd28c6..d79d58e9 100644 --- a/hyp3_autorift/vend/README.md +++ b/hyp3_autorift/vend/README.md @@ -60,3 +60,7 @@ We've replaced it with `hyp3_autorift.io.get_topsinsar_config`. to fix the `noDataMask` used for the search range and %-valid pixel calculations. Unfortunately, this bug exists upstream but this fix is dependent on changes in (4) which are not easily applied upstream. Therefore, these changes are *not* expected to be applied upstream to `nasa-jpl/autoRIFT` without a significant refactor upstream. +8. The changes listed in `CHANGES-UPSTREAM-78.diff` were applied from upstream ([nasa-jpl/autorift#78](https://github.com/nasa-jpl/autorift/pull/78)) + in [ASFHyP3/hyp3-autorift#218](https://github.com/ASFHyP3/hyp3-autorift/pull/218) to run a Geogrid-only workflow to + create the GeoTIFFs necessary for correcting the scale-projection issue in polar-sterographic products generated + from Sentinel-1 pairs that were created using HyP3 autoRIFT versions < 0.9.0, which was released November 2, 2022