From d1c4d7f93fe3f9ec11bf11e32259ea02b21a0dcd Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Thu, 3 Jul 2025 11:30:42 -0700 Subject: [PATCH 1/5] disable polarimetric symmetrization by default --- share/nisar/defaults/gcov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/nisar/defaults/gcov.yaml b/share/nisar/defaults/gcov.yaml index db0c71352..3b9da8a89 100644 --- a/share/nisar/defaults/gcov.yaml +++ b/share/nisar/defaults/gcov.yaml @@ -177,7 +177,7 @@ runconfig: # HV and VH), otherwise, the flag is ignored. # If enabled, the output product's "HV" dataset will contain symmetrized # HV/VH data and the "VH" dataset will be omitted from the output. - symmetrize_cross_pol_channels: True + symmetrize_cross_pol_channels: False # TODO OPTIONAL - Only checked when internet access is available dem_download: From 2ac26942f19a6ff2e3145a96ca52044d09f867ea Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Tue, 22 Jul 2025 13:58:03 -0700 Subject: [PATCH 2/5] revert changes to `symmetrize_cross_pol_channels` --- share/nisar/defaults/gcov.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/nisar/defaults/gcov.yaml b/share/nisar/defaults/gcov.yaml index 3b9da8a89..db0c71352 100644 --- a/share/nisar/defaults/gcov.yaml +++ b/share/nisar/defaults/gcov.yaml @@ -177,7 +177,7 @@ runconfig: # HV and VH), otherwise, the flag is ignored. # If enabled, the output product's "HV" dataset will contain symmetrized # HV/VH data and the "VH" dataset will be omitted from the output. - symmetrize_cross_pol_channels: False + symmetrize_cross_pol_channels: True # TODO OPTIONAL - Only checked when internet access is available dem_download: From 05d7fda0ff21704541179bfc5b0fb5415ebae1b6 Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Tue, 22 Jul 2025 16:01:58 -0700 Subject: [PATCH 3/5] Update GCOV and GSLC specification XMLs --- .../nisar/products/XML/L2/nisar_L2_GCOV.xml | 291 ++++++++++------ .../nisar/products/XML/L2/nisar_L2_GSLC.xml | 321 +++++++++++------- 2 files changed, 371 insertions(+), 241 deletions(-) diff --git a/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml b/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml index 021b48b6a..a9e931bdb 100644 --- a/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml +++ b/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml @@ -105,7 +105,7 @@ + shape="numberOfObservations"> List of planned datatakes included in the product @@ -127,13 +127,19 @@ List of frequency layers available in the product - + List of each input raw dataset's observation mode + + - Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 - + Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 + @@ -182,7 +188,7 @@ name="/science/LSAR/identification/processingType" shape="scalar"> Nominal (or) Urgent (or) Custom (or) Undefined + lang="en">Processing pipeline used to generate this granule. "Nominal": standard production system; "Urgent": time-sensitive processing in response to urgent response events; "Custom": user-initiated processing outside the nominal production system X coordinates in specified projection Y coordinates in specified projection @@ -329,7 +337,7 @@ valid_min="0" _FillValue="nan" grid_mapping="projection" - units="1">Radiometric terrain correction factor to normalize GCOV terms from gamma0 to sigma0 + units="1">Radiometric terrain correction (RTC) scaling factor to normalize backscatter coefficients from gamma0 to sigma0, accounting for local terrain Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value `0`. GCOV pixels outside of the radar acquisition extent are filled with the value `255` + grid_mapping="projection">Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value 0. GCOV pixels outside of the radar acquisition extent are filled with the value 255 X coordinates in specified projection Y coordinates in specified projection @@ -706,7 +716,7 @@ valid_min="0" _FillValue="nan" grid_mapping="projection" - units="1">Radiometric terrain correction factor to normalize GCOV terms from gamma0 to sigma0 + units="1">Radiometric terrain correction (RTC) scaling factor to normalize backscatter coefficients from gamma0 to sigma0, accounting for local terrain Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value `0`. GCOV pixels outside of the radar acquisition extent are filled with the value `255` + grid_mapping="projection">Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value 0. GCOV pixels outside of the radar acquisition extent are filled with the value 255 East component of unit vector of LOS from target to sensor + units="1">East component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location North component of unit vector of LOS from target to sensor + units="1">North component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location East component of unit vector along ground track + units="1">East component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) North component of unit vector along ground track + units="1">North component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) X coordinates in specified projection X coordinates in specified projection - - + + Product map grid projection: EPSG code, with additional projection information as HDF5 Attributes + + + Y coordinates in specified projection + + + X coordinates in specified projection + Crosstalk in H-transmit channel expressed as ratio txV / txH Crosstalk in V-transmit channel expressed as ratio txH / txV Crosstalk in H-receive channel expressed as ratio rxV / rxH Crosstalk in V-receive channel expressed as ratio rxH / rxV + + @@ -2437,14 +2519,14 @@ Reference Terrain Height as a function of map coordinates + units="meters">Reference terrain height as a function of map coordinates scalar values - - - number of datatakes in product - - - number of observations in product + lang="en">Number of observations in product @@ -3372,28 +3445,22 @@ Shape of calibration LUTs + lang="en">Shape of real-valued calibration LUTs - Shape of antenna pattern datasets + lang="en">Shape of complex-valued calibration LUTs - - Shape of crosstalk datasets - - + shape="numberOfObservations"> List of planned datatakes included in the product @@ -127,13 +127,19 @@ List of frequency layers available in the product - + List of each input raw dataset's observation mode + + - Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 - + Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 + @@ -182,7 +188,7 @@ name="/science/LSAR/identification/processingType" shape="scalar"> Nominal (or) Urgent (or) Custom (or) Undefined + lang="en">Processing pipeline used to generate this granule. "Nominal": standard production system; "Urgent": time-sensitive processing in response to urgent response events; "Custom": user-initiated processing outside the nominal production system Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of `0` indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value `255`. + _FillValue="255">Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of 0 indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value 255. Focused SLC image (HH) @@ -373,7 +379,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image HV" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (HV) @@ -393,7 +399,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VH" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VH) @@ -413,7 +419,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VV" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VV) @@ -433,7 +439,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RH" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RH) @@ -453,7 +459,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RV" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RV) @@ -538,14 +544,14 @@ Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of `0` indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value `255`. + _FillValue="255">Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of 0 indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value 255. Focused SLC image (HH) @@ -626,7 +632,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image HV" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (HV) @@ -646,7 +652,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VH" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VH) @@ -666,7 +672,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VV" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VV) @@ -686,7 +692,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RH" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RH) @@ -706,7 +712,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RVH" - grid_mapping='projection' + grid_mapping="projection" DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RV) @@ -832,7 +838,7 @@ _FillValue="nan" grid_mapping="projection" long_name="LOS unit vector X" - units="1">East component of unit vector of LOS from target to sensor + units="1">East component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location North component of unit vector of LOS from target to sensor + units="1">North component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location East component of unit vector along ground track + units="1">East component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) North component of unit vector along ground track + units="1">North component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) X coordinates in specified projection X coordinates in specified projection - - + + Product map grid projection: EPSG code, with additional projection information as HDF5 Attributes + + + Y coordinates in specified projection + + + X coordinates in specified projection + Crosstalk in H-transmit channel expressed as ratio txV / txH Crosstalk in V-transmit channel expressed as ratio txH / txV Crosstalk in H-receive channel expressed as ratio rxV / rxH Crosstalk in V-receive channel expressed as ratio rxH / rxV + + @@ -2096,7 +2174,7 @@ lang="en" _FillValue="nan" grid_mapping="projection" - units="meters">Reference Terrain Height as a function of geographical location + units="meters">Reference terrain height as a function of map coordinates scalar values - - - number of datatakes in product - - - number of observations in product + lang="en">Number of observations in product @@ -3116,28 +3185,22 @@ Shape of calibration LUTs + lang="en">Shape of real-valued calibration LUTs - Shape of antenna pattern datasets + lang="en">Shape of complex-valued calibration LUTs - - Shape of crosstalk datasets - - Number of input L1 SLC granules + name="numberOfInputL1Files"/> From 749058db5115479f727ca055d828370ecd1ec07e Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Wed, 23 Jul 2025 11:45:11 -0700 Subject: [PATCH 4/5] Revert changes to the GCOV and GSLC specification XMLs --- .../nisar/products/XML/L2/nisar_L2_GCOV.xml | 291 ++++++---------- .../nisar/products/XML/L2/nisar_L2_GSLC.xml | 321 +++++++----------- 2 files changed, 241 insertions(+), 371 deletions(-) diff --git a/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml b/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml index a9e931bdb..021b48b6a 100644 --- a/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml +++ b/python/packages/nisar/products/XML/L2/nisar_L2_GCOV.xml @@ -105,7 +105,7 @@ + shape="numberOfDatatakes"> List of planned datatakes included in the product @@ -127,19 +127,13 @@ List of frequency layers available in the product - - List of each input raw dataset's observation mode - - - Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 - + Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 + @@ -188,7 +182,7 @@ name="/science/LSAR/identification/processingType" shape="scalar"> Processing pipeline used to generate this granule. "Nominal": standard production system; "Urgent": time-sensitive processing in response to urgent response events; "Custom": user-initiated processing outside the nominal production system + lang="en">Nominal (or) Urgent (or) Custom (or) Undefined X coordinates in specified projection Y coordinates in specified projection @@ -337,7 +329,7 @@ valid_min="0" _FillValue="nan" grid_mapping="projection" - units="1">Radiometric terrain correction (RTC) scaling factor to normalize backscatter coefficients from gamma0 to sigma0, accounting for local terrain + units="1">Radiometric terrain correction factor to normalize GCOV terms from gamma0 to sigma0 Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value 0. GCOV pixels outside of the radar acquisition extent are filled with the value 255 + grid_mapping="projection">Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value `0`. GCOV pixels outside of the radar acquisition extent are filled with the value `255` X coordinates in specified projection Y coordinates in specified projection @@ -716,7 +706,7 @@ valid_min="0" _FillValue="nan" grid_mapping="projection" - units="1">Radiometric terrain correction (RTC) scaling factor to normalize backscatter coefficients from gamma0 to sigma0, accounting for local terrain + units="1">Radiometric terrain correction factor to normalize GCOV terms from gamma0 to sigma0 Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value 0. GCOV pixels outside of the radar acquisition extent are filled with the value 255 + grid_mapping="projection">Mask indicating the subswath number associated with valid GCOV samples. A GCOV sample is only considered valid if it is generated from fully-focused radar samples. If at least one radar sample in the averaging set is partially focused or invalid, the corresponding mask pixel will contain the value `0`. GCOV pixels outside of the radar acquisition extent are filled with the value `255` East component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location + units="1">East component of unit vector of LOS from target to sensor North component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location + units="1">North component of unit vector of LOS from target to sensor East component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) + units="1">East component of unit vector along ground track North component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) + units="1">North component of unit vector along ground track X coordinates in specified projection X coordinates in specified projection + + - - Product map grid projection: EPSG code, with additional projection information as HDF5 Attributes - - - Y coordinates in specified projection - - - X coordinates in specified projection - Crosstalk in H-transmit channel expressed as ratio txV / txH Crosstalk in V-transmit channel expressed as ratio txH / txV Crosstalk in H-receive channel expressed as ratio rxV / rxH Crosstalk in V-receive channel expressed as ratio rxH / rxV - - @@ -2519,14 +2437,14 @@ Reference terrain height as a function of map coordinates + units="meters">Reference Terrain Height as a function of map coordinates scalar values + + + number of datatakes in product + + + Number of observations in product + lang="en">number of observations in product @@ -3445,22 +3372,28 @@ Shape of real-valued calibration LUTs + lang="en">Shape of calibration LUTs - Shape of complex-valued calibration LUTs + lang="en">Shape of antenna pattern datasets + + Shape of crosstalk datasets + + + shape="numberOfDatatakes"> List of planned datatakes included in the product @@ -127,19 +127,13 @@ List of frequency layers available in the product - - List of each input raw dataset's observation mode - - - Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 - + Indicates if the radar operation mode is a diagnostic mode (1-2) or DBFed science (0): 0, 1, or 2 + @@ -188,7 +182,7 @@ name="/science/LSAR/identification/processingType" shape="scalar"> Processing pipeline used to generate this granule. "Nominal": standard production system; "Urgent": time-sensitive processing in response to urgent response events; "Custom": user-initiated processing outside the nominal production system + lang="en">Nominal (or) Urgent (or) Custom (or) Undefined Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of 0 indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value 255. + _FillValue="255">Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of `0` indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value `255`. Focused SLC image (HH) @@ -379,7 +373,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image HV" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (HV) @@ -399,7 +393,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VH" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VH) @@ -419,7 +413,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VV" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VV) @@ -439,7 +433,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RH" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RH) @@ -459,7 +453,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RV" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RV) @@ -544,14 +538,14 @@ Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of 0 indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value 255. + _FillValue="255">Mask indicating the subswath number representing valid GSLC samples. Each GSLC pixel is assumed valid if all the pixels in the interpolation window are fully focused in the input RSLC. A value of `0` indicates that at least one RSLC pixel in the interpolation window is partially focused or invalid. Pixels outside of the radar acquisition extent are filled with the value `255`. Focused SLC image (HH) @@ -632,7 +626,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image HV" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (HV) @@ -652,7 +646,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VH" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VH) @@ -672,7 +666,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image VV" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (VV) @@ -692,7 +686,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RH" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RH) @@ -712,7 +706,7 @@ mean_real_value="Arithmetic average of the real part of the numeric data points" sample_stddev_real="Standard deviation of the real part of the numeric data points" long_name="Geocoded single-look complex image RVH" - grid_mapping="projection" + grid_mapping='projection' DIMENSION_LIST="HDF5 internal attribute" _FillValue="(nan+nan*j)" units="1">Focused SLC image (RV) @@ -838,7 +832,7 @@ _FillValue="nan" grid_mapping="projection" long_name="LOS unit vector X" - units="1">East component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location + units="1">East component of unit vector of LOS from target to sensor North component of the line-of-sight (LOS) unit vector, defined from the target to the sensor, expressed in the east-north-up (ENU) coordinate system with its origin at the target location + units="1">North component of unit vector of LOS from target to sensor East component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) + units="1">East component of unit vector along ground track North component of the along-track unit vector at the target location, expressed in the east-north-up (ENU) coordinate system and projected onto the horizontal plane (i.e., excluding the up component) + units="1">North component of unit vector along ground track X coordinates in specified projection X coordinates in specified projection + + - - Product map grid projection: EPSG code, with additional projection information as HDF5 Attributes - - - Y coordinates in specified projection - - - X coordinates in specified projection - Crosstalk in H-transmit channel expressed as ratio txV / txH Crosstalk in V-transmit channel expressed as ratio txH / txV Crosstalk in H-receive channel expressed as ratio rxV / rxH Crosstalk in V-receive channel expressed as ratio rxH / rxV - - @@ -2174,7 +2096,7 @@ lang="en" _FillValue="nan" grid_mapping="projection" - units="meters">Reference terrain height as a function of map coordinates + units="meters">Reference Terrain Height as a function of geographical location scalar values + + + number of datatakes in product + + + Number of observations in product + lang="en">number of observations in product @@ -3185,22 +3116,28 @@ Shape of real-valued calibration LUTs + lang="en">Shape of calibration LUTs - Shape of complex-valued calibration LUTs + lang="en">Shape of antenna pattern datasets + + Shape of crosstalk datasets + + Number of input L1 SLC granules + name="numberOfInputL0BFiles"/> From e27a59805445a200c43a08067f119cde93278fb6 Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Wed, 31 Dec 2025 15:11:27 -0800 Subject: [PATCH 5/5] Add configurable handling for RTC minimum value thresholding --- cxx/isce3/geocode/GeocodeCov.cpp | 77 ++++--- cxx/isce3/geocode/GeocodeCov.h | 62 +++++- cxx/isce3/geocode/GeocodePolygon.cpp | 31 ++- cxx/isce3/geocode/GeocodePolygon.h | 18 +- cxx/isce3/geometry/RTC.cpp | 199 ++++++++++++++---- cxx/isce3/geometry/RTC.h | 95 ++++++++- .../pybind_isce3/geocode/GeocodeCov.cpp | 20 +- .../pybind_isce3/geocode/GeocodePolygon.cpp | 19 +- .../extensions/pybind_isce3/geometry/RTC.cpp | 69 +++++- python/extensions/pybind_isce3/geometry/RTC.h | 3 + .../pybind_isce3/geometry/geometry.cpp | 3 + .../nisar/products/writers/GcovWriter.py | 4 + .../nisar/workflows/gcov_runconfig.py | 20 ++ share/nisar/defaults/gcov.yaml | 18 +- share/nisar/schemas/gcov.yaml | 15 ++ tests/cxx/isce3/geocode/geocodeCov.cpp | 7 +- 16 files changed, 548 insertions(+), 112 deletions(-) diff --git a/cxx/isce3/geocode/GeocodeCov.cpp b/cxx/isce3/geocode/GeocodeCov.cpp index 09f9e6ce4..7048fc55c 100644 --- a/cxx/isce3/geocode/GeocodeCov.cpp +++ b/cxx/isce3/geocode/GeocodeCov.cpp @@ -27,6 +27,7 @@ using isce3::core::OrbitInterpBorderMode; using isce3::core::Vec3; using isce3::core::GeocodeMemoryMode; +using isce3::geometry::rtcMinValueMode; namespace isce3 { namespace geocode { @@ -131,7 +132,9 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, bool flag_upsample_radar_grid, bool flag_apply_rtc, isce3::geometry::rtcInputTerrainRadiometry input_terrain_radiometry, isce3::geometry::rtcOutputTerrainRadiometry output_terrain_radiometry, - int exponent, float rtc_min_value_db, double rtc_geogrid_upsampling, + int exponent, float rtc_min_value_db, float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, + double rtc_geogrid_upsampling, isce3::geometry::rtcAlgorithm rtc_algorithm, isce3::geometry::rtcAreaBetaMode rtc_area_beta_mode, double abs_cal_factor, float clip_min, float clip_max, @@ -161,7 +164,8 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, geocodeInterp(radar_grid, input_raster, output_raster, dem_raster, flag_apply_rtc, flag_az_baseband_doppler, flatten, input_terrain_radiometry, output_terrain_radiometry, - rtc_min_value_db, rtc_geogrid_upsampling, rtc_algorithm, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, out_geo_rdr, out_geo_dem, out_geo_rtc, out_geo_rtc_gamma0_to_sigma0, @@ -177,8 +181,8 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, geocodeInterp(radar_grid, input_raster, output_raster, dem_raster, flag_apply_rtc, flag_az_baseband_doppler, flatten, input_terrain_radiometry, output_terrain_radiometry, - rtc_min_value_db, rtc_geogrid_upsampling, rtc_algorithm, - rtc_area_beta_mode, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, out_geo_rdr, out_geo_dem, out_geo_rtc, out_geo_rtc_gamma0_to_sigma0, phase_screen_raster, az_time_correction, @@ -191,8 +195,8 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, geocodeInterp(radar_grid, input_raster, output_raster, dem_raster, flag_apply_rtc, flag_az_baseband_doppler, flatten, input_terrain_radiometry, output_terrain_radiometry, - rtc_min_value_db, rtc_geogrid_upsampling, rtc_algorithm, - rtc_area_beta_mode, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, out_geo_rdr, out_geo_dem, out_geo_rtc, out_geo_rtc_gamma0_to_sigma0, phase_screen_raster, az_time_correction, @@ -205,8 +209,8 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, geocodeAreaProj(radar_grid, input_raster, output_raster, dem_raster, geogrid_upsampling, flag_upsample_radar_grid, flag_apply_rtc, input_terrain_radiometry, output_terrain_radiometry, - rtc_min_value_db, rtc_geogrid_upsampling, rtc_algorithm, - rtc_area_beta_mode, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, out_off_diag_terms, out_geo_rdr, out_geo_dem, out_geo_nlooks, out_geo_rtc, out_geo_rtc_gamma0_to_sigma0, @@ -222,8 +226,9 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, dem_raster, geogrid_upsampling, flag_upsample_radar_grid, flag_apply_rtc, input_terrain_radiometry, output_terrain_radiometry, rtc_min_value_db, - rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, - abs_cal_factor, clip_min, + rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, + rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, out_off_diag_terms, out_geo_rdr, out_geo_dem, out_geo_nlooks, out_geo_rtc, out_geo_rtc_gamma0_to_sigma0, az_time_correction, @@ -238,8 +243,9 @@ void Geocode::geocode(const isce3::product::RadarGridParameters& radar_grid, dem_raster, geogrid_upsampling, flag_upsample_radar_grid, flag_apply_rtc, input_terrain_radiometry, output_terrain_radiometry, rtc_min_value_db, - rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, - abs_cal_factor, clip_min, + rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, + rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, out_off_diag_terms, out_geo_rdr, out_geo_dem, out_geo_nlooks, out_geo_rtc, out_geo_rtc_gamma0_to_sigma0, az_time_correction, @@ -260,7 +266,8 @@ void Geocode::geocodeInterp( bool flag_az_baseband_doppler, bool flatten, isce3::geometry::rtcInputTerrainRadiometry input_terrain_radiometry, isce3::geometry::rtcOutputTerrainRadiometry output_terrain_radiometry, - float rtc_min_value_db, double rtc_geogrid_upsampling, + float rtc_min_value_db, float rtc_transition_value_db, isce3::geometry::rtcMinValueMode rtc_min_value_mode, + double rtc_geogrid_upsampling, isce3::geometry::rtcAlgorithm rtc_algorithm, isce3::geometry::rtcAreaBetaMode rtc_area_beta_mode, double abs_cal_factor, @@ -413,13 +420,6 @@ void Geocode::geocodeInterp( info << "clip max: " << clip_max << pyre::journal::newline; // RTC - double rtc_min_value = 0; - if (!std::isnan(rtc_min_value_db) && flag_apply_rtc) { - rtc_min_value = std::pow(10, (rtc_min_value_db / 10)); - info << "RTC min. value: " << rtc_min_value_db - << " [dB] = " << rtc_min_value << pyre::journal::newline; - } - if (abs_cal_factor != 1) info << "absolute calibration factor: " << abs_cal_factor << pyre::journal::newline; @@ -506,6 +506,7 @@ void Geocode::geocodeInterp( input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_algorithm, rtc_area_beta_mode, rtc_geogrid_upsampling, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode, out_geo_rdr, out_geo_grid, rtc_sigma0_raster, az_time_correction, slant_range_correction, rtc_memory_mode, dem_interp_method, _threshold, @@ -866,7 +867,7 @@ void Geocode::geocodeInterp( rdrBlockWidth, rdrBlockLength, azimuthFirstLine, rangeFirstPixel, interp.get(), radar_grid, flag_az_baseband_doppler, flatten, phase_screen_raster, - phase_screen_array, rtc_min_value, + phase_screen_array, abs_cal_factor_effective, clip_min, clip_max, flag_apply_rtc, rtc_area_array, rtc_area_sigma0_array, out_geo_rtc_band, out_geo_rtc_array, out_geo_rtc_gamma0_to_sigma0_band, @@ -953,7 +954,6 @@ inline void Geocode::_interpolate( const bool flag_az_baseband_doppler, const bool flatten, isce3::io::Raster* phase_screen_raster, isce3::core::Matrix& phase_screen_array, - float rtc_min_value, double abs_cal_factor_effective, float clip_min, float clip_max, bool flag_apply_rtc, const isce3::core::Matrix& rtc_area, @@ -1086,10 +1086,9 @@ inline void Geocode::_interpolate( float rtc_value = rtc_area(int(rdrY + azimuthFirstLine), int(rdrX + rangeFirstPixel)); - - if (std::isnan(rtc_value) || rtc_value < rtc_min_value) { + + if (std::isnan(rtc_value)) continue; - } /* RTC normalization values are proportional to backscater @@ -1875,7 +1874,9 @@ void Geocode::geocodeAreaProj( bool flag_upsample_radar_grid, bool flag_apply_rtc, isce3::geometry::rtcInputTerrainRadiometry input_terrain_radiometry, isce3::geometry::rtcOutputTerrainRadiometry output_terrain_radiometry, - float rtc_min_value_db, double rtc_geogrid_upsampling, + float rtc_min_value_db, float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, + double rtc_geogrid_upsampling, isce3::geometry::rtcAlgorithm rtc_algorithm, isce3::geometry::rtcAreaBetaMode rtc_area_beta_mode, double abs_cal_factor, @@ -1919,7 +1920,8 @@ void Geocode::geocodeAreaProj( output_raster, dem_raster, geogrid_upsampling, flag_upsample_radar_grid, flag_apply_rtc, input_terrain_radiometry, output_terrain_radiometry, - rtc_min_value_db, rtc_geogrid_upsampling, rtc_algorithm, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, min_nlooks, upsampled_radar_grid_nlooks, out_off_diag_terms, out_geo_rdr, @@ -2099,6 +2101,7 @@ void Geocode::geocodeAreaProj( input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_algorithm, rtc_area_beta_mode, rtc_geogrid_upsampling, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode, out_geo_rdr, out_geo_grid, rtc_sigma0_raster, az_time_correction, slant_range_correction, rtc_memory_mode, dem_interp_method, _threshold, @@ -2197,14 +2200,6 @@ void Geocode::geocodeAreaProj( const long long progress_block = ((long long) imax) * jmax / 100; - double rtc_min_value = 0; - - if (!std::isnan(rtc_min_value_db) && flag_apply_rtc) { - rtc_min_value = std::pow(10., (rtc_min_value_db / 10.)); - info << "RTC min. value: " << rtc_min_value_db - << " [dB] = " << rtc_min_value << pyre::journal::newline; - } - if (abs_cal_factor != 1) info << "absolute calibration factor: " << abs_cal_factor << pyre::journal::newline; @@ -2297,8 +2292,7 @@ void Geocode::geocodeAreaProj( rtc_raster, rtc_sigma0_raster, az_time_correction, slant_range_correction, input_raster, offset_y, offset_x, - output_raster, rtc_area, rtc_area_sigma, - rtc_min_value, abs_cal_factor, + output_raster, rtc_area, rtc_area_sigma, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, flag_upsample_radar_grid, input_layover_shadow_mask_raster, input_layover_shadow_mask, sub_swaths, @@ -2325,8 +2319,7 @@ void Geocode::geocodeAreaProj( rtc_raster, rtc_sigma0_raster, az_time_correction, slant_range_correction, input_raster, offset_y, offset_x, - output_raster, rtc_area, rtc_area_sigma, - rtc_min_value, abs_cal_factor, + output_raster, rtc_area, rtc_area_sigma, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, flag_upsample_radar_grid, input_layover_shadow_mask_raster, input_layover_shadow_mask, sub_swaths, @@ -2519,7 +2512,7 @@ void Geocode::_runBlock( int raster_offset_y, int raster_offset_x, isce3::io::Raster& output_raster, isce3::core::Matrix& rtc_area, isce3::core::Matrix& rtc_area_sigma, - float rtc_min_value, double abs_cal_factor, float clip_min, + double abs_cal_factor, float clip_min, float clip_max, float min_nlooks, float radar_grid_nlooks, bool flag_upsample_radar_grid, isce3::io::Raster* input_layover_shadow_mask_raster, @@ -3311,8 +3304,10 @@ void Geocode::_runBlock( rtc_value = rtc_area_block(y - offset_y, x - offset_x); } - if (std::isnan(rtc_value) || rtc_value < rtc_min_value) + + if (std::isnan(rtc_value)) { continue; + } nlooks += w; if (isce3::is_complex()) diff --git a/cxx/isce3/geocode/GeocodeCov.h b/cxx/isce3/geocode/GeocodeCov.h index d3c437717..fe238eb95 100644 --- a/cxx/isce3/geocode/GeocodeCov.h +++ b/cxx/isce3/geocode/GeocodeCov.h @@ -33,6 +33,7 @@ enum geocodeOutputMode { }; + template class Geocode { public: @@ -77,7 +78,19 @@ class Geocode { * The value 0 indicates that the the exponent is based on the data type of * the input raster (1 for real and 2 for complex rasters). * @param[in] rtc_min_value_db Minimum value for the RTC area factor. - * Radar data with RTC area factor below this limit will be set to NaN. + * Radar data with RTC area factor below this limit will be considered invalid. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[in] rtc_geogrid_upsampling Geogrid upsampling to compute * the radiometric terrain correction RTC. * @param[in] rtc_algorithm RTC algorithm @@ -92,7 +105,7 @@ class Geocode { * @param[in] clip_min Clip (limit) minimum output values * @param[in] clip_max Clip (limit) maximum output values * @param[in] min_nlooks Minimum number of looks. Geogrid data - * below this limit will be set to NaN + * below this limit will be considered invalid * @param[in] radar_grid_nlooks Radar grid number of looks. This * parameters determines the multilooking factor used to compute * out_geo_nlooks. @@ -162,6 +175,9 @@ class Geocode { rtcOutputTerrainRadiometry::GAMMA_NAUGHT, int exponent = 0, float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, double rtc_geogrid_upsampling = std::numeric_limits::quiet_NaN(), isce3::geometry::rtcAlgorithm rtc_algorithm = @@ -230,7 +246,19 @@ class Geocode { * @param[in] input_terrain_radiometry Input terrain radiometry * @param[in] output_terrain_radiometry Output terrain radiometry * @param[in] rtc_min_value_db Minimum value for the RTC area factor. - * Radar data with RTC area factor below this limit will be set to NaN. + * Radar data with RTC area factor below this limit will be considered invalid. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[in] rtc_geogrid_upsampling Geogrid upsampling to compute the * radiometric terrain correction RTC. * @param[in] rtc_algorithm RTC algorithm @@ -302,6 +330,9 @@ class Geocode { output_terrain_radiometry = isce3::geometry:: rtcOutputTerrainRadiometry::GAMMA_NAUGHT, float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, double rtc_geogrid_upsampling = std::numeric_limits::quiet_NaN(), isce3::geometry::rtcAlgorithm rtc_algorithm = @@ -368,7 +399,19 @@ class Geocode { * @param[in] input_terrain_radiometry Input terrain radiometry * @param[in] output_terrain_radiometry Output terrain radiometry * @param[in] rtc_min_value_db Minimum value for the RTC area factor. - * Radar data with RTC area factor below this limit will be set to NaN. + * Radar data with RTC area factor below this limit will be considered invalid. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[in] rtc_geogrid_upsampling Geogrid upsampling to compute the * radiometric terrain correction RTC. * @param[in] rtc_algorithm RTC algorithm @@ -383,7 +426,7 @@ class Geocode { * @param[in] clip_min Clip (limit) minimum output values * @param[in] clip_max Clip (limit) maximum output values * @param[in] min_nlooks Minimum number of looks. Geogrid data - * below this limit will be set to NaN + * below this limit will be considered invalid * @param[in] radar_grid_nlooks Radar grid number of looks. This * parameters determines the multilooking factor used to compute out_nlooks. * @param[out] out_off_diag_terms Output raster containing the @@ -449,6 +492,9 @@ class Geocode { output_terrain_radiometry = isce3::geometry:: rtcOutputTerrainRadiometry::GAMMA_NAUGHT, float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, double rtc_geogrid_upsampling = std::numeric_limits::quiet_NaN(), isce3::geometry::rtcAlgorithm rtc_algorithm = @@ -647,7 +693,7 @@ class Geocode { isce3::io::Raster& output_raster, isce3::core::Matrix& rtc_area, isce3::core::Matrix& rtc_area_sigma, - float rtc_min_value, double abs_cal_factor, + double abs_cal_factor, float clip_min, float clip_max, float min_nlooks, float radar_grid_nlooks, bool flag_upsample_radar_grid, @@ -682,8 +728,6 @@ class Geocode { * @param[in] flatten flag to flatten the geocoded SLC * @param[in] phase_screen_raster Phase screen raster * @param[in] phase_screen_array Phase screen array - * @param[in] rtc_min_value_db Minimum value for the RTC area factor. - * Radar data with RTC area factor below this limit will be set to NaN. * @param[in] abs_cal_factor Absolute calibration factor applied * to real-valued output datasets (assumed to be proportional to * power/intensity). If the output is complex valued, its considered @@ -734,7 +778,7 @@ class Geocode { const bool flag_az_baseband_doppler, const bool flatten, isce3::io::Raster* phase_screen_raster, isce3::core::Matrix& phase_screen_array, - float rtc_min_value, double abs_cal_factor, + double abs_cal_factor, float clip_min, float clip_max, bool flag_run_rtc, const isce3::core::Matrix& rtc_area, const isce3::core::Matrix& rtc_area_sigma, diff --git a/cxx/isce3/geocode/GeocodePolygon.cpp b/cxx/isce3/geocode/GeocodePolygon.cpp index e7ed3a33e..59b60c251 100644 --- a/cxx/isce3/geocode/GeocodePolygon.cpp +++ b/cxx/isce3/geocode/GeocodePolygon.cpp @@ -3,6 +3,7 @@ #include "GeocodeHelpers.h" #include +#include #include #include @@ -145,7 +146,9 @@ void GeocodePolygon::getPolygonMean( isce3::geometry::rtcInputTerrainRadiometry input_terrain_radiometry, isce3::geometry::rtcOutputTerrainRadiometry output_terrain_radiometry, int exponent, double geogrid_upsampling, - float rtc_min_value_db, double abs_cal_factor, float radar_grid_nlooks, + float rtc_min_value_db, float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, + double abs_cal_factor, float radar_grid_nlooks, isce3::io::Raster* output_off_diag_terms, isce3::io::Raster* output_radargrid_data, isce3::io::Raster* output_rtc, isce3::io::Raster* output_weights, isce3::core::dataInterpMethod interp_method) { @@ -157,11 +160,16 @@ void GeocodePolygon::getPolygonMean( geogrid_upsampling = 2; assert(geogrid_upsampling > 0); + std::string rtc_min_value_mode_str = get_rtc_min_value_mode_str( + rtc_min_value_mode); + _info <<"look side: " << radar_grid.lookSide() << pyre::journal::newline << "radar_grid length: " << radar_grid.length() << ", width: " << radar_grid.width() << pyre::journal::newline - << "RTC min value [dB]: " << rtc_min_value_db << pyre::journal::endl; + << "RTC min value [dB]: " << rtc_min_value_db << pyre::journal::newline + << "RTC min value mode: " << rtc_min_value_mode_str + << pyre::journal::endl; _info << "cropping radar grid from index (a0: " << _yoff; _info << ", r0: " << _xoff << ") to index (af: " << _yoff + _ysize; @@ -232,6 +240,7 @@ void GeocodePolygon::getPolygonMean( output_terrain_radiometry, rtc_area_mode, rtc_algorithm, rtc_area_beta_mode, geogrid_upsampling * 2, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode, out_sigma, az_time_correction, slant_range_correction, rtc_memory_mode, interp_method, _threshold, _num_iter, _delta_range); @@ -264,21 +273,24 @@ void GeocodePolygon::getPolygonMean( _info << "output dtype: GDT_Float32" << pyre::journal::endl; _getPolygonMean( rtc_area, radar_grid_cropped, input_raster, output_raster, - flag_apply_rtc, rtc_min_value, abs_cal_factor, radar_grid_nlooks, + flag_apply_rtc, rtc_min_value, rtc_min_value_mode, + abs_cal_factor, radar_grid_nlooks, output_off_diag_terms, output_radargrid_data, output_weights); } else if (input_raster.dtype() == GDT_CFloat32 && exponent == 2) { _info << "input dtype: GDT_CFloat32" << pyre::journal::endl; _info << "output dtype: GDT_Float32" << pyre::journal::endl; _getPolygonMean( rtc_area, radar_grid_cropped, input_raster, output_raster, - flag_apply_rtc, rtc_min_value, abs_cal_factor, radar_grid_nlooks, + flag_apply_rtc, rtc_min_value, rtc_min_value_mode, + abs_cal_factor, radar_grid_nlooks, output_off_diag_terms, output_radargrid_data, output_weights); } else if (input_raster.dtype() == GDT_CFloat32 && exponent == 1) { _info << "input dtype: GDT_CFloat32" << pyre::journal::endl; _info << "output dtype: GDT_CFloat32" << pyre::journal::endl; _getPolygonMean>( rtc_area, radar_grid_cropped, input_raster, output_raster, - flag_apply_rtc, rtc_min_value, abs_cal_factor, radar_grid_nlooks, + flag_apply_rtc, rtc_min_value, rtc_min_value_mode, + abs_cal_factor, radar_grid_nlooks, output_off_diag_terms, output_radargrid_data, output_weights); } else _info << "ERROR not implemented for datatype: " << input_raster.dtype() @@ -294,7 +306,7 @@ void GeocodePolygon::_getPolygonMean( isce3::io::Raster& input_raster, isce3::io::Raster& output_raster, bool flag_apply_rtc, - float rtc_min_value, + float rtc_min_value, isce3::geometry::rtcMinValueMode rtc_min_value_mode, double abs_cal_factor, float radar_grid_nlooks, isce3::io::Raster* output_off_diag_terms, isce3::io::Raster* output_radargrid_data, @@ -397,9 +409,12 @@ void GeocodePolygon::_getPolygonMean( */ w = std::abs(w); if (flag_apply_rtc) { - const float rtc_value = rtc_area(y, x); - if (std::isnan(rtc_value) || rtc_value < rtc_min_value) + float rtc_value = rtc_area(y, x); + if (std::isnan(rtc_value) || + (!rtc_min_value_mode && rtc_value < rtc_min_value)) continue; + else if (rtc_value < rtc_min_value) + rtc_value = rtc_min_value; nlooks += w; w /= rtc_value; } else { diff --git a/cxx/isce3/geocode/GeocodePolygon.h b/cxx/isce3/geocode/GeocodePolygon.h index 98e29c275..1fed4d74c 100644 --- a/cxx/isce3/geocode/GeocodePolygon.h +++ b/cxx/isce3/geocode/GeocodePolygon.h @@ -63,6 +63,18 @@ class GeocodePolygon { * @param[in] geogrid_upsampling Geogrid upsampling (in each direction) * @param[in] rtc_min_value_db Minimum value for the RTC area factor. * Radar data with RTC area factor below this limit are ignored. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[in] abs_cal_factor Absolute calibration factor. * @param[in] radar_grid_nlooks Radar grid number of looks. This * parameters determines the multilooking factor used to compute out_nlooks. @@ -91,6 +103,9 @@ class GeocodePolygon { double geogrid_upsampling = std::numeric_limits::quiet_NaN(), float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, double abs_cal_factor = 1, float radar_grid_nlooks = 1, isce3::io::Raster* output_off_diag_terms = nullptr, isce3::io::Raster* output_radargrid_data = nullptr, @@ -137,7 +152,8 @@ class GeocodePolygon { isce3::io::Raster& input_raster, isce3::io::Raster& output_raster, bool flag_apply_rtc = false, - float rtc_min_value = 0, + float rtc_min_value = 0, isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, double abs_cal_factor = 1, float radar_grid_nlooks = 1, isce3::io::Raster* output_off_diag_terms = nullptr, isce3::io::Raster* output_radargrid_data = nullptr, diff --git a/cxx/isce3/geometry/RTC.cpp b/cxx/isce3/geometry/RTC.cpp index 95fe03b37..edf434db3 100644 --- a/cxx/isce3/geometry/RTC.cpp +++ b/cxx/isce3/geometry/RTC.cpp @@ -124,7 +124,7 @@ static int _geo2rdrWrapper(const Vec3& inputLLH, const Ellipsoid& ellipsoid, template void _applyRtc(isce3::io::Raster& input_raster, isce3::io::Raster& input_rtc, - isce3::io::Raster& output_raster, float rtc_min_value, + isce3::io::Raster& output_raster, double abs_cal_factor, float clip_min, float clip_max, pyre::journal::info_t& info, bool flag_complex_to_real_squared) { @@ -138,9 +138,6 @@ void _applyRtc(isce3::io::Raster& input_raster, isce3::io::Raster& input_rtc, getBlockProcessingParametersY(length, width, nbands, sizeof(T), &info, &block_length, &nblocks); - if (std::isnan(rtc_min_value)) - rtc_min_value = 0; - if (!isnan(abs_cal_factor)) { abs_cal_factor = 1.0; } @@ -187,8 +184,7 @@ void _applyRtc(isce3::io::Raster& input_raster, isce3::io::Raster& input_rtc, for (int jj = 0; jj < width; ++jj) { float rtc_ratio_value = rtc_ratio(i, jj); - if (std::isnan(rtc_ratio_value) || - rtc_ratio_value < rtc_min_value) { + if (std::isnan(rtc_ratio_value)) { /* assign NaN by multiplication to cast it to the radar_data_block data type. See comments above (outside for loops) */ @@ -219,8 +215,7 @@ void _applyRtc(isce3::io::Raster& input_raster, isce3::io::Raster& input_rtc, /* assign NaN by multiplication to cast it to the radar_data_block data type. See comments above (outside for loops) */ - if (std::isnan(rtc_ratio_value) || - rtc_ratio_value < rtc_min_value) { + if (std::isnan(rtc_ratio_value)) { radar_data_block(i, jj) *= std::numeric_limits::quiet_NaN(); } @@ -250,24 +245,92 @@ void _applyRtc(isce3::io::Raster& input_raster, isce3::io::Raster& input_rtc, } void _applyRtcMinValueDb(isce3::core::Matrix& out_array, - float rtc_min_value_db, rtcAreaMode rtc_area_mode, + float rtc_min_value_db, float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, + rtcAreaMode rtc_area_mode, pyre::journal::info_t& info) { - if (!std::isnan(rtc_min_value_db) && - rtc_area_mode == rtcAreaMode::AREA_FACTOR) { - float rtc_min_value = std::pow(10., (rtc_min_value_db / 10.)); - info << "applying min. RTC value: " << rtc_min_value_db - << " [dB] ~= " << rtc_min_value << pyre::journal::endl; - _Pragma("omp parallel for schedule(dynamic) collapse(2)") - for (int i = 0; i < out_array.length(); ++i) - for (int j = 0; j < out_array.width(); ++j) { - if (out_array(i, j) >= rtc_min_value) - continue; + if (std::isnan(rtc_min_value_db) || + rtc_min_value_mode == rtcMinValueMode::DISABLED || + rtc_area_mode != rtcAreaMode::AREA_FACTOR) + return; + + float rtc_min_value = std::pow(10., (rtc_min_value_db / 10.)); + float rtc_transition_value = std::pow(10., (rtc_transition_value_db / 10.)); + + info << "applying min. RTC value: " << rtc_min_value_db + << " [dB] ~= " << rtc_min_value << pyre::journal::newline; + + if (rtc_min_value_mode == rtcMinValueMode::TRANSITION) { + if (std::isnan(rtc_transition_value_db)) { + info << "RTC transition value not provided. Using RTC min value + 3 dB." + << pyre::journal::newline; + rtc_transition_value_db = rtc_min_value_db + 3.0f; + } + else { + info << "RTC transition value: " << rtc_transition_value_db + << " [dB] ~= " << rtc_transition_value << pyre::journal::newline; + } + if (rtc_min_value_db >= rtc_transition_value_db) { + std::string error_message = + "ERROR rtc_min_value_db must be less than " + "rtc_transition_value_db for TRANSITION mode."; + throw isce3::except::InvalidArgument(ISCE_SRCINFO(), error_message); + } + } + + info << pyre::journal::endl; + + _Pragma("omp parallel for schedule(dynamic) collapse(2)") + for (int i = 0; i < out_array.length(); ++i) + for (int j = 0; j < out_array.width(); ++j) { + // Skip if RTC value is valid, i.e., above min RTC value + if ((out_array(i, j) >= rtc_min_value && + rtc_min_value_mode != rtcMinValueMode::TRANSITION) || + out_array(i, j) >= rtc_transition_value) + continue; + if (rtc_min_value_mode == rtcMinValueMode::TRANSITION) { + /* + float new_rtc_value = rtc_transition_value + + (rtc_transition_value - out_array(i, j)) * + (1 - rtc_transition_value) / + (rtc_transition_value - rtc_min_value); + */ + // Smooth transition using logistic function + + // Steepness parameter for logistic function + const float k = 20.0; + + // Normalized distance between rtc_min_value and + // rtc_transition_value + const float t = (out_array(i, j) - rtc_min_value) / + (rtc_transition_value - rtc_min_value); + + // Logistic in [0, 1] + const float sigmoid = 1.0f / (1.0f + std::exp(-k * (t - 0.5f))); + + // Scale logistic output from: + // - `1.0` at `rtc_min_value` + // - `rtc_transition_value` at `rtc_transition_value` + const float new_rtc_value = (1.0 + (rtc_transition_value - 1.0) * sigmoid); + + _Pragma("omp atomic write") out_array(i, j) = new_rtc_value; + } + else if (rtc_min_value_mode == rtcMinValueMode::CLIP) { + _Pragma("omp atomic write") out_array(i, j) = + rtc_min_value; + } + else if (rtc_min_value_mode == rtcMinValueMode::TRANSITION || + rtc_min_value_mode == rtcMinValueMode::BYPASS_RTC) { + _Pragma("omp atomic write") out_array(i, j) = 1.0f; + } + else if (rtc_min_value_mode == rtcMinValueMode::INVALID) { _Pragma("omp atomic write") out_array(i, j) = std::numeric_limits::quiet_NaN(); - } - info << "... done" << pyre::journal::endl; - } + } + } + info << "... done" << pyre::journal::endl; + } @@ -301,6 +364,8 @@ void applyRtc(const isce3::product::RadarGridParameters& radar_grid, rtcAreaMode rtc_area_mode, rtcAlgorithm rtc_algorithm, rtcAreaBetaMode rtc_area_beta_mode, double geogrid_upsampling, float rtc_min_value_db, + float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, double abs_cal_factor, float clip_min, float clip_max, isce3::io::Raster* out_sigma, const isce3::core::LUT2d& az_time_correction, @@ -347,8 +412,9 @@ void applyRtc(const isce3::product::RadarGridParameters& radar_grid, computeRtc(radar_grid, orbit, input_dop, dem_raster, *rtc_raster, input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_algorithm, rtc_area_beta_mode, - geogrid_upsampling, rtc_min_value_db, out_sigma, - az_time_correction, slant_range_correction, + geogrid_upsampling, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode, + out_sigma, az_time_correction, slant_range_correction, rtc_memory_mode); } else { info << "reading pre-computed RTC..." << pyre::journal::endl; @@ -375,21 +441,21 @@ void applyRtc(const isce3::product::RadarGridParameters& radar_grid, if (input_raster.dtype() == GDT_Float32 || (input_raster.dtype() == GDT_CFloat32 && flag_complex_to_real)) _applyRtc(input_raster, *rtc_raster, output_raster, - rtc_min_value_db, abs_cal_factor, clip_min, clip_max, info, + abs_cal_factor, clip_min, clip_max, info, flag_complex_to_real); else if (input_raster.dtype() == GDT_Float64 || (input_raster.dtype() == GDT_CFloat64 && flag_complex_to_real)) _applyRtc(input_raster, *rtc_raster, output_raster, - rtc_min_value_db, abs_cal_factor, clip_min, clip_max, info, + abs_cal_factor, clip_min, clip_max, info, flag_complex_to_real); else if (input_raster.dtype() == GDT_CFloat32) _applyRtc>(input_raster, *rtc_raster, output_raster, - rtc_min_value_db, abs_cal_factor, clip_min, clip_max, info, + abs_cal_factor, clip_min, clip_max, info, flag_complex_to_real); else if (input_raster.dtype() == GDT_CFloat64) _applyRtc>(input_raster, *rtc_raster, - output_raster, rtc_min_value_db, abs_cal_factor, clip_min, - clip_max, info, flag_complex_to_real); + output_raster, abs_cal_factor, + clip_min, clip_max, info, flag_complex_to_real); else { std::string error_message = "ERROR not implemented for input raster datatype"; @@ -442,6 +508,8 @@ void computeRtc(const isce3::product::RadarGridParameters& radar_grid, rtcAreaMode rtc_area_mode, rtcAlgorithm rtc_algorithm, rtcAreaBetaMode rtc_area_beta_mode, double geogrid_upsampling, float rtc_min_value_db, + float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, isce3::io::Raster* out_sigma, const isce3::core::LUT2d& az_time_correction, const isce3::core::LUT2d& slant_range_correction, @@ -478,8 +546,8 @@ void computeRtc(const isce3::product::RadarGridParameters& radar_grid, x0, dx, geogrid_length, geogrid_width, epsg, input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_algorithm, rtc_area_beta_mode, - geogrid_upsampling, rtc_min_value_db, - nullptr, nullptr, out_sigma, az_time_correction, + geogrid_upsampling, rtc_min_value_db, rtc_transition_value_db, + rtc_min_value_mode, nullptr, nullptr, out_sigma, az_time_correction, slant_range_correction, rtc_memory_mode, interp_method, threshold, num_iter, delta_range, min_block_size, max_block_size); @@ -496,6 +564,8 @@ void computeRtc(isce3::io::Raster& dem_raster, isce3::io::Raster& output_raster, rtcAreaMode rtc_area_mode, rtcAlgorithm rtc_algorithm, rtcAreaBetaMode rtc_area_beta_mode, double geogrid_upsampling, float rtc_min_value_db, + float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, isce3::io::Raster* out_geo_rdr, isce3::io::Raster* out_geo_grid, isce3::io::Raster* out_sigma, const isce3::core::LUT2d& az_time_correction, @@ -513,7 +583,8 @@ void computeRtc(isce3::io::Raster& dem_raster, isce3::io::Raster& output_raster, input_dop, geogrid, input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_area_beta_mode, geogrid_upsampling, - rtc_min_value_db, out_geo_rdr, out_geo_grid, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + out_geo_rdr, out_geo_grid, out_sigma, az_time_correction, slant_range_correction, rtc_memory_mode, interp_method, threshold, num_iter, delta_range, min_block_size, max_block_size); @@ -527,8 +598,8 @@ void computeRtc(isce3::io::Raster& dem_raster, isce3::io::Raster& output_raster, computeRtcBilinearDistribution(dem_raster, output_raster, radar_grid, orbit, input_dop, geogrid, input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, - geogrid_upsampling, rtc_min_value_db, out_sigma, - threshold, num_iter, delta_range, + geogrid_upsampling, rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + out_sigma, threshold, num_iter, delta_range, az_time_correction, slant_range_correction); } } @@ -729,6 +800,8 @@ void computeRtcBilinearDistribution(isce3::io::Raster& dem_raster, rtcOutputTerrainRadiometry output_terrain_radiometry, rtcAreaMode rtc_area_mode, double upsample_factor, float rtc_min_value_db, + float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, isce3::io::Raster* out_sigma, double threshold, int num_iter, double delta_range, const isce3::core::LUT2d& az_time_correction, @@ -747,7 +820,8 @@ void computeRtcBilinearDistribution(isce3::io::Raster& dem_raster, rtcAreaBetaMode rtc_area_beta_mode = rtcAreaBetaMode::PIXEL_AREA; print_parameters(info, radar_grid, input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_area_beta_mode, - upsample_factor, rtc_min_value_db); + upsample_factor, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode); const double yf = geogrid.startY() + geogrid.length() * geogrid.spacingY(); const double margin_x = std::abs(geogrid.spacingX()) * 20; @@ -1070,7 +1144,8 @@ void computeRtcBilinearDistribution(isce3::io::Raster& dem_raster, } } - _applyRtcMinValueDb(out_array, rtc_min_value_db, rtc_area_mode, info); + _applyRtcMinValueDb(out_array, rtc_min_value_db, rtc_transition_value_db, + rtc_min_value_mode, rtc_area_mode, info); output_raster.setBlock( out_array.data(), 0, 0, radar_grid.width(), radar_grid.length()); @@ -1623,6 +1698,8 @@ void computeRtcAreaProj(isce3::io::Raster& dem_raster, rtcOutputTerrainRadiometry output_terrain_radiometry, rtcAreaMode rtc_area_mode, rtcAreaBetaMode rtc_area_beta_mode, double geogrid_upsampling, float rtc_min_value_db, + float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode, isce3::io::Raster* out_geo_rdr, isce3::io::Raster* out_geo_grid, isce3::io::Raster* out_sigma, const isce3::core::LUT2d& az_time_correction, @@ -1656,7 +1733,8 @@ void computeRtcAreaProj(isce3::io::Raster& dem_raster, geogrid.print(); print_parameters(info, radar_grid, input_terrain_radiometry, output_terrain_radiometry, rtc_area_mode, rtc_area_beta_mode, - geogrid_upsampling, rtc_min_value_db); + geogrid_upsampling, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode); int epsgcode = dem_raster.getEPSG(); info << "DEM EPSG: " << epsgcode << pyre::journal::endl; @@ -1759,7 +1837,9 @@ void computeRtcAreaProj(isce3::io::Raster& dem_raster, _normalizeRtcArea(out_gamma_array, out_beta_array, info); } - _applyRtcMinValueDb(out_gamma_array, rtc_min_value_db, rtc_area_mode, info); + _applyRtcMinValueDb(out_gamma_array, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode, + rtc_area_mode, info); info << "saving RTC area normalization factor" << pyre::journal::endl; output_raster.setBlock( @@ -1874,6 +1954,34 @@ std::string get_rtc_area_beta_mode_str(rtcAreaBetaMode rtc_area_beta_mode) return rtc_area_beta_mode_str; } +std::string get_rtc_min_value_mode_str( + isce3::geometry::rtcMinValueMode rtc_min_value_mode) +{ + std::string rtc_min_value_mode_str; + switch (rtc_min_value_mode) { + case isce3::geometry::rtcMinValueMode::DISABLED: + rtc_min_value_mode_str = "disabled (no minimum value thresholding applied)"; + break; + case isce3::geometry::rtcMinValueMode::CLIP: + rtc_min_value_mode_str = "clip (to RTC minimum value)"; + break; + case isce3::geometry::rtcMinValueMode::INVALID: + rtc_min_value_mode_str = "invalid (samples with RTC factor below minimum value are considered invalid)"; + break; + case isce3::geometry::rtcMinValueMode::BYPASS_RTC: + rtc_min_value_mode_str = "bypass RTC (no correction applied to samples with RTC factor below minimum value)"; + break; + case isce3::geometry::rtcMinValueMode::TRANSITION: + rtc_min_value_mode_str = "transition (same as bypass RTC, but with smooth transition between 'rtc_transition_value_db' and 'rtc_min_value_db')"; + break; + default: + std::string error_message = "ERROR invalid RTC min value mode"; + throw isce3::except::InvalidArgument(ISCE_SRCINFO(), error_message); + break; + } + return rtc_min_value_mode_str; +} + /** Convert enum output_mode to string */ std::string get_rtc_algorithm_str(rtcAlgorithm rtc_algorithm) @@ -1900,7 +2008,8 @@ void print_parameters(pyre::journal::info_t& channel, rtcOutputTerrainRadiometry output_terrain_radiometry, rtcAreaMode rtc_area_mode, rtcAreaBetaMode rtc_area_beta_mode, double geogrid_upsampling, - float rtc_min_value_db) + float rtc_min_value_db, float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode) { std::string input_terrain_radiometry_str = get_input_terrain_radiometry_str(input_terrain_radiometry); @@ -1913,6 +2022,9 @@ void print_parameters(pyre::journal::info_t& channel, std::string rtc_area_beta_mode_str = get_rtc_area_beta_mode_str( rtc_area_beta_mode); + std::string rtc_min_value_mode_str = get_rtc_min_value_mode_str( + rtc_min_value_mode); + channel << "input radiometry: " << input_terrain_radiometry_str << pyre::journal::newline << "output radiometry: " << output_terrain_radiometry_str @@ -1926,7 +2038,12 @@ void print_parameters(pyre::journal::info_t& channel, << pyre::journal::newline << "radar-grid length: " << radar_grid.length() << ", width: " << radar_grid.width() << pyre::journal::newline - << "RTC min value [dB]: " << rtc_min_value_db - << pyre::journal::newline << pyre::journal::endl; + << "RTC min value mode: " << rtc_min_value_mode_str + << pyre::journal::newline; + if (rtc_min_value_mode != isce3::geometry::rtcMinValueMode::DISABLED) { + channel << "RTC min value [dB]: " << rtc_min_value_db + << pyre::journal::newline; + } + channel << pyre::journal::endl; } }} // namespace isce3::geometry diff --git a/cxx/isce3/geometry/RTC.h b/cxx/isce3/geometry/RTC.h index cd4275246..8bb95ffa3 100644 --- a/cxx/isce3/geometry/RTC.h +++ b/cxx/isce3/geometry/RTC.h @@ -39,6 +39,15 @@ enum rtcAreaMode { AREA = 0, AREA_FACTOR = 1 }; * RTC_AREA_PROJECTION) */ enum rtcAlgorithm { RTC_BILINEAR_DISTRIBUTION = 0, RTC_AREA_PROJECTION = 1 }; +/** Enumeration type to indicate RTC minimum value mode */ +enum rtcMinValueMode { + DISABLED = 0, + CLIP = 1, + INVALID = 2, + BYPASS_RTC = 3, + TRANSITION = 4 +}; + /**Enumeration type to indicate RTC area beta mode * (option only available for rtcAlgorithm.RTC_AREA_PROJECTION) */ @@ -79,6 +88,18 @@ enum rtcAreaBetaMode { * @param[in] rtc_min_value_db Minimum value for the RTC area normalization * factor. Radar data with RTC area normalization factor below this limit will * be set to NaN. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[in] abs_cal_factor Absolute calibration factor. * @param[in] clip_min Clip minimum output values * @param[in] clip_max Clip maximum output values @@ -106,6 +127,9 @@ void applyRtc(const isce3::product::RadarGridParameters& radarGrid, rtcAreaBetaMode rtc_area_beta_mode = rtcAreaBetaMode::AUTO, double geogrid_upsampling = std::numeric_limits::quiet_NaN(), float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, double abs_cal_factor = 1, float clip_min = std::numeric_limits::quiet_NaN(), float clip_max = std::numeric_limits::quiet_NaN(), @@ -136,7 +160,19 @@ void applyRtc(const isce3::product::RadarGridParameters& radarGrid, * @param[in] geogrid_upsampling Geogrid upsampling * @param[in] rtc_min_value_db Minimum value for the RTC area normalization * factor. Radar data with RTC area normalization factor below this limit will - * be set to NaN.. + * be set to NaN. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[out] out_sigma Output sigma surface area * (rtc_area_mode = AREA) or area factor (rtc_area_mode = AREA_FACTOR) raster * @param[in] az_time_correction Azimuth additive correction, in @@ -164,6 +200,9 @@ void computeRtc(const isce3::product::RadarGridParameters& radarGrid, rtcAreaBetaMode rtc_area_beta_mode = rtcAreaBetaMode::AUTO, double geogrid_upsampling = std::numeric_limits::quiet_NaN(), float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, isce3::io::Raster* out_sigma = nullptr, const isce3::core::LUT2d& az_time_correction = {}, const isce3::core::LUT2d& slant_range_correction = {}, @@ -203,6 +242,18 @@ void computeRtc(const isce3::product::RadarGridParameters& radarGrid, * @param[in] rtc_min_value_db Minimum value for the RTC area normalization * factor. Radar data with RTC area normalization factor below this limit will * be set to NaN + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[out] out_geo_rdr Raster to which the radar-grid positions * (range and azimuth) of the geogrid pixels vertices will be saved. * @param[out] out_geo_grid Raster to which the radar-grid positions @@ -236,6 +287,9 @@ void computeRtc(isce3::io::Raster& dem_raster, isce3::io::Raster& output_raster, rtcAreaBetaMode rtc_area_beta_mode = rtcAreaBetaMode::AUTO, double geogrid_upsampling = std::numeric_limits::quiet_NaN(), float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, isce3::io::Raster* out_geo_rdr = nullptr, isce3::io::Raster* out_geo_grid = nullptr, isce3::io::Raster* out_sigma = nullptr, @@ -266,6 +320,18 @@ void computeRtc(isce3::io::Raster& dem_raster, isce3::io::Raster& output_raster, * @param[in] rtc_min_value_db Minimum value for the RTC area normalization * factor. Radar data with RTC area normalization factor below this limit will * be set to NaN + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[out] out_sigma Output sigma surface area * (rtc_area_mode = AREA) or area factor (rtc_area_mode = AREA_FACTOR) raster * @param[in] threshold Azimuth time threshold for convergence (s) @@ -289,6 +355,9 @@ void computeRtcBilinearDistribution(isce3::io::Raster& dem_raster, rtcAreaMode rtc_area_mode = rtcAreaMode::AREA_FACTOR, double geogrid_upsampling = std::numeric_limits::quiet_NaN(), float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, isce3::io::Raster* out_sigma = nullptr, double threshold = 1e-8, int num_iter = 100, double delta_range = 1e-8, const isce3::core::LUT2d& az_time_correction = {}, @@ -314,7 +383,19 @@ void computeRtcBilinearDistribution(isce3::io::Raster& dem_raster, * @param[in] geogrid_upsampling Geogrid upsampling * @param[in] rtc_min_value_db Minimum value for the RTC area normalization * factor. Radar data with RTC area normalization factor below this limit will - * be set to NaN.. + * be set to NaN. + * @param[in] rtc_transition_value_db RTC transition start value in dB used when + * `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + * between `rtc_transition_value_db` and `rtc_min_value_db` will have + * a smooth transition applied to the RTC correction. + * @param[in] rtc_min_value_mode Specifies how the RTC minimum value is handled: + * DISABLED - No minimum-value thresholding is applied. + * CLIP - RTC values below the minimum are clipped to the minimum value. + * INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + * BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + * the minimum value. + * TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + * `rtc_transition_value_db` and `rtc_min_value_db`. * @param[out] out_geo_rdr Raster to which the radar-grid positions * (range and azimuth) of the geogrid pixels vertices will be saved. * @param[out] out_geo_grid Raster to which the radar-grid positions @@ -347,6 +428,9 @@ void computeRtcAreaProj(isce3::io::Raster& dem, rtcAreaBetaMode rtc_area_beta_mode = rtcAreaBetaMode::AUTO, double geogrid_upsampling = std::numeric_limits::quiet_NaN(), float rtc_min_value_db = std::numeric_limits::quiet_NaN(), + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(), + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION, isce3::io::Raster* out_geo_rdr = nullptr, isce3::io::Raster* out_geo_grid = nullptr, isce3::io::Raster* out_sigma = nullptr, @@ -375,6 +459,8 @@ std::string get_output_terrain_radiometry_str( rtcOutputTerrainRadiometry output_terrain_radiometry); std::string get_rtc_area_mode_str(rtcAreaMode rtc_area_mode); std::string get_rtc_area_beta_mode_str(rtcAreaBetaMode rtc_area_beta_mode); +std::string get_rtc_min_value_mode_str( + rtcMinValueMode rtc_min_value_mode); std::string get_rtc_algorithm_str(rtcAlgorithm rtc_algorithm); void print_parameters(pyre::journal::info_t& channel, @@ -384,5 +470,8 @@ void print_parameters(pyre::journal::info_t& channel, rtcAreaMode rtc_area_mode, rtcAreaBetaMode rtc_area_beta_mode, double geogrid_upsampling, - float rtc_min_value_db); + float rtc_min_value_db, + float rtc_transition_value_db, + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION); }} // namespace isce3::geometry diff --git a/python/extensions/pybind_isce3/geocode/GeocodeCov.cpp b/python/extensions/pybind_isce3/geocode/GeocodeCov.cpp index 255df9108..05e12b8c3 100644 --- a/python/extensions/pybind_isce3/geocode/GeocodeCov.cpp +++ b/python/extensions/pybind_isce3/geocode/GeocodeCov.cpp @@ -22,6 +22,7 @@ using isce3::geometry::rtcAlgorithm; using isce3::geometry::rtcAreaBetaMode; using isce3::geometry::rtcInputTerrainRadiometry; using isce3::geometry::rtcOutputTerrainRadiometry; +using isce3::geometry::rtcMinValueMode; using isce3::io::Raster; using isce3::product::RadarGridParameters; @@ -81,6 +82,9 @@ void addbinding(py::class_>& pyGeocode) py::arg("exponent") = 0, py::arg("rtc_min_value_db") = std::numeric_limits::quiet_NaN(), + py::arg("rtc_transition_value_db") = + std::numeric_limits::quiet_NaN(), + py::arg("rtc_min_value_mode") = rtcMinValueMode::DISABLED, py::arg("rtc_upsampling") = std::numeric_limits::quiet_NaN(), py::arg("rtc_algorithm") = @@ -175,7 +179,21 @@ void addbinding(py::class_>& pyGeocode) of the input raster (1 for real and 2 for complex rasters). rtc_min_value_db: float, optional Minimum value for the RTC area factor. Radar data with - RTC area factor below this limit will be set to NaN. + RTC area factor below this limit will be considered invalid. + rtc_transition_value_db : float, optional + RTC transition start value in dB used when + `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + between `rtc_transition_value_db` and `rtc_min_value_db` will have + a smooth transition applied to the RTC correction. + rtc_min_value_mode: isce3.geometry.RtcMinValueMode, optional + Specifies how the RTC minimum value is handled: + DISABLED - No minimum-value thresholding is applied. + CLIP - RTC values below the minimum are clipped to the minimum value. + INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + the minimum value. + TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + `rtc_transition_value_db` and `rtc_min_value_db`. rtc_geogrid_upsampling: int, optional Geogrid upsampling to compute the radiometric terrain correction RTC. diff --git a/python/extensions/pybind_isce3/geocode/GeocodePolygon.cpp b/python/extensions/pybind_isce3/geocode/GeocodePolygon.cpp index ee194d5fd..8141e395a 100644 --- a/python/extensions/pybind_isce3/geocode/GeocodePolygon.cpp +++ b/python/extensions/pybind_isce3/geocode/GeocodePolygon.cpp @@ -10,7 +10,7 @@ namespace py = pybind11; using isce3::geocode::GeocodePolygon; using isce3::geometry::rtcInputTerrainRadiometry; using isce3::geometry::rtcOutputTerrainRadiometry; -using isce3::geometry::rtcInputTerrainRadiometry; +using isce3::geometry::rtcMinValueMode; template void addbinding(py::class_> &pyGeocodePolygon) @@ -25,7 +25,7 @@ void addbinding(py::class_> &pyGeocodePolygon) const isce3::core::LUT2d &, isce3::io::Raster &, double, - int, + int, double>(), py::arg("x_vect"), py::arg("y_vect"), @@ -70,6 +70,8 @@ void addbinding(py::class_> &pyGeocodePolygon) py::arg("exponent") = 0, py::arg("geogrid_upsampling") = 1, py::arg("rtc_min_value_db") = std::numeric_limits::quiet_NaN(), + py::arg("rtc_transition_value_db") = std::numeric_limits::quiet_NaN(), + py::arg("rtc_min_value_mode") = rtcMinValueMode::DISABLED, py::arg("abs_cal_factor") = 1, py::arg("radargrid_nlooks") = 1, py::arg("output_off_diag_terms") = nullptr, @@ -80,7 +82,9 @@ void addbinding(py::class_> &pyGeocodePolygon) R"( Calculate the mean value of radar-grid samples using a polygon defined over geographical coordinates. - Arguments: + + Parameters: + ---------- radar_grid Radar grid input_dop Doppler LUT associated with the radar grid input_raster Input raster @@ -95,6 +99,15 @@ void addbinding(py::class_> &pyGeocodePolygon) output_mode Output mode geogrid_upsampling Geogrid upsampling (in each direction) rtc_min_value_db Minimum value for the RTC area factor. + rtc_min_value_mode + Determine whether to clip RTC values + below the minimum RTC value specified by `rtc_min_value_db`, instead of + considering associated radar samples as invalid. + If `true`, RTC values below the minimum threshold are clipped to + that threshold and associated radar samples are considered valid. + If `false`, radar samples corresponding to RTC values below the + minimum threshold are considered invalid, which may result in + NaNs in the output if no valid samples are available. Radar data with RTC area factor below this limit are ignored. abs_cal_factor Absolute calibration factor. radar_grid_nlooks Radar grid number of looks. This diff --git a/python/extensions/pybind_isce3/geometry/RTC.cpp b/python/extensions/pybind_isce3/geometry/RTC.cpp index e8735250d..d967d56c4 100644 --- a/python/extensions/pybind_isce3/geometry/RTC.cpp +++ b/python/extensions/pybind_isce3/geometry/RTC.cpp @@ -13,6 +13,7 @@ namespace py = pybind11; using isce3::geometry::rtcAlgorithm; using isce3::geometry::rtcInputTerrainRadiometry; using isce3::geometry::rtcOutputTerrainRadiometry; +using isce3::geometry::rtcMinValueMode; using isce3::geometry::rtcAreaMode; using isce3::geometry::rtcAreaBetaMode; @@ -32,6 +33,17 @@ void addbinding( .value("GAMMA_NAUGHT", rtcOutputTerrainRadiometry::GAMMA_NAUGHT); } +void addbinding( + py::enum_& pyRtcMinValueMode) +{ + pyRtcMinValueMode + .value("DISABLED", rtcMinValueMode::DISABLED) + .value("CLIP", rtcMinValueMode::CLIP) + .value("INVALID", rtcMinValueMode::INVALID) + .value("BYPASS_RTC", rtcMinValueMode::BYPASS_RTC) + .value("TRANSITION", rtcMinValueMode::TRANSITION); +} + void addbinding(py::enum_ & pyAlgorithm) { pyAlgorithm @@ -87,6 +99,9 @@ void addbinding_apply_rtc(pybind11::module& m) std::numeric_limits::quiet_NaN(), py::arg("rtc_min_value_db") = std::numeric_limits::quiet_NaN(), + py::arg("rtc_transition_value_db") = + std::numeric_limits::quiet_NaN(), + py::arg("rtc_min_value_mode") = rtcMinValueMode::DISABLED, py::arg("abs_cal_factor") = 1, py::arg("clip_min") = std::numeric_limits::quiet_NaN(), py::arg("clip_max") = std::numeric_limits::quiet_NaN(), @@ -133,6 +148,20 @@ void addbinding_apply_rtc(pybind11::module& m) rtc_min_value_db : float, optional Minimum value for the RTC area factor. Radar data with RTC area factor below this limit are ignored. + rtc_transition_value_db : float, optional + RTC transition start value in dB used when + `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + between `rtc_transition_value_db` and `rtc_min_value_db` will have + a smooth transition applied to the RTC correction. + rtc_min_value_mode: isce3.geometry.RtcMinValueMode, optional + Specifies how the RTC minimum value is handled: + DISABLED - No minimum-value thresholding is applied. + CLIP - RTC values below the minimum are clipped to the minimum value. + INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + the minimum value. + TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + `rtc_transition_value_db` and `rtc_min_value_db`. abs_cal_factor : double, optional Absolute calibration factor. clip_min : float, optional @@ -167,7 +196,7 @@ void addbinding_compute_rtc(pybind11::module& m) isce3::io::Raster&, rtcInputTerrainRadiometry, rtcOutputTerrainRadiometry, rtcAreaMode, rtcAlgorithm, rtcAreaBetaMode, - double, float, isce3::io::Raster*, + double, float, float, rtcMinValueMode, isce3::io::Raster*, const isce3::core::LUT2d&, const isce3::core::LUT2d&, isce3::core::MemoryModeBlocksY, @@ -189,6 +218,9 @@ void addbinding_compute_rtc(pybind11::module& m) std::numeric_limits::quiet_NaN(), py::arg("rtc_min_value_db") = std::numeric_limits::quiet_NaN(), + py::arg("rtc_transition_value_db") = + std::numeric_limits::quiet_NaN(), + py::arg("rtc_min_value_mode") = rtcMinValueMode::DISABLED, py::arg("out_sigma") = nullptr, py::arg("az_time_correction") = isce3::core::LUT2d(), py::arg("slant_range_correction") = isce3::core::LUT2d(), @@ -233,7 +265,21 @@ void addbinding_compute_rtc(pybind11::module& m) rtc_min_value_db : float, optional Minimum value for the RTC area factor. Radar data with RTC area factor below this limit are ignored. + rtc_transition_value_db : float, optional + RTC transition start value in dB used when + `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + between `rtc_transition_value_db` and `rtc_min_value_db` will have + a smooth transition applied to the RTC correction. + rtc_min_value_mode: isce3.geometry.RtcMinValueMode, optional + Specifies how the RTC minimum value is handled: + DISABLED - No minimum-value thresholding is applied. + CLIP - RTC values below the minimum are clipped to the minimum value. + INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + the minimum value. + TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between out_sigma : isce3.io.Raster, optional + `rtc_transition_value_db` and `rtc_min_value_db`. Output sigma surface area (rtc_area_mode = AREA) or area factor (rtc_area_mode = AREA_FACTOR) raster az_time_correction: isce3.core.LUT2d @@ -271,7 +317,7 @@ void addbinding_compute_rtc_bbox(pybind11::module& m) const int, const int, rtcInputTerrainRadiometry, rtcOutputTerrainRadiometry, rtcAreaMode, rtcAlgorithm, rtcAreaBetaMode, - double, float, isce3::io::Raster*, + double, float, float, rtcMinValueMode, isce3::io::Raster*, isce3::io::Raster*, isce3::io::Raster*, const isce3::core::LUT2d&, const isce3::core::LUT2d&, @@ -297,6 +343,9 @@ void addbinding_compute_rtc_bbox(pybind11::module& m) std::numeric_limits::quiet_NaN(), py::arg("rtc_min_value_db") = std::numeric_limits::quiet_NaN(), + py::arg("rtc_transition_value_db") = + std::numeric_limits::quiet_NaN(), + py::arg("rtc_min_value_mode") = rtcMinValueMode::DISABLED, py::arg("out_geo_rdr") = nullptr, py::arg("out_geo_grid") = nullptr, py::arg("out_sigma") = nullptr, py::arg("az_time_correction") = isce3::core::LUT2d(), @@ -355,7 +404,21 @@ void addbinding_compute_rtc_bbox(pybind11::module& m) Geogrid upsampling (in each direction) rtc_min_value_db : float, optional Minimum value for the RTC area factor. Radar - data with RTC area factor below this limit are ignored. + data with RTC area factor below this limit are ignored. + rtc_transition_value_db : float, optional + RTC transition start value in dB used when + `rtc_min_value_mode = TRANSITION`. Samples with an RTC area factor + between `rtc_transition_value_db` and `rtc_min_value_db` will have + a smooth transition applied to the RTC correction. + rtc_min_value_mode: isce3.geometry.RtcMinValueMode, optional + Specifies how the RTC minimum value is handled: + DISABLED - No minimum-value thresholding is applied. + CLIP - RTC values below the minimum are clipped to the minimum value. + INVALID - Samples with an RTC factor below the minimum value are marked as invalid. + BYPASS_RTC - RTC correction is bypassed for samples with an RTC factor below + the minimum value. + TRANSITION - Same as BYPASS_RTC, but applies a smooth transition between + `rtc_transition_value_db` and `rtc_min_value_db`. out_geo_rdr : isce3.io.Raster, optional Raster to which the radar-grid positions (range and azimuth) of the geogrid pixels vertices will be saved (output). diff --git a/python/extensions/pybind_isce3/geometry/RTC.h b/python/extensions/pybind_isce3/geometry/RTC.h index ceb1acc08..7658e43eb 100644 --- a/python/extensions/pybind_isce3/geometry/RTC.h +++ b/python/extensions/pybind_isce3/geometry/RTC.h @@ -8,11 +8,14 @@ using isce3::geometry::rtcAreaMode; using isce3::geometry::rtcAreaBetaMode; using isce3::geometry::rtcInputTerrainRadiometry; using isce3::geometry::rtcOutputTerrainRadiometry; +using isce3::geometry::rtcMinValueMode; void addbinding( pybind11::enum_& pyInputTerrainRadiometry); void addbinding( pybind11::enum_& pyOutputTerrainRadiometry); +void addbinding( + pybind11::enum_& pyRtcMinValueMode); void addbinding(pybind11::enum_ & pyRtcAlgorithm); void addbinding(pybind11::enum_ & pyRtcAreaMode); void addbinding(pybind11::enum_ & pyRtcAreaBetaMode); diff --git a/python/extensions/pybind_isce3/geometry/geometry.cpp b/python/extensions/pybind_isce3/geometry/geometry.cpp index 8193aa3bd..012a87bab 100644 --- a/python/extensions/pybind_isce3/geometry/geometry.cpp +++ b/python/extensions/pybind_isce3/geometry/geometry.cpp @@ -38,6 +38,8 @@ void addsubmodule_geometry(py::module & m) pyInputTerrainRadiometry(geometry, "RtcInputTerrainRadiometry"); py::enum_ pyOutputTerrainRadiometry(geometry, "RtcOutputTerrainRadiometry"); + py::enum_ + pyRtcMinValueMode(geometry, "RtcMinValueMode"); py::enum_ pyRtcAlgorithm(geometry, "RtcAlgorithm"); py::enum_ @@ -51,6 +53,7 @@ void addsubmodule_geometry(py::module & m) addbinding(pyRdr2Geo); addbinding(pyInputTerrainRadiometry); addbinding(pyOutputTerrainRadiometry); + addbinding(pyRtcMinValueMode); addbinding(pyRtcAlgorithm); addbinding(pyRtcAreaMode); addbinding(pyRtcAreaBetaMode); diff --git a/python/packages/nisar/products/writers/GcovWriter.py b/python/packages/nisar/products/writers/GcovWriter.py index 3016bd31c..06c0aa654 100644 --- a/python/packages/nisar/products/writers/GcovWriter.py +++ b/python/packages/nisar/products/writers/GcovWriter.py @@ -48,6 +48,8 @@ def run_geocode_cov(cfg, hdf5_obj, root_ds, rtc_algorithm = rtc_dict['algorithm_type_enum'] input_terrain_radiometry = rtc_dict['input_terrain_radiometry_enum'] rtc_min_value_db = rtc_dict['rtc_min_value_db'] + rtc_transition_value_db = rtc_dict['rtc_transition_value_db'] + rtc_min_value_mode = rtc_dict['rtc_min_value_mode_enum'] rtc_upsampling = rtc_dict['dem_upsampling'] rtc_area_beta_mode = \ @@ -221,6 +223,8 @@ def run_geocode_cov(cfg, hdf5_obj, root_ds, input_terrain_radiometry=input_terrain_radiometry, output_terrain_radiometry=output_terrain_radiometry, rtc_min_value_db=rtc_min_value_db, + rtc_transition_value_db=rtc_transition_value_db, + rtc_min_value_mode=rtc_min_value_mode, rtc_upsampling=rtc_upsampling, rtc_algorithm=rtc_algorithm, radargrid_nlooks=radar_grid_nlooks, diff --git a/python/packages/nisar/workflows/gcov_runconfig.py b/python/packages/nisar/workflows/gcov_runconfig.py index 81443c1f5..b18a0b60d 100644 --- a/python/packages/nisar/workflows/gcov_runconfig.py +++ b/python/packages/nisar/workflows/gcov_runconfig.py @@ -102,6 +102,26 @@ def load(self): rtc_dict['output_type_enum'] = \ isce3.geometry.RtcOutputTerrainRadiometry.GAMMA_NAUGHT + rtc_min_value_mode = rtc_dict['rtc_min_value_mode'] + if rtc_min_value_mode == 'disabled': + rtc_dict['rtc_min_value_mode_enum'] = \ + isce3.geometry.RtcMinValueMode.DISABLED + elif rtc_min_value_mode == 'clip': + rtc_dict['rtc_min_value_mode_enum'] = \ + isce3.geometry.RtcMinValueMode.CLIP + elif rtc_min_value_mode == 'invalid': + rtc_dict['rtc_min_value_mode_enum'] = \ + isce3.geometry.RtcMinValueMode.INVALID + elif rtc_min_value_mode == 'bypass_rtc': + rtc_dict['rtc_min_value_mode_enum'] = \ + isce3.geometry.RtcMinValueMode.BYPASS_RTC + elif rtc_min_value_mode == 'transition': + rtc_dict['rtc_min_value_mode_enum'] = \ + isce3.geometry.RtcMinValueMode.TRANSITION + else: + raise ValueError( + f"unexpected rtc_min_value_mode: {rtc_min_value_mode}") + geocode_algorithm = self.cfg['processing']['geocode']['algorithm_type'] geocode_dict['output_mode'] = \ isce3.geocode.normalize_geocode_output_mode(geocode_algorithm) diff --git a/share/nisar/defaults/gcov.yaml b/share/nisar/defaults/gcov.yaml index edca80568..9e92fbe80 100644 --- a/share/nisar/defaults/gcov.yaml +++ b/share/nisar/defaults/gcov.yaml @@ -254,12 +254,28 @@ runconfig: # "sigma0" input_terrain_radiometry: beta0 + # RTC minimum value mode. Options: + # "disabled" - No minimum value enforcement + # "clip" - Clip values below the minimum RTC area factor + # "invalid" - Set output pixels to invalid where RTC area factor is below + # the minimum threshold + # "bypass_rtc" - Bypass RTC correction where RTC area factor is below + # the minimum threshold (i.e., output pixel = input pixel) + # "transition" - Apply a smooth (linear) transition between threshold value + # defined by `rtc_min_value_db` and the bypass RTC value + # defined by `rtc_transition_value_db` + rtc_min_value_mode: transition + # Minimum RTC area factor (in dB). Specifies the lowest # allowable denominator (in dB) for dividing GCOV samples. # If not set, no minimum is enforced, which may lead # to divisions by very small values and result in infinite # or inaccurate outputs. - rtc_min_value_db: + rtc_min_value_db: -30 + + # RTC transition value (in dB). Only relevant if + # rtc_min_value_mode is 'transition' + rtc_transition_value_db: -27 # RTC DEM upsampling factor dem_upsampling: 2 diff --git a/share/nisar/schemas/gcov.yaml b/share/nisar/schemas/gcov.yaml index 398696262..8b2835c7e 100644 --- a/share/nisar/schemas/gcov.yaml +++ b/share/nisar/schemas/gcov.yaml @@ -344,6 +344,17 @@ rtc_options: # Input terrain radiometry convention input_terrain_radiometry: enum('beta0', 'sigma0', required=False) + # RTC minimum value mode. Options: + # "disabled" - No minimum value enforcement + # "clip" - Clip values below the minimum RTC area factor + # "invalid" - Set output pixels to invalid where RTC area factor is below + # the minimum threshold + # "bypass_rtc" - Bypass RTC correction where RTC area factor is below + # the minimum threshold (i.e., output pixel = input pixel) + # "transition" - Same as "bypass_rtc", but with a smooth transition between the + # `rtc_transition_value_db` and `rtc_min_value_db` thresholds + rtc_min_value_mode: enum('disabled', 'clip', 'invalid', 'bypass_rtc', 'transition', required=False) + # Minimum RTC area factor (in dB). Specifies the lowest # allowable denominator (in dB) for dividing GCOV samples. # If not set, no minimum is enforced, which may lead @@ -351,6 +362,10 @@ rtc_options: # or inaccurate outputs. rtc_min_value_db: num(required=False) + # RTC transition value (in dB). Only relevant if + # rtc_min_value_mode is 'transition' + rtc_transition_value_db: num(required=False) + # RTC DEM upsampling factor dem_upsampling: int(min=1, required=False) diff --git a/tests/cxx/isce3/geocode/geocodeCov.cpp b/tests/cxx/isce3/geocode/geocodeCov.cpp index 908c64417..0963e23de 100644 --- a/tests/cxx/isce3/geocode/geocodeCov.cpp +++ b/tests/cxx/isce3/geocode/geocodeCov.cpp @@ -123,6 +123,9 @@ TEST(GeocodeTest, TestGeocodeCov) { isce3::geometry::rtcOutputTerrainRadiometry::GAMMA_NAUGHT; int exponent = 0; float rtc_min_value_db = std::numeric_limits::quiet_NaN(); + float rtc_transition_value_db = std::numeric_limits::quiet_NaN(); + isce3::geometry::rtcMinValueMode rtc_min_value_mode = + isce3::geometry::rtcMinValueMode::TRANSITION; double rtc_geogrid_upsampling = std::numeric_limits::quiet_NaN(); isce3::geometry::rtcAlgorithm rtc_algorithm = @@ -245,6 +248,7 @@ TEST(GeocodeTest, TestGeocodeCov) { flatten, geogrid_upsampling, flag_upsample_radar_grid, flag_apply_rtc, input_terrain_radiometry, output_terrain_radiometry, exponent, rtc_min_value_db, + rtc_transition_value_db, rtc_min_value_mode, rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, @@ -301,7 +305,8 @@ TEST(GeocodeTest, TestGeocodeCov) { demRaster, output_mode, flag_az_baseband_doppler, flatten, geogrid_upsampling, flag_upsample_radar_grid, flag_apply_rtc, input_terrain_radiometry, output_terrain_radiometry, exponent, - rtc_min_value_db, rtc_geogrid_upsampling, rtc_algorithm, + rtc_min_value_db, rtc_transition_value_db, rtc_min_value_mode, + rtc_geogrid_upsampling, rtc_algorithm, rtc_area_beta_mode, abs_cal_factor, clip_min, clip_max, min_nlooks, radar_grid_nlooks, &geocoded_off_diag_raster, out_geo_rdr, out_geo_dem,