mirror of
https://github.com/wassname/simpeg.git
synced 2026-09-11 12:44:29 +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.debug: print 'Calling ObjFunction.startup'
|
||||||
|
|
||||||
if self.reg.mref is None:
|
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.reg.mref = m0
|
||||||
|
|
||||||
self.phi_d = np.nan
|
self.phi_d = np.nan
|
||||||
|
|||||||
@@ -800,13 +800,15 @@ class NewtonRoot(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
tol = 1.000e-06
|
tol = 1.000e-06
|
||||||
solveTol = 0 # Default direct solve.
|
|
||||||
maxIter = 20
|
maxIter = 20
|
||||||
stepDcr = 0.5
|
stepDcr = 0.5
|
||||||
maxLS = 30
|
maxLS = 30
|
||||||
comments = False
|
comments = False
|
||||||
doLS = True
|
doLS = True
|
||||||
|
|
||||||
|
Solver = Solver
|
||||||
|
solverOpts = {}
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
Utils.setKwargs(self, **kwargs)
|
Utils.setKwargs(self, **kwargs)
|
||||||
|
|
||||||
@@ -828,13 +830,9 @@ class NewtonRoot(object):
|
|||||||
while True:
|
while True:
|
||||||
|
|
||||||
r, J = fun(x, return_g=True)
|
r, J = fun(x, return_g=True)
|
||||||
if self.solveTol == 0:
|
|
||||||
Jinv = Solver(J)
|
Jinv = self.Solver(J, **self.solverOpts)
|
||||||
dh = - Jinv.solve(r)
|
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);
|
|
||||||
|
|
||||||
muLS = 1.
|
muLS = 1.
|
||||||
LScnt = 1
|
LScnt = 1
|
||||||
@@ -862,7 +860,7 @@ class NewtonRoot(object):
|
|||||||
if norm(rt) < self.tol:
|
if norm(rt) < self.tol:
|
||||||
break
|
break
|
||||||
if self.iter > self.maxIter:
|
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
|
break
|
||||||
|
|
||||||
return x
|
return x
|
||||||
|
|||||||
+14
-1
@@ -56,7 +56,7 @@ class Parameter(object):
|
|||||||
if (self.current is None or
|
if (self.current is None or
|
||||||
not self.opt.iter == self.currentIter):
|
not self.opt.iter == self.currentIter):
|
||||||
self.current = self.nextIter()
|
self.current = self.nextIter()
|
||||||
self.currentIter = self.opt.iter
|
self.currentIter = getattr(self.opt, 'iter', 0)
|
||||||
return self.current
|
return self.current
|
||||||
|
|
||||||
def nextIter(self):
|
def nextIter(self):
|
||||||
@@ -162,3 +162,16 @@ class BetaSchedule(BetaEstimate):
|
|||||||
self.beta /= self.coolingFactor
|
self.beta /= self.coolingFactor
|
||||||
|
|
||||||
return self.beta
|
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):
|
class BaseProblem(object):
|
||||||
"""
|
"""
|
||||||
Problem is the base class for all geophysical forward problems in SimPEG.
|
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
|
__metaclass__ = Utils.SimPEGMetaClass
|
||||||
|
|
||||||
counter = None #: A SimPEG.Utils.Counter object
|
counter = None #: A SimPEG.Utils.Counter object
|
||||||
|
|
||||||
surveyPair = Survey.BaseSurvey
|
surveyPair = Survey.BaseSurvey #: A SimPEG.Survey Class
|
||||||
modelPair = Model.BaseModel
|
modelPair = Model.BaseModel #: A SimPEG.Model Class
|
||||||
|
|
||||||
def __init__(self, model, **kwargs):
|
def __init__(self, model, **kwargs):
|
||||||
Utils.setKwargs(self, **kwargs)
|
Utils.setKwargs(self, **kwargs)
|
||||||
@@ -49,7 +21,9 @@ class BaseProblem(object):
|
|||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
@property
|
@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
|
@property
|
||||||
def survey(self):
|
def survey(self):
|
||||||
@@ -73,48 +47,33 @@ class BaseProblem(object):
|
|||||||
self._survey = None
|
self._survey = None
|
||||||
|
|
||||||
@property
|
@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
|
@Utils.timeIt
|
||||||
def Jvec(self, m, v, u=None):
|
def Jvec(self, m, v, u=None):
|
||||||
"""
|
"""
|
||||||
|
Effect of J(m) on a vector v.
|
||||||
|
|
||||||
:param numpy.array m: model
|
:param numpy.array m: model
|
||||||
:param numpy.array v: vector to multiply
|
:param numpy.array v: vector to multiply
|
||||||
:param numpy.array u: fields
|
:param numpy.array u: fields
|
||||||
:rtype: numpy.array
|
:rtype: numpy.array
|
||||||
:return: Jv
|
: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.')
|
raise NotImplementedError('J is not yet implemented.')
|
||||||
|
|
||||||
@Utils.timeIt
|
@Utils.timeIt
|
||||||
def Jtvec(self, m, v, u=None):
|
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 m: model
|
||||||
:param numpy.array v: vector to multiply
|
:param numpy.array v: vector to multiply
|
||||||
:param numpy.array u: fields
|
:param numpy.array u: fields
|
||||||
:rtype: numpy.array
|
:rtype: numpy.array
|
||||||
:return: JTv
|
:return: JTv
|
||||||
|
|
||||||
Effect of transpose of J on a vector v.
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError('Jt is not yet implemented.')
|
raise NotImplementedError('Jt is not yet implemented.')
|
||||||
|
|
||||||
@@ -122,29 +81,26 @@ class BaseProblem(object):
|
|||||||
@Utils.timeIt
|
@Utils.timeIt
|
||||||
def Jvec_approx(self, m, v, u=None):
|
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 m: model
|
||||||
:param numpy.array v: vector to multiply
|
:param numpy.array v: vector to multiply
|
||||||
:param numpy.array u: fields
|
:param numpy.array u: fields
|
||||||
:rtype: numpy.array
|
:rtype: numpy.array
|
||||||
:return: Jv
|
:return: approxJv
|
||||||
|
|
||||||
Approximate effect of J on a vector v
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.Jvec(m, v, u)
|
return self.Jvec(m, v, u)
|
||||||
|
|
||||||
@Utils.timeIt
|
@Utils.timeIt
|
||||||
def Jtvec_approx(self, m, v, u=None):
|
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 m: model
|
||||||
:param numpy.array v: vector to multiply
|
:param numpy.array v: vector to multiply
|
||||||
:param numpy.array u: fields
|
:param numpy.array u: fields
|
||||||
:rtype: numpy.array
|
:rtype: numpy.array
|
||||||
:return: JTv
|
:return: JTv
|
||||||
|
|
||||||
Approximate transpose of J*v
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return self.Jtvec(m, v, u)
|
return self.Jtvec(m, v, u)
|
||||||
|
|
||||||
@@ -152,26 +108,28 @@ class BaseProblem(object):
|
|||||||
"""
|
"""
|
||||||
The field given the model.
|
The field given the model.
|
||||||
|
|
||||||
.. math::
|
:param numpy.array m: model
|
||||||
u(m)
|
: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, **survey_kwargs):
|
||||||
def createSyntheticSurvey(self, m, std=0.05, u=None, **geometry_kwargs):
|
|
||||||
"""
|
"""
|
||||||
Create synthetic survey given a model, and a standard deviation.
|
Create synthetic survey given a model, and a standard deviation.
|
||||||
|
|
||||||
:param numpy.array m: geophysical model
|
:param numpy.array m: geophysical model
|
||||||
:param numpy.array std: standard deviation
|
: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
|
:rtype: SurveyObject
|
||||||
:return: survey
|
:return: survey
|
||||||
|
|
||||||
Returns the observed data with random Gaussian noise
|
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.
|
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.pair(self)
|
||||||
survey.dtrue = survey.dpred(m, u=u)
|
survey.dtrue = survey.dpred(m, u=u)
|
||||||
noise = std*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
|
noise = std*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
|
||||||
|
|||||||
+19
-12
@@ -60,7 +60,8 @@ class BaseSurvey(object):
|
|||||||
@Utils.count
|
@Utils.count
|
||||||
@Utils.requires('prob')
|
@Utils.requires('prob')
|
||||||
def dpred(self, m, u=None):
|
def dpred(self, m, u=None):
|
||||||
"""
|
"""dpred(m, u=None)
|
||||||
|
|
||||||
Create the projected data from a model.
|
Create the projected data from a model.
|
||||||
The field, u, (if provided) will be used for the predicted data
|
The field, u, (if provided) will be used for the predicted data
|
||||||
instead of recalculating the fields (which may be expensive!).
|
instead of recalculating the fields (which may be expensive!).
|
||||||
@@ -77,9 +78,9 @@ class BaseSurvey(object):
|
|||||||
|
|
||||||
@Utils.count
|
@Utils.count
|
||||||
def projectFields(self, u):
|
def projectFields(self, u):
|
||||||
"""
|
"""projectFields(u)
|
||||||
This function projects the fields onto the data space.
|
|
||||||
|
|
||||||
|
This function projects the fields onto the data space.
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
|
|
||||||
@@ -89,22 +90,23 @@ class BaseSurvey(object):
|
|||||||
|
|
||||||
@Utils.count
|
@Utils.count
|
||||||
def projectFieldsDeriv(self, u):
|
def projectFieldsDeriv(self, u):
|
||||||
"""
|
"""projectFieldsDeriv(u)
|
||||||
This function projects the fields onto the data space.
|
|
||||||
|
|
||||||
|
This function s the derivative of projects the fields onto the data space.
|
||||||
|
|
||||||
.. math::
|
.. math::
|
||||||
|
|
||||||
\\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P}
|
\\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P}
|
||||||
"""
|
"""
|
||||||
return sp.identity(u.size)
|
raise NotImplemented('projectFields is not yet implemented.')
|
||||||
|
|
||||||
@Utils.count
|
@Utils.count
|
||||||
def residual(self, m, u=None):
|
def residual(self, m, u=None):
|
||||||
"""
|
"""residual(m, u=None)
|
||||||
|
|
||||||
:param numpy.array m: geophysical model
|
:param numpy.array m: geophysical model
|
||||||
:param numpy.array u: fields
|
:param numpy.array u: fields
|
||||||
:rtype: float
|
:rtype: numpy.array
|
||||||
:return: data residual
|
:return: data residual
|
||||||
|
|
||||||
The data residual:
|
The data residual:
|
||||||
@@ -129,6 +131,7 @@ class BaseSurvey(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if getattr(self,'_Wd',None) is None:
|
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
|
eps = np.linalg.norm(Utils.mkvc(self.dobs),2)*1e-5
|
||||||
self._Wd = 1/(abs(self.dobs)*self.std+eps)
|
self._Wd = 1/(abs(self.dobs)*self.std+eps)
|
||||||
return self._Wd
|
return self._Wd
|
||||||
@@ -137,11 +140,12 @@ class BaseSurvey(object):
|
|||||||
self._Wd = value
|
self._Wd = value
|
||||||
|
|
||||||
def residualWeighted(self, m, u=None):
|
def residualWeighted(self, m, u=None):
|
||||||
"""
|
"""residualWeighted(m, u=None)
|
||||||
|
|
||||||
:param numpy.array m: geophysical model
|
:param numpy.array m: geophysical model
|
||||||
:param numpy.array u: fields
|
:param numpy.array u: fields
|
||||||
:rtype: float
|
:rtype: numpy.array
|
||||||
:return: data residual
|
:return: weighted data residual
|
||||||
|
|
||||||
The 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})
|
\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))
|
return Utils.mkvc(self.Wd*self.residual(m, u=u))
|
||||||
|
|
||||||
@@ -205,7 +209,10 @@ class BaseRx(object):
|
|||||||
def nD(self):
|
def nD(self):
|
||||||
return self.locs.shape[0]
|
return self.locs.shape[0]
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> dbd1334e0bf48dedc12f744841e71725a9d98d50
|
||||||
class BaseTx(object):
|
class BaseTx(object):
|
||||||
"""SimPEG Transmitter Object"""
|
"""SimPEG Transmitter Object"""
|
||||||
|
|
||||||
|
|||||||
@@ -70,20 +70,37 @@ def getIndecesBlock(p0,p1,ccMesh):
|
|||||||
# Return a tuple
|
# Return a tuple
|
||||||
return ind
|
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.
|
Build a block with the conductivity specified by condVal. Returns an array.
|
||||||
condVals[0] conductivity of the block
|
vals[0] conductivity of the block
|
||||||
condVals[1] conductivity of the ground
|
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)
|
ind = getIndecesBlock(p0,p1,ccMesh)
|
||||||
|
|
||||||
sigma[ind] = condVals[0]
|
sigma[ind] = vals[0]
|
||||||
|
|
||||||
return sigma
|
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.
|
Define a two layered model. Depth of the first layer must be specified.
|
||||||
CondVals vector with the conductivity values of the layers. Eg:
|
CondVals vector with the conductivity values of the layers. Eg:
|
||||||
@@ -94,7 +111,7 @@ def defineTwoLayeredConductivity(ccMesh,depth,condVals):
|
|||||||
0 depth zf
|
0 depth zf
|
||||||
1st layer 2nd layer
|
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,:])
|
dim = np.size(ccMesh[0,:])
|
||||||
|
|
||||||
@@ -116,7 +133,7 @@ def defineTwoLayeredConductivity(ccMesh,depth,condVals):
|
|||||||
|
|
||||||
ind = getIndecesBlock(p0,p1,ccMesh)
|
ind = getIndecesBlock(p0,p1,ccMesh)
|
||||||
|
|
||||||
sigma[ind] = condVals[0];
|
sigma[ind] = vals[0];
|
||||||
|
|
||||||
return sigma
|
return sigma
|
||||||
|
|
||||||
@@ -230,9 +247,9 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
p0 = np.array([0.5,0.5,0.5])[:testDim]
|
p0 = np.array([0.5,0.5,0.5])[:testDim]
|
||||||
p1 = np.array([1.0,1.0,1.0])[: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
|
# Plot sigma model
|
||||||
print sigma.shape
|
print sigma.shape
|
||||||
@@ -242,10 +259,10 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
print('Testing the two layered model')
|
print('Testing the two layered model')
|
||||||
condVals = np.array([100,1e-5]);
|
vals = np.array([100,1e-5]);
|
||||||
depth = 1.0;
|
depth = 1.0;
|
||||||
|
|
||||||
sigma = defineTwoLayeredConductivity(ccMesh,depth,condVals)
|
sigma = defineTwoLayeredConductivity(ccMesh,depth,vals)
|
||||||
|
|
||||||
M.plotImage(sigma)
|
M.plotImage(sigma)
|
||||||
print 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')
|
axes[1].set_title('TreeMesh')
|
||||||
rM.plotGrid(ax=axes[2], **opts)
|
rM.plotGrid(ax=axes[2], **opts)
|
||||||
axes[2].set_title('LogicallyRectMesh')
|
axes[2].set_title('LogicallyRectMesh')
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
Variable Locations and Terminology
|
Variable Locations and Terminology
|
||||||
@@ -58,10 +59,12 @@ of the TensorMesh.
|
|||||||
:include-source:
|
:include-source:
|
||||||
|
|
||||||
from SimPEG import Mesh, np
|
from SimPEG import Mesh, np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
hx = np.r_[3,2,1,1,1,1,2,3]
|
hx = np.r_[3,2,1,1,1,1,2,3]
|
||||||
hy = np.r_[3,1,1,3]
|
hy = np.r_[3,1,1,3]
|
||||||
M = Mesh.TensorMesh([hx, hy])
|
M = Mesh.TensorMesh([hx, hy])
|
||||||
M.plotGrid(centers=True)
|
M.plotGrid(centers=True)
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
|
||||||
In this simple mesh, the hx vector defines the widths of the cell
|
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)
|
M.plotGrid(faces=True, nodes=True)
|
||||||
plt.title('Cell faces in the x- and y-directions.')
|
plt.title('Cell faces in the x- and y-directions.')
|
||||||
plt.legend(('Nodes', 'X-Faces', 'Y-Faces'))
|
plt.legend(('Nodes', 'X-Faces', 'Y-Faces'))
|
||||||
|
plt.show()
|
||||||
|
|
||||||
Generally, the faces are used to discretize fluxes, quantities that
|
Generally, the faces are used to discretize fluxes, quantities that
|
||||||
leave or enter the cells. As such, these fluxes have a direction to
|
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:
|
:include-source:
|
||||||
|
|
||||||
from SimPEG import Mesh
|
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?
|
How many of each?
|
||||||
-----------------
|
-----------------
|
||||||
@@ -159,7 +163,7 @@ vector grid size.
|
|||||||
:include-source:
|
:include-source:
|
||||||
|
|
||||||
from SimPEG import Mesh
|
from SimPEG import Mesh
|
||||||
Mesh.TensorMesh([4,5]).plotGrid(faces=True)
|
Mesh.TensorMesh([4,5]).plotGrid(faces=True, showIt=True)
|
||||||
|
|
||||||
|
|
||||||
Making Tensors
|
Making Tensors
|
||||||
@@ -183,7 +187,7 @@ notation::
|
|||||||
from SimPEG import Mesh, Utils
|
from SimPEG import Mesh, Utils
|
||||||
h1 = (5, 10, 1.5), (20, 5), (3, 10)
|
h1 = (5, 10, 1.5), (20, 5), (3, 10)
|
||||||
M = Mesh.TensorMesh(Utils.meshTensors(h1, h1))
|
M = Mesh.TensorMesh(Utils.meshTensors(h1, h1))
|
||||||
M.plotGrid()
|
M.plotGrid(showIt=True)
|
||||||
|
|
||||||
Hopefully, you now know how to create TensorMesh objects in SimPEG,
|
Hopefully, you now know how to create TensorMesh objects in SimPEG,
|
||||||
and by extension you are also familiar with how to create and use
|
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::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
api_Forward
|
api_Model
|
||||||
|
api_Survey
|
||||||
|
api_Problem
|
||||||
|
|
||||||
Inversion
|
Inversion
|
||||||
*********
|
*********
|
||||||
|
|||||||
Reference in New Issue
Block a user