Problem.Jvec, Problem.Jtvec, Problem.fields, DataMisfit, survey.dpred take a fields object f (not a solution vector, u)

This commit is contained in:
Lindsey Heagy
2016-03-29 22:49:03 -07:00
parent 1d208a8747
commit 0a0caceaca
7 changed files with 98 additions and 104 deletions
+11 -13
View File
@@ -200,11 +200,11 @@ class ProblemDC_CC(Problem.BaseProblem):
return F return F
def Jvec(self, m, v, u=None): def Jvec(self, m, v, f=None):
""" """
: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 Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: Jv :return: Jv
@@ -225,11 +225,10 @@ class ProblemDC_CC(Problem.BaseProblem):
# Set current model; clear dependent property $\mathbf{A(m)}$ # Set current model; clear dependent property $\mathbf{A(m)}$
self.curModel = m self.curModel = m
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
if u is None: if f is None:
# Run forward simulation if $u$ not provided # Run forward simulation if $u$ not provided
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol'] f = self.fields(self.curModel)
else: u = f[self.survey.srcList, 'phi_sol']
u = u[self.survey.srcList, 'phi_sol']
D = self.mesh.faceDiv D = self.mesh.faceDiv
G = self.mesh.cellGrad G = self.mesh.cellGrad
@@ -251,19 +250,18 @@ class ProblemDC_CC(Problem.BaseProblem):
if self.Ainv is None: if self.Ainv is None:
self.Ainv = self.Solver(dA_du, **self.solverOpts) self.Ainv = self.Solver(dA_du, **self.solverOpts)
P = self.survey.getP(self.mesh) P = self.survey.getP(self.mesh)
Jv = - P * mkvc( self.Ainv * dCdm_x_v ) Jv = - P * mkvc( self.Ainv * dCdm_x_v )
return Jv return Jv
def Jtvec(self, m, v, u=None): def Jtvec(self, m, v, f=None):
self.curModel = m self.curModel = m
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
if u is None: if f is None:
# Run forward simulation if $u$ not provided # Run forward simulation if $f$ not provided
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol'] f = self.fields(self.curModel)
else: u = f[self.survey.srcList, 'phi_sol']
u = u[self.survey.srcList, 'phi_sol']
shp = u.shape shp = u.shape
P = self.survey.getP(self.mesh) P = self.survey.getP(self.mesh)
+4 -4
View File
@@ -14,12 +14,12 @@ class SurveyIP(SurveyDC):
Survey.BaseSurvey.__init__(self, **kwargs) Survey.BaseSurvey.__init__(self, **kwargs)
self._Ps = {} self._Ps = {}
def dpred(self, m, u=None): def dpred(self, m, f=None):
""" """
Predicted data. Predicted data.
.. math:: .. math::
d_\\text{pred} = Pu(m) d_\\text{pred} = Pf(m)
""" """
return self.prob.forward(m) return self.prob.forward(m)
@@ -143,10 +143,10 @@ class ProblemIP(Problem.BaseProblem):
J_x_v = - P * mkvc( self.Ainv * dCdm_x_v ) J_x_v = - P * mkvc( self.Ainv * dCdm_x_v )
return -J_x_v return -J_x_v
def Jvec(self, m, v, u=None): def Jvec(self, m, v, f=None):
return self.forward(v) return self.forward(v)
def Jtvec(self, m, v, u=None): def Jtvec(self, m, v, f=None):
self.curModel = m self.curModel = m
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$ # sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
+21 -25
View File
@@ -22,11 +22,11 @@ class BaseDataMisfit(object):
Utils.setKwargs(self,**kwargs) Utils.setKwargs(self,**kwargs)
@Utils.timeIt @Utils.timeIt
def eval(self, m, u=None): def eval(self, m, f=None):
"""eval(m, u=None) """eval(m, f=None)
:param numpy.array m: geophysical model :param numpy.array m: geophysical model
:param numpy.array u: fields :param Fields f: fields
:rtype: float :rtype: float
:return: data misfit :return: data misfit
@@ -34,11 +34,11 @@ class BaseDataMisfit(object):
raise NotImplementedError('This method should be overwritten.') raise NotImplementedError('This method should be overwritten.')
@Utils.timeIt @Utils.timeIt
def evalDeriv(self, m, u=None): def evalDeriv(self, m, f=None):
"""evalDeriv(m, u=None) """evalDeriv(m, f=None)
:param numpy.array m: geophysical model :param numpy.array m: geophysical model
:param numpy.array u: fields :param Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: data misfit derivative :return: data misfit derivative
@@ -47,12 +47,12 @@ class BaseDataMisfit(object):
@Utils.timeIt @Utils.timeIt
def eval2Deriv(self, m, v, u=None): def eval2Deriv(self, m, v, f=None):
"""eval2Deriv(m, v, u=None) """eval2Deriv(m, v, f=None)
:param numpy.array m: geophysical model :param numpy.array m: geophysical model
:param numpy.array v: vector to multiply :param numpy.array v: vector to multiply
:param numpy.array u: fields :param Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: data misfit derivative :return: data misfit derivative
@@ -108,24 +108,20 @@ class l2_DataMisfit(BaseDataMisfit):
self._Wd = value self._Wd = value
@Utils.timeIt @Utils.timeIt
def eval(self, m, u=None): def eval(self, m, f=None):
"eval(m, u=None)" "eval(m, f=None)"
prob = self.prob if f is None: f = self.prob.fields(m)
survey = self.survey R = self.Wd * self.survey.residual(m, f)
R = self.Wd * survey.residual(m, u)
return 0.5*np.vdot(R, R) return 0.5*np.vdot(R, R)
@Utils.timeIt @Utils.timeIt
def evalDeriv(self, m, u=None): def evalDeriv(self, m, f=None):
"evalDeriv(m, u=None)" "evalDeriv(m, f=None)"
prob = self.prob if f is None: f = self.prob.fields(m)
survey = self.survey return self.prob.Jtvec(m, self.Wd * (self.Wd * self.survey.residual(m, f=f)), f=f)
if u is None: u = prob.fields(m)
return prob.Jtvec(m, self.Wd * (self.Wd * survey.residual(m, u)), u)
@Utils.timeIt @Utils.timeIt
def eval2Deriv(self, m, v, u=None): def eval2Deriv(self, m, v, f=None):
"eval2Deriv(m, v, u=None)" "eval2Deriv(m, v, f=None)"
prob = self.prob if f is None: f = prob.fields(m)
if u is None: u = prob.fields(m) return self.prob.Jtvec_approx(m, self.Wd * (self.Wd * prob.Jvec_approx(m, v, f=f)), f=f)
return prob.Jtvec_approx(m, self.Wd * (self.Wd * prob.Jvec_approx(m, v, u=u)), u)
+29 -29
View File
@@ -45,19 +45,19 @@ class RichardsSurvey(Survey.BaseSurvey):
@Utils.count @Utils.count
@Utils.requires('prob') @Utils.requires('prob')
def dpred(self, m, u=None): def dpred(self, m, f=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, f, (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!).
.. math:: .. math::
d_\\text{pred} = P(u(m), m) d_\\text{pred} = P(f(m), m)
Where P is a projection of the fields onto the data space. Where P is a projection of the fields onto the data space.
""" """
if u is None: u = self.prob.fields(m) if f is None: f = self.prob.fields(m)
return Utils.mkvc(self.eval(u, m)) return Utils.mkvc(self.eval(f, m))
@Utils.requires('prob') @Utils.requires('prob')
def eval(self, U, m): def eval(self, U, m):
@@ -233,16 +233,16 @@ class RichardsProblem(Problem.BaseTimeProblem):
return r, J return r, J
@Utils.timeIt @Utils.timeIt
def Jfull(self, m, u=None): def Jfull(self, m, f=None):
if u is None: if f is None:
u = self.fields(m) f = self.fields(m)
nn = len(u)-1 nn = len(f)-1
Asubs, Adiags, Bs = range(nn), range(nn), range(nn) Asubs, Adiags, Bs = range(nn), range(nn), range(nn)
for ii in range(nn): for ii in range(nn):
dt = self.timeSteps[ii] dt = self.timeSteps[ii]
bc = self.getBoundaryConditions(ii, u[ii]) bc = self.getBoundaryConditions(ii, f[ii])
Asubs[ii], Adiags[ii], Bs[ii] = self.diagsJacobian(m, u[ii], u[ii+1], dt, bc) Asubs[ii], Adiags[ii], Bs[ii] = self.diagsJacobian(m, f[ii], f[ii+1], dt, bc)
Ad = sp.block_diag(Adiags) Ad = sp.block_diag(Adiags)
zRight = Utils.spzeros((len(Asubs)-1)*Asubs[0].shape[0],Adiags[0].shape[1]) zRight = Utils.spzeros((len(Asubs)-1)*Asubs[0].shape[0],Adiags[0].shape[1])
zTop = Utils.spzeros(Adiags[0].shape[0], len(Adiags)*Adiags[0].shape[1]) zTop = Utils.spzeros(Adiags[0].shape[0], len(Adiags)*Adiags[0].shape[1])
@@ -251,7 +251,7 @@ class RichardsProblem(Problem.BaseTimeProblem):
B = np.array(sp.vstack(Bs).todense()) B = np.array(sp.vstack(Bs).todense())
Ainv = self.Solver(A, **self.solverOpts) Ainv = self.Solver(A, **self.solverOpts)
P = self.survey.evalDeriv(u, m) P = self.survey.evalDeriv(f, m)
AinvB = Ainv * B AinvB = Ainv * B
z = np.zeros((self.mesh.nC, B.shape[1])) z = np.zeros((self.mesh.nC, B.shape[1]))
zAinvB = np.vstack((z, AinvB)) zAinvB = np.vstack((z, AinvB))
@@ -259,41 +259,41 @@ class RichardsProblem(Problem.BaseTimeProblem):
return J return J
@Utils.timeIt @Utils.timeIt
def Jvec(self, m, v, u=None): def Jvec(self, m, v, f=None):
if u is None: if f is None:
u = self.fields(m) f = self.fields(m)
JvC = range(len(u)-1) # Cell to hold each row of the long vector. JvC = range(len(f)-1) # Cell to hold each row of the long vector.
# This is done via forward substitution. # This is done via forward substitution.
bc = self.getBoundaryConditions(0, u[0]) bc = self.getBoundaryConditions(0, f[0])
temp, Adiag, B = self.diagsJacobian(m, u[0], u[1], self.timeSteps[0], bc) temp, Adiag, B = self.diagsJacobian(m, f[0], f[1], self.timeSteps[0], bc)
Adiaginv = self.Solver(Adiag, **self.solverOpts) Adiaginv = self.Solver(Adiag, **self.solverOpts)
JvC[0] = Adiaginv * (B*v) JvC[0] = Adiaginv * (B*v)
for ii in range(1,len(u)-1): for ii in range(1,len(f)-1):
bc = self.getBoundaryConditions(ii, u[ii]) bc = self.getBoundaryConditions(ii, f[ii])
Asub, Adiag, B = self.diagsJacobian(m, u[ii], u[ii+1], self.timeSteps[ii], bc) Asub, Adiag, B = self.diagsJacobian(m, f[ii], f[ii+1], self.timeSteps[ii], bc)
Adiaginv = self.Solver(Adiag, **self.solverOpts) Adiaginv = self.Solver(Adiag, **self.solverOpts)
JvC[ii] = Adiaginv * (B*v - Asub*JvC[ii-1]) JvC[ii] = Adiaginv * (B*v - Asub*JvC[ii-1])
P = self.survey.evalDeriv(u, m) P = self.survey.evalDeriv(f, m)
return P * np.concatenate([np.zeros(self.mesh.nC)] + JvC) return P * np.concatenate([np.zeros(self.mesh.nC)] + JvC)
@Utils.timeIt @Utils.timeIt
def Jtvec(self, m, v, u=None): def Jtvec(self, m, v, f=None):
if u is None: if f is None:
u = self.field(m) f = self.field(m)
P = self.survey.evalDeriv(u, m) P = self.survey.evalDeriv(f, m)
PTv = P.T*v PTv = P.T*v
# This is done via backward substitution. # This is done via backward substitution.
minus = 0 minus = 0
BJtv = 0 BJtv = 0
for ii in range(len(u)-1,0,-1): for ii in range(len(f)-1,0,-1):
bc = self.getBoundaryConditions(ii-1, u[ii-1]) bc = self.getBoundaryConditions(ii-1, f[ii-1])
Asub, Adiag, B = self.diagsJacobian(m, u[ii-1], u[ii], self.timeSteps[ii-1], bc) Asub, Adiag, B = self.diagsJacobian(m, f[ii-1], f[ii], self.timeSteps[ii-1], bc)
#select the correct part of v #select the correct part of v
vpart = range((ii)*Adiag.shape[0], (ii+1)*Adiag.shape[0]) vpart = range((ii)*Adiag.shape[0], (ii+1)*Adiag.shape[0])
AdiaginvT = self.Solver(Adiag.T, **self.solverOpts) AdiaginvT = self.Solver(Adiag.T, **self.solverOpts)
+14 -14
View File
@@ -88,28 +88,28 @@ class BaseProblem(object):
return self.survey is not None return self.survey is not None
@Utils.timeIt @Utils.timeIt
def Jvec(self, m, v, u=None): def Jvec(self, m, v, f=None):
"""Jvec(m, v, u=None) """Jvec(m, v, f=None)
Effect of J(m) on a vector v. 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 Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: Jv :return: Jv
""" """
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, f=None):
"""Jtvec(m, v, u=None) """Jtvec(m, v, f=None)
Effect of transpose of J(m) on a vector v. 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 Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: JTv :return: JTv
""" """
@@ -117,28 +117,28 @@ class BaseProblem(object):
@Utils.timeIt @Utils.timeIt
def Jvec_approx(self, m, v, u=None): def Jvec_approx(self, m, v, f=None):
"""Jvec_approx(m, v, u=None) """Jvec_approx(m, v, f=None)
Approximate effect of J(m) on a vector v 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 Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: approxJv :return: approxJv
""" """
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, f=None):
"""Jtvec_approx(m, v, u=None) """Jtvec_approx(m, v, f=None)
Approximate effect of transpose of J(m) on a vector v. 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 Fields f: fields
:rtype: numpy.array :rtype: numpy.array
:return: JTv :return: JTv
""" """
@@ -224,9 +224,9 @@ class LinearProblem(BaseProblem):
def fields(self, m): def fields(self, m):
return self.G.dot(m) return self.G.dot(m)
def Jvec(self, m, v, u=None): def Jvec(self, m, v, f=None):
return self.G.dot(v) return self.G.dot(v)
def Jtvec(self, m, v, u=None): def Jtvec(self, m, v, f=None):
return self.G.T.dot(v) return self.G.T.dot(v)
+12 -12
View File
@@ -295,21 +295,21 @@ class BaseSurvey(object):
@Utils.count @Utils.count
@Utils.requires('prob') @Utils.requires('prob')
def dpred(self, m, u=None): def dpred(self, m, f=None):
"""dpred(m, u=None) """dpred(m, f=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 fields, f, (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!).
.. math:: .. math::
d_\\text{pred} = P(u(m)) d_\\text{pred} = P(f(m))
Where P is a projection of the fields onto the data space. Where P is a projection of the fields onto the data space.
""" """
if u is None: u = self.prob.fields(m) if f is None: f = self.prob.fields(m)
return Utils.mkvc(self.eval(u)) return Utils.mkvc(self.eval(f))
@Utils.count @Utils.count
@@ -337,11 +337,11 @@ class BaseSurvey(object):
raise NotImplemented('eval is not yet implemented.') raise NotImplemented('eval is not yet implemented.')
@Utils.count @Utils.count
def residual(self, m, u=None): def residual(self, m, f=None):
"""residual(m, u=None) """residual(m, f=None)
:param numpy.array m: geophysical model :param numpy.array m: geophysical model
:param numpy.array u: fields :param numpy.array f: fields
:rtype: numpy.array :rtype: numpy.array
:return: data residual :return: data residual
@@ -352,14 +352,14 @@ class BaseSurvey(object):
\mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs} \mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}
""" """
return Utils.mkvc(self.dpred(m, u=u) - self.dobs) return Utils.mkvc(self.dpred(m, f=f) - self.dobs)
@property @property
def isSynthetic(self): def isSynthetic(self):
"Check if the data is synthetic." "Check if the data is synthetic."
return self.mtrue is not None return self.mtrue is not None
def makeSyntheticData(self, m, std=0.05, u=None, force=False): def makeSyntheticData(self, m, std=0.05, f=None, force=False):
""" """
Make synthetic data given a model, and a standard deviation. Make synthetic data given a model, and a standard deviation.
@@ -372,7 +372,7 @@ class BaseSurvey(object):
if getattr(self, 'dobs', None) is not None and not force: if getattr(self, 'dobs', None) is not None and not force:
raise Exception('Survey already has dobs. You can use force=True to override this exception.') raise Exception('Survey already has dobs. You can use force=True to override this exception.')
self.mtrue = m self.mtrue = m
self.dtrue = self.dpred(m, u=u) self.dtrue = self.dpred(m, f=f)
noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape) noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape)
self.dobs = self.dtrue+noise self.dobs = self.dtrue+noise
self.std = self.dobs*0 + std self.std = self.dobs*0 + std
+6 -6
View File
@@ -116,8 +116,8 @@ class RichardsTests1D(unittest.TestCase):
v = np.random.rand(self.survey.nD) v = np.random.rand(self.survey.nD)
z = np.random.rand(self.M.nC) z = np.random.rand(self.M.nC)
Hs = self.prob.fields(self.Ks) Hs = self.prob.fields(self.Ks)
vJz = v.dot(self.prob.Jvec(self.Ks,z,u=Hs)) vJz = v.dot(self.prob.Jvec(self.Ks,z,f=Hs))
zJv = z.dot(self.prob.Jtvec(self.Ks,v,u=Hs)) zJv = z.dot(self.prob.Jtvec(self.Ks,v,f=Hs))
tol = TOL*(10**int(np.log10(np.abs(zJv)))) tol = TOL*(10**int(np.log10(np.abs(zJv))))
passed = np.abs(vJz - zJv) < tol passed = np.abs(vJz - zJv) < tol
print 'Richards Adjoint Test - PressureHead' print 'Richards Adjoint Test - PressureHead'
@@ -188,8 +188,8 @@ class RichardsTests2D(unittest.TestCase):
v = np.random.rand(self.survey.nD) v = np.random.rand(self.survey.nD)
z = np.random.rand(self.M.nC) z = np.random.rand(self.M.nC)
Hs = self.prob.fields(self.Ks) Hs = self.prob.fields(self.Ks)
vJz = v.dot(self.prob.Jvec(self.Ks,z,u=Hs)) vJz = v.dot(self.prob.Jvec(self.Ks,z,f=Hs))
zJv = z.dot(self.prob.Jtvec(self.Ks,v,u=Hs)) zJv = z.dot(self.prob.Jtvec(self.Ks,v,f=Hs))
tol = TOL*(10**int(np.log10(np.abs(zJv)))) tol = TOL*(10**int(np.log10(np.abs(zJv))))
passed = np.abs(vJz - zJv) < tol passed = np.abs(vJz - zJv) < tol
print '2D: Richards Adjoint Test - PressureHead' print '2D: Richards Adjoint Test - PressureHead'
@@ -260,8 +260,8 @@ class RichardsTests3D(unittest.TestCase):
v = np.random.rand(self.survey.nD) v = np.random.rand(self.survey.nD)
z = np.random.rand(self.M.nC) z = np.random.rand(self.M.nC)
Hs = self.prob.fields(self.Ks) Hs = self.prob.fields(self.Ks)
vJz = v.dot(self.prob.Jvec(self.Ks,z,u=Hs)) vJz = v.dot(self.prob.Jvec(self.Ks,z,f=Hs))
zJv = z.dot(self.prob.Jtvec(self.Ks,v,u=Hs)) zJv = z.dot(self.prob.Jtvec(self.Ks,v,f=Hs))
tol = TOL*(10**int(np.log10(np.abs(zJv)))) tol = TOL*(10**int(np.log10(np.abs(zJv))))
passed = np.abs(vJz - zJv) < tol passed = np.abs(vJz - zJv) < tol
print '3D: Richards Adjoint Test - PressureHead' print '3D: Richards Adjoint Test - PressureHead'