mirror of
https://github.com/wassname/simpeg.git
synced 2026-07-14 11:18:18 +08:00
181 lines
5.9 KiB
Python
181 lines
5.9 KiB
Python
from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver
|
|
from SimPEG.EM.Base import BaseEMProblem
|
|
from SimPEG.EM.TDEM.SurveyTDEM import Survey as SurveyTDEM
|
|
from SimPEG.EM.TDEM.FieldsTDEM import *
|
|
from scipy.constants import mu_0
|
|
import time
|
|
|
|
class BaseTDEMProblem(Problem.BaseTimeProblem, BaseEMProblem):
|
|
"""
|
|
We start with the first order form of Maxwell's equations
|
|
"""
|
|
surveyPair = SurveyTDEM
|
|
fieldsPair = Fields
|
|
|
|
def __init__(self, mesh, mapping=None, **kwargs):
|
|
Problem.BaseTimeProblem.__init__(self, mesh, mapping=mapping, **kwargs)
|
|
|
|
|
|
# _FieldsForward_pair = FieldsTDEM #: used for the forward calculation only
|
|
|
|
def fields(self, m):
|
|
"""
|
|
Solve the forward problem for the fields.
|
|
|
|
:param numpy.array m: inversion model (nP,)
|
|
:rtype numpy.array:
|
|
:return F: fields
|
|
"""
|
|
|
|
tic = time.time()
|
|
self.curModel = m
|
|
F = self.fieldsPair(self.mesh, self.survey)
|
|
|
|
# for
|
|
|
|
|
|
def Jvec(self, m, v, u=None):
|
|
return None
|
|
|
|
def Jtvec(self, m, v, u=None):
|
|
return None
|
|
|
|
def getSourceTerm(self, tInd):
|
|
return None
|
|
# return S_m, S_e
|
|
|
|
|
|
|
|
##########################################################################################
|
|
################################ E-B Formulation #########################################
|
|
##########################################################################################
|
|
|
|
class Problem_b(BaseTDEMProblem):
|
|
"""
|
|
Starting from the quasi-static E-B formulation of Maxwell's equations (semi-discretized)
|
|
|
|
.. math::
|
|
|
|
\mathbf{C} \mathbf{e} + \\frac{\partial \mathbf{b}}{\partial t} = \mathbf{s_m} \\\\
|
|
\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{s_e}
|
|
|
|
where :math:`\mathbf{s_e}` is an integrated quantity, we eliminate :math:`\mathbf{e}` using
|
|
|
|
.. math::
|
|
\mathbf{e} = \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e}^{-1} \mathbf{s_e}
|
|
|
|
to obtain a second order semi-discretized system in :math:`\mathbf{b}`
|
|
|
|
.. math::
|
|
\mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} + \\frac{\partial \mathbf{b}}{\partial t} = \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{s_e} + \mathbf{s_m}
|
|
|
|
and moving everything except the time derivative to the rhs gives
|
|
|
|
.. math::
|
|
\\frac{\partial \mathbf{b}}{\partial t} = -\mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} + \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{s_e} + \mathbf{s_m}
|
|
|
|
For the time discretization, we use backward euler. To solve for the :math:`n+1`th time step, we have
|
|
|
|
.. math::
|
|
\\frac{\mathbf{b}^{n+1} - \mathbf{b}^{n}}{\mathbf{dt}} = -\mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b}^{n+1} + \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{s_e}^{n+1} + \mathbf{s_m}^{n+1}
|
|
|
|
re-arranging to put :math:`\mathbf{b}^{n+1}` on the left hand side gives
|
|
|
|
.. math::
|
|
(\mathbf{I} + \mathbf{dt} \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}) \mathbf{b}^{n+1} = \mathbf{b}^{n} + \mathbf{dt}(\mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{s_e}^{n+1} + \mathbf{s_m}^{n+1})
|
|
|
|
:param Mesh mesh: mesh
|
|
:param Mapping mapping: mapping
|
|
"""
|
|
|
|
_fieldType = 'b'
|
|
_eqLocs = 'FE'
|
|
fieldsPair = Fields_b
|
|
surveyPair = SurveyTDEM
|
|
|
|
def __init__(self, mesh, mapping=None, **kwargs):
|
|
BaseTDEMProblem.__init__(self, mesh, mapping=mapping, **kwargs)
|
|
|
|
def getA(self, tInd):
|
|
"""
|
|
System matrix at a given time index
|
|
|
|
.. math::
|
|
(\mathbf{I} + \mathbf{dt} \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f})
|
|
|
|
"""
|
|
|
|
dt = self.timeSteps[tInd]
|
|
C = self.mesh.edgeCurl
|
|
MeSigmaI = self.MeSigmaI
|
|
MfMui = self.MfMui
|
|
I = Utils.speye(self.mesh.nF)
|
|
|
|
A = I + dt * ( C * ( MeSigmaI * (C.T * MfMui ) ) )
|
|
|
|
if self._makeASymmetric is True:
|
|
return MeMui.T * A
|
|
return A
|
|
|
|
def getADeriv(self, freq, u, v, adjoint=False):
|
|
dt = self.timeSteps[tInd]
|
|
C = self.mesh.edgeCurl
|
|
MeSigmaI = self.MeSigmaIDeriv
|
|
MfMui = self.MfMui
|
|
I = Utils.speye(self.mesh.nF)
|
|
|
|
if adjoint:
|
|
if self._makeASymmetric is True:
|
|
v = MfMui * v
|
|
return dt * MfMui.T * ( C * ( MeSigmaIDeriv.T * ( C.T * v ) ) )
|
|
|
|
ADeriv = dt * ( C * ( MeSigmaIDeriv * (C.T * ( MfMui * v ) ) ) )
|
|
if self._makeASymmetric is True:
|
|
return MeMui.T * ADeriv
|
|
return ADeriv
|
|
|
|
|
|
def getRHS(self, tInd):
|
|
dt = self.timeSteps[tInd]
|
|
C = self.mesh.edgeCurl
|
|
MeSigmaI = self.MeSigmaI
|
|
MfMui = self.MfMui
|
|
|
|
S_m, S_e = self.getSourceTerm(tInd+1) # I think this is tInd+1 ?
|
|
|
|
B_n = np.c_[[F[src,'b',tInd] for src in self.survey.srcList]].T
|
|
if B_n.shape[0] is not 1:
|
|
raise NotImplementedError('getRHS not implemented for this shape of B_n')
|
|
|
|
return B_n + dt * (C * (MeSigmaIDeriv * S_e) + S_m)
|
|
|
|
def getRHSDeriv(self, tInd, src, v, adjoint=False):
|
|
|
|
raise NotImplementedError
|
|
|
|
dt = self.timeSteps[tInd]
|
|
C = self.mesh.edgeCurl
|
|
MeSigmaI = self.MeSigmaI
|
|
MeSigmaIDeriv = self.MeSigmaIDeriv
|
|
MfMui = self.MfMui
|
|
|
|
S_m, S_e = src.eval(tInd+1, self) # I think this is tInd+1 ?
|
|
S_m, S_e = src.evalDeriv(tInd+1, self, adjoint=adjoint) # I think this is tInd+1 ?
|
|
|
|
B_n = np.c_[[F[src,'b',tInd] for src in self.survey.srcList]].T
|
|
if B_n.shape[0] is not 1:
|
|
raise NotImplementedError('getRHS not implemented for this shape of B_n')
|
|
|
|
# return B_n + dt * (C * (MeSigmaIDeriv * S_e) + S_m)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|