Result of SimPEG hackathon

- Incorporate field class on DC
- Add IP forward modelling and inversion
- Modify notebooks
- change folder name form simpegDC to simpegDCIP
This commit is contained in:
seogi_macbook
2015-06-03 08:29:05 -07:00
parent 820bf85930
commit e0d9c27d87
17 changed files with 1276 additions and 234 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

+93 -36
View File
@@ -1,27 +1,70 @@
from SimPEG import *
class FieldsDC_CC(Problem.Fields):
knownFields = {'phi_sol':'CC'}
aliasFields = {
'phi' : ['phi_sol','CC','_phi'],
'e' : ['phi_sol','F','_e'],
'j' : ['phi_sol','F','_j']
}
def __init__(self,mesh,survey,**kwargs):
super(FieldsDC_CC, self).__init__(mesh, survey, **kwargs)
def startup(self):
self._cellGrad = self.survey.prob.mesh.cellGrad
def _phi(self, phi_sol, srcList):
phi = phi_sol
for i, src in enumerate(srcList):
phi_p = src.phi_p(self.survey.prob)
if phi_p is not None:
phi[:,i] += phi_p
return phi
def _e(self, phi_sol, srcList):
e = -self._cellGrad*phi_sol
for i, src in enumerate(srcList):
e_p = src.e_p(self.survey.prob)
if e_p is not None:
e[:,i] += e_p
return e
def _j(self, phi_sol, srcList):
j = -self.survey.prob.Msig*self._cellGrad*phi_sol
for i, src in enumerate(srcList):
j_p = src.j_p(self.survey.prob)
if j_p is not None:
j[:,i] += j_p
return j
class SrcDipole(Survey.BaseSrc):
"""A dipole source, locA and locB are moved to the closest cell-centers"""
current = 1
loc = None
_rhsDict = None
# _rhsDict = None
def __init__(self, rxList, locA, locB, **kwargs):
self.loc = (locA, locB)
super(SrcDipole, self).__init__(rxList, **kwargs)
def getRhs(self, mesh):
if getattr(self, '_rhsDict', None) is None:
self._rhsDict = {}
if mesh not in self._rhsDict:
pts = [self.loc[0], self.loc[1]]
inds = Utils.closestPoints(mesh, pts)
q = np.zeros(mesh.nC)
q[inds] = - self.current * ( np.r_[1., -1.] / mesh.vol[inds] )
self._rhsDict[mesh] = q
return self._rhsDict[mesh]
def eval(self, prob):
# Recompute rhs
# if getattr(self, '_rhsDict', None) is None:
# self._rhsDict = {}
# if mesh not in self._rhsDict:
pts = [self.loc[0], self.loc[1]]
inds = Utils.closestPoints(prob.mesh, pts)
q = np.zeros(prob.mesh.nC)
q[inds] = - self.current * ( np.r_[1., -1.] / prob.mesh.vol[inds] )
# self._rhsDict[mesh] = q
# return self._rhsDict[mesh]
return q
class RxDipole(Survey.BaseRx):
@@ -53,7 +96,7 @@ class SurveyDC(Survey.BaseSurvey):
def __init__(self, srcList, **kwargs):
self.srcList = srcList
Survey.BaseSurvey.__init__(self, **kwargs)
self._rhsDict = {}
# self._rhsDict = {}
self._Ps = {}
def projectFields(self, u):
@@ -64,13 +107,7 @@ class SurveyDC(Survey.BaseSurvey):
d_\\text{pred} = Pu(m)
"""
P = self.getP(self.prob.mesh)
return P*mkvc(u)
def getRhs(self, mesh):
if mesh not in self._rhsDict:
RHS = np.array([src.getRhs(mesh) for src in self.srcList]).T
self._rhsDict[mesh] = RHS
return self._rhsDict[mesh]
return P*mkvc(u[self.srcList, 'phi_sol'])
def getP(self, mesh):
if mesh in self._Ps:
@@ -82,9 +119,7 @@ class SurveyDC(Survey.BaseSurvey):
return self._Ps[mesh]
class ProblemDC(Problem.BaseProblem):
class ProblemDC_CC(Problem.BaseProblem):
"""
**ProblemDC**
@@ -94,6 +129,8 @@ class ProblemDC(Problem.BaseProblem):
surveyPair = SurveyDC
Solver = Solver
fieldsPair = FieldsDC_CC
Ainv = None
def __init__(self, mesh, **kwargs):
Problem.BaseProblem.__init__(self, mesh)
@@ -143,13 +180,25 @@ class ProblemDC(Problem.BaseProblem):
self._A = self._A.tocsc()
return self._A
def getRHS(self):
# if self.mesh not in self._rhsDict:
RHS = np.array([src.eval(self) for src in self.survey.srcList]).T
# self._rhsDict[mesh] = RHS
# return self._rhsDict[mesh]
return RHS
def fields(self, m):
F = self.fieldsPair(self.mesh, self.survey)
self.curModel = m
A = self.A
Ainv = self.Solver(A, **self.solverOpts)
Q = self.survey.getRhs(self.mesh)
Phi = Ainv * Q
return Phi
self.Ainv = self.Solver(A, **self.solverOpts)
RHS = self.getRHS()
Phi = self.Ainv * RHS
Srcs = self.survey.srcList
F[Srcs, 'phi_sol'] = Phi
return F
def Jvec(self, m, v, u=None):
"""
@@ -178,10 +227,9 @@ class ProblemDC(Problem.BaseProblem):
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
if u is None:
# Run forward simulation if $u$ not provided
u = self.fields(self.curModel)
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol']
else:
shp = (self.mesh.nC, self.survey.nSrc)
u = u.reshape(shp, order='F')
u = u[self.survey.srcList, 'phi_sol']
D = self.mesh.faceDiv
G = self.mesh.cellGrad
@@ -199,9 +247,12 @@ class ProblemDC(Problem.BaseProblem):
# Take derivative of $C(m,u)$ w.r.t. $u$
dCdu = self.A
# Solve for $\deriv{u}{m}$
dCdu_inv = self.Solver(dCdu, **self.solverOpts)
# dCdu_inv = self.Solver(dCdu, **self.solverOpts)
if self.Ainv is None:
self.Ainv = self.Solver(dCdu, **self.solverOpts)
P = self.survey.getP(self.mesh)
J_x_v = - P * mkvc( dCdu_inv * dCdm_x_v )
J_x_v = - P * mkvc( self.Ainv * dCdm_x_v )
return J_x_v
def Jtvec(self, m, v, u=None):
@@ -209,10 +260,12 @@ class ProblemDC(Problem.BaseProblem):
self.curModel = m
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
if u is None:
u = self.fields(self.curModel)
# Run forward simulation if $u$ not provided
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol']
else:
u = u[self.survey.srcList, 'phi_sol']
shp = (self.mesh.nC, self.survey.nSrc)
u = u.reshape(shp, order='F')
shp = u.shape
P = self.survey.getP(self.mesh)
PT_x_v = (P.T*v).reshape(shp, order='F')
@@ -221,9 +274,13 @@ class ProblemDC(Problem.BaseProblem):
A = self.A
mT_dm = self.mapping.deriv(m)
# We probably always need this due to the linesearch .. (?)
dCdu = A.T
Ainv = self.Solver(dCdu, **self.solverOpts)
w = Ainv * PT_x_v
self.Ainv = self.Solver(dCdu, **self.solverOpts)
# if self.Ainv is None:
# self.Ainv = self.Solver(dCdu, **self.solverOpts)
w = self.Ainv * PT_x_v
Jtv = 0
for i, ui in enumerate(u.T): # loop over each column
+182
View File
@@ -0,0 +1,182 @@
from SimPEG import *
from BaseDC import SurveyDC, FieldsDC_CC
class SurveyIP(SurveyDC):
"""
**SurveyDC**
Geophysical DC resistivity data.
"""
def __init__(self, srcList, **kwargs):
self.srcList = srcList
Survey.BaseSurvey.__init__(self, **kwargs)
self._Ps = {}
def dpred(self, m, u=None):
"""
Predicted data.
.. math::
d_\\text{pred} = Pu(m)
"""
return self.prob.forward(m)
class ProblemIP(Problem.BaseProblem):
"""
**ProblemIP**
Geophysical IP resistivity problem.
"""
surveyPair = SurveyDC
Solver = Solver
sigma = None
Ainv = None
u = None
def __init__(self, mesh, **kwargs):
Problem.BaseProblem.__init__(self, mesh)
self.mesh.setCellGradBC('neumann')
Utils.setKwargs(self, **kwargs)
# deleteTheseOnModelUpdate = ['_A', '_Msig', '_dMdsig']
@property
def Msig(self):
if getattr(self, '_Msig', None) is None:
# sigma = self.curModel.transform
sigma = self.sigma
Av = self.mesh.aveF2CC
self._Msig = Utils.sdiag(1/(self.mesh.dim * Av.T * (1/sigma)))
return self._Msig
@property
def dMdsig(self):
if getattr(self, '_dMdsig', None) is None:
# sigma = self.curModel.transform
sigma = self.sigma
Av = self.mesh.aveF2CC
dMdprop = self.mesh.dim * Utils.sdiag(self.Msig.diagonal()**2) * Av.T * Utils.sdiag(1./sigma**2)
self._dMdsig = lambda Gu: Utils.sdiag(Gu) * dMdprop
return self._dMdsig
@property
def A(self):
"""
Makes the matrix A(m) for the DC resistivity problem.
:param numpy.array m: model
:rtype: scipy.csc_matrix
:return: A(m)
.. math::
c(m,u) = A(m)u - q = G\\text{sdiag}(M(mT(m)))Du - q = 0
Where M() is the mass matrix and mT is the model transform.
"""
if getattr(self, '_A', None) is None:
D = self.mesh.faceDiv
G = self.mesh.cellGrad
self._A = D*self.Msig*G
# Remove the null space from the matrix.
self._A[-1,-1] /= self.mesh.vol[-1]
self._A = self._A.tocsc()
return self._A
def getRHS(self):
# if self.mesh not in self._rhsDict:
RHS = np.array([src.eval(self) for src in self.survey.srcList]).T
# self._rhsDict[mesh] = RHS
# return self._rhsDict[mesh]
return RHS
def fields(self, m):
if self.u is None:
A = self.A
if self.Ainv == None:
self.Ainv = self.Solver(A, **self.solverOpts)
Q = self.getRHS()
self.u = self.Ainv * Q
return self.u
def forward(self, m, u=None):
# Set current model; clear dependent property $\mathbf{A(m)}$
self.curModel = m
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
sigma = self.sigma
if self.u is None:
# Run forward simulation if $u$ not provided
u = self.fields(sigma)
shp = (self.mesh.nC, self.survey.nSrc)
u = self.u.reshape(shp, order='F')
D = self.mesh.faceDiv
G = self.mesh.cellGrad
# Derivative of model transform, $\deriv{\sigma}{\m}$
# dsigdm_x_v = self.curModel.transformDeriv * v
dsigdm_x_v = Utils.sdiag(sigma) * self.curModel.transformDeriv * m
# Take derivative of $C(m,u)$ w.r.t. $m$
dCdm_x_v = np.empty_like(u)
# loop over fields for each source
for i in range(self.survey.nSrc):
# Derivative of inner product, $\left(\mathbf{M}_{1/\sigma}^f\right)^{-1}$
dAdsig = D * self.dMdsig( G * u[:,i] )
dCdm_x_v[:, i] = dAdsig * dsigdm_x_v
# Take derivative of $C(m,u)$ w.r.t. $u$
if self.Ainv == None:
self.Ainv = self.Solver(A, **self.solverOpts)
# dCdu = self.A
# Solve for $\deriv{u}{m}$
# dCdu_inv = self.Solver(dCdu, **self.solverOpts)
P = self.survey.getP(self.mesh)
J_x_v = - P * mkvc( self.Ainv * dCdm_x_v )
return -J_x_v
def Jvec(self, m, v, u=None):
return self.forward(v)
def Jtvec(self, m, v, u=None):
self.curModel = m
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
sigma = self.sigma
if self.u is None:
u = self.fields(sigma)
else:
u = self.u
shp = (self.mesh.nC, self.survey.nSrc)
u = u.reshape(shp, order='F')
P = self.survey.getP(self.mesh)
PT_x_v = (P.T*v).reshape(shp, order='F')
D = self.mesh.faceDiv
G = self.mesh.cellGrad
A = self.A
mT_dm = Utils.sdiag(sigma)*self.mapping.deriv(m)
# mT_dm = self.mapping.deriv(m)
# dCdu = A.T
# Ainv = self.Solver(dCdu, **self.solverOpts)
# if self.Ainv == None:
self.Ainv = self.Solver(A.T, **self.solverOpts)
w = self.Ainv * PT_x_v
Jtv = 0
for i, ui in enumerate(u.T): # loop over each column
Jtv += self.dMdsig( G * ui ).T * ( D.T * w[:,i] )
Jtv = - mT_dm.T * ( Jtv )
return -Jtv
@@ -1,5 +1,5 @@
from SimPEG import *
import simpegDC as DC
import simpegDCIP as DC
import matplotlib.pyplot as plt
@@ -26,7 +26,7 @@ def run(plotIt=False):
rx = DC.RxDipole(xyz_rxP, xyz_rxN)
src = DC.SrcDipole([rx], [-200, 0, -12.5], [+200, 0, -12.5])
survey = DC.SurveyDC([src])
problem = DC.ProblemDC(mesh)
problem = DC.ProblemDC_CC(mesh)
problem.pair(survey)
try:
from pymatsolver import MumpsSolver
@@ -1,5 +1,5 @@
from SimPEG import *
import simpegDC as DC
import simpegDCIP as DC
import matplotlib.pyplot as plt
@@ -55,7 +55,7 @@ def example(aSpacing=2.5, nElecs=10, plotIt=False):
srcList = getSrcList(nElecs, aSpacing, in2D=True)
survey = DC.SurveyDC(srcList)
problem = DC.ProblemDC(mesh)
problem = DC.ProblemDC_CC(mesh)
problem.pair(survey)
return mesh, survey, problem
@@ -38,8 +38,8 @@ class DCProblemTests(unittest.TestCase):
u = np.random.rand(self.mesh.nC*self.survey.nSrc)
v = np.random.rand(self.mesh.nC)
w = np.random.rand(self.survey.dobs.shape[0])
wtJv = w.dot(self.p.Jvec(self.m0, v, u=u))
vtJtw = v.dot(self.p.Jtvec(self.m0, w, u=u))
wtJv = w.dot(self.p.Jvec(self.m0, v))
vtJtw = v.dot(self.p.Jtvec(self.m0, w))
passed = np.abs(wtJv - vtJtw) < 1e-10
print 'Adjoint Test', np.abs(wtJv - vtJtw), passed
self.assertTrue(passed)
@@ -8,6 +8,5 @@ class DCAnalyticTests(unittest.TestCase):
self.assertTrue(DC.Examples.Verification.run() < 0.1)
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,57 @@
import unittest
import simpegDC as DC
from SimPEG import *
from pymatsolver import MumpsSolver
class IPforwardTests(unittest.TestCase):
def test_IPforward(self):
cs = 12.5
nc = 500/cs+1
hx = [(cs,7, -1.3),(cs,nc),(cs,7, 1.3)]
hy = [(cs,7, -1.3),(cs,int(nc/2+1)),(cs,7, 1.3)]
hz = [(cs,7, -1.3),(cs,int(nc/2+1))]
mesh = Mesh.TensorMesh([hx, hy, hz], 'CCN')
sighalf = 1e-2
sigma = np.ones(mesh.nC)*sighalf
p0 = np.r_[-50., 50., -50.]
p1 = np.r_[ 50.,-50., -150.]
blk_ind = Utils.ModelBuilder.getIndecesBlock(p0, p1, mesh.gridCC)
sigma[blk_ind] = 1e-3
eta = np.zeros_like(sigma)
eta[blk_ind] = 0.1
sigmaInf = sigma.copy()
sigma0 = sigma*(1-eta)
nElecs = 11
x_temp = np.linspace(-250, 250, nElecs)
aSpacing = x_temp[1]-x_temp[0]
y_temp = 0.
xyz = Utils.ndgrid(x_temp, np.r_[y_temp], np.r_[0.])
srcList = DC.Examples.WennerArray.getSrcList(nElecs,aSpacing)
survey = DC.SurveyDC(srcList)
imap = Maps.IdentityMap(mesh)
problem = DC.ProblemDC_CC(mesh, mapping= imap )
problem.Solver = MumpsSolver
problem.pair(survey)
phi0 = survey.dpred(sigma0)
phiInf = survey.dpred(sigmaInf)
phiIP_true = phi0-phiInf
surveyIP = DC.SurveyIP(srcList)
problemIP = DC.ProblemIP(mesh, sigma=sigma)
problemIP.pair(surveyIP)
problemIP.Solver = MumpsSolver
phiIP_approx = surveyIP.dpred(eta)
err = np.linalg.norm(phiIP_true-phiIP_approx) / np.linalg.norm(phiIP_true)
self.assertTrue(err < 0.02)
if __name__ == '__main__':
unittest.main()
+80
View File
@@ -0,0 +1,80 @@
import unittest
from SimPEG import *
import simpegDC as DC
from pymatsolver import MumpsSolver
class IPProblemTests(unittest.TestCase):
def setUp(self):
cs = 12.5
nc = 500/cs+1
hx = [(cs,0, -1.3),(cs,nc),(cs,0, 1.3)]
hy = [(cs,0, -1.3),(cs,int(nc/2+1)),(cs,0, 1.3)]
hz = [(cs,0, -1.3),(cs,int(nc/2+1))]
mesh = Mesh.TensorMesh([hx, hy, hz], 'CCN')
sighalf = 1e-2
sigma = np.ones(mesh.nC)*sighalf
p0 = np.r_[-50., 50., -50.]
p1 = np.r_[ 50.,-50., -150.]
blk_ind = Utils.ModelBuilder.getIndecesBlock(p0, p1, mesh.gridCC)
sigma[blk_ind] = 1e-3
eta = np.zeros_like(sigma)
eta[blk_ind] = 0.1
nElecs = 5
x_temp = np.linspace(-250, 250, nElecs)
aSpacing = x_temp[1]-x_temp[0]
y_temp = 0.
xyz = Utils.ndgrid(x_temp, np.r_[y_temp], np.r_[0.])
srcList = DC.Examples.WennerArray.getSrcList(nElecs,aSpacing)
survey = DC.SurveyIP(srcList)
imap = Maps.IdentityMap(mesh)
problem = DC.ProblemIP(mesh, sigma=sigma, mapping= imap)
problem.pair(survey)
problem.Solver = MumpsSolver
mSynth = eta
survey.makeSyntheticData(mSynth)
# Now set up the problem to do some minimization
dmis = DataMisfit.l2_DataMisfit(survey)
reg = Regularization.Tikhonov(mesh)
opt = Optimization.InexactGaussNewton(maxIterLS=20, maxIter=10, tolF=1e-6, tolX=1e-6, tolG=1e-6, maxIterCG=6)
invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta=1e4)
inv = Inversion.BaseInversion(invProb)
self.inv = inv
self.reg = reg
self.p = problem
self.mesh = mesh
self.m0 = mSynth
self.survey = survey
self.dmis = dmis
def test_misfit(self):
derChk = lambda m: [self.survey.dpred(m), lambda mx: self.p.Jvec(self.m0, mx)]
passed = Tests.checkDerivative(derChk, self.m0*0, plotIt=False)
self.assertTrue(passed)
def test_adjoint(self):
# Adjoint Test
u = np.random.rand(self.mesh.nC*self.survey.nSrc)
v = np.random.rand(self.mesh.nC)
w = np.random.rand(self.survey.dobs.shape[0])
wtJv = w.dot(self.p.Jvec(self.m0, v))
vtJtw = v.dot(self.p.Jtvec(self.m0, w))
passed = np.abs(wtJv - vtJtw) < 1e-10
print 'Adjoint Test', np.abs(wtJv - vtJtw), passed
self.assertTrue(passed)
def test_dataObj(self):
derChk = lambda m: [self.dmis.eval(m), self.dmis.evalDeriv(m)]
passed = Tests.checkDerivative(derChk, self.m0, plotIt=False)
self.assertTrue(passed)
if __name__ == '__main__':
unittest.main()
@@ -1,2 +1,3 @@
from BaseDC import *
from BaseIP import *
import Examples