mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-27 21:08:35 +08:00
44ad57e90d
Merge spectral IP stuff, and incorporate Lindsey's comments
350 lines
11 KiB
Python
350 lines
11 KiB
Python
from SimPEG import Problem, Utils
|
|
from SimPEG.EM.Base import BaseEMProblem
|
|
from SurveyDC import Survey, Survey_ky
|
|
from FieldsDC_2D import Fields_ky, Fields_ky_CC, Fields_ky_N
|
|
from SimPEG.Utils import sdiag
|
|
import numpy as np
|
|
from SimPEG.Utils import Zero
|
|
from BoundaryUtils import getxBCyBC_CC
|
|
|
|
class BaseDCProblem_2D(BaseEMProblem):
|
|
|
|
surveyPair = Survey_ky
|
|
fieldsPair = Fields_ky
|
|
nky = 15
|
|
kys = np.logspace(-4, 1, nky)
|
|
Ainv = [None for i in range(nky)]
|
|
nT = nky # Only for using TimeFields
|
|
|
|
def fields(self, m):
|
|
self.curModel = m
|
|
|
|
if not self.Ainv[0] == None:
|
|
for i in range(self.nky):
|
|
self.Ainv[i].clean()
|
|
|
|
f = self.fieldsPair(self.mesh, self.survey)
|
|
Srcs = self.survey.srcList
|
|
for iky in range(self.nky):
|
|
ky = self.kys[iky]
|
|
A = self.getA(ky)
|
|
self.Ainv[iky] = self.Solver(A, **self.solverOpts)
|
|
RHS = self.getRHS(ky)
|
|
u = self.Ainv[iky] * RHS
|
|
f[Srcs, self._solutionType, iky] = u
|
|
return f
|
|
|
|
def Jvec(self, m, v, f=None):
|
|
|
|
if f is None:
|
|
f = self.fields(m)
|
|
|
|
self.curModel = m
|
|
|
|
Jv = self.dataPair(self.survey) #same size as the data
|
|
Jv0 = self.dataPair(self.survey)
|
|
|
|
# Assume y=0.
|
|
# This needs some thoughts to implement in general when src is dipole
|
|
dky = np.diff(self.kys)
|
|
dky = np.r_[dky[0], dky]
|
|
y = 0.
|
|
|
|
#TODO: this loop is pretty slow .. (Parellize)
|
|
for iky in range(self.nky):
|
|
ky = self.kys[iky]
|
|
A = self.getA(ky)
|
|
for src in self.survey.srcList:
|
|
u_src = f[src, self._solutionType, iky] # solution vector
|
|
dA_dm_v = self.getADeriv(ky, u_src, v)
|
|
dRHS_dm_v = self.getRHSDeriv(ky, src, v)
|
|
du_dm_v = self.Ainv[iky] * ( - dA_dm_v + dRHS_dm_v )
|
|
for rx in src.rxList:
|
|
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
|
df_dm_v = df_dmFun(iky, src, du_dm_v, v, adjoint=False)
|
|
# Trapezoidal intergration
|
|
Jv1_temp = 1./np.pi*rx.evalDeriv(ky, src, self.mesh, f, df_dm_v)
|
|
if iky==0:
|
|
#First assigment
|
|
Jv[src, rx] = Jv1_temp*dky[iky]*np.cos(ky*y)
|
|
else:
|
|
Jv[src, rx] += Jv1_temp*dky[iky] /2.*np.cos(ky*y)
|
|
Jv[src, rx] += Jv0[src, rx]*dky[iky]/2.*np.cos(ky*y)
|
|
Jv0[src, rx] = Jv1_temp.copy()
|
|
return Utils.mkvc(Jv)
|
|
|
|
def Jtvec(self, m, v, f=None):
|
|
if f is None:
|
|
f = self.fields(m)
|
|
|
|
self.curModel = m
|
|
|
|
# Ensure v is a data object.
|
|
if not isinstance(v, self.dataPair):
|
|
v = self.dataPair(self.survey, v)
|
|
|
|
Jtv = np.zeros(m.size, dtype=float)
|
|
|
|
# Assume y=0.
|
|
# This needs some thoughts to implement in general when src is dipole
|
|
dky = np.diff(self.kys)
|
|
dky = np.r_[dky[0], dky]
|
|
y = 0.
|
|
|
|
for src in self.survey.srcList:
|
|
for rx in src.rxList:
|
|
Jtv_temp1 = np.zeros(m.size, dtype=float)
|
|
Jtv_temp0 = np.zeros(m.size, dtype=float)
|
|
#TODO: this loop is pretty slow .. (Parellize)
|
|
for iky in range(self.nky):
|
|
u_src = f[src, self._solutionType, iky]
|
|
ky = self.kys[iky]
|
|
AT = self.getA(ky)
|
|
PTv = rx.evalDeriv(ky, src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
|
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
|
df_duT, df_dmT = df_duTFun(iky, src, None, PTv, adjoint=True)
|
|
|
|
ATinvdf_duT = self.Ainv[iky] * df_duT
|
|
|
|
dA_dmT = self.getADeriv(ky, u_src, ATinvdf_duT, adjoint=True)
|
|
dRHS_dmT = self.getRHSDeriv(ky, src, ATinvdf_duT, adjoint=True)
|
|
du_dmT = -dA_dmT + dRHS_dmT
|
|
Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT).astype(float)
|
|
# Trapezoidal intergration
|
|
if iky==0:
|
|
#First assigment
|
|
Jtv += Jtv_temp1*dky[iky]*np.cos(ky*y)
|
|
else:
|
|
Jtv += Jtv_temp1*dky[iky]/2.*np.cos(ky*y)
|
|
Jtv += Jtv_temp0*dky[iky]/2.*np.cos(ky*y)
|
|
Jtv_temp0 = Jtv_temp1.copy()
|
|
return Utils.mkvc(Jtv)
|
|
|
|
def getSourceTerm(self, ky):
|
|
"""
|
|
takes concept of source and turns it into a matrix
|
|
"""
|
|
"""
|
|
Evaluates the sources, and puts them in matrix form
|
|
|
|
:rtype: (numpy.ndarray, numpy.ndarray)
|
|
:return: q (nC or nN, nSrc)
|
|
"""
|
|
|
|
Srcs = self.survey.srcList
|
|
|
|
if self._formulation is 'EB':
|
|
n = self.mesh.nN
|
|
# return NotImplementedError
|
|
|
|
elif self._formulation is 'HJ':
|
|
n = self.mesh.nC
|
|
|
|
q = np.zeros((n, len(Srcs)))
|
|
|
|
for i, src in enumerate(Srcs):
|
|
q[:,i] = src.eval(self)
|
|
return q
|
|
|
|
class Problem2D_CC(BaseDCProblem_2D):
|
|
|
|
_solutionType = 'phiSolution'
|
|
_formulation = 'HJ' # CC potentials means J is on faces
|
|
fieldsPair = Fields_ky_CC
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
|
|
self.setBC()
|
|
|
|
def getA(self, ky):
|
|
"""
|
|
|
|
Make the A matrix for the cell centered DC resistivity problem
|
|
|
|
A = D MfRhoI G
|
|
|
|
"""
|
|
|
|
D = self.Div
|
|
G = self.Grad
|
|
vol = self.mesh.vol
|
|
MfRhoI = self.MfRhoI
|
|
# Get resistivity rho
|
|
rho = self.curModel.rho
|
|
A = D * MfRhoI * G + Utils.sdiag(ky**2*vol/rho)
|
|
return A
|
|
|
|
def getADeriv(self, ky, u, v, adjoint= False):
|
|
|
|
D = self.Div
|
|
G = self.Grad
|
|
vol = self.mesh.vol
|
|
MfRhoIDeriv = self.MfRhoIDeriv
|
|
rho = self.curModel.rho
|
|
if adjoint:
|
|
return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
|
|
return D * ((MfRhoIDeriv( G * u )) * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
|
|
|
|
def getRHS(self, ky):
|
|
"""
|
|
RHS for the DC problem
|
|
|
|
q
|
|
"""
|
|
|
|
RHS = self.getSourceTerm(ky)
|
|
return RHS
|
|
|
|
def getRHSDeriv(self, ky, src, v, adjoint=False):
|
|
"""
|
|
Derivative of the right hand side with respect to the model
|
|
"""
|
|
# TODO: add qDeriv for RHS depending on m
|
|
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
|
|
# return qDeriv
|
|
return Zero()
|
|
|
|
def setBC(self):
|
|
if self.mesh.dim==3:
|
|
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
|
gBFxm = self.mesh.gridFx[fxm,:]
|
|
gBFxp = self.mesh.gridFx[fxp,:]
|
|
gBFym = self.mesh.gridFy[fym,:]
|
|
gBFyp = self.mesh.gridFy[fyp,:]
|
|
gBFzm = self.mesh.gridFz[fzm,:]
|
|
gBFzp = self.mesh.gridFz[fzp,:]
|
|
|
|
# Setup Mixed B.C (alpha, beta, gamma)
|
|
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
|
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
|
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
|
|
|
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
|
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
|
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
|
|
|
beta_xm, beta_xp = temp_xm, temp_xp
|
|
beta_ym, beta_yp = temp_ym, temp_yp
|
|
beta_zm, beta_zp = temp_zm, temp_zp
|
|
|
|
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
|
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
|
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
|
|
|
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
|
|
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
|
|
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
|
|
|
|
elif self.mesh.dim==2:
|
|
|
|
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
|
gBFxm = self.mesh.gridFx[fxm,:]
|
|
gBFxp = self.mesh.gridFx[fxp,:]
|
|
gBFym = self.mesh.gridFy[fym,:]
|
|
gBFyp = self.mesh.gridFy[fyp,:]
|
|
|
|
# Setup Mixed B.C (alpha, beta, gamma)
|
|
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
|
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
|
|
|
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
|
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
|
|
|
beta_xm, beta_xp = temp_xm, temp_xp
|
|
beta_ym, beta_yp = temp_ym, temp_yp
|
|
|
|
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
|
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
|
|
|
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
|
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
|
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
|
|
|
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
|
V = self.Vol
|
|
self.Div = V * self.mesh.faceDiv
|
|
P_BC, B = self.mesh.getBCProjWF_simple()
|
|
M = B*self.mesh.aveCC2F
|
|
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
|
|
|
class Problem2D_N(BaseDCProblem_2D):
|
|
|
|
_solutionType = 'phiSolution'
|
|
_formulation = 'EB' # CC potentials means J is on faces
|
|
fieldsPair = Fields_ky_N
|
|
|
|
def __init__(self, mesh, **kwargs):
|
|
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
|
|
# self.setBC()
|
|
|
|
@property
|
|
def MnSigma(self):
|
|
"""
|
|
Node inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
|
"""
|
|
# TODO: only works isotropic sigma
|
|
sigma = self.curModel.sigma
|
|
vol = self.mesh.vol
|
|
MnSigma = Utils.sdiag(self.mesh.aveN2CC.T*(Utils.sdiag(vol)*sigma))
|
|
|
|
return MnSigma
|
|
|
|
def MnSigmaDeriv(self, u):
|
|
"""
|
|
Derivative of MnSigma with respect to the model
|
|
"""
|
|
sigma = self.curModel.sigma
|
|
sigmaderiv = self.curModel.sigmaDeriv
|
|
vol = self.mesh.vol
|
|
return Utils.sdiag(u)*self.mesh.aveN2CC.T*Utils.sdiag(vol) * self.curModel.sigmaDeriv
|
|
|
|
def getA(self, ky):
|
|
"""
|
|
|
|
Make the A matrix for the cell centered DC resistivity problem
|
|
|
|
A = D MfRhoI G
|
|
|
|
"""
|
|
|
|
MeSigma = self.MeSigma
|
|
MnSigma = self.MnSigma
|
|
Grad = self.mesh.nodalGrad
|
|
# Get conductivity sigma
|
|
sigma = self.curModel.sigma
|
|
A = Grad.T * MeSigma * Grad + ky**2*MnSigma
|
|
|
|
# Handling Null space of A
|
|
A[0,0] = A[0,0] + 1.
|
|
return A
|
|
|
|
def getADeriv(self, ky, u, v, adjoint= False):
|
|
|
|
MeSigma = self.MeSigma
|
|
Grad = self.mesh.nodalGrad
|
|
sigma = self.curModel.sigma
|
|
vol = self.mesh.vol
|
|
|
|
if adjoint:
|
|
return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u).T*v
|
|
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v
|
|
|
|
def getRHS(self, ky):
|
|
"""
|
|
RHS for the DC problem
|
|
|
|
q
|
|
"""
|
|
|
|
RHS = self.getSourceTerm(ky)
|
|
return RHS
|
|
|
|
def getRHSDeriv(self, ky, src, v, adjoint=False):
|
|
"""
|
|
Derivative of the right hand side with respect to the model
|
|
"""
|
|
# TODO: add qDeriv for RHS depending on m
|
|
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
|
|
# return qDeriv
|
|
return Zero()
|