def design_matrix4deformation(inps): # Date Info ts_obj = timeseries(inps.timeseries_file) ts_obj.open() # Design matrix - temporal deformation model print('-'*80) print('correct topographic phase residual (DEM error) (Fattahi & Amelung, 2013, IEEE-TGRS)') msg = 'ordinal least squares (OLS) inversion with L2-norm minimization on: phase' if inps.phaseVelocity: msg += ' velocity' if inps.rangeDist.size != 1: msg += ' (pixel-wisely)' print(msg) tbase = np.array(ts_obj.tbase, np.float32) / 365.25 # 1. Polynomial - 2D matrix in size of (numDate, polyOrder+1) print("temporal deformation model: polynomial order = "+str(inps.polyOrder)) A_def = np.ones((ts_obj.numDate, 1), np.float32) for i in range(inps.polyOrder): Ai = np.array(tbase**(i+1) / gamma(i+2), np.float32).reshape(-1, 1) A_def = np.hstack((A_def, Ai)) # 2. Step function - 2D matrix in size of (numDate, len(inps.stepFuncDate)) if inps.stepFuncDate: print("temporal deformation model: step functions at "+str(inps.stepFuncDate)) t_steps = ptime.yyyymmdd2years(inps.stepFuncDate) t = np.array(ptime.yyyymmdd2years(ts_obj.dateList)) for t_step in t_steps: Ai = np.array(t > t_step, np.float32).reshape(-1, 1) A_def = np.hstack((A_def, Ai)) print('-'*80) return A_def
def read_exclude_date(inps, dateListAll): # Merge ex_date/startDate/endDate into ex_date yy_list_all = ptime.yyyymmdd2years(dateListAll) exDateList = [] # ex_date exDateList += ptime.read_date_list(list(inps.excludeDate), date_list_all=dateListAll) if exDateList: print('exclude date:' + str(exDateList)) # startDate if inps.startDate: print('start date: ' + inps.startDate) yy_min = ptime.yyyymmdd2years(ptime.yyyymmdd(inps.startDate)) for i in range(len(dateListAll)): date = dateListAll[i] if yy_list_all[i] < yy_min and date not in exDateList: print(' remove date: ' + date) exDateList.append(date) # endDate if inps.endDate: print('end date: ' + inps.endDate) yy_max = ptime.yyyymmdd2years(ptime.yyyymmdd(inps.endDate)) for i in range(len(dateListAll)): date = dateListAll[i] if yy_list_all[i] > yy_max and date not in exDateList: print(' remove date: ' + date) exDateList.append(date) exDateList = sorted(list(set(exDateList))) return exDateList
def read_inps2model(inps, date_list=None): """get model info from inps""" # check model date limits if not date_list: date_list = inps.dateList dmin, dmax = date_list[0], date_list[-1] ymin = ptime.yyyymmdd2years(dmin) ymax = ptime.yyyymmdd2years(dmax) if inps.step: for d_step in inps.step: y_step = ptime.yyyymmdd2years(d_step) if not (ymin < y_step < ymax): raise ValueError( f'input step date "{d_step}" exceed date list min/max: {dmin}, {dmax}' ) if inps.expDict: for d_onset in inps.expDict.keys(): y_onset = ptime.yyyymmdd2years(d_onset) if y_onset >= ymax: raise ValueError( f'input exp onset date "{d_onset}" >= the last date: {dmax}' ) if inps.logDict: for d_onset in inps.logDict.keys(): y_onset = ptime.yyyymmdd2years(d_onset) if y_onset >= ymax: raise ValueError( f'input log onset date "{d_onset}" >= the last date: {dmax}' ) model = dict() model['polynomial'] = inps.polynomial model['periodic'] = inps.periodic model['step'] = inps.step model['exp'] = inps.expDict model['log'] = inps.logDict # msg print( 'estimate deformation model with the following assumed time functions:' ) for key, value in model.items(): print(' {:<10} : {}'.format(key, value)) if 'polynomial' not in model.keys(): raise ValueError( 'linear/polynomial model is NOT included! Are you sure?!') # number of parameters num_param = (model['polynomial'] + 1 + len(model['periodic']) * 2 + len(model['step']) + sum([len(val) for key, val in model['exp'].items()]) + sum([len(val) for key, val in model['log'].items()])) return model, num_param
def get_design_matrix4step_func(date_list, step_date_list, seconds=0): """design matrix/function model of coseismic velocity estimation Parameters: date_list : list of dates in YYYYMMDD format step_date_list : Heaviside step function(s) with date in YYYYMMDD Returns: A : 2D array of zeros & ones in size of (num_date, num_step) """ num_date = len(date_list) num_step = len(step_date_list) A = np.zeros((num_date, num_step), dtype=np.float32) t = np.array(ptime.yyyymmdd2years(date_list, seconds=seconds)) t_steps = ptime.yyyymmdd2years(step_date_list) for i, t_step in enumerate(t_steps): A[:, i] = np.array(t > t_step).flatten() return A
def get_design_matrix4log_func(date_list, log_dict, seconds=0): """design matrix/function model of logarithmic postseismic relaxation estimation Reference: Eq. (4) in Hetland et al. (2012, JGR) Note that there is a typo in the paper for this equation, based on the MInTS code, it should be: Sum_i{ a_i * H(t-Ti) * [1 + log((t-T_i)/tau_i)] } instead of the one below shown in the paper: Sum_i{ a_i * H(t-Ti) * [1 + log((t)/tau_i)] } where: a_i amplitude of i-th log term T_i onset time of i-th log term tau_i char time of i-th log term (relaxation time) H(t-T_i) Heaviside func of i-th log term (ensuring the log func is one-sided) Parameters: date_list : list of dates in YYYYMMDD format log_dict : dict of log func(s) info as: {{onset_time1} : [{char_time11,...,char_time1N}], {onset_time2} : [{char_time21,...,char_time2N}], ... } where onset_time is string in YYYYMMDD format and char_time is float32 in decimal days Returns: A : 2D array of zeros & ones in size of (num_date, num_log) """ num_date = len(date_list) num_log = sum([len(log_dict[x]) for x in log_dict]) A = np.zeros((num_date, num_log), dtype=np.float32) t = np.array(ptime.yyyymmdd2years(date_list, seconds=seconds)) # loop for onset time(s) i = 0 for log_onset in log_dict.keys(): # convert string to float in years log_T = ptime.yyyymmdd2years(log_onset) # loop for charateristic time(s) for log_tau in log_dict[log_onset]: # convert time from days to years log_tau /= 365.25 olderr = np.seterr(invalid='ignore', divide='ignore') A[:, i] = np.array(t > log_T).flatten() * np.nan_to_num(np.log(1 + (t - log_T) / log_tau), nan=0, neginf=0) np.seterr(**olderr) i += 1 return A
def correct_local_oscilator_drift(fname, rg_dist_file=None, out_file=None): print('-'*50) print('correct Local Oscilator Drift for Envisat using an empirical model (Marinkovic and Larsen, 2013)') print('-'*50) atr = readfile.read_attribute(fname) # Check Sensor Type platform = atr['PLATFORM'] print('platform: '+platform) if not platform.lower() in ['env', 'envisat']: print('No need to correct LOD for '+platform) return # output file name if not out_file: out_file = '{}_LODcor{}'.format(os.path.splitext(fname)[0], os.path.splitext(fname)[1]) # Get LOD ramp rate from empirical model if not rg_dist_file: print('calculate range distance from file metadata') rg_dist = get_relative_range_distance(atr) else: print('read range distance from file: %s' % (rg_dist_file)) rg_dist = readfile.read(rg_dist_file, datasetName='slantRangeDistance', print_msg=False)[0] rg_dist -= rg_dist[int(atr['REF_Y']), int(atr['REF_X'])] ramp_rate = np.array(rg_dist * 3.87e-7, np.float32) # Correct LOD Ramp for Input fname range2phase = -4*np.pi / float(atr['WAVELENGTH']) k = atr['FILE_TYPE'] if k == 'timeseries': # read obj = timeseries(fname) obj.open() data = obj.read() # correct LOD diff_year = np.array(obj.yearList) diff_year -= diff_year[obj.refIndex] for i in range(data.shape[0]): data[i, :, :] -= ramp_rate * diff_year[i] # write obj_out = timeseries(out_file) obj_out.write2hdf5(data, refFile=fname) elif k in ['.unw']: data, atr = readfile.read(fname) dates = ptime.yyyymmdd2years(ptime.yyyymmdd(atr['DATE12'].split('-'))) dt = dates[1] - dates[0] data -= ramp_rate * range2phase * dt writefile.write(data, out_file=out_file, metadata=atr) else: print('No need to correct for LOD for %s file' % (k)) return out_file
def get_design_matrix4exp_func(date_list, exp_dict, seconds=0): """design matrix/function model of exponential postseismic relaxation estimation Reference: Eq. (5) in Hetland et al. (2012, JGR). Note that there is a typo in the paper for this equation, based on the MInTS code, it should be: Sum_i{ a_i * H(t-Ti) * [1 - e^(-(t-T_i)/tau_i)] } instead of the one below shown in the paper: Sum_i{ a_i * H(t-Ti) * [1 - e^(-(t)/tau_i)] } where: a_i amplitude of i-th exp term T_i onset time of i-th exp term tau_i char time of i-th exp term (relaxation time) H(t-T_i) Heaviside func of i-th exp term (ensuring the exp func is one-sided) Parameters: date_list : list of dates in YYYYMMDD format exp_dict : dict of exp func(s) info as: {{onset_time1} : [{char_time11,...,char_time1N}], {onset_time2} : [{char_time21,...,char_time2N}], ... } where onset_time is string in YYYYMMDD format and char_time is float32 in decimal days Returns: A : 2D array of zeros & ones in size of (num_date, num_exp) """ num_date = len(date_list) num_exp = sum([len(val) for key, val in exp_dict.items()]) A = np.zeros((num_date, num_exp), dtype=np.float32) t = np.array(ptime.yyyymmdd2years(date_list, seconds=seconds)) # loop for onset time(s) i = 0 for exp_onset in exp_dict.keys(): # convert string to float in years exp_T = ptime.yyyymmdd2years(exp_onset) # loop for charateristic time(s) for exp_tau in exp_dict[exp_onset]: # convert time from days to years exp_tau /= 365.25 A[:, i] = np.array(t > exp_T).flatten() * (1 - np.exp(-1 * (t - exp_T) / exp_tau)) i += 1 return A
def get_design_matrix4time_func(date_list, poly_order=2, step_func_dates=[]): """get design matrix for temporal deformation model""" # temporal baseline in the unit of years tbase = ptime.date_list2tbase(date_list)[0] tbase = np.array(tbase, dtype=np.float32) / 365.25 # 1. Polynomial - 2D matrix in size of (numDate, polyOrder+1) A_def = np.ones((len(date_list), 1), np.float32) for i in range(poly_order): Ai = np.array(tbase**(i + 1) / gamma(i + 2), np.float32).reshape(-1, 1) A_def = np.hstack((A_def, Ai)) # 2. Step function - 2D matrix in size of (numDate, len(step_func_dates)) if step_func_dates: t_steps = ptime.yyyymmdd2years(step_func_dates) t = np.array(ptime.yyyymmdd2years(date_list)) for t_step in t_steps: Ai = np.array(t > t_step, np.float32).reshape(-1, 1) A_def = np.hstack((A_def, Ai)) return A_def
def read_exclude_date(inps, dateListAll): # Merge ex_date/startDate/endDate into ex_date yy_list_all = ptime.yyyymmdd2years(dateListAll) exDateList = [] # 1. template_file if inps.template_file: print('read option from template file: ' + inps.template_file) inps = read_template2inps(inps.template_file, inps) # 2. ex_date exDateList += ptime.read_date_list(list(inps.excludeDate), date_list_all=dateListAll) if exDateList: print('exclude date:' + str(exDateList)) # 3. startDate if inps.startDate: print('start date: ' + inps.startDate) yy_min = ptime.yyyymmdd2years(ptime.yyyymmdd(inps.startDate)) for i in range(len(dateListAll)): date = dateListAll[i] if yy_list_all[i] < yy_min and date not in exDateList: print(' remove date: ' + date) exDateList.append(date) # 4. endDate if inps.endDate: print('end date: ' + inps.endDate) yy_max = ptime.yyyymmdd2years(ptime.yyyymmdd(inps.endDate)) for i in range(len(dateListAll)): date = dateListAll[i] if yy_list_all[i] > yy_max and date not in exDateList: print(' remove date: ' + date) exDateList.append(date) exDateList = list(set(exDateList)) return exDateList
def get_design_matrix4time_func(date_list, model=None, ref_date=None, seconds=0): """Design matrix (function model) for time functions parameter estimation. Parameters: date_list - list of str in YYYYMMDD format, size=num_date model - dict of time functions, e.g.: {'polynomial' : 2, # int, polynomial degree with 1 (linear), 2 (quadratic), 3 (cubic), etc. 'periodic' : [1.0, 0.5], # list of float, period(s) in years. 1.0 (annual), 0.5 (semiannual), etc. 'step' : ['20061014'], # list of str, date(s) in YYYYMMDD. 'exp' : {'20181026': [60], # dict, key for onset time in YYYYMMDD and value for char. times in days. ... }, 'log' : {'20161231': [80.5], # dict, key for onset time in YYYYMMDD and value for char. times in days. '20190125': [100, 200], ... }, ... } ref_date - reference date from date_list seconds - float or str, acquisition time of the day info in seconds. Returns: A - 2D array of design matrix in size of (num_date, num_param) num_param = (poly_deg + 1) + 2*len(periodic) + len(steps) + len(exp_taus) + len(log_taus) """ ## prepare time info # convert list of date into array of years in float yr_diff = np.array(ptime.yyyymmdd2years(date_list, seconds=seconds)) # reference date if ref_date is None: ref_date = date_list[0] yr_diff -= yr_diff[date_list.index(ref_date)] ## construct design matrix A # default model value if not model: model = {'polynomial' : 1} # read the models poly_deg = model.get('polynomial', 0) periods = model.get('periodic', []) steps = model.get('step', []) exps = model.get('exp', dict()) logs = model.get('log', dict()) num_period = len(periods) num_step = len(steps) num_exp = sum([len(val) for key, val in exps.items()]) num_log = sum([len(val) for key, val in logs.items()]) num_param = (poly_deg + 1) + (2 * num_period) + num_step + num_exp + num_log if num_param <= 1: raise ValueError('NO time functions specified!') # initialize the design matrix num_date = len(yr_diff) A = np.zeros((num_date, num_param), dtype=np.float32) c0 = 0 # update linear/polynomial term(s) # poly_deg of 0 --> offset # poly_deg of 1 --> velocity # ... c1 = c0 + poly_deg + 1 A[:, c0:c1] = get_design_matrix4polynomial_func(yr_diff, poly_deg) c0 = c1 # update periodic term(s) if num_period > 0: c1 = c0 + 2 * num_period A[:, c0:c1] = get_design_matrix4periodic_func(yr_diff, periods) c0 = c1 # update coseismic/step term(s) if num_step > 0: c1 = c0 + num_step A[:, c0:c1] = get_design_matrix4step_func(date_list, steps, seconds=seconds) c0 = c1 # update exponential term(s) if num_exp > 0: c1 = c0 + num_exp A[:, c0:c1] = get_design_matrix4exp_func(date_list, exps, seconds=seconds) c0 = c1 # update logarithmic term(s) if num_log > 0: c1 = c0 + num_log A[:, c0:c1] = get_design_matrix4log_func(date_list, logs, seconds=seconds) c0 = c1 return A