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/7] 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/7] 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/7] 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/7] 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 fa38bc003b79929a469fe53d612a60ac513f821c Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Mon, 6 Oct 2025 15:29:03 -0700 Subject: [PATCH 5/7] Make the radar grid azimuth and range spacing parameters configurable in the static layers runconfig --- python/packages/nisar/workflows/static.py | 210 +++++++++++++--------- share/nisar/defaults/static.yaml | 10 ++ share/nisar/schemas/static.yaml | 2 + 3 files changed, 141 insertions(+), 81 deletions(-) diff --git a/python/packages/nisar/workflows/static.py b/python/packages/nisar/workflows/static.py index e7165519b..736659497 100644 --- a/python/packages/nisar/workflows/static.py +++ b/python/packages/nisar/workflows/static.py @@ -15,7 +15,8 @@ from nisar.static.geo_grid import get_output_geo_grid from nisar.static.geometry_layers import compute_geometry_layers from nisar.static.granule_id import form_granule_id -from nisar.static.layover_shadow_mask import compute_geocoded_layover_shadow_mask +from nisar.static.layover_shadow_mask import \ + compute_geocoded_layover_shadow_mask from nisar.static.logging import get_logger, log_elapsed_time from nisar.static.product import ( build_hdf5_dataset_creation_kwds_dict, @@ -25,7 +26,8 @@ ) from nisar.static.rtc_anf_layers import compute_rtc_anf_layers from nisar.static.runconfig import get_runconfig_params -from nisar.static.util import get_raster_dataset_metadata_item, scratch_directory +from nisar.static.util import get_raster_dataset_metadata_item, \ + scratch_directory from nisar.static.water_mask import binarize_and_reproject_water_mask import isce3 @@ -34,7 +36,8 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: """ - Run the NISAR Static Layers workflow with the specified run configuration file. + Run the NISAR Static Layers workflow with the specified run configuration + file. Will generate a single STATIC HDF5 granule, as specified in the runconfig. @@ -65,51 +68,75 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: # Construct a DEM interpolator. dem_interp_method = processing_params["dem"]["interp_method"] - dem = isce3.geometry.DEMInterpolator(dem_raster) - dem.interp_method = dem_interp_method # Construct the output geocoded coordinate grid. geo_grid_params = processing_params["geo_grid"] geo_grid = get_output_geo_grid(dem_raster=dem_raster, **geo_grid_params) logger.info(f"Output geo grid: {geo_grid}") - # Parse the orbit and attitude data from the input XML files. Crop the data to the - # time interval of interest to avoid possible geo2rdr convergence errors due to - # ambiguity between orbit periods. + # Parse the orbit and attitude data from the input XML files. Crop the + # data to the time interval of interest to avoid possible geo2rdr + # convergence errors due to ambiguity between orbit periods. orbit, attitude = get_cropped_orbit_and_attitude( orbit_xml_file=dynamic_ancillary_files["orbit_xml_file"], pointing_xml_file=dynamic_ancillary_files["pointing_xml_file"], **processing_params["ephemeris"], ) - # Get the Doppler centroid associated with the radar grid. NISAR image grids are - # always zero-Doppler. + # Get the Doppler centroid associated with the radar grid. NISAR image + # grids are always zero-Doppler. img_grid_doppler = isce3.core.LUT2d() - # Estimate the required radar grid spacing necessary to avoid undersampling the - # output geocoded grid. + # Estimate the required radar grid spacing necessary to avoid + # undersampling the output geocoded grid. # XXX: We deliberately don't pass geo2rdr parameters to either - # `infer_radar_grid_spacing_from_geo_grid()` or `get_bounding_radar_grid()` because - # these functions use `geo2rdr_bracket`, which takes different parameters than the - # legacy `geo2rdr` routine that's used by most of the workflow. Exposing both sets - # of parameters would introduce a lot of additional bookkeeping for seemingly little - # benefit. + # `infer_radar_grid_spacing_from_geo_grid()` or `get_bounding_radar_grid()` + # because these functions use `geo2rdr_bracket`, which takes different + # parameters than the legacy `geo2rdr` routine that's used by most of the + # workflow. Exposing both sets of parameters would introduce a lot of + # additional bookkeeping for seemingly little benefit. logger.info("Estimate maximum required radar grid spacing") radar_grid_params = processing_params["radar_grid"] look_side = radar_grid_params["look_side"] wavelength = radar_grid_params["wavelength"] - az_spacing, rg_spacing = isce3.geometry.infer_radar_grid_spacing_from_geo_grid( - geo_grid=geo_grid, - dem=dem, - orbit=orbit, - doppler=img_grid_doppler, - look_side=look_side, - wavelength=wavelength, - **radar_grid_params["spacing"], - ) - # Compute a radar grid whose footprint on the ground encloses the geocoded grid on - # which each output layer is defined. + radar_grid_spacing_params = radar_grid_params["spacing"] + az_spacing = radar_grid_spacing_params["az_spacing"] + rg_spacing = radar_grid_spacing_params["rg_spacing"] + + logger.info(f'az_spacing from runconfig: {az_spacing}') + logger.info(f'rg_spacing from runconfig: {rg_spacing}') + az_spacing_inferred, rg_spacing_inferred = \ + isce3.geometry.infer_radar_grid_spacing_from_geo_grid( + geo_grid=geo_grid, + dem=dem, + orbit=orbit, + doppler=img_grid_doppler, + look_side=look_side, + wavelength=wavelength, + **radar_grid_params["spacing"], + ) + logger.info(f'az_spacing from inferred: {az_spacing_inferred}') + logger.info(f'rg_spacing from inferred: {rg_spacing_inferred}') + + if rg_spacing is None or az_spacing is None: + az_spacing_inferred, rg_spacing_inferred = \ + isce3.geometry.infer_radar_grid_spacing_from_geo_grid( + geo_grid=geo_grid, + dem=dem, + orbit=orbit, + doppler=img_grid_doppler, + look_side=look_side, + wavelength=wavelength, + **radar_grid_params["spacing"], + ) + if rg_spacing is None: + rg_spacing = rg_spacing_inferred + if az_spacing is None: + az_spacing = az_spacing_inferred + + # Compute a radar grid whose footprint on the ground encloses the geocoded + # grid on which each output layer is defined. logger.info("Compute a radar grid spanning the region of interest") radar_grid = isce3.geometry.get_bounding_radar_grid( geo_grid=geo_grid, @@ -133,14 +160,15 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: **processing_params["doppler"], ) - # Create a (possibly temporary) scratch directory to store intermediate files. + # Create a (possibly temporary) scratch directory to store intermediate + # files. logger.info("Create scratch directory") with scratch_directory( product_paths["scratch_dir"], delete=product_paths["delete_scratch_dir"] ) as scratch_dir: - # Compute static geometry layers (height above ellipsoid, line-of-sight X and Y, - # local incidence angle). Results are stored as GeoTIFF files in the scratch - # directory. + # Compute static geometry layers (height above ellipsoid, + # line-of-sight X and Y, local incidence angle). Results are stored as + # GeoTIFF files in the scratch directory. logger.info("Compute static geometry layers") geo2rdr_params = processing_params["geo2rdr"] with log_elapsed_time(logger.info, "Computing static geometry layers"): @@ -155,13 +183,16 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: dem_interp_method=dem_interp_method, geo2rdr_params=geo2rdr_params, ) - reprojected_dem, los_east, los_north, local_inc_angle = geometry_layers + reprojected_dem, los_east, los_north, local_inc_angle = \ + geometry_layers - # Compute static mask layers (geocoded layover/shadow mask and water mask). + # Compute static mask layers (geocoded layover/shadow mask and water + # mask). # Results are stored as GeoTIFF files in the scratch directory. logger.info("Compute geocoded layover/shadow mask layer") geocode_params = processing_params["geocode"] - with log_elapsed_time(logger.info, "Computing geocoded layover/shadow mask"): + with log_elapsed_time(logger.info, + "Computing geocoded layover/shadow mask"): layover_shadow_mask = compute_geocoded_layover_shadow_mask( radar_grid=radar_grid, orbit=orbit, @@ -179,7 +210,8 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: ) logger.info("Compute re-projected binary water mask layer") - with log_elapsed_time(logger.info, "Computing re-projected binary water mask"): + with log_elapsed_time(logger.info, + "Computing re-projected binary water mask"): binary_water_mask = binarize_and_reproject_water_mask( water_distance_raster_file=water_mask_raster_file, geo_grid=geo_grid, @@ -187,43 +219,48 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: **processing_params["water_mask"], ) - # Compute radiometric terrain correction (RTC) area normalization factor (ANF) - # layers. Results are stored as GeoTIFF files in the scratch directory. + # Compute radiometric terrain correction (RTC) area normalization + # factor (ANF) layers. Results are stored as GeoTIFF files in the + # scratch directory. logger.info("Compute RTC area normalization factor layers") rtc_params = processing_params["rtc"] - with log_elapsed_time(logger.info, "Computing RTC area normalization layers"): - gamma0_to_beta0_factor, gamma0_to_sigma0_factor = compute_rtc_anf_layers( - radar_grid=radar_grid, - orbit=orbit, - native_doppler=native_doppler, - img_grid_doppler=img_grid_doppler, - geo_grid=geo_grid, - dem_raster=dem_raster, - scratch_dir=scratch_dir, - dem_interp_method=dem_interp_method, - geo2rdr_params=geo2rdr_params, - **geocode_params, - **rtc_params, - ) + with log_elapsed_time(logger.info, + "Computing RTC area normalization layers"): + gamma0_to_beta0_factor, gamma0_to_sigma0_factor = \ + compute_rtc_anf_layers( + radar_grid=radar_grid, + orbit=orbit, + native_doppler=native_doppler, + img_grid_doppler=img_grid_doppler, + geo_grid=geo_grid, + dem_raster=dem_raster, + scratch_dir=scratch_dir, + dem_interp_method=dem_interp_method, + geo2rdr_params=geo2rdr_params, + **geocode_params, + **rtc_params, + ) # Infer the orbit pass direction from the orbit velocity vectors. orbit_pass_direction = isce3.core.get_orbit_pass_direction(orbit) - # Pop 'product_counter' from the dict. This parameter is used to form the - # granule ID but doesn't correspond to any dataset in the 'identification' group - # of the product. The other dict contents will be passed as keyword arguments to - # `populate_identification_group()` below. + # Pop 'product_counter' from the dict. This parameter is used to form + # the granule ID but doesn't correspond to any dataset in the + # 'identification' group of the product. The other dict contents will + # be passed as keyword arguments to `populate_identification_group()` + # below. product_counter = primary_executable_params.pop("product_counter") # Get `validity_start_datetime` from the input parameters as a - # `datetime.datetime` object. If it was passed as a non-quoted string in ISO - # 8601 format, `ruamel.yaml` will have already converted it. Otherwise, manually - # convert it here. + # `datetime.datetime` object. If it was passed as a non-quoted string + # in ISO 8601 format, `ruamel.yaml` will have already converted it. + # Otherwise, manually convert it here. validity_start_datetime = primary_executable_params.pop( "validity_start_datetime" ) if not isinstance(validity_start_datetime, datetime): - validity_start_datetime = datetime.fromisoformat(validity_start_datetime) + validity_start_datetime = \ + datetime.fromisoformat(validity_start_datetime) # Get the unique ID of the granule based on the input parameters. radar_band = primary_executable_params["radar_band"] @@ -237,7 +274,8 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: x_posting=abs(geo_grid.spacing_x), y_posting=abs(geo_grid.spacing_y), validity_start_datetime=validity_start_datetime, - composite_release_id=primary_executable_params["composite_release_id"], + composite_release_id=primary_executable_params[ + "composite_release_id"], processing_center=primary_executable_params["processing_center"], product_counter=product_counter, **geometry_params, @@ -262,28 +300,34 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: # Populate global attributes in the root group of the file. logger.info("Populate global HDF5 attributes") product_spec = nisar.products.get_product_spec("STATIC") - nisar.products.populate_global_attrs_from_spec(hdf5_file, product_spec) + nisar.products.populate_global_attrs_from_spec(hdf5_file, + product_spec) # Get the current processing datetime (truncated to integer seconds # precision). - processing_datetime = datetime.now(timezone.utc).replace(microsecond=0) + processing_datetime = \ + datetime.now(timezone.utc).replace(microsecond=0) - # XXX: It's not really obvious what should go in the `zeroDopplerStartTime` - # and `zeroDopplerEndTime` datasets in the 'identification' group. For now, - # we'll use the start & stop time of the radar grid, which is roughly + # XXX: It's not really obvious what should go in the + # `zeroDopplerStartTime` and `zeroDopplerEndTime` datasets in the + # 'identification' group. For now, we'll use the start & stop time + # of the radar grid, which is roughly # analogous what they represent in other NISAR L2 products. - img_grid_start_datetime = radar_grid.ref_epoch + isce3.core.TimeDelta( - radar_grid.sensing_start - ) - img_grid_end_datetime = radar_grid.ref_epoch + isce3.core.TimeDelta( - radar_grid.sensing_stop - ) + img_grid_start_datetime = (radar_grid.ref_epoch + + isce3.core.TimeDelta( + radar_grid.sensing_start)) + img_grid_end_datetime = (radar_grid.ref_epoch + + isce3.core.TimeDelta( + radar_grid.sensing_stop)) # Populate the 'identification' group. logger.info("Populate identification metadata in output HDF5 file") - instrument_group = hdf5_file.create_group(f"/science/{radar_band}SAR") - identification_group = instrument_group.create_group("identification") - bounding_polygon = make_geo_grid_bounding_polygon(geo_grid, dem=dem) + instrument_group = \ + hdf5_file.create_group(f"/science/{radar_band}SAR") + identification_group = \ + instrument_group.create_group("identification") + bounding_polygon = make_geo_grid_bounding_polygon(geo_grid, + dem=dem) populate_identification_group( identification_group=identification_group, product_spec=product_spec, @@ -311,13 +355,15 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: ) # Populate the 'grids' group. - logger.info("Populate raster layers and grid coordinates in output HDF5") + logger.info("Populate raster layers and grid coordinates in output" + " HDF5") grids_group = instrument_group.create_group("STATIC/grids") dataset_creation_kwds = build_hdf5_dataset_creation_kwds_dict( dataset_shape=(geo_grid.length, geo_grid.width), **output_params["dataset"] ) - with log_elapsed_time(logger.info, "Writing raster layers to output HDF5"): + with log_elapsed_time(logger.info, "Writing raster layers to" + " output HDF5"): populate_grids_group( grids_group=grids_group, product_spec=product_spec, @@ -360,18 +406,20 @@ def main(args: Sequence[str] | None = None) -> None: Parameters ---------- args : sequence of str or None, optional - The list of arguments. If None, the argument list is taken from `sys.argv`. - Defaults to None. + The list of arguments. If None, the argument list is taken from + `sys.argv`. Defaults to None. """ # Setup the argument parser. - parser = argparse.ArgumentParser(description="Run the NISAR Static Layers workflow") + parser = argparse.ArgumentParser( + description="Run the NISAR Static Layers workflow") parser.add_argument( "config_file", type=Path, help="Run configuration YAML file for the STATIC workflow", ) - # Parse the arguments and convert the result to a dict of keyword arguments. + # Parse the arguments and convert the result to a dict of keyword + # arguments. kwargs = vars(parser.parse_args(args)) # Run the workflow with the unpacked keyword arguments. diff --git a/share/nisar/defaults/static.yaml b/share/nisar/defaults/static.yaml index 83077376f..791536cf2 100644 --- a/share/nisar/defaults/static.yaml +++ b/share/nisar/defaults/static.yaml @@ -225,6 +225,16 @@ runconfig: # Defaults to 0.24. wavelength: 0.24 spacing: + # [OPTIONAL] Azimuth interval, in seconds. Equivalent to the Pulse + # Repetition Interval (PRI). + # If not provided, it will be inferred from the specified geographic + # grid. If provided, must be a positive value. + az_spacing: + # [OPTIONAL] Slant-range spacing, in meters, of the radar grid. + # Must be a positive value. + # If not provided, it will be inferred from the specified geographic + # grid. If provided, must be a positive value. + rg_spacing: # [OPTIONAL] Side length of the NxN grid of samples used to estimate the # required radar grid pixel spacing necessary to avoid undersampling the # output geocoded grid. diff --git a/share/nisar/schemas/static.yaml b/share/nisar/schemas/static.yaml index 7d20a5670..d0110ac4f 100644 --- a/share/nisar/schemas/static.yaml +++ b/share/nisar/schemas/static.yaml @@ -94,6 +94,8 @@ radar_grid_options: bounding_box: include('radar_grid_bounding_box_options', required=False) radar_grid_spacing_options: + az_spacing: num(min=0.0, required=False) + rg_spacing: num(min=0.0, required=False) pts_per_side: int(min=2, required=False) radar_grid_bounding_box_options: From bbaf53149637daa4d9497d07b424574fe6646d1f Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Tue, 20 Jan 2026 16:53:56 -0800 Subject: [PATCH 6/7] Update the STATIC workflow to load the DEM only where needed. --- cxx/isce3/geometry/loadDem.h | 2 +- .../pybind_isce3/geometry/DEMInterpolator.cpp | 83 +++++++++++++++++++ .../pybind_isce3/geometry/DEMInterpolator.h | 1 + .../pybind_isce3/geometry/geometry.cpp | 1 + python/packages/nisar/workflows/static.py | 43 +++++----- 5 files changed, 109 insertions(+), 21 deletions(-) diff --git a/cxx/isce3/geometry/loadDem.h b/cxx/isce3/geometry/loadDem.h index d4c7ae57d..eb35139c8 100644 --- a/cxx/isce3/geometry/loadDem.h +++ b/cxx/isce3/geometry/loadDem.h @@ -61,7 +61,7 @@ isce3::geometry::DEMInterpolator DEMRasterToInterpolator( * (when the DEM is in geographic coordinates and `proj` is in polar stereo) * @param[in] minY Minimum Y/northing position * @param[in] maxY Maximum Y/northing position -* @param[out] dem_interp_block DEM interpolation object +* @param[out] dem_interp DEM interpolation object * @param[in] proj Projection object (nullptr to use same * DEM projection) * @param[in] dem_margin_x_in_pixels DEM X/easting margin in pixels diff --git a/python/extensions/pybind_isce3/geometry/DEMInterpolator.cpp b/python/extensions/pybind_isce3/geometry/DEMInterpolator.cpp index a82cab5d4..47167b30f 100644 --- a/python/extensions/pybind_isce3/geometry/DEMInterpolator.cpp +++ b/python/extensions/pybind_isce3/geometry/DEMInterpolator.cpp @@ -218,3 +218,86 @@ void addbinding_DEM_raster2interpolator(py::module& m) )") ; } + + +void addbinding_load_dem_from_proj(py::module& m) +{ + m.def("load_dem_from_proj", + [](isce3::io::Raster &dem_raster, + const double x0, + const double xf, + const double minY, + const double maxY, + const isce3::core::dataInterpMethod dem_interp_method, + isce3::core::ProjectionBase* proj, + const int dem_margin_x_in_pixels, + const int dem_margin_y_in_pixels, + const int dem_raster_band) { + + DEMInterp dem_interp(0, dem_interp_method); + + isce3::geometry::loadDemFromProj(dem_raster, + x0, + xf, + minY, + maxY, + &dem_interp, + proj, + dem_margin_x_in_pixels, + dem_margin_y_in_pixels, + dem_raster_band); + + return dem_interp; + }, + py::arg("dem_raster"), + py::arg("x0"), + py::arg("xf"), + py::arg("min_y"), + py::arg("max_y"), + py::arg("dem_interp_method") = isce3::core::BIQUINTIC_METHOD, + py::arg("proj") = nullptr, + py::arg("dem_margin_x_in_pixels") = 100, + py::arg("dem_margin_y_in_pixels") = 200, + py::arg("dem_raster_band") = 1, + R"( + Load DEM raster into a DEMInterpolator object around a given bounding box + in the same or different coordinate system as the DEM raster + + Parameters + ---------- + dem_raster: isce3.io.Raster + Raster of the DEM + x0: double + If the DEM is in geographic coordinates and the `x0` coordinate is not + from the polar stereo system EPSG 3031 or EPSG 3413, this point represents + the minimum X coordinate value. In this case, the maximum + longitude span that this function can handle is 180 degrees + (when the DEM is in geographic coordinates and `proj` is in polar stereo + xf: double + Easting/longitude of eastern edge of bounding box + If the DEM is in geographic coordinates and the `xf` coordinate is not + from the polar stereo system EPSG 3031 or EPSG 3413, this point represents + the maximum X coordinate value. In this case, the maximum + longitude span that this function can handle is 180 degrees + (when the DEM is in geographic coordinates and `proj` is in polar stereo) + min_y: double + Minimum Y/northing position + max_y: double + Maximum Y/northing position + dem_interp_method: isce3.core.DataInterpMethod + DEM interpolation method + proj: + Projection object (nullptr to use same DEM projection) + dem_margin_x_in_pixels, int + DEM X/easting margin in pixels + dem_margin_y_in_pixels, int + DEM Y/northing margin in pixels + dem_raster_band: int + DEM raster band (starting from 1) + + Returns + ------- + dem_interp: isce3.geometry.DEMInterpolator + DEM interpolator for given DEM raster and geo grid. + )"); +} diff --git a/python/extensions/pybind_isce3/geometry/DEMInterpolator.h b/python/extensions/pybind_isce3/geometry/DEMInterpolator.h index f5ccd765a..1fb9efca9 100644 --- a/python/extensions/pybind_isce3/geometry/DEMInterpolator.h +++ b/python/extensions/pybind_isce3/geometry/DEMInterpolator.h @@ -5,3 +5,4 @@ void addbinding(pybind11::class_&); void addbinding_DEM_raster2interpolator(pybind11::module&); +void addbinding_load_dem_from_proj(pybind11::module&); diff --git a/python/extensions/pybind_isce3/geometry/geometry.cpp b/python/extensions/pybind_isce3/geometry/geometry.cpp index 8193aa3bd..822985ed4 100644 --- a/python/extensions/pybind_isce3/geometry/geometry.cpp +++ b/python/extensions/pybind_isce3/geometry/geometry.cpp @@ -72,4 +72,5 @@ void addsubmodule_geometry(py::module & m) addbinding_pnt_intersect(geometry); addbinding_look_inc_from_sr(geometry); addbinding_DEM_raster2interpolator(geometry); + addbinding_load_dem_from_proj(geometry); } diff --git a/python/packages/nisar/workflows/static.py b/python/packages/nisar/workflows/static.py index 736659497..19a09daa7 100644 --- a/python/packages/nisar/workflows/static.py +++ b/python/packages/nisar/workflows/static.py @@ -31,7 +31,8 @@ from nisar.static.water_mask import binarize_and_reproject_water_mask import isce3 -from isce3.geometry import make_geo_grid_bounding_polygon +from isce3.geometry import make_geo_grid_bounding_polygon, load_dem_from_proj +from isce3.core import normalize_data_interp_method def run_static_layers_workflow(config_file: os.PathLike | str) -> None: @@ -74,6 +75,19 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: geo_grid = get_output_geo_grid(dem_raster=dem_raster, **geo_grid_params) logger.info(f"Output geo grid: {geo_grid}") + proj = isce3.core.make_projection(geo_grid.epsg) + + # dem = isce3.geometry.DEMInterpolator(dem_raster) + # dem.interp_method = dem_interp_method + dem_interp = load_dem_from_proj( + dem_raster, + geo_grid.start_x, + geo_grid.end_x, + geo_grid.end_y, + geo_grid.start_y, + normalize_data_interp_method(dem_interp_method), + proj) + # Parse the orbit and attitude data from the input XML files. Crop the # data to the time interval of interest to avoid possible geo2rdr # convergence errors due to ambiguity between orbit periods. @@ -100,35 +114,24 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: look_side = radar_grid_params["look_side"] wavelength = radar_grid_params["wavelength"] + # read azimuth time interval and range spacing from the input runconfig radar_grid_spacing_params = radar_grid_params["spacing"] az_spacing = radar_grid_spacing_params["az_spacing"] rg_spacing = radar_grid_spacing_params["rg_spacing"] + pts_per_side = radar_grid_spacing_params["pts_per_side"] - logger.info(f'az_spacing from runconfig: {az_spacing}') - logger.info(f'rg_spacing from runconfig: {rg_spacing}') - az_spacing_inferred, rg_spacing_inferred = \ - isce3.geometry.infer_radar_grid_spacing_from_geo_grid( - geo_grid=geo_grid, - dem=dem, - orbit=orbit, - doppler=img_grid_doppler, - look_side=look_side, - wavelength=wavelength, - **radar_grid_params["spacing"], - ) - logger.info(f'az_spacing from inferred: {az_spacing_inferred}') - logger.info(f'rg_spacing from inferred: {rg_spacing_inferred}') - + # if either the azimuth time interval or range spacing is not provided + # infer it from the geogrid if rg_spacing is None or az_spacing is None: az_spacing_inferred, rg_spacing_inferred = \ isce3.geometry.infer_radar_grid_spacing_from_geo_grid( geo_grid=geo_grid, - dem=dem, + dem=dem_interp, orbit=orbit, doppler=img_grid_doppler, look_side=look_side, wavelength=wavelength, - **radar_grid_params["spacing"], + pts_per_side=pts_per_side ) if rg_spacing is None: rg_spacing = rg_spacing_inferred @@ -156,7 +159,7 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: radar_grid=radar_grid, orbit=orbit, attitude=attitude, - dem=dem, + dem=dem_interp, **processing_params["doppler"], ) @@ -327,7 +330,7 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: identification_group = \ instrument_group.create_group("identification") bounding_polygon = make_geo_grid_bounding_polygon(geo_grid, - dem=dem) + dem=dem_interp) populate_identification_group( identification_group=identification_group, product_spec=product_spec, From 8080a743e1ab9facf4d7b895a4f2aa85a337322e Mon Sep 17 00:00:00 2001 From: "Gustavo H. X. Shiroma" Date: Mon, 26 Jan 2026 10:09:04 -0800 Subject: [PATCH 7/7] revert changes related to radar grid parameters --- python/packages/nisar/workflows/static.py | 34 +++++++---------------- share/nisar/defaults/static.yaml | 10 ------- share/nisar/schemas/static.yaml | 2 -- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/python/packages/nisar/workflows/static.py b/python/packages/nisar/workflows/static.py index 19a09daa7..879329b56 100644 --- a/python/packages/nisar/workflows/static.py +++ b/python/packages/nisar/workflows/static.py @@ -113,30 +113,16 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None: radar_grid_params = processing_params["radar_grid"] look_side = radar_grid_params["look_side"] wavelength = radar_grid_params["wavelength"] - - # read azimuth time interval and range spacing from the input runconfig - radar_grid_spacing_params = radar_grid_params["spacing"] - az_spacing = radar_grid_spacing_params["az_spacing"] - rg_spacing = radar_grid_spacing_params["rg_spacing"] - pts_per_side = radar_grid_spacing_params["pts_per_side"] - - # if either the azimuth time interval or range spacing is not provided - # infer it from the geogrid - if rg_spacing is None or az_spacing is None: - az_spacing_inferred, rg_spacing_inferred = \ - isce3.geometry.infer_radar_grid_spacing_from_geo_grid( - geo_grid=geo_grid, - dem=dem_interp, - orbit=orbit, - doppler=img_grid_doppler, - look_side=look_side, - wavelength=wavelength, - pts_per_side=pts_per_side - ) - if rg_spacing is None: - rg_spacing = rg_spacing_inferred - if az_spacing is None: - az_spacing = az_spacing_inferred + az_spacing, rg_spacing = \ + isce3.geometry.infer_radar_grid_spacing_from_geo_grid( + geo_grid=geo_grid, + dem=dem_interp, + orbit=orbit, + doppler=img_grid_doppler, + look_side=look_side, + wavelength=wavelength, + **radar_grid_params["spacing"], + ) # Compute a radar grid whose footprint on the ground encloses the geocoded # grid on which each output layer is defined. diff --git a/share/nisar/defaults/static.yaml b/share/nisar/defaults/static.yaml index 791536cf2..83077376f 100644 --- a/share/nisar/defaults/static.yaml +++ b/share/nisar/defaults/static.yaml @@ -225,16 +225,6 @@ runconfig: # Defaults to 0.24. wavelength: 0.24 spacing: - # [OPTIONAL] Azimuth interval, in seconds. Equivalent to the Pulse - # Repetition Interval (PRI). - # If not provided, it will be inferred from the specified geographic - # grid. If provided, must be a positive value. - az_spacing: - # [OPTIONAL] Slant-range spacing, in meters, of the radar grid. - # Must be a positive value. - # If not provided, it will be inferred from the specified geographic - # grid. If provided, must be a positive value. - rg_spacing: # [OPTIONAL] Side length of the NxN grid of samples used to estimate the # required radar grid pixel spacing necessary to avoid undersampling the # output geocoded grid. diff --git a/share/nisar/schemas/static.yaml b/share/nisar/schemas/static.yaml index d0110ac4f..7d20a5670 100644 --- a/share/nisar/schemas/static.yaml +++ b/share/nisar/schemas/static.yaml @@ -94,8 +94,6 @@ radar_grid_options: bounding_box: include('radar_grid_bounding_box_options', required=False) radar_grid_spacing_options: - az_spacing: num(min=0.0, required=False) - rg_spacing: num(min=0.0, required=False) pts_per_side: int(min=2, required=False) radar_grid_bounding_box_options: