From 908f05fdf08bac9add8e8cd09eb6843781c8ea42 Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Tue, 29 Aug 2023 09:02:31 -0700 Subject: [PATCH 1/5] update tag and version of the RTC-S1 SAS to final v1.0.0 --- Docker/Dockerfile | 2 +- Docker/environment.yml | 2 +- build_docker_image.sh | 2 +- src/rtc/version.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Docker/Dockerfile b/Docker/Dockerfile index bbffc467..800e406f 100644 --- a/Docker/Dockerfile +++ b/Docker/Dockerfile @@ -2,7 +2,7 @@ FROM oraclelinux:8 LABEL author="OPERA ADT" \ description="RTC cal/val release R4" \ - version="0.4.2-calval" + version="1.0.0-final" RUN yum -y update &&\ yum -y install curl &&\ diff --git a/Docker/environment.yml b/Docker/environment.yml index 7ebdce7f..7126233f 100644 --- a/Docker/environment.yml +++ b/Docker/environment.yml @@ -1,4 +1,4 @@ -name: rtc_sas_final +name: rtc_s1_sas_final channels: - conda-forge dependencies: diff --git a/build_docker_image.sh b/build_docker_image.sh index 82f60ac2..dc788c99 100755 --- a/build_docker_image.sh +++ b/build_docker_image.sh @@ -2,7 +2,7 @@ REPO=opera IMAGE=rtc -TAG=final_0.5.0 +TAG=final_1.0.0 echo "IMAGE is $REPO/$IMAGE:$TAG" diff --git a/src/rtc/version.py b/src/rtc/version.py index 63b33ba8..7a58c6e8 100644 --- a/src/rtc/version.py +++ b/src/rtc/version.py @@ -1 +1 @@ -VERSION='0.4.2' +VERSION='1.0.0' From 7ebcf8106bb6360a848ccf997769356ffbcffe9a Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Wed, 30 Aug 2023 15:44:56 -0700 Subject: [PATCH 2/5] update product specs version to 1.0 --- src/rtc/h5_prep.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtc/h5_prep.py b/src/rtc/h5_prep.py index ace4ad7e..cb755c16 100644 --- a/src/rtc/h5_prep.py +++ b/src/rtc/h5_prep.py @@ -23,7 +23,7 @@ DATE_TIME_FILENAME_FORMAT = '%Y%m%dT%H%M%SZ' DATA_BASE_GROUP = '/data' -PRODUCT_SPECIFICATION_VERSION = 0.1 +PRODUCT_SPECIFICATION_VERSION = 1.0 logger = logging.getLogger('rtc_s1') From b2f7f501ed9518363bff96c93c07c87dd41066cb Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Wed, 30 Aug 2023 15:46:20 -0700 Subject: [PATCH 3/5] check for ancillary file discontinuities not happening exactly on the antimeridian --- src/rtc/core.py | 56 ++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/rtc/core.py b/src/rtc/core.py index 612ffd81..e6fb4b3d 100644 --- a/src/rtc/core.py +++ b/src/rtc/core.py @@ -248,9 +248,12 @@ def get_tile_srs_bbox(tile_min_y_projected, tile_max_y_projected, tile_max_x = np.max(tile_x_array) # handles antimeridian: tile_max_x around +180 and tile_min_x around -180 - # add 360 to tile_min_x, so it becomes a little greater than +180 - if tile_max_x > tile_min_x + 340: - tile_min_x, tile_max_x = tile_max_x, tile_min_x + 360 + if polygon_srs.IsGeographic() and tile_max_x - tile_min_x > 180: + # unwrap negative longitude values + # move longitude range from [-180, 180] to [0, 360] + new_tile_x_array = [x + (x < 0) * 360 for x in tile_x_array] + tile_min_x = np.min(new_tile_x_array) + tile_max_x = np.max(new_tile_x_array) tile_ring = ogr.Geometry(ogr.wkbLinearRing) tile_ring.AddPoint(tile_min_x, tile_max_y) @@ -265,7 +268,7 @@ def get_tile_srs_bbox(tile_min_y_projected, tile_max_y_projected, def _antimeridian_crossing_requires_special_handling( - file_srs, file_min_x, tile_min_x, tile_max_x): + file_srs, ancillary_min_x, ancillary_max_x, tile_min_x, tile_max_x): ''' Check if ancillary input requires special handling due to the antimeridian crossing @@ -274,8 +277,10 @@ def _antimeridian_crossing_requires_special_handling( ---------- file_srs: osr.SpatialReference Ancillary file spatial reference system (SRS) - file_min_x: float + ancillary_min_x: float Ancillary file min longitude value in degrees + ancillary_max_x: float + Ancillary file max longitude value in degrees tile_min_x: float Tile min longitude value in degrees tile_max_x: float @@ -287,24 +292,26 @@ def _antimeridian_crossing_requires_special_handling( Flag that indicate if the ancillary input requires special handling ''' - # Flag to indicate if the if the tile crosses the antimeridian. - flag_tile_crosses_antimeridian = tile_min_x < 180 and tile_max_x >= 180 - - # Flag to test if the ancillary input file is in geographic - # coordinates and if its longitude domain is represented - # within the [-180, +180] range, rather than, for example, inside - # the [0, +360] interval. - # This is verified by the test `min_x < -165`. There's no specific reason - # why -165 is used. It could be -160, or even 0. However, testing for - # -165 is more general than -160 or 0, but still not too close to -180. - flag_input_geographic_and_longitude_lt_m165 = \ - file_srs.IsGeographic() and file_min_x < -165 - - # If both are true, tile requires special handling due to the - # antimeridian crossing - flag_requires_special_handling = ( - flag_tile_crosses_antimeridian and - flag_input_geographic_and_longitude_lt_m165) + if not file_srs.IsGeographic(): + flag_requires_special_handling = False + return flag_requires_special_handling + + # Check whether the ancillary file covers the entire longitude range + # use 359 instead of 360 degrees to have some buffer + flag_ancillary_covers_entire_longitude_range = \ + (ancillary_max_x - ancillary_min_x) > 359 + + if not flag_ancillary_covers_entire_longitude_range: + flag_requires_special_handling = False + return flag_requires_special_handling + + # Flag to indicate if the tile crosses the ancillary file + # discontinuity (ancillary_max_x). + flag_tile_crosses_discontinuity = \ + tile_min_x < ancillary_max_x < tile_max_x + + flag_requires_special_handling = \ + flag_tile_crosses_discontinuity return flag_requires_special_handling @@ -430,7 +437,8 @@ def check_ancillary_inputs(check_ancillary_inputs_coverage, # If needed, test for antimeridian ("dateline") crossing if _antimeridian_crossing_requires_special_handling( - ancillary_srs, ancillary_x0, geogrid_x0, geogrid_xf): + ancillary_srs, ancillary_x0, ancillary_xf, + geogrid_x0, geogrid_xf): logger.info(f'The input RTC-S1 product crosses the antimeridian' ' (dateline). Verifying the' From 457097f6eeed75de1f36204547c41222cea2a43e Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Fri, 1 Sep 2023 15:45:05 -0700 Subject: [PATCH 4/5] address edge case in which `intersection_2` is empty; add comments --- src/rtc/core.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/rtc/core.py b/src/rtc/core.py index e6fb4b3d..dc12041f 100644 --- a/src/rtc/core.py +++ b/src/rtc/core.py @@ -454,15 +454,28 @@ def check_ancillary_inputs(check_ancillary_inputs_coverage, logger.info(f' left side (-180 -> +180): {check_1_str}') # Right side of the antimeridian crossing: +180 -> +360 - ancillary_polygon_2 = _get_ogr_polygon( + # + # Get the intersection between the geogrid and the right side + # of the antimeridian (with a litter buffer represented by + # ANTIMERIDIAN_CROSSING_RIGHT_SIDE_TEST_BUFFER) + antimeridian_right_side_polygon = _get_ogr_polygon( ancillary_xf + ANTIMERIDIAN_CROSSING_RIGHT_SIDE_TEST_BUFFER, 90, ancillary_xf + 360, -90, ancillary_srs) - intersection_2 = geogrid_polygon.Intersection(ancillary_polygon_2) + + intersection_2 = geogrid_polygon.Intersection( + antimeridian_right_side_polygon) + + # Create a polygon representing the ancillary dataset + # at the right side of the antimeridian ancillary_polygon_2 = _get_ogr_polygon( ancillary_x0 + 360, ancillary_y0, ancillary_xf + 360, ancillary_yf, ancillary_srs) - flag_2_ok = intersection_2.Within(ancillary_polygon_2) + + # Check if the geogrid-intersected area (if valid) is within + # the ancillary polygon + flag_2_ok = (intersection_2.IsEmpty() or + intersection_2.Within(ancillary_polygon_2)) check_2_str = 'ok' if flag_2_ok else 'fail' logger.info(f' right side (+180 -> +360): {check_2_str}') From d057983a54da85428cc1c9de2e8b91bcae6d5f4d Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Fri, 1 Sep 2023 17:16:15 -0700 Subject: [PATCH 5/5] improve comments --- src/rtc/core.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/rtc/core.py b/src/rtc/core.py index dc12041f..c96f897d 100644 --- a/src/rtc/core.py +++ b/src/rtc/core.py @@ -292,12 +292,18 @@ def _antimeridian_crossing_requires_special_handling( Flag that indicate if the ancillary input requires special handling ''' + # The coordinate wrapping around the ancillary file + # discontinuities such as the antimeridian only happens + # if the DEM is provided in geographic coordinates if not file_srs.IsGeographic(): flag_requires_special_handling = False return flag_requires_special_handling # Check whether the ancillary file covers the entire longitude range - # use 359 instead of 360 degrees to have some buffer + # Mark flag as True if the longitude coordinates span completes + # or is close to complete the circle (360 degrees). + # We use 359 instead of 360 degrees to have some buffer + # for incomplete ancillary files flag_ancillary_covers_entire_longitude_range = \ (ancillary_max_x - ancillary_min_x) > 359 @@ -307,6 +313,10 @@ def _antimeridian_crossing_requires_special_handling( # Flag to indicate if the tile crosses the ancillary file # discontinuity (ancillary_max_x). + # Notice that`ancillary_max_x` refers to the eastern edge + # of the ancillary file, which, for the antimeridian case, + # may not lay exactly on +/- 180. For example, it may be + # 179.9998611111111 flag_tile_crosses_discontinuity = \ tile_min_x < ancillary_max_x < tile_max_x