mirror of
https://github.com/wassname/simpeg.git
synced 2026-08-15 12:54:52 +08:00
Merge branch 'em/dev' into em/primsec
# Conflicts: # SimPEG/EM/FDEM/SrcFDEM.py # tests/em/fdem/inverse/adjoint/test_FDEM_adjointEB.py
This commit is contained in:
+49
-65
@@ -54,8 +54,7 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
sol = Ainv * rhs
|
||||
Srcs = self.survey.getSrcByFreq(freq)
|
||||
ftype = self._fieldType + 'Solution'
|
||||
F[Srcs, ftype] = sol
|
||||
F[Srcs, self._solutionType] = sol
|
||||
Ainv.clean()
|
||||
return F
|
||||
|
||||
@@ -78,30 +77,19 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
Jv = self.dataPair(self.survey)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
A = self.getA(freq) #
|
||||
A = self.getA(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
ftype = self._fieldType + 'Solution'
|
||||
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 )
|
||||
u_src = u[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_duFun = getattr(u, '_%sDeriv_u'%rx.projField, None)
|
||||
df_dudu_dm = df_duFun(src, du_dm, adjoint=False)
|
||||
|
||||
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, u, v) # wrt u, also have wrt m
|
||||
|
||||
Jv[src, rx] = P(Df_Dm)
|
||||
|
||||
df_dmFun = getattr(u, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, u, df_dm_v)
|
||||
Ainv.clean()
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
@@ -132,32 +120,28 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
ATinv = self.Solver(AT, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
ftype = self._fieldType + 'Solution'
|
||||
u_src = u[src, ftype]
|
||||
u_src = u[src, self._solutionType]
|
||||
|
||||
for rx in src.rxList:
|
||||
PTv = rx.projectFieldsDeriv(src, self.mesh, u, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
|
||||
PTv = rx.evalDeriv(src, self.mesh, u, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
|
||||
|
||||
df_duTFun = getattr(u, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
|
||||
df_duTFun = getattr(u, '_%sDeriv_u'%rx.projField, None)
|
||||
df_duT = df_duTFun(src, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = ATinv * df_duT
|
||||
|
||||
dA_dmT = self.getADeriv_m(freq, u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv_m(freq,src, ATinvdf_duT, adjoint=True)
|
||||
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_dmFun = getattr(u, '_%sDeriv_m'%rx.projField, None)
|
||||
dfT_dm = df_dmFun(src, PTv, adjoint=True)
|
||||
df_dmT = df_dmT + du_dmT
|
||||
|
||||
du_dmT += dfT_dm
|
||||
|
||||
# TODO: this should be taken care of by the reciever
|
||||
# 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
|
||||
Jtv += np.array(df_dmT, dtype=complex).real
|
||||
elif real_or_imag is 'imag':
|
||||
Jtv += - np.array(du_dmT,dtype=complex).real
|
||||
Jtv += - np.array(df_dmT, dtype=complex).real
|
||||
else:
|
||||
raise Exception('Must be real or imag')
|
||||
|
||||
@@ -174,10 +158,10 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
:return: S_m, S_e (nE or nF, nSrc)
|
||||
"""
|
||||
Srcs = self.survey.getSrcByFreq(freq)
|
||||
if self._eqLocs is 'FE':
|
||||
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._eqLocs is 'EF':
|
||||
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)
|
||||
|
||||
@@ -213,9 +197,9 @@ class Problem_e(BaseFDEMProblem):
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_fieldType = 'e'
|
||||
_eqLocs = 'FE'
|
||||
fieldsPair = Fields_e
|
||||
_solutionType = 'eSolution'
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields_e
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -239,7 +223,7 @@ class Problem_e(BaseFDEMProblem):
|
||||
return C.T*MfMui*C + 1j*omega(freq)*MeSigma
|
||||
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
def getADeriv(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
@@ -280,7 +264,7 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
return C.T * (MfMui * S_m) -1j * omega(freq) * S_e
|
||||
|
||||
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
@@ -323,9 +307,9 @@ class Problem_b(BaseFDEMProblem):
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_fieldType = 'b'
|
||||
_eqLocs = 'FE'
|
||||
fieldsPair = Fields_b
|
||||
_solutionType = 'bSolution'
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields_b
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -353,7 +337,7 @@ class Problem_b(BaseFDEMProblem):
|
||||
return MfMui.T*A
|
||||
return A
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
def getADeriv(self, freq, u, v, adjoint=False):
|
||||
|
||||
"""
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
@@ -410,7 +394,7 @@ class Problem_b(BaseFDEMProblem):
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
@@ -471,9 +455,9 @@ class Problem_j(BaseFDEMProblem):
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_fieldType = 'j'
|
||||
_eqLocs = 'EF'
|
||||
fieldsPair = Fields_j
|
||||
_solutionType = 'jSolution'
|
||||
_formulation = 'HJ'
|
||||
fieldsPair = Fields_j
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -502,7 +486,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
return A
|
||||
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
def getADeriv(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
@@ -523,16 +507,16 @@ class Problem_j(BaseFDEMProblem):
|
||||
MeMuI = self.MeMuI
|
||||
MfRho = self.MfRho
|
||||
C = self.mesh.edgeCurl
|
||||
MfRhoDeriv_m = self.MfRhoDeriv(u)
|
||||
MfRhoDeriv = self.MfRhoDeriv(u)
|
||||
|
||||
if adjoint:
|
||||
if self._makeASymmetric is True:
|
||||
v = MfRho * v
|
||||
return MfRhoDeriv_m.T * (C * (MeMuI.T * (C.T * v)))
|
||||
return MfRhoDeriv.T * (C * (MeMuI.T * (C.T * v)))
|
||||
|
||||
if self._makeASymmetric is True:
|
||||
return MfRho.T * (C * ( MeMuI * (C.T * (MfRhoDeriv_m * v) )))
|
||||
return C * (MeMuI * (C.T * (MfRhoDeriv_m * v)))
|
||||
return MfRho.T * (C * ( MeMuI * (C.T * (MfRhoDeriv * v) )))
|
||||
return C * (MeMuI * (C.T * (MfRhoDeriv * v)))
|
||||
|
||||
|
||||
def getRHS(self, freq):
|
||||
@@ -559,7 +543,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
@@ -609,9 +593,9 @@ class Problem_h(BaseFDEMProblem):
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_fieldType = 'h'
|
||||
_eqLocs = 'EF'
|
||||
fieldsPair = Fields_h
|
||||
_solutionType = 'hSolution'
|
||||
_formulation = 'HJ'
|
||||
fieldsPair = Fields_h
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -634,7 +618,7 @@ class Problem_h(BaseFDEMProblem):
|
||||
|
||||
return C.T * (MfRho * C) + 1j*omega(freq)*MeMu
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
def getADeriv(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
@@ -651,11 +635,11 @@ class Problem_h(BaseFDEMProblem):
|
||||
|
||||
MeMu = self.MeMu
|
||||
C = self.mesh.edgeCurl
|
||||
MfRhoDeriv_m = self.MfRhoDeriv(C*u)
|
||||
MfRhoDeriv = self.MfRhoDeriv(C*u)
|
||||
|
||||
if adjoint:
|
||||
return MfRhoDeriv_m.T * (C * v)
|
||||
return C.T * (MfRhoDeriv_m * v)
|
||||
return MfRhoDeriv.T * (C * v)
|
||||
return C.T * (MfRhoDeriv * v)
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
@@ -676,7 +660,7 @@ class Problem_h(BaseFDEMProblem):
|
||||
|
||||
return S_m + C.T * ( MfRho * S_e )
|
||||
|
||||
def getRHSDeriv_m(self, freq, src, v, adjoint=False):
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
|
||||
+698
-313
File diff suppressed because it is too large
Load Diff
+125
-86
@@ -1,7 +1,7 @@
|
||||
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 SimPEG.Utils import Zero
|
||||
|
||||
class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
@@ -14,7 +14,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
def eval(self, prob):
|
||||
"""
|
||||
Evaluate the source terms.
|
||||
Evaluate the source terms.
|
||||
- :math:`S_m` : magnetic source term
|
||||
- :math:`S_e` : electric source term
|
||||
|
||||
@@ -36,12 +36,12 @@ class BaseSrc(Survey.BaseSrc):
|
||||
: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
|
||||
: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)
|
||||
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)
|
||||
return lambda v: self.S_mDeriv(prob, v, adjoint), lambda v: self.S_eDeriv(prob, v, adjoint)
|
||||
|
||||
def bPrimary(self, prob):
|
||||
"""
|
||||
@@ -49,7 +49,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
@@ -59,7 +59,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
@@ -69,7 +69,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary electric field
|
||||
:return: primary electric field
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
@@ -79,13 +79,13 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary current density
|
||||
:return: primary current density
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def S_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
Magnetic source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
@@ -95,7 +95,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
def S_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
Electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
@@ -136,15 +136,26 @@ class RawVec_e(BaseSrc):
|
||||
: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) [True]
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, S_e): #, ePrimary=None, bPrimary=None, hPrimary=None, jPrimary=None):
|
||||
self._S_e = np.array(S_e,dtype=complex)
|
||||
def __init__(self, rxList, freq, S_e, integrate=True): #, ePrimary=None, bPrimary=None, hPrimary=None, jPrimary=None):
|
||||
self._S_e = np.array(S_e, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
|
||||
BaseSrc.__init__(self, rxList)
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -155,10 +166,11 @@ class RawVec_m(BaseSrc):
|
||||
: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) [True]
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, S_m, integrate = True): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
||||
self._S_m = np.array(S_m,dtype=complex)
|
||||
def __init__(self, rxList, freq, S_m, integrate=True): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
||||
self._S_m = np.array(S_m, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
|
||||
@@ -166,12 +178,14 @@ class RawVec_m(BaseSrc):
|
||||
|
||||
def S_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
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
|
||||
|
||||
|
||||
@@ -183,36 +197,51 @@ class RawVec(BaseSrc):
|
||||
: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) [True]
|
||||
"""
|
||||
def __init__(self, rxList, freq, S_m, S_e, integrate = True):
|
||||
self._S_m = np.array(S_m,dtype=complex)
|
||||
self._S_e = np.array(S_e,dtype=complex)
|
||||
def __init__(self, rxList, freq, S_m, S_e, integrate=True):
|
||||
self._S_m = np.array(S_m, dtype=complex)
|
||||
self._S_e = np.array(S_e, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
BaseSrc.__init__(self, rxList)
|
||||
|
||||
def S_m(self, prob):
|
||||
if prob._eqLocs is 'EF' and self.integrate is True:
|
||||
"""
|
||||
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):
|
||||
if prob._eqLocs is 'FE' and self.integrate is True:
|
||||
"""
|
||||
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!).
|
||||
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::
|
||||
.. 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}}
|
||||
|
||||
@@ -225,17 +254,17 @@ class MagDipole(BaseSrc):
|
||||
and define a zero-frequency primary problem, noting that the source is
|
||||
generated by a divergence free electric current
|
||||
|
||||
.. math::
|
||||
.. 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
|
||||
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::
|
||||
.. 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
|
||||
Our secondary problem is then
|
||||
|
||||
.. math::
|
||||
\mathbf{C} \mathbf{e^S} + i \omega \mathbf{b^S} = - i \omega \mathbf{b^P} \\\\
|
||||
@@ -245,15 +274,15 @@ class MagDipole(BaseSrc):
|
||||
: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
|
||||
: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):
|
||||
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu=mu_0):
|
||||
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
|
||||
self.integrate = False
|
||||
@@ -265,17 +294,17 @@ class MagDipole(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
eqLocs = prob._eqLocs
|
||||
formulation = prob._formulation
|
||||
|
||||
if eqLocs is 'FE':
|
||||
if formulation is 'EB':
|
||||
gridX = prob.mesh.gridEx
|
||||
gridY = prob.mesh.gridEy
|
||||
gridZ = prob.mesh.gridEz
|
||||
C = prob.mesh.edgeCurl
|
||||
|
||||
elif eqLocs is 'EF':
|
||||
elif formulation is 'HJ':
|
||||
gridX = prob.mesh.gridFx
|
||||
gridY = prob.mesh.gridFy
|
||||
gridZ = prob.mesh.gridFz
|
||||
@@ -303,10 +332,10 @@ class MagDipole(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return h_from_b(prob,b)
|
||||
return 1./self.mu * b
|
||||
|
||||
def S_m(self, prob):
|
||||
"""
|
||||
@@ -314,10 +343,12 @@ class MagDipole(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
: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):
|
||||
@@ -326,21 +357,21 @@ class MagDipole(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
|
||||
if all(np.r_[self.mu] == np.r_[prob.curModel.mu]):
|
||||
return Zero()
|
||||
else:
|
||||
eqLocs = prob._eqLocs
|
||||
formulation = prob._formulation
|
||||
|
||||
if eqLocs is 'FE':
|
||||
if formulation is 'EB':
|
||||
mui_s = prob.curModel.mui - 1./self.mu
|
||||
MMui_s = prob.mesh.getFaceInnerProduct(mui_s)
|
||||
C = prob.mesh.edgeCurl
|
||||
elif eqLocs is 'EF':
|
||||
elif formulation is 'HJ':
|
||||
mu_s = prob.curModel.mu - self.mu
|
||||
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s,invMat=True)
|
||||
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s, invMat=True)
|
||||
C = prob.mesh.edgeCurl.T
|
||||
|
||||
return -C.T * (MMui_s * self.bPrimary(prob))
|
||||
@@ -353,21 +384,20 @@ class MagDipole_Bfield(BaseSrc):
|
||||
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.
|
||||
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
|
||||
: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):
|
||||
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
|
||||
@@ -379,18 +409,18 @@ class MagDipole_Bfield(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
|
||||
eqLocs = prob._eqLocs
|
||||
formulation = prob._formulation
|
||||
|
||||
if eqLocs is 'FE':
|
||||
if formulation is 'EB':
|
||||
gridX = prob.mesh.gridFx
|
||||
gridY = prob.mesh.gridFy
|
||||
gridZ = prob.mesh.gridFz
|
||||
C = prob.mesh.edgeCurl
|
||||
|
||||
elif eqLocs is 'EF':
|
||||
elif formulation is 'HJ':
|
||||
gridX = prob.mesh.gridEx
|
||||
gridY = prob.mesh.gridEy
|
||||
gridZ = prob.mesh.gridEz
|
||||
@@ -418,10 +448,10 @@ class MagDipole_Bfield(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return h_from_b(prob, b)
|
||||
return 1/self.mu * b
|
||||
|
||||
def S_m(self, prob):
|
||||
"""
|
||||
@@ -429,9 +459,11 @@ class MagDipole_Bfield(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
: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):
|
||||
@@ -440,20 +472,20 @@ class MagDipole_Bfield(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
if all(np.r_[self.mu] == np.r_[prob.curModel.mu]):
|
||||
return Zero()
|
||||
else:
|
||||
eqLocs = prob._eqLocs
|
||||
formulation = prob._formulation
|
||||
|
||||
if eqLocs is 'FE':
|
||||
if formulation is 'EB':
|
||||
mui_s = prob.curModel.mui - 1./self.mu
|
||||
MMui_s = prob.mesh.getFaceInnerProduct(mui_s)
|
||||
C = prob.mesh.edgeCurl
|
||||
elif eqLocs is 'EF':
|
||||
elif formulation is 'HJ':
|
||||
mu_s = prob.curModel.mu - self.mu
|
||||
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s,invMat=True)
|
||||
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s, invMat=True)
|
||||
C = prob.mesh.edgeCurl.T
|
||||
|
||||
return -C.T * (MMui_s * self.bPrimary(prob))
|
||||
@@ -463,22 +495,22 @@ 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!).
|
||||
flux density is divergence free (no magnetic monopoles!).
|
||||
|
||||
This approach uses a primary-secondary in frequency in the same fashion as the MagDipole.
|
||||
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
|
||||
: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):
|
||||
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
|
||||
@@ -491,17 +523,17 @@ class CircularLoop(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
eqLocs = prob._eqLocs
|
||||
formulation = prob._formulation
|
||||
|
||||
if eqLocs is 'FE':
|
||||
if formulation is 'EB':
|
||||
gridX = prob.mesh.gridEx
|
||||
gridY = prob.mesh.gridEy
|
||||
gridZ = prob.mesh.gridEz
|
||||
C = prob.mesh.edgeCurl
|
||||
|
||||
elif eqLocs is 'EF':
|
||||
elif formulation is 'HJ':
|
||||
gridX = prob.mesh.gridFx
|
||||
gridY = prob.mesh.gridFy
|
||||
gridZ = prob.mesh.gridFz
|
||||
@@ -511,10 +543,10 @@ class CircularLoop(BaseSrc):
|
||||
if not prob.mesh.isSymmetric:
|
||||
# TODO ?
|
||||
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
||||
a = MagneticDipoleVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
a = MagneticLoopVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
|
||||
else:
|
||||
srcfct = MagneticDipoleVectorPotential
|
||||
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)
|
||||
@@ -528,7 +560,7 @@ class CircularLoop(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return 1./self.mu*b
|
||||
@@ -539,9 +571,11 @@ class CircularLoop(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
: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):
|
||||
@@ -550,24 +584,27 @@ class CircularLoop(BaseSrc):
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
if all(np.r_[self.mu] == np.r_[prob.curModel.mu]):
|
||||
return Zero()
|
||||
else:
|
||||
eqLocs = prob._eqLocs
|
||||
formulation = prob._formulation
|
||||
|
||||
if eqLocs is 'FE':
|
||||
if formulation is 'EB':
|
||||
mui_s = prob.curModel.mui - 1./self.mu
|
||||
MMui_s = prob.mesh.getFaceInnerProduct(mui_s)
|
||||
C = prob.mesh.edgeCurl
|
||||
elif eqLocs is 'EF':
|
||||
|
||||
|
||||
elif formulation is 'HJ':
|
||||
mu_s = prob.curModel.mu - self.mu
|
||||
MMui_s = prob.mesh.getEdgeInnerProduct(mu_s,invMat=True)
|
||||
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):
|
||||
|
||||
# TODO: This will only work for E-B formulation
|
||||
@@ -582,22 +619,22 @@ class PrimSecSigma(BaseSrc):
|
||||
|
||||
def _solvePrimary(self):
|
||||
# check if I have fields
|
||||
# if not, solve the primary to get fields object
|
||||
# if not, solve the primary to get fields object
|
||||
if self._primarySurvey.ispaired:
|
||||
if self._primarySurvey.prob is not self._primaryProblem:
|
||||
raise Exception "The survey object is already paired to a problem. Use survey.unpair()"
|
||||
else:
|
||||
self._primaryProblem.pair(self._primarySurvey)
|
||||
|
||||
return
|
||||
return
|
||||
|
||||
def ePrimary(self,prob):
|
||||
# check if a primary problem is defined
|
||||
if getattr(self, '_ePrimary', None) is None:
|
||||
if self._primaryProblem is None or self._primarySurvey is None:
|
||||
raise Exception "if Not specifying a ePrimary, a primarySurvey and primaryProblem must be provided."
|
||||
|
||||
self._ePrimary = self._solvePrimary[:,'e']
|
||||
|
||||
self._ePrimary = self._solvePrimary[:,'e']
|
||||
|
||||
return self._ePrimary
|
||||
|
||||
@@ -609,7 +646,9 @@ class PrimSecSigma(BaseSrc):
|
||||
def S_eDeriv(self, prob, v, adjoint = False):
|
||||
MeSigmaDeriv = prob.MeSigmaDeriv
|
||||
if adjoint is not True:
|
||||
return MeSigmaDeriv(Utils.mkvc(self._ePrimary)) * v
|
||||
return MeSigmaDeriv(Utils.mkvc(self._ePrimary)) * v
|
||||
return MeSigmaDeriv(Utils.mkvc(self._ePrimary)) * v
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from SimPEG.EM.Utils import *
|
||||
from scipy.constants import mu_0
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
import SrcFDEM as Src
|
||||
from SimPEG import sp
|
||||
|
||||
|
||||
####################################################
|
||||
@@ -18,33 +19,33 @@ class Rx(SimPEG.Survey.BaseRx):
|
||||
"""
|
||||
|
||||
knownRxTypes = {
|
||||
'exr':['e', 'Ex', 'real'],
|
||||
'eyr':['e', 'Ey', 'real'],
|
||||
'ezr':['e', 'Ez', 'real'],
|
||||
'exi':['e', 'Ex', 'imag'],
|
||||
'eyi':['e', 'Ey', 'imag'],
|
||||
'ezi':['e', 'Ez', 'imag'],
|
||||
'exr':['e', 'x', 'real'],
|
||||
'eyr':['e', 'y', 'real'],
|
||||
'ezr':['e', 'z', 'real'],
|
||||
'exi':['e', 'x', 'imag'],
|
||||
'eyi':['e', 'y', 'imag'],
|
||||
'ezi':['e', 'z', 'imag'],
|
||||
|
||||
'bxr':['b', 'Fx', 'real'],
|
||||
'byr':['b', 'Fy', 'real'],
|
||||
'bzr':['b', 'Fz', 'real'],
|
||||
'bxi':['b', 'Fx', 'imag'],
|
||||
'byi':['b', 'Fy', 'imag'],
|
||||
'bzi':['b', 'Fz', 'imag'],
|
||||
'bxr':['b', 'x', 'real'],
|
||||
'byr':['b', 'y', 'real'],
|
||||
'bzr':['b', 'z', 'real'],
|
||||
'bxi':['b', 'x', 'imag'],
|
||||
'byi':['b', 'y', 'imag'],
|
||||
'bzi':['b', 'z', 'imag'],
|
||||
|
||||
'jxr':['j', 'Fx', 'real'],
|
||||
'jyr':['j', 'Fy', 'real'],
|
||||
'jzr':['j', 'Fz', 'real'],
|
||||
'jxi':['j', 'Fx', 'imag'],
|
||||
'jyi':['j', 'Fy', 'imag'],
|
||||
'jzi':['j', 'Fz', 'imag'],
|
||||
'jxr':['j', 'x', 'real'],
|
||||
'jyr':['j', 'y', 'real'],
|
||||
'jzr':['j', 'z', 'real'],
|
||||
'jxi':['j', 'x', 'imag'],
|
||||
'jyi':['j', 'y', 'imag'],
|
||||
'jzi':['j', 'z', 'imag'],
|
||||
|
||||
'hxr':['h', 'Ex', 'real'],
|
||||
'hyr':['h', 'Ey', 'real'],
|
||||
'hzr':['h', 'Ez', 'real'],
|
||||
'hxi':['h', 'Ex', 'imag'],
|
||||
'hyi':['h', 'Ey', 'imag'],
|
||||
'hzi':['h', 'Ez', 'imag'],
|
||||
'hxr':['h', 'x', 'real'],
|
||||
'hyr':['h', 'y', 'real'],
|
||||
'hzr':['h', 'z', 'real'],
|
||||
'hxi':['h', 'x', 'imag'],
|
||||
'hyi':['h', 'y', 'imag'],
|
||||
'hzi':['h', 'z', 'imag'],
|
||||
}
|
||||
radius = None
|
||||
|
||||
@@ -56,34 +57,37 @@ class Rx(SimPEG.Survey.BaseRx):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
@property
|
||||
def projGLoc(self):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
return self.knownRxTypes[self.rxType][1]
|
||||
|
||||
@property
|
||||
def projComp(self):
|
||||
"""Component projection (real/imag)"""
|
||||
return self.knownRxTypes[self.rxType][2]
|
||||
|
||||
def projectFields(self, src, mesh, u):
|
||||
def projGLoc(self, u):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
return u._GLoc(self.rxType[0]) + self.knownRxTypes[self.rxType][1]
|
||||
|
||||
def eval(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
|
||||
:param Fields f: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
P = self.getP(mesh)
|
||||
# projGLoc = u._GLoc(self.knownRxTypes[self.rxType][0])
|
||||
# projGLoc += self.knownRxTypes[self.rxType][1]
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(u))
|
||||
u_part_complex = u[src, self.projField]
|
||||
# get the real or imag component
|
||||
real_or_imag = self.projComp
|
||||
u_part = getattr(u_part_complex, real_or_imag)
|
||||
|
||||
return P*u_part
|
||||
|
||||
def projectFieldsDeriv(self, src, mesh, u, v, adjoint=False):
|
||||
def evalDeriv(self, src, mesh, u, v, adjoint=False):
|
||||
"""
|
||||
Derivative of projected fields with respect to the inversion model times a vector.
|
||||
|
||||
@@ -94,7 +98,8 @@ class Rx(SimPEG.Survey.BaseRx):
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
P = self.getP(mesh)
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(u))
|
||||
|
||||
if not adjoint:
|
||||
Pv_complex = P * v
|
||||
@@ -171,7 +176,7 @@ class Survey(SimPEG.Survey.BaseSurvey):
|
||||
assert freq in self._freqDict, "The requested frequency is not in this survey."
|
||||
return self._freqDict[freq]
|
||||
|
||||
def projectFields(self, u):
|
||||
def eval(self, u):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
:param Fields u: fields object
|
||||
@@ -181,8 +186,9 @@ class Survey(SimPEG.Survey.BaseSurvey):
|
||||
data = SimPEG.Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.projectFields(src, self.mesh, u)
|
||||
data[src, rx] = rx.eval(src, self.mesh, u)
|
||||
return data
|
||||
|
||||
def projectFieldsDeriv(self, u):
|
||||
raise Exception('Use Sources to project fields deriv.')
|
||||
def evalDeriv(self, u):
|
||||
raise Exception('Use Receivers to project fields deriv.')
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ class FieldsTDEM(Problem.TimeFields):
|
||||
else:
|
||||
e = np.zeros((nE,nSrc)) # if nSrc == 1 else (nE, nSrc))
|
||||
u = np.concatenate((u, b, e))
|
||||
|
||||
return Utils.mkvc(u,nSrc)
|
||||
|
||||
|
||||
@@ -128,7 +129,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
u = self.fields(m)
|
||||
p = self.Gvec(m, v, u)
|
||||
y = self.solveAh(m, p)
|
||||
Jv = self.survey.projectFieldsDeriv(u, v=y)
|
||||
Jv = self.survey.evalDeriv(u, v=y)
|
||||
if self.verbose: print '%s\nDone calculating J(v)\n%s'%('*'*50,'*'*50)
|
||||
return - mkvc(Jv)
|
||||
|
||||
@@ -155,7 +156,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
p = self.survey.projectFieldsDeriv(u, v=v, adjoint=True)
|
||||
p = self.survey.evalDeriv(u, v=v, adjoint=True)
|
||||
y = self.solveAht(m, p)
|
||||
w = self.Gtvec(m, y, u)
|
||||
if self.verbose: print '%s\nDone calculating J^T(v)\n%s'%('*'*50,'*'*50)
|
||||
|
||||
@@ -51,12 +51,12 @@ class RxTDEM(Survey.BaseTimeRx):
|
||||
else:
|
||||
return timeMesh.getInterpolationMat(self.times, self.projTLoc)
|
||||
|
||||
def projectFields(self, src, mesh, timeMesh, u):
|
||||
def eval(self, src, mesh, timeMesh, u):
|
||||
P = self.getP(mesh, timeMesh)
|
||||
u_part = Utils.mkvc(u[src, self.projField, :])
|
||||
return P*u_part
|
||||
|
||||
def projectFieldsDeriv(self, src, mesh, timeMesh, u, v, adjoint=False):
|
||||
def evalDeriv(self, src, mesh, timeMesh, u, v, adjoint=False):
|
||||
P = self.getP(mesh, timeMesh)
|
||||
|
||||
if not adjoint:
|
||||
@@ -79,12 +79,32 @@ class SrcTDEM(Survey.BaseSrc):
|
||||
|
||||
class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
|
||||
def __init__(self,rxList,loc):
|
||||
def __init__(self,rxList,loc,waveformType="STEPOFF"):
|
||||
self.loc = loc
|
||||
self.waveformType = waveformType
|
||||
SrcTDEM.__init__(self,rxList)
|
||||
|
||||
def getInitialFields(self, mesh):
|
||||
"""Vertical magnetic dipole, magnetic vector potential"""
|
||||
if self.waveformType == "STEPOFF":
|
||||
print ">> Step waveform: Non-zero initial condition"
|
||||
if mesh._meshType is 'CYL':
|
||||
if mesh.isSymmetric:
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, 'Ey')
|
||||
else:
|
||||
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'])
|
||||
else:
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
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 = MagneticDipoleVectorPotential(self.loc, mesh, 'Ey')
|
||||
@@ -93,13 +113,12 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'])
|
||||
else:
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
|
||||
return {"b": mesh.edgeCurl*MVP}
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP
|
||||
|
||||
|
||||
class SrcTDEM_CircularLoop_MVP(SrcTDEM):
|
||||
def __init__(self,rxList,loc,radius,waveformType):
|
||||
def __init__(self,rxList,loc,radius,waveformType="STEPOFF"):
|
||||
self.loc = loc
|
||||
self.radius = radius
|
||||
self.waveformType = waveformType
|
||||
@@ -149,27 +168,27 @@ class SurveyTDEM(Survey.BaseSurvey):
|
||||
self.srcList = srcList
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
|
||||
def projectFields(self, u):
|
||||
def eval(self, u):
|
||||
data = Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.projectFields(src, self.mesh, self.prob.timeMesh, u)
|
||||
data[src, rx] = rx.eval(src, self.mesh, self.prob.timeMesh, u)
|
||||
return data
|
||||
|
||||
def projectFieldsDeriv(self, u, v=None, adjoint=False):
|
||||
def evalDeriv(self, u, v=None, adjoint=False):
|
||||
assert v is not None, 'v to multiply must be provided.'
|
||||
|
||||
if not adjoint:
|
||||
data = Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.projectFieldsDeriv(src, self.mesh, self.prob.timeMesh, u, v)
|
||||
data[src, rx] = rx.evalDeriv(src, self.mesh, self.prob.timeMesh, u, v)
|
||||
return data
|
||||
else:
|
||||
f = FieldsTDEM(self.mesh, self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
Ptv = rx.projectFieldsDeriv(src, self.mesh, self.prob.timeMesh, u, v, adjoint=True)
|
||||
Ptv = rx.evalDeriv(src, self.mesh, self.prob.timeMesh, u, v, adjoint=True)
|
||||
Ptv = Ptv.reshape((-1, self.prob.timeMesh.nN), order='F')
|
||||
if rx.projField not in f: # first time we are projecting
|
||||
f[src, rx.projField, :] = Ptv
|
||||
|
||||
@@ -13,37 +13,4 @@ def k(freq, sigma, mu=mu_0, eps=epsilon_0):
|
||||
beta = w * np.sqrt( mu*eps/2 * ( np.sqrt(1. + (sigma / (eps*w))**2 ) - 1) )
|
||||
return alp - 1j*beta
|
||||
|
||||
# Constitutive relations
|
||||
def e_from_j(prob,j):
|
||||
eqLocs = prob._eqLocs
|
||||
if eqLocs is 'FE':
|
||||
MSigmaI = prob.MeSigmaI
|
||||
elif eqLocs is 'EF':
|
||||
MSigmaI = prob.MfRho
|
||||
return MSigmaI*j
|
||||
|
||||
def j_from_e(prob,e):
|
||||
eqLocs = prob._eqLocs
|
||||
if eqLocs is 'FE':
|
||||
MSigma = prob.MeSigma
|
||||
elif eqLocs is 'EF':
|
||||
MSigma = prob.MfRhoI
|
||||
return MSigma*e
|
||||
|
||||
def b_from_h(prob,h):
|
||||
eqLocs = prob._eqLocs
|
||||
if eqLocs is 'FE':
|
||||
MMu = prob.MfMuiI
|
||||
elif eqLocs is 'EF':
|
||||
MMu = prob.MeMu
|
||||
return MMu*h
|
||||
|
||||
def h_from_b(prob,b):
|
||||
eqLocs = prob._eqLocs
|
||||
if eqLocs is 'FE':
|
||||
MMuI = prob.MfMui
|
||||
elif eqLocs is 'EF':
|
||||
MMuI = prob.MeMuI
|
||||
return MMuI*b
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
# import Sources
|
||||
# import Ana
|
||||
# import Solver
|
||||
from EMUtils import omega, e_from_j, j_from_e, b_from_h, h_from_b
|
||||
from EMUtils import omega, k
|
||||
from AnalyticUtils import MagneticDipoleFields, MagneticDipoleVectorPotential, MagneticLoopVectorPotential
|
||||
@@ -4,19 +4,28 @@ from SimPEG import EM
|
||||
import sys
|
||||
from scipy.constants import mu_0
|
||||
|
||||
def getFDEMProblem(fdemType, comp, SrcList, freq, verbose=False):
|
||||
cs = 5.
|
||||
ncx, ncy, ncz = 6, 6, 6
|
||||
npad = 3
|
||||
FLR = 1e-20 # "zero", so if residual below this --> pass regardless of order
|
||||
CONDUCTIVITY = 1e1
|
||||
MU = mu_0
|
||||
freq = 5e-1
|
||||
|
||||
|
||||
def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False):
|
||||
cs = 10.
|
||||
ncx, ncy, ncz = 0, 0, 0
|
||||
npad = 8
|
||||
hx = [(cs,npad,-1.3), (cs,ncx), (cs,npad,1.3)]
|
||||
hy = [(cs,npad,-1.3), (cs,ncy), (cs,npad,1.3)]
|
||||
hz = [(cs,npad,-1.3), (cs,ncz), (cs,npad,1.3)]
|
||||
mesh = Mesh.TensorMesh([hx,hy,hz],['C','C','C'])
|
||||
|
||||
mapping = Maps.ExpMap(mesh)
|
||||
if useMu is True:
|
||||
mapping = [('sigma', Maps.ExpMap(mesh)), ('mu', Maps.IdentityMap(mesh))]
|
||||
else:
|
||||
mapping = Maps.ExpMap(mesh)
|
||||
|
||||
x = np.array([np.linspace(-30,-15,3),np.linspace(15,30,3)]) #don't sample right by the source
|
||||
XYZ = Utils.ndgrid(x,x,np.r_[0.])
|
||||
x = np.array([np.linspace(-5.*cs,-2.*cs,3),np.linspace(5.*cs,2.*cs,3)]) + cs/4. #don't sample right by the source, slightly off alignment from either staggered grid
|
||||
XYZ = Utils.ndgrid(x,x,np.linspace(-2.*cs,2.*cs,5))
|
||||
Rx0 = EM.FDEM.Rx(XYZ, comp)
|
||||
|
||||
Src = []
|
||||
@@ -32,15 +41,15 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, verbose=False):
|
||||
if fdemType is 'e' or fdemType is 'b':
|
||||
S_m = np.zeros(mesh.nF)
|
||||
S_e = np.zeros(mesh.nE)
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1.
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1.
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3
|
||||
Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, S_e))
|
||||
|
||||
elif fdemType is 'h' or fdemType is 'j':
|
||||
S_m = np.zeros(mesh.nE)
|
||||
S_e = np.zeros(mesh.nF)
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1.
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1.
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3
|
||||
Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, S_e))
|
||||
elif SrcType is 'PrimSecSigma':
|
||||
if fdemType is 'e' or fdemType is 'b':
|
||||
@@ -77,6 +86,48 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, verbose=False):
|
||||
from pymatsolver import MumpsSolver
|
||||
prb.Solver = MumpsSolver
|
||||
except ImportError, e:
|
||||
pass
|
||||
prb.Solver = SolverLU
|
||||
|
||||
return prb
|
||||
return prb
|
||||
|
||||
def crossCheckTest(SrcList, fdemType1, fdemType2, comp, addrandoms = False, useMu=False, TOL=1e-5, verbose=False):
|
||||
|
||||
l2norm = lambda r: np.sqrt(r.dot(r))
|
||||
|
||||
prb1 = getFDEMProblem(fdemType1, comp, SrcList, freq, useMu, verbose)
|
||||
mesh = prb1.mesh
|
||||
print 'Cross Checking Forward: %s, %s formulations - %s' % (fdemType1, fdemType2, comp)
|
||||
|
||||
logsig = np.log(np.ones(mesh.nC)*CONDUCTIVITY)
|
||||
mu = np.ones(mesh.nC)*MU
|
||||
|
||||
if addrandoms is True:
|
||||
logsig += np.random.randn(mesh.nC)*np.log(CONDUCTIVITY)*1e-1
|
||||
mu += np.random.randn(mesh.nC)*MU*1e-1
|
||||
|
||||
if useMu is True:
|
||||
m = np.r_[logsig, mu]
|
||||
else:
|
||||
m = logsig
|
||||
|
||||
survey1 = prb1.survey
|
||||
d1 = survey1.dpred(m)
|
||||
|
||||
if verbose:
|
||||
print ' Problem 1 solved'
|
||||
|
||||
|
||||
prb2 = getFDEMProblem(fdemType2, comp, SrcList, freq, useMu, verbose)
|
||||
|
||||
survey2 = prb2.survey
|
||||
d2 = survey2.dpred(m)
|
||||
|
||||
if verbose:
|
||||
print ' Problem 2 solved'
|
||||
|
||||
r = d2-d1
|
||||
l2r = l2norm(r)
|
||||
|
||||
tol = np.max([TOL*(10**int(np.log10(0.5* (l2norm(d1) + l2norm(d2)) ))),FLR])
|
||||
print l2norm(d1), l2norm(d2), l2r , tol, l2r < tol
|
||||
return l2r < tol
|
||||
|
||||
Reference in New Issue
Block a user