9
9
10
10
import h5py
11
11
import journal
12
+ import os
12
13
import pybind_isce3 as isce3
14
+ from osgeo import gdal
15
+ import numpy as np
13
16
from pybind_nisar .workflows import h5_prep
14
17
from pybind_nisar .workflows .unwrap_runconfig import UnwrapRunConfig
15
18
from pybind_nisar .workflows .yaml_argparse import YamlArgparse
@@ -22,6 +25,7 @@ def run(cfg: dict, input_hdf5: str, output_hdf5: str):
22
25
23
26
# pull parameters from dictionary
24
27
freq_pols = cfg ['processing' ]['input_subset' ]['list_of_frequencies' ]
28
+ scratch_path = pathlib .Path (cfg ['ProductPathGroup' ]['ScratchPath' ])
25
29
unwrap_args = cfg ['processing' ]['phase_unwrap' ]
26
30
27
31
# Create error and info channels
@@ -36,11 +40,21 @@ def run(cfg: dict, input_hdf5: str, output_hdf5: str):
36
40
error_channel .log (err_str )
37
41
raise ValueError (err_str )
38
42
39
- # ICU unwrapping (CPU only)
40
- unwrap_obj = isce3 .unwrap .ICU ()
43
+ # Instantiate correct unwrap object
44
+ if unwrap_args ['algorithm' ] == 'icu' :
45
+ unwrap_obj = isce3 .unwrap .ICU ()
46
+ elif unwrap_args ['algorithm' ] == 'phass' :
47
+ unwrap_obj = isce3 .unwrap .Phass ()
48
+ else :
49
+ err_str = "Invalid unwrapping algorithm"
50
+ error_channel .log (err_str )
51
+ raise ValueError (err_str )
52
+
53
+ # Depending on unwrapper, set unwrap attributes
41
54
unwrap_obj = set_unwrap_attributes (unwrap_obj , unwrap_args )
42
55
info_channel .log ("Running phase unwrapping with: " )
43
- info_channel = write_unwrap_attributes (unwrap_obj , info_channel )
56
+ log_unwrap_attributes (unwrap_obj , info_channel ,
57
+ unwrap_args ['algorithm' ])
44
58
45
59
t_all = time .time ()
46
60
@@ -54,10 +68,9 @@ def run(cfg: dict, input_hdf5: str, output_hdf5: str):
54
68
src_pol_group_path = f'{ src_freq_group_path } /interferogram/{ pol } '
55
69
dst_pol_group_path = f'{ dst_freq_group_path } /interferogram/{ pol } '
56
70
57
- # Prepare igram input raster
71
+ # Interferogram filepath
58
72
igram_path = f'HDF5:{ crossmul_path } :/' \
59
73
f'{ src_pol_group_path } /wrappedInterferogram'
60
- igram_raster = isce3 .io .Raster (igram_path )
61
74
62
75
# Prepare correlation input raster
63
76
corr_path = f'HDF5:{ crossmul_path } :/' \
@@ -75,6 +88,54 @@ def run(cfg: dict, input_hdf5: str, output_hdf5: str):
75
88
conn_comp_dataset = dst_h5 [conn_comp_path ]
76
89
conn_comp_raster = isce3 .io .Raster (f"IH5:::ID={ conn_comp_dataset .id .id } " .encode ("utf-8" ),
77
90
update = True )
91
+
92
+ # If unwrapping algorithm is ICU, run it with or without seed
93
+ if unwrap_args ['algorithm' ] == 'icu' :
94
+ # Allocate interferogram as ISCE3 raster
95
+ igram_raster = isce3 .io .Raster (igram_path )
96
+ if 'seed' in unwrap_args ['icu' ]:
97
+ unwrap_obj .unwrap (uigram_raster , conn_comp_raster ,
98
+ igram_raster ,
99
+ corr_raster , seed = unwrap_args ['seed' ])
100
+ else :
101
+ unwrap_obj .unwrap (uigram_raster , conn_comp_raster ,
102
+ igram_raster ,
103
+ corr_raster )
104
+ else :
105
+ # Unwrapping algorithm is PHASS which requires
106
+ # the interferometric phase as input raster
107
+ unwrap_scratch = scratch_path / f'unwrap/freq{ freq } /{ pol } '
108
+ unwrap_scratch .mkdir (parents = True , exist_ok = True )
109
+
110
+ # Using GDAL pixel function to compute a wrapped phase VRT
111
+ ds = gdal .Open (igram_path , gdal .GA_ReadOnly )
112
+ vrttmpl = f'''
113
+ <VRTDataset rasterXSize="{ ds .RasterXSize } " rasterYSize="{ ds .RasterYSize } ">
114
+ <VRTRasterBand dataType="Float32" band="1" subClass="VRTDerivedRasterBand">
115
+ <Description>Phase</Description>
116
+ <PixelFunctionType>phase</PixelFunctionType>
117
+ <SimpleSource>
118
+ <SourceFilename>{ igram_path } </SourceFilename>
119
+ </SimpleSource>
120
+ </VRTRasterBand>
121
+ </VRTDataset>'''
122
+ ds = None
123
+ with open (os .path .join (unwrap_scratch , 'wrapped_phase.vrt' ),
124
+ 'w' ) as fid :
125
+ fid .write (vrttmpl )
126
+
127
+ # Open phase_raster as ISCE3 raster
128
+ phase_raster = isce3 .io .Raster (os .path .join (unwrap_scratch , 'wrapped_phase.vrt' ))
129
+
130
+ # Check if power raster has been allocated
131
+ if 'power' in unwrap_args ['phass' ]:
132
+ power_raster = isce3 .io .Raster (unwrap_args ['phass' ]['power' ])
133
+ unwrap_obj .unwrap (phase_raster , power_raster ,
134
+ corr_raster , uigram_raster , conn_comp_raster )
135
+ else :
136
+ unwrap_obj .unwrap (phase_raster , corr_raster ,
137
+ uigram_raster , conn_comp_raster )
138
+
78
139
if 'seed' in unwrap_args :
79
140
unwrap_obj .unwrap (uigram_raster , conn_comp_raster , igram_raster ,
80
141
corr_raster , seed = unwrap_args ['seed' ])
@@ -85,8 +146,7 @@ def run(cfg: dict, input_hdf5: str, output_hdf5: str):
85
146
# Copy coherence magnitude and culled offsets to RIFG
86
147
dataset_names = ['coherenceMagnitude' , 'alongTrackOffset' ,
87
148
'slantRangeOffset' ]
88
- group_names = ['interferogram' , 'pixelOffsets' ,
89
- 'pixelOffsets' ]
149
+ group_names = ['interferogram' , 'pixelOffsets' , 'pixelOffsets' ]
90
150
for dataset_name , group_name in zip (dataset_names , group_names ):
91
151
dst_path = f'{ dst_freq_group_path } /{ group_name } /{ pol } /{ dataset_name } '
92
152
src_path = f'{ src_freq_group_path } /{ group_name } /{ pol } /{ dataset_name } '
@@ -99,29 +159,36 @@ def run(cfg: dict, input_hdf5: str, output_hdf5: str):
99
159
info_channel .log (f"Successfully ran phase unwrapping in { t_all_elapsed :.3f} seconds" )
100
160
101
161
102
- def write_unwrap_attributes (unwrap , info ):
162
+ def log_unwrap_attributes (unwrap , info , algorithm ):
103
163
'''
104
- Write unwrap attributes to info channel
164
+ Write unwrap attributes to info
165
+ channel depending on unwrapping algorithm
105
166
'''
106
- info .log (f"Number of buffer lines: { unwrap .buffer_lines } " )
107
- info .log (f"Number of overlap lines: { unwrap .overlap_lines } " )
108
- info .log (f"Use phase gradient neutron: { unwrap .use_phase_grad_neut } " )
109
- info .log (f"Use intensity neutron: { unwrap .use_intensity_neut } " )
110
- info .log (f"Phase gradient window size: { unwrap .phase_grad_win_size } " )
111
- info .log (f"Phase gradient threshold: { unwrap .neut_phase_grad_thr } " )
112
- info .log (f"Neutron intensity threshold: { unwrap .neut_intensity_thr } " )
113
- info .log (
114
- f"Maximum intesity correlation threshold: { unwrap .neut_correlation_thr } " )
115
- info .log (f"Number of trees: { unwrap .trees_number } " )
116
- info .log (f"Maximum branch length: { unwrap .max_branch_length } " )
117
- info .log (f"Pixel spacing ratio: { unwrap .ratio_dxdy } " )
118
- info .log (f"Initial correlation threshold: { unwrap .init_corr_thr } " )
119
- info .log (f"Maximum correlation threshold: { unwrap .max_corr_thr } " )
120
- info .log (f"Correlation threshold increments: { unwrap .corr_incr_thr } " )
121
- info .log (f"Minimum tile area fraction: { unwrap .min_cc_area } " )
122
- info .log (f"Number of bootstraping lines: { unwrap .num_bs_lines } " )
123
- info .log (f"Minimum overlapping area: { unwrap .min_overlap_area } " )
124
- info .log (f"Phase variance threshold: { unwrap .phase_var_thr } " )
167
+ info .log (f"Unwrapping algorithm:{ algorithm } " )
168
+ if algorithm == 'icu' :
169
+ info .log (f"Number of buffer lines: { unwrap .buffer_lines } " )
170
+ info .log (f"Number of overlap lines: { unwrap .overlap_lines } " )
171
+ info .log (f"Use phase gradient neutron: { unwrap .use_phase_grad_neut } " )
172
+ info .log (f"Use intensity neutron: { unwrap .use_intensity_neut } " )
173
+ info .log (f"Phase gradient window size: { unwrap .phase_grad_win_size } " )
174
+ info .log (f"Phase gradient threshold: { unwrap .neut_phase_grad_thr } " )
175
+ info .log (f"Neutron intensity threshold: { unwrap .neut_intensity_thr } " )
176
+ info .log (f"Maximum intensity correlation "
177
+ f"threshold: { unwrap .neut_correlation_thr } " )
178
+ info .log (f"Number of trees: { unwrap .trees_number } " )
179
+ info .log (f"Maximum branch length: { unwrap .max_branch_length } " )
180
+ info .log (f"Pixel spacing ratio: { unwrap .ratio_dxdy } " )
181
+ info .log (f"Initial correlation threshold: { unwrap .init_corr_thr } " )
182
+ info .log (f"Maximum correlation threshold: { unwrap .max_corr_thr } " )
183
+ info .log (f"Correlation threshold increments: { unwrap .corr_incr_thr } " )
184
+ info .log (f"Minimum tile area fraction: { unwrap .min_cc_area } " )
185
+ info .log (f"Number of bootstraping lines: { unwrap .num_bs_lines } " )
186
+ info .log (f"Minimum overlapping area: { unwrap .min_overlap_area } " )
187
+ info .log (f"Phase variance threshold: { unwrap .phase_var_thr } " )
188
+ else :
189
+ info .log (f"Good correlation: { unwrap .good_correlation } " )
190
+ info .log (
191
+ f"Minimum size of an unwrapped region: { unwrap .min_pixels_region } " )
125
192
126
193
return info
127
194
@@ -131,43 +198,60 @@ def set_unwrap_attributes(unwrap, cfg: dict):
131
198
Assign user-defined values in cfg to
132
199
the unwrap object
133
200
'''
201
+ error_channel = journal .error ('unwrap.set_unwrap_attributes' )
134
202
135
- if 'buffer_lines' in cfg :
136
- unwrap .buffer_lines = cfg ['buffer_lines' ]
137
- if 'overlap_lines' in cfg :
138
- unwrap .overlap_lines = cfg ['overlap_lines' ]
139
- if 'use_phase_gradient_neutron' in cfg :
140
- unwrap .use_phase_grad_neut = cfg ['use_phase_gradient_neutron' ]
141
- if 'use_intensity_neutron' in cfg :
142
- unwrap .use_intensity_neut = cfg ['use_intensity_neutron' ]
143
- if 'phase_gradient_window_size' in cfg :
144
- unwrap .phase_grad_win_size = cfg ['phase_gradient_window_size' ]
145
- if 'neutron_phase_gradient_threshold' in cfg :
146
- unwrap .neut_phase_grad_thr = cfg ['neutron_phase_gradient_threshold' ]
147
- if 'neutron_intensity_threshold' in cfg :
148
- unwrap .neut_intensity_thr = cfg ['neutron_intensity_threshold' ]
149
- if 'max_intensity_correlation_threshold' in cfg :
150
- unwrap .neut_correlation_thr = cfg ['max_intensity_correlation_threshold' ]
151
- if 'trees_number' in cfg :
152
- unwrap .trees_number = cfg ['trees_number' ]
153
- if 'max_branch_length' in cfg :
154
- unwrap .max_branch_length = cfg ['max_branch_length' ]
155
- if 'pixel_spacing_ratio' in cfg :
156
- unwrap .ratio_dxdy = cfg ['pixel_spacing_ratio' ]
157
- if 'initial_correlation_threshold' in cfg :
158
- unwrap .init_corr_thr = cfg ['initial_correlation_threshold' ]
159
- if 'max_correlation_threshold' in cfg :
160
- unwrap .max_corr_thr = cfg ['max_correlation_threshold' ]
203
+ algorithm = cfg ['algorithm' ]
161
204
if 'correlation_threshold_increments' in cfg :
162
205
unwrap .corr_incr_thr = cfg ['correlation_threshold_increments' ]
163
- if 'min_tile_area' in cfg :
164
- unwrap .min_cc_area = cfg ['min_tile_area' ]
165
- if 'bootstrap_lines' in cfg :
166
- unwrap .num_bs_lines = cfg ['bootstrap_lines' ]
167
- if 'min_overlap_area' in cfg :
168
- unwrap .min_overlap_area = cfg ['min_overlap_area' ]
169
- if 'phase_variance_threshold' in cfg :
170
- unwrap .phase_var_thr = cfg ['phase_variance_threshold' ]
206
+
207
+ if algorithm == 'icu' :
208
+ icu_cfg = cfg ['icu' ]
209
+ if 'buffer_lines' in icu_cfg :
210
+ unwrap .buffer_lines = icu_cfg ['buffer_lines' ]
211
+ if 'overlap_lines' in icu_cfg :
212
+ unwrap .overlap_lines = icu_cfg ['overlap_lines' ]
213
+ if 'use_phase_gradient_neutron' in icu_cfg :
214
+ unwrap .use_phase_grad_neut = icu_cfg ['use_phase_gradient_neutron' ]
215
+ if 'use_intensity_neutron' in icu_cfg :
216
+ unwrap .use_intensity_neut = icu_cfg ['use_intensity_neutron' ]
217
+ if 'phase_gradient_window_size' in icu_cfg :
218
+ unwrap .phase_grad_win_size = icu_cfg ['phase_gradient_window_size' ]
219
+ if 'neutron_phase_gradient_threshold' in icu_cfg :
220
+ unwrap .neut_phase_grad_thr = icu_cfg [
221
+ 'neutron_phase_gradient_threshold' ]
222
+ if 'neutron_intensity_threshold' in icu_cfg :
223
+ unwrap .neut_intensity_thr = icu_cfg ['neutron_intensity_threshold' ]
224
+ if 'max_intensity_correlation_threshold' in icu_cfg :
225
+ unwrap .neut_correlation_thr = icu_cfg [
226
+ 'max_intensity_correlation_threshold' ]
227
+ if 'trees_number' in icu_cfg :
228
+ unwrap .trees_number = icu_cfg ['trees_number' ]
229
+ if 'max_branch_length' in icu_cfg :
230
+ unwrap .max_branch_length = icu_cfg ['max_branch_length' ]
231
+ if 'pixel_spacing_ratio' in icu_cfg :
232
+ unwrap .ratio_dxdy = icu_cfg ['pixel_spacing_ratio' ]
233
+ if 'initial_correlation_threshold' in icu_cfg :
234
+ unwrap .init_corr_thr = icu_cfg ['initial_correlation_threshold' ]
235
+ if 'max_correlation_threshold' in icu_cfg :
236
+ unwrap .max_corr_thr = icu_cfg ['max_correlation_threshold' ]
237
+ if 'min_tile_area' in icu_cfg :
238
+ unwrap .min_cc_area = icu_cfg ['min_tile_area' ]
239
+ if 'bootstrap_lines' in icu_cfg :
240
+ unwrap .num_bs_lines = icu_cfg ['bootstrap_lines' ]
241
+ if 'min_overlap_area' in icu_cfg :
242
+ unwrap .min_overlap_area = icu_cfg ['min_overlap_area' ]
243
+ if 'phase_variance_threshold' in icu_cfg :
244
+ unwrap .phase_var_thr = icu_cfg ['phase_variance_threshold' ]
245
+ elif algorithm == 'phass' :
246
+ phass_cfg = cfg ['phass' ]
247
+ if 'good_correlation' in phass_cfg :
248
+ unwrap .good_correlation = phass_cfg ['good_correlation' ]
249
+ if 'min_unwrap_area' in phass_cfg :
250
+ unwrap .min_pixels_region = phass_cfg ['min_unwrap_area' ]
251
+ else :
252
+ err_str = "Not a valid unwrapping algorithm"
253
+ error_channel .log (err_str )
254
+ raise ValueError (err_str )
171
255
172
256
return unwrap
173
257
@@ -187,13 +271,8 @@ def set_unwrap_attributes(unwrap, cfg: dict):
187
271
# Prepare RUNW HDF5
188
272
out_paths = h5_prep .run (unwrap_runconfig .cfg )
189
273
190
- # out_paths['RIFG'] from h5_prep does not have actual interferogram data.
191
- # Use RIFG path from CLI or YAML
192
- if args .run_config_path is None :
193
- rifg = args .crossmul
194
- else :
195
- rifg = unwrap_runconfig .cfg ['processing' ]['phase_unwrap' ][
196
- 'crossmul_path' ]
274
+ # Use RIFG from crossmul_path
275
+ rifg_h5 = unwrap_runconfig .cfg ['processing' ]['phase_unwrap' ]['crossmul_path' ]
197
276
198
277
# Run phase unwrapping
199
- run (unwrap_runconfig .cfg , rifg , out_paths ['RUNW' ])
278
+ run (unwrap_runconfig .cfg , rifg_h5 , out_paths ['RUNW' ])
0 commit comments