mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-27 19:48:52 +08:00
691 lines
22 KiB
Python
691 lines
22 KiB
Python
from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver
|
|
from scipy.constants import mu_0
|
|
from SurveyFDEM import Survey as SurveyFDEM
|
|
from FieldsFDEM import Fields, Fields_e, Fields_b, Fields_h, Fields_j
|
|
from SimPEG.EM.Base import BaseEMProblem
|
|
from SimPEG.EM.Utils import omega
|
|
|
|
|
|
class BaseFDEMProblem(BaseEMProblem):
|
|
"""
|
|
We start by looking at Maxwell's equations in the electric
|
|
field \\\(\\\mathbf{e}\\\) and the magnetic flux
|
|
density \\\(\\\mathbf{b}\\\)
|
|
|
|
.. math ::
|
|
|
|
\mathbf{C} \mathbf{e} + i \omega \mathbf{b} = \mathbf{s_m} \\\\
|
|
{\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`). 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}^{\\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`). 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}\\\)
|
|
"""
|
|
|
|
surveyPair = SurveyFDEM
|
|
fieldsPair = Fields
|
|
|
|
def fields(self, m):
|
|
"""
|
|
Solve the forward problem for the fields.
|
|
|
|
:param numpy.array m: inversion model (nP,)
|
|
:rtype numpy.array:
|
|
:return f: forward solution
|
|
"""
|
|
|
|
self.curModel = m
|
|
f = self.fieldsPair(self.mesh, self.survey)
|
|
|
|
for freq in self.survey.freqs:
|
|
A = self.getA(freq)
|
|
rhs = self.getRHS(freq)
|
|
Ainv = self.Solver(A, **self.solverOpts)
|
|
u = Ainv * rhs
|
|
Srcs = self.survey.getSrcByFreq(freq)
|
|
f[Srcs, self._solutionType] = u
|
|
Ainv.clean()
|
|
return f
|
|
|
|
def Jvec(self, m, v, f=None):
|
|
"""
|
|
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)
|
|
|
|
self.curModel = m
|
|
|
|
Jv = self.dataPair(self.survey)
|
|
|
|
for freq in self.survey.freqs:
|
|
A = self.getA(freq)
|
|
Ainv = self.Solver(A, **self.solverOpts) # create the concept of Ainv (actually a solve)
|
|
|
|
for src in self.survey.getSrcByFreq(freq):
|
|
u_src = f[src, self._solutionType]
|
|
dA_dm_v = self.getADeriv(freq, u_src, v)
|
|
dRHS_dm_v = self.getRHSDeriv(freq, src, v)
|
|
du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v )
|
|
|
|
for rx in src.rxList:
|
|
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
|
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
|
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
|
Ainv.clean()
|
|
return Utils.mkvc(Jv)
|
|
|
|
def Jtvec(self, m, v, f=None):
|
|
"""
|
|
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)
|
|
|
|
self.curModel = m
|
|
|
|
# Ensure v is a data object.
|
|
if not isinstance(v, self.dataPair):
|
|
v = self.dataPair(self.survey, v)
|
|
|
|
Jtv = np.zeros(m.size)
|
|
|
|
for freq in self.survey.freqs:
|
|
AT = self.getA(freq).T
|
|
ATinv = self.Solver(AT, **self.solverOpts)
|
|
|
|
for src in self.survey.getSrcByFreq(freq):
|
|
u_src = f[src, self._solutionType]
|
|
|
|
for rx in src.rxList:
|
|
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
|
|
|
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
|
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
|
|
|
ATinvdf_duT = ATinv * df_duT
|
|
|
|
dA_dmT = self.getADeriv(freq, u_src, ATinvdf_duT, adjoint=True)
|
|
dRHS_dmT = self.getRHSDeriv(freq, src, ATinvdf_duT, adjoint=True)
|
|
du_dmT = -dA_dmT + dRHS_dmT
|
|
|
|
df_dmT = df_dmT + du_dmT
|
|
|
|
# TODO: this should be taken care of by the reciever?
|
|
real_or_imag = rx.projComp
|
|
if real_or_imag is 'real':
|
|
Jtv += np.array(df_dmT, dtype=complex).real
|
|
elif real_or_imag is 'imag':
|
|
Jtv += - np.array(df_dmT, dtype=complex).real
|
|
else:
|
|
raise Exception('Must be real or imag')
|
|
|
|
ATinv.clean()
|
|
|
|
return Utils.mkvc(Jtv)
|
|
|
|
def getSourceTerm(self, freq):
|
|
"""
|
|
Evaluates the sources for a given frequency and puts them in matrix form
|
|
|
|
: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._formulation is 'EB':
|
|
s_m = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
|
s_e = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
|
elif self._formulation is 'HJ':
|
|
s_m = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
|
s_e = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
|
|
|
for i, src in enumerate(Srcs):
|
|
smi, sei = src.eval(self)
|
|
#Why are you adding?
|
|
s_m[:,i] = s_m[:,i] + smi
|
|
s_e[:,i] = s_e[:,i] + sei
|
|
|
|
return s_m, s_e
|
|
|
|
|
|
##########################################################################################
|
|
################################ E-B Formulation #########################################
|
|
##########################################################################################
|
|
|
|
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:
|
|
|
|
.. 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
|
|
"""
|
|
|
|
_solutionType = 'eSolution'
|
|
_formulation = 'EB'
|
|
fieldsPair = Fields_e
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
|
|
|
def getA(self, freq):
|
|
"""
|
|
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
|
|
"""
|
|
|
|
MfMui = self.MfMui
|
|
MeSigma = self.MeSigma
|
|
C = self.mesh.edgeCurl
|
|
|
|
return C.T*MfMui*C + 1j*omega(freq)*MeSigma
|
|
|
|
|
|
def getADeriv(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)
|
|
|
|
if adjoint:
|
|
return 1j * omega(freq) * ( dMe_dsig.T * v )
|
|
|
|
return 1j * omega(freq) * ( dMe_dsig * v )
|
|
|
|
def getRHS(self, freq):
|
|
"""
|
|
Right hand side for the system
|
|
|
|
.. 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
|
|
|
|
return C.T * (MfMui * s_m) -1j * omega(freq) * s_e
|
|
|
|
def getRHSDeriv(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=adjoint)
|
|
|
|
if adjoint:
|
|
dRHS = MfMui * (C * v)
|
|
return s_mDeriv(dRHS) - 1j * omega(freq) * s_eDeriv(v)
|
|
|
|
else:
|
|
return C.T * (MfMui * s_mDeriv(v)) -1j * omega(freq) * s_eDeriv(v)
|
|
|
|
|
|
class Problem_b(BaseFDEMProblem):
|
|
"""
|
|
We eliminate :math:`\mathbf{e}` using
|
|
|
|
.. math ::
|
|
|
|
\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 :math:`\mathbf{b}` using:
|
|
|
|
.. math ::
|
|
|
|
\\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
|
|
|
|
:param SimPEG.Mesh mesh: mesh
|
|
"""
|
|
|
|
_solutionType = 'bSolution'
|
|
_formulation = 'EB'
|
|
fieldsPair = Fields_b
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
|
|
|
def getA(self, freq):
|
|
"""
|
|
System matrix
|
|
|
|
.. 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
|
|
MeSigmaI = self.MeSigmaI
|
|
C = self.mesh.edgeCurl
|
|
iomega = 1j * omega(freq) * sp.eye(self.mesh.nF)
|
|
|
|
A = C * (MeSigmaI * (C.T * MfMui)) + iomega
|
|
|
|
if self._makeASymmetric is True:
|
|
return MfMui.T*A
|
|
return A
|
|
|
|
def getADeriv(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
|
|
vec = C.T * (MfMui * u)
|
|
|
|
MeSigmaIDeriv = MeSigmaIDeriv(vec)
|
|
|
|
if adjoint:
|
|
if self._makeASymmetric is True:
|
|
v = MfMui * v
|
|
return MeSigmaIDeriv.T * (C.T * v)
|
|
|
|
if self._makeASymmetric is True:
|
|
return MfMui.T * ( C * ( MeSigmaIDeriv * v ) )
|
|
return C * ( MeSigmaIDeriv * v )
|
|
|
|
|
|
def getRHS(self, freq):
|
|
"""
|
|
Right hand side for the system
|
|
|
|
.. 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)
|
|
C = self.mesh.edgeCurl
|
|
MeSigmaI = self.MeSigmaI
|
|
|
|
RHS = s_m + C * ( MeSigmaI * s_e )
|
|
|
|
if self._makeASymmetric is True:
|
|
MfMui = self.MfMui
|
|
return MfMui.T * RHS
|
|
|
|
return RHS
|
|
|
|
def getRHSDeriv(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
|
|
|
|
if self._makeASymmetric and adjoint:
|
|
v = self.MfMui * v
|
|
|
|
MeSigmaIDeriv = self.MeSigmaIDeriv(s_e)
|
|
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
|
|
|
if not adjoint:
|
|
RHSderiv = C * (MeSigmaIDeriv * v)
|
|
SrcDeriv = s_mDeriv(v) + C * (self.MeSigmaI * s_eDeriv(v))
|
|
elif adjoint:
|
|
RHSderiv = MeSigmaIDeriv.T * (C.T * v)
|
|
SrcDeriv = s_mDeriv(v) + self.MeSigmaI.T * (C.T * s_eDeriv(v))
|
|
|
|
if self._makeASymmetric is True and not adjoint:
|
|
return MfMui.T * (SrcDeriv + RHSderiv)
|
|
|
|
return RHSderiv + SrcDeriv
|
|
|
|
|
|
|
|
##########################################################################################
|
|
################################ H-J Formulation #########################################
|
|
##########################################################################################
|
|
|
|
|
|
class Problem_j(BaseFDEMProblem):
|
|
"""
|
|
We eliminate \\\(\\\mathbf{h}\\\) using
|
|
|
|
.. math ::
|
|
|
|
\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
|
|
|
|
.. math ::
|
|
|
|
\\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!!
|
|
|
|
:param SimPEG.Mesh mesh: mesh
|
|
"""
|
|
|
|
_solutionType = 'jSolution'
|
|
_formulation = 'HJ'
|
|
fieldsPair = Fields_j
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
|
|
|
def getA(self, freq):
|
|
"""
|
|
System matrix
|
|
|
|
.. 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
|
|
MfRho = self.MfRho
|
|
C = self.mesh.edgeCurl
|
|
iomega = 1j * omega(freq) * sp.eye(self.mesh.nF)
|
|
|
|
A = C * MeMuI * C.T * MfRho + iomega
|
|
|
|
if self._makeASymmetric is True:
|
|
return MfRho.T*A
|
|
return A
|
|
|
|
|
|
def getADeriv(self, freq, u, v, adjoint=False):
|
|
"""
|
|
Product of the derivative of our system matrix with respect to the model and a vector
|
|
|
|
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
|
|
|
|
.. 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
|
|
MfRho = self.MfRho
|
|
C = self.mesh.edgeCurl
|
|
MfRhoDeriv = self.MfRhoDeriv(u)
|
|
|
|
if adjoint:
|
|
if self._makeASymmetric is True:
|
|
v = MfRho * v
|
|
return MfRhoDeriv.T * (C * (MeMuI.T * (C.T * v)))
|
|
|
|
if self._makeASymmetric is True:
|
|
return MfRho.T * (C * ( MeMuI * (C.T * (MfRhoDeriv * v) )))
|
|
return C * (MeMuI * (C.T * (MfRhoDeriv * v)))
|
|
|
|
|
|
def getRHS(self, freq):
|
|
"""
|
|
Right hand side for the system
|
|
|
|
.. 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)
|
|
C = self.mesh.edgeCurl
|
|
MeMuI = self.MeMuI
|
|
|
|
RHS = C * (MeMuI * s_m) - 1j * omega(freq) * s_e
|
|
if self._makeASymmetric is True:
|
|
MfRho = self.MfRho
|
|
return MfRho.T*RHS
|
|
|
|
return RHS
|
|
|
|
def getRHSDeriv(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=adjoint)
|
|
|
|
if adjoint:
|
|
if self._makeASymmetric:
|
|
MfRho = self.MfRho
|
|
v = MfRho*v
|
|
return s_mDeriv(MeMuI.T * (C.T * v)) - 1j * omega(freq) * s_eDeriv(v)
|
|
|
|
else:
|
|
RHSDeriv = C * (MeMuI * s_mDeriv(v)) - 1j * omega(freq) * s_eDeriv(v)
|
|
|
|
if self._makeASymmetric:
|
|
MfRho = self.MfRho
|
|
return MfRho.T * RHSDeriv
|
|
return RHSDeriv
|
|
|
|
|
|
|
|
|
|
class Problem_h(BaseFDEMProblem):
|
|
"""
|
|
We eliminate \\\(\\\mathbf{j}\\\) using
|
|
|
|
.. math ::
|
|
|
|
\mathbf{j} = \mathbf{C} \mathbf{h} - \mathbf{s_e}
|
|
|
|
and solve for \\\(\\\mathbf{h}\\\) using
|
|
|
|
.. math ::
|
|
|
|
\\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
|
|
"""
|
|
|
|
_solutionType = 'hSolution'
|
|
_formulation = 'HJ'
|
|
fieldsPair = Fields_h
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
|
|
|
def getA(self, freq):
|
|
"""
|
|
System matrix
|
|
|
|
.. 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
|
|
"""
|
|
|
|
MeMu = self.MeMu
|
|
MfRho = self.MfRho
|
|
C = self.mesh.edgeCurl
|
|
|
|
return C.T * (MfRho * C) + 1j*omega(freq)*MeMu
|
|
|
|
def getADeriv(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
|
|
MfRhoDeriv = self.MfRhoDeriv(C*u)
|
|
|
|
if adjoint:
|
|
return MfRhoDeriv.T * (C * v)
|
|
return C.T * (MfRhoDeriv * v)
|
|
|
|
def getRHS(self, freq):
|
|
"""
|
|
Right hand side for the system
|
|
|
|
.. math ::
|
|
|
|
\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
|
|
|
|
return s_m + C.T * ( MfRho * s_e )
|
|
|
|
def getRHSDeriv(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
|
|
|
|
MfRhoDeriv = self.MfRhoDeriv(s_e)
|
|
if not adjoint:
|
|
RHSDeriv = C.T * (MfRhoDeriv * v)
|
|
elif adjoint:
|
|
RHSDeriv = MfRhoDeriv.T * (C * v)
|
|
|
|
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
|
|
|
return RHSDeriv + s_mDeriv(v) + C.T * (MfRho * s_eDeriv(v))
|
|
|