def _ts_to_ifgs(tsincr, preread_ifgs, params): """ Function that converts an incremental displacement time series into interferometric phase observations. Used to re-construct an interferogram network from a time series. :param ndarray tsincr: incremental time series array of size (ifg.shape, nepochs-1) :param dict preread_ifgs: Dictionary of shared.PrereadIfg class instances :return: None, interferograms are saved to disk """ log.debug('Reconstructing interferometric observations from time series') ifgs = list(OrderedDict(sorted(preread_ifgs.items())).values()) _, n = mpiops.run_once(get_epochs, ifgs) index_first, index_second = n[:len(ifgs)], n[len(ifgs):] num_ifgs_tuples = mpiops.array_split(list(enumerate(ifgs))) num_ifgs_tuples = [(int(num), ifg) for num, ifg in num_ifgs_tuples] for i, ifg in num_ifgs_tuples: aps_correction_on_disc = MultiplePaths.aps_error_path( ifg.tmp_path, params) phase = np.sum(tsincr[:, :, index_first[i]:index_second[i]], axis=2) np.save(file=aps_correction_on_disc, arr=phase) _save_aps_corrected_phase(ifg.tmp_path, phase)
def spatio_temporal_filter(params: dict) -> None: """ Applies a spatio-temporal filter to remove the atmospheric phase screen (APS) and saves the corrected interferograms. Firstly the incremental time series is computed using the SVD method, before a cascade of temporal then spatial Gaussian filters is applied. The resulting APS corrections are saved to disc before being subtracted from each interferogram. :param params: Dictionary of PyRate configuration parameters. """ if params[C.APSEST]: log.info('Doing APS spatio-temporal filtering') else: log.info('APS spatio-temporal filtering not required') return tiles = params[C.TILES] preread_ifgs = params[C.PREREAD_IFGS] ifg_paths = [ ifg_path.tmp_sampled_path for ifg_path in params[C.INTERFEROGRAM_FILES] ] # perform some checks on existing ifgs log.debug('Checking APS correction status') if mpiops.run_once(shared.check_correction_status, ifg_paths, ifc.PYRATE_APS_ERROR): log.debug('Finished APS correction') return # return if True condition returned aps_paths = [MultiplePaths.aps_error_path(i, params) for i in ifg_paths] if all(a.exists() for a in aps_paths): log.warning('Reusing APS errors from previous run') _apply_aps_correction(ifg_paths, aps_paths, params) return # obtain the incremental time series using SVD tsincr = _calc_svd_time_series(ifg_paths, params, preread_ifgs, tiles) mpiops.comm.barrier() # get lists of epochs and ifgs ifgs = list(OrderedDict(sorted(preread_ifgs.items())).values()) epochlist = mpiops.run_once(get_epochs, ifgs)[0] # first perform temporal high pass filter ts_hp = temporal_high_pass_filter(tsincr, epochlist, params) # second perform spatial low pass filter to obtain APS correction in ts domain ifg = Ifg(ifg_paths[0]) # just grab any for parameters in slpfilter ifg.open() ts_aps = spatial_low_pass_filter(ts_hp, ifg, params) ifg.close() # construct APS corrections for each ifg _make_aps_corrections(ts_aps, ifgs, params) # apply correction to ifgs and save ifgs to disc. _apply_aps_correction(ifg_paths, aps_paths, params) # update/save the phase_data in the tiled numpy files shared.save_numpy_phase(ifg_paths, params)
def test_aps_error_files_on_disc(self, slpfmethod, slpfcutoff, slpforder): self.params[cf.SLPF_METHOD] = slpfmethod self.params[cf.SLPF_CUTOFF] = slpfcutoff self.params[cf.SLPF_ORDER] = slpforder wrap_spatio_temporal_filter(self.params) # test_orb_errors_written aps_error_files = [ MultiplePaths.aps_error_path(i, self.params) for i in self.ifg_paths ] assert all(p.exists() for p in aps_error_files) last_mod_times = [os.stat(o).st_mtime for o in aps_error_files] phase_prev = [i.phase_data for i in self.ifgs] # run aps error removal again wrap_spatio_temporal_filter(self.params) aps_error_files2 = [ MultiplePaths.aps_error_path(i, self.params) for i in self.ifg_paths ] # if files are written again - times will change last_mod_times_2 = [os.stat(o).st_mtime for o in aps_error_files2] # test_aps_error_reused_if_params_unchanged assert all(a == b for a, b in zip(last_mod_times, last_mod_times_2)) phase_now = [i.phase_data for i in self.ifgs] # run aps error correction once mroe wrap_spatio_temporal_filter(self.params) aps_error_files3 = [ MultiplePaths.aps_error_path(i, self.params) for i in self.ifg_paths ] last_mod_times_3 = [os.stat(o).st_mtime for o in aps_error_files3] assert all(a == b for a, b in zip(last_mod_times, last_mod_times_3)) phase_again = [i.phase_data for i in self.ifgs] np.testing.assert_array_equal(phase_prev, phase_now) np.testing.assert_array_equal(phase_prev, phase_again)
def wrap_spatio_temporal_filter(params): """ A wrapper for the spatio-temporal filter so it can be tested. See docstring for spatio_temporal_filter. """ if params[cf.APSEST]: log.info('Doing APS spatio-temporal filtering') else: log.info('APS spatio-temporal filtering not required') return tiles = params[cf.TILES] preread_ifgs = params[cf.PREREAD_IFGS] ifg_paths = [ ifg_path.tmp_sampled_path for ifg_path in params[cf.INTERFEROGRAM_FILES] ] # perform some checks on existing ifgs log.debug('Checking APS correction status') if mpiops.run_once(shared.check_correction_status, ifg_paths, ifc.PYRATE_APS_ERROR): log.debug('Finished APS correction') return # return if True condition returned aps_error_files_on_disc = [ MultiplePaths.aps_error_path(i, params) for i in ifg_paths ] if all(a.exists() for a in aps_error_files_on_disc): log.warning("Reusing APS errors from previous run!!!") for ifg_path, a in mpiops.array_split( list(zip(ifg_paths, aps_error_files_on_disc))): phase = np.load(a) _save_aps_corrected_phase(ifg_path, phase) else: tsincr = _calc_svd_time_series(ifg_paths, params, preread_ifgs, tiles) mpiops.comm.barrier() spatio_temporal_filter(tsincr, ifg_paths, params, preread_ifgs) mpiops.comm.barrier() shared.save_numpy_phase(ifg_paths, params)
def _make_aps_corrections(ts_aps: np.ndarray, ifgs: List[Ifg], params: dict) -> None: """ Function to convert the time series APS filter output into interferometric phase corrections and save them to disc. :param ts_aps: Incremental APS time series array. :param ifgs: List of Ifg class objects. :param params: Dictionary of PyRate configuration parameters. """ log.debug('Reconstructing interferometric observations from time series') # get first and second image indices _, n = mpiops.run_once(get_epochs, ifgs) index_first, index_second = n[:len(ifgs)], n[len(ifgs):] num_ifgs_tuples = mpiops.array_split(list(enumerate(ifgs))) for i, ifg in [(int(num), ifg) for num, ifg in num_ifgs_tuples]: # sum time slice data from first to second epoch ifg_aps = np.sum(ts_aps[:, :, index_first[i]:index_second[i]], axis=2) aps_error_on_disc = MultiplePaths.aps_error_path(ifg.tmp_path, params) np.save(file=aps_error_on_disc, arr=ifg_aps) # save APS as numpy array mpiops.comm.barrier()