mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-27 23:40:00 +08:00
155 lines
4.4 KiB
Python
155 lines
4.4 KiB
Python
import Utils, Survey, Problem, numpy as np, scipy.sparse as sp, gc
|
|
|
|
|
|
def _splitForward(forward):
|
|
assert forward.ispaired, 'The problem and survey must be paired.'
|
|
if isinstance(forward, Survey.BaseSurvey):
|
|
survey = forward
|
|
prob = forward.prob
|
|
elif isinstance(forward, Problem.BaseProblem):
|
|
prob = forward
|
|
survey = forward.survey
|
|
else:
|
|
raise Exception('The forward simulation must either be a problem or a survey.')
|
|
|
|
return prob, survey
|
|
|
|
|
|
class BaseDataMisfit(object):
|
|
"""BaseDataMisfit
|
|
|
|
.. note::
|
|
|
|
You should inherit from this class to create your own data misfit term.
|
|
"""
|
|
|
|
__metaclass__ = Utils.SimPEGMetaClass
|
|
|
|
debug = False #: Print debugging information
|
|
counter = None #: Set this to a SimPEG.Utils.Counter() if you want to count things
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def splitForward(self, forward):
|
|
"""splitForward(forward)
|
|
|
|
Split the forward simulation into a problem and a survey
|
|
|
|
:param Problem,Survey forward: forward simulation
|
|
:rtype: Problem,Survey
|
|
:return: (prob, survey)
|
|
|
|
"""
|
|
prob, survey = _splitForward(forward)
|
|
return prob, survey
|
|
|
|
@Utils.timeIt
|
|
def dataObj(self, forward, m, u=None):
|
|
"""dataObj(forward, m, u=None)
|
|
|
|
:param Problem,Survey forward: forward simulation
|
|
:param numpy.array m: geophysical model
|
|
:param numpy.array u: fields
|
|
:rtype: float
|
|
:return: data misfit
|
|
|
|
"""
|
|
raise NotImplementedError('This method should be overwritten.')
|
|
|
|
@Utils.timeIt
|
|
def dataObjDeriv(self, forward, m, u=None):
|
|
"""dataObjDeriv(forward, m, u=None)
|
|
|
|
:param Problem,Survey forward: forward simulation
|
|
:param numpy.array m: geophysical model
|
|
:param numpy.array u: fields
|
|
:rtype: numpy.array
|
|
:return: data misfit derivative
|
|
|
|
"""
|
|
raise NotImplementedError('This method should be overwritten.')
|
|
|
|
|
|
@Utils.timeIt
|
|
def dataObj2Deriv(self, forward, m, v, u=None):
|
|
"""dataObj2Deriv(forward, m, v, u=None)
|
|
|
|
:param Problem,Survey forward: forward simulation
|
|
:param numpy.array m: geophysical model
|
|
:param numpy.array v: vector to multiply
|
|
:param numpy.array u: fields
|
|
:rtype: numpy.array
|
|
:return: data misfit derivative
|
|
|
|
"""
|
|
raise NotImplementedError('This method should be overwritten.')
|
|
|
|
def target(self, forward):
|
|
"""target(forward)
|
|
|
|
Target for data misfit. By default this is the number of data,
|
|
which satisfies the Discrepancy Principle.
|
|
|
|
:param Problem,Survey forward: forward simulation
|
|
:rtype: float
|
|
:return: data misfit target
|
|
|
|
"""
|
|
prob, survey = self.splitForward(forward)
|
|
return survey.nD
|
|
|
|
|
|
class l2_DataMisfit(object):
|
|
"""
|
|
|
|
The data misfit with an l_2 norm:
|
|
|
|
.. math::
|
|
|
|
\mu_\\text{data} = {1\over 2}\left| \mathbf{W}_d (\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}) \\right|_2^2
|
|
|
|
"""
|
|
|
|
def __init__(self, **kwargs):
|
|
pass
|
|
|
|
def getWd(self, survey):
|
|
"""getWd(survey)
|
|
|
|
Get the data weighting matrix.
|
|
|
|
This is based on the norm of the data plus a noise floor.
|
|
|
|
:param Survey survey: geophysical survey
|
|
:rtype: scipy.sparse.csr_matrix
|
|
:return: Wd
|
|
|
|
"""
|
|
eps = np.linalg.norm(Utils.mkvc(survey.dobs),2)*1e-5
|
|
return Utils.sdiag(1/(abs(survey.dobs)*survey.std+eps))
|
|
|
|
@Utils.timeIt
|
|
def dataObj(self, forward, m, u=None):
|
|
"dataObj2Deriv(forward, m, u=None)"
|
|
prob, survey = _splitForward(forward)
|
|
Wd = self.getWd(survey)
|
|
R = Wd * survey.residual(m, u=u)
|
|
return 0.5*np.vdot(R, R)
|
|
|
|
@Utils.timeIt
|
|
def dataObjDeriv(self, forward, m, u=None):
|
|
"dataObj2Deriv(forward, m, u=None)"
|
|
prob, survey = _splitForward(forward)
|
|
if u is None: u = prob.fields(m)
|
|
Wd = self.getWd(survey)
|
|
return prob.Jtvec(m, Wd * (Wd * survey.residual(m, u=u)), u=u)
|
|
|
|
@Utils.timeIt
|
|
def dataObj2Deriv(self, forward, m, v, u=None):
|
|
"dataObj2Deriv(forward, m, v, u=None)"
|
|
prob, survey = _splitForward(forward)
|
|
if u is None: u = prob.fields(m)
|
|
Wd = self.getWd(survey)
|
|
return prob.Jtvec_approx(m, Wd * (Wd * prob.Jvec_approx(m, v, u=u)), u=u)
|