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 read_zmm_file(self, z_fn=None): """ Read in Egbert zrr file """ if z_fn is not None: self.z_fn = z_fn self.read_header() self.initialize_arrays() ### read each data block and fill the appropriate array for ii, period_block in enumerate(self._get_period_blocks()): data_block = self._read_period_block(period_block) self.period[ii] = data_block['period'] self._fill_tf_array_from_block(data_block['tf'], ii) self._fill_sig_array_from_block(data_block['sig'], ii) self._fill_res_array_from_block(data_block['res'], ii) ### make Z and Tipper self.Z = self.calculate_impedance() try: self.Tipper = self.calculate_tippers() except ZMMError: self.Tipper = mtz.Tipper() print('*** No HZ found cannot calculate induction vectors. ***')
def calculate_tippers(self, angle=0.): """ calculate induction vectors """ # check to see if there is a vertical magnetic field in the TFs if self.hz is None: raise ZMMError("Cannot return tipper data because the TFs do not " "contain the vertical magnetic field 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) # don't need to transform predicated channels (assuming no tilt in Hz) hz_index = self.hz.index v = np.eye(self.transfer_functions.shape[1], self.transfer_functions.shape[1]) # 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 tipper information tipper = np.zeros((self.num_freq, 2), dtype=np.complex64) tipper[:, 0] = rotated_transfer_functions[:, hz_index - 2, hx_index] # Tx tipper[:, 1] = rotated_transfer_functions[:, hz_index - 2, hy_index] # Ty # and the variance/error information var = np.zeros((self.num_freq, 2)) var[:, 0] = np.real(rotated_sigma_e[:, hz_index - 2, hz_index - 2] * rotated_sigma_s[:, hx_index, hx_index]) # Tx var[:, 1] = np.real(rotated_sigma_e[:, hz_index - 2, hz_index - 2] * rotated_sigma_s[:, hy_index, hy_index]) # Ty error = np.sqrt(var) tipper = tipper.reshape((self.num_freq, 1, 2)) error = error.reshape((self.num_freq, 1, 2)) tipper_obj = mtz.Tipper(tipper, error, self.frequency) return tipper_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])
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))
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 n_edi_fn = mt_obj.write_mt_file(fn_basename=c_edi_fn.name) ptm = mtplot.plot_multiple_mt_responses(fn_list=[edi_01, edi_02, n_edi_fn], plot_style='compare')
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
'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'), ('acqdate', 'Nov. 1986'), ('loc', 'Long Valley, CA'), ('lat', loc_dict[name][0]), ('lon', loc_dict[name][1]), ('elev', 2200)]) #----------------INFO------------------------------------------------ data_edi.info_dict = dict([('max lines', 1000),
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)