Skip to content

Commit 36ab7f4

Browse files
jungkyoJungGitHub Enterprise
authored andcommitted
Merge pull request #883 from jungkyoj/split_main_band
Split-spectrum (InSAR ionosphere phase correction)
2 parents 23b3847 + 6ec06e6 commit 36ab7f4

File tree

8 files changed

+650
-11
lines changed

8 files changed

+650
-11
lines changed

python/packages/isce3/splitspectrum/splitspectrum.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,11 @@ def bandpass_spectrum(self,
295295
)
296296

297297
# remove the windowing effect from the spectrum
298-
spectrum_target = fft(slc_raster, n=fft_size) / \
299-
window_target
298+
spectrum_target = fft(slc_raster, n=fft_size)
299+
spectrum_target = np.divide(spectrum_target,
300+
window_target,
301+
out=np.zeros_like(spectrum_target),
302+
where=window_target!=0)
300303
# apply new bandpass window to spectrum
301304
slc_bandpassed = ifft(spectrum_target
302305
* window_bandpass

python/packages/nisar/workflows/insar.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
import time
33

44
import journal
5-
from nisar.workflows import (crossmul, dense_offsets, geo2rdr,
5+
from nisar.workflows import (bandpass_insar, crossmul, dense_offsets, geo2rdr,
66
geocode_insar, h5_prep, filter_interferogram,
7-
rdr2geo, resample_slc, rubbersheet, unwrap,
8-
bandpass_insar)
7+
rdr2geo, resample_slc, rubbersheet,
8+
split_spectrum, unwrap)
99
from nisar.workflows.insar_runconfig import InsarRunConfig
1010
from nisar.workflows.persistence import Persistence
1111
from nisar.workflows.yaml_argparse import YamlArgparse
@@ -64,6 +64,10 @@ def run(cfg: dict, out_paths: dict, run_steps: dict):
6464
if run_steps['unwrap'] and 'RUNW' in out_paths:
6565
unwrap.run(cfg, out_paths['RIFG'], out_paths['RUNW'])
6666

67+
if run_steps['ionosphere'] and \
68+
cfg['processing']['ionosphere_phase_correction']['enabled']:
69+
split_spectrum.run(cfg)
70+
6771
if run_steps['geocode'] and 'GUNW' in out_paths:
6872
geocode_insar.run(cfg, out_paths['RUNW'], out_paths['GUNW'])
6973

@@ -86,4 +90,4 @@ def run(cfg: dict, out_paths: dict, run_steps: dict):
8690
if persist.run:
8791
_, out_paths = h5_prep.get_products_and_paths(insar_runcfg.cfg)
8892

89-
run(insar_runcfg.cfg, out_paths, persist.run_steps)
93+
run(insar_runcfg.cfg, out_paths, persist.run_steps)

python/packages/nisar/workflows/insar_runconfig.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
from nisar.products.readers import SLC
12
from nisar.workflows.geo2rdr_runconfig import Geo2rdrRunConfig
3+
import nisar.workflows.helpers as helpers
24
import journal
35
import os
6+
import h5py
7+
import numpy as np
48
import warnings
59

610
class InsarRunConfig(Geo2rdrRunConfig):
@@ -150,6 +154,185 @@ def yaml_check(self):
150154
if algorithm not in self.cfg['processing']['phase_unwrap']:
151155
self.cfg['processing']['phase_unwrap'][algorithm]={}
152156

157+
iono_cfg = self.cfg['processing']['ionosphere_phase_correction']
158+
159+
# If ionosphere phase correction is enabled, check defaults
160+
if iono_cfg['enabled']:
161+
# Extract split-spectrum dictionary
162+
split_cfg = iono_cfg['split_range_spectrum']
163+
iono_freq_pol = iono_cfg['list_of_frequencies']
164+
iono_method = iono_cfg['spectral_diversity']
165+
166+
# Extract main range bandwidth from reference SLC
167+
ref_slc_path = self.cfg['input_file_group']['input_file_path']
168+
sec_slc_path = self.cfg['input_file_group']['secondary_file_path']
169+
170+
ref_slc = SLC(hdf5file=ref_slc_path)
171+
sec_slc = SLC(hdf5file=sec_slc_path)
172+
173+
# extract the polarizations from reference and secondary hdf5
174+
with h5py.File(ref_slc_path, 'r', libver='latest',
175+
swmr=True) as ref_h5, \
176+
h5py.File(sec_slc_path, 'r', libver='latest',
177+
swmr=True) as sec_h5:
178+
179+
ref_pol_path = os.path.join(
180+
ref_slc.SwathPath, 'frequencyA', 'listOfPolarizations')
181+
ref_pols_freqA = list(
182+
np.array(ref_h5[ref_pol_path][()], dtype=str))
183+
184+
sec_pol_path = os.path.join(
185+
sec_slc.SwathPath, 'frequencyA', 'listOfPolarizations')
186+
sec_pols_freqA = list(
187+
np.array(sec_h5[sec_pol_path][()], dtype=str))
188+
189+
rg_main_bandwidth = ref_slc.getSwathMetadata(
190+
'A').processed_range_bandwidth
191+
192+
# get common polarzations of freqA from reference and secondary
193+
common_pol_refsec_freqA = set.intersection(
194+
set(ref_pols_freqA), set(sec_pols_freqA))
195+
196+
# If no common polarizations found between reference and secondary,
197+
# then throw errors.
198+
if not common_pol_refsec_freqA:
199+
err_str = "No common polarization between frequency A rasters"
200+
error_channel.log(err_str)
201+
raise FileNotFoundError(err_str)
202+
203+
# If polarizations are given, then check if HDF5 has them.
204+
# If not, then throw error.
205+
if iono_freq_pol['A']:
206+
for iono_pol in iono_freq_pol['A']:
207+
if (iono_pol not in ref_pols_freqA) or \
208+
(iono_pol not in sec_pols_freqA):
209+
err_str = f"polarzations {iono_pol} for ionosphere estimation are requested, but not found"
210+
error_channel.log(err_str)
211+
raise FileNotFoundError(err_str)
212+
213+
# If common polarization found, but input polarizations are not given,
214+
# then assign the common polarization for split_main_band
215+
if (common_pol_refsec_freqA) and (not iono_freq_pol['A']):
216+
# Co-polarizations are found, split_main_band will be used for co-pols
217+
common_copol_ref_sec = [pol for pol in common_pol_refsec_freqA
218+
if pol in ['VV', 'HH']]
219+
iono_freq_pol['A'] = common_copol_ref_sec
220+
221+
# If common co-pols not found, cross-pol will be alternatively used.
222+
if not common_copol_ref_sec:
223+
iono_freq_pol['A'] = common_pol_refsec_freqA
224+
225+
warning_str = f"{iono_freq_pol} will be used for {iono_method}"
226+
warning_channel.log(warning_str)
227+
self.cfg['processing'][
228+
'ionosphere_phase_correction'][
229+
'list_of_frequencies'] = iono_freq_pol
230+
231+
# Depending on how the user has selected "spectral_diversity" check if
232+
# "low_bandwidth" and "high_bandwidth" are assigned. Otherwise, use default
233+
if iono_method == 'split_main_band':
234+
# If "low_bandwidth" or 'high_bandwidth" is not allocated, split the main range bandwidth
235+
# into two 1/3 sub-bands.
236+
if split_cfg['low_band_bandwidth'] is None:
237+
split_cfg['low_band_bandwidth'] = rg_main_bandwidth / 3.0
238+
info_str = "low band width for low sub-bands are not given;"\
239+
"It is automatically set by 1/3 of range bandwidth of frequencyA"
240+
warning_channel.log(info_str)
241+
242+
if split_cfg['high_band_bandwidth'] is None:
243+
split_cfg['high_band_bandwidth'] = rg_main_bandwidth / 3.0
244+
info_str = "high band width for high sub-band are not given;"\
245+
"It is automatically set by 1/3 of range bandwidth of frequencyA"
246+
warning_channel.log(info_str)
247+
248+
# If polarzations for frequency B are requested
249+
# for split_main_band method, then throw error
250+
if iono_freq_pol['B']:
251+
err_str = f"Incorrect polarzations {iono_freq_pol['B']} for frequency B are requested. "\
252+
f"{iono_method} should not have polarizations in frequency B."
253+
error_channel.log(err_str)
254+
raise FileNotFoundError(err_str)
255+
256+
# methods that use side band
257+
if iono_method in ['main_side_band', 'main_diff_main_side_band']:
258+
# extract the polarizations from reference and secondary hdf5
259+
with h5py.File(ref_slc_path, 'r', libver='latest',
260+
swmr=True) as ref_h5, \
261+
h5py.File(sec_slc_path, 'r', libver='latest',
262+
swmr=True) as sec_h5:
263+
264+
ref_pol_path = os.path.join(
265+
ref_slc.SwathPath, 'frequencyB', 'listOfPolarizations')
266+
ref_pols_freqB = list(
267+
np.array(ref_h5[ref_pol_path][()], dtype=str))
268+
269+
sec_pol_path = os.path.join(
270+
sec_slc.SwathPath, 'frequencyB', 'listOfPolarizations')
271+
sec_pols_freqB = list(
272+
np.array(sec_h5[sec_pol_path][()], dtype=str))
273+
274+
# find common polarizations for freq B between ref and sec HDF5
275+
common_pol_refsec_freqB = set.intersection(
276+
set(ref_pols_freqB), set(sec_pols_freqB))
277+
278+
# when common polarzations are not found, throw error.
279+
if not common_pol_refsec_freqB:
280+
err_str = "No common polarization between frequencyB rasters"
281+
error_channel.log(err_str)
282+
raise FileNotFoundError(err_str)
283+
284+
common_pol_ref_freq_a_b = set.intersection(
285+
set(ref_pols_freqA), set(ref_pols_freqB))
286+
if not common_pol_ref_freq_a_b:
287+
err_str = "No common polarization between frequency A and B rasters"
288+
error_channel.log(err_str)
289+
raise FileNotFoundError(err_str)
290+
291+
# If polarizations are given, then check if HDF5 has them.
292+
# If not, then throw error.
293+
if iono_freq_pol['B']:
294+
for iono_pol in iono_freq_pol['B']:
295+
if (iono_pol not in ref_pols_freqB) or \
296+
(iono_pol not in sec_pols_freqB):
297+
err_str = f"polarzations {iono_pol} for ionosphere"\
298+
"estimation are requested, but not found"
299+
error_channel.log(err_str)
300+
raise FileNotFoundError(err_str)
301+
302+
# Co-polarizations are found and input pol for freq B is not given
303+
else:
304+
common_pol_refsec_freq_ab = set.intersection(
305+
set(common_pol_refsec_freqB), set(common_pol_ref_freq_a_b))
306+
307+
# if pol of freq A is given, this pol is used for freq B.
308+
if iono_freq_pol['A']:
309+
common_pol_refsec_freq_ab = set.intersection(
310+
set(iono_freq_pol['A']), set(common_pol_refsec_freq_ab))
311+
312+
common_copol_ref_sec = [pol for pol in common_pol_refsec_freq_ab
313+
if pol in ['VV', 'HH']]
314+
315+
if common_copol_ref_sec:
316+
info_str = f"{common_copol_ref_sec} will be "\
317+
f"used for {iono_method}"
318+
warning_channel.log(info_str)
319+
self.cfg['processing'][
320+
'ionosphere_phase_correction'][
321+
'list_of_frequencies']['A'] = common_copol_ref_sec
322+
self.cfg['processing'][
323+
'ionosphere_phase_correction'][
324+
'list_of_frequencies']['A'] = common_copol_ref_sec
325+
326+
# If common co-pols not found, cross-pol will be alternatively used.
327+
else:
328+
info_str = f"{common_pol_refsec_freq_ab} will be used for split_main_band"
329+
warning_channel.log(info_str)
330+
self.cfg['processing'][
331+
'ionosphere_phase_correction'][
332+
'list_of_frequencies']['A'] = common_pol_refsec_freq_ab
333+
self.cfg['processing'][
334+
'ionosphere_phase_correction'][
335+
'list_of_frequencies']['B'] = common_pol_refsec_freq_ab
153336

154337
if 'interp_method' not in self.cfg['processing']['geocode']:
155338
self.cfg['processing']['geocode']['interp_method'] = 'BILINEAR'

python/packages/nisar/workflows/persistence.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ class Persistence():
77
basic class that determines InSAR persistence
88
'''
99
# init InSAR steps in reverse chronological run order
10-
insar_steps = ['geocode', 'unwrap', 'filter_interferogram', 'crossmul', 'fine_resample',
11-
'rubbersheet', 'dense_offsets', 'coarse_resample', 'geo2rdr', 'rdr2geo',
12-
'h5_prep', 'bandpass_insar']
10+
insar_steps = ['geocode', 'ionosphere', 'unwrap', 'filter_interferogram', 'crossmul',
11+
'fine_resample', 'rubbersheet', 'dense_offsets', 'coarse_resample',
12+
'geo2rdr', 'rdr2geo', 'h5_prep', 'bandpass_insar']
1313

1414
def __init__(self, restart=False):
1515
# bool flag that determines if insar.run is called
@@ -50,18 +50,25 @@ def read_log(self):
5050
if 'successfully ran INSAR' in log_line:
5151
break
5252

53+
# success message found
54+
success_msg_found = False
5355
# check for message indicating successful run of step
54-
if 'Successfully ran' in log_line or 'successfully ran' in log_line:
56+
if 'uccessfully ran' in log_line:
5557
# iterate thru reverse chronological steps
5658
for insar_step in self.insar_steps:
5759
# any step not found in line will be step to run
5860
if insar_step not in log_line:
5961
# set step name found to True
6062
self.run_steps[insar_step] = True
63+
success_msg_found = True
6164
else:
6265
# check if any steps need to be run
6366
if any(self.run_steps.values()):
6467
self.run = True
6568

66-
# assume all previous steps successfully run and stop
69+
# all previous steps successfully run and stop
6770
break
71+
72+
# check if any steps need to be run or success msg not found
73+
if not success_msg_found:
74+
self.__init__(True)

0 commit comments

Comments
 (0)