Working Jvec for the MT problem - not currently working. Dimensional mismatch with matrices.

This commit is contained in:
GudniRos
2015-06-23 08:31:44 -07:00
parent 60b6c24e19
commit 2cbfe2d6b9
5 changed files with 500 additions and 195 deletions
+97
View File
@@ -23,3 +23,100 @@ class BaseMTProblem(BaseFDEMProblem):
# Use the forward and devs from BaseFDEMProblem
# Might need to add more stuff here.
def Jvec(self, m, v, f=None):
if f is None:
f = self.fields(m)
self.curModel = m
Jv = self.dataPair(self.survey)
for freq in self.survey.freqs:
dA_du = self.getA(freq) #
dA_duI = self.Solver(dA_du, **self.solverOpts)
for src in self.survey.getSrcByFreq(freq):
ftype = self._fieldType + 'Solution'
u_src = f[src, ftype]
dA_dm = self.getADeriv_m(freq, u_src, v)
dRHS_dm = self.getRHSDeriv_m(freq, v)
if dRHS_dm is None:
du_dm = dA_duI * ( - dA_dm )
else:
du_dm = dA_duI * ( - dA_dm + dRHS_dm )
for rx in src.rxList:
# df_duFun = u.deriv_u(rx.fieldsUsed, m)
if 'e' in self._fieldType:
projField = 'b'
elif 'b' in self._fieldType:
projField = 'e'
df_duFun = getattr(f, '_%sDeriv_u'%projField, None)
df_du = df_duFun(src, du_dm, adjoint=False)
if df_du is not None:
du_dm = df_du
df_dmFun = getattr(f, '_%sDeriv_m'%projField, None)
df_dm = df_dmFun(src, v, adjoint=False)
if df_dm is not None:
du_dm += df_dm
P = lambda v: rx.projectFieldsDeriv(src, self.mesh, f, v) # wrt u, also have wrt m
Jv[src, rx] = P(du_dm)
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)
for freq in self.survey.freqs:
AT = self.getA(freq).T
ATinv = self.Solver(AT, **self.solverOpts)
for src in self.survey.getSrcByFreq(freq):
ftype = self._fieldType + 'Solution'
u_src = f[src, ftype]
for rx in src.rxList:
PTv = rx.projectFieldsDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
df_duTFun = getattr(f, '_%sDeriv_u'%rx.projField, None)
df_duT = df_duTFun(src, PTv, adjoint=True)
if df_duT is not None:
dA_duIT = ATinv * df_duT
else:
dA_duIT = ATinv * PTv
dA_dmT = self.getADeriv_m(freq, u_src, dA_duIT, adjoint=True)
dRHS_dmT = self.getRHSDeriv_m(src, dA_duIT, adjoint=True)
if dRHS_dmT is None:
du_dmT = - dA_dmT
else:
du_dmT = -dA_dmT + dRHS_dmT
df_dmFun = getattr(f, '_%sDeriv_m'%rx.projField, None)
dfT_dm = df_dmFun(src, PTv, adjoint=True)
if dfT_dm is not None:
du_dmT += dfT_dm
real_or_imag = rx.projComp
if real_or_imag == 'real':
Jtv += du_dmT.real
elif real_or_imag == 'imag':
Jtv += - du_dmT.real
else:
raise Exception('Must be real or imag')
return Jtv
+82 -9
View File
@@ -9,15 +9,88 @@ from simpegEM.Utils.EMUtils import omega
##############
class FieldsMT(Problem.Fields):
"""Field Storage for a MT survey."""
knownFields = {'b_px': 'F','b_py': 'F', 'e_px': 'E','e_py': 'E','b_1d':'E','e_1d':'F'}
knownFields = {}
dtype = complex
def _b_1dDeriv_u(self,src,v,adjoint=False):
"""
The derivative of b_1d wrt u
"""
nG = self.mesh.nodalGrad
if adjoint:
return - 1./( 1j*omega(src.freq) ) * ( nG.T * v)
return - 1./( 1j*omega(src.freq) ) * ( nG * v)
class FieldsMT_1D(FieldsMT):
"""
Fields storage for the 1D MT solution.
"""
knownFields = {'e_1dSolution':'F'}
aliasFields = {
'e_1d' : ['e_1dSolution','F','_e'],
'e_1dPrimary' : ['e_1dSolution','F','_ePrimary'],
'e_1dSecondary' : ['e_1dSolution','F','_eSecondary'],
'b_1d' : ['e_1dSolution','E','_b'],
'b_1dPrimary' : ['e_1dSolution','E','_bPrimary'],
'b_1dSecondary' : ['e_1dSolution','E','_bSecondary']
}
def __init__(self,mesh,survey,**kwargs):
FieldsMT.__init__(self,mesh,survey,**kwargs)
def _ePrimary(self, eSolution, srcList):
ePrimary = np.zeros_like(eSolution)
for i, src in enumerate(srcList):
ep = src.ePrimary(self.survey.prob)
if ep is not None:
ePrimary[:,i] = ep[:,-1]
return ePrimary
def _eSecondary(self, eSolution, srcList):
return eSolution
def _e(self, eSolution, srcList):
return self._ePrimary(eSolution,srcList) + self._eSecondary(eSolution,srcList)
def _eDeriv_u(self, src, v, adjoint = False):
return None
def _eDeriv_m(self, src, v, adjoint = False):
# assuming primary does not depend on the model
return None
def _bPrimary(self, eSolution, srcList):
bPrimary = np.zeros([self.survey.mesh.nE,eSolution.shape[1]], dtype = complex)
for i, src in enumerate(srcList):
bp = src.bPrimary(self.survey.prob)
if bp is not None:
bPrimary[:,i] += bp[:,-1]
return bPrimary
def _bSecondary(self, eSolution, srcList):
C = self.mesh.nodalGrad
b = (C * eSolution)
for i, src in enumerate(srcList):
b[:,i] *= - 1./(1j*omega(src.freq))
# There is no magnetic source in the MT problem
# S_m, _ = src.eval(self.survey.prob)
# if S_m is not None:
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
return b
def _b(self, eSolution, srcList):
return self._bPrimary(eSolution, srcList) + self._bSecondary(eSolution, srcList)
def _bSecondaryDeriv_u(self, src, v, adjoint = False):
C = self.mesh.nodalGrad
if adjoint:
return - 1./(1j*omega(src.freq)) * (C.T * v)
return - 1./(1j*omega(src.freq)) * (C * v)
def _bSecondaryDeriv_m(self, src, v, adjoint = False):
S_mDeriv, _ = src.evalDeriv(self.survey.prob, adjoint)
S_mDeriv = S_mDeriv(v)
if S_mDeriv is not None:
return 1./(1j * omega(src.freq)) * S_mDeriv
return None
def _bDeriv_u(self, src, v, adjoint=False):
# Primary does not depend on u
return self._bSecondaryDeriv_u(src, v, adjoint)
def _bDeriv_m(self, src, v, adjoint=False):
# Assuming the primary does not depend on the model
return self._bSecondaryDeriv_m(src, v, adjoint)
+14 -12
View File
@@ -3,7 +3,7 @@ from SimPEG import mkvc
from scipy.constants import mu_0
from simpegMT.BaseMT import BaseMTProblem
from simpegMT.SurveyMT import SurveyMT
from simpegMT.FieldsMT import FieldsMT
from simpegMT.FieldsMT import FieldsMT_1D
from simpegMT.DataMT import DataMT
from simpegMT.Utils.MT1Danalytic import getEHfields
import numpy as np
@@ -18,19 +18,19 @@ class eForm_psField(BaseMTProblem):
"""
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
_fieldType = 'e'
_fieldType = 'e_1d'
_eqLocs = 'EF'
def __init__(self, mesh, **kwargs):
BaseMTProblem.__init__(self, mesh, **kwargs)
self.fieldsPair = FieldsMT_1D
def getA(self, freq,):
def getA(self, freq):
"""
Function to get the A matrix.
:param float freq: Frequency
:param logic full: Return full A or the inner part
:rtype: scipy.sparse.csr_matrix
:return: A
"""
@@ -54,11 +54,13 @@ class eForm_psField(BaseMTProblem):
"""
dsig_dm = self.curModel.sigmaDeriv
MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
# Need to make the dMf_dsig symmetirc (nN,nN), don't know how to do this
dMf_dsig = self.mesh.getFaceInnerProductDeriv(self.curModel.sigma)(u) * self.curModel.sigmaDeriv
if adjoint:
return 1j * omega(freq) * ( dsig_dm.T * ( dMf_dsig.T * v ) )
return 1j * omega(freq) * ( dMf_dsig * ( dsig_dm * v ) )
return 1j * omega(freq) * ( dMf_dsig.T * v )
# Note: output has to be nN/nF, not nC/nE.
return 1j * omega(freq) * ( (dMf_dsig * dMf_dsig.T)**(1/2) * v)
def getRHS(self, freq):
"""
@@ -73,7 +75,7 @@ class eForm_psField(BaseMTProblem):
S_e = Src.S_e(self)
return -1j * omega(freq) * S_e
def getRHSderiv_m(self, freq, u, v, adjoint=False):
def getRHSDeriv_m(self, freq, v, adjoint=False):
"""
The derivative of the RHS wrt sigma
"""
@@ -91,7 +93,7 @@ class eForm_psField(BaseMTProblem):
# Set the current model
self.curModel = m
F = FieldsMT(self.mesh, self.survey)
F = FieldsMT_1D(self.mesh, self.survey)
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
@@ -110,12 +112,12 @@ class eForm_psField(BaseMTProblem):
# Store the fields
# NOTE: only store
F[Src, 'e_1d'] = e[:,1] # Only storing the yx polarization as 1d
F[Src, 'e_1dSolution'] = e[:,1] # Only storing the yx polarization as 1d
# F[Src, 'e_py'] = 0*e[:,0]
# Note curl e = -iwb so b = -curl e /iw
b = -( self.mesh.nodalGrad * e )/( 1j*omega(freq) )
# b = -( self.mesh.nodalGrad * e )/( 1j*omega(freq) )
# F[Src, 'b_px'] = 0*b[:,0]
F[Src, 'b_1d'] = b[:,1]
# F[Src, 'b_1d'] = b[:,1]
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
+26 -18
View File
@@ -83,7 +83,7 @@ class RxMT(Survey.BaseRx):
"""Component projection (real/imag)"""
return self.knownRxTypes[self.rxType][1]
def projectFields(self, src, mesh, u):
def projectFields(self, src, mesh, f):
'''
Project the fields and return the
'''
@@ -91,8 +91,8 @@ class RxMT(Survey.BaseRx):
if self.projType is 'Z1D':
Pex = mesh.getInterpolationMat(self.locs,'Fx')
Pbx = mesh.getInterpolationMat(self.locs,'Ex')
ex = Pex*mkvc(u[src,'e_1d'],2)
bx = Pbx*mkvc(u[src,'b_1d'],2)/mu_0
ex = Pex*mkvc(f[src,'e_1d'],2)
bx = Pbx*mkvc(f[src,'b_1d'],2)/mu_0
f_part_complex = ex/bx
# elif self.projType is 'Z2D':
elif self.projType is 'Z3D':
@@ -103,14 +103,14 @@ class RxMT(Survey.BaseRx):
Pby = mesh.getInterpolationMat(self.locs,'Fy')
# Get the fields at location
# px: x-polaration and py: y-polaration.
ex_px = Pex*u[src,'e_px']
ey_px = Pey*u[src,'e_px']
ex_py = Pex*u[src,'e_py']
ey_py = Pey*u[src,'e_py']
hx_px = Pbx*u[src,'b_px']/mu_0
hy_px = Pby*u[src,'b_px']/mu_0
hx_py = Pbx*u[src,'b_py']/mu_0
hy_py = Pby*u[src,'b_py']/mu_0
ex_px = Pex*f[src,'e_px']
ey_px = Pey*f[src,'e_px']
ex_py = Pex*f[src,'e_py']
ey_py = Pey*f[src,'e_py']
hx_px = Pbx*f[src,'b_px']/mu_0
hy_px = Pby*f[src,'b_px']/mu_0
hx_py = Pbx*f[src,'b_py']/mu_0
hy_py = Pby*f[src,'b_py']/mu_0
# Make the complex data
if 'zxx' in self.rxType:
f_part_complex = (ex_px*hy_py - ex_py*hy_px)/(hx_px*hy_py - hx_py*hy_px)
@@ -140,7 +140,7 @@ class RxMT(Survey.BaseRx):
Pbx = mesh.getInterpolationMat(self.locs,'Ex')
# ex = Pex*mkvc(f[src,'e_1d'],2)
# bx = Pbx*mkvc(f[src,'b_1d'],2)/mu_0
deriv_complex = Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0))*(Pex*v) - Utils.sdiag(Pex*mkvc(f[src,'e_1d'],2))*(Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)).T*Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)))*(Pbx*f._b_1dDeriv_u(src,v)/mu_0)
deriv_complex = Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0))*(Pex*v) - Utils.sdiag(Pex*mkvc(f[src,'e_1d'],2))*(Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)).T*Utils.sdiag(1./(Pbx*mkvc(f[src,'b_1d'],2)/mu_0)))*(Pbx*f._bDeriv_u(src,v)/mu_0)
# elif self.projType is 'Z2D
elif self.projType is 'Z3D':
pass
@@ -156,7 +156,8 @@ class RxMT(Survey.BaseRx):
###############
### Sources ###
###############
class srcMT(Survey.BaseSrc):
# Note: Should like inheret from FDEM
class srcMT(SrcFDEM): # Survey.BaseSrc):
'''
Sources for the MT problem.
Use the SimPEG BaseSrc, since the source fields share properties with the transmitters.
@@ -205,7 +206,11 @@ class srcMT_polxy_1Dprimary(srcMT):
def bPrimary(self,problem):
# Project ePrimary to bPrimary
# Satisfies the primary(background) field conditions
bBG_bp = (- problem.mesh.edgeCurl * self.ePrimary )/( 1j*omega(freq) )
if problem.mesh.dim == 1:
C = problem.mesh.nodalGrad
elif problem.mesh.dim == 3:
C = problem.mesh.edgeCurl
bBG_bp = (- C * self.ePrimary(problem) )/( 1j*omega(self.freq) )
return bBG_bp
def S_e(self,problem):
@@ -231,15 +236,18 @@ class srcMT_polxy_1Dprimary(srcMT):
def S_eDeriv(self, problem, v, adjoint = False):
# Need to deal with
if problem.mesh.dim == 1:
pass
# Need to use the faceInnerProduct
MsigmaDeriv = problem.mesh.getFaceInnerProductDeriv(problem.curModel.sigma)(self.ePrimary(problem)[:,-1]) * problem.curModel.sigmaDeriv
MsigmaDeriv = ( MsigmaDeriv * MsigmaDeriv.T)**2
if problem.mesh.dim == 2:
pass
if problem.mesh.dim == 3:
MesigmaDeriv = problem.MeSigmaDeriv(self.ePrimary(problem))
MsigmaDeriv = problem.MeSigmaDeriv(self.ePrimary(problem))
if adjoint:
return MesigmaDeriv.T * v
return MsigmaDeriv.T * v
else:
return MesigmaDeriv * v
# Moved the v in front to make the multi work
return MsigmaDeriv * v
##############