Files
simpeg/simpegEM/TDEM/BaseTDEM.py
T
2014-02-12 16:59:56 -08:00

156 lines
4.8 KiB
Python

from SimPEG import Solver
from SimPEG.Problem import BaseProblem
from simpegEM.Utils import Sources
from FieldsTDEM import FieldsTDEM
from scipy.constants import mu_0
from SimPEG.Utils import sdiag, mkvc
import numpy as np
class MixinInitialFieldCalc(object):
"""docstring for MixinInitialFieldCalc"""
def getInitialFields(self):
if self.data.txType == 'VMD_MVP':
# Vertical magnetic dipole, magnetic vector potential
F = self._getInitialFields_VMD_MVP()
else:
exStr = 'Invalid txType: ' + str(self.data.txType)
raise Exception(exStr)
return F
def _getInitialFields_VMD_MVP(self):
if self.mesh._meshType is 'CYL1D':
MVP = Sources.MagneticDipoleVectorPotential(np.r_[0,0,self.data.txLoc], np.c_[np.zeros(self.mesh.nN), self.mesh.gridN], 'x')
elif self.mesh._meshType is 'TENSOR':
MVPx = Sources.MagneticDipoleVectorPotential(self.data.txLoc, self.mesh.gridEx, 'x')
MVPy = Sources.MagneticDipoleVectorPotential(self.data.txLoc, self.mesh.gridEy, 'y')
MVPz = Sources.MagneticDipoleVectorPotential(self.data.txLoc, self.mesh.gridEz, 'z')
MVP = np.concatenate((MVPx, MVPy, MVPz))
# Initialize field object
F = FieldsTDEM(self.mesh, 1, self.times.size, 'b')
# Set initial B
F.b0 = self.mesh.edgeCurl*MVP
return F
class MixinTimeStuff(object):
"""docstring for MixinTimeStuff"""
def dt():
doc = "Size of time steps"
def fget(self):
return self._dt
def fdel(self):
del self._dt
return locals()
dt = property(**dt())
def nsteps():
doc = "Number of steps to take"
def fget(self):
return self._nsteps
def fdel(self):
del self._nsteps
return locals()
nsteps = property(**nsteps())
def times():
doc = "Modelling times"
def fget(self):
t = np.r_[1:self.nsteps[0]+1]*self.dt[0]
for i in range(1,self.dt.size):
t = np.r_[t, np.r_[1:self.nsteps[i]+1]*self.dt[i]+t[-1]]
return t
return locals()
times = property(**times())
def getDt(self, tInd):
return np.concatenate([self.dt[i].repeat(self.nsteps[i]) for i in range(self.dt.size)])[tInd]
def setTimes(self, dt, nsteps):
dt = np.array(dt)
nsteps = np.array(nsteps)
assert dt.size==nsteps.size, "dt, nsteps must be same length"
self._dt = dt
self._nsteps = nsteps
class ProblemBaseTDEM(MixinTimeStuff, MixinInitialFieldCalc, BaseProblem):
"""docstring for ProblemTDEM1D"""
def __init__(self, mesh, model, **kwargs):
BaseProblem.__init__(self, mesh, model, **kwargs)
####################################################
# Physical Properties
####################################################
@property
def sigma(self):
return self._sigma
@sigma.setter
def sigma(self, value):
self._sigma = value
_sigma = None
####################################################
# Mass Matrices
####################################################
@property
def MfMui(self): return self._MfMui
@property
def MeSigma(self): return self._MeSigma
@property
def MeSigmaI(self): return self._MeSigmaI
def makeMassMatrices(self, m):
self._MeSigma = self.mesh.getMass(m, loc='e')
self._MeSigmaI = sdiag(1/self.MeSigma.diagonal())
self._MfMui = self.mesh.getMass(1/mu_0, loc='f')
def calcFields(self, sol, solType, tInd):
if solType == 'b':
b = sol
e = self.MeSigmaI*self.mesh.edgeCurl.T*self.MfMui*b
# Todo: implement non-zero js
else:
errStr = 'solType: ' + solType
raise NotImplementedError(errStr)
return {'b':b, 'e':e}
solveOpts = {'factorize':True,'backend':'scipy'}
def fields(self, m, useThisRhs=None, useThisCalcFields=None):
RHS = useThisRhs or self.getRHS
CalcFields = useThisCalcFields or self.calcFields
self.makeMassMatrices(m)
F = self.getInitialFields()
#TODO: Split next code to forward and adjoint.
# fields would call forward
dtFact = None
for tInd, t in enumerate(self.times):
dt = self.getDt(tInd)
if dt!=dtFact:
dtFact = dt
A = self.getA(tInd)
# print 'Factoring... (dt = ' + str(dt) + ')'
Asolve = Solver(A, options=self.solveOpts)
# print 'Done'
rhs = RHS(tInd, F)
sol = Asolve.solve(rhs)
if sol.ndim == 1:
sol.shape = (sol.size,1)
newFields = CalcFields(sol, self.solType, tInd)
F.update(newFields, tInd)
return F