def _get_station_data( data, location, orientation, component, plot_error=False): # Get the components if component in ['app_res', 'phase', 'amplitude']: real_tuple = _extract_location_data(data, location, orientation, 'real', plot_error) imag_tuple = _extract_location_data(data, location, orientation, 'imag', plot_error) if plot_error: freqs, real_data, real_std, real_floor = real_tuple freqs, imag_data, imag_std, imag_floor = imag_tuple # Add up the uncertainties real_uncert = real_std * np.abs(real_data) + real_floor imag_uncert = imag_std * np.abs(imag_data) + imag_floor else: freqs, real_data = real_tuple freqs, imag_data = imag_tuple if 'app_res' in component: comp_data = real_data + 1j * imag_data plot_data = (1. / (mu_0 * omega(freqs))) * np.abs(comp_data) ** 2 if plot_error: res_uncert = ( (2. / (mu_0 * omega(freqs))) * (real_data * real_uncert + imag_data * imag_uncert) ) errorbars = [res_uncert, res_uncert] elif 'phase' in component: plot_data = np.arctan2(imag_data, real_data) * (180. / np.pi) if plot_error: phs_uncert = ( (1. / (real_data ** 2 + imag_data ** 2)) * ((real_data * real_uncert - imag_data * imag_uncert)) ) * (180. / np.pi) # Scale back the errorbars errorbars = [phs_uncert, phs_uncert] elif 'amplitude' in component: comp_data = real_data + 1j * imag_data plot_data = np.abs(comp_data) if plot_error: amp_uncert = ((1. / plot_data) * ((np.abs(real_data) * real_uncert) + (np.abs(imag_data) * imag_uncert)) ) errorbars = [amp_uncert, amp_uncert] #[low_unsert, up_unsert] else: if plot_error: freqs, plot_data, std_data, floor_data = _extract_location_data( data, location, orientation, component, return_uncert=plot_error) attr_uncert = std_data * np.abs(plot_data) + floor_data errorbars = [attr_uncert, attr_uncert] else: freqs, plot_data = _extract_location_data( data, location, orientation, component, return_uncert=plot_error) if plot_error: return (freqs, plot_data, errorbars) else: return (freqs, plot_data)
def _get_map_data(data, frequency, orientation, component, plot_error=False): """ Function for getting frequency map data """ # Get the components if component in ['app_res', 'phase', 'amplitude']: real_tuple = _extract_frequency_data(data, frequency, orientation, 'real', plot_error) imag_tuple = _extract_frequency_data(data, frequency, orientation, 'imag', plot_error) if plot_error: freqs, real_data, real_std, real_floor = real_tuple freqs, imag_data, imag_std, imag_floor = imag_tuple # Add up the uncertainties real_uncert = real_std * np.abs(real_data) + real_floor imag_uncert = imag_std * np.abs(imag_data) + imag_floor else: freqs, real_data = real_tuple freqs, imag_data = imag_tuple if 'app_res' in component: comp_data = real_data + 1j * imag_data plot_data = (1. / (mu_0 * omega(freqs))) * np.abs(comp_data)**2 if plot_error: res_uncert = ( (2. / (mu_0 * omega(freqs))) * (real_data * real_uncert + imag_data * imag_uncert)) errorbars = [res_uncert, res_uncert] elif 'phase' in component: plot_data = np.arctan2(imag_data, real_data) * (180. / np.pi) if plot_error: phs_uncert = ((1. / (real_data**2 + imag_data**2)) * ((real_data * real_uncert - imag_data * imag_uncert))) * (180. / np.pi) # Scale back the errorbars errorbars = [phs_uncert, phs_uncert] elif 'amplitude' in component: comp_data = real_data + 1j * imag_data plot_data = np.abs(comp_data) if plot_error: amp_uncert = ((1. / plot_data) * ((np.abs(real_data) * real_uncert) + (np.abs(imag_data) * imag_uncert))) errorbars = [amp_uncert, amp_uncert] #[low_unsert, up_unsert] else: if plot_error: freqs, plot_data, std_data, floor_data = _extract_frequency_data( data, frequency, orientation, component, return_uncert=error) attr_uncert = std_data * np.abs(plot_data) + floor_data errorbars = [attr_uncert, attr_uncert] else: freqs, plot_data = _extract_frequency_data(data, frequency, orientation, component, return_uncert=False) return (freqs, plot_data, errorbars)
def getADeriv(self, freq, u, v, adjoint=False): """ The derivative of A wrt sigma """ u_src = u['e_1dSolution'] dMfSigma_dm = self.MfSigmaDeriv(u_src) if adjoint: return 1j * omega(freq) * mkvc(dMfSigma_dm.T * v, ) # Note: output has to be nN/nF, not nC/nE. # v should be nC return 1j * omega(freq) * mkvc(dMfSigma_dm * v, )
def getADeriv(self, freq, u, v, adjoint=False): """ The derivative of A wrt sigma """ u_src = u['e_1dSolution'] dMfSigma_dm = self.MfSigmaDeriv(u_src) if adjoint: return 1j * omega(freq) * mkvc(dMfSigma_dm.T * v,) # Note: output has to be nN/nF, not nC/nE. # v should be nC return 1j * omega(freq) * mkvc(dMfSigma_dm * v,)
def getADeriv(self, freq, u, v, adjoint=False): """ Calculate the derivative of A wrt m. :param float freq: Frequency :param SimPEG.EM.NSEM.FieldsNSEM u: NSEM Fields object :param numpy.ndarray v: vector of size (nU,) (adjoint=False) and size (nP,) (adjoint=True) :rtype: numpy.ndarray :return: Calculated derivative (nP,) (adjoint=False) and (nU,)[NOTE return as a (nU/2,2) columnwise polarizations] (adjoint=True) for both polarizations """ # Fix u to be a matrix nE,2 # This considers both polarizations and returns a nE,2 matrix for each polarization # The solution types sol0, sol1 = self._solutionType if adjoint: dMe_dsigV = ( self.MeSigmaDeriv(u[sol0], v[:self.mesh.nE], adjoint) + self.MeSigmaDeriv(u[sol1], v[self.mesh.nE:], adjoint) ) else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack( ( mkvc(self.MeSigmaDeriv(u[sol0], v, adjoint), 2), mkvc(self.MeSigmaDeriv(u[sol1], v, adjoint), 2) ) ) return 1j * omega(freq) * dMe_dsigV
def _get_plot_data(data, location, orientation, component): if 'app_res' in component: freqs, dat_r = _extract_location_data( data, location, orientation, 'real') freqs, dat_i = _extract_location_data( data, location, orientation, 'imag') dat = dat_r + 1j * dat_i plot_data = 1. / (mu_0 * omega(freqs)) * np.abs(dat) ** 2 elif 'phase' in component: freqs, dat_r = _extract_location_data( data, location, orientation, 'real') freqs, dat_i = _extract_location_data( data, location, orientation, 'imag') plot_data = np.arctan2(dat_i, dat_r) * (180. / np.pi) elif 'amplitude' in component: freqs, dat_r = _extract_location_data( data, location, orientation, 'real') freqs, dat_i = _extract_location_data( data, location, orientation, 'imag') dat_complex = dat_r + 1j * dat_i plot_data = np.abs(dat_complex) else: freqs, plot_data = _extract_location_data( data, location, orientation, component) return (freqs, plot_data)
def getADeriv(self, freq, u, v, adjoint=False): """ Calculate the derivative of A wrt m. :param float freq: Frequency :param SimPEG.EM.NSEM.FieldsNSEM u: NSEM Fields object :param numpy.ndarray v: vector of size (nU,) (adjoint=False) and size (nP,) (adjoint=True) :rtype: numpy.ndarray :return: Calculated derivative (nP,) (adjoint=False) and (nU,)[NOTE return as a (nU/2,2) columnwise polarizations] (adjoint=True) for both polarizations """ # Fix u to be a matrix nE,2 # This considers both polarizations and returns a nE,2 matrix for each polarization # The solution types sol0, sol1 = self._solutionType if adjoint: dMe_dsigV = sp.hstack((self.MeSigmaDeriv( u[sol0]).T, self.MeSigmaDeriv(u[sol1]).T)) * v else: # Need a nE,2 matrix to be returned dMe_dsigV = np.hstack( (mkvc(self.MeSigmaDeriv(u[sol0]) * v, 2), mkvc(self.MeSigmaDeriv(u[sol1]) * v, 2))) return 1j * omega(freq) * dMe_dsigV
def _get_plot_data(data, location, orientation, component): if 'app_res' in component: freqs, dat_r = _extract_location_data(data, location, orientation, 'real') freqs, dat_i = _extract_location_data(data, location, orientation, 'imag') dat = dat_r + 1j * dat_i plot_data = 1. / (mu_0 * omega(freqs)) * np.abs(dat)**2 elif 'phase' in component: freqs, dat_r = _extract_location_data(data, location, orientation, 'real') freqs, dat_i = _extract_location_data(data, location, orientation, 'imag') plot_data = np.arctan2(dat_i, dat_r) * (180. / np.pi) elif 'amplitude' in component: freqs, dat_r = _extract_location_data(data, location, orientation, 'real') freqs, dat_i = _extract_location_data(data, location, orientation, 'imag') dat_complex = dat_r + 1j * dat_i plot_data = np.abs(dat_complex) else: freqs, plot_data = _extract_location_data(data, location, orientation, component) return (freqs, plot_data)
def getRHSDeriv(self, freq, v, adjoint=False): """ The derivative of the RHS wrt sigma """ Src = self.survey.getSrcByFreq(freq)[0] S_eDeriv = mkvc(Src.S_eDeriv_m(self, v, adjoint), ) return -1j * omega(freq) * S_eDeriv
def getRHSDeriv(self, freq, v, adjoint=False): """ The derivative of the RHS wrt sigma """ Src = self.survey.getSrcByFreq(freq)[0] S_eDeriv = mkvc(Src.S_eDeriv_m(self, v, adjoint),) return -1j * omega(freq) * S_eDeriv
def getRHS(self, freq): """ Function to return the right hand side for the system. :param float freq: Frequency :rtype: numpy.ndarray :return: RHS for 1 polarizations, primary fields (nF, 1) """ # Get sources for the frequncy(polarizations) Src = self.survey.getSrcByFreq(freq)[0] # Only select the yx polarization S_e = mkvc(Src.S_e(self)[:, 1], 2) return -1j * omega(freq) * S_e
def getA(self, freq): """ Function to get the A system. :param float freq: Frequency :rtype: scipy.sparse.csr_matrix :return: A """ Mfmui = self.MfMui Mesig = self.MeSigma C = self.mesh.edgeCurl return C.T*Mfmui*C + 1j*omega(freq)*Mesig
def getA(self, freq): """ Function to get the A system. :param float freq: Frequency :rtype: scipy.sparse.csr_matrix :return: A """ Mfmui = self.MfMui Mesig = self.MeSigma C = self.mesh.edgeCurl return C.T * Mfmui * C + 1j * omega(freq) * Mesig
def getRHS(self, freq): """ Function to return the right hand side for the system. :param float freq: Frequency :rtype: numpy.ndarray :return: RHS for both polarizations, primary fields (nE, 2) """ # Get sources for the frequncy(polarizations) Src = self.survey.getSrcByFreq(freq)[0] S_e = Src.S_e(self) return -1j * omega(freq) * S_e
def getA(self, freq): """ Function to get the A matrix. :param float freq: Frequency :rtype: scipy.sparse.csr_matrix :return: A """ # Note: need to use the code above since in the 1D problem I want # e to live on Faces(nodes) and h on edges(cells). Might need to rethink this # Possible that _fieldType and _eqLocs can fix this MeMui = self.MeMui MfSigma = self.MfSigma C = self.mesh.nodalGrad # Make A A = C.T*MeMui*C + 1j*omega(freq)*MfSigma # Either return full or only the inner part of A return A
def getRHSDeriv(self, freq, v, adjoint=False): """ The derivative of the RHS with respect to the model and the source :param float freq: Frequency :param numpy.ndarray v: vector of size (nU,) (adjoint=False) and size (nP,) (adjoint=True) :rtype: numpy.ndarray :return: Calculated derivative (nP,) (adjoint=False) and (nU,2) (adjoint=True) for both polarizations """ # Note: the formulation of the derivative is the same for adjoint or not. Src = self.survey.getSrcByFreq(freq)[0] S_eDeriv = Src.S_eDeriv(self, v, adjoint) dRHS_dm = -1j * omega(freq) * S_eDeriv return dRHS_dm
def getA(self, freq): """ Function to get the A matrix. :param float freq: Frequency :rtype: scipy.sparse.csr_matrix :return: A """ # Note: need to use the code above since in the 1D problem I want # e to live on Faces(nodes) and h on edges(cells). Might need to rethink this # Possible that _fieldType and _eqLocs can fix this MeMui = self.MeMui MfSigma = self.MfSigma C = self.mesh.nodalGrad # Make A A = C.T * MeMui * C + 1j * omega(freq) * MfSigma # Either return full or only the inner part of A return A
import numpy as np from scipy.constants import epsilon_0 from scipy.constants import mu_0 from SimPEG.EM.Utils.EMUtils import k from SimPEG.EM.Utils.EMUtils import omega __all__ = ['MT_LayeredEarth'] # Evaluate Impedance Z of a layer _ImpZ = lambda f, mu, k: omega(f) * mu / k # Complex Cole-Cole Conductivity - EM utils _PCC = lambda siginf, m, t, c, f: siginf * (1. - (m / (1. + (1j * omega(f) * t)**c))) # matrix P relating Up and Down components with E and H fields _P = lambda z: np.matrix([[ 1., 1, ], [-1. / z, 1. / z]], dtype='complex_') _Pinv = lambda z: np.matrix([[1., -z], [1., z]], dtype='complex_') / 2. # matrix T for transition of Up and Down components accross a layer _T = lambda h, k: np.matrix( [[np.exp(1j * k * h), 0.], [0., np.exp(-1j * k * h)]], dtype='complex_') _Tinv = lambda h, k: np.matrix( [[np.exp(-1j * k * h), 0.], [0., np.exp(1j * k * h)]], dtype='complex_') # Propagate Up and Down component for a certain frequency & evaluate E and H field
import numpy as np from scipy.constants import epsilon_0 from scipy.constants import mu_0 from SimPEG.EM.Utils.EMUtils import k from SimPEG.EM.Utils.EMUtils import omega __all__ = [ 'MT_LayeredEarth' ] # Evaluate Impedance Z of a layer _ImpZ = lambda f, mu, k: omega(f)*mu/k # Complex Cole-Cole Conductivity - EM utils _PCC = lambda siginf, m, t, c, f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c))) # matrix P relating Up and Down components with E and H fields _P = lambda z: np.matrix([[1., 1, ], [-1./z, 1./z]], dtype='complex_') _Pinv = lambda z: np.matrix([[1., -z], [1., z]], dtype='complex_')/2. # matrix T for transition of Up and Down components accross a layer _T = lambda h, k: np.matrix([[np.exp(1j*k*h), 0.], [0., np.exp(-1j*k*h)]], dtype='complex_') _Tinv = lambda h, k: np.matrix([[np.exp(-1j*k*h), 0.], [0., np.exp(1j*k*h)]], dtype='complex_') # Propagate Up and Down component for a certain frequency & evaluate E and H field def _Propagate(f, thickness, sig, chg, taux, c, mu_r, eps_r, n): if isinstance(eps_r, float): epsmodel = np.ones_like(sig)*eps_r else:
def MT_LayeredEarth(freq, thickness, sig, return_type='Res-Phase', chg=0., tau=0., c=0., mu_r=1., eps_r=1.): """ This code compute the analytic response of a n-layered Earth to a plane wave (Magnetotellurics). All physical properties arrays convention describes the layers parameters from the top layer to the bottom layer. The solution is first developed in Ward and Hohmann 1988. See also http://em.geosci.xyz/content/maxwell3_fdem/natural_sources/MT_N_layered_Earth.html :param freq: the frequency at which we take the measurements :type freq: float or numpy.array :param thickness: thickness of the Earth layers in meters, size is len(sig)-1. The last one is already considered infinite. For 1-layer Earth, thickness = None or 0. :type thickness: float or numpy.array :param sig: electric conductivity of the Earth layers in S/m :type sig: float or numpy.array :param str return_type: Output return_type. 'Res-Phase' returns apparent resisitivity and Phase. 'Impedance' returns the complex Impedance :param numpy.array chg: Cole-Cole Parameters for chargeable layers: chargeability :param numpy.array tau: Cole-Cole Parameters for chargeable layers: time decay constant :param numpy.array c: Cole-Cole Parameters for chargeable layers: geometric factor :param mu_r: relative magnetic permeability :type mu_r: float or numpy.array :param eps_r: relative dielectric permittivity :type eps_r: float or numpy.array """ if isinstance(freq, float): F = np.r_[freq] else: F = freq if isinstance(sig, float): sigmodel = np.r_[sig] else: sigmodel = sig if isinstance(thickness, float): if thickness == 0.: thickmodel = np.empty(0) else: thickmodel = np.r_[thickness] elif thickness is None: thickmodel = np.empty(0) else: thickmodel = thickness # Count the number of layers nlayer = len(sigmodel) Res = np.zeros_like(F) Phase = np.zeros_like(F) App_ImpZ = np.zeros_like(F, dtype='complex_') for i in range(0, len(F)): _, EH, _, _ = _Propagate(F[i], thickmodel, sigmodel, chg, tau, c, mu_r, eps_r, nlayer) App_ImpZ[i] = EH[0, 1]/EH[1, 1] Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i])) Phase[i] = np.angle(App_ImpZ[i], deg=True) if return_type == 'Res-Phase': return Res, Phase elif return_type == 'Impedance': return App_ImpZ
def MT_LayeredEarth(freq, thickness, sig, return_type='Res-Phase', chg=0., tau=0., c=0., mu_r=1., eps_r=1.): """ This code compute the analytic response of a n-layered Earth to a plane wave (Magnetotellurics). All physical properties arrays convention describes the layers parameters from the top layer to the bottom layer. The solution is first developed in Ward and Hohmann 1988. See also http://em.geosci.xyz/content/maxwell3_fdem/natural_sources/MT_N_layered_Earth.html :param freq: the frequency at which we take the measurements :type freq: float or numpy.ndarray :param thickness: thickness of the Earth layers in meters, size is len(sig)-1. The last one is already considered infinite. For 1-layer Earth, thickness = None or 0. :type thickness: float or numpy.ndarray :param sig: electric conductivity of the Earth layers in S/m :type sig: float or numpy.ndarray :param str return_type: Output return_type. 'Res-Phase' returns apparent resisitivity and Phase. 'Impedance' returns the complex Impedance :param numpy.ndarray chg: Cole-Cole Parameters for chargeable layers: chargeability :param numpy.ndarray tau: Cole-Cole Parameters for chargeable layers: time decay constant :param numpy.ndarray c: Cole-Cole Parameters for chargeable layers: geometric factor :param mu_r: relative magnetic permeability :type mu_r: float or numpy.ndarray :param eps_r: relative dielectric permittivity :type eps_r: float or numpy.ndarray """ if isinstance(freq, float): F = np.r_[freq] else: F = freq if isinstance(sig, float): sigmodel = np.r_[sig] else: sigmodel = sig if isinstance(thickness, float): if thickness == 0.: thickmodel = np.empty(0) else: thickmodel = np.r_[thickness] elif thickness is None: thickmodel = np.empty(0) else: thickmodel = thickness # Count the number of layers nlayer = len(sigmodel) Res = np.zeros_like(F) Phase = np.zeros_like(F) App_ImpZ = np.zeros_like(F, dtype='complex_') for i in range(0, len(F)): _, EH, _, _ = _Propagate(F[i], thickmodel, sigmodel, chg, tau, c, mu_r, eps_r, nlayer) App_ImpZ[i] = EH[0, 1]/EH[1, 1] Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i])) Phase[i] = np.angle(App_ImpZ[i], deg=True) if return_type == 'Res-Phase': return Res, Phase elif return_type == 'Impedance': return App_ImpZ