mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-28 13:02:41 +08:00
Merge branch 'master' of https://github.com/simpeg/simpeg into cylClean
Conflicts: SimPEG/Survey.py
This commit is contained in:
@@ -61,7 +61,7 @@ class BaseObjFunction(object):
|
||||
if self.debug: print 'Calling ObjFunction.startup'
|
||||
|
||||
if self.reg.mref is None:
|
||||
print 'Regularization has not set mref. SimPEG will set it to m0.'
|
||||
print 'Regularization has not set mref. SimPEG.ObjFunction will set it to m0.'
|
||||
self.reg.mref = m0
|
||||
|
||||
self.phi_d = np.nan
|
||||
|
||||
@@ -800,13 +800,15 @@ class NewtonRoot(object):
|
||||
"""
|
||||
|
||||
tol = 1.000e-06
|
||||
solveTol = 0 # Default direct solve.
|
||||
maxIter = 20
|
||||
stepDcr = 0.5
|
||||
maxLS = 30
|
||||
comments = False
|
||||
doLS = True
|
||||
|
||||
Solver = Solver
|
||||
solverOpts = {}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
|
||||
@@ -828,13 +830,9 @@ class NewtonRoot(object):
|
||||
while True:
|
||||
|
||||
r, J = fun(x, return_g=True)
|
||||
if self.solveTol == 0:
|
||||
Jinv = Solver(J)
|
||||
dh = - Jinv.solve(r)
|
||||
else:
|
||||
raise NotImplementedError('Iterative solve on NewtonRoot is not yet implemented.')
|
||||
# M = @(x) tril(J)\(diag(J).*(triu(J)\x));
|
||||
# [dh, ~] = bicgstab(J,-r,O.solveTol,500,M);
|
||||
|
||||
Jinv = self.Solver(J, **self.solverOpts)
|
||||
dh = - Jinv.solve(r)
|
||||
|
||||
muLS = 1.
|
||||
LScnt = 1
|
||||
@@ -862,7 +860,7 @@ class NewtonRoot(object):
|
||||
if norm(rt) < self.tol:
|
||||
break
|
||||
if self.iter > self.maxIter:
|
||||
print 'NewtonRoot stopped by maxIters. norm: %4.4e' % norm(rt)
|
||||
print 'NewtonRoot stopped by maxIters (%d). norm: %4.4e' % (self.maxIter, norm(rt))
|
||||
break
|
||||
|
||||
return x
|
||||
|
||||
+14
-1
@@ -56,7 +56,7 @@ class Parameter(object):
|
||||
if (self.current is None or
|
||||
not self.opt.iter == self.currentIter):
|
||||
self.current = self.nextIter()
|
||||
self.currentIter = self.opt.iter
|
||||
self.currentIter = getattr(self.opt, 'iter', 0)
|
||||
return self.current
|
||||
|
||||
def nextIter(self):
|
||||
@@ -162,3 +162,16 @@ class BetaSchedule(BetaEstimate):
|
||||
self.beta /= self.coolingFactor
|
||||
|
||||
return self.beta
|
||||
|
||||
|
||||
class UpdateReferenceModel(Parameter):
|
||||
|
||||
mref0 = None
|
||||
|
||||
def nextIter(self):
|
||||
mref = getattr(self, 'm_prev', None)
|
||||
if mref is None:
|
||||
if self.debug: print 'UpdateReferenceModel is using mref0'
|
||||
mref = self.mref0
|
||||
self.m_prev = self.objFunc.m_current
|
||||
return mref
|
||||
|
||||
+24
-66
@@ -4,42 +4,14 @@ import Model
|
||||
class BaseProblem(object):
|
||||
"""
|
||||
Problem is the base class for all geophysical forward problems in SimPEG.
|
||||
|
||||
|
||||
The problem is a partial differential equation of the form:
|
||||
|
||||
.. math::
|
||||
c(m, u) = 0
|
||||
|
||||
Here, m is the model and u is the field (or fields).
|
||||
Given the model, m, we can calculate the fields u(m),
|
||||
however, the data we collect is a subset of the fields,
|
||||
and can be defined by a linear projection, P.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pu(m)
|
||||
|
||||
We are interested in how changing the model transforms the data,
|
||||
as such we can take write the Taylor expansion:
|
||||
|
||||
.. math::
|
||||
Pu(m + hv) = Pu(m) + hP\\frac{\partial u(m)}{\partial m} v + \mathcal{O}(h^2 \left\| v \\right\| )
|
||||
|
||||
We can linearize and define the sensitivity matrix as:
|
||||
|
||||
.. math::
|
||||
J = P\\frac{\partial u}{\partial m}
|
||||
|
||||
The sensitivity matrix, and it's transpose will be used in the inverse problem
|
||||
to (locally) find how model parameters change the data, and optimize!
|
||||
"""
|
||||
|
||||
__metaclass__ = Utils.SimPEGMetaClass
|
||||
|
||||
counter = None #: A SimPEG.Utils.Counter object
|
||||
|
||||
surveyPair = Survey.BaseSurvey
|
||||
modelPair = Model.BaseModel
|
||||
surveyPair = Survey.BaseSurvey #: A SimPEG.Survey Class
|
||||
modelPair = Model.BaseModel #: A SimPEG.Model Class
|
||||
|
||||
def __init__(self, model, **kwargs):
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
@@ -49,7 +21,9 @@ class BaseProblem(object):
|
||||
self.model = model
|
||||
|
||||
@property
|
||||
def mesh(self): return self.model.mesh
|
||||
def mesh(self):
|
||||
"""SimPEG mesh that is associated with the model provided."""
|
||||
return self.model.mesh
|
||||
|
||||
@property
|
||||
def survey(self):
|
||||
@@ -73,48 +47,33 @@ class BaseProblem(object):
|
||||
self._survey = None
|
||||
|
||||
@property
|
||||
def ispaired(self): return self.survey is not None
|
||||
def ispaired(self):
|
||||
"""True if the problem is paired to a survey."""
|
||||
return self.survey is not None
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec(self, m, v, u=None):
|
||||
"""
|
||||
Effect of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:rtype: numpy.array
|
||||
:return: Jv
|
||||
|
||||
Working with the general PDE, c(m, u) = 0, where m is the model and u is the field,
|
||||
the sensitivity is defined as:
|
||||
|
||||
.. math::
|
||||
J = P\\frac{\partial u}{\partial m}
|
||||
|
||||
We can take the derivative of the PDE:
|
||||
|
||||
.. math::
|
||||
\\nabla_m c(m, u) \delta m + \\nabla_u c(m, u) \delta u = 0
|
||||
|
||||
If the forward problem is invertible, then we can rearrange for du/dm:
|
||||
|
||||
.. math::
|
||||
J = - P \left( \\nabla_u c(m, u) \\right)^{-1} \\nabla_m c(m, u)
|
||||
|
||||
This can often be computed given a vector (i.e. J(v)) rather than stored, as J is a large dense matrix.
|
||||
|
||||
"""
|
||||
raise NotImplementedError('J is not yet implemented.')
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec(self, m, v, u=None):
|
||||
"""
|
||||
Effect of transpose of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:rtype: numpy.array
|
||||
:return: JTv
|
||||
|
||||
Effect of transpose of J on a vector v.
|
||||
"""
|
||||
raise NotImplementedError('Jt is not yet implemented.')
|
||||
|
||||
@@ -122,29 +81,26 @@ class BaseProblem(object):
|
||||
@Utils.timeIt
|
||||
def Jvec_approx(self, m, v, u=None):
|
||||
"""
|
||||
Approximate effect of J(m) on a vector v
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:rtype: numpy.array
|
||||
:return: Jv
|
||||
|
||||
Approximate effect of J on a vector v
|
||||
|
||||
:return: approxJv
|
||||
"""
|
||||
return self.Jvec(m, v, u)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec_approx(self, m, v, u=None):
|
||||
"""
|
||||
Approximate effect of transpose of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:rtype: numpy.array
|
||||
:return: JTv
|
||||
|
||||
Approximate transpose of J*v
|
||||
|
||||
"""
|
||||
return self.Jtvec(m, v, u)
|
||||
|
||||
@@ -152,26 +108,28 @@ class BaseProblem(object):
|
||||
"""
|
||||
The field given the model.
|
||||
|
||||
.. math::
|
||||
u(m)
|
||||
:param numpy.array m: model
|
||||
:rtype: numpy.array
|
||||
:return: u, the fields
|
||||
|
||||
"""
|
||||
pass
|
||||
raise NotImplementedError('fields is not yet implemented.')
|
||||
|
||||
#TODO: Rename and refactor to createSyntheticData
|
||||
def createSyntheticSurvey(self, m, std=0.05, u=None, **geometry_kwargs):
|
||||
def createSyntheticSurvey(self, m, std=0.05, u=None, **survey_kwargs):
|
||||
"""
|
||||
Create synthetic survey given a model, and a standard deviation.
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array std: standard deviation
|
||||
:param numpy.array u: fields for the given model (if pre-calculated)
|
||||
:param numpy.array survey_kwargs: Keyword arguments for initiating the survey.
|
||||
:rtype: SurveyObject
|
||||
:return: survey
|
||||
|
||||
Returns the observed data with random Gaussian noise
|
||||
and Wd which is the same size as data, and can be used to weight the inversion.
|
||||
"""
|
||||
survey = self.surveyPair(mtrue=m, **geometry_kwargs)
|
||||
survey = self.surveyPair(mtrue=m, **survey_kwargs)
|
||||
survey.pair(self)
|
||||
survey.dtrue = survey.dpred(m, u=u)
|
||||
noise = std*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
|
||||
|
||||
+19
-12
@@ -60,7 +60,8 @@ class BaseSurvey(object):
|
||||
@Utils.count
|
||||
@Utils.requires('prob')
|
||||
def dpred(self, m, u=None):
|
||||
"""
|
||||
"""dpred(m, u=None)
|
||||
|
||||
Create the projected data from a model.
|
||||
The field, u, (if provided) will be used for the predicted data
|
||||
instead of recalculating the fields (which may be expensive!).
|
||||
@@ -77,9 +78,9 @@ class BaseSurvey(object):
|
||||
|
||||
@Utils.count
|
||||
def projectFields(self, u):
|
||||
"""
|
||||
This function projects the fields onto the data space.
|
||||
"""projectFields(u)
|
||||
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -89,22 +90,23 @@ class BaseSurvey(object):
|
||||
|
||||
@Utils.count
|
||||
def projectFieldsDeriv(self, u):
|
||||
"""
|
||||
This function projects the fields onto the data space.
|
||||
"""projectFieldsDeriv(u)
|
||||
|
||||
This function s the derivative of projects the fields onto the data space.
|
||||
|
||||
.. math::
|
||||
|
||||
\\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P}
|
||||
"""
|
||||
return sp.identity(u.size)
|
||||
raise NotImplemented('projectFields is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def residual(self, m, u=None):
|
||||
"""
|
||||
"""residual(m, u=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:rtype: float
|
||||
:rtype: numpy.array
|
||||
:return: data residual
|
||||
|
||||
The data residual:
|
||||
@@ -129,6 +131,7 @@ class BaseSurvey(object):
|
||||
|
||||
"""
|
||||
if getattr(self,'_Wd',None) is None:
|
||||
print 'SimPEG is making Survey.Wd to be norm of the data plus a floor.'
|
||||
eps = np.linalg.norm(Utils.mkvc(self.dobs),2)*1e-5
|
||||
self._Wd = 1/(abs(self.dobs)*self.std+eps)
|
||||
return self._Wd
|
||||
@@ -137,11 +140,12 @@ class BaseSurvey(object):
|
||||
self._Wd = value
|
||||
|
||||
def residualWeighted(self, m, u=None):
|
||||
"""
|
||||
"""residualWeighted(m, u=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:rtype: float
|
||||
:return: data residual
|
||||
:rtype: numpy.array
|
||||
:return: weighted data residual
|
||||
|
||||
The weighted data residual:
|
||||
|
||||
@@ -149,7 +153,7 @@ class BaseSurvey(object):
|
||||
|
||||
\mu_\\text{data}^{\\text{weighted}} = \mathbf{W}_d(\mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs})
|
||||
|
||||
Where W_d is a covariance matrix that weights the data residual.
|
||||
Where \\\\(W_d\\\\) is a covariance matrix that weights the data residual.
|
||||
"""
|
||||
return Utils.mkvc(self.Wd*self.residual(m, u=u))
|
||||
|
||||
@@ -205,7 +209,10 @@ class BaseRx(object):
|
||||
def nD(self):
|
||||
return self.locs.shape[0]
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> dbd1334e0bf48dedc12f744841e71725a9d98d50
|
||||
class BaseTx(object):
|
||||
"""SimPEG Transmitter Object"""
|
||||
|
||||
|
||||
@@ -70,20 +70,37 @@ def getIndecesBlock(p0,p1,ccMesh):
|
||||
# Return a tuple
|
||||
return ind
|
||||
|
||||
def defineBlockConductivity(ccMesh,p0,p1,condVals):
|
||||
def defineBlock(ccMesh,p0,p1,vals=[0,1]):
|
||||
"""
|
||||
Build a block with the conductivity specified by condVal. Returns an array.
|
||||
condVals[0] conductivity of the block
|
||||
condVals[1] conductivity of the ground
|
||||
vals[0] conductivity of the block
|
||||
vals[1] conductivity of the ground
|
||||
"""
|
||||
sigma = np.zeros(ccMesh.shape[0]) + condVals[1]
|
||||
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
|
||||
ind = getIndecesBlock(p0,p1,ccMesh)
|
||||
|
||||
sigma[ind] = condVals[0]
|
||||
sigma[ind] = vals[0]
|
||||
|
||||
return sigma
|
||||
|
||||
def defineTwoLayeredConductivity(ccMesh,depth,condVals):
|
||||
def defineElipse(ccMesh, center=[0,0,0], anisotropy=[1,1,1], slope=10., theta=0.):
|
||||
G = ccMesh.copy()
|
||||
dim = ccMesh.shape[1]
|
||||
for i in range(dim):
|
||||
G[:, i] = G[:,i] - center[i]
|
||||
|
||||
theta = -theta*np.pi/180
|
||||
M = np.array([[np.cos(theta),-np.sin(theta),0],[np.sin(theta),np.cos(theta),0],[0,0,1.]])
|
||||
M = M[:dim,:dim]
|
||||
G = M.dot(G.T).T
|
||||
|
||||
for i in range(dim):
|
||||
G[:, i] = G[:,i]/anisotropy[i]*2.
|
||||
|
||||
D = np.sqrt(np.sum(G**2,axis=1))
|
||||
return -np.arctan((D-1)*slope)*(2./np.pi)/2.+0.5
|
||||
|
||||
def defineTwoLayers(ccMesh,depth,vals=[0,1]):
|
||||
"""
|
||||
Define a two layered model. Depth of the first layer must be specified.
|
||||
CondVals vector with the conductivity values of the layers. Eg:
|
||||
@@ -94,7 +111,7 @@ def defineTwoLayeredConductivity(ccMesh,depth,condVals):
|
||||
0 depth zf
|
||||
1st layer 2nd layer
|
||||
"""
|
||||
sigma = np.zeros(ccMesh.shape[0]) + condVals[1]
|
||||
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
|
||||
|
||||
dim = np.size(ccMesh[0,:])
|
||||
|
||||
@@ -116,7 +133,7 @@ def defineTwoLayeredConductivity(ccMesh,depth,condVals):
|
||||
|
||||
ind = getIndecesBlock(p0,p1,ccMesh)
|
||||
|
||||
sigma[ind] = condVals[0];
|
||||
sigma[ind] = vals[0];
|
||||
|
||||
return sigma
|
||||
|
||||
@@ -230,9 +247,9 @@ if __name__ == '__main__':
|
||||
|
||||
p0 = np.array([0.5,0.5,0.5])[:testDim]
|
||||
p1 = np.array([1.0,1.0,1.0])[:testDim]
|
||||
condVals = np.array([100,1e-6])
|
||||
vals = np.array([100,1e-6])
|
||||
|
||||
sigma = defineBlockConductivity(ccMesh,p0,p1,condVals)
|
||||
sigma = defineBlockConductivity(ccMesh,p0,p1,vals)
|
||||
|
||||
# Plot sigma model
|
||||
print sigma.shape
|
||||
@@ -242,10 +259,10 @@ if __name__ == '__main__':
|
||||
|
||||
# -----------------------------------------
|
||||
print('Testing the two layered model')
|
||||
condVals = np.array([100,1e-5]);
|
||||
vals = np.array([100,1e-5]);
|
||||
depth = 1.0;
|
||||
|
||||
sigma = defineTwoLayeredConductivity(ccMesh,depth,condVals)
|
||||
sigma = defineTwoLayeredConductivity(ccMesh,depth,vals)
|
||||
|
||||
M.plotImage(sigma)
|
||||
print sigma
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
.. _api_Forward:
|
||||
|
||||
|
||||
Model
|
||||
=====
|
||||
|
||||
.. automodule:: SimPEG.Model
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
Survey
|
||||
======
|
||||
|
||||
.. automodule:: SimPEG.Survey
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
Problem
|
||||
=======
|
||||
|
||||
.. automodule:: SimPEG.Problem
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
+7
-3
@@ -39,6 +39,7 @@ the implementations.
|
||||
axes[1].set_title('TreeMesh')
|
||||
rM.plotGrid(ax=axes[2], **opts)
|
||||
axes[2].set_title('LogicallyRectMesh')
|
||||
plt.show()
|
||||
|
||||
|
||||
Variable Locations and Terminology
|
||||
@@ -58,10 +59,12 @@ of the TensorMesh.
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, np
|
||||
import matplotlib.pyplot as plt
|
||||
hx = np.r_[3,2,1,1,1,1,2,3]
|
||||
hy = np.r_[3,1,1,3]
|
||||
M = Mesh.TensorMesh([hx, hy])
|
||||
M.plotGrid(centers=True)
|
||||
plt.show()
|
||||
|
||||
|
||||
In this simple mesh, the hx vector defines the widths of the cell
|
||||
@@ -85,6 +88,7 @@ plotted above as red circles. Other terminology for this mesh are:
|
||||
M.plotGrid(faces=True, nodes=True)
|
||||
plt.title('Cell faces in the x- and y-directions.')
|
||||
plt.legend(('Nodes', 'X-Faces', 'Y-Faces'))
|
||||
plt.show()
|
||||
|
||||
Generally, the faces are used to discretize fluxes, quantities that
|
||||
leave or enter the cells. As such, these fluxes have a direction to
|
||||
@@ -102,7 +106,7 @@ and live on the edges(!) of the cell.
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh
|
||||
Mesh.TensorMesh([1,1,1]).plotGrid(faces=True, edges=True, centers=True)
|
||||
Mesh.TensorMesh([1,1,1]).plotGrid(faces=True, edges=True, centers=True, showIt=True)
|
||||
|
||||
How many of each?
|
||||
-----------------
|
||||
@@ -159,7 +163,7 @@ vector grid size.
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh
|
||||
Mesh.TensorMesh([4,5]).plotGrid(faces=True)
|
||||
Mesh.TensorMesh([4,5]).plotGrid(faces=True, showIt=True)
|
||||
|
||||
|
||||
Making Tensors
|
||||
@@ -183,7 +187,7 @@ notation::
|
||||
from SimPEG import Mesh, Utils
|
||||
h1 = (5, 10, 1.5), (20, 5), (3, 10)
|
||||
M = Mesh.TensorMesh(Utils.meshTensors(h1, h1))
|
||||
M.plotGrid()
|
||||
M.plotGrid(showIt=True)
|
||||
|
||||
Hopefully, you now know how to create TensorMesh objects in SimPEG,
|
||||
and by extension you are also familiar with how to create and use
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
.. _api_Model:
|
||||
|
||||
|
||||
Model
|
||||
*****
|
||||
|
||||
A SimPEG model operates on a vector and transforms it to another space.
|
||||
We will use an example commonly applied in electromagnetics (EM) of the
|
||||
log-conductivity model (:class:`SimPEG.Model.LogModel`).
|
||||
Electrical conductivity varies over many orders of magnitude, so it is a common
|
||||
technique when solving the inverse problem to parameterize and optimize in terms
|
||||
of log conductivity. This makes sense not only because it ensures all conductivities
|
||||
will be positive, but because this is fundamentally the space where conductivity
|
||||
lives (i.e. it varies logarithmically). In SimPEG, we use the term Model to
|
||||
describe how to get between these two spaces.
|
||||
|
||||
The API
|
||||
=======
|
||||
|
||||
.. autoclass:: SimPEG.Model.BaseModel
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Model.BaseNonLinearModel
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Model.ComboModel
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Common Models
|
||||
=============
|
||||
|
||||
.. autoclass:: SimPEG.Model.LogModel
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Model.Vertical1DModel
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Model.Mesh2Mesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,71 @@
|
||||
.. _api_Problem:
|
||||
|
||||
|
||||
Problem
|
||||
*******
|
||||
|
||||
The problem is a partial differential equation of the form:
|
||||
|
||||
.. math::
|
||||
|
||||
c(m, u) = 0
|
||||
|
||||
Here, \\(m\\) is the model and u is the field (or fields).
|
||||
Given the model, \\(m\\), we can calculate the fields \\(u(m)\\),
|
||||
however, the data we collect is a subset of the fields,
|
||||
and can be defined by a linear projection, \\(P\\).
|
||||
|
||||
.. math::
|
||||
|
||||
d_\text{pred} = P u(m)
|
||||
|
||||
For the inverse problem, we are interested in how changing the model transforms the data,
|
||||
as such we can take write the Taylor expansion:
|
||||
|
||||
.. math::
|
||||
|
||||
Pu(m + hv) = Pu(m) + hP\frac{\partial u(m)}{\partial m} v + \mathcal{O}(h^2 \left\| v \right\| )
|
||||
|
||||
We can linearize and define the sensitivity matrix as:
|
||||
|
||||
.. math::
|
||||
|
||||
J = P\frac{\partial u}{\partial m}
|
||||
|
||||
The sensitivity matrix, and it's transpose will be used in the inverse problem
|
||||
to (locally) find how model parameters change the data, and optimize!
|
||||
|
||||
|
||||
Working with the general PDE, \\(c(m, u) = 0\\), where m is the model and u is the field,
|
||||
the sensitivity is defined as:
|
||||
|
||||
.. math::
|
||||
|
||||
J = P\frac{\partial u}{\partial m}
|
||||
|
||||
We can take the derivative of the PDE:
|
||||
|
||||
.. math::
|
||||
|
||||
\nabla_m c(m, u) \partial m + \nabla_u c(m, u) \partial u = 0
|
||||
|
||||
If the forward problem is invertible, then we can rearrange for \\(\\frac{\\partial u}{\\partial m}\\):
|
||||
|
||||
.. math::
|
||||
|
||||
J = - P \left( \nabla_u c(m, u) \right)^{-1} \nabla_m c(m, u)
|
||||
|
||||
This can often be computed given a vector (i.e. \\(J(v)\\)) rather than stored, as \\(J\\) is a large dense matrix.
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
u(m)
|
||||
|
||||
The API
|
||||
=======
|
||||
|
||||
.. automodule:: SimPEG.Problem
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.. _api_Survey:
|
||||
|
||||
|
||||
Survey
|
||||
======
|
||||
|
||||
.. automodule:: SimPEG.Survey
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
+3
-1
@@ -39,7 +39,9 @@ Forward Problems
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api_Forward
|
||||
api_Model
|
||||
api_Survey
|
||||
api_Problem
|
||||
|
||||
Inversion
|
||||
*********
|
||||
|
||||
Reference in New Issue
Block a user