mirror of
https://github.com/wassname/simpeg.git
synced 2026-08-12 12:30:37 +08:00
276 lines
8.3 KiB
Python
276 lines
8.3 KiB
Python
import SimPEG
|
|
from SimPEG import np, Utils
|
|
from SimPEG.Utils import Zero, Identity
|
|
from scipy.constants import mu_0
|
|
from SimPEG.EM.Utils import *
|
|
|
|
####################################################
|
|
# Receivers
|
|
####################################################
|
|
|
|
class Rx(SimPEG.Survey.BaseTimeRx):
|
|
|
|
knownRxTypes = {
|
|
'ex':['e', 'Ex', 'N'],
|
|
'ey':['e', 'Ey', 'N'],
|
|
'ez':['e', 'Ez', 'N'],
|
|
|
|
'bx':['b', 'Fx', 'N'],
|
|
'by':['b', 'Fy', 'N'],
|
|
'bz':['b', 'Fz', 'N'],
|
|
|
|
'dbxdt':['b', 'Fx', 'CC'],
|
|
'dbydt':['b', 'Fy', 'CC'],
|
|
'dbzdt':['b', 'Fz', 'CC'],
|
|
}
|
|
|
|
def __init__(self, locs, times, rxType):
|
|
SimPEG.Survey.BaseTimeRx.__init__(self, locs, times, rxType)
|
|
|
|
@property
|
|
def projField(self):
|
|
"""Field Type projection (e.g. e b ...)"""
|
|
return self.knownRxTypes[self.rxType][0]
|
|
|
|
@property
|
|
def projGLoc(self):
|
|
"""Grid Location projection (e.g. Ex Fy ...)"""
|
|
return self.knownRxTypes[self.rxType][1]
|
|
|
|
@property
|
|
def projTLoc(self):
|
|
"""Time Location projection (e.g. CC N)"""
|
|
return self.knownRxTypes[self.rxType][2]
|
|
|
|
def getTimeP(self, timeMesh):
|
|
"""
|
|
Returns the time projection matrix.
|
|
|
|
.. note::
|
|
|
|
This is not stored in memory, but is created on demand.
|
|
"""
|
|
if self.rxType in ['dbxdt','dbydt','dbzdt']:
|
|
return timeMesh.getInterpolationMat(self.times, self.projTLoc)*timeMesh.faceDiv
|
|
else:
|
|
return timeMesh.getInterpolationMat(self.times, self.projTLoc)
|
|
|
|
def eval(self, src, mesh, timeMesh, u):
|
|
P = self.getP(mesh, timeMesh)
|
|
u_part = Utils.mkvc(u[src, self.projField, :])
|
|
return P*u_part
|
|
|
|
def evalDeriv(self, src, mesh, timeMesh, u, v, adjoint=False):
|
|
P = self.getP(mesh, timeMesh)
|
|
|
|
if not adjoint:
|
|
return P * Utils.mkvc(v[src, self.projField, :])
|
|
elif adjoint:
|
|
return P.T * v[src, self]
|
|
|
|
####################################################
|
|
# Sources
|
|
####################################################
|
|
|
|
class BaseWaveform(object):
|
|
|
|
def __init__(self, offTime=0., hasInitialFields=False):
|
|
self.offTime = offTime
|
|
self.hasInitialFields = hasInitialFields
|
|
|
|
def _assertMatchesPair(self, pair):
|
|
assert (isinstance(self, pair)
|
|
), "Waveform object must be an instance of a %s BaseWaveform class."%(pair.__name__)
|
|
|
|
def eval(self, time):
|
|
raise NotImplementedError
|
|
|
|
def evalDeriv(self, time):
|
|
raise NotImplementedError # needed for E-formulation
|
|
|
|
|
|
class StepOffWaveform(BaseWaveform):
|
|
|
|
def __init__(self, offTime=0.):
|
|
BaseWaveform.__init__(self, offTime, hasInitialFields=True)
|
|
|
|
def eval(self, time):
|
|
return 0.
|
|
|
|
|
|
class RawWaveform(BaseWaveform):
|
|
|
|
def __init__(self, offTime=0.):
|
|
BaseWaveform.__init__(self, offTime, hasInitialFields=True)
|
|
|
|
def eval(self, time):
|
|
raise NotImplementedError 'RawWaveform has not been implemented, you should write it!'
|
|
|
|
|
|
class TriangularWaveform(BaseWaveform):
|
|
|
|
def __init__(self, offTime=0.):
|
|
BaseWaveform.__init__(self, offTime, hasInitialFields=True)
|
|
|
|
def eval(self, time):
|
|
raise NotImplementedError 'TriangularWaveform has not been implemented, you should write it!'
|
|
|
|
|
|
|
|
class BaseSrc(SimPEG.Survey.BaseSrc):
|
|
|
|
rxPair = Rx
|
|
integrate = True
|
|
waveformPair = StepOffWaveform
|
|
|
|
@property
|
|
def waveform(self):
|
|
"A waveform instance is not None"
|
|
return getattr(self, '_waveform', None)
|
|
@waveform.setter
|
|
def waveform(self, val):
|
|
# if self.waveform is None:
|
|
val._assertMatchesPair(self.waveformPair)
|
|
self._waveform = val
|
|
|
|
|
|
def __init__(self, rxList, waveform = None):
|
|
self.waveform = waveform
|
|
SimPEG.Survey.BaseSrc.__init__(self, rxList)
|
|
|
|
|
|
def bInitial(self, prob):
|
|
return Zero()
|
|
|
|
def bInitialDeriv(self, prob, v=None, adjoint=False):
|
|
return Zero()
|
|
|
|
def eval(self, prob, time):
|
|
S_m = self.S_m(prob, time)
|
|
S_e = self.S_e(prob, time)
|
|
return S_m, S_e
|
|
|
|
def evalDeriv(self, prob, time, v=None, adjoint=False):
|
|
if v is not None:
|
|
return self.S_mDeriv(prob, time, v, adjoint), self.S_eDeriv(prob, time, v, adjoint)
|
|
else:
|
|
return lambda v: self.S_mDeriv(prob, time, v, adjoint), lambda v: self.S_eDeriv(prob, time, v, adjoint)
|
|
|
|
def S_m(self, prob, time):
|
|
return Zero()
|
|
|
|
def S_e(self, prob, time):
|
|
return Zero()
|
|
|
|
def S_mDeriv(self, prob, time):
|
|
raise NotImplementedError
|
|
|
|
def S_eDeriv(self, prob, time):
|
|
raise NotImplementedError
|
|
|
|
|
|
class MagDipole(BaseSrc):
|
|
def __init__(self, rxList, waveform=None, loc=None, orientation='Z', moment=1., mu=mu_0):
|
|
|
|
self.loc = loc
|
|
self.orientation = orientation
|
|
assert orientation in ['X','Y','Z'], "Orientation (right now) doesn't actually do anything! The methods in SrcUtils should take care of this..."
|
|
self.moment = moment
|
|
self.mu = mu
|
|
self.integrate = False
|
|
BaseSrc.__init__(self, rxList, waveform)
|
|
|
|
def _bfromVectorPotential(self, prob):
|
|
if prob._eqLocs is 'FE':
|
|
gridX = prob.mesh.gridEx
|
|
gridY = prob.mesh.gridEy
|
|
gridZ = prob.mesh.gridEz
|
|
C = prob.mesh.edgeCurl
|
|
|
|
elif prob._eqLocs is 'EF':
|
|
gridX = prob.mesh.gridFx
|
|
gridY = prob.mesh.gridFy
|
|
gridZ = prob.mesh.gridFz
|
|
C = prob.mesh.edgeCurl.T
|
|
|
|
|
|
if prob.mesh._meshType is 'CYL':
|
|
if not prob.mesh.isSymmetric:
|
|
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
|
a = MagneticDipoleVectorPotential(self.loc, gridY, 'y', mu=self.mu, moment=self.moment)
|
|
|
|
else:
|
|
srcfct = MagneticDipoleVectorPotential
|
|
ax = srcfct(self.loc, gridX, 'x', mu=self.mu, moment=self.moment)
|
|
ay = srcfct(self.loc, gridY, 'y', mu=self.mu, moment=self.moment)
|
|
az = srcfct(self.loc, gridZ, 'z', mu=self.mu, moment=self.moment)
|
|
a = np.concatenate((ax, ay, az))
|
|
|
|
return C*a
|
|
|
|
|
|
def bInitial(self, prob):
|
|
eqLocs = prob._eqLocs
|
|
|
|
if self.waveform.hasInitialFields is False:
|
|
return Zero()
|
|
|
|
return self._bfromVectorPotential(prob)
|
|
|
|
def S_m(self, prob, time):
|
|
if self.waveform.hasInitialFields is False:
|
|
raise NotImplementedError
|
|
return Zero()
|
|
|
|
def S_e(self, prob, time):
|
|
if self.waveform.hasInitialFields is False:
|
|
raise NotImplementedError
|
|
return Zero()
|
|
|
|
####################################################
|
|
# Survey
|
|
####################################################
|
|
|
|
class Survey(SimPEG.Survey.BaseSurvey):
|
|
"""
|
|
Time domain electromagnetic survey
|
|
"""
|
|
|
|
srcPair = BaseSrc
|
|
rxPair = Rx
|
|
|
|
def __init__(self, srcList, **kwargs):
|
|
# Sort these by frequency
|
|
self.srcList = srcList
|
|
SimPEG.Survey.BaseSurvey.__init__(self, **kwargs)
|
|
|
|
def eval(self, u):
|
|
data = SimPEG.Survey.Data(self)
|
|
for src in self.srcList:
|
|
for rx in src.rxList:
|
|
data[src, rx] = rx.eval(src, self.mesh, self.prob.timeMesh, u)
|
|
return data
|
|
|
|
def evalDeriv(self, u, v=None, adjoint=False):
|
|
assert v is not None, 'v to multiply must be provided.'
|
|
|
|
if not adjoint:
|
|
data = SimPEG.Survey.Data(self)
|
|
for src in self.srcList:
|
|
for rx in src.rxList:
|
|
data[src, rx] = rx.evalDeriv(src, self.mesh, self.prob.timeMesh, u, v)
|
|
return data
|
|
else:
|
|
f = FieldsTDEM(self.mesh, self)
|
|
for src in self.srcList:
|
|
for rx in src.rxList:
|
|
Ptv = rx.evalDeriv(src, self.mesh, self.prob.timeMesh, u, v, adjoint=True)
|
|
Ptv = Ptv.reshape((-1, self.prob.timeMesh.nN), order='F')
|
|
if rx.projField not in f: # first time we are projecting
|
|
f[src, rx.projField, :] = Ptv
|
|
else: # there are already fields, so let's add to them!
|
|
f[src, rx.projField, :] += Ptv
|
|
return f
|
|
|
|
|