mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-30 07:38:08 +08:00
179 lines
5.3 KiB
Python
179 lines
5.3 KiB
Python
import numpy as np
|
|
from SimPEG.utils import sdiag
|
|
|
|
class Inversion(object):
|
|
"""docstring for Inversion"""
|
|
|
|
maxIter = 10
|
|
|
|
def __init__(self, prob, reg, opt):
|
|
self.prob = prob
|
|
self.reg = reg
|
|
self.opt = opt
|
|
|
|
@property
|
|
def Wd(self):
|
|
"""
|
|
Standard deviation weighting matrix.
|
|
"""
|
|
return sdiag(1/self.prob.std)
|
|
|
|
def run(self, m0):
|
|
m = m0
|
|
self._iter = 0
|
|
while True:
|
|
self._beta = self.getBeta()
|
|
m = self.opt.minimize(self.evalFunction,m)
|
|
if self.stoppingCriteria(): break
|
|
self._iter += 1
|
|
|
|
def getBeta(self):
|
|
return 1
|
|
|
|
def stoppingCriteria(self):
|
|
self._STOP = np.zeros(2,dtype=bool)
|
|
self._STOP[0] = self._iter >= maxIter
|
|
self._STOP[1] = self._phi_d_last <= self.phi_d_target
|
|
return np.any(self._STOP)
|
|
|
|
|
|
def evalFunction(self, m, return_g=True, return_H=True):
|
|
|
|
u = self.prob.field(m)
|
|
phi_d = self.dataObj(m, u)
|
|
phi_m = self.modelObj(m)
|
|
|
|
self._phi_d_last = phi_d
|
|
self._phi_m_last = phi_m
|
|
|
|
f = phi_d + self._beta * phi_m
|
|
|
|
out = (f,)
|
|
if return_g:
|
|
phi_dDeriv = self.dataObjDeriv(m, u)
|
|
phi_mDeriv = self.modelObjDeriv(m)
|
|
|
|
g = phi_dDeriv + self._beta * phi_mDeriv
|
|
out += (g,)
|
|
|
|
if return_H:
|
|
def H_fun(v):
|
|
phi_d2Deriv = self.dataObj2Deriv(m, u, v)
|
|
phi_m2Deriv = self.modelObj2Deriv(m)*v
|
|
|
|
return phi_d2Deriv + self._beta * phi_m2Deriv
|
|
|
|
out += (H_fun,)
|
|
return out
|
|
|
|
|
|
def modelObj(self, m, u=None):
|
|
self.reg.misfit(m)
|
|
|
|
|
|
def dataObj(self, m, u=None):
|
|
"""
|
|
:param numpy.array m: geophysical model
|
|
:param numpy.array u: fields
|
|
:rtype: float
|
|
:return: data misfit
|
|
|
|
The data misfit using an l_2 norm is:
|
|
|
|
.. math::
|
|
|
|
\mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2
|
|
|
|
Where P is a projection matrix that brings the field on the full domain to the data measurement locations;
|
|
u is the field of interest; d_obs is the observed data; and W is the weighting matrix.
|
|
"""
|
|
R = self.Wd*self.prob.misfit(u=u)
|
|
R = mkvc(R)
|
|
return 0.5*R.dot(R)
|
|
|
|
def dataObjDeriv(self, m, u=None):
|
|
"""
|
|
:param numpy.array m: geophysical model
|
|
:param numpy.array u: fields
|
|
:rtype: numpy.array
|
|
:return: data misfit derivative
|
|
|
|
The data misfit using an l_2 norm is:
|
|
|
|
.. math::
|
|
|
|
\mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2
|
|
|
|
If the field, u, is provided, the calculation of the data is fast:
|
|
|
|
.. math::
|
|
|
|
\mathbf{d}_\\text{pred} = \mathbf{Pu(m)}
|
|
|
|
\mathbf{R} = \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs})
|
|
|
|
Where P is a projection matrix that brings the field on the full domain to the data measurement locations;
|
|
u is the field of interest; d_obs is the observed data; and W is the weighting matrix.
|
|
|
|
The derivative of this, with respect to the model, is:
|
|
|
|
.. math::
|
|
|
|
\\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R}
|
|
|
|
"""
|
|
if u is None:
|
|
u = self.field(m)
|
|
|
|
R = self.W*(self.dpred(m, u=u) - self.dobs)
|
|
|
|
dmisfit = 0
|
|
for i in range(self.RHS.shape[1]): # Loop over each right hand side
|
|
dmisfit += self.Jt(m, self.W[:,i]*R[:,i], u=u[:,i])
|
|
|
|
return dmisfit
|
|
|
|
def dataObj2Deriv(self, m, u=None):
|
|
"""
|
|
:param numpy.array m: geophysical model
|
|
:param numpy.array u: fields
|
|
:rtype: numpy.array
|
|
:return: data misfit derivative
|
|
|
|
The data misfit using an l_2 norm is:
|
|
|
|
.. math::
|
|
|
|
\mu_\\text{data} = {1\over 2}\left| \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2
|
|
|
|
If the field, u, is provided, the calculation of the data is fast:
|
|
|
|
.. math::
|
|
|
|
\mathbf{d}_\\text{pred} = \mathbf{Pu(m)}
|
|
|
|
\mathbf{R} = \mathbf{W} \circ (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs})
|
|
|
|
Where P is a projection matrix that brings the field on the full domain to the data measurement locations;
|
|
u is the field of interest; d_obs is the observed data; and W is the weighting matrix.
|
|
|
|
The derivative of this, with respect to the model, is:
|
|
|
|
.. math::
|
|
|
|
\\frac{\partial \mu_\\text{data}}{\partial \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ R}
|
|
|
|
\\frac{\partial^2 \mu_\\text{data}}{\partial^2 \mathbf{m}} = \mathbf{J}^\\top \mathbf{W \circ W J}
|
|
|
|
"""
|
|
if u is None:
|
|
u = self.field(m)
|
|
|
|
R = self.W*(self.dpred(m, u=u) - self.dobs)
|
|
|
|
dmisfit = 0
|
|
for i in range(self.RHS.shape[1]): # Loop over each right hand side
|
|
dmisfit += self.Jt(m, self.W[:,i]*R[:,i], u=u[:,i])
|
|
|
|
return dmisfit
|