mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-28 02:47:11 +08:00
183 lines
5.2 KiB
Python
183 lines
5.2 KiB
Python
from SimPEG import *
|
|
from BaseDC import SurveyDC, FieldsDC_CC
|
|
|
|
class SurveyIP(SurveyDC):
|
|
"""
|
|
**SurveyDC**
|
|
|
|
Geophysical DC resistivity data.
|
|
|
|
"""
|
|
|
|
def __init__(self, srcList, **kwargs):
|
|
self.srcList = srcList
|
|
Survey.BaseSurvey.__init__(self, **kwargs)
|
|
self._Ps = {}
|
|
|
|
def dpred(self, m, f=None):
|
|
"""
|
|
Predicted data.
|
|
|
|
.. math::
|
|
d_\\text{pred} = Pf(m)
|
|
"""
|
|
|
|
return self.prob.forward(m)
|
|
|
|
|
|
class ProblemIP(Problem.BaseProblem):
|
|
"""
|
|
**ProblemIP**
|
|
|
|
Geophysical IP resistivity problem.
|
|
|
|
"""
|
|
|
|
surveyPair = SurveyDC
|
|
Solver = Solver
|
|
sigma = None
|
|
Ainv = None
|
|
u = None
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
Problem.BaseProblem.__init__(self, mesh)
|
|
self.mesh.setCellGradBC('neumann')
|
|
Utils.setKwargs(self, **kwargs)
|
|
|
|
# deleteTheseOnModelUpdate = ['_A', '_Msig', '_dMdsig']
|
|
|
|
@property
|
|
def Msig(self):
|
|
if getattr(self, '_Msig', None) is None:
|
|
# sigma = self.curModel.transform
|
|
sigma = self.sigma
|
|
Av = self.mesh.aveF2CC
|
|
self._Msig = Utils.sdiag(1/(self.mesh.dim * Av.T * (1/sigma)))
|
|
return self._Msig
|
|
|
|
@property
|
|
def dMdsig(self):
|
|
if getattr(self, '_dMdsig', None) is None:
|
|
# sigma = self.curModel.transform
|
|
sigma = self.sigma
|
|
Av = self.mesh.aveF2CC
|
|
dMdprop = self.mesh.dim * Utils.sdiag(self.Msig.diagonal()**2) * Av.T * Utils.sdiag(1./sigma**2)
|
|
self._dMdsig = lambda Gu: Utils.sdiag(Gu) * dMdprop
|
|
return self._dMdsig
|
|
|
|
@property
|
|
def A(self):
|
|
"""
|
|
Makes the matrix A(m) for the DC resistivity problem.
|
|
|
|
:param numpy.array m: model
|
|
:rtype: scipy.csc_matrix
|
|
:return: A(m)
|
|
|
|
.. math::
|
|
c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0
|
|
|
|
Where M() is the mass matrix and mT is the model transform.
|
|
"""
|
|
if getattr(self, '_A', None) is None:
|
|
D = self.mesh.faceDiv
|
|
G = self.mesh.cellGrad
|
|
self._A = D*self.Msig*G
|
|
# Remove the null space from the matrix.
|
|
self._A[-1,-1] /= self.mesh.vol[-1]
|
|
self._A = self._A.tocsc()
|
|
return self._A
|
|
|
|
def getRHS(self):
|
|
# if self.mesh not in self._rhsDict:
|
|
RHS = np.array([src.eval(self) for src in self.survey.srcList]).T
|
|
# self._rhsDict[mesh] = RHS
|
|
# return self._rhsDict[mesh]
|
|
return RHS
|
|
|
|
def fields(self, m):
|
|
if self.u is None:
|
|
A = self.A
|
|
if self.Ainv == None:
|
|
self.Ainv = self.Solver(A, **self.solverOpts)
|
|
Q = self.getRHS()
|
|
self.u = self.Ainv * Q
|
|
return self.u
|
|
|
|
def forward(self, m, u=None):
|
|
# Set current model; clear dependent property $\mathbf{A(m)}$
|
|
self.curModel = m
|
|
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
|
sigma = self.sigma
|
|
if self.u is None:
|
|
# Run forward simulation if $u$ not provided
|
|
u = self.fields(sigma)
|
|
|
|
shp = (self.mesh.nC, self.survey.nSrc)
|
|
u = self.u.reshape(shp, order='F')
|
|
|
|
D = self.mesh.faceDiv
|
|
G = self.mesh.cellGrad
|
|
# Derivative of model transform, $\deriv{\sigma}{\m}$
|
|
# dsigdm_x_v = self.curModel.transformDeriv * v
|
|
|
|
dsigdm_x_v = Utils.sdiag(sigma) * self.curModel.transformDeriv * m
|
|
|
|
# Take derivative of $C(m,u)$ w.r.t. $m$
|
|
dCdm_x_v = np.empty_like(u)
|
|
# loop over fields for each source
|
|
for i in range(self.survey.nSrc):
|
|
# Derivative of inner product, $\left(\mathbf{M}_{1/\sigma}^f\right)^{-1}$
|
|
dAdsig = D * self.dMdsig( G * u[:,i] )
|
|
dCdm_x_v[:, i] = dAdsig * dsigdm_x_v
|
|
|
|
# Take derivative of $C(m,u)$ w.r.t. $u$
|
|
|
|
if self.Ainv == None:
|
|
self.Ainv = self.Solver(A, **self.solverOpts)
|
|
|
|
# dCdu = self.A
|
|
# Solve for $\deriv{u}{m}$
|
|
# dCdu_inv = self.Solver(dCdu, **self.solverOpts)
|
|
P = self.survey.getP(self.mesh)
|
|
J_x_v = - P * mkvc( self.Ainv * dCdm_x_v )
|
|
return -J_x_v
|
|
|
|
def Jvec(self, m, v, f=None):
|
|
return self.forward(v)
|
|
|
|
def Jtvec(self, m, v, f=None):
|
|
|
|
self.curModel = m
|
|
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
|
sigma = self.sigma
|
|
if self.u is None:
|
|
u = self.fields(sigma)
|
|
else:
|
|
u = self.u
|
|
shp = (self.mesh.nC, self.survey.nSrc)
|
|
u = u.reshape(shp, order='F')
|
|
P = self.survey.getP(self.mesh)
|
|
PT_x_v = (P.T*v).reshape(shp, order='F')
|
|
|
|
D = self.mesh.faceDiv
|
|
G = self.mesh.cellGrad
|
|
A = self.A
|
|
mT_dm = Utils.sdiag(sigma)*self.mapping.deriv(m)
|
|
# mT_dm = self.mapping.deriv(m)
|
|
|
|
# dCdu = A.T
|
|
# Ainv = self.Solver(dCdu, **self.solverOpts)
|
|
# if self.Ainv == None:
|
|
self.Ainv = self.Solver(A.T, **self.solverOpts)
|
|
|
|
w = self.Ainv * PT_x_v
|
|
|
|
Jtv = 0
|
|
for i, ui in enumerate(u.T): # loop over each column
|
|
Jtv += self.dMdsig( G * ui ).T * ( D.T * w[:,i] )
|
|
|
|
Jtv = - mT_dm.T * ( Jtv )
|
|
return -Jtv
|
|
|