Skip to content

Commit e7aeec1

Browse files
Virginia Brancatovbrancat
authored andcommitted
Geocode dense offsets (#812)
* Adddefault margin in default * Modify insar runconfig to include checks on dense offsets cfg * Modify radar grid for geocoding dense offsets * Add checks to dense offsets cfg for stand-alone usage of geocode_insar.py * Correct bug for stand-alone usage of geocode_insar.py * Correct mispelled variable in dense_offsets.py * Add dataset to geocode in insar schema * isort input and pep8 notation formatting * Correct ampcor parameter in unit test * Correct path to layover/shadow dataset * Correct path to dataset to geocode * Correct dense offsets search windo for unit test * Correct bg in margin definition for geocode_insar.py * Creating dense offsets radar grid from scratch * Pep8 notation formatting * Remove radar grid multilook and correct tabs in geocode_insar_runconfig.py * Correctly allocate the radar grid for interferogram/coherence * Correcting bug in geocode_insar_runconfig * Correct bug in insar_runconfig.py * Update start pixel of offset radar grid * Remove multiplication for 1.0 in offset prf computation Co-authored-by: vbrancat <[email protected]>
1 parent b11b264 commit e7aeec1

File tree

7 files changed

+131
-34
lines changed

7 files changed

+131
-34
lines changed

python/packages/pybind_nisar/workflows/dense_offsets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ def set_optional_attributes(ampcor_obj, cfg, length, width):
239239
err_str = "The input gross offset does not match the offset width*offset length"
240240
error_channel.log(err_str)
241241
raise RuntimeError(err_str)
242-
gross_offset = gross_offset.reshape(window_number, 2)
242+
gross_offset = gross_offset.reshape(windows_number, 2)
243243
gross_azimuth = gross_offset[:, 0]
244244
gross_range = gross_offset[:, 1]
245245
ampcor_obj.setVaryingGrossOffset(gross_azimuth, gross_range)

python/packages/pybind_nisar/workflows/geocode_insar.py

Lines changed: 82 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
collection of functions for NISAR geocode workflow
55
"""
66

7+
import pathlib
78
import time
89

910
import h5py
1011
import journal
11-
import pathlib
1212
import pybind_isce3 as isce3
1313
from pybind_nisar.products.readers import SLC
1414
from pybind_nisar.workflows import h5_prep
15-
from pybind_nisar.workflows.h5_prep import add_radar_grid_cubes_to_hdf5
1615
from pybind_nisar.workflows.geocode_insar_runconfig import \
1716
GeocodeInsarRunConfig
17+
from pybind_nisar.workflows.h5_prep import add_radar_grid_cubes_to_hdf5
1818
from pybind_nisar.workflows.yaml_argparse import YamlArgparse
1919

2020

@@ -39,6 +39,7 @@ def run(cfg, runw_hdf5, output_hdf5):
3939
interp_method = cfg["processing"]["geocode"]["interp_method"]
4040
gunw_datasets = cfg["processing"]["geocode"]["datasets"]
4141
scratch_path = pathlib.Path(cfg['ProductPathGroup']['ScratchPath'])
42+
offset_cfg = cfg["processing"]["dense_offsets"]
4243

4344
slc = SLC(hdf5file=ref_hdf5)
4445

@@ -75,7 +76,8 @@ def run(cfg, runw_hdf5, output_hdf5):
7576

7677
radar_grid_slc = slc.getRadarGrid(freq)
7778
if az_looks > 1 or rg_looks > 1:
78-
radar_grid_multilook = radar_grid_slc.multilook(az_looks, rg_looks)
79+
radar_grid_mlook = radar_grid_slc.multilook(az_looks, rg_looks)
80+
7981
geo_grid = geogrids[freq]
8082
geo.geogrid(
8183
geo_grid.start_x,
@@ -86,34 +88,90 @@ def run(cfg, runw_hdf5, output_hdf5):
8688
geo_grid.length,
8789
geo_grid.epsg,
8890
)
89-
src_freq_path = f"/science/LSAR/RUNW/swaths/frequency{freq}/interferogram"
90-
dst_freq_path = f"/science/LSAR/GUNW/grids/frequency{freq}/interferogram"
91+
src_freq_path = f"/science/LSAR/RUNW/swaths/frequency{freq}"
92+
dst_freq_path = f"/science/LSAR/GUNW/grids/frequency{freq}"
9193

9294
for pol in pol_list:
93-
src_group_path = f"{src_freq_path}/{pol}"
94-
dst_group_path = f"{dst_freq_path}/{pol}"
95-
9695
# iterate over key: dataset name value: bool flag to perform geocode
9796
for dataset_name, geocode_this_dataset in gunw_datasets.items():
9897
if not geocode_this_dataset:
9998
continue
10099

101-
if dataset_name in ['alongTrackOffset','slantRangeOffset']:
102-
src_group_path = f"/science/LSAR/RUNW/swaths/frequency{freq}/pixelOffsets/{pol}"
103-
dst_group_path = f"/science/LSAR/GUNW/grids/frequency{freq}/pixelOffsets/{pol}"
100+
# Create radar grid for the offsets (and dataset path)
101+
if dataset_name in ['alongTrackOffset', 'slantRangeOffset']:
102+
src_group_path = f'{src_freq_path}/pixelOffsets/{pol}'
103+
dst_group_path = f'{dst_freq_path}/pixelOffsets/{pol}'
104+
105+
# Define margin used during dense offsets execution
106+
margin = max(offset_cfg['margin'],
107+
offset_cfg['gross_offset_range'],
108+
offset_cfg['gross_offset_azimuth'])
109+
110+
# If not allocated, determine shape of the offsets
111+
if offset_cfg['offset_length'] is None:
112+
length_margin = 2 * margin + 2 * offset_cfg[
113+
'half_search_azimuth'] + \
114+
offset_cfg['window_azimuth']
115+
offset_cfg['offset_length'] = (radar_grid_slc.length -
116+
length_margin) // offset_cfg['skip_azimuth']
117+
if offset_cfg['offset_width'] is None:
118+
width_margin = 2 * margin + 2 * offset_cfg[
119+
'half_search_range'] + \
120+
offset_cfg['window_range']
121+
offset_cfg['offset_width'] = (radar_grid_slc.width -
122+
width_margin) // offset_cfg['skip_azimuth']
123+
# Determine the starting range and sensing start for the offset radar grid
124+
offset_starting_range = radar_grid_slc.starting_range + \
125+
(offset_cfg['start_pixel_range'] + offset_cfg['window_range']//2)\
126+
* radar_grid_slc.range_pixel_spacing
127+
offset_sensing_start = radar_grid_slc.sensing_start + \
128+
(offset_cfg['start_pixel_azimuth'] + offset_cfg['window_azimuth']//2)\
129+
/ radar_grid_slc.prf
130+
# Range spacing for offsets
131+
offset_range_spacing = radar_grid_slc.range_pixel_spacing * offset_cfg['skip_range']
132+
offset_prf = radar_grid_slc.prf / offset_cfg['skip_azimuth']
133+
134+
# Create offset radar grid
135+
radar_grid = isce3.product.RadarGridParameters(offset_sensing_start,
136+
radar_grid_slc.wavelength,
137+
offset_prf,
138+
offset_starting_range,
139+
offset_range_spacing,
140+
radar_grid_slc.lookside,
141+
offset_cfg['offset_length'],
142+
offset_cfg['offset_width'],
143+
radar_grid_slc.ref_epoch)
144+
# prepare input raster
145+
input_raster_str = (
146+
f"HDF5:{runw_hdf5}:/{src_group_path}/{dataset_name}"
147+
)
148+
input_raster = isce3.io.Raster(input_raster_str)
149+
150+
# access the HDF5 dataset for a given frequency and pol
151+
geo.data_interpolator = interp_method
152+
dataset_path = f"{dst_group_path}/{dataset_name}"
104153

105154
# prepare input raster
106-
107-
if (dataset_name == "layoverShadowMask"):
155+
elif (dataset_name == "layoverShadowMask"):
108156
# prepare input raster
109157
raster_ref = scratch_path / 'rdr2geo' / f'freq{freq}' / 'mask.rdr'
110158
input_raster = isce3.io.Raster(str(raster_ref))
111-
159+
112160
# access the HDF5 dataset for layover shadow mask
113-
dataset_path = f"{dst_freq_path}/{dataset_name}"
161+
dataset_path = f"{dst_freq_path}/interferogram/{dataset_name}"
114162
geo.data_interpolator = 'NEAREST'
115163
radar_grid = radar_grid_slc
116-
else:
164+
else:
165+
# Assign correct radar grid
166+
if az_looks > 1 or rg_looks > 1:
167+
radar_grid = radar_grid_mlook
168+
else:
169+
radar_grid = radar_grid_slc
170+
171+
# Prepare input path
172+
src_group_path = f'{src_freq_path}/interferogram/{pol}'
173+
dst_group_path = f'{dst_freq_path}/interferogram/{pol}'
174+
117175
# prepare input raster
118176
input_raster_str = (
119177
f"HDF5:{runw_hdf5}:/{src_group_path}/{dataset_name}"
@@ -122,10 +180,8 @@ def run(cfg, runw_hdf5, output_hdf5):
122180

123181
# access the HDF5 dataset for a given frequency and pol
124182
geo.data_interpolator = interp_method
125-
radar_grid = radar_grid_multilook
126183
dataset_path = f"{dst_group_path}/{dataset_name}"
127184

128-
129185
geocoded_dataset = dst_h5[dataset_path]
130186

131187
# Construct the output ratster directly from HDF5 dataset
@@ -165,17 +221,16 @@ def run(cfg, runw_hdf5, output_hdf5):
165221
computer cubes values outside radar-grid boundaries
166222
'''
167223
native_doppler.bounds_error = False
168-
add_radar_grid_cubes_to_hdf5(dst_h5, cube_group_name,
169-
cube_geogrid, radar_grid_cubes_heights,
170-
radar_grid, orbit, native_doppler,
171-
grid_zero_doppler, threshold_geo2rdr,
224+
add_radar_grid_cubes_to_hdf5(dst_h5, cube_group_name,
225+
cube_geogrid, radar_grid_cubes_heights,
226+
radar_grid, orbit, native_doppler,
227+
grid_zero_doppler, threshold_geo2rdr,
172228
iteration_geo2rdr)
173229

174230
t_all_elapsed = time.time() - t_all
175231
info_channel.log(f"Successfully ran geocode in {t_all_elapsed:.3f} seconds")
176232

177233

178-
179234
if __name__ == "__main__":
180235
"""
181236
run geocode from command line
@@ -190,10 +245,10 @@ def run(cfg, runw_hdf5, output_hdf5):
190245

191246
# prepare RIFG HDF5
192247
out_paths = h5_prep.run(geocode_insar_runconfig.cfg)
193-
if args.run_config_path is None:
194-
out_paths['RUNW'] = args.runw_h5
195-
else:
196-
out_paths['RUNW'] = geocode_insar_runconfig.cfg['processing']['geocode']['runw_path']
248+
runw_path = geocode_insar_runconfig.cfg['processing']['geocode'][
249+
'runw_path']
250+
if runw_path is not None:
251+
out_paths['RUNW'] = runw_path
197252

198253
# Run geocode
199254
run(geocode_insar_runconfig.cfg, out_paths["RUNW"], out_paths["GUNW"])

python/packages/pybind_nisar/workflows/geocode_insar_runconfig.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def yaml_check(self):
4949
gunw_datasets = ["connectedComponents", "coherenceMagnitude", "unwrappedPhase",
5050
"alongTrackOffset", "slantRangeOffset", "layoverShadowMask"]
5151
for gunw_dataset in gunw_datasets:
52-
if gunw_dataset not in self.cfg['processing']['geocode']:
52+
if gunw_dataset not in self.cfg['processing']['geocode']['datasets']:
5353
self.cfg['processing']['geocode']['datasets'][gunw_dataset] = True
5454

5555
if self.cfg['processing']['dem_margin'] is None:
@@ -74,3 +74,22 @@ def yaml_check(self):
7474
err_str = f"range looks = {rg_looks} not an odd integer."
7575
error_channel.log(err_str)
7676
raise ValueError(err_str)
77+
78+
# To geocode the offsets we need the offset field shape and
79+
# the start pixel in range and azimuth. Note, margin and gross_offsets
80+
# are allocated as defaults in share/nisar/defaults/insar.yaml
81+
geocode_azimuth_offset = self.cfg['processing']['geocode']['datasets'][
82+
'alongTrackOffset']
83+
geocode_range_offset = self.cfg['processing']['geocode']['datasets'][
84+
'slantRangeOffset']
85+
if geocode_azimuth_offset or geocode_range_offset:
86+
offset_cfg = self.cfg['processing']['dense_offsets']
87+
margin = max(offset_cfg['margin'],
88+
offset_cfg['gross_offset_range'],
89+
offset_cfg['gross_offset_azimuth'])
90+
if offset_cfg['start_pixel_range'] is None:
91+
offset_cfg['start_pixel_range'] = margin + offset_cfg[
92+
'half_search_range']
93+
if offset_cfg['start_pixel_azimuth'] is None:
94+
offset_cfg['start_pixel_azimuth'] = margin + offset_cfg[
95+
'half_search_azimuth']

python/packages/pybind_nisar/workflows/insar_runconfig.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import journal
2+
import numpy as np
13
from pybind_nisar.workflows.geo2rdr_runconfig import Geo2rdrRunConfig
24

35

@@ -13,6 +15,7 @@ def yaml_check(self):
1315
Check submodule paths from YAML
1416
'''
1517
scratch_path = self.cfg['ProductPathGroup']['ScratchPath']
18+
error_channel = journal.error('InsarRunConfig.yaml_check')
1619

1720
# If dense_offsets is disabled and rubbersheet is enabled
1821
# throw an exception and do not run the workflow
@@ -73,6 +76,24 @@ def yaml_check(self):
7376
'layoverShadowMask']
7477

7578
for gunw_dataset in gunw_datasets:
76-
if gunw_dataset not in self.cfg['processing']['geocode']:
79+
if gunw_dataset not in self.cfg['processing']['geocode']['datasets']:
7780
self.cfg['processing']['geocode']['datasets'][
7881
gunw_dataset] = True
82+
83+
# To geocode the offsets we need the offset field shape and
84+
# the start pixel in range and azimuth. Note, margin and gross_offsets
85+
# are allocated as defaults in share/nisar/defaults/insar.yaml
86+
geocode_azimuth_offset = self.cfg['processing'][
87+
'geocode']['datasets']['alongTrackOffset']
88+
geocode_range_offset = self.cfg['processing'][
89+
'geocode']['datasets']['slantRangeOffset']
90+
if geocode_azimuth_offset or geocode_range_offset:
91+
offset_cfg = self.cfg['processing']['dense_offsets']
92+
margin = max(offset_cfg['margin'], offset_cfg['gross_offset_range'],
93+
offset_cfg['gross_offset_azimuth'])
94+
if offset_cfg['start_pixel_range'] is None:
95+
offset_cfg['start_pixel_range'] = margin + offset_cfg[
96+
'half_search_range']
97+
if offset_cfg['start_pixel_azimuth'] is None:
98+
offset_cfg['start_pixel_azimuth'] = margin + offset_cfg[
99+
'half_search_azimuth']

share/nisar/defaults/insar.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ runconfig:
171171
# Number of lines to skip in reference image for next offset estimate
172172
skip_azimuth: 32
173173
# Margin around image edges to avoid for offset computation
174-
margin:
174+
margin: 0
175175
# Number of columns of output offset (covariance, snr) file
176176
offset_width:
177177
# Number of lines of output offset (covariance, snr) file

share/nisar/schemas/insar.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,9 @@ gunw_datasets:
405405
connectedComponents: bool(required=False)
406406
coherenceMagnitude: bool(required=False)
407407
unwrappedPhase: bool(required=False)
408-
408+
layoverShadowMask: bool(required=False)
409+
alongTrackOffset: bool(required=False)
410+
slantRangeOffset: bool(required=False)
409411

410412
qa_options:
411413
# Enabled file format validation

tests/data/insar_test.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ runconfig:
117117
enabled: True
118118
window_range: 64
119119
window_azimuth: 64
120-
half_search_range: 20
121-
half_search_azimuth: 20
120+
half_search_range: 10
121+
half_search_azimuth: 10
122122
skip_range: 8
123123
skip_azimuth: 8
124124
correlation_surface_zoom: 8

0 commit comments

Comments
 (0)