Merge branch 'master' of https://github.com/simpeg/simpeg into cylClean

Conflicts:
	SimPEG/Survey.py
This commit is contained in:
rowanc1
2014-04-14 09:44:51 -07:00
12 changed files with 231 additions and 135 deletions
+1 -1
View File
@@ -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
+7 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"""
+29 -12
View File
@@ -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