From a2ffa0462b6b790c5b6b6c3e2e72b3d9255a0718 Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Mon, 29 Jan 2024 20:33:46 +0800 Subject: [PATCH] read/load support for `isce2/alos2App` dense offset (#1143) + utils.readfile.auto_no_data_value(): support alos2App dense offset + utils.readfile.get_slice_list(): alos2App uses rg/az order, instead of az/rg order in other isce2 applications. + utils.isce_utils.extract_alosStack_metadata/extract_image_size_alosStack(): support geometry files from alos2App/dense_offset, which have different naming conventions than those from InSAR. + load_data: use absolute path for better robustness --- src/mintpy/load_data.py | 1 + src/mintpy/utils/isce_utils.py | 57 +++++++++++++++++++++++----------- src/mintpy/utils/readfile.py | 21 +++++++++++-- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/mintpy/load_data.py b/src/mintpy/load_data.py index 3ef78c695..01ec011a2 100644 --- a/src/mintpy/load_data.py +++ b/src/mintpy/load_data.py @@ -668,6 +668,7 @@ def prepare_metadata(iDict): # --baseline-dir / --geometry-dir baseline_dir = iDict['mintpy.load.baselineDir'] geom_dir = os.path.dirname(iDict['mintpy.load.demFile']) + geom_dir = os.path.abspath(geom_dir) # --dset-dir / --file-pattern obs_keys = [ diff --git a/src/mintpy/utils/isce_utils.py b/src/mintpy/utils/isce_utils.py index 9ec357663..2338c941c 100644 --- a/src/mintpy/utils/isce_utils.py +++ b/src/mintpy/utils/isce_utils.py @@ -47,7 +47,7 @@ def get_processor(meta_file): """ Get the name of ISCE processor (imaging mode) """ - meta_dir = os.path.dirname(meta_file) + meta_dir = os.path.dirname(os.path.abspath(meta_file)) tops_meta_file = os.path.join(meta_dir, 'IW*.xml') alos_meta_file = os.path.join(meta_dir, '*.track.xml') stripmap_meta_files = [os.path.join(meta_dir, i) for i in ['data.db', 'data.dat', 'data']] @@ -366,29 +366,40 @@ def extract_alosStack_metadata(meta_file, geom_dir): meta['azimuthPixelSize'] *= meta['ALOOKS'] # LAT/LON_REF1/2/3/4 + lat_files = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lat')) + if len(lat_files) > 0: + # geometry files from alosStack + lat_files = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lat')) + lon_files = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lon')) + los_files = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.los')) + else: + # geometry files from alos2App / dense offset, which are then multilooked by mintpy + lat_files = [os.path.join(geom_dir, 'lat.rdr.mli')] + lon_files = [os.path.join(geom_dir, 'lon.rdr.mli')] + los_files = [os.path.join(geom_dir, 'los.rdr.mli')] + edge = 3 - lat_file = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lat'))[0] img = isceobj.createImage() - img.load(lat_file+'.xml') + img.load(lat_files[0] + '.xml') width = img.width length = img.length - data = np.memmap(lat_file, dtype='float64', mode='r', shape=(length, width)) + + data = np.memmap(lat_files[0], dtype='float64', mode='r', shape=(length, width)) meta['LAT_REF1'] = str(data[ 0+edge, 0+edge]) meta['LAT_REF2'] = str(data[ 0+edge, -1-edge]) meta['LAT_REF3'] = str(data[-1-edge, 0+edge]) meta['LAT_REF4'] = str(data[-1-edge, -1-edge]) - lon_file = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lon'))[0] - data = np.memmap(lon_file, dtype='float64', mode='r', shape=(length, width)) + data = np.memmap(lon_files[0], dtype='float64', mode='r', shape=(length, width)) meta['LON_REF1'] = str(data[ 0+edge, 0+edge]) meta['LON_REF2'] = str(data[ 0+edge, -1-edge]) meta['LON_REF3'] = str(data[-1-edge, 0+edge]) meta['LON_REF4'] = str(data[-1-edge, -1-edge]) # CENTER_INCIDENCE_ANGLE is optional - los_files = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.los')) if len(los_files) > 0: - data = np.memmap(los_files[0], dtype='float32', mode='r', shape=(length*2, width))[0:length*2:2, :] + # use readfile.read() instead of np.memmap() to better handle different interleaves + data = readfile.read(los_files[0], datasetName='incidenceAngle')[0] inc_angle = data[int(length/2), int(width/2)] meta['CENTER_INCIDENCE_ANGLE'] = str(inc_angle) @@ -414,20 +425,30 @@ def alos2_acquisition_modes(): def extract_image_size_alosStack(geom_dir): - import isce - import isceobj # grab the number of looks in azimuth / range direction - lats = glob.glob(os.path.join(geom_dir, '*_*rlks_*alks.lat')) - rlooks = max(int(os.path.splitext(os.path.basename(x))[0].split('_')[1].strip('rlks')) for x in lats) - alooks = max(int(os.path.splitext(os.path.basename(x))[0].split('_')[2].strip('alks')) for x in lats) + lat_files = glob.glob(os.path.join(geom_dir, '*_*rlks_*alks.lat')) + lat_xml_files = [os.path.join(geom_dir, f'lat.rdr{x}.xml') for x in ['', '.mli']] + lat_xml_files = [x for x in lat_xml_files if os.path.exists(x)] + if len(lat_files) > 0: + # alosStack for InSAR + rlooks = max(int(os.path.splitext(os.path.basename(x))[0].split('_')[1].strip('rlks')) for x in lat_files) + alooks = max(int(os.path.splitext(os.path.basename(x))[0].split('_')[2].strip('alks')) for x in lat_files) + lat_xml_file = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lat.xml'))[0] + elif len(lat_xml_files) == 2: + # alos2App for dense offset, which are multilooked by mintpy + meta_ori = readfile.read_isce_xml(lat_xml_files[0]) + meta_mli = readfile.read_isce_xml(lat_xml_files[1]) + rlooks = int(np.floor( int(meta_ori['WIDTH']) / int(meta_mli['WIDTH']) )) + alooks = int(np.floor( int(meta_ori['LENGTH']) / int(meta_mli['LENGTH']) )) + lat_xml_file = lat_xml_files[1] + else: + raise ValueError(f'Un-recognized lookup table files in directory: {geom_dir}!') # grab the number of rows / coluns - lat = glob.glob(os.path.join(geom_dir, f'*_{rlooks}rlks_{alooks}alks.lat'))[0] - img = isceobj.createImage() - img.load(lat+'.xml') - width = img.width - length = img.length + meta_mli = readfile.read_isce_xml(lat_xml_file) + width = int(meta_mli['WIDTH']) + length = int(meta_mli['LENGTH']) return (rlooks, alooks, width, length) diff --git a/src/mintpy/utils/readfile.py b/src/mintpy/utils/readfile.py index 796f310fd..104057099 100644 --- a/src/mintpy/utils/readfile.py +++ b/src/mintpy/utils/readfile.py @@ -838,10 +838,17 @@ def get_hdf5_2d_dataset(name, obj): elif 'offset' in fbase and num_band == 2: # ampcor offset file, e.g. offset.bip, dense_offsets.bil slice_list = ['azimuthOffset', 'rangeOffset'] + if fname.endswith('_denseoffset.off'): + # for alos2App dense offset, the file has the opposite band order + # e.g. 231206-240103_denseoffset.off + slice_list = ['rangeOffset', 'azimuthOffset'] - elif 'offset' in fbase and '_cov' in fbase and num_band == 3: + elif 'offset' in fbase and 'cov' in fname and num_band == 3: # ampcor offset covariance file, e.g. offset_cov.bip, dense_offsets_cov.bil slice_list = ['azimuthOffsetVar', 'rangeOffsetVar', 'offsetCovar'] + if fname.endswith('_denseoffset.cov'): + # for alos2App dense offset, e.g. 231206-240103_denseoffset.cov + slice_list = ['rangeOffsetVar', 'azimuthOffsetVar', 'offsetCovar'] elif fext in ['.lkv']: slice_list = ['east', 'north', 'up'] @@ -1364,8 +1371,16 @@ def auto_no_data_value(meta): # known file types # isce2: dense offsets from topsApp.py - if processor == 'isce' and fname.endswith('dense_offsets.bil') and num_band == 2: - no_data_value = -10000. + if processor == 'isce' and num_band == 2: + # isce2 dense offset + if fname.endswith('dense_offsets.bil'): + # from topsApp.py + no_data_value = -10000. + elif fname.endswith('_denseoffset.off'): + # from alos2App.py + no_data_value = 0. + else: + no_data_value = None else: # default value for unknown file types