def test_get_all_epochs(self): # test function to extract all dates from sequence of ifgs ifgs = small5_mock_ifgs() for i in ifgs: i.nodata_value = 0 dates = [date(2006, 8, 28), date(2006, 11, 6), date(2006, 12, 11), date(2007, 1, 15), date(2007, 3, 26), date(2007, 9, 17)] self.assertEqual(dates, sorted(set(get_all_epochs(ifgs))))
def get_network_design_matrix(ifgs, degree, scale, intercept=True): # pylint: disable=too-many-locals """ Returns larger-format design matrix for network error correction. The network design matrix includes rows which relate to those of NaN cells. :param list ifgs: List of Ifg class objects :param str degree: model to fit (PLANAR / QUADRATIC / PART_CUBIC) :param int scale: Scale factor for design matrix to improve inversion robustness :param bool intercept: whether to include columns for intercept estimation. :return: netdm: network design matrix :rtype: ndarray """ if degree not in [PLANAR, QUADRATIC, PART_CUBIC]: raise OrbitalError("Invalid degree argument") if scale < 1: raise OrbitalError("Scale argument must be greater or equal to 1") nifgs = len(ifgs) if nifgs < 1: # can feasibly do correction on a single Ifg/2 epochs raise OrbitalError("Invalid number of Ifgs: %s" % nifgs) # init sparse network design matrix nepochs = len(set(get_all_epochs(ifgs))) # no intercepts here; they are included separately below ncoef = _get_num_params(degree) shape = [ifgs[0].num_cells * nifgs, ncoef * nepochs] if intercept: shape[1] += nepochs # add extra space for intercepts netdm = zeros(shape, dtype=float32) # calc location for individual design matrices dates = [ifg.first for ifg in ifgs] + [ifg.second for ifg in ifgs] ids = first_second_ids(dates) tmpdm = get_design_matrix(ifgs[0], degree, intercept=intercept, scale=scale) # iteratively build up sparse matrix for i, ifg in enumerate(ifgs): rs = i * ifg.num_cells # starting row m = ids[ifg.first] * (ncoef + intercept) # start col for first s = ids[ifg.second] * (ncoef + intercept) # start col for second netdm[rs:rs + ifg.num_cells, m:m + ncoef + intercept] = -tmpdm netdm[rs:rs + ifg.num_cells, s:s + ncoef + intercept] = tmpdm return netdm
def get_network_design_matrix(ifgs, degree, offset): # pylint: disable=too-many-locals """ Returns larger-format design matrix for network error correction. The network design matrix includes rows which relate to those of NaN cells. :param list ifgs: List of Ifg class objects :param str degree: model to fit (PLANAR / QUADRATIC / PART_CUBIC) :param bool offset: True to include offset cols, otherwise False. :return: netdm: network design matrix :rtype: ndarray """ if degree not in [PLANAR, QUADRATIC, PART_CUBIC]: raise OrbitalError("Invalid degree argument") nifgs = len(ifgs) if nifgs < 1: # can feasibly do correction on a single Ifg/2 epochs raise OrbitalError("Invalid number of Ifgs: %s" % nifgs) # init sparse network design matrix nepochs = len(set(get_all_epochs(ifgs))) # no offsets: they are made separately below ncoef = _get_num_params(degree) shape = [ifgs[0].num_cells * nifgs, ncoef * nepochs] if offset: shape[1] += nifgs # add extra block for offset cols netdm = zeros(shape, dtype=float32) # calc location for individual design matrices dates = [ifg.first for ifg in ifgs] + [ifg.second for ifg in ifgs] ids = first_second_ids(dates) offset_col = nepochs * ncoef # base offset for the offset cols tmpdm = get_design_matrix(ifgs[0], degree, offset=False) # iteratively build up sparse matrix for i, ifg in enumerate(ifgs): rs = i * ifg.num_cells # starting row m = ids[ifg.first] * ncoef # start col for first s = ids[ifg.second] * ncoef # start col for second netdm[rs:rs + ifg.num_cells, m:m + ncoef] = -tmpdm netdm[rs:rs + ifg.num_cells, s:s + ncoef] = tmpdm # offsets are diagonal cols across the extra array block created above if offset: netdm[rs:rs + ifg.num_cells, offset_col + i] = 1 # init offset cols return netdm
def test_get_epoch_count(self): self.assertEqual(6, len(set(get_all_epochs(small5_mock_ifgs()))))
def network_orbital_correction(ifg_paths, params, m_ifgs: Optional[List] = 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 ifg_paths: 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 offset = params[cf.ORBFIT_OFFSET] degree = params[cf.ORBITAL_FIT_DEGREE] preread_ifgs = params[cf.PREREAD_IFGS] # all orbit corrections available? if isinstance(ifg_paths[0], str): if __check_and_apply_orberrors_found_on_disc(ifg_paths, params): log.warning("Reusing orbfit errors from previous run!!!") return # all corrections are available in numpy files already saved - return ifgs = [shared.Ifg(i) for i in ifg_paths] else: # alternate test paths # TODO: improve ifgs = ifg_paths 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 = first_second_ids(get_all_epochs(temp_ifgs)) else: ids = first_second_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(ifg_paths[0]) # ifgs here are paths temp_ifg.open() dm = get_design_matrix(temp_ifg, degree, offset=False) temp_ifg.close() else: ifg = ifgs[0] dm = get_design_matrix(ifg, degree, offset=False) for i in ifg_paths: # 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, params)
def network_orbital_correction(ifg_paths, params, m_ifgs: Optional[List] = 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 ifg_paths: List of Ifg class objects reduced to a minimum spanning tree network :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) :return: None - interferogram phase data is updated and saved to disk """ # pylint: disable=too-many-locals, too-many-arguments offset = params[C.ORBFIT_OFFSET] degree = params[C.ORBITAL_FIT_DEGREE] preread_ifgs = params[C.PREREAD_IFGS] intercept = params[C.ORBFIT_INTERCEPT] scale = params[C.ORBFIT_SCALE] # all orbit corrections available? if isinstance(ifg_paths[0], str): if __check_and_apply_orberrors_found_on_disc(ifg_paths, params): log.warning("Reusing orbfit errors from previous run!!!") return # all corrections are available in numpy files already saved - return ifgs = [shared.Ifg(i) for i in ifg_paths] else: # alternate test paths # TODO: improve ifgs = ifg_paths src_ifgs = ifgs if m_ifgs is None else m_ifgs src_ifgs = mst.mst_from_ifgs(src_ifgs)[3] # use networkx mst if preread_ifgs: temp_ifgs = OrderedDict(sorted(preread_ifgs.items())).values() ids = first_second_ids(get_all_epochs(temp_ifgs)) else: ids = first_second_ids(get_all_epochs(ifgs)) nepochs = len(set(ids)) # call the actual inversion routine coefs = calc_network_orb_correction(src_ifgs, degree, scale, nepochs, intercept=intercept) # 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(ifg_paths[0]) # ifgs here are paths temp_ifg.open() dm = get_design_matrix(temp_ifg, degree, intercept=intercept, scale=scale) temp_ifg.close() else: ifg = ifgs[0] dm = get_design_matrix(ifg, degree, intercept=intercept, scale=scale) for i in ifg_paths: # 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, params)