mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-30 05:41:42 +08:00
817 lines
26 KiB
Python
817 lines
26 KiB
Python
from SimPEG import Survey, Problem, Utils, np, sp
|
|
from scipy.constants import mu_0
|
|
from SimPEG.EM.Utils import *
|
|
from SimPEG.Utils import Zero
|
|
|
|
class BaseSrc(Survey.BaseSrc):
|
|
"""
|
|
Base source class for FDEM Survey
|
|
"""
|
|
|
|
freq = None
|
|
integrate = False
|
|
_ePrimary = None
|
|
_bPrimary = None
|
|
_hPrimary = None
|
|
_jPrimary = None
|
|
|
|
def __init__(self, rxList, **kwargs):
|
|
Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
|
|
|
def eval(self, prob):
|
|
"""
|
|
- :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, 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
|
|
"""
|
|
if self._bPrimary is None:
|
|
return Zero()
|
|
return self._bPrimary
|
|
|
|
def bPrimaryDeriv(self, prob, v, adjoint=False):
|
|
"""
|
|
Derivative of the primary magnetic flux density
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:param numpy.ndarray v: vector
|
|
:param bool adjoint: adjoint?
|
|
: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
|
|
"""
|
|
if self._hPrimary is None:
|
|
return Zero()
|
|
return self._hPrimary
|
|
|
|
def hPrimaryDeriv(self, prob, v, adjoint=False):
|
|
"""
|
|
Derivative of the primary magnetic field
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:param numpy.ndarray v: vector
|
|
:param bool adjoint: adjoint?
|
|
:rtype: numpy.ndarray
|
|
:return: primary magnetic flux density
|
|
"""
|
|
return Zero()
|
|
|
|
def ePrimary(self, prob):
|
|
"""
|
|
Primary electric field
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:rtype: numpy.ndarray
|
|
:return: primary electric field
|
|
"""
|
|
if self._ePrimary is None:
|
|
return Zero()
|
|
return self._ePrimary
|
|
|
|
def ePrimaryDeriv(self, prob, v, adjoint=False):
|
|
"""
|
|
Derivative of the primary electric field
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:param numpy.ndarray v: vector
|
|
:param bool adjoint: adjoint?
|
|
:rtype: numpy.ndarray
|
|
:return: primary magnetic flux density
|
|
"""
|
|
return Zero()
|
|
|
|
def jPrimary(self, prob):
|
|
"""
|
|
Primary current density
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:rtype: numpy.ndarray
|
|
:return: primary current density
|
|
"""
|
|
if self._jPrimary is None:
|
|
return Zero()
|
|
return self._jPrimary
|
|
|
|
def jPrimaryDeriv(self, prob, v, adjoint=False):
|
|
"""
|
|
Derivative of the primary current density
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:param numpy.ndarray v: vector
|
|
:param bool adjoint: adjoint?
|
|
:rtype: numpy.ndarray
|
|
:return: primary magnetic flux 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
|
|
|
|
:param list rxList: receiver list
|
|
:param float freq: frequency
|
|
:param numpy.array s_e: electric source term
|
|
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
|
"""
|
|
|
|
def __init__(self, rxList, freq, s_e, **kwargs):
|
|
self._s_e = np.array(s_e, dtype=complex)
|
|
self.freq = float(freq)
|
|
|
|
BaseSrc.__init__(self, rxList, **kwargs)
|
|
|
|
def s_e(self, prob):
|
|
"""
|
|
Electric source term
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:rtype: numpy.ndarray
|
|
:return: electric source term on mesh
|
|
"""
|
|
if prob._formulation is 'EB' and self.integrate is True:
|
|
return prob.Me * self._s_e
|
|
return self._s_e
|
|
|
|
|
|
class RawVec_m(BaseSrc):
|
|
"""
|
|
RawVec magnetic source. It is defined by the user provided vector s_m
|
|
|
|
:param float freq: frequency
|
|
:param rxList: receiver list
|
|
:param numpy.array s_m: magnetic source term
|
|
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
|
"""
|
|
|
|
def __init__(self, rxList, freq, s_m, **kwargs): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
|
self._s_m = np.array(s_m, dtype=complex)
|
|
self.freq = float(freq)
|
|
|
|
BaseSrc.__init__(self, rxList, **kwargs)
|
|
|
|
def s_m(self, prob):
|
|
"""
|
|
Magnetic source term
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:rtype: numpy.ndarray
|
|
:return: magnetic source term on mesh
|
|
"""
|
|
if prob._formulation is 'HJ' and self.integrate is True:
|
|
return prob.Me * self._s_m
|
|
return self._s_m
|
|
|
|
|
|
class RawVec(BaseSrc):
|
|
"""
|
|
RawVec source. It is defined by the user provided vectors s_m, s_e
|
|
|
|
:param rxList: receiver list
|
|
:param float freq: frequency
|
|
:param numpy.array s_m: magnetic source term
|
|
:param numpy.array s_e: electric source term
|
|
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
|
"""
|
|
def __init__(self, rxList, freq, s_m, s_e, **kwargs):
|
|
self._s_m = np.array(s_m, dtype=complex)
|
|
self._s_e = np.array(s_e, dtype=complex)
|
|
self.freq = float(freq)
|
|
BaseSrc.__init__(self, rxList, **kwargs)
|
|
|
|
def s_m(self, prob):
|
|
"""
|
|
Magnetic source term
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:rtype: numpy.ndarray
|
|
:return: magnetic source term on mesh
|
|
"""
|
|
if prob._formulation is 'HJ' and self.integrate is True:
|
|
return prob.Me * self._s_m
|
|
return self._s_m
|
|
|
|
def s_e(self, prob):
|
|
"""
|
|
Electric source term
|
|
|
|
:param Problem prob: FDEM Problem
|
|
:rtype: numpy.ndarray
|
|
:return: electric source term on mesh
|
|
"""
|
|
if prob._formulation is 'EB' and self.integrate is True:
|
|
return prob.Me * self._s_e
|
|
return self._s_e
|
|
|
|
|
|
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
|
|
"""
|
|
|
|
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu=mu_0, **kwargs):
|
|
self.freq = float(freq)
|
|
self.loc = loc
|
|
self.orientation = orientation
|
|
assert orientation in ['X','Y','Z'], "Orientation (right now) doesn't actually do anything! The methods in SrcUtils should take care of this..."
|
|
self.moment = moment
|
|
self.mu = mu
|
|
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
|
|
"""
|
|
formulation = prob._formulation
|
|
|
|
if formulation is 'EB':
|
|
gridX = prob.mesh.gridEx
|
|
gridY = prob.mesh.gridEy
|
|
gridZ = prob.mesh.gridEz
|
|
C = prob.mesh.edgeCurl
|
|
|
|
elif formulation is 'HJ':
|
|
gridX = prob.mesh.gridFx
|
|
gridY = prob.mesh.gridFy
|
|
gridZ = prob.mesh.gridFz
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
|
|
if prob.mesh._meshType is 'CYL':
|
|
if not prob.mesh.isSymmetric:
|
|
# TODO ?
|
|
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
|
a = MagneticDipoleVectorPotential(self.loc, gridY, 'y', mu=self.mu, moment=self.moment)
|
|
|
|
else:
|
|
srcfct = MagneticDipoleVectorPotential
|
|
ax = srcfct(self.loc, gridX, 'x', mu=self.mu, moment=self.moment)
|
|
ay = srcfct(self.loc, gridY, 'y', mu=self.mu, moment=self.moment)
|
|
az = srcfct(self.loc, gridZ, 'z', mu=self.mu, moment=self.moment)
|
|
a = np.concatenate((ax, ay, az))
|
|
|
|
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_p = self.bPrimary(prob)
|
|
if prob._formulation is 'HJ':
|
|
b_p = prob.Me * b_p
|
|
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:
|
|
formulation = prob._formulation
|
|
|
|
if formulation is 'EB':
|
|
mui_s = prob.curModel.mui - 1./self.mu
|
|
MMui_s = prob.mesh.getFaceInnerProduct(mui_s)
|
|
C = prob.mesh.edgeCurl
|
|
elif formulation is 'HJ':
|
|
mu_s = prob.curModel.mu - self.mu
|
|
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s, invMat=True)
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
return -C.T * (MMui_s * self.bPrimary(prob))
|
|
|
|
|
|
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
|
|
"""
|
|
|
|
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu = mu_0):
|
|
self.freq = float(freq)
|
|
self.loc = loc
|
|
assert orientation in ['X','Y','Z'], "Orientation (right now) doesn't actually do anything! The methods in SrcUtils should take care of this..."
|
|
self.orientation = orientation
|
|
self.moment = moment
|
|
self.mu = mu
|
|
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
|
|
"""
|
|
|
|
formulation = prob._formulation
|
|
|
|
if formulation is 'EB':
|
|
gridX = prob.mesh.gridFx
|
|
gridY = prob.mesh.gridFy
|
|
gridZ = prob.mesh.gridFz
|
|
C = prob.mesh.edgeCurl
|
|
|
|
elif formulation is 'HJ':
|
|
gridX = prob.mesh.gridEx
|
|
gridY = prob.mesh.gridEy
|
|
gridZ = prob.mesh.gridEz
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
srcfct = MagneticDipoleFields
|
|
if prob.mesh._meshType is 'CYL':
|
|
if not prob.mesh.isSymmetric:
|
|
# TODO ?
|
|
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
|
bx = srcfct(self.loc, gridX, 'x', mu=self.mu, moment=self.moment)
|
|
bz = srcfct(self.loc, gridZ, 'z', mu=self.mu, moment=self.moment)
|
|
b = np.concatenate((bx,bz))
|
|
else:
|
|
bx = srcfct(self.loc, gridX, 'x', mu=self.mu, moment=self.moment)
|
|
by = srcfct(self.loc, gridY, 'y', mu=self.mu, moment=self.moment)
|
|
bz = srcfct(self.loc, gridZ, 'z', mu=self.mu, moment=self.moment)
|
|
b = np.concatenate((bx,by,bz))
|
|
|
|
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 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)
|
|
if prob._formulation is 'HJ':
|
|
b = prob.Me * b
|
|
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:
|
|
formulation = prob._formulation
|
|
|
|
if formulation is 'EB':
|
|
mui_s = prob.curModel.mui - 1./self.mu
|
|
MMui_s = prob.mesh.getFaceInnerProduct(mui_s)
|
|
C = prob.mesh.edgeCurl
|
|
elif formulation is 'HJ':
|
|
mu_s = prob.curModel.mu - self.mu
|
|
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s, invMat=True)
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
return -C.T * (MMui_s * self.bPrimary(prob))
|
|
|
|
|
|
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
|
|
"""
|
|
|
|
def __init__(self, rxList, freq, loc, orientation='Z', radius=1., mu=mu_0):
|
|
self.freq = float(freq)
|
|
self.orientation = orientation
|
|
assert orientation in ['X','Y','Z'], "Orientation (right now) doesn't actually do anything! The methods in SrcUtils should take care of this..."
|
|
self.radius = radius
|
|
self.mu = mu
|
|
self.loc = loc
|
|
self.integrate = False
|
|
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
|
|
"""
|
|
formulation = prob._formulation
|
|
|
|
if formulation is 'EB':
|
|
gridX = prob.mesh.gridEx
|
|
gridY = prob.mesh.gridEy
|
|
gridZ = prob.mesh.gridEz
|
|
C = prob.mesh.edgeCurl
|
|
|
|
elif formulation is 'HJ':
|
|
gridX = prob.mesh.gridFx
|
|
gridY = prob.mesh.gridFy
|
|
gridZ = prob.mesh.gridFz
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
if prob.mesh._meshType is 'CYL':
|
|
if not prob.mesh.isSymmetric:
|
|
# TODO ?
|
|
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
|
a = MagneticLoopVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
|
|
|
else:
|
|
srcfct = MagneticLoopVectorPotential
|
|
ax = srcfct(self.loc, gridX, 'x', self.radius, mu=self.mu)
|
|
ay = srcfct(self.loc, gridY, 'y', self.radius, mu=self.mu)
|
|
az = srcfct(self.loc, gridZ, 'z', self.radius, mu=self.mu)
|
|
a = np.concatenate((ax, ay, az))
|
|
|
|
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)
|
|
if prob._formulation is 'HJ':
|
|
b = prob.Me * b
|
|
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:
|
|
formulation = prob._formulation
|
|
|
|
if formulation is 'EB':
|
|
mui_s = prob.curModel.mui - 1./self.mu
|
|
MMui_s = prob.mesh.getFaceInnerProduct(mui_s)
|
|
C = prob.mesh.edgeCurl
|
|
|
|
|
|
elif formulation is 'HJ':
|
|
mu_s = prob.curModel.mu - self.mu
|
|
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s, invMat=True)
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
return -C.T * (MMui_s * self.bPrimary(prob))
|
|
|
|
|
|
class PrimSecSigma(BaseSrc):
|
|
|
|
def __init__(self, rxList, freq, sigBack, ePrimary, **kwargs):
|
|
self.sigBack = sigBack
|
|
|
|
BaseSrc.__init__(self, rxList, freq=freq, _ePrimary=ePrimary, **kwargs)
|
|
|
|
def s_e(self, prob):
|
|
return (prob.MeSigma - prob.mesh.getEdgeInnerProduct(self.sigBack)) * self.ePrimary(prob)
|
|
|
|
def s_eDeriv(self, prob, v, adjoint=False):
|
|
if adjoint:
|
|
return prob.MeSigmaDeriv(self.ePrimary(prob)).T * v
|
|
return prob.MeSigmaDeriv(self.ePrimary(prob)) * v
|
|
|
|
|
|
class PrimSecMappedSigma(BaseSrc):
|
|
|
|
"""
|
|
Primary-Secondary Source in which a mapping is provided to put the current model
|
|
onto the primary mesh. This is solved on every model update.
|
|
|
|
There are a lot of layers to the derivatives here!
|
|
|
|
**Required**
|
|
:param list rxList: Receiver List
|
|
:param float freq: frequency
|
|
:param ProblemFDEM primaryProblem: FDEM primary problem
|
|
:param SurveyFDEM primarySurvey: FDEM primary survey
|
|
|
|
**Optional**
|
|
:param Mapping map2meshSecondary: mapping current model to act as primary model on the secondary mesh
|
|
|
|
"""
|
|
|
|
def __init__(self, rxList, freq, primaryProblem, primarySurvey, map2meshSecondary = None ,**kwargs):
|
|
|
|
self.primaryProblem = primaryProblem
|
|
self.primarySurvey = primarySurvey
|
|
|
|
if self.primaryProblem.ispaired is False:
|
|
self.primaryProblem.pair(self.primarySurvey)
|
|
|
|
self.map2meshSecondary = map2meshSecondary
|
|
|
|
BaseSrc.__init__(self, rxList, freq=freq, **kwargs)
|
|
|
|
def _ProjPrimary(self, prob):
|
|
# if getattr(self, '__ProjPrimary', None) is None:
|
|
return self.primaryProblem.mesh.getInterpolationMatCartMesh(prob.mesh, locType='F', locTypeTo='E')
|
|
# return self.__ProjPrimary
|
|
|
|
|
|
def _primaryFields(self, prob, fieldType=None):
|
|
|
|
# TODO: cache and check if prob.curModel has changed
|
|
fields = self.primaryProblem.fields(prob.curModel.sigmaModel)
|
|
|
|
if fieldType is not None:
|
|
return fields[:,fieldType]
|
|
return fields
|
|
|
|
def _primaryFieldsDeriv(self, prob, v, adjoint=False, f=None):
|
|
if adjoint:
|
|
raise NotImplementedError
|
|
|
|
# TODO: this should not be hard-coded for j
|
|
# jp = self._primaryFields(prob)[:,'j']
|
|
|
|
# TODO: pull apart Jvec so that don't have to copy paste this code in
|
|
# A = self.primaryProblem.getA(self.freq)
|
|
# Ainv = self.primaryProblem.Solver(A, **self.primaryProblem.solverOpts) # create the concept of Ainv (actually a solve)
|
|
|
|
if f is None:
|
|
f = self._primaryFields(prob.curModel.sigmaModel)
|
|
|
|
freq = self.freq
|
|
|
|
A = self.primaryProblem.getA(freq)
|
|
Ainv = self.primaryProblem.Solver(A, **self.primaryProblem.solverOpts) # create the concept of Ainv (actually a solve)
|
|
|
|
src = self.primarySurvey.srcList[0]
|
|
# for src in self.survey.getSrcByFreq(freq):
|
|
u_src = Utils.mkvc(f[src, self.primaryProblem._solutionType])
|
|
dA_dm_v = self.primaryProblem.getADeriv(freq, u_src, v)
|
|
dRHS_dm_v = self.primaryProblem.getRHSDeriv(freq, src, v)
|
|
du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v )
|
|
|
|
df_dmFun = getattr(f, '_{0}Deriv'.format('j'), 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 df_dm_v
|
|
|
|
# return self.primaryProblem.Jvec(prob.curModel, v, f=f)
|
|
|
|
def ePrimary(self, prob, f=None):
|
|
if f is None:
|
|
f = self._primaryFields(prob)
|
|
|
|
ep = self._ProjPrimary(prob) * (
|
|
self.primaryProblem.MfI * (
|
|
self.primaryProblem.MfRho * f[:,'j'])
|
|
)
|
|
|
|
return Utils.mkvc(ep)
|
|
|
|
def ePrimaryDeriv(self, prob, v, adjoint=False, f=None):
|
|
|
|
if adjoint is True:
|
|
raise NotImplementedError
|
|
|
|
if f is None:
|
|
f = self._primaryFields(prob)
|
|
|
|
epDeriv = self._ProjPrimary(prob) * (
|
|
self.primaryProblem.MfI * (
|
|
(self.primaryProblem.MfRhoDeriv(f[:,'j']) * v)
|
|
+
|
|
(self.primaryProblem.MfRho * self._primaryFieldsDeriv(prob, v, f=f))
|
|
)
|
|
)
|
|
|
|
return Utils.mkvc(epDeriv)
|
|
|
|
|
|
def s_e(self, prob):
|
|
sigmaPrimary = self.map2meshSecondary * prob.curModel.sigmaModel
|
|
|
|
return Utils.mkvc((prob.MeSigma - prob.mesh.getEdgeInnerProduct(sigmaPrimary)) * self.ePrimary(prob))
|
|
|
|
|
|
def s_eDeriv(self, prob, v, adjoint=False):
|
|
if adjoint:
|
|
raise NotImplementedError
|
|
return prob.MeSigmaDeriv(self.ePrimary(prob)).T * v
|
|
|
|
sigmaPrimary = self.map2meshSecondary * prob.curModel.sigmaModel
|
|
sigmaPrimaryDeriv = self.map2meshSecondary.deriv(prob.curModel.sigmaModel)
|
|
|
|
f = self._primaryFields(prob)
|
|
ePrimary = self.ePrimary(prob,f=f)
|
|
|
|
return (prob.MeSigmaDeriv(ePrimary) * v
|
|
- prob.mesh.getEdgeInnerProductDeriv(sigmaPrimary)(ePrimary) * sigmaPrimaryDeriv * v
|
|
+ (prob.MeSigma - prob.mesh.getEdgeInnerProduct(sigmaPrimary)) * self.ePrimaryDeriv(prob, v, None, f=f)
|
|
)
|
|
|
|
|
|
|
|
|