def __init__(self, z_object=None, z_array=None, z_err_array=None, freq=None, rot_z=0): #--> read in z_object if z_object is not None: if z_object.freq == None: raise AttributeError('z_object needs to have attrtibute'+\ 'freq filled') #--> make the z_object an attribute self._Z = z_object #--> if an array is input read it in and make it a z_object if z_array is not None: if freq is None: raise IOError('freq needs to be input') self._Z = mtz.Z(z_array, z_err_array) assert len(freq)==len(self._Z.z), \ 'length of freq is not the same as z' self._Z.freq = freq #--> rotate data if desired self.rotate(rot_z) # compute the invariants self.compute_invariants()
def __init__(self, fn=None, **kwargs): self._fn = fn self.station = kwargs.pop('station', None) self._lat = kwargs.pop('lat', None) self._lon = kwargs.pop('lon', None) self._elev = kwargs.pop('elev', None) self._Z = kwargs.pop('Z', MTz.Z()) self._Tipper = kwargs.pop('Tipper', MTz.Tipper()) self._utm_zone = kwargs.pop('utm_zone', None) self._east = kwargs.pop('east', None) self._north = kwargs.pop('north', None) self._rotation_angle = kwargs.pop('rotation_angle', 0) self.edi_object = MTedi.Edi() self.pt = None self.zinv = None self._utm_ellipsoid = 23 #provide key words to fill values if an edi file does not exist for key in kwargs.keys(): setattr(self, key, kwargs[key]) #--> read in the file name given if self._fn is not None: self._set_fn(fn)
def remove_distortion(z_array=None, z_object=None): if z_array is not None: z_obj = MTz.Z(z_array=z_array) elif z_object is not None: z_obj = z_object #0. generate a Z object #1. find distortion via function above, #2. remove distortion via method of z object dis, diserr = find_distortion(z_obj) try: distortion_tensor, zd, zd_err = z_obj.no_distortion(dis, distortion_err_tensor=diserr) distortion_z_obj = z_obj distortion_z_obj.z = zd distortion_z_obj.zerr = zd_err return distortion_tensor, distortion_z_obj except MTex.MTpyError_Z: print 'Could not compute distortion tensor' return np.identity(2), z_obj
def __init__(self, z_fn=None, **kwargs): # EgbertHeader.__init__(self, **kwargs) super(ZMM, self).__init__() self.z_fn = z_fn self._header_count = 0 self.Z = mtz.Z() self.Tipper = mtz.Tipper() self.transfer_functions = None self.sigma_e = None self.sigma_s = None self.period = None for key in list(kwargs.keys()): setattr(self, key, kwargs[key])
dfn = r"c:\Users\jpeacock\Documents\MountainPass\modem_inv\inv_08\mp_modem_data_z03_t05_topo.dat" mfn = r"c:\Users\jpeacock\Documents\MountainPass\modem_inv\inv_08\mp_sm02_topo.rho" occam1d_path = r"c:\MinGW32-xy\Peacock\occam\occam1d.exe" sv_dir = os.path.dirname(dfn) # ============================================================================= # read in data file and get mean and median of determinant # ============================================================================= d_obj = modem.Data() d_obj.read_data_file(dfn) rho = np.zeros((d_obj.data_array.shape[0], d_obj.period_list.shape[0])) phase = np.zeros_like(rho) for ii, d_arr in enumerate(d_obj.data_array): z_obj = mtz.Z(d_arr['z'], freq=1. / d_obj.period_list) rho[ii, :] = z_obj.res_det phase[ii, :] = z_obj.phase_det #mean_rho = np.apply_along_axis(lambda x: x[np.nonzero(x)].mean(), 0, rho) median_rho = np.apply_along_axis(lambda x: np.median(x[np.nonzero(x)]), 0, rho) median_rho[0] = 0 #mean_phase = np.apply_along_axis(lambda x: x[np.nonzero(x)].mean(), 0, phase) median_phase = np.apply_along_axis(lambda x: np.median(x[np.nonzero(x)]), 0, phase) median_phase[0] = 0 # make occam data file ocd = occam1d.Data() rp_tuple = (1. / d_obj.period_list, median_rho, median_rho * .05, median_phase, median_phase * .05) ocd.save_path = sv_dir
def interpolate(self, new_freq_array): """ interpolate the impedance tensor onto different frequencies. **Arguments** *new_freq_array* : np.ndarray a 1-d array of frequencies to interpolate on to. Must be with in the bounds of the existing frequency range, anything outside and an error will occur. **Returns** : *new_z_object* : mtpy.core.z.Z object a new impedance object with the corresponding frequencies and components. *new_tipper_object* : mtpy.core.z.Tipper object a new tipper object with the corresponding frequencies and components. :Example: :: >>> # make a new edi file for interpolated frequencies >>> import mtpy.core.mt as mt >>> edi_fn = r"/home/edi_files/mt_01.edi" >>> mt_obj = mt.MT(edi_fn) >>> # create a new frequency range to interpolate onto >>> new_freq = np.logspace(-3, 3, 24) >>> new_z_object, new_tipper_obj = mt_obj.interpolate(new_freq) >>> mt_obj.write_edi_file(new_fn=r"/home/edi_files/mt_01_interp.edi", >>> new_Z=new_z_object, >>> new_Tipper=new_tipper_object) """ # if the interpolation module has not been loaded return if interp_import is False: print('could not interpolate, need to install scipy') return #make sure the input is a numpy array if type(new_freq_array) != np.ndarray: new_freq_array = np.array(new_freq_array) # check the bounds of the new frequency array if self.Z.freq.min() > new_freq_array.min(): raise ValueError('New frequency minimum of {0:.5g}'.format(new_freq_array.min())+\ ' is smaller than old frequency minimum of {0:.5g}'.format(self.Z.freq.min())+\ '. The new frequency range needs to be within the '+\ 'bounds of the old one.') if self.Z.freq.max() < new_freq_array.max(): raise ValueError('New frequency maximum of {0:.5g}'.format(new_freq_array.max())+\ 'is smaller than old frequency maximum of {0:.5g}'.format(self.Z.freq.max())+\ '. The new frequency range needs to be within the '+\ 'bounds of the old one.') # make a new Z object new_Z = MTz.Z(z_array=np.zeros((new_freq_array.shape[0], 2, 2), dtype='complex'), zerr_array=np.zeros((new_freq_array.shape[0], 2, 2)), freq=new_freq_array) new_Tipper = MTz.Tipper(tipper_array=np.zeros((new_freq_array.shape[0], 1, 2), dtype='complex'), tippererr_array=np.zeros((new_freq_array.shape[0], 1, 2)), freq=new_freq_array) # interpolate the impedance tensor for ii in range(2): for jj in range(2): z_func_real = spi.interp1d(self.Z.freq, self.Z.z[:, ii, jj].real, kind='slinear') z_func_imag = spi.interp1d(self.Z.freq, self.Z.z[:, ii, jj].imag, kind='slinear') new_Z.z[:, ii, jj] = z_func_real(new_freq_array)+\ 1j*z_func_imag(new_freq_array) z_func_err = spi.interp1d(self.Z.freq, self.Z.zerr[:, ii, jj], kind='slinear') new_Z.zerr[:, ii, jj] = z_func_err(new_freq_array) # if there is not tipper than skip if self.Tipper.tipper is None: return new_Z, None # interpolate the Tipper for jj in range(2): t_func_real = spi.interp1d(self.Z.freq, self.Tipper.tipper[:, 0, jj].real, kind='slinear') t_func_imag = spi.interp1d(self.Z.freq, self.Tipper.tipper[:, 0, jj].imag, kind='slinear') new_Tipper.tipper[:, 0, jj] = t_func_real(new_freq_array)+\ 1j*t_func_imag(new_freq_array) t_func_err = spi.interp1d(self.Z.freq, self.Tipper.tippererr[:, 0, jj], kind='slinear') new_Tipper.tippererr[:, 0, jj] = t_func_err(new_freq_array) return new_Z, new_Tipper
def __init__(self, fn=None, **kwargs): self._fn = fn self.station = kwargs.pop('station', None) self._lat = kwargs.pop('lat', None) self._lon = kwargs.pop('lon', None) self._elev = kwargs.pop('elev', None) self._Z = kwargs.pop('Z', MTz.Z()) self._Tipper = kwargs.pop('Tipper', MTz.Tipper()) self._utm_zone = kwargs.pop('utm_zone', None) self._east = kwargs.pop('east', None) self._north = kwargs.pop('north', None) self._rotation_angle = kwargs.pop('rotation_angle', 0) self._data_type = kwargs.pop('data_type', 'z') #provide key words to fill values if an edi file does not exist if 'z_object' in kwargs: self._Z = kwargs['z_object'] if 'z_array' in kwargs: self._Z.z = kwargs['z_array'] if 'zerr_array' in kwargs: self._Z.zerr = kwargs['zerr_array'] if 'freq' in kwargs: self._Z.freq = kwargs['freq'] self._Tipper.freq = kwargs['freq'] if 'tipper_object' in kwargs: self._Tipper = kwargs['tipper_object'] if 'tipper' in kwargs: self._Tipper.tipper = kwargs['tipper'] if 'tippererr' in kwargs: self._Tipper.tippererr = kwargs['tippererr'] if 'resisitivity' in kwargs: self._Z.resistivity = kwargs['resistivity'] if 'resisitivity_err' in kwargs: self._Z.resistivity_err = kwargs['resistivity_err'] if 'phase' in kwargs: self._Z.phase = kwargs['phase'] if 'phase_err' in kwargs: self._Z.phase = kwargs['phase_err'] self.edi_object = MTedi.Edi() self.pt = None self.zinv = None self._utm_ellipsoid = 23 #--> read in the edi file if its given if self._fn is not None: if self._fn[-3:] == 'edi': self._read_edi_file() else: not_fn = self._fn[os.path.basename(self._fn).find['.']:] raise MTex.MTpyError_file_handling('File '+\ 'type {0} not supported yet.'.format(not_fn))
def find_distortion(z_object, g='det', num_freq=None, lo_dims=None): """ find optimal distortion tensor from z object automatically determine the dimensionality over all frequencies, then find the appropriate distortion tensor D Parameters ---------- **z_object** : mtpy.core.z object **g** : [ 'det' | '01' | '10 ] type of distortion correction *default* is 'det' **num_freq** : int number of frequencies to look for distortion from the index 0 *default* is None, meaning all frequencies are used **lo_dims** : list list of dimensions for each frequency *default* is None, meaning calculated from data Returns ------- **distortion** : np.ndarray(2, 2) distortion array all real values **distortion_err** : np.ndarray(2, 2) distortion error array Examples -------- :Estimate Distortion: :: >>> import mtpy.analysis.distortion as distortion >>> dis, dis_err = distortion.find_distortion(z_obj, num_freq=12) """ if num_freq is not None: if num_freq > z_object.freq.size: num_freq = z_object.freq.size print('Number of frequencies to sweep over is too high for z') print('setting num_freq to {0}'.format(num_freq)) else: num_freq = z_object.freq.size z_obj = MTz.Z(z_object.z[0:num_freq], z_object.z_err[0:num_freq], z_object.freq[0:num_freq]) g = 'det' dim_arr = MTge.dimensionality(z_object=z_obj) st_arr = -1 * MTge.strike_angle(z_object=z_obj)[:, 0] dis = np.zeros_like(z_obj.z, dtype=np.float) dis_err = np.ones_like(z_obj.z, dtype=np.float) #dictionary of values that should be no distortion in case distortion #cannot be calculated for that component rot_mat = np.matrix([[0, -1], [1, 0]]) for idx, dim in enumerate(dim_arr): if np.any(z_obj.z[idx] == 0.0 + 0.0j) == True: dis[idx] = np.identity(2) print('Found a zero in z at {0}, skipping'.format(idx)) continue if dim == 1: if g in ['01', '10']: gr = np.abs(z_obj.z.real[idx, int(g[0]), int(g[1])]) gi = np.abs(z_obj.z.imag[idx, int(g[0]), int(g[1])]) else: gr = np.sqrt(np.linalg.det(z_obj.z.real[idx])) gi = np.sqrt(np.linalg.det(z_obj.z.imag[idx])) dis[idx] = np.mean(np.array([ (1. / gr * np.dot(z_obj.z.real[idx], rot_mat)), (1. / gi * np.dot(z_obj.z.imag[idx], rot_mat)) ]), axis=0) if z_obj.z_err is not None: # find errors of entries for calculating weights gr_err = 1. / gr * np.abs(z_obj.z_err[idx]) gr_err[np.where(gr_err == 0.0)] = 1.0 gi_err = 1. / gi * np.abs(z_obj.z_err[idx]) gi_err[np.where(gi_err == 0.0)] = 1.0 dis_err[idx] = np.mean(np.array([gi_err, gr_err]), axis=0) elif dim == 2: P = 1 strike_ang = st_arr[idx] if np.isnan(strike_ang): strike_ang = 0.0 if z_obj.z_err is not None: err_arr = z_obj.z_err[idx] err_arr[np.where(err_arr == 0.0)] = 1.0 else: err_arr = None tetm_arr, tetm_err = MTcc.rotatematrix_incl_errors( z_obj.z[idx], strike_ang, inmatrix_err=err_arr) tetm_r = tetm_arr.real tetm_i = tetm_arr.imag t_arr_r = -4 * P * tetm_r[0, 1] * tetm_r[1, 0] / np.linalg.det(tetm_r) t_arr_i = -4 * P * tetm_i[0, 1] * tetm_i[1, 0] / np.linalg.det(tetm_i) try: T = np.sqrt(max([t_arr_r, t_arr_i])) + .001 except ValueError: T = 2 sr = np.sqrt(T**2 + 4 * P * tetm_r[0, 1] * tetm_r[1, 0] / np.linalg.det(tetm_r)) si = np.sqrt(T**2 + 4 * P * tetm_i[0, 1] * tetm_i[1, 0] / np.linalg.det(tetm_i)) par_r = 2 * tetm_r[0, 1] / (T - sr) orth_r = 2 * tetm_r[1, 0] / (T + sr) par_i = 2 * tetm_i[0, 1] / (T - si) orth_i = 2 * tetm_i[1, 0] / (T + si) mat2_r = np.matrix([[0, 1. / orth_r], [1. / par_r, 0]]) mat2_i = np.matrix([[0, 1. / orth_i], [1. / par_i, 0]]) avg_mat = np.mean(np.array( [np.dot(tetm_r, mat2_r), np.dot(tetm_i, mat2_i)]), axis=0) dis[idx] = avg_mat if err_arr is not None: # find errors of entries for calculating weights sigma_sr = np.sqrt((-(2 * P * tetm_r[0, 1] * tetm_r[1, 0] * \ tetm_r[1, 1] * err_arr[0, 0]) / \ (np.linalg.det(tetm_r) ** 2 * sr)) ** 2 + \ ((2 * P * tetm_r[0, 0] * tetm_r[1, 0] * tetm_r[1, 1] * err_arr[0, 1]) / (np.linalg.det(tetm_r) ** 2 * sr)) ** 2 + \ ((2 * P * tetm_r[0, 0] * tetm_r[0, 1] * tetm_r[1, 1] * err_arr[1, 0]) / \ (np.linalg.det(tetm_r) ** 2 * sr)) ** 2 + \ (-(2 * P * tetm_r[0, 1] * tetm_r[1, 0] * \ tetm_r[0, 0] * err_arr[1, 1]) / \ (np.linalg.det(tetm_r) ** 2 * sr)) ** 2) sigma_dr_11 = 0.5 * sigma_sr sigma_dr_22 = 0.5 * sigma_sr sigma_dr_12 = np.sqrt((mat2_r[0, 1] / tetm_r[0, 0] * err_arr[0, 0]) ** 2 + \ (mat2_r[0, 1] / tetm_r[1, 0] * err_arr[1, 0]) ** 2 + \ (0.5 * tetm_r[0, 0] / tetm_r[1, 0] * sigma_sr) ** 2) sigma_dr_21 = np.sqrt((mat2_r[1, 0] / tetm_r[1, 1] * err_arr[1, 1]) ** 2 + \ (mat2_r[1, 0] / tetm_r[0, 1] * err_arr[0, 1]) ** 2 + \ (0.5 * tetm_r[1, 1] / tetm_r[0, 1] * sigma_sr) ** 2) dis_err_r = np.array([[sigma_dr_11, sigma_dr_12], [sigma_dr_21, sigma_dr_22]]) sigma_si = np.sqrt((-(2 * P * tetm_i[0, 1] * tetm_i[1, 0] * \ tetm_i[1, 1] * err_arr[0, 0]) / \ (np.linalg.det(tetm_i) ** 2 * sr)) ** 2 + \ ((2 * P * tetm_i[0, 0] * tetm_i[1, 0] * \ tetm_i[1, 1] * err_arr[0, 1]) / \ (np.linalg.det(tetm_i) ** 2 * sr)) ** 2 + \ ((2 * P * tetm_i[0, 0] * tetm_i[0, 1] * \ tetm_i[1, 1] * err_arr[1, 0]) / \ (np.linalg.det(tetm_i) ** 2 * sr)) ** 2 + \ (-(2 * P * tetm_i[0, 1] * tetm_i[1, 0] * \ tetm_i[0, 0] * err_arr[1, 1]) / \ (np.linalg.det(tetm_i) ** 2 * sr)) ** 2) sigma_di_11 = 0.5 * sigma_si sigma_di_22 = 0.5 * sigma_si sigma_di_12 = np.sqrt((mat2_i[0, 1] / tetm_i[0, 0] * err_arr[0, 0]) ** 2 + \ (mat2_i[0, 1] / tetm_i[1, 0] * err_arr[1, 0]) ** 2 + \ (0.5 * tetm_i[0, 0] / tetm_i[1, 0] * sigma_si) ** 2) sigma_di_21 = np.sqrt((mat2_i[1, 0] / tetm_i[1, 1] * err_arr[1, 1]) ** 2 + \ (mat2_i[1, 0] / tetm_i[0, 1] * err_arr[0, 1]) ** 2 + \ (0.5 * tetm_i[1, 1] / tetm_i[0, 1] * sigma_si) ** 2) dis_err_i = np.array([[sigma_di_11, sigma_di_12], [sigma_di_21, sigma_di_22]]) dis_err[idx] = np.mean(np.array([dis_err_r, dis_err_i])) else: dis[idx] = np.identity(2) nonzero_idx = np.array(list(set(np.nonzero(dis)[0]))) dis_avg, weights_sum = np.average(dis[nonzero_idx], axis=0, weights=(1. / dis_err[nonzero_idx])**2, returned=True) dis_avg_err = np.sqrt(1. / weights_sum) return dis_avg, dis_avg_err
def plot(self): """ plot the data """ if self.station is None: return s_index = np.where(self.ws_data.data['station'] == self.station)[0][0] z_obj = mtz.Z(self.ws_data.data[s_index]['z_data'], self.ws_data.data[s_index]['z_data_err']*\ self.ws_data.data[s_index]['z_err_map'], 1./self.ws_data.period_list) period = self.ws_data.period_list # need to make sure that resistivity and phase is computed z_obj._compute_res_phase() plt.rcParams['font.size'] = self.plot_settings.fs fontdict = {'size': self.plot_settings.fs + 2, 'weight': 'bold'} #--> make key word dictionaries for plotting kw_xx = { 'color': self.plot_settings.cted, 'marker': self.plot_settings.mted, 'ms': self.plot_settings.ms, 'ls': ':', 'lw': self.plot_settings.lw, 'e_capsize': self.plot_settings.e_capsize, 'e_capthick': self.plot_settings.e_capthick, 'picker': 3 } kw_yy = { 'color': self.plot_settings.ctmd, 'marker': self.plot_settings.mtmd, 'ms': self.plot_settings.ms, 'ls': ':', 'lw': self.plot_settings.lw, 'e_capsize': self.plot_settings.e_capsize, 'e_capthick': self.plot_settings.e_capthick, 'picker': 3 } #convert to apparent resistivity and phase if self.plot_z == True: scaling = np.zeros_like(z_obj.z) for ii in range(2): for jj in range(2): scaling[:, ii, jj] = 1. / np.sqrt(z_obj.freq) plot_res = abs(z_obj.z.real * scaling) plot_res_err = abs(z_obj.z_err * scaling) plot_phase = abs(z_obj.z.imag * scaling) plot_phase_err = abs(z_obj.z_err * scaling) h_ratio = [1, 1] elif self.plot_z == False: plot_res = z_obj.resistivity plot_res_err = z_obj.resistivity_err plot_phase = z_obj.phase plot_phase_err = z_obj.phase_err h_ratio = [2, 1] #find locations where points have been masked nzxx = np.nonzero(z_obj.z[:, 0, 0])[0] nzxy = np.nonzero(z_obj.z[:, 0, 1])[0] nzyx = np.nonzero(z_obj.z[:, 1, 0])[0] nzyy = np.nonzero(z_obj.z[:, 1, 1])[0] self.figure.clf() self.figure.suptitle(str(self.station), fontdict=fontdict) #set the grid of subplots gs = gridspec.GridSpec(2, 4, height_ratios=h_ratio) gs.update(wspace=self.plot_settings.subplot_wspace, left=self.plot_settings.subplot_left, top=self.plot_settings.subplot_top, bottom=self.plot_settings.subplot_bottom, right=self.plot_settings.subplot_right, hspace=self.plot_settings.subplot_hspace) axrxx = self.figure.add_subplot(gs[0, 0]) axrxy = self.figure.add_subplot(gs[0, 1], sharex=axrxx) axryx = self.figure.add_subplot(gs[0, 2], sharex=axrxx) axryy = self.figure.add_subplot(gs[0, 3], sharex=axrxx) axpxx = self.figure.add_subplot(gs[1, 0]) axpxy = self.figure.add_subplot(gs[1, 1], sharex=axrxx) axpyx = self.figure.add_subplot(gs[1, 2], sharex=axrxx) axpyy = self.figure.add_subplot(gs[1, 3], sharex=axrxx) self.ax_list = [axrxx, axrxy, axryx, axryy, axpxx, axpxy, axpyx, axpyy] # plot data response erxx = mtplottools.plot_errorbar(axrxx, period[nzxx], plot_res[nzxx, 0, 0], plot_res_err[nzxx, 0, 0], **kw_xx) erxy = mtplottools.plot_errorbar(axrxy, period[nzxy], plot_res[nzxy, 0, 1], plot_res_err[nzxy, 0, 1], **kw_xx) eryx = mtplottools.plot_errorbar(axryx, period[nzyx], plot_res[nzyx, 1, 0], plot_res_err[nzyx, 1, 0], **kw_yy) eryy = mtplottools.plot_errorbar(axryy, period[nzyy], plot_res[nzyy, 1, 1], plot_res_err[nzyy, 1, 1], **kw_yy) #plot phase epxx = mtplottools.plot_errorbar(axpxx, period[nzxx], plot_phase[nzxx, 0, 0], plot_phase_err[nzxx, 0, 0], **kw_xx) epxy = mtplottools.plot_errorbar(axpxy, period[nzxy], plot_phase[nzxy, 0, 1], plot_phase_err[nzxy, 0, 1], **kw_xx) epyx = mtplottools.plot_errorbar(axpyx, period[nzyx], plot_phase[nzyx, 1, 0], plot_phase_err[nzyx, 1, 0], **kw_yy) epyy = mtplottools.plot_errorbar(axpyy, period[nzyy], plot_phase[nzyy, 1, 1], plot_phase_err[nzyy, 1, 1], **kw_yy) #---------------------------------------------- # get error bar list for editing later self._err_list = [[erxx[1][0], erxx[1][1], erxx[2][0]], [erxy[1][0], erxy[1][1], erxy[2][0]], [eryx[1][0], eryx[1][1], eryx[2][0]], [eryy[1][0], eryy[1][1], eryy[2][0]]] line_list = [[erxx[0]], [erxy[0]], [eryx[0]], [eryy[0]]] #------------------------------------------ # make things look nice # set titles of the Z components label_list = [['$Z_{xx}$'], ['$Z_{xy}$'], ['$Z_{yx}$'], ['$Z_{yy}$']] for ax, label in zip(self.ax_list[0:4], label_list): ax.set_title(label[0], fontdict={ 'size': self.plot_settings.fs + 2, 'weight': 'bold' }) #--> set limits if input if self.plot_settings.res_xx_limits is not None: axrxx.set_ylim(self.plot_settings.res_xx_limits) if self.plot_settings.res_xy_limits is not None: axrxy.set_ylim(self.plot_settings.res_xy_limits) if self.plot_settings.res_yx_limits is not None: axryx.set_ylim(self.plot_settings.res_yx_limits) if self.plot_settings.res_yy_limits is not None: axryy.set_ylim(self.plot_settings.res_yy_limits) if self.plot_settings.phase_xx_limits is not None: axpxx.set_ylim(self.plot_settings.phase_xx_limits) if self.plot_settings.phase_xy_limits is not None: axpxy.set_ylim(self.plot_settings.phase_xy_limits) if self.plot_settings.phase_yx_limits is not None: axpyx.set_ylim(self.plot_settings.phase_yx_limits) if self.plot_settings.phase_yy_limits is not None: axpyy.set_ylim(self.plot_settings.phase_yy_limits) #set axis properties for aa, ax in enumerate(self.ax_list): ax.tick_params(axis='y', pad=self.plot_settings.ylabel_pad) ylabels = ax.get_yticks().tolist() if aa < 4: ylabels[-1] = '' ylabels[0] = '' ax.set_yticklabels(ylabels) plt.setp(ax.get_xticklabels(), visible=False) if self.plot_z == True: ax.set_yscale('log') else: ax.set_xlabel('Period (s)', fontdict=fontdict) if aa < 4 and self.plot_z is False: ax.set_yscale('log') #set axes labels if aa == 0: if self.plot_z == False: ax.set_ylabel('App. Res. ($\mathbf{\Omega \cdot m}$)', fontdict=fontdict) elif self.plot_z == True: ax.set_ylabel('Re[Z (mV/km nT)]', fontdict=fontdict) elif aa == 4: if self.plot_z == False: ax.set_ylabel('Phase (deg)', fontdict=fontdict) elif self.plot_z == True: ax.set_ylabel('Im[Z (mV/km nT)]', fontdict=fontdict) ax.set_xscale('log') ax.set_xlim(xmin=10**(np.floor(np.log10(period[0]))) * 1.01, xmax=10**(np.ceil(np.log10(period[-1]))) * .99) ax.grid(True, alpha=.25) ##---------------------------------------------- #plot model response if self.ws_resp is not None: s_index = np.where( self.ws_resp.resp['station'] == self.station)[0][0] resp_z_obj = mtz.Z(self.ws_resp.resp[s_index]['z_resp'], None, 1. / self.ws_resp.period_list) resp_z_err = np.nan_to_num((z_obj.z - resp_z_obj.z) / z_obj.z_err) resp_z_obj._compute_res_phase() #convert to apparent resistivity and phase if self.plot_z == True: scaling = np.zeros_like(resp_z_obj.z) for ii in range(2): for jj in range(2): scaling[:, ii, jj] = 1. / np.sqrt(resp_z_obj.freq) r_plot_res = abs(resp_z_obj.z.real * scaling) r_plot_phase = abs(resp_z_obj.z.imag * scaling) elif self.plot_z == False: r_plot_res = resp_z_obj.resistivity r_plot_phase = resp_z_obj.phase rms_xx = resp_z_err[:, 0, 0].std() rms_xy = resp_z_err[:, 0, 1].std() rms_yx = resp_z_err[:, 1, 0].std() rms_yy = resp_z_err[:, 1, 1].std() #--> make key word dictionaries for plotting kw_xx = { 'color': self.plot_settings.ctem, 'marker': self.plot_settings.mtem, 'ms': self.plot_settings.ms, 'ls': ':', 'lw': self.plot_settings.lw, 'e_capsize': self.plot_settings.e_capsize, 'e_capthick': self.plot_settings.e_capthick } kw_yy = { 'color': self.plot_settings.ctmm, 'marker': self.plot_settings.mtmm, 'ms': self.plot_settings.ms, 'ls': ':', 'lw': self.plot_settings.lw, 'e_capsize': self.plot_settings.e_capsize, 'e_capthick': self.plot_settings.e_capthick } # plot data response rerxx = mtplottools.plot_errorbar(axrxx, period[nzxx], r_plot_res[nzxx, 0, 0], None, **kw_xx) rerxy = mtplottools.plot_errorbar(axrxy, period[nzxy], r_plot_res[nzxy, 0, 1], None, **kw_xx) reryx = mtplottools.plot_errorbar(axryx, period[nzyx], r_plot_res[nzyx, 1, 0], None, **kw_yy) reryy = mtplottools.plot_errorbar(axryy, period[nzyy], r_plot_res[nzyy, 1, 1], None, **kw_yy) #plot phase repxx = mtplottools.plot_errorbar(axpxx, period[nzxx], r_plot_phase[nzxx, 0, 0], None, **kw_xx) repxy = mtplottools.plot_errorbar(axpxy, period[nzxy], r_plot_phase[nzxy, 0, 1], None, **kw_xx) repyx = mtplottools.plot_errorbar(axpyx, period[nzyx], r_plot_phase[nzyx, 1, 0], None, **kw_yy) repyy = mtplottools.plot_errorbar(axpyy, period[nzyy], r_plot_phase[nzyy, 1, 1], None, **kw_yy) # add labels to legends line_list[0] += [rerxx[0]] line_list[1] += [rerxy[0]] line_list[2] += [reryx[0]] line_list[3] += [reryy[0]] label_list[0] += ['$Z^m_{xx}$ ' + 'rms={0:.2f}'.format(rms_xx)] label_list[1] += ['$Z^m_{xy}$ ' + 'rms={0:.2f}'.format(rms_xy)] label_list[2] += ['$Z^m_{yx}$ ' + 'rms={0:.2f}'.format(rms_yx)] label_list[3] += ['$Z^m_{yy}$ ' + 'rms={0:.2f}'.format(rms_yy)] legend_ax_list = self.ax_list[0:4] for aa, ax in enumerate(legend_ax_list): ax.legend( line_list[aa], label_list[aa], loc=self.plot_settings.legend_loc, bbox_to_anchor=self.plot_settings.legend_pos, markerscale=self.plot_settings.legend_marker_scale, borderaxespad=self.plot_settings.legend_border_axes_pad, labelspacing=self.plot_settings.legend_label_spacing, handletextpad=self.plot_settings.legend_handle_text_pad, borderpad=self.plot_settings.legend_border_pad, prop={'size': max([self.plot_settings.fs, 5])}) self.mpl_widget.draw()
jj, kk = index_dict[ii] try: zr, zi = zz.split("+") zi = zi.replace("i", "") except ValueError: zr = zz zi = 0 if ii < 4: z[mm, jj, kk] = float(zr) - 1j * float(zi) else: err[mm, jj, kk] = np.sqrt(np.abs(float(zr) + 1j * float(zi))) z[:, 1, 0] *= -1 z[:, 0, 1] *= 796 z[:, 1, 0] *= 796 return z, err for txt_fn in fn_path.glob("*.txt"): # if 's22' not in txt_fn.name: # continue zmm_fn = txt_fn.with_suffix(".zmm") if zmm_fn.exists(): m_obj = mt.MT(zmm_fn) new_z, new_err = read_txt(txt_fn) m_obj.Z = z.Z(new_z, new_err, np.array(f_list)) m_obj.write_mt_file(fn_basename="{0}_uc".format(m_obj.station)) else: print("ERROR: No zmm file {0}".format(zmm_fn))
def calculate_depth_nb(z_object = None, z_array = None, periods = None): """ Determine an array of Z_nb (depth dependent Niblett-Bostick transformed Z) from the 1D and 2D parts of an impedance tensor array Z. The calculation of the Z_nb needs 6 steps: 1) Determine the dimensionality of the Z(T), discard all 3D parts 2) Rotate all Z(T) to TE/TM setup (T_parallel/T_ortho) 3) Transform every component individually by Niblett-Bostick 4) collect the respective 2 components each for equal/similar depths 5) interprete them as TE_nb/TM_nb 6) set up Z_nb(depth) If 1D layers occur inbetween 2D layers, the strike angle is undefined therein. We take an - arbitrarily chosen - linear interpolation of strike angle for these layers, with the values varying between the angles of the bounding upper and lower 2D layers (linearly w.r.t. the periods). Use the output for instance for the determination of NB-transformed phase tensors. Note: No propagation of errors implemented yet! Arguments ------------- *z_object* : mtpy.core.z object *z_array* : np.ndarray [num_periods, 2, 2] *periods* : np.ndarray(num_periods) only input if input z_array, otherwise periods are extracted from z_object.freq Returns ------------------ *depth_array* : np.ndarray(num_periods, dtype=['period', 'depth_min', 'depth_max', 'rho_min', 'rho_max']) numpy structured array with keywords. - period --> period in s - depth_min --> minimum depth estimated (m) - depth_max --> maximum depth estimated (m) - rho_min --> minimum resistivity estimated (Ohm-m) - rho_max --> maximum resistivity estimated (Ohm-m) Example ------------ >>> import mtpy.analysis.niblettbostick as nb >>> depth_array = nb.calculate_znb(z_object=z1) >>> # plot the results >>> import matplotlib.pyplot as plt >>> fig = plt.figure() >>> ax = fig.add_subplot(1,1,1) >>> ax.semilogy(depth_array['depth_min'], depth_array['period']) >>> ax.semilogy(depth_array['depth_max'], depth_array['period']) >>> plt.show() """ #deal with inputs if z_object is not None: z_obj = z_object periods = 1./z_object.freq else: z_obj = MTz.Z(z_array=z_array, freq=1./periods) periods = periods dimensions = MTge.dimensionality(z_array=z_obj.z) angles = MTge.strike_angle(z_array=z_obj.z) #reduce actual Z by the 3D layers: # z_2d = z[np.where(dimensions != 3)[0]] angles_2d = np.nan_to_num(angles[np.where(dimensions != 3)][:, 0]) periods_2d = periods[np.where(dimensions != 3)] # interperpolate strike angle onto all periods # make a function for strike using only 2d angles strike_interp = spi.interp1d(periods_2d, angles_2d, bounds_error=False, fill_value=0) strike_angles = strike_interp(periods) # rotate z to be along the interpolated strike angles z_obj.rotate(strike_angles) # angles_incl1D = interpolate_strike_angles(angles_2d, periods_2d) # z3 = MTz.rotate_z(z_2d, -angles_incl1D)[0] #at this point we assume that the two modes are the off-diagonal elements!! #TE is element (1,2), TM at (2,1) # lo_nb_max = [] # lo_nb_min = [] depth_array = np.zeros(periods.shape[0], dtype=[('period', np.float), ('depth_min', np.float), ('depth_max', np.float), ('rho_min', np.float), ('rho_max', np.float)]) ## app_res, app_res_err, phase, phase_err = MTz.z2resphi(z3, periods_2d) # app_res, app_res_err, phase, phase_err = MTz.z2resphi(z_rot, periods) for ii, per in enumerate(periods): te_rho, te_depth = rhophi2rhodepth(z_obj.resistivity[ii, 0, 1], z_obj.phase[ii, 0, 1], per) tm_rho, tm_depth = rhophi2rhodepth(z_obj.resistivity[ii, 1, 0], z_obj.phase[ii, 1, 0], per) depth_array[ii]['period'] = per depth_array[ii]['depth_min'] = min([te_depth, tm_depth]) depth_array[ii]['depth_max'] = max([te_depth, tm_depth]) depth_array[ii]['rho_min'] = min([te_rho, tm_rho]) depth_array[ii]['rho_max'] = max([te_rho, tm_rho]) return depth_array
if f_index == nf: data_list.append({ 'name': name, 'res': res, 'phase': phase, 'res_err': res_err, 'phase_err': phase, 'tipper': tipper, 'tipper_err': tipper_err }) print 'Station = {0}, no. freq = {1}'.format(name, nf) #write edi file data_edi = mtedi.Edi() data_z = mtz.Z() data_z.freq = frequency data_z.set_res_phase(res, phase, reserr_array=res_err, phaseerr_array=phase_err) data_T = mtz.Tipper(tipper_array=tipper, tippererr_array=tipper_err) data_T.freq = frequency data_edi.Z = data_z data_edi.Tipper = data_T #---------------HEADER---------------------------------------------- data_edi.head = dict([('dataid', name), ('acqby', 'P. E. Wannamaker'), ('fileby', 'P.E. Wannamaker'),
def read_j_file(self, j_fn=None): """ read_j_file will read in a *.j file output by BIRRP (better than reading lots of *.<k>r<l>.rf files) Input: j-filename Output: 4-tuple - periods : N-array - Z_array : 2-tuple - values and errors - tipper_array : 2-tuple - values and errors - processing_dict : parsed processing parameters from j-file header """ # read data z_index_dict = { 'zxx': (0, 0), 'zxy': (0, 1), 'zyx': (1, 0), 'zyy': (1, 1) } t_index_dict = {'tzx': (0, 0), 'tzy': (0, 1)} if j_fn is not None: self.j_fn = j_fn print('--> Reading {0}'.format(self.j_fn)) j_line_list = self._validate_j_file() self.read_header(j_lines=j_line_list) self.read_metadata(j_lines=j_line_list) data_lines = [ j_line for j_line in j_line_list if not '>' in j_line and not '#' in j_line ][1:] # sometimes birrp outputs some missing periods, so the best way to deal with # this that I could come up with was to get things into dictionaries with # key words that are the period values, then fill in Z and T from there # leaving any missing values as 0 # make empty dictionary that have keys as the component z_dict = dict([(z_key, {}) for z_key in list(z_index_dict.keys())]) t_dict = dict([(t_key, {}) for t_key in list(t_index_dict.keys())]) for d_line in data_lines: # check to see if we are at the beginning of a component block, if so # set the dictionary key to that value if 'z' in d_line.lower(): d_key = d_line.strip().split()[0].lower() # if we are at the number of periods line, skip it elif len( d_line.strip().split()) == 1 and 'r' not in d_line.lower(): continue elif 'r' in d_line.lower(): break # get the numbers into the correct dictionary with a key as period and # for now we will leave the numbers as a list, which we will parse later else: # split the line up into each number d_list = d_line.strip().split() # make a copy of the list to be sure we don't rewrite any values, # not sure if this is necessary at the moment d_value_list = list(d_list) for d_index, d_value in enumerate(d_list): # check to see if the column number can be converted into a float # if it can't, then it will be set to 0, which is assumed to be # a masked number when writing to an .edi file try: d_value = float(d_value) # need to check for masked points represented by # birrp as -999, apparently if d_value == -999 or np.isnan(d_value): d_value_list[d_index] = 0.0 else: d_value_list[d_index] = d_value except ValueError: d_value_list[d_index] = 0.0 # put the numbers in the correct dictionary as: # key = period, value = [real, imaginary, error] if d_key in list(z_index_dict.keys()): z_dict[d_key][d_value_list[0]] = d_value_list[1:4] elif d_key in list(t_index_dict.keys()): t_dict[d_key][d_value_list[0]] = d_value_list[1:4] # --> now we need to get the set of periods for all components # check to see if there is any tipper data output all_periods = [] for z_key in list(z_index_dict.keys()): for f_key in list(z_dict[z_key].keys()): all_periods.append(f_key) if len(list(t_dict['tzx'].keys())) == 0: print('Could not find any Tipper data in {0}'.format(self.j_fn)) find_tipper = False else: for t_key in list(t_index_dict.keys()): for f_key in list(t_dict[t_key].keys()): all_periods.append(f_key) find_tipper = True all_periods = np.array(sorted(list(set(all_periods)))) all_periods = all_periods[np.nonzero(all_periods)] num_per = len(all_periods) # fill arrays using the period key from all_periods z_arr = np.zeros((num_per, 2, 2), dtype=np.complex) z_err_arr = np.zeros((num_per, 2, 2), dtype=np.float) t_arr = np.zeros((num_per, 1, 2), dtype=np.complex) t_err_arr = np.zeros((num_per, 1, 2), dtype=np.float) for p_index, per in enumerate(all_periods): for z_key in sorted(z_index_dict.keys()): kk = z_index_dict[z_key][0] ll = z_index_dict[z_key][1] try: z_value = z_dict[z_key][per][0] + 1j * z_dict[z_key][per][1] z_arr[p_index, kk, ll] = z_value z_err_arr[p_index, kk, ll] = z_dict[z_key][per][2] except KeyError: print('No value found for period {0:.4g}'.format(per)) print('For component {0}'.format(z_key)) if find_tipper is True: for t_key in sorted(t_index_dict.keys()): kk = t_index_dict[t_key][0] ll = t_index_dict[t_key][1] try: t_value = t_dict[t_key][per][ 0] + 1j * t_dict[t_key][per][1] t_arr[p_index, kk, ll] = t_value t_err_arr[p_index, kk, ll] = t_dict[t_key][per][2] except KeyError: print('No value found for period {0:.4g}'.format(per)) print('For component {0}'.format(t_key)) # put the results into mtpy objects freq = 1. / all_periods z_arr[np.where(z_arr == np.inf)] = 0 + 0j t_arr[np.where(t_arr == np.inf)] = 0 + 0j z_err_arr[np.where(z_err_arr == np.inf)] = 10**6 t_err_arr[np.where(t_err_arr == np.inf)] = 10**6 self.Z = mtz.Z(z_arr, z_err_arr, freq) self.Tipper = mtz.Tipper(t_arr, t_err_arr, freq)
def calculate_impedance(self, angle=0.): """ calculate the impedances from the transfer functions """ # check to see if there are actually electric fields in the TFs if not hasattr(self, 'ex') or not hasattr(self, 'ey'): raise ZMMError("Cannot return apparent resistivity and phase " "data because these TFs do not contain electric " "fields as a predicted channel.") # transform the TFs first... # build transformation matrix for predictor channels # (horizontal magnetic fields) hx_index = self.hx.index hy_index = self.hy.index u = np.eye(2, 2) u[hx_index, hx_index] = np.cos(np.deg2rad(self.hx.azimuth - angle)) u[hx_index, hy_index] = np.sin(np.deg2rad(self.hx.azimuth - angle)) u[hy_index, hx_index] = np.cos(np.deg2rad(self.hy.azimuth - angle)) u[hy_index, hy_index] = np.sin(np.deg2rad(self.hy.azimuth - angle)) u = np.linalg.inv(u) # build transformation matrix for predicted channels (electric fields) ex_index = self.ex.index ey_index = self.ey.index v = np.eye(self.transfer_functions.shape[1], self.transfer_functions.shape[1]) v[ex_index - 2, ex_index - 2] = np.cos(np.deg2rad(self.ex.azimuth - angle)) v[ey_index - 2, ex_index - 2] = np.sin(np.deg2rad(self.ex.azimuth - angle)) v[ex_index - 2, ey_index - 2] = np.cos(np.deg2rad(self.ey.azimuth - angle)) v[ey_index - 2, ey_index - 2] = np.sin(np.deg2rad(self.ey.azimuth - angle)) # matrix multiplication... rotated_transfer_functions = np.matmul( v, np.matmul(self.transfer_functions, u.T)) rotated_sigma_s = np.matmul(u, np.matmul(self.sigma_s, u.T)) rotated_sigma_e = np.matmul(v, np.matmul(self.sigma_e, v.T)) # now pull out the impedance tensor z = np.zeros((self.num_freq, 2, 2), dtype=np.complex64) z[:, 0, 0] = rotated_transfer_functions[:, ex_index - 2, hx_index] # Zxx z[:, 0, 1] = rotated_transfer_functions[:, ex_index - 2, hy_index] # Zxy z[:, 1, 0] = rotated_transfer_functions[:, ey_index - 2, hx_index] # Zyx z[:, 1, 1] = rotated_transfer_functions[:, ey_index - 2, hy_index] # Zyy # and the variance information var = np.zeros((self.num_freq, 2, 2)) var[:, 0, 0] = np.real(rotated_sigma_e[:, ex_index - 2, ex_index - 2] * rotated_sigma_s[:, hx_index, hx_index]) var[:, 0, 1] = np.real(rotated_sigma_e[:, ex_index - 2, ex_index - 2] * rotated_sigma_s[:, hy_index, hy_index]) var[:, 1, 0] = np.real(rotated_sigma_e[:, ey_index - 2, ey_index - 2] * rotated_sigma_s[:, hx_index, hx_index]) var[:, 1, 1] = np.real(rotated_sigma_e[:, ey_index - 2, ey_index - 2] * rotated_sigma_s[:, hy_index, hy_index]) error = np.sqrt(var) z_object = mtz.Z(z, error, self.frequency) return z_object
import numpy as np import mtpy.core.z as mtz import matplotlib.pyplot as plt dfn = r"c:\Users\jpeacock\OneDrive - DOI\Geothermal\Umatilla\modem_inv\inv_07\um_modem_data_z05.dat" d_obj = modem.Data() d_obj.read_data_file(dfn) rho = np.zeros((d_obj.data_array.shape[0], d_obj.period_list.shape[0])) # det_z = np.linalg.det(d_obj.data_array['z']) # mean_z = np.mean(det_z[np.nonzero(det_z)], axis=0) # mean_rho = (.02/(1/d_obj.period_list))*np.abs(mean_z) for ii, d_arr in enumerate(d_obj.data_array): z_obj = mtz.Z(d_arr["z"], freq=1.0 / d_obj.period_list) rho[ii, :] = z_obj.res_det mean_rho = np.apply_along_axis(lambda x: x[np.nonzero(x)].mean(), 0, rho) median_rho = np.apply_along_axis(lambda x: np.median(x[np.nonzero(x)]), 0, rho) fig = plt.figure() ax = fig.add_subplot(1, 1, 1) (l1, ) = ax.loglog(d_obj.period_list, mean_rho, lw=2, color=(0.75, 0.25, 0)) (l2, ) = ax.loglog(d_obj.period_list, median_rho, lw=2, color=(0, 0.25, 0.75)) ax.loglog( d_obj.period_list, np.repeat(mean_rho.mean(), d_obj.period_list.size), ls="--",
# check for empty values and set them to 0, check for any # other characters sometimes there are ****** for a null # component try: d_lines[ii] = float(dd) if d_lines[ii] == 1.0e32: d_lines[ii] = 0.0 except ValueError: d_lines[ii] = 0.0 data_dict[key] += d_lines ## fill useful arrays freq_arr = np.array(data_dict["freq"], dtype=np.float) ## fill impedance tensor z_obj = mtz.Z() z_obj.freq = freq_arr.copy() z_obj.z = np.zeros((freq_arr.size, 2, 2), dtype=np.complex) z_obj.z_err = np.zeros((freq_arr.size, 2, 2), dtype=np.float) try: z_obj.rotation_angle = data_dict["zrot"] except KeyError: z_obj.rotation_angle = np.zeros_like(freq_arr) z_obj.z[:, 0, 0] = np.array(data_dict["zxxr"]) + np.array(data_dict["zxxi"]) * 1j z_obj.z[:, 0, 1] = np.array(data_dict["zxyr"]) + np.array(data_dict["zxyi"]) * 1j z_obj.z[:, 1, 0] = np.array(data_dict["zyxr"]) + np.array(data_dict["zyxi"]) * 1j z_obj.z[:, 1, 1] = np.array(data_dict["zyyr"]) + np.array(data_dict["zyyi"]) * 1j z_obj.z_err[:, 0, 0] = np.array(data_dict["zxx.var"]) z_obj.z_err[:, 0, 1] = np.array(data_dict["zxy.var"])
def interpolate(self, new_freq_array, interp_type='slinear'): """ Interpolate the impedance tensor onto different frequencies Arguments ------------ *new_freq_array* : np.ndarray a 1-d array of frequencies to interpolate on to. Must be with in the bounds of the existing frequency range, anything outside and an error will occur. Returns ----------- *new_z_object* : mtpy.core.z.Z object a new impedance object with the corresponding frequencies and components. *new_tipper_object* : mtpy.core.z.Tipper object a new tipper object with the corresponding frequencies and components. Examples ---------- :Interpolate: :: >>> import mtpy.core.mt as mt >>> edi_fn = r"/home/edi_files/mt_01.edi" >>> mt_obj = mt.MT(edi_fn) >>> # create a new frequency range to interpolate onto >>> new_freq = np.logspace(-3, 3, 24) >>> new_z_object, new_tipper_obj = mt_obj.interpolate(new_freq) >>> mt_obj.write_edi_file(new_fn=r"/home/edi_files/mt_01_interp.edi", >>> ... new_Z=new_z_object, >>> ... new_Tipper=new_tipper_object) """ # if the interpolation module has not been loaded return if interp_import is False: print('could not interpolate, need to install scipy') return #make sure the input is a numpy array if type(new_freq_array) != np.ndarray: new_freq_array = np.array(new_freq_array) # check the bounds of the new frequency array if self.Z.freq.min() > new_freq_array.min(): raise ValueError('New frequency minimum of {0:.5g}'.format(new_freq_array.min())+\ ' is smaller than old frequency minimum of {0:.5g}'.format(self.Z.freq.min())+\ '. The new frequency range needs to be within the '+\ 'bounds of the old one.') if self.Z.freq.max() < new_freq_array.max(): raise ValueError('New frequency maximum of {0:.5g}'.format(new_freq_array.max())+\ 'is smaller than old frequency maximum of {0:.5g}'.format(self.Z.freq.max())+\ '. The new frequency range needs to be within the '+\ 'bounds of the old one.') # make a new Z object new_Z = MTz.Z(z_array=np.zeros((new_freq_array.shape[0], 2, 2), dtype='complex'), z_err_array=np.zeros((new_freq_array.shape[0], 2, 2)), freq=new_freq_array) new_Tipper = MTz.Tipper(tipper_array=np.zeros( (new_freq_array.shape[0], 1, 2), dtype='complex'), tipper_err_array=np.zeros( (new_freq_array.shape[0], 1, 2)), freq=new_freq_array) # interpolate the impedance tensor for ii in range(2): for jj in range(2): # need to look out for zeros in the impedance # get the indicies of non-zero components nz_index = np.nonzero(self.Z.z[:, ii, jj]) if len(nz_index[0]) == 0: continue # get the non-zero components z_real = self.Z.z[nz_index, ii, jj].real z_imag = self.Z.z[nz_index, ii, jj].imag z_err = self.Z.z_err[nz_index, ii, jj] # get the frequencies of non-zero components f = self.Z.freq[nz_index] # get frequencies to interpolate on to, making sure the # bounds are with in non-zero components new_nz_index = np.where((new_freq_array >= f.min()) & (new_freq_array <= f.max())) new_f = new_freq_array[new_nz_index] # create a function that does 1d interpolation z_func_real = spi.interp1d(f, z_real, kind=interp_type) z_func_imag = spi.interp1d(f, z_imag, kind=interp_type) z_func_err = spi.interp1d(f, z_err, kind=interp_type) # interpolate onto new frequency range new_Z.z[new_nz_index, ii, jj] = z_func_real(new_f) + 1j * z_func_imag(new_f) new_Z.z_err[new_nz_index, ii, jj] = z_func_err(new_f) # if there is not tipper than skip if self.Tipper.tipper is None: return new_Z, new_Tipper # interpolate the Tipper for jj in range(2): # get indicies of non-zero components nz_index = np.nonzero(self.Tipper.tipper[:, 0, jj]) if len(nz_index[0]) == 0: continue # get non-zero components t_real = self.Tipper.tipper[nz_index, 0, jj].real t_imag = self.Tipper.tipper[nz_index, 0, jj].imag t_err = self.Tipper.tipper_err[nz_index, 0, jj] # get frequencies for non-zero components f = self.Tipper.freq[nz_index] # create interpolation functions t_func_real = spi.interp1d(f, t_real, kind=interp_type) t_func_imag = spi.interp1d(f, t_imag, kind=interp_type) t_func_err = spi.interp1d(f, t_err, kind=interp_type) # get new frequency to interpolate over, making sure bounds are # for non-zero components new_nz_index = np.where((new_freq_array >= f.min()) & (new_freq_array <= f.max())) new_f = new_freq_array[new_nz_index] # interpolate onto new frequency range new_Tipper.tipper[new_nz_index, 0, jj] = t_func_real(new_f)+\ 1j*t_func_imag(new_f) new_Tipper.tipper_err[new_nz_index, 0, jj] = t_func_err(new_f) return new_Z, new_Tipper
line = line.strip().split() if len(line) < 2: break else: mlst.append({}) for ii, key in enumerate(mkeys): if ii == 0: mlst[jj][key] = line[ii] elif ii == 1: nedi = line[1][1:-1] nedi = nedi.split(',') mlst[jj][key] = [ os.path.join(edipath, edistem + kk + '.edi') for kk in nedi ] elif ii == 2: mlst[jj][key] = Z.Z(os.path.join(edipath, line[ii] + '.edi')) else: # if ii==5: # #conversion of feet to meters # mlst[jj][key]=float(line[ii]) # else: # mlst[jj][key]=float(line[ii]) mlst[jj][key] = float(line[ii]) #============================================================================== # read in impedance and stack for each station #============================================================================== ns = len(mlst) for ll in range(ns): z1 = mlst[ll]['model-sounding'].z.copy()
count += len(f_index[0]) # now replace data_arr = data_arr[np.nonzero(data_arr['freq'])] sort_index = np.argsort(data_arr['freq']) # check to see if the sorted indexes are descending or ascending, # make sure that frequency is descending if data_arr['freq'][0] > data_arr['freq'][1]: sort_index = sort_index[::-1] data_arr = data_arr[sort_index] new_z = z.Z(data_arr['z'], data_arr['z_err'], data_arr['freq']) # check for all zeros in tipper, meaning there is only # one unique value if np.unique(data_arr['tipper']).size > 1: new_t = z.Tipper(data_arr['tipper'], data_arr['tipper_err'], data_arr['freq']) else: new_t = z.Tipper() mt_obj = mt.MT(edi_01) mt_obj.Z = new_z mt_obj.Tipper = new_t
def remove_distortion(z_array=None, z_object=None, num_freq=None, g='det'): """ remove distortion from an impedance tensor using the method outlined by Bibby et al., [2005]. Parameters ----------- **z_array** : np.ndarray((nf, 2, 2)) numpy array of impedance tensor *default* is None **z_object** : mtpy.core.z object *default* is None **num_freq** : int number of frequecies to look for distortion *default* is None, meaning look over all frequencies **g** : [ 'det' | '01' | '10 ] type of distortion to look for *default* is 'det' Returns -------- **distortion** : np.ndarray (2, 2) distortion array **new_z_obj** : mtpy.core.z z object with distortion removed and error calculated Examples ------------- :Remove Distortion: :: >>> import mtpy.analysis.distortion as distortion >>> d, new_z = distortion.remove_distortion(z_object=z_obj) """ if z_array is not None: z_obj = MTz.Z(z_array=z_array) elif z_object is not None: z_obj = z_object zero_idx = np.where(z_obj.z == 0 + 0j) # 0. generate a Z object # 1. find distortion via function above, # 2. remove distortion via method of z object dis, dis_err = find_distortion(z_obj, num_freq=num_freq, g=g) try: # distortion_tensor, zd, zd_err = z_obj.no_distortion(dis, distortion_err_tensor=dis_err) distortion_tensor, zd, zd_err = z_obj.remove_distortion( dis, distortion_err_tensor=dis_err) zd_err = np.nan_to_num(zd_err) zd_err[np.where(zd_err == 0.0)] = 1.0 distortion_z_obj = z_obj distortion_z_obj.z = zd distortion_z_obj.z[zero_idx] = 0.0 + 0.0j distortion_z_obj.z_err = zd_err return distortion_tensor, distortion_z_obj except MTex.MTpyError_Z: print('Could not compute distortion tensor') return np.identity(2), z_obj
line = line.strip().split() if len(line) < 2: break else: mlst.append({}) for ii, key in enumerate(mkeys): if ii == 0: mlst[jj][key] = line[ii] elif ii == 1: nedi = line[1][1:-1] nedi = nedi.split(",") mlst[jj][key] = [ os.path.join(edipath, edistem + kk + ".edi") for kk in nedi ] elif ii == 2: mlst[jj][key] = Z.Z(os.path.join(edipath, line[ii] + ".edi")) else: # if ii==5: # #conversion of feet to meters # mlst[jj][key]=float(line[ii]) # else: # mlst[jj][key]=float(line[ii]) mlst[jj][key] = float(line[ii]) # ============================================================================== # read in impedance and stack for each station # ============================================================================== ns = len(mlst) for ll in range(ns): z1 = mlst[ll]["model-sounding"].z.copy()