def cvd(ifg_path, params, r_dist, calc_alpha=False, write_vals=False, save_acg=False): """ Calculate the 1D covariance function of an entire interferogram as the radial average of its 2D autocorrelation. :param str ifg_path: An interferogram file path. OR :param Ifg class ifg_path: A pyrate.shared.Ifg class object :param dict params: Dictionary of configuration parameters :param ndarray r_dist: Array of distance values from the image centre (See Rdist class for more details) :param bool calc_alpha: If True calculate alpha :param bool write_vals: If True write maxvar and alpha values to interferogram metadata :param bool save_acg: If True write autocorrelation and radial distance data to numpy array file on disk :return: maxvar: The maximum variance (at zero lag) :rtype: float :return: alpha: the exponential length-scale of decay factor :rtype: float """ if isinstance(ifg_path, str): # used during MPI ifg = shared.Ifg(ifg_path) ifg.open() else: ifg = ifg_path shared.nan_and_mm_convert(ifg, params) # calculate 2D auto-correlation of image using the # spectral method (Wiener-Khinchin theorem) if ifg.nan_converted: # if nancoverted earlier, convert nans back to 0's phase = where(isnan(ifg.phase_data), 0, ifg.phase_data) else: phase = ifg.phase_data maxvar, alpha = cvd_from_phase(phase, ifg, r_dist, calc_alpha, save_acg=save_acg, params=params) if write_vals: _add_metadata(ifg, maxvar, alpha) if isinstance(ifg_path, str): ifg.close() return maxvar, alpha
def pre_prepare_ifgs(ifg_paths, params): """ Open ifg for reading """ ifgs = [Ifg(p) for p in ifg_paths] for i in ifgs: if not i.is_open: i.open(readonly=False) nan_and_mm_convert(i, params) log.info('Opened ifg for reading') return ifgs
def independent_orbital_correction(ifg, degree, offset, params): """ Calculates and removes an orbital error surface from a single independent interferogram. Warning: This will write orbital error corrected phase_data to the ifg. :param Ifg class instance ifg: the interferogram to be corrected :param str degree: model to fit (PLANAR / QUADRATIC / PART_CUBIC) :param bool offset: True to calculate the model using an offset :param dict params: dictionary of configuration parameters :return: None - interferogram phase data is updated and saved to disk """ ifg = shared.Ifg(ifg) if isinstance(ifg, str) else ifg if not ifg.is_open: ifg.open() shared.nan_and_mm_convert(ifg, params) # vectorise, keeping NODATA vphase = reshape(ifg.phase_data, ifg.num_cells) dm = get_design_matrix(ifg, degree, offset) # filter NaNs out before getting model clean_dm = dm[~isnan(vphase)] data = vphase[~isnan(vphase)] model = lstsq(clean_dm, data)[0] # first arg is the model params # calculate forward model & morph back to 2D if offset: fullorb = np.reshape(np.dot(dm[:, :-1], model[:-1]), ifg.phase_data.shape) else: fullorb = np.reshape(np.dot(dm, model), ifg.phase_data.shape) offset_removal = nanmedian(np.ravel(ifg.phase_data - fullorb)) # subtract orbital error from the ifg ifg.phase_data -= (fullorb - offset_removal) # set orbfit meta tag and save phase to file _save_orbital_error_corrected_phase(ifg) if ifg.open(): ifg.close()
def independent_correction(ifg, degree, offset, params): """ Calculates and removes orbital correction from an interferogram. .. warn:: This will write orbital error corrected phase_data in the interferograms. :param ifg: The interferogram to remove remove the orbital error from :param degree: PLANAR, QUADRATIC or PART_CUBIC :param offset: Boolean :param params: Parameter dictionary :return xxxx """ ifg = shared.Ifg(ifg) if isinstance(ifg, str) else ifg if not ifg.is_open: ifg.open() shared.nan_and_mm_convert(ifg, params) # vectorise, keeping NODATA vphase = reshape(ifg.phase_data, ifg.num_cells) dm = get_design_matrix(ifg, degree, offset) # filter NaNs out before getting model clean_dm = dm[~isnan(vphase)] data = vphase[~isnan(vphase)] model = lstsq(clean_dm, data)[0] # first arg is the model params # calculate forward model & morph back to 2D if offset: fullorb = np.reshape(np.dot(dm[:, :-1], model[:-1]), ifg.phase_data.shape) else: fullorb = np.reshape(np.dot(dm, model), ifg.phase_data.shape) offset_removal = nanmedian(np.ravel(ifg.phase_data - fullorb)) ifg.phase_data -= (fullorb - offset_removal) # set orbfit tags after orbital error correction _save_orbital_error_corrected_phase(ifg) if ifg.open(): ifg.close()
def cvd(ifg_path, params, calc_alpha=False): """ Calculate average covariance versus distance (autocorrelation) and its best fitting exponential function. :param ifg_path: An interferogram. ifg: :py:class:`pyrate.shared.Ifg` :param: params: Dictionary of configuration parameters :param calc_alpha: Whether to calculate alpha :return xxxx """ # pylint: disable=invalid-name # pylint: disable=too-many-locals if isinstance(ifg_path, str): # used during MPI ifg = shared.Ifg(ifg_path) ifg.open() else: ifg = ifg_path # assert isinstance(ifg_path, shared.Ifg) # ifg = ifg_path shared.nan_and_mm_convert(ifg, params) # calculate 2D auto-correlation of image using the # spectral method (Wiener-Khinchin theorem) if ifg.nan_converted: # saves heaps of time with no-nan conversion phase = where(isnan(ifg.phase_data), 0, ifg.phase_data) else: phase = ifg.phase_data # distance division factor of 1000 converts to km and is needed to match # Matlab code output distfact = 1000 nrows, ncols = phase.shape fft_phase = fft2(phase) pspec = real(fft_phase)**2 + imag(fft_phase)**2 autocorr_grid = ifft2(pspec) nzc = np.sum(np.sum(phase != 0)) autocorr_grid = fftshift(real(autocorr_grid)) / nzc # pixel distances from pixel at zero lag (image centre). xx, yy = meshgrid(range(ncols), range(nrows)) # r_dist is distance from the center # doing np.divide and np.sqrt will improve performance as it keeps # calculations in the numpy land r_dist = np.divide(np.sqrt(((xx-ifg.x_centre) * ifg.x_size)**2 + ((yy-ifg.y_centre) * ifg.y_size)**2), distfact) r_dist = reshape(r_dist, ifg.num_cells) acg = reshape(autocorr_grid, ifg.num_cells) # Symmetry in image; keep only unique points # tmp = unique_points(zip(acg, r_dist)) # Sudipta: Is this faster than keeping only the 1st half as in Matlab? # Sudipta: Unlikely, as unique_point is a search/comparison, # whereas keeping 1st half is just numpy indexing. # If it is not faster, why was this done differently here? r_dist = r_dist[:int(ceil(ifg.num_cells/2.0)) + ifg.nrows] acg = acg[:len(r_dist)] # Alternative method to remove duplicate cells (from Matlab Pirate code) # r_dist = r_dist[:ceil(len(r_dist)/2)+nlines] # Reason for '+nlines' term unknown # eg. array([x for x in set([(1,1), (2,2), (1,1)])]) # the above shortens r_dist by some number of cells # bin width for collecting data bin_width = max(ifg.x_size, ifg.y_size) * 2 / distfact # pick the smallest axis to determine circle search radius # print 'ifg.X_CENTRE, ifg.Y_CENTRE=', ifg.x_centre, ifg.y_centre # print 'ifg.X_SIZE, ifg.Y_SIZE', ifg.x_size, ifg.y_size if (ifg.x_centre * ifg.x_size) < (ifg.y_centre * ifg.y_size): maxdist = ifg.x_centre * ifg.x_size / distfact else: maxdist = ifg.y_centre * ifg.y_size/ distfact # filter out data where the of lag distance is greater than maxdist # r_dist = array([e for e in rorig if e <= maxdist]) # # MG: prefers to use all the data # acg = array([e for e in rorig if e <= maxdist]) indices_to_keep = r_dist < maxdist r_dist = r_dist[indices_to_keep] acg = acg[indices_to_keep] if isinstance(ifg_path, str): ifg.close() if calc_alpha: # classify values of r_dist according to bin number rbin = ceil(r_dist / bin_width).astype(int) maxbin = max(rbin) # consistent with Matlab code cvdav = zeros(shape=(2, maxbin)) # the following stays in numpy land # distance instead of bin number cvdav[0, :] = np.multiply(range(maxbin), bin_width) # mean variance for the bins cvdav[1, :] = [mean(acg[rbin == b]) for b in range(maxbin)] # calculate best fit function maxvar*exp(-alpha*r_dist) alphaguess = 2 / (maxbin * bin_width) alpha = fmin(pendiffexp, x0=alphaguess, args=(cvdav,), disp=0, xtol=1e-6, ftol=1e-6) print("1st guess alpha", alphaguess, 'converged alpha:', alpha) # maximum variance usually at the zero lag: max(acg[:len(r_dist)]) return np.max(acg), alpha[0] else: return np.max(acg), None
def network_orbital_correction(ifgs, degree, offset, params, m_ifgs=None, preread_ifgs=None): """ This algorithm implements a network inversion to determine orbital corrections for a set of interferograms forming a connected network. Warning: This will write orbital error corrected phase_data to the ifgs. :param list ifgs: List of Ifg class objects reduced to a minimum spanning tree network :param str degree: model to fit (PLANAR / QUADRATIC / PART_CUBIC) :param bool offset: True to calculate the model using offsets :param dict params: dictionary of configuration parameters :param list m_ifgs: list of multilooked Ifg class objects (sequence must be multilooked versions of 'ifgs' arg) :param dict preread_ifgs: Dictionary containing information specifically for MPI jobs (optional) :return: None - interferogram phase data is updated and saved to disk """ # pylint: disable=too-many-locals, too-many-arguments src_ifgs = ifgs if m_ifgs is None else m_ifgs src_ifgs = mst.mst_from_ifgs(src_ifgs)[3] # use networkx mst vphase = vstack([i.phase_data.reshape((i.num_cells, 1)) for i in src_ifgs]) vphase = squeeze(vphase) B = get_network_design_matrix(src_ifgs, degree, offset) # filter NaNs out before getting model B = B[~isnan(vphase)] orbparams = dot(pinv(B, 1e-6), vphase[~isnan(vphase)]) ncoef = _get_num_params(degree) if preread_ifgs: temp_ifgs = OrderedDict(sorted(preread_ifgs.items())).values() ids = master_slave_ids(get_all_epochs(temp_ifgs)) else: ids = master_slave_ids(get_all_epochs(ifgs)) coefs = [ orbparams[i:i + ncoef] for i in range(0, len(set(ids)) * ncoef, ncoef) ] # create full res DM to expand determined coefficients into full res # orbital correction (eg. expand coarser model to full size) if preread_ifgs: temp_ifg = Ifg(ifgs[0]) # ifgs here are paths temp_ifg.open() dm = get_design_matrix(temp_ifg, degree, offset=False) temp_ifg.close() else: dm = get_design_matrix(ifgs[0], degree, offset=False) for i in ifgs: # open if not Ifg instance if isinstance(i, str): # pragma: no cover # are paths i = Ifg(i) i.open(readonly=False) shared.nan_and_mm_convert(i, params) _remove_network_orb_error(coefs, dm, i, ids, offset)
def network_correction(ifgs, degree, offset, params, m_ifgs=None, preread_ifgs=None): """ Calculates orbital correction model, removing this from the interferograms. .. warn:: This will write orbital error corrected phase_data in the interferograms. :param ifgs: Interferograms reduced to a minimum tree from prior MST calculations :param degree: PLANAR, QUADRATIC or PART_CUBIC :param offset: True to calculate the model using offsets :param params: Parameter dictionary :param m_ifgs: Multi-looked orbfit interferograms (sequence must be mlooked versions of 'ifgs' arg) :param preread_ifgs: Parameters dict corresponding to config file :return xxxx """ # pylint: disable=too-many-locals, too-many-arguments src_ifgs = ifgs if m_ifgs is None else m_ifgs src_ifgs = mst.mst_from_ifgs(src_ifgs)[3] # use networkx mst vphase = vstack([i.phase_data.reshape((i.num_cells, 1)) for i in src_ifgs]) vphase = squeeze(vphase) B = get_network_design_matrix(src_ifgs, degree, offset) # filter NaNs out before getting model B = B[~isnan(vphase)] orbparams = dot(pinv(B, 1e-6), vphase[~isnan(vphase)]) ncoef = _get_num_params(degree) if preread_ifgs: temp_ifgs = OrderedDict(sorted(preread_ifgs.items())).values() ids = master_slave_ids(get_all_epochs(temp_ifgs)) else: ids = master_slave_ids(get_all_epochs(ifgs)) coefs = [ orbparams[i:i + ncoef] for i in range(0, len(set(ids)) * ncoef, ncoef) ] # create full res DM to expand determined coefficients into full res # orbital correction (eg. expand coarser model to full size) if preread_ifgs: temp_ifg = Ifg(ifgs[0]) # ifgs here are paths temp_ifg.open() dm = get_design_matrix(temp_ifg, degree, offset=False) temp_ifg.close() else: dm = get_design_matrix(ifgs[0], degree, offset=False) # TODO: remove this import from tests suite from tests.common import MockIfg for i in ifgs: # open if not Ifg instance if not (isinstance(i, Ifg) or isinstance(i, MockIfg)): # pragma: no cover # are paths i = Ifg(i) i.open(readonly=False) shared.nan_and_mm_convert(i, params) _remove_networkx_error(coefs, dm, i, ids, offset)