def _inner(ifg_paths): if isinstance(ifg_paths[0], Ifg): ifgs = ifg_paths else: ifgs = [Ifg(ifg_path) for ifg_path in ifg_paths] for ifg in ifgs: if not ifg.is_open: ifg.open(readonly=False) phase_data = [i.phase_data for i in ifgs] if params[cf.PARALLEL]: ref_phs = Parallel(n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))( delayed(_est_ref_phs_method2)( p, half_chip_size, refpx, refpy, thresh) for p in phase_data) for n, ifg in enumerate(ifgs): ifg.phase_data -= ref_phs[n] else: ref_phs = np.zeros(len(ifgs)) for n, ifg in enumerate(ifgs): ref_phs[n] = \ _est_ref_phs_method2(phase_data[n], half_chip_size, refpx, refpy, thresh) ifg.phase_data -= ref_phs[n] for ifg in ifgs: _update_phase_metadata(ifg) ifg.close() return ref_phs
def _inner(proc_ifgs, phase_data_sum): if isinstance(proc_ifgs[0], Ifg): proc_ifgs = proc_ifgs else: proc_ifgs = [Ifg(ifg_path) for ifg_path in proc_ifgs] for ifg in proc_ifgs: if not ifg.is_open: ifg.open(readonly=False) comp = np.isnan(phase_data_sum) comp = np.ravel(comp, order='F') if params[C.PARALLEL]: log.debug("Calculating ref phase using multiprocessing") ref_phs = Parallel( n_jobs=params[C.PROCESSES], verbose=joblib_log_level(C.LOG_LEVEL))( delayed(_est_ref_phs_ifg_median)(p.phase_data, comp) for p in proc_ifgs) else: log.debug("Calculating ref phase") ref_phs = np.zeros(len(proc_ifgs)) for n, ifg in enumerate(proc_ifgs): ref_phs[n] = _est_ref_phs_ifg_median(ifg.phase_data, comp) return ref_phs
def _inner(proc_ifgs, phase_data_sum): if isinstance(proc_ifgs[0], Ifg): proc_ifgs = proc_ifgs else: proc_ifgs = [Ifg(ifg_path) for ifg_path in proc_ifgs] for ifg in proc_ifgs: if not ifg.is_open: ifg.open(readonly=False) comp = np.isnan(phase_data_sum) comp = np.ravel(comp, order='F') if params[cf.PARALLEL]: phase_data = [i.phase_data for i in proc_ifgs] log.info("Calculating ref phase using multiprocessing") ref_phs = Parallel(n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))( delayed(_est_ref_phs_method1)(p, comp) for p in phase_data) for n, ifg in enumerate(proc_ifgs): ifg.phase_data -= ref_phs[n] else: log.info("Calculating ref phase") ref_phs = np.zeros(len(proc_ifgs)) for n, ifg in enumerate(proc_ifgs): ref_phs[n] = _est_ref_phs_method1(ifg.phase_data, comp) ifg.phase_data -= ref_phs[n] for ifg in proc_ifgs: _update_phase_metadata(ifg) ifg.close() return ref_phs
def do_geotiff(unw_paths: List[MultiplePaths], params: dict) -> List[str]: """ Convert input interferograms to geotiff format. """ # pylint: disable=expression-not-assigned log.info("Converting input interferograms to geotiff") parallel = params[cf.PARALLEL] if parallel: log.info("Running geotiff conversion in parallel with {} processes".format(params[cf.PROCESSES])) dest_base_ifgs = Parallel(n_jobs=params[cf.PROCESSES], verbose=shared.joblib_log_level(cf.LOG_LEVEL))( delayed(_geotiff_multiprocessing)(p, params) for p in unw_paths) else: log.info("Running geotiff conversion in serial") dest_base_ifgs = [_geotiff_multiprocessing(b, params) for b in unw_paths] return dest_base_ifgs
def stack_rate(ifgs, params, vcmt, mst=None): """ Pixel-by-pixel rate (velocity) estimation using iterative weighted least-squares stacking method. :param Ifg.object ifgs: Sequence of interferogram objects from which to extract observations :param dict params: Configuration parameters :param ndarray vcmt: Derived positive definite temporal variance covariance matrix :param ndarray mst: Pixel-wise matrix describing the minimum spanning tree network :return: rate: Rate (velocity) map :rtype: ndarray :return: error: Standard deviation of the rate map :rtype: ndarray :return: samples: Number of observations used in rate calculation per pixel :rtype: ndarray """ maxsig, nsig, pthresh, cols, error, mst, obs, parallel, _, rate, rows, samples, span = _stack_setup(ifgs, mst, params) # pixel-by-pixel calculation. # nested loops to loop over the 2 image dimensions if parallel: log.info('Calculating stack rate in parallel') res = Parallel(n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))( delayed(_stack_rate_by_pixel)(r, c, mst, nsig, obs, pthresh, span, vcmt) for r, c in itertools.product(range(rows), range(cols)) ) res = np.array(res) rate = res[:, 0].reshape(rows, cols) error = res[:, 1].reshape(rows, cols) samples = res[:, 2].reshape(rows, cols) else: log.info('Calculating stack rate in serial') for i in range(rows): for j in range(cols): rate[i, j], error[i, j], samples[i, j] = _stack_rate_by_pixel(i, j, mst, nsig, obs, pthresh, span, vcmt) # overwrite the data whose error is larger than the # maximum sigma user threshold mask = ~isnan(error) mask[mask] &= error[mask] > maxsig rate[mask] = nan error[mask] = nan # samples[mask] = nan # should we also mask the samples? return rate, error, samples
def ref_pixel(ifgs, params): """ Determines the most appropriate reference pixel coordinate by conducting a grid search and calculating the mean standard deviation with patches around candidate pixels from the given interferograms. If the config file REFX or REFY values are empty or negative, the search for the reference pixel is performed. If the REFX|Y values are within the bounds of the raster, a search is not performed. REFX|Y values outside the upper bounds cause an exception. :param list ifgs: List of interferogram objects :param dict params: Dictionary of configuration parameters :return: tuple of best REFX and REFY coordinates :rtype: tuple """ half_patch_size, thresh, grid = ref_pixel_setup(ifgs, params) parallel = params[cf.PARALLEL] if parallel: phase_data = [i.phase_data for i in ifgs] mean_sds = Parallel( n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))(delayed(_ref_pixel_multi)( g, half_patch_size, phase_data, thresh, params) for g in grid) refxy = find_min_mean(mean_sds, grid) else: phase_data = [i.phase_data for i in ifgs] mean_sds = [] for g in grid: mean_sds.append( _ref_pixel_multi(g, half_patch_size, phase_data, thresh, params)) refxy = find_min_mean(mean_sds, grid) if isinstance(refxy, ValueError): raise ValueError('Refpixel calculation not possible!') refy, refx = refxy if refy and refx: return refy, refx raise RefPixelError("Could not find a reference pixel")
def stack_rate_array(ifgs, params, vcmt, mst=None): """ This function loops over all interferogram pixels in a 3-dimensional array and estimates the pixel rate (velocity) by applying the iterative weighted least-squares stacking algorithm 'pyrate.core.stack.stack_rate_pixel'. :param Ifg.object ifgs: Sequence of objects containing the interferometric observations :param dict params: Configuration parameters :param ndarray vcmt: Derived positive definite temporal variance covariance matrix :param ndarray mst: Pixel-wise matrix describing the minimum spanning tree network :return: rate: Rate (velocity) map :rtype: ndarray :return: error: Standard deviation of the rate map :rtype: ndarray :return: samples: Number of observations used in rate calculation for each pixel :rtype: ndarray """ nsig, pthresh, cols, error, mst, obs, parallel, _, rate, rows, samples, span = _stack_setup( ifgs, mst, params) # pixel-by-pixel calculation. # nested loops to loop over the 2 image dimensions if parallel: log.info('Calculating stack rate in parallel') res = Parallel( n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))( delayed(stack_rate_pixel)(obs[:, r, c], mst[:, r, c], vcmt, span, nsig, pthresh) for r, c in itertools.product(range(rows), range(cols))) res = np.array(res) rate = res[:, 0].reshape(rows, cols) error = res[:, 1].reshape(rows, cols) samples = res[:, 2].reshape(rows, cols) else: log.info('Calculating stack rate in serial') for i in range(rows): for j in range(cols): rate[i, j], error[i, j], samples[i, j] = stack_rate_pixel( obs[:, i, j], mst[:, i, j], vcmt, span, nsig, pthresh) return rate, error, samples
def mst_parallel(ifgs, params): """ Wrapper function for calculating MST matrix in non-MPI runs. :param list ifgs: List of interferogram objects (Ifg class) :param dict params: Dictionary of parameters :return: result: 3-dimensional Minimum Spanning Tree matrix :rtype: ndarray """ log.info('Calculating MST in tiles') ncpus = params[cf.PROCESSES] no_ifgs = len(ifgs) no_y, no_x = ifgs[0].phase_data.shape tiles = create_tiles(ifgs[0].shape) no_tiles = len(tiles) # need to break up the ifg class as multiprocessing does not allow pickling # don't read in all the phase data at once # use data paths and locally read in each core/process, # gdal read is very fast ifg_paths = [i.data_path for i in ifgs] result = empty(shape=(no_ifgs, no_y, no_x), dtype=np.bool) if params[cf.PARALLEL]: log.info('Calculating MST using {} tiles in parallel using {} ' \ 'processes'.format(no_tiles, ncpus)) t_msts = Parallel( n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))( delayed(mst_multiprocessing)(t, ifg_paths, params=params) for t in tiles) for k, tile in enumerate(tiles): result[:, tile.top_left_y:tile.bottom_right_y, tile.top_left_x:tile.bottom_right_x] = t_msts[k] else: log.info('Calculating MST using {} tiles in serial'.format(no_tiles)) for k, tile in enumerate(tiles): result[:, tile.top_left_y:tile.bottom_right_y, tile.top_left_x: tile.bottom_right_x] = \ mst_multiprocessing(tile, ifg_paths, params=params) return result
def do_geotiff(base_unw_paths, params): """ Convert input interferograms to geotiff format. :param list base_unw_paths: List of unwrapped interferograms :param dict params: Parameters dictionary corresponding to config file """ # pylint: disable=expression-not-assigned log.info("Converting input interferograms to geotiff") parallel = params[cf.PARALLEL] if parallel: log.info("Running geotiff conversion in parallel with {} " "processes".format(params[cf.PROCESSES])) dest_base_ifgs = Parallel(n_jobs=params[cf.PROCESSES], verbose=shared.joblib_log_level(cf.LOG_LEVEL))( delayed(_geotiff_multiprocessing)(p, params) for p in base_unw_paths) else: log.info("Running geotiff conversion in serial") dest_base_ifgs = [_geotiff_multiprocessing(b, params) for b in base_unw_paths] return dest_base_ifgs
def time_series(ifgs, params, vcmt=None, mst=None): """ Calculates the displacement time series from the given interferogram network. Solves the linear least squares system using either the SVD method (similar to the SBAS method implemented by Berardino et al. 2002) or a Finite Difference method using a Laplacian Smoothing operator (similar to the method implemented by Schmidt and Burgmann 2003) :param list ifgs: list of interferogram class objects. :param dict params: Dictionary of configuration parameters :param ndarray vcmt: Positive definite temporal variance covariance matrix :param ndarray mst: [optional] Minimum spanning tree array. :return: Tuple with the elements: - incremental displacement time series, - cumulative displacement time series, and - velocity for the epoch interval these outputs are multi-dimensional arrays of size(nrows, ncols, nepochs-1), where: - *nrows* is the number of rows in the ifgs, - *ncols* is the number of columns in the ifgs, and - *nepochs* is the number of unique epochs (dates) :rtype: tuple """ b0_mat, interp, p_thresh, sm_factor, sm_order, ts_method, ifg_data, mst, \ ncols, nrows, nvelpar, parallel, span, tsvel_matrix = \ _time_series_setup(ifgs, mst, params) if parallel: log.info('Calculating timeseries in parallel') res = np.array( Parallel( n_jobs=params[cf.PROCESSES], verbose=joblib_log_level(cf.LOG_LEVEL))( delayed(_time_series_by_pixel) (i, j, b0_mat, sm_factor, sm_order, ifg_data, mst, nvelpar, p_thresh, interp, vcmt, ts_method) for (i, j) in itertools.product(range(nrows), range(ncols)))) tsvel_matrix = np.reshape(res, newshape=(nrows, ncols, res.shape[1])) else: log.info('Calculating timeseries in serial') for row in range(nrows): for col in range(ncols): tsvel_matrix[row, col] = _time_series_by_pixel( row, col, b0_mat, sm_factor, sm_order, ifg_data, mst, nvelpar, p_thresh, interp, vcmt, ts_method) tsvel_matrix = where(tsvel_matrix == 0, nan, tsvel_matrix) # SB: do the span multiplication as a numpy linalg operation, MUCH faster # not even this is necessary here, perform late for performance tsincr = tsvel_matrix * span tscum = cumsum(tsincr, 2) # SB: perform this after tsvel_matrix has been nan converted, # saves the step of comparing a large matrix (tsincr) to zero. # tscum = where(tscum == 0, nan, tscum) return tsincr, tscum, tsvel_matrix