Merge branch 'master' into em/primsec

# Conflicts:
#	SimPEG/EM/FDEM/SrcFDEM.py
This commit is contained in:
Lindsey Heagy
2016-02-10 16:15:01 -08:00
105 changed files with 4446 additions and 2910 deletions
+2 -2
View File
@@ -2,7 +2,6 @@ from __future__ import division
import numpy as np
from scipy.constants import mu_0, pi
from scipy.special import erf
import matplotlib.pyplot as plt
from SimPEG import Utils
@@ -59,8 +58,9 @@ def MagneticDipoleWholeSpace(XYZ, srcLoc, sig, f, moment=1., orientation='X', mu
from SimPEG import EM
import matplotlib.pyplot as plt
from scipy.constants import mu_0
freqs = np.logspace(-2,5,100)
Bx, By, Bz = EM.Analytics.FDEM.AnalyticMagDipoleWholeSpace([0,100,0], [0,0,0], 1e-2, freqs, m=1, orientation='Z')
Bx, By, Bz = EM.Analytics.FDEM.MagneticDipoleWholeSpace([0,100,0], [0,0,0], 1e-2, freqs, moment=1, orientation='Z')
plt.loglog(freqs, np.abs(Bz.real)/mu_0, 'b')
plt.loglog(freqs, np.abs(Bz.imag)/mu_0, 'r')
plt.legend(('real','imag'))
-97
View File
@@ -1,97 +0,0 @@
from SimPEG import *
import SimPEG.EM as EM
from scipy.constants import mu_0
import matplotlib.pyplot as plt
def run(plotIt=True):
cs, ncx, ncz, npad = 5., 25, 15, 15
hx = [(cs,ncx), (cs,npad,1.3)]
hz = [(cs,npad,-1.3), (cs,ncz), (cs,npad,1.3)]
mesh = Mesh.CylMesh([hx,1,hz], '00C')
active = mesh.vectorCCz<0.
layer = (mesh.vectorCCz<0.) & (mesh.vectorCCz>=-100.)
actMap = Maps.ActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz)
mapping = Maps.ExpMap(mesh) * Maps.Vertical1DMap(mesh) * actMap
sig_half = 2e-3
sig_air = 1e-8
sig_layer = 1e-3
sigma = np.ones(mesh.nCz)*sig_air
sigma[active] = sig_half
sigma[layer] = sig_layer
mtrue = np.log(sigma[active])
if plotIt:
fig, ax = plt.subplots(1,1, figsize = (3, 6))
plt.semilogx(sigma[active], mesh.vectorCCz[active])
ax.set_ylim(-600, 0)
ax.set_xlim(1e-4, 1e-2)
ax.set_xlabel('Conductivity (S/m)', fontsize = 14)
ax.set_ylabel('Depth (m)', fontsize = 14)
ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5)
rxOffset=1e-3
rx = EM.TDEM.RxTDEM(np.array([[rxOffset, 0., 30]]), np.logspace(-5,-3, 31), 'bz')
src = EM.TDEM.SrcTDEM_VMD_MVP([rx], np.array([0., 0., 80]))
survey = EM.TDEM.SurveyTDEM([src])
prb = EM.TDEM.ProblemTDEM_b(mesh, mapping=mapping)
prb.Solver = SolverLU
prb.timeSteps = [(1e-06, 20),(1e-05, 20), (0.0001, 20)]
prb.pair(survey)
dtrue = survey.dpred(mtrue)
survey.dtrue = dtrue
std = 0.05
noise = std*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
survey.dobs = survey.dtrue+noise
survey.std = survey.dobs*0 + std
survey.Wd = 1/(abs(survey.dobs)*std)
if plotIt:
fig, ax = plt.subplots(1,1, figsize = (10, 6))
ax.loglog(rx.times, dtrue, 'b.-')
ax.loglog(rx.times, survey.dobs, 'r.-')
ax.legend(('Noisefree', '$d^{obs}$'), fontsize = 16)
ax.set_xlabel('Time (s)', fontsize = 14)
ax.set_ylabel('$B_z$ (T)', fontsize = 16)
ax.set_xlabel('Time (s)', fontsize = 14)
ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5)
dmisfit = DataMisfit.l2_DataMisfit(survey)
regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]])
reg = Regularization.Tikhonov(regMesh)
opt = Optimization.InexactGaussNewton(maxIter = 5)
invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt)
# Create an inversion object
beta = Directives.BetaSchedule(coolingFactor=5, coolingRate=2)
betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0)
inv = Inversion.BaseInversion(invProb, directiveList=[beta,betaest])
m0 = np.log(np.ones(mtrue.size)*sig_half)
reg.alpha_s = 1e-2
reg.alpha_x = 1.
prb.counter = opt.counter = Utils.Counter()
opt.LSshorten = 0.5
opt.remember('xc')
mopt = inv.run(m0)
if plotIt:
fig, ax = plt.subplots(1,1, figsize = (3, 6))
plt.semilogx(sigma[active], mesh.vectorCCz[active])
plt.semilogx(np.exp(mopt), mesh.vectorCCz[active])
ax.set_ylim(-600, 0)
ax.set_xlim(1e-4, 1e-2)
ax.set_xlabel('Conductivity (S/m)', fontsize = 14)
ax.set_ylabel('Depth (m)', fontsize = 14)
ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5)
plt.legend(['$\sigma_{true}$', '$\sigma_{pred}$'])
plt.show()
if __name__ == '__main__':
run()
-1
View File
@@ -1 +0,0 @@
import CylInversion
+248 -113
View File
@@ -15,18 +15,20 @@ class BaseFDEMProblem(BaseEMProblem):
.. math ::
\mathbf{C} \mathbf{e} + i \omega \mathbf{b} = \mathbf{s_m} \\\\
{\mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{M^e} \mathbf{s_e}}
{\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{s_e}}
if using the E-B formulation (:code:`Problem_e`
or :code:`Problem_b`) or the magnetic field
or :code:`Problem_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity.
If we write Maxwell's equations in terms of
\\\(\\\mathbf{h}\\\) and current density \\\(\\\mathbf{j}\\\)
.. math ::
\mathbf{C}^T \mathbf{M_{\\rho}^f} \mathbf{j} + i \omega \mathbf{M_{\mu}^e} \mathbf{h} = \mathbf{M^e} \mathbf{s_m} \\\\
\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + i \omega \mathbf{M_{\mu}^e} \mathbf{h} = \mathbf{s_m} \\\\
\mathbf{C} \mathbf{h} - \mathbf{j} = \mathbf{s_e}
if using the H-J formulation (:code:`Problem_j` or :code:`Problem_h`).
if using the H-J formulation (:code:`Problem_j` or :code:`Problem_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity.
The problem performs the elimination so that we are solving the system for \\\(\\\mathbf{e},\\\mathbf{b},\\\mathbf{j} \\\) or \\\(\\\mathbf{h}\\\)
"""
@@ -36,7 +38,11 @@ class BaseFDEMProblem(BaseEMProblem):
def fields(self, m=None):
"""
Solve the forward problem for the fields.
Solve the forward problem for the fields.
:param numpy.array m: inversion model (nP,)
:rtype numpy.array:
:return F: forward solution
"""
self.curModel = m
@@ -50,16 +56,22 @@ class BaseFDEMProblem(BaseEMProblem):
Srcs = self.survey.getSrcByFreq(freq)
ftype = self._fieldType + 'Solution'
F[Srcs, ftype] = sol
Ainv.clean()
return F
def Jvec(self, m, v, f=None):
def Jvec(self, m, v, u=None):
"""
Sensitivity times a vector
Sensitivity times a vector.
:param numpy.array m: inversion model (nP,)
:param numpy.array v: vector which we take sensitivity product with (nP,)
:param SimPEG.EM.FDEM.Fields u: fields object
:rtype numpy.array:
:return: Jv (ndata,)
"""
if f is None:
f = self.fields(m)
if u is None:
u = self.fields(m)
self.curModel = m
@@ -71,33 +83,41 @@ class BaseFDEMProblem(BaseEMProblem):
for src in self.survey.getSrcByFreq(freq):
ftype = self._fieldType + 'Solution'
u_src = f[src, ftype]
u_src = u[src, ftype]
dA_dm = self.getADeriv_m(freq, u_src, v)
dRHS_dm = self.getRHSDeriv_m(freq, src, v)
du_dm = Ainv * ( - dA_dm + dRHS_dm )
for rx in src.rxList:
df_duFun = getattr(f, '_%sDeriv_u'%rx.projField, None)
df_duFun = getattr(u, '_%sDeriv_u'%rx.projField, None)
df_dudu_dm = df_duFun(src, du_dm, adjoint=False)
df_dmFun = getattr(f, '_%sDeriv_m'%rx.projField, None)
df_dmFun = getattr(u, '_%sDeriv_m'%rx.projField, None)
df_dm = df_dmFun(src, v, adjoint=False)
Df_Dm = np.array(df_dudu_dm + df_dm,dtype=complex)
P = lambda v: rx.projectFieldsDeriv(src, self.mesh, f, v) # wrt u, also have wrt m
P = lambda v: rx.projectFieldsDeriv(src, self.mesh, u, v) # wrt u, also have wrt m
Jv[src, rx] = P(Df_Dm)
Ainv.clean()
return Utils.mkvc(Jv)
def Jtvec(self, m, v, f=None):
def Jtvec(self, m, v, u=None):
"""
Sensitivity transpose times a vector
Sensitivity transpose times a vector
:param numpy.array m: inversion model (nP,)
:param numpy.array v: vector which we take adjoint product with (nP,)
:param SimPEG.EM.FDEM.Fields u: fields object
:rtype numpy.array:
:return: Jv (ndata,)
"""
if f is None:
f = self.fields(m)
if u is None:
u = self.fields(m)
self.curModel = m
@@ -113,12 +133,12 @@ class BaseFDEMProblem(BaseEMProblem):
for src in self.survey.getSrcByFreq(freq):
ftype = self._fieldType + 'Solution'
u_src = f[src, ftype]
u_src = u[src, ftype]
for rx in src.rxList:
PTv = rx.projectFieldsDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
PTv = rx.projectFieldsDeriv(src, self.mesh, u, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
df_duTFun = getattr(f, '_%sDeriv_u'%rx.projField, None)
df_duTFun = getattr(u, '_%sDeriv_u'%rx.projField, None)
df_duT = df_duTFun(src, PTv, adjoint=True)
ATinvdf_duT = ATinv * df_duT
@@ -127,11 +147,12 @@ class BaseFDEMProblem(BaseEMProblem):
dRHS_dmT = self.getRHSDeriv_m(freq,src, ATinvdf_duT, adjoint=True)
du_dmT = -dA_dmT + dRHS_dmT
df_dmFun = getattr(f, '_%sDeriv_m'%rx.projField, None)
df_dmFun = getattr(u, '_%sDeriv_m'%rx.projField, None)
dfT_dm = df_dmFun(src, PTv, adjoint=True)
du_dmT += dfT_dm
# TODO: this should be taken care of by the reciever
real_or_imag = rx.projComp
if real_or_imag is 'real':
Jtv += np.array(du_dmT,dtype=complex).real
@@ -139,16 +160,18 @@ class BaseFDEMProblem(BaseEMProblem):
Jtv += - np.array(du_dmT,dtype=complex).real
else:
raise Exception('Must be real or imag')
ATinv.clean()
return Jtv
return Utils.mkvc(Jtv)
def getSourceTerm(self, freq):
"""
Evaluates the sources for a given frequency and puts them in matrix form
Evaluates the sources for a given frequency and puts them in matrix form
:param float freq: Frequency
:rtype: numpy.ndarray (nE or nF, nSrc)
:return: S_m, S_e
:param float freq: Frequency
:rtype: (numpy.ndarray, numpy.ndarray)
:return: S_m, S_e (nE or nF, nSrc)
"""
Srcs = self.survey.getSrcByFreq(freq)
if self._eqLocs is 'FE':
@@ -172,20 +195,22 @@ class BaseFDEMProblem(BaseEMProblem):
class Problem_e(BaseFDEMProblem):
"""
By eliminating the magnetic flux density using
.. math ::
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} + \mathbf{s_m}\\right)
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
By eliminating the magnetic flux density using
.. math ::
\\left(\mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} \mathbf{C}+ i \omega \mathbf{M^e_{\sigma}} \\right)\mathbf{e} = \mathbf{C}^T \mathbf{M_{\mu^{-1}}^f}\mathbf{s_m} -i\omega\mathbf{M^e}\mathbf{s_e}
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} + \mathbf{s_m}\\right)
which we solve for \\\(\\\mathbf{e}\\\).
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
.. math ::
\\left(\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{C}+ i \omega \mathbf{M^e_{\sigma}} \\right)\mathbf{e} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}\mathbf{s_m} -i\omega\mathbf{M^e}\mathbf{s_e}
which we solve for :math:`\mathbf{e}`.
:param SimPEG.Mesh mesh: mesh
"""
_fieldType = 'e'
@@ -197,13 +222,16 @@ class Problem_e(BaseFDEMProblem):
def getA(self, freq):
"""
.. math ::
\mathbf{A} = \mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} \mathbf{C} + i \omega \mathbf{M^e_{\sigma}}
System matrix
.. math ::
\mathbf{A} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{C} + i \omega \mathbf{M^e_{\sigma}}
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
MfMui = self.MfMui
MeSigma = self.MeSigma
C = self.mesh.edgeCurl
@@ -212,6 +240,20 @@ class Problem_e(BaseFDEMProblem):
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
Product of the derivative of our system matrix with respect to the model and a vector
.. math ::
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = i \omega \\frac{d \mathbf{M^e_{\sigma}}\mathbf{v} }{d\mathbf{m}}
:param float freq: frequency
:param numpy.ndarray u: solution vector (nE,)
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
"""
dsig_dm = self.curModel.sigmaDeriv
dMe_dsig = self.MeSigmaDeriv(u)
@@ -222,26 +264,37 @@ class Problem_e(BaseFDEMProblem):
def getRHS(self, freq):
"""
.. math ::
\mathbf{RHS} = \mathbf{C}^T \mathbf{M_{\mu^{-1}}^f}\mathbf{s_m} -i\omega\mathbf{M_e}\mathbf{s_e}
Right hand side for the system
:param float freq: Frequency
:rtype: numpy.ndarray (nE, nSrc)
:return: RHS
.. math ::
\mathbf{RHS} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}\mathbf{s_m} -i\omega\mathbf{M_e}\mathbf{s_e}
:param float freq: Frequency
:rtype: numpy.ndarray
:return: RHS (nE, nSrc)
"""
S_m, S_e = self.getSourceTerm(freq)
C = self.mesh.edgeCurl
MfMui = self.MfMui
RHS = C.T * (MfMui * S_m) -1j * omega(freq) * S_e
return RHS
return C.T * (MfMui * S_m) -1j * omega(freq) * S_e
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
:param float freq: frequency
:param SimPEG.EM.FDEM.Src src: FDEM source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of rhs deriv with a vector
"""
C = self.mesh.edgeCurl
MfMui = self.MfMui
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint)
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
if adjoint:
dRHS = MfMui * (C * v)
@@ -252,20 +305,22 @@ class Problem_e(BaseFDEMProblem):
class Problem_b(BaseFDEMProblem):
"""
We eliminate \\\(\\\mathbf{e}\\\) using
We eliminate :math:`\mathbf{e}` using
.. math ::
.. math ::
\mathbf{e} = \mathbf{M^e_{\sigma}}^{-1} \\left(\mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{s_e}\\right)
\mathbf{e} = \mathbf{M^e_{\sigma}}^{-1} \\left(\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{s_e}\\right)
and solve for \\\(\\\mathbf{b}\\\) using:
and solve for :math:`\mathbf{b}` using:
.. math ::
.. math ::
\\left(\mathbf{C} \mathbf{M^e_{\sigma}}^{-1} \mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} + i \omega \\right)\mathbf{b} = \mathbf{s_m} + \mathbf{M^e_{\sigma}}^{-1}\mathbf{M^e}\mathbf{s_e}
\\left(\mathbf{C} \mathbf{M^e_{\sigma}}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} + i \omega \\right)\mathbf{b} = \mathbf{s_m} + \mathbf{M^e_{\sigma}}^{-1}\mathbf{M^e}\mathbf{s_e}
.. note ::
The inverse problem will not work with full anisotropy
.. note ::
The inverse problem will not work with full anisotropy
:param SimPEG.Mesh mesh: mesh
"""
_fieldType = 'b'
@@ -277,12 +332,14 @@ class Problem_b(BaseFDEMProblem):
def getA(self, freq):
"""
.. math ::
\mathbf{A} = \mathbf{C} \mathbf{M^e_{\sigma}}^{-1} \mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} + i \omega
System matrix
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
.. math ::
\mathbf{A} = \mathbf{C} \mathbf{M^e_{\sigma}}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} + i \omega
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
MfMui = self.MfMui
@@ -298,6 +355,20 @@ class Problem_b(BaseFDEMProblem):
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
Product of the derivative of our system matrix with respect to the model and a vector
.. math ::
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = \mathbf{C} \\frac{\mathbf{M^e_{\sigma}} \mathbf{v}}{d\mathbf{m}}
:param float freq: frequency
:param numpy.ndarray u: solution vector (nF,)
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
"""
MfMui = self.MfMui
C = self.mesh.edgeCurl
MeSigmaIDeriv = self.MeSigmaIDeriv
@@ -317,12 +388,14 @@ class Problem_b(BaseFDEMProblem):
def getRHS(self, freq):
"""
.. math ::
\mathbf{RHS} = \mathbf{s_m} + \mathbf{M^e_{\sigma}}^{-1}\mathbf{s_e}
Right hand side for the system
:param float freq: Frequency
:rtype: numpy.ndarray (nE, nSrc)
:return: RHS
.. math ::
\mathbf{RHS} = \mathbf{s_m} + \mathbf{M^e_{\sigma}}^{-1}\mathbf{s_e}
:param float freq: Frequency
:rtype: numpy.ndarray
:return: RHS (nE, nSrc)
"""
S_m, S_e = self.getSourceTerm(freq)
@@ -338,6 +411,17 @@ class Problem_b(BaseFDEMProblem):
return RHS
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
:param float freq: frequency
:param SimPEG.EM.FDEM.Src src: FDEM source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of rhs deriv with a vector
"""
C = self.mesh.edgeCurl
S_m, S_e = src.eval(self)
MfMui = self.MfMui
@@ -346,7 +430,7 @@ class Problem_b(BaseFDEMProblem):
v = self.MfMui * v
MeSigmaIDeriv = self.MeSigmaIDeriv(S_e)
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint)
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
if not adjoint:
RHSderiv = C * (MeSigmaIDeriv * v)
@@ -369,21 +453,22 @@ class Problem_b(BaseFDEMProblem):
class Problem_j(BaseFDEMProblem):
"""
We eliminate \\\(\\\mathbf{h}\\\) using
We eliminate \\\(\\\mathbf{h}\\\) using
.. math ::
.. math ::
\mathbf{h} = \\frac{1}{i \omega} \mathbf{M_{\mu}^e}^{-1} \\left(-\mathbf{C}^T \mathbf{M_{\\rho}^f} \mathbf{j} + \mathbf{M^e} \mathbf{s_m} \\right)
\mathbf{h} = \\frac{1}{i \omega} \mathbf{M_{\mu}^e}^{-1} \\left(-\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + \mathbf{M^e} \mathbf{s_m} \\right)
and solve for \\\(\\\mathbf{j}\\\) using
and solve for \\\(\\\mathbf{j}\\\) using
.. math ::
.. math ::
\\left(\mathbf{C} \mathbf{M_{\mu}^e}^{-1} \mathbf{C}^T \mathbf{M_{\\rho}^f} + i \omega\\right)\mathbf{j} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1} \mathbf{M^e} \mathbf{s_m} -i\omega\mathbf{s_e}
\\left(\mathbf{C} \mathbf{M_{\mu}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} + i \omega\\right)\mathbf{j} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1} \mathbf{M^e} \mathbf{s_m} -i\omega\mathbf{s_e}
.. note::
This implementation does not yet work with full anisotropy!!
.. note::
This implementation does not yet work with full anisotropy!!
:param SimPEG.Mesh mesh: mesh
"""
_fieldType = 'j'
@@ -395,12 +480,14 @@ class Problem_j(BaseFDEMProblem):
def getA(self, freq):
"""
.. math ::
\\mathbf{A} = \\mathbf{C} \\mathbf{M^e_{mu^{-1}}} \\mathbf{C}^T \\mathbf{M^f_{\\sigma^{-1}}} + i\\omega
System matrix
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
.. math ::
\\mathbf{A} = \\mathbf{C} \\mathbf{M^e_{\\mu^{-1}}} \\mathbf{C}^{\\top} \\mathbf{M^f_{\\sigma^{-1}}} + i\\omega
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
MeMuI = self.MeMuI
@@ -417,12 +504,20 @@ class Problem_j(BaseFDEMProblem):
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
In this case, we assume that electrical conductivity, \\\(\\\sigma\\\) is the physical property of interest (i.e. \\\(\\\sigma\\\) = model.transform). Then we want
Product of the derivative of our system matrix with respect to the model and a vector
.. math ::
In this case, we assume that electrical conductivity, :math:`\sigma` is the physical property of interest (i.e. :math:`\sigma` = model.transform). Then we want
\\frac{\mathbf{A(\sigma)} \mathbf{v}}{d \\mathbf{m}} &= \\mathbf{C} \\mathbf{M^e_{mu^{-1}}} \\mathbf{C^T} \\frac{d \\mathbf{M^f_{\\sigma^{-1}}}}{d \\mathbf{m}}
&= \\mathbf{C} \\mathbf{M^e_{mu}^{-1}} \\mathbf{C^T} \\frac{d \\mathbf{M^f_{\\sigma^{-1}}}}{d \\mathbf{\\sigma^{-1}}} \\frac{d \\mathbf{\\sigma^{-1}}}{d \\mathbf{\\sigma}} \\frac{d \\mathbf{\\sigma}}{d \\mathbf{m}}
.. math ::
\\frac{\mathbf{A(\sigma)} \mathbf{v}}{d \mathbf{m}} = \mathbf{C} \mathbf{M^e_{mu^{-1}}} \mathbf{C^{\\top}} \\frac{d \mathbf{M^f_{\sigma^{-1}}}\mathbf{v} }{d \mathbf{m}}
:param float freq: frequency
:param numpy.ndarray u: solution vector (nF,)
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
"""
MeMuI = self.MeMuI
@@ -442,12 +537,15 @@ class Problem_j(BaseFDEMProblem):
def getRHS(self, freq):
"""
.. math ::
Right hand side for the system
\mathbf{RHS} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1}\mathbf{s_m} -i\omega \mathbf{s_e}
:param float freq: Frequency
:rtype: numpy.ndarray (nE, nSrc)
:return: RHS
.. math ::
\mathbf{RHS} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1}\mathbf{s_m} -i\omega \mathbf{s_e}
:param float freq: Frequency
:rtype: numpy.ndarray (nE, nSrc)
:return: RHS
"""
S_m, S_e = self.getSourceTerm(freq)
@@ -462,9 +560,20 @@ class Problem_j(BaseFDEMProblem):
return RHS
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
:param float freq: frequency
:param SimPEG.EM.FDEM.Src src: FDEM source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of rhs deriv with a vector
"""
C = self.mesh.edgeCurl
MeMuI = self.MeMuI
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint)
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
if adjoint:
if self._makeASymmetric:
@@ -485,18 +594,19 @@ class Problem_j(BaseFDEMProblem):
class Problem_h(BaseFDEMProblem):
"""
We eliminate \\\(\\\mathbf{j}\\\) using
We eliminate \\\(\\\mathbf{j}\\\) using
.. math ::
.. math ::
\mathbf{j} = \mathbf{C} \mathbf{h} - \mathbf{s_e}
\mathbf{j} = \mathbf{C} \mathbf{h} - \mathbf{s_e}
and solve for \\\(\\\mathbf{h}\\\) using
and solve for \\\(\\\mathbf{h}\\\) using
.. math ::
.. math ::
\\left(\mathbf{C}^T \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}\\right) \mathbf{h} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^T \mathbf{M_{\\rho}^f} \mathbf{s_e}
\\left(\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}\\right) \mathbf{h} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{s_e}
:param SimPEG.Mesh mesh: mesh
"""
_fieldType = 'h'
@@ -508,13 +618,14 @@ class Problem_h(BaseFDEMProblem):
def getA(self, freq):
"""
.. math ::
System matrix
\mathbf{A} = \mathbf{C}^T \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}
.. math::
\mathbf{A} = \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
MeMu = self.MeMu
@@ -524,6 +635,19 @@ class Problem_h(BaseFDEMProblem):
return C.T * (MfRho * C) + 1j*omega(freq)*MeMu
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
Product of the derivative of our system matrix with respect to the model and a vector
.. math::
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = \mathbf{C}^{\\top}\\frac{d \mathbf{M^f_{\\rho}}\mathbf{v} }{d\mathbf{m}}
:param float freq: frequency
:param numpy.ndarray u: solution vector (nE,)
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
"""
MeMu = self.MeMu
C = self.mesh.edgeCurl
@@ -535,24 +659,35 @@ class Problem_h(BaseFDEMProblem):
def getRHS(self, freq):
"""
.. math ::
Right hand side for the system
\mathbf{RHS} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^T \mathbf{M_{\\rho}^f} \mathbf{s_e}
.. math ::
:param float freq: Frequency
:rtype: numpy.ndarray (nE, nSrc)
:return: RHS
\mathbf{RHS} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{s_e}
:param float freq: Frequency
:rtype: numpy.ndarray
:return: RHS (nE, nSrc)
"""
S_m, S_e = self.getSourceTerm(freq)
C = self.mesh.edgeCurl
MfRho = self.MfRho
RHS = S_m + C.T * ( MfRho * S_e )
return RHS
return S_m + C.T * ( MfRho * S_e )
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
:param float freq: frequency
:param SimPEG.EM.FDEM.Src src: FDEM source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of rhs deriv with a vector
"""
_, S_e = src.eval(self)
C = self.mesh.edgeCurl
MfRho = self.MfRho
@@ -563,7 +698,7 @@ class Problem_h(BaseFDEMProblem):
elif adjoint:
RHSDeriv = MfRhoDeriv.T * (C * v)
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint)
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
return RHSDeriv + S_mDeriv(v) + C.T * (MfRho * S_eDeriv(v))
+512 -9
View File
@@ -7,11 +7,39 @@ from SimPEG.Utils import Zero, Identity
class Fields(SimPEG.Problem.Fields):
"""Fancy Field Storage for a FDEM survey."""
"""
Fancy Field Storage for a FDEM survey. Only one field type is stored for
each problem, the rest are computed. The fields obejct acts like an array and is indexed by
.. code-block:: python
f = problem.fields(m)
e = f[srcList,'e']
b = f[srcList,'b']
If accessing all sources for a given field, use the :code:`:`
.. code-block:: python
f = problem.fields(m)
e = f[:,'e']
b = f[:,'b']
The array returned will be size (nE or nF, nSrcs :math:`\\times` nFrequencies)
"""
knownFields = {}
dtype = complex
class Fields_e(Fields):
"""
Fields object for Problem_e.
:param Mesh mesh: mesh
:param Survey survey: survey
"""
knownFields = {'eSolution':'E'}
aliasFields = {
'e' : ['eSolution','E','_e'],
@@ -30,6 +58,15 @@ class Fields_e(Fields):
self._edgeCurl = self.survey.prob.mesh.edgeCurl
def _ePrimary(self, eSolution, srcList):
"""
Primary electric field from source
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary electric field as defined by the sources
"""
ePrimary = np.zeros_like(eSolution)
for i, src in enumerate(srcList):
ep = src.ePrimary(self.prob)
@@ -37,19 +74,67 @@ class Fields_e(Fields):
return ePrimary
def _eSecondary(self, eSolution, srcList):
"""
Secondary electric field is the thing we solved for
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary electric field
"""
return eSolution
def _e(self, eSolution, srcList):
"""
Total electric field is sum of primary and secondary
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total electric field
"""
return self._ePrimary(eSolution,srcList) + self._eSecondary(eSolution,srcList)
def _eDeriv_u(self, src, v, adjoint = False):
"""
Derivative of the total electric field with respect to the thing we
solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the electric field with respect to the field we solved for with a vector
"""
return Identity()*v
def _eDeriv_m(self, src, v, adjoint = False):
"""
Derivative of the total electric field with respect to the inversion model. Here, we assume that the primary does not depend on the model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: SimPEG.Utils.Zero
:return: product of the electric field derivative with respect to the inversion model with a vector
"""
# assuming primary does not depend on the model
return Zero()
def _bPrimary(self, eSolution, srcList):
"""
Primary magnetic flux density from source
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary magnetic flux density as defined by the sources
"""
bPrimary = np.zeros([self._edgeCurl.shape[0],eSolution.shape[1]],dtype = complex)
for i, src in enumerate(srcList):
bp = src.bPrimary(self.prob)
@@ -57,6 +142,15 @@ class Fields_e(Fields):
return bPrimary
def _bSecondary(self, eSolution, srcList):
"""
Secondary magnetic flux density from eSolution
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary magnetic flux density
"""
C = self._edgeCurl
b = (C * eSolution)
for i, src in enumerate(srcList):
@@ -66,29 +160,84 @@ class Fields_e(Fields):
return b
def _bSecondaryDeriv_u(self, src, v, adjoint = False):
"""
Derivative of the secondary magnetic flux density with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the secondary magnetic flux density with respect to the field we solved for with a vector
"""
C = self._edgeCurl
if adjoint:
return - 1./(1j*omega(src.freq)) * (C.T * v)
return - 1./(1j*omega(src.freq)) * (C * v)
def _bSecondaryDeriv_m(self, src, v, adjoint = False):
S_mDeriv, _ = src.evalDeriv(self.prob, adjoint)
S_mDeriv = S_mDeriv(v)
"""
Derivative of the secondary magnetic flux density with respect to the inversion model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the secondary magnetic flux density derivative with respect to the inversion model with a vector
"""
S_mDeriv, _ = src.evalDeriv(self.prob, v, adjoint)
return 1./(1j * omega(src.freq)) * S_mDeriv
def _b(self, eSolution, srcList):
"""
Total magnetic flux density is sum of primary and secondary
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total magnetic flux density
"""
return self._bPrimary(eSolution, srcList) + self._bSecondary(eSolution, srcList)
def _bDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total magnetic flux density with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the magnetic flux density with respect to the field we solved for with a vector
"""
# Primary does not depend on u
return self._bSecondaryDeriv_u(src, v, adjoint)
def _bDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total magnetic flux density with respect to the inversion model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: SimPEG.Utils.Zero
:return: product of the magnetic flux density derivative with respect to the inversion model with a vector
"""
# Assuming the primary does not depend on the model
return self._bSecondaryDeriv_m(src, v, adjoint)
class Fields_b(Fields):
"""
Fields object for Problem_b.
:param Mesh mesh: mesh
:param Survey survey: survey
"""
knownFields = {'bSolution':'F'}
aliasFields = {
'b' : ['bSolution','F','_b'],
@@ -111,6 +260,15 @@ class Fields_b(Fields):
self._Me = self.survey.prob.Me
def _bPrimary(self, bSolution, srcList):
"""
Primary magnetic flux density from source
:param numpy.ndarray bSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary electric field as defined by the sources
"""
bPrimary = np.zeros_like(bSolution)
for i, src in enumerate(srcList):
bp = src.bPrimary(self.prob)
@@ -118,19 +276,66 @@ class Fields_b(Fields):
return bPrimary
def _bSecondary(self, bSolution, srcList):
"""
Secondary magnetic flux density is the thing we solved for
:param numpy.ndarray bSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary magnetic flux density
"""
return bSolution
def _b(self, bSolution, srcList):
"""
Total magnetic flux density is sum of primary and secondary
:param numpy.ndarray bSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total magnetic flux density
"""
return self._bPrimary(bSolution, srcList) + self._bSecondary(bSolution, srcList)
def _bDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total magnetic flux density with respect to the thing we
solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the magnetic flux density with respect to the field we solved for with a vector
"""
return Identity()*v
def _bDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total magnetic flux density with respect to the inversion model. Here, we assume that the primary does not depend on the model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: SimPEG.Utils.Zero
:return: product of the magnetic flux density derivative with respect to the inversion model with a vector
"""
# assuming primary does not depend on the model
return Zero()
def _ePrimary(self, bSolution, srcList):
"""
Primary electric field from source
:param numpy.ndarray bSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary electric field as defined by the sources
"""
ePrimary = np.zeros([self._edgeCurl.shape[1],bSolution.shape[1]],dtype = complex)
for i,src in enumerate(srcList):
ep = src.ePrimary(self.prob)
@@ -138,6 +343,15 @@ class Fields_b(Fields):
return ePrimary
def _eSecondary(self, bSolution, srcList):
"""
Secondary electric field from bSolution
:param numpy.ndarray bSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary electric field
"""
e = self._MeSigmaI * ( self._edgeCurl.T * ( self._MfMui * bSolution))
for i,src in enumerate(srcList):
_,S_e = src.eval(self.prob)
@@ -145,12 +359,32 @@ class Fields_b(Fields):
return e
def _eSecondaryDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the secondary electric field with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the secondary electric field with respect to the field we solved for with a vector
"""
if not adjoint:
return self._MeSigmaI * ( self._edgeCurl.T * ( self._MfMui * v) )
else:
return self._MfMui.T * (self._edgeCurl * (self._MeSigmaI.T * v))
def _eSecondaryDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the secondary electric field with respect to the inversion model
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the secondary electric field with respect to the model with a vector
"""
bSolution = self[[src],'bSolution']
_,S_e = src.eval(self.prob)
Me = self._Me
@@ -166,25 +400,60 @@ class Fields_b(Fields):
elif adjoint:
de_dm = self._MeSigmaIDeriv(w).T * v
_, S_eDeriv = src.evalDeriv(self.prob, adjoint)
Se_Deriv = S_eDeriv(v)
_, S_eDeriv = src.evalDeriv(self.prob, v, adjoint)
de_dm = de_dm - self._MeSigmaI * Se_Deriv
de_dm = de_dm - self._MeSigmaI * S_eDeriv
return de_dm
def _e(self, bSolution, srcList):
"""
Total electric field is sum of primary and secondary
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total electric field
"""
return self._ePrimary(bSolution, srcList) + self._eSecondary(bSolution, srcList)
def _eDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total electric field with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the electric field with respect to the field we solved for with a vector
"""
return self._eSecondaryDeriv_u(src, v, adjoint)
def _eDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total electric field density with respect to the inversion model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the electric field derivative with respect to the inversion model with a vector
"""
# assuming primary doesn't depend on model
return self._eSecondaryDeriv_m(src, v, adjoint)
class Fields_j(Fields):
"""
Fields object for Problem_j.
:param Mesh mesh: mesh
:param Survey survey: survey
"""
knownFields = {'jSolution':'F'}
aliasFields = {
'j' : ['jSolution','F','_j'],
@@ -207,6 +476,15 @@ class Fields_j(Fields):
self._Me = self.survey.prob.Me
def _jPrimary(self, jSolution, srcList):
"""
Primary current density from source
:param numpy.ndarray jSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary current density as defined by the sources
"""
jPrimary = np.zeros_like(jSolution,dtype = complex)
for i, src in enumerate(srcList):
jp = src.jPrimary(self.prob)
@@ -214,19 +492,66 @@ class Fields_j(Fields):
return jPrimary
def _jSecondary(self, jSolution, srcList):
"""
Secondary current density is the thing we solved for
:param numpy.ndarray jSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary current density
"""
return jSolution
def _j(self, jSolution, srcList):
"""
Total current density is sum of primary and secondary
:param numpy.ndarray jSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total current density
"""
return self._jPrimary(jSolution, srcList) + self._jSecondary(jSolution, srcList)
def _jDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total current density with respect to the thing we
solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the current density with respect to the field we solved for with a vector
"""
return Identity()*v
def _jDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total current density with respect to the inversion model. Here, we assume that the primary does not depend on the model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: SimPEG.Utils.Zero
:return: product of the current density derivative with respect to the inversion model with a vector
"""
# assuming primary does not depend on the model
return Zero()
def _hPrimary(self, jSolution, srcList):
"""
Primary magnetic field from source
:param numpy.ndarray hSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary magnetic field as defined by the sources
"""
hPrimary = np.zeros([self._edgeCurl.shape[1],jSolution.shape[1]],dtype = complex)
for i, src in enumerate(srcList):
hp = src.hPrimary(self.prob)
@@ -234,6 +559,15 @@ class Fields_j(Fields):
return hPrimary
def _hSecondary(self, jSolution, srcList):
"""
Secondary magnetic field from bSolution
:param numpy.ndarray jSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary magnetic field
"""
h = self._MeMuI * (self._edgeCurl.T * (self._MfRho * jSolution) )
for i, src in enumerate(srcList):
h[:,i] *= -1./(1j*omega(src.freq))
@@ -242,12 +576,32 @@ class Fields_j(Fields):
return h
def _hSecondaryDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the secondary magnetic field with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the secondary magnetic field with respect to the field we solved for with a vector
"""
if not adjoint:
return -1./(1j*omega(src.freq)) * self._MeMuI * (self._edgeCurl.T * (self._MfRho * v) )
elif adjoint:
return -1./(1j*omega(src.freq)) * self._MfRho.T * (self._edgeCurl * ( self._MeMuI.T * v))
def _hSecondaryDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the secondary magnetic field with respect to the inversion model
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the secondary magnetic field with respect to the model with a vector
"""
jSolution = self[[src],'jSolution']
MeMuI = self._MeMuI
C = self._edgeCurl
@@ -260,7 +614,7 @@ class Fields_j(Fields):
elif adjoint:
hDeriv_m = -1./(1j*omega(src.freq)) * MfRhoDeriv(jSolution).T * ( C * (MeMuI.T * v ) )
S_mDeriv,_ = src.evalDeriv(self.prob, adjoint)
S_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
if not adjoint:
S_mDeriv = S_mDeriv(v)
@@ -272,17 +626,53 @@ class Fields_j(Fields):
def _h(self, jSolution, srcList):
"""
Total magnetic field is sum of primary and secondary
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total magnetic field
"""
return self._hPrimary(jSolution, srcList) + self._hSecondary(jSolution, srcList)
def _hDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total magnetic field with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the magnetic field with respect to the field we solved for with a vector
"""
return self._hSecondaryDeriv_u(src, v, adjoint)
def _hDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total magnetic field density with respect to the inversion model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the magnetic field derivative with respect to the inversion model with a vector
"""
# assuming the primary doesn't depend on the model
return self._hSecondaryDeriv_m(src, v, adjoint)
class Fields_h(Fields):
"""
Fields object for Problem_h.
:param Mesh mesh: mesh
:param Survey survey: survey
"""
knownFields = {'hSolution':'E'}
aliasFields = {
'h' : ['hSolution','E','_h'],
@@ -303,6 +693,15 @@ class Fields_h(Fields):
self._MfRho = self.survey.prob.MfRho
def _hPrimary(self, hSolution, srcList):
"""
Primary magnetic field from source
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary magnetic field as defined by the sources
"""
hPrimary = np.zeros_like(hSolution,dtype = complex)
for i, src in enumerate(srcList):
hp = src.hPrimary(self.prob)
@@ -310,19 +709,67 @@ class Fields_h(Fields):
return hPrimary
def _hSecondary(self, hSolution, srcList):
"""
Secondary magnetic field is the thing we solved for
:param numpy.ndarray hSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary magnetic field
"""
return hSolution
def _h(self, hSolution, srcList):
"""
Total magnetic field is sum of primary and secondary
:param numpy.ndarray hSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total magnetic field
"""
return self._hPrimary(hSolution, srcList) + self._hSecondary(hSolution, srcList)
def _hDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total magnetic field with respect to the thing we
solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the magnetic field with respect to the field we solved for with a vector
"""
return Identity()*v
def _hDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total magnetic field with respect to the inversion model. Here, we assume that the primary does not depend on the model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: SimPEG.Utils.Zero
:return: product of the magnetic field derivative with respect to the inversion model with a vector
"""
# assuming primary does not depend on the model
return Zero()
def _jPrimary(self, hSolution, srcList):
"""
Primary current density from source
:param numpy.ndarray hSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: primary current density as defined by the sources
"""
jPrimary = np.zeros([self._edgeCurl.shape[0], hSolution.shape[1]], dtype = complex)
for i, src in enumerate(srcList):
jp = src.jPrimary(self.prob)
@@ -330,6 +777,15 @@ class Fields_h(Fields):
return jPrimary
def _jSecondary(self, hSolution, srcList):
"""
Secondary current density from eSolution
:param numpy.ndarray hSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: secondary current density
"""
j = self._edgeCurl*hSolution
for i, src in enumerate(srcList):
_,S_e = src.eval(self.prob)
@@ -337,22 +793,69 @@ class Fields_h(Fields):
return j
def _jSecondaryDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the secondary current density with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the secondary current density with respect to the field we solved for with a vector
"""
if not adjoint:
return self._edgeCurl*v
elif adjoint:
return self._edgeCurl.T*v
def _jSecondaryDeriv_m(self, src, v, adjoint=False):
_,S_eDeriv = src.evalDeriv(self.prob, adjoint)
S_eDeriv = S_eDeriv(v)
"""
Derivative of the secondary current density with respect to the inversion model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the secondary current density derivative with respect to the inversion model with a vector
"""
_,S_eDeriv = src.evalDeriv(self.prob, v, adjoint)
return -S_eDeriv
def _j(self, hSolution, srcList):
"""
Total current density is sum of primary and secondary
:param numpy.ndarray eSolution: field we solved for
:param list srcList: list of sources
:rtype: numpy.ndarray
:return: total current density
"""
return self._jPrimary(hSolution, srcList) + self._jSecondary(hSolution, srcList)
def _jDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the total current density with respect to the thing we solved for
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of the derivative of the current density with respect to the field we solved for with a vector
"""
return self._jSecondaryDeriv_u(src,v,adjoint)
def _jDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the total current density with respect to the inversion model.
:param SimPEG.EM.FDEM.Src src: source
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: SimPEG.Utils.Zero
:return: product of the current density with respect to the inversion model with a vector
"""
# assuming the primary does not depend on the model
return self._jSecondaryDeriv_m(src,v,adjoint)
+274 -19
View File
@@ -1,55 +1,141 @@
from SimPEG import Survey, Problem, Utils, np, sp
from scipy.constants import mu_0
from SimPEG.EM.Utils import *
from SimPEG.Utils import Zero
# from SurveyFDEM import Rx
from SimPEG.Utils import Zero
class BaseSrc(Survey.BaseSrc):
"""
Base source class for FDEM Survey
"""
freq = None
# rxPair = Rx
# rxPair = RxFDEM
integrate = True
def eval(self, prob):
"""
Evaluate the source terms.
- :math:`S_m` : magnetic source term
- :math:`S_e` : electric source term
:param Problem prob: FDEM Problem
:rtype: (numpy.ndarray, numpy.ndarray)
:return: tuple with magnetic source term and electric source term
"""
S_m = self.S_m(prob)
S_e = self.S_e(prob)
return S_m, S_e
def evalDeriv(self, prob, adjoint=False):
return lambda v: self.S_mDeriv(prob,v,adjoint), lambda v: self.S_eDeriv(prob,v,adjoint)
def evalDeriv(self, prob, v=None, adjoint=False):
"""
Derivatives of the source terms with respect to the inversion model
- :code:`S_mDeriv` : derivative of the magnetic source term
- :code:`S_eDeriv` : derivative of the electric source term
:param Problem prob: FDEM Problem
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: (numpy.ndarray, numpy.ndarray)
:return: tuple with magnetic source term and electric source term derivatives times a vector
"""
if v is not None:
return self.S_mDeriv(prob,v,adjoint), self.S_eDeriv(prob,v,adjoint)
else:
return lambda v: self.S_mDeriv(prob,v,adjoint), lambda v: self.S_eDeriv(prob,v,adjoint)
def bPrimary(self, prob):
"""
Primary magnetic flux density
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: primary magnetic flux density
"""
return Zero()
def hPrimary(self, prob):
"""
Primary magnetic field
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
return Zero()
def ePrimary(self, prob):
"""
Primary electric field
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: primary electric field
"""
return Zero()
def jPrimary(self, prob):
"""
Primary current density
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: primary current density
"""
return Zero()
def S_m(self, prob):
"""
Magnetic source term
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: magnetic source term on mesh
"""
return Zero()
def S_e(self, prob):
"""
Electric source term
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: electric source term on mesh
"""
return Zero()
def S_mDeriv(self, prob, v, adjoint = False):
"""
Derivative of magnetic source term with respect to the inversion model
:param Problem prob: FDEM Problem
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of magnetic source term derivative with a vector
"""
return Zero()
def S_eDeriv(self, prob, v, adjoint = False):
"""
Derivative of electric source term with respect to the inversion model
:param Problem prob: FDEM Problem
:param numpy.ndarray v: vector to take product with
:param bool adjoint: adjoint?
:rtype: numpy.ndarray
:return: product of electric source term derivative with a vector
"""
return Zero()
class RawVec_e(BaseSrc):
"""
RawVec electric source. It is defined by the user provided vector S_e
RawVec electric source. It is defined by the user provided vector S_e
:param numpy.array S_e: electric source term
:param float freq: frequency
:param rxList: receiver list
:param list rxList: receiver list
:param float freq: frequency
:param numpy.array S_e: electric source term
"""
def __init__(self, rxList, freq, S_e): #, ePrimary=None, bPrimary=None, hPrimary=None, jPrimary=None):
@@ -58,16 +144,17 @@ class RawVec_e(BaseSrc):
BaseSrc.__init__(self, rxList)
def S_e(self, prob):
return self._S_e
class RawVec_m(BaseSrc):
"""
RawVec magnetic source. It is defined by the user provided vector S_m
RawVec magnetic source. It is defined by the user provided vector S_m
:param numpy.array S_m: magnetic source term
:param float freq: frequency
:param rxList: receiver list
:param float freq: frequency
:param rxList: receiver list
:param numpy.array S_m: magnetic source term
"""
def __init__(self, rxList, freq, S_m, integrate = True): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
@@ -78,17 +165,24 @@ class RawVec_m(BaseSrc):
BaseSrc.__init__(self, rxList)
def S_m(self, prob):
"""
Magnetic source term
:param Problem prob: FDEM Problem
:rtype: numpy.ndarray
:return: magnetic source term on mesh
"""
return self._S_m
class RawVec(BaseSrc):
"""
RawVec source. It is defined by the user provided vectors S_m, S_e
RawVec source. It is defined by the user provided vectors S_m, S_e
:param numpy.array S_m: magnetic source term
:param numpy.array S_e: electric source term
:param float freq: frequency
:param rxList: receiver list
:param rxList: receiver list
:param float freq: frequency
:param numpy.array S_m: magnetic source term
:param numpy.array S_e: electric source term
"""
def __init__(self, rxList, freq, S_m, S_e, integrate = True):
self._S_m = np.array(S_m,dtype=complex)
@@ -109,6 +203,51 @@ class RawVec(BaseSrc):
class MagDipole(BaseSrc):
"""
Point magnetic dipole source calculated by taking the curl of a magnetic
vector potential. By taking the discrete curl, we ensure that the magnetic
flux density is divergence free (no magnetic monopoles!).
This approach uses a primary-secondary in frequency. Here we show the
derivation for E-B formulation noting that similar steps are followed for
the H-J formulation.
.. math::
\mathbf{C} \mathbf{e} + i \omega \mathbf{b} = \mathbf{s_m} \\\\
{\mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{s_e}}
We split up the fields and :math:`\mu^{-1}` into primary (:math:`\mathbf{P}`) and secondary (:math:`\mathbf{S}`) components
- :math:`\mathbf{e} = \mathbf{e^P} + \mathbf{e^S}`
- :math:`\mathbf{b} = \mathbf{b^P} + \mathbf{b^S}`
- :math:`\\boldsymbol{\mu}^{\mathbf{-1}} = \\boldsymbol{\mu}^{\mathbf{-1}^\mathbf{P}} + \\boldsymbol{\mu}^{\mathbf{-1}^\mathbf{S}}`
and define a zero-frequency primary problem, noting that the source is
generated by a divergence free electric current
.. math::
\mathbf{C} \mathbf{e^P} = \mathbf{s_m^P} = 0 \\\\
{\mathbf{C}^T \mathbf{{M_{\mu^{-1}}^f}^P} \mathbf{b^P} - \mathbf{M_{\sigma}^e} \mathbf{e^P} = \mathbf{M^e} \mathbf{s_e^P}}
Since :math:`\mathbf{e^P}` is curl-free, divergence-free, we assume that there is no constant field background, the :math:`\mathbf{e^P} = 0`, so our primary problem is
.. math::
\mathbf{e^P} = 0 \\\\
{\mathbf{C}^T \mathbf{{M_{\mu^{-1}}^f}^P} \mathbf{b^P} = \mathbf{s_e^P}}
Our secondary problem is then
.. math::
\mathbf{C} \mathbf{e^S} + i \omega \mathbf{b^S} = - i \omega \mathbf{b^P} \\\\
{\mathbf{C}^T \mathbf{M_{\mu^{-1}}^f} \mathbf{b^S} - \mathbf{M_{\sigma}^e} \mathbf{e^S} = -\mathbf{C}^T \mathbf{{M_{\mu^{-1}}^f}^S} \mathbf{b^P}}
:param list rxList: receiver list
:param float freq: frequency
:param numpy.ndarray loc: source location (ie: :code:`np.r_[xloc,yloc,zloc]`)
:param string orientation: 'X', 'Y', 'Z'
:param float moment: magnetic dipole moment
:param float mu: background magnetic permeability
"""
#TODO: right now, orientation doesn't actually do anything! The methods in SrcUtils should take care of that
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu = mu_0):
@@ -121,6 +260,13 @@ class MagDipole(BaseSrc):
BaseSrc.__init__(self, rxList)
def bPrimary(self, prob):
"""
The primary magnetic flux density from a magnetic vector potential
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
eqLocs = prob._eqLocs
if eqLocs is 'FE':
@@ -152,14 +298,37 @@ class MagDipole(BaseSrc):
return C*a
def hPrimary(self, prob):
"""
The primary magnetic field from a magnetic vector potential
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
b = self.bPrimary(prob)
return h_from_b(prob,b)
def S_m(self, prob):
"""
The magnetic source term
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
b_p = self.bPrimary(prob)
return -1j*omega(self.freq)*b_p
def S_e(self, prob):
"""
The electric source term
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
if all(np.r_[self.mu] == np.r_[prob.curModel.mu]):
return Zero()
else:
@@ -179,6 +348,21 @@ class MagDipole(BaseSrc):
class MagDipole_Bfield(BaseSrc):
"""
Point magnetic dipole source calculated with the analytic solution for the
fields from a magnetic dipole. No discrete curl is taken, so the magnetic
flux density may not be strictly divergence free.
This approach uses a primary-secondary in frequency in the same fashion as the MagDipole.
:param list rxList: receiver list
:param float freq: frequency
:param numpy.ndarray loc: source location (ie: :code:`np.r_[xloc,yloc,zloc]`)
:param string orientation: 'X', 'Y', 'Z'
:param float moment: magnetic dipole moment
:param float mu: background magnetic permeability
"""
#TODO: right now, orientation doesn't actually do anything! The methods in SrcUtils should take care of that
#TODO: neither does moment
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu = mu_0):
@@ -190,6 +374,14 @@ class MagDipole_Bfield(BaseSrc):
BaseSrc.__init__(self, rxList)
def bPrimary(self, prob):
"""
The primary magnetic flux density from the analytic solution for magnetic fields from a dipole
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
eqLocs = prob._eqLocs
if eqLocs is 'FE':
@@ -221,14 +413,35 @@ class MagDipole_Bfield(BaseSrc):
return b
def hPrimary(self, prob):
"""
The primary magnetic field from a magnetic vector potential
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
b = self.bPrimary(prob)
return h_from_b(prob, b)
def S_m(self, prob):
"""
The magnetic source term
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
b = self.bPrimary(prob)
return -1j*omega(self.freq)*b
def S_e(self, prob):
"""
The electric source term
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
if all(np.r_[self.mu] == np.r_[prob.curModel.mu]):
return Zero()
else:
@@ -247,6 +460,20 @@ class MagDipole_Bfield(BaseSrc):
class CircularLoop(BaseSrc):
"""
Circular loop magnetic source calculated by taking the curl of a magnetic
vector potential. By taking the discrete curl, we ensure that the magnetic
flux density is divergence free (no magnetic monopoles!).
This approach uses a primary-secondary in frequency in the same fashion as the MagDipole.
:param list rxList: receiver list
:param float freq: frequency
:param numpy.ndarray loc: source location (ie: :code:`np.r_[xloc,yloc,zloc]`)
:param string orientation: 'X', 'Y', 'Z'
:param float moment: magnetic dipole moment
:param float mu: background magnetic permeability
"""
#TODO: right now, orientation doesn't actually do anything! The methods in SrcUtils should take care of that
def __init__(self, rxList, freq, loc, orientation='Z', radius = 1., mu=mu_0):
@@ -259,6 +486,13 @@ class CircularLoop(BaseSrc):
BaseSrc.__init__(self, rxList)
def bPrimary(self, prob):
"""
The primary magnetic flux density from a magnetic vector potential
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
eqLocs = prob._eqLocs
if eqLocs is 'FE':
@@ -289,14 +523,35 @@ class CircularLoop(BaseSrc):
return C*a
def hPrimary(self, prob):
"""
The primary magnetic field from a magnetic vector potential
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
b = self.bPrimary(prob)
return 1./self.mu*b
def S_m(self, prob):
"""
The magnetic source term
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
b = self.bPrimary(prob)
return -1j*omega(self.freq)*b
def S_e(self, prob):
"""
The electric source term
:param Problem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
if all(np.r_[self.mu] == np.r_[prob.curModel.mu]):
return Zero()
else:
+42 -2
View File
@@ -10,6 +10,12 @@ import SrcFDEM as Src
####################################################
class Rx(SimPEG.Survey.BaseRx):
"""
Frequency domain receivers
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
:param string rxType: reciever type from knownRxTypes
"""
knownRxTypes = {
'exr':['e', 'Ex', 'real'],
@@ -61,6 +67,15 @@ class Rx(SimPEG.Survey.BaseRx):
return self.knownRxTypes[self.rxType][2]
def projectFields(self, src, mesh, u):
"""
Project fields to recievers to get data.
:param Source src: FDEM source
:param Mesh mesh: mesh used
:param Fields u: fields object
:rtype: numpy.ndarray
:return: fields projected to recievers
"""
P = self.getP(mesh)
u_part_complex = u[src, self.projField]
# get the real or imag component
@@ -69,6 +84,16 @@ class Rx(SimPEG.Survey.BaseRx):
return P*u_part
def projectFieldsDeriv(self, src, mesh, u, v, adjoint=False):
"""
Derivative of projected fields with respect to the inversion model times a vector.
:param Source src: FDEM source
:param Mesh mesh: mesh used
:param Fields u: fields object
:param numpy.ndarray v: vector to multiply
:rtype: numpy.ndarray
:return: fields projected to recievers
"""
P = self.getP(mesh)
if not adjoint:
@@ -95,10 +120,13 @@ class Rx(SimPEG.Survey.BaseRx):
class Survey(SimPEG.Survey.BaseSurvey):
"""
docstring for SurveyFDEM
Frequency domain electromagnetic survey
:param list srcList: list of FDEM sources used in the survey
"""
srcPair = Src.BaseSrc
rxPaair = Rx
def __init__(self, srcList, **kwargs):
# Sort these by frequency
@@ -126,6 +154,7 @@ class Survey(SimPEG.Survey.BaseSurvey):
@property
def nSrcByFreq(self):
"""Number of sources at each frequency"""
if getattr(self, '_nSrcByFreq', None) is None:
self._nSrcByFreq = {}
for freq in self.freqs:
@@ -133,11 +162,22 @@ class Survey(SimPEG.Survey.BaseSurvey):
return self._nSrcByFreq
def getSrcByFreq(self, freq):
"""Returns the sources associated with a specific frequency."""
"""
Returns the sources associated with a specific frequency.
:param float freq: frequency for which we look up sources
:rtype: dictionary
:return: sources at the sepcified frequency
"""
assert freq in self._freqDict, "The requested frequency is not in this survey."
return self._freqDict[freq]
def projectFields(self, u):
"""
Project fields to receiver locations
:param Fields u: fields object
:rtype: numpy.ndarray
:return: data
"""
data = SimPEG.Survey.Data(self)
for src in self.srcList:
for rx in src.rxList:
+9 -1
View File
@@ -31,12 +31,20 @@ class FieldsTDEM(Problem.TimeFields):
class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
"""docstring for ProblemTDEM1D"""
"""docstring for BaseTDEMProblem"""
def __init__(self, mesh, mapping=None, **kwargs):
BaseTimeProblem.__init__(self, mesh, mapping=mapping, **kwargs)
_FieldsForward_pair = FieldsTDEM #: used for the forward calculation only
waveformType = "STEPOFF"
current = None
def currentwaveform(self, wave):
self._timeSteps = np.diff(wave[:,0])
self.current = wave[:,1]
self.waveformType = "GENERAL"
def fields(self, m):
if self.verbose: print '%s\nCalculating fields(m)\n%s'%('*'*50,'*'*50)
self.curModel = m
+24 -6
View File
@@ -99,14 +99,33 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
class SrcTDEM_CircularLoop_MVP(SrcTDEM):
def __init__(self,rxList,loc,radius):
def __init__(self,rxList,loc,radius,waveformType):
self.loc = loc
self.radius = radius
SrcTDEM.__init__(self,rxList)
self.waveformType = waveformType
SrcTDEM.__init__(self,rxList)
def getInitialFields(self, mesh):
"""Circular Loop, magnetic vector potential"""
if self.waveformType == "STEPOFF":
print ">> Step waveform: Non-zero initial condition"
if mesh._meshType is 'CYL':
if mesh.isSymmetric:
MVP = MagneticLoopVectorPotential(self.loc, mesh, 'Ey', self.radius)
else:
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
elif mesh._meshType is 'TENSOR':
MVP = MagneticLoopVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'], self.radius)
else:
raise Exception('Unknown mesh for CircularLoop')
return {"b": mesh.edgeCurl*MVP}
elif self.waveformType == "GENERAL":
print ">> General waveform: Zero initial condition"
return {"b": np.zeros(mesh.nF)}
else:
raise NotImplementedError("Only use STEPOFF or GENERAL")
def getMeS(self, mesh, MfMui):
if mesh._meshType is 'CYL':
if mesh.isSymmetric:
MVP = MagneticLoopVectorPotential(self.loc, mesh, 'Ey', self.radius)
@@ -115,9 +134,8 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM):
elif mesh._meshType is 'TENSOR':
MVP = MagneticLoopVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'], self.radius)
else:
raise Exception('Unknown mesh for CircularLoop')
return {"b": mesh.edgeCurl*MVP}
raise Exception('Unknown mesh for CircularLoop')
return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP
class SurveyTDEM(Survey.BaseSurvey):
+1 -1
View File
@@ -1,6 +1,6 @@
# from EM import *
import TDEM
import FDEM
import Base
import Analytics
import Utils
from scipy.constants import mu_0, epsilon_0