Compare commits

...
5 changed files with 447 additions and 238 deletions
+306 -162
View File
@@ -1,4 +1,6 @@
import Utils, numpy as np, scipy.sparse as sp import Utils
import numpy as np
import scipy.sparse as sp
from scipy.sparse.linalg import LinearOperator from scipy.sparse.linalg import LinearOperator
from Tests import checkDerivative from Tests import checkDerivative
from PropMaps import PropMap, Property from PropMaps import PropMap, Property
@@ -6,6 +8,7 @@ from numpy.polynomial import polynomial
from scipy.interpolate import UnivariateSpline from scipy.interpolate import UnivariateSpline
import warnings import warnings
class IdentityMap(object): class IdentityMap(object):
""" """
SimPEG Map SimPEG Map
@@ -17,10 +20,11 @@ class IdentityMap(object):
Utils.setKwargs(self, **kwargs) Utils.setKwargs(self, **kwargs)
if nP is not None: if nP is not None:
assert type(nP) in [int, long], ' Number of parameters must be an integer.' assert type(nP) in [int, long], 'Number of parameters '
'must be an integer.'
self.mesh = mesh self.mesh = mesh
self._nP = nP self._nP = nP
@property @property
def nP(self): def nP(self):
@@ -50,14 +54,14 @@ class IdentityMap(object):
return ('*', self.nP) return ('*', self.nP)
return (self.mesh.nC, self.nP) return (self.mesh.nC, self.nP)
def _transform(self, m): def _transform(self, m):
""" """
Changes the model into the physical property. Changes the model into the physical property.
.. note:: .. note::
This can be called by the __mul__ property against a numpy.ndarray. This can be called by the __mul__ property against a
:meth:numpy.ndarray.
:param numpy.array m: model :param numpy.array m: model
:rtype: numpy.array :rtype: numpy.array
@@ -81,7 +85,7 @@ class IdentityMap(object):
""" """
raise NotImplementedError('The transformInverse is not implemented.') raise NotImplementedError('The transformInverse is not implemented.')
def deriv(self, m): def deriv(self, m, v=None):
""" """
The derivative of the transformation. The derivative of the transformation.
@@ -90,13 +94,16 @@ class IdentityMap(object):
:return: derivative of transformed model :return: derivative of transformed model
""" """
if v is not None:
return v
return sp.identity(self.nP) return sp.identity(self.nP)
def test(self, m=None, **kwargs): def test(self, m=None, **kwargs):
"""Test the derivative of the mapping. """Test the derivative of the mapping.
:param numpy.array m: model :param numpy.array m: model
:param kwargs: key word arguments of :meth:`SimPEG.Tests.checkDerivative` :param kwargs: key word arguments of
:meth:`SimPEG.Tests.checkDerivative`
:rtype: bool :rtype: bool
:return: passed the test? :return: passed the test?
@@ -106,26 +113,52 @@ class IdentityMap(object):
m = abs(np.random.rand(self.nP)) m = abs(np.random.rand(self.nP))
if 'plotIt' not in kwargs: if 'plotIt' not in kwargs:
kwargs['plotIt'] = False kwargs['plotIt'] = False
return checkDerivative(lambda m : [self * m, self.deriv(m)], m, num=4, **kwargs) return checkDerivative(lambda m : [self * m, self.deriv(m)], m, num=4,
**kwargs)
def testVec(self, m=None, **kwargs):
"""Test the derivative of the mapping times a vector.
:param numpy.array m: model
:param kwargs: key word arguments of
:meth:`SimPEG.Tests.checkDerivative`
:rtype: bool
:return: passed the test?
"""
print 'Testing %s' % str(self)
if m is None:
m = abs(np.random.rand(self.nP))
if 'plotIt' not in kwargs:
kwargs['plotIt'] = False
return checkDerivative(lambda m: [self*m, lambda x: self.deriv(m, x)],
m, num=4, **kwargs)
def _assertMatchesPair(self, pair): def _assertMatchesPair(self, pair):
assert (isinstance(self, pair) or assert (isinstance(self, pair) or
isinstance(self, ComboMap) and isinstance(self.maps[0], pair) isinstance(self, ComboMap) and isinstance(self.maps[0], pair)
), "Mapping object must be an instance of a %s class."%(pair.__name__) ), ("Mapping object must be an instance of a %s"
" class."% (pair.__name__))
def __mul__(self, val): def __mul__(self, val):
if isinstance(val, IdentityMap): if isinstance(val, IdentityMap):
if not (self.shape[1] == '*' or val.shape[0] == '*') and not self.shape[1] == val.shape[0]: if (not (self.shape[1] == '*' or val.shape[0] == '*') and not
raise ValueError('Dimension mismatch in %s and %s.' % (str(self), str(val))) self.shape[1] == val.shape[0]):
raise ValueError('Dimension mismatch in %s and %s.'
% (str(self), str(val)))
return ComboMap([self, val]) return ComboMap([self, val])
elif isinstance(val, np.ndarray): elif isinstance(val, np.ndarray):
if not self.shape[1] == '*' and not self.shape[1] == val.shape[0]: if not self.shape[1] == '*' and not self.shape[1] == val.shape[0]:
raise ValueError('Dimension mismatch in %s and np.ndarray%s.' % (str(self), str(val.shape))) raise ValueError('Dimension mismatch in %s and np.ndarray%s.'
% (str(self), str(val.shape)))
return self._transform(val) return self._transform(val)
raise Exception('Unrecognized data type to multiply. Try a map or a numpy.ndarray!') raise Exception('Unrecognized data type to multiply. '
'Try a map or a numpy.ndarray!')
def __str__(self): def __str__(self):
return "%s(%s,%s)" % (self.__class__.__name__, self.shape[0], self.shape[1]) return "%s(%s,%s)" % (self.__class__.__name__, self.shape[0],
self.shape[1])
class ComboMap(IdentityMap): class ComboMap(IdentityMap):
@@ -136,11 +169,17 @@ class ComboMap(IdentityMap):
self.maps = [] self.maps = []
for ii, m in enumerate(maps): for ii, m in enumerate(maps):
assert isinstance(m, IdentityMap), 'Unrecognized data type, inherit from an IdentityMap or ComboMap!' assert isinstance(m, IdentityMap), "Unrecognized data type, "
if ii > 0 and not (self.shape[1] == '*' or m.shape[0] == '*') and not self.shape[1] == m.shape[0]: "inherit from an IdentityMap or ComboMap!"
if (ii > 0 and not (self.shape[1] == '*' or m.shape[0] == '*') and
not self.shape[1] == m.shape[0]):
prev = self.maps[-1] prev = self.maps[-1]
errArgs = (prev.__class__.__name__, prev.shape[0], prev.shape[1], m.__class__.__name__, m.shape[0], m.shape[1]) errArgs = (prev.__class__.__name__, prev.shape[0],
raise ValueError('Dimension mismatch in map[%s] (%s, %s) and map[%s] (%s, %s).' % errArgs) prev.shape[1], m.__class__.__name__, m.shape[0],
m.shape[1])
raise ValueError('Dimension mismatch in map[%s] (%s, %s) '
'and map[%s] (%s, %s).' % errArgs)
if isinstance(m, ComboMap): if isinstance(m, ComboMap):
self.maps += m.maps self.maps += m.maps
@@ -164,8 +203,13 @@ class ComboMap(IdentityMap):
m = map_i * m m = map_i * m
return m return m
def deriv(self, m): def deriv(self, m, v=None):
deriv = 1
if v is not None:
deriv = v
else:
deriv = 1
mi = m mi = m
for map_i in reversed(self.maps): for map_i in reversed(self.maps):
deriv = map_i.deriv(mi) * deriv deriv = map_i.deriv(mi) * deriv
@@ -212,8 +256,7 @@ class ExpMap(IdentityMap):
""" """
return np.log(Utils.mkvc(D)) return np.log(Utils.mkvc(D))
def deriv(self, m, v=None):
def deriv(self, m):
""" """
:param numpy.array m: model :param numpy.array m: model
:rtype: scipy.sparse.csr_matrix :rtype: scipy.sparse.csr_matrix
@@ -236,7 +279,11 @@ class ExpMap(IdentityMap):
\\frac{\partial \exp{m}}{\partial m} = \\text{sdiag}(\exp{m}) \\frac{\partial \exp{m}}{\partial m} = \\text{sdiag}(\exp{m})
""" """
return Utils.sdiag(np.exp(Utils.mkvc(m))) deriv = Utils.sdiag(np.exp(Utils.mkvc(m)))
if v is not None:
return deriv * v
return deriv
class ReciprocalMap(IdentityMap): class ReciprocalMap(IdentityMap):
""" """
@@ -253,10 +300,12 @@ class ReciprocalMap(IdentityMap):
def inverse(self, D): def inverse(self, D):
return 1.0 / Utils.mkvc(m) return 1.0 / Utils.mkvc(m)
def deriv(self, m): def deriv(self, m, v=None):
# TODO: if this is a tensor, you might have a problem. # TODO: if this is a tensor, you might have a problem.
return Utils.sdiag( - Utils.mkvc(m)**(-2) ) deriv = Utils.sdiag( - Utils.mkvc(m)**(-2) )
if v is not None:
return deriv * v
return deriv
class LogMap(IdentityMap): class LogMap(IdentityMap):
@@ -265,13 +314,13 @@ class LogMap(IdentityMap):
If \\(p\\) is the physical property and \\(m\\) is the model, then If \\(p\\) is the physical property and \\(m\\) is the model, then
..math:: .. math::
p = \\log(m) p = \\log(m)
and and
..math:: .. math::
m = \\exp(p) m = \\exp(p)
@@ -286,17 +335,20 @@ class LogMap(IdentityMap):
def _transform(self, m): def _transform(self, m):
return np.log(Utils.mkvc(m)) return np.log(Utils.mkvc(m))
def deriv(self, m): def deriv(self, m, v=None):
mod = Utils.mkvc(m) mod = Utils.mkvc(m)
deriv = np.zeros(mod.shape) deriv = np.zeros(mod.shape)
tol = 1e-16 # zero tol = 1e-16 # zero
ind = np.greater_equal(np.abs(mod),tol) ind = np.greater_equal(np.abs(mod), tol)
deriv[ind] = 1.0/mod[ind] deriv[ind] = 1.0/mod[ind]
if v is not None:
return Utils.sdiag(deriv)*v
return Utils.sdiag(deriv) return Utils.sdiag(deriv)
def inverse(self, m): def inverse(self, m):
return np.exp(Utils.mkvc(m)) return np.exp(Utils.mkvc(m))
class SurjectFull(IdentityMap): class SurjectFull(IdentityMap):
""" """
SurjectFull SurjectFull
@@ -305,8 +357,8 @@ class SurjectFull(IdentityMap):
full model space. full model space.
""" """
def __init__(self,mesh,**kwargs): def __init__(self, mesh, **kwargs):
IdentityMap.__init__(self, mesh,**kwargs) IdentityMap.__init__(self, mesh, **kwargs)
@property @property
def nP(self): def nP(self):
@@ -318,22 +370,28 @@ class SurjectFull(IdentityMap):
:rtype: numpy.array :rtype: numpy.array
:return: transformed model :return: transformed model
""" """
return np.ones(self.mesh.nC)*m return np.ones(self.mesh.nC) * m
def deriv(self, m): def deriv(self, m, v=None):
""" """
:param numpy.array m: model :param numpy.array m: model
:rtype: numpy.array :rtype: numpy.array
:return: derivative of transformed model :return: derivative of transformed model
""" """
return np.ones([self.mesh.nC,1]) deriv = np.ones([self.mesh.nC,1])
if v is not None:
return deriv * v
return deriv
class FullMap(SurjectFull): class FullMap(SurjectFull):
def __init__(self,mesh,**kwargs): """FullMap is depreciated. Use SurjectVertical1DMap instead.
"""
def __init__(self, mesh, **kwargs):
warnings.warn( warnings.warn(
"`FullMap` is deprecated and will be removed in future versions. Use `SurjectFull` instead", "`FullMap` is deprecated and will be removed in future versions. Use `SurjectFull` instead",
FutureWarning) FutureWarning)
SurjectFull.__init__(self,mesh,**kwargs) SurjectFull.__init__(self, mesh, **kwargs)
class SurjectVertical1D(IdentityMap): class SurjectVertical1D(IdentityMap):
"""SurjectVertical1DMap """SurjectVertical1DMap
@@ -363,7 +421,7 @@ class SurjectVertical1D(IdentityMap):
repNum = self.mesh.vnC[:self.mesh.dim-1].prod() repNum = self.mesh.vnC[:self.mesh.dim-1].prod()
return Utils.mkvc(m).repeat(repNum) return Utils.mkvc(m).repeat(repNum)
def deriv(self, m): def deriv(self, m, v=None):
""" """
:param numpy.array m: model :param numpy.array m: model
:rtype: scipy.sparse.csr_matrix :rtype: scipy.sparse.csr_matrix
@@ -374,14 +432,22 @@ class SurjectVertical1D(IdentityMap):
(np.ones(repNum), (np.ones(repNum),
(range(repNum), np.zeros(repNum)) (range(repNum), np.zeros(repNum))
), shape=(repNum, 1)) ), shape=(repNum, 1))
return sp.kron(sp.identity(self.nP), repVec) deriv = sp.kron(sp.identity(self.nP), repVec)
if v is not None:
return deriv * v
return deriv
class Vertical1DMap(SurjectVertical1D): class Vertical1DMap(SurjectVertical1D):
def __init__(self,mesh,**kwargs): """
Vertical1DMap is depreciated. Use SurjectVertical1D instead.
"""
def __init__(self, mesh, **kwargs):
warnings.warn( warnings.warn(
"`Vertical1DMap` is deprecated and will be removed in future versions. Use `SurjectVertical1D` instead", "`Vertical1DMap` is deprecated and will be removed in future versions. Use `SurjectVertical1D` instead",
FutureWarning) FutureWarning)
SurjectVertical1D.__init__(self,mesh,**kwargs) SurjectVertical1D.__init__(self, mesh, **kwargs)
class Surject2Dto3D(IdentityMap): class Surject2Dto3D(IdentityMap):
"""Map2Dto3D """Map2Dto3D
@@ -390,12 +456,12 @@ class Surject2Dto3D(IdentityMap):
3D model space. 3D model space.
""" """
normal = 'Y' #: The normal normal = 'Y' #: The normal
def __init__(self, mesh, **kwargs): def __init__(self, mesh, **kwargs):
assert mesh.dim == 3, 'Only works for a 3D Mesh' assert mesh.dim == 3, 'Only works for a 3D Mesh'
IdentityMap.__init__(self, mesh, **kwargs) IdentityMap.__init__(self, mesh, **kwargs)
assert self.normal in ['X','Y','Z'], 'For now, only "Y" normal is supported' assert self.normal in ['X', 'Y', 'Z'], 'For now, only "Y" normal is supported'
@property @property
def nP(self): def nP(self):
@@ -424,7 +490,7 @@ class Surject2Dto3D(IdentityMap):
elif self.normal == 'X': elif self.normal == 'X':
return Utils.mkvc(m.reshape(self.mesh.vnC[[1,2]], order='F')[np.newaxis,:,:].repeat(self.mesh.nCx,axis=0)) return Utils.mkvc(m.reshape(self.mesh.vnC[[1,2]], order='F')[np.newaxis,:,:].repeat(self.mesh.nCx,axis=0))
def deriv(self, m): def deriv(self, m, v=None):
""" """
:param numpy.array m: model :param numpy.array m: model
:rtype: scipy.sparse.csr_matrix :rtype: scipy.sparse.csr_matrix
@@ -436,19 +502,25 @@ class Surject2Dto3D(IdentityMap):
(np.ones(nC), (np.ones(nC),
(range(nC), inds) (range(nC), inds)
), shape=(nC, nP)) ), shape=(nC, nP))
if v is not None:
return P * v
return P return P
class Map2Dto3D(Surject2Dto3D): class Map2Dto3D(Surject2Dto3D):
def __init__(self,mesh,**kwargs): """Map2Dto3D is depreciated. Use Surject2Dto3D instead
"""
def __init__(self, mesh, **kwargs):
warnings.warn( warnings.warn(
"`Map2Dto3D` is deprecated and will be removed in future versions. Use `Surject2Dto3D` instead", "`Map2Dto3D` is deprecated and will be removed in future versions. Use `Surject2Dto3D` instead",
FutureWarning) FutureWarning)
Surject2Dto3D.__init__(self,mesh,**kwargs) Surject2Dto3D.__init__(self, mesh, **kwargs)
class Mesh2Mesh(IdentityMap): class Mesh2Mesh(IdentityMap):
""" """
Takes a model on one mesh are translates it to another mesh. Takes a model on one mesh are translates it to another mesh.
""" """
def __init__(self, meshes, **kwargs): def __init__(self, meshes, **kwargs):
@@ -461,7 +533,7 @@ class Mesh2Mesh(IdentityMap):
self.mesh = meshes[0] self.mesh = meshes[0]
self.mesh2 = meshes[1] self.mesh2 = meshes[1]
self.P = self.mesh2.getInterpolationMat(self.mesh.gridCC,'CC',zerosOutside=True) self.P = self.mesh2.getInterpolationMat(self.mesh.gridCC, 'CC', zerosOutside=True)
@property @property
def shape(self): def shape(self):
@@ -472,9 +544,13 @@ class Mesh2Mesh(IdentityMap):
def nP(self): def nP(self):
"""Number of parameters in the model.""" """Number of parameters in the model."""
return self.mesh2.nC return self.mesh2.nC
def _transform(self, m): def _transform(self, m):
return self.P*m return self.P * m
def deriv(self, m):
def deriv(self, m, v=None):
if v is not None:
return self.P * v
return self.P return self.P
@@ -484,9 +560,9 @@ class InjectActiveCells(IdentityMap):
""" """
indActive = None #: Active Cells indActive = None #: Active Cells
valInactive = None #: Values of inactive Cells valInactive = None #: Values of inactive Cells
nC = None #: Number of cells in the full model nC = None #: Number of cells in the full model
def __init__(self, mesh, indActive, valInactive, nC=None): def __init__(self, mesh, indActive, valInactive, nC=None):
self.mesh = mesh self.mesh = mesh
@@ -494,7 +570,7 @@ class InjectActiveCells(IdentityMap):
self.nC = nC or mesh.nC self.nC = nC or mesh.nC
if indActive.dtype is not bool: if indActive.dtype is not bool:
z = np.zeros(self.nC,dtype=bool) z = np.zeros(self.nC, dtype=bool)
z[indActive] = True z[indActive] = True
indActive = z indActive = z
self.indActive = indActive self.indActive = indActive
@@ -508,7 +584,9 @@ class InjectActiveCells(IdentityMap):
self.valInactive[self.indActive] = 0 self.valInactive[self.indActive] = 0
inds = np.nonzero(self.indActive)[0] inds = np.nonzero(self.indActive)[0]
self.P = sp.csr_matrix((np.ones(inds.size),(inds, range(inds.size))), shape=(self.nC, self.nP)) self.P = sp.csr_matrix((np.ones(inds.size), (inds, range(inds.size))),
shape=(self.nC, self.nP)
)
@property @property
def shape(self): def shape(self):
@@ -520,18 +598,25 @@ class InjectActiveCells(IdentityMap):
return self.indActive.sum() return self.indActive.sum()
def _transform(self, m): def _transform(self, m):
return self.P*m + self.valInactive return self.P * m + self.valInactive
def inverse(self, D): def inverse(self, D):
return self.P.T*D return self.P.T*D
def deriv(self, m): def deriv(self, m, v=None):
if v is not None:
return self.P * v
return self.P return self.P
class ActiveCells(InjectActiveCells): class ActiveCells(InjectActiveCells):
"""ActiveCells is depreciated. Use InjectActiveCells instead.
"""
def __init__(self, mesh, indActive, valInactive, nC=None): def __init__(self, mesh, indActive, valInactive, nC=None):
warnings.warn( warnings.warn(
"`ActiveCells` is deprecated and will be removed in future versions. Use `InjectActiveCells` instead", "`ActiveCells` is deprecated and will be removed in future "
"versions. Use `InjectActiveCells` instead",
FutureWarning) FutureWarning)
InjectActiveCells.__init__(self, mesh, indActive, valInactive, nC) InjectActiveCells.__init__(self, mesh, indActive, valInactive, nC)
@@ -539,11 +624,10 @@ class ActiveCells(InjectActiveCells):
class Weighting(IdentityMap): class Weighting(IdentityMap):
""" """
Model weight parameters. Model weight parameters.
""" """
weights = None #: Active Cells weights = None #: Active Cells
nC = None #: Number of cells in the full model nC = None #: Number of cells in the full model
def __init__(self, mesh, weights=None, nC=None): def __init__(self, mesh, weights=None, nC=None):
self.mesh = mesh self.mesh = mesh
@@ -573,7 +657,9 @@ class Weighting(IdentityMap):
Pinv = Utils.sdiag(self.weights**(-1.)) Pinv = Utils.sdiag(self.weights**(-1.))
return Pinv*D return Pinv*D
def deriv(self, m): def deriv(self, m, v=None):
if v is not None:
return self.P * v
return self.P return self.P
@@ -601,26 +687,32 @@ class ComplexMap(IdentityMap):
nC = self.mesh.nC nC = self.mesh.nC
return m[:nC] + m[nC:]*1j return m[:nC] + m[nC:]*1j
def deriv(self, m): def deriv(self, m, v=None):
nC = self.nP/2 nC = self.nP/2
shp = (nC, nC*2) shp = (nC, nC*2)
def fwd(v): def fwd(v):
return v[:nC] + v[nC:]*1j return v[:nC] + v[nC:]*1j
def adj(v): def adj(v):
return np.r_[v.real,v.imag] return np.r_[v.real, v.imag]
return LinearOperator(shp,matvec=fwd,rmatvec=adj) if v is not None:
return LinearOperator(shp, matvec=fwd, rmatvec=adj) * v
return LinearOperator(shp, matvec=fwd, rmatvec=adj)
inverse = deriv inverse = deriv
class CircleMap(IdentityMap): class ParametricCircleMap(IdentityMap):
"""CircleMap """ParametricCircleMap
Parameterize the model space using a circle in a wholespace. Parameterize the model space using a circle in a wholespace.
..math:: ..math::
\sigma(m) = \sigma_1 + (\sigma_2 - \sigma_1)\left(\\arctan\left(100*\sqrt{(\\vec{x}-x_0)^2 + (\\vec{y}-y_0)}-r\\right) \pi^{-1} + 0.5\\right) \sigma(m) = \sigma_1 + (\sigma_2 - \sigma_1)\left(
\\arctan\left(100*\sqrt{(\\vec{x}-x_0)^2 + (\\vec{y}-y_0)}-r
\\right) \pi^{-1} + 0.5\\right)
Define the model as: Define the model as:
@@ -629,46 +721,69 @@ class CircleMap(IdentityMap):
m = [\sigma_1, \sigma_2, x_0, y_0, r] m = [\sigma_1, \sigma_2, x_0, y_0, r]
""" """
def __init__(self, mesh, logSigma=True):
assert mesh.dim == 2, "Working for a 2D mesh only right now. But it isn't that hard to change.. :)"
IdentityMap.__init__(self, mesh)
self.logSigma = logSigma
slope = 1e-1 slope = 1e-1
def __init__(self, mesh, logSigma=True):
assert mesh.dim == 2, "Working for a 2D mesh only right now. "
"But it isn't that hard to change.. :)"
IdentityMap.__init__(self, mesh)
# TODO: this should be done through a composition with and ExpMap
self.logSigma = logSigma
@property @property
def nP(self): def nP(self):
return 5 return 5
def _transform(self, m): def _transform(self, m):
a = self.slope a = self.slope
sig1,sig2,x,y,r = m[0],m[1],m[2],m[3],m[4] sig1, sig2, x, y, r = m[0], m[1], m[2], m[3], m[4]
if self.logSigma: if self.logSigma:
sig1, sig2 = np.exp(sig1), np.exp(sig2) sig1, sig2 = np.exp(sig1), np.exp(sig2)
X = self.mesh.gridCC[:,0] X = self.mesh.gridCC[:, 0]
Y = self.mesh.gridCC[:,1] Y = self.mesh.gridCC[:, 1]
return sig1 + (sig2 - sig1)*(np.arctan(a*(np.sqrt((X-x)**2 + (Y-y)**2) - r))/np.pi + 0.5) return sig1 + (sig2 - sig1)*(np.arctan(a*(np.sqrt((X-x)**2 +
(Y-y)**2) - r))/np.pi + 0.5)
def deriv(self, m): def deriv(self, m, v=None):
a = self.slope a = self.slope
sig1,sig2,x,y,r = m[0],m[1],m[2],m[3],m[4] sig1, sig2, x, y, r = m[0], m[1], m[2], m[3], m[4]
if self.logSigma: if self.logSigma:
sig1, sig2 = np.exp(sig1), np.exp(sig2) sig1, sig2 = np.exp(sig1), np.exp(sig2)
X = self.mesh.gridCC[:,0] X = self.mesh.gridCC[:, 0]
Y = self.mesh.gridCC[:,1] Y = self.mesh.gridCC[:, 1]
if self.logSigma: if self.logSigma:
g1 = -(np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi + 0.5)*sig1 + sig1 g1 = -(np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi +
g2 = (np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi + 0.5)*sig2 0.5)*sig1 + sig1
g2 = (np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi +
0.5)*sig2
else: else:
g1 = -(np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi + 0.5) + 1.0 g1 = -(np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi +
g2 = (np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi + 0.5) 0.5) + 1.0
g2 = (np.arctan(a*(-r + np.sqrt((X - x)**2 + (Y - y)**2)))/np.pi +
0.5)
g3 = a*(-X + x)*(-sig1 + sig2)/(np.pi*(a**2*(-r + np.sqrt((X - x)**2 + (Y - y)**2))**2 + 1)*np.sqrt((X - x)**2 + (Y - y)**2)) g3 = a*(-X + x)*(-sig1 + sig2)/(np.pi*(a**2*(-r + np.sqrt((X - x)**2 + (Y - y)**2))**2 + 1)*np.sqrt((X - x)**2 + (Y - y)**2))
g4 = a*(-Y + y)*(-sig1 + sig2)/(np.pi*(a**2*(-r + np.sqrt((X - x)**2 + (Y - y)**2))**2 + 1)*np.sqrt((X - x)**2 + (Y - y)**2)) g4 = a*(-Y + y)*(-sig1 + sig2)/(np.pi*(a**2*(-r + np.sqrt((X - x)**2 + (Y - y)**2))**2 + 1)*np.sqrt((X - x)**2 + (Y - y)**2))
g5 = -a*(-sig1 + sig2)/(np.pi*(a**2*(-r + np.sqrt((X - x)**2 + (Y - y)**2))**2 + 1)) g5 = -a*(-sig1 + sig2)/(np.pi*(a**2*(-r + np.sqrt((X - x)**2 + (Y - y)**2))**2 + 1))
return sp.csr_matrix(np.c_[g1,g2,g3,g4,g5])
if v is not None:
return sp.csr_matrix(np.c_[g1, g2, g3, g4, g5]) * v
return sp.csr_matrix(np.c_[g1, g2, g3, g4, g5])
class PolyMap(IdentityMap): class CircleMap(ParametricCircleMap):
"""CircleMap is depreciated. Use ParametricCircleMap instead.
"""
def __init__(self, mesh, logSigma=True):
warnings.warn(
"`CircleMap` is deprecated and will be removed in future "
"versions. Use `ParametricCircleMap` instead",
FutureWarning)
ParametricCircleMap.__init__(self, mesh, logSigma)
class ParametricPolyMap(IdentityMap):
"""PolyMap """PolyMap
@@ -687,7 +802,8 @@ class PolyMap(IdentityMap):
Can take in an actInd vector to account for topography. Can take in an actInd vector to account for topography.
""" """
def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None):
def __init__(self, mesh, order, logSigma=True, normal='X', actInd=None):
IdentityMap.__init__(self, mesh) IdentityMap.__init__(self, mesh)
self.logSigma = logSigma self.logSigma = logSigma
self.order = order self.order = order
@@ -712,78 +828,88 @@ class PolyMap(IdentityMap):
if np.isscalar(self.order): if np.isscalar(self.order):
nP = self.order+3 nP = self.order+3
else: else:
nP =(self.order[0]+1)*(self.order[1]+1)+2 nP = (self.order[0]+1)*(self.order[1]+1)+2
return nP return nP
def _transform(self, m): def _transform(self, m):
# Set model parameters # Set model parameters
alpha = self.slope alpha = self.slope
sig1,sig2 = m[0],m[1] sig1, sig2 = m[0], m[1]
c = m[2:] c = m[2:]
if self.logSigma: if self.logSigma:
sig1, sig2 = np.exp(sig1), np.exp(sig2) sig1, sig2 = np.exp(sig1), np.exp(sig2)
#2D
# 2D
if self.mesh.dim == 2: if self.mesh.dim == 2:
X = self.mesh.gridCC[self.actInd,0] X = self.mesh.gridCC[self.actInd, 0]
Y = self.mesh.gridCC[self.actInd,1] Y = self.mesh.gridCC[self.actInd, 1]
if self.normal =='X': if self.normal =='X':
f = polynomial.polyval(Y, c) - X f = polynomial.polyval(Y, c) - X
elif self.normal =='Y': elif self.normal =='Y':
f = polynomial.polyval(X, c) - Y f = polynomial.polyval(X, c) - Y
else: else:
raise(Exception("Input for normal = X or Y or Z")) raise(Exception("Input for normal = X or Y or Z"))
#3D
# 3D
elif self.mesh.dim == 3: elif self.mesh.dim == 3:
X = self.mesh.gridCC[self.actInd,0] X = self.mesh.gridCC[self.actInd, 0]
Y = self.mesh.gridCC[self.actInd,1] Y = self.mesh.gridCC[self.actInd, 1]
Z = self.mesh.gridCC[self.actInd,2] Z = self.mesh.gridCC[self.actInd, 2]
if self.normal =='X':
f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X if self.normal == 'X':
elif self.normal =='Y': f = (polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,
f = polynomial.polyval2d(X, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - Y self.order[1]+1))) - X)
elif self.normal =='Z': elif self.normal == 'Y':
f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z f = (polynomial.polyval2d(X, Z, c.reshape((self.order[0]+1,
self.order[1]+1))) - Y)
elif self.normal == 'Z':
f = (polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,
self.order[1]+1))) - Z)
else: else:
raise(Exception("Input for normal = X or Y or Z")) raise(Exception("Input for normal = X or Y or Z"))
else: else:
raise(Exception("Only supports 2D")) raise(Exception("Only supports 2D"))
return sig1+(sig2-sig1)*(np.arctan(alpha*f)/np.pi+0.5) return sig1+(sig2-sig1)*(np.arctan(alpha*f)/np.pi+0.5)
def deriv(self, m): def deriv(self, m, v=None):
alpha = self.slope alpha = self.slope
sig1,sig2, c = m[0],m[1],m[2:] sig1, sig2, c = m[0], m[1], m[2:]
if self.logSigma: if self.logSigma:
sig1, sig2 = np.exp(sig1), np.exp(sig2) sig1, sig2 = np.exp(sig1), np.exp(sig2)
#2D
if self.mesh.dim == 2:
X = self.mesh.gridCC[self.actInd,0]
Y = self.mesh.gridCC[self.actInd,1]
if self.normal =='X': # 2D
if self.mesh.dim == 2:
X = self.mesh.gridCC[self.actInd, 0]
Y = self.mesh.gridCC[self.actInd, 1]
if self.normal == 'X':
f = polynomial.polyval(Y, c) - X f = polynomial.polyval(Y, c) - X
V = polynomial.polyvander(Y, len(c)-1) V = polynomial.polyvander(Y, len(c)-1)
elif self.normal =='Y': elif self.normal == 'Y':
f = polynomial.polyval(X, c) - Y f = polynomial.polyval(X, c) - Y
V = polynomial.polyvander(X, len(c)-1) V = polynomial.polyvander(X, len(c)-1)
else: else:
raise(Exception("Input for normal = X or Y or Z")) raise(Exception("Input for normal = X or Y or Z"))
#3D
elif self.mesh.dim == 3:
X = self.mesh.gridCC[self.actInd,0]
Y = self.mesh.gridCC[self.actInd,1]
Z = self.mesh.gridCC[self.actInd,2]
if self.normal =='X': # 3D
f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X elif self.mesh.dim == 3:
X = self.mesh.gridCC[self.actInd, 0]
Y = self.mesh.gridCC[self.actInd, 1]
Z = self.mesh.gridCC[self.actInd, 2]
if self.normal == 'X':
f = (polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,
self.order[1]+1))) - X)
V = polynomial.polyvander2d(Y, Z, self.order) V = polynomial.polyvander2d(Y, Z, self.order)
elif self.normal =='Y': elif self.normal == 'Y':
f = polynomial.polyval2d(X, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - Y f = (polynomial.polyval2d(X, Z, c.reshape((self.order[0]+1,
self.order[1]+1))) - Y)
V = polynomial.polyvander2d(X, Z, self.order) V = polynomial.polyvander2d(X, Z, self.order)
elif self.normal =='Z': elif self.normal == 'Z':
f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z f = (polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,
self.order[1]+1))) - Z)
V = polynomial.polyvander2d(X, Y, self.order) V = polynomial.polyvander2d(X, Y, self.order)
else: else:
raise(Exception("Input for normal = X or Y or Z")) raise(Exception("Input for normal = X or Y or Z"))
@@ -797,13 +923,17 @@ class PolyMap(IdentityMap):
g3 = Utils.sdiag(alpha*(sig2-sig1)/(1.+(alpha*f)**2)/np.pi)*V g3 = Utils.sdiag(alpha*(sig2-sig1)/(1.+(alpha*f)**2)/np.pi)*V
return sp.csr_matrix(np.c_[g1,g2,g3]) if v is not None:
return sp.csr_matrix(np.c_[g1, g2, g3]) * v
return sp.csr_matrix(np.c_[g1, g2, g3])
class SplineMap(IdentityMap):
class ParametricSplineMap(IdentityMap):
"""SplineMap """SplineMap
Parameterize the boundary of two geological units using a spline interpolation Parameterize the boundary of two geological units using
a spline interpolation
..math:: ..math::
@@ -816,7 +946,10 @@ class SplineMap(IdentityMap):
m = [\sigma_1, \sigma_2, y] m = [\sigma_1, \sigma_2, y]
""" """
def __init__(self, mesh, pts, ptsv=None,order=3, logSigma=True, normal='X'):
slope = 1e4
def __init__(self, mesh, pts, ptsv=None, order=3, logSigma=True, normal='X'):
IdentityMap.__init__(self, mesh) IdentityMap.__init__(self, mesh)
self.logSigma = logSigma self.logSigma = logSigma
self.order = order self.order = order
@@ -826,7 +959,6 @@ class SplineMap(IdentityMap):
self.ptsv = ptsv self.ptsv = ptsv
self.spl = None self.spl = None
slope = 1e4
@property @property
def nP(self): def nP(self):
if self.mesh.dim == 2: if self.mesh.dim == 2:
@@ -839,18 +971,18 @@ class SplineMap(IdentityMap):
def _transform(self, m): def _transform(self, m):
# Set model parameters # Set model parameters
alpha = self.slope alpha = self.slope
sig1,sig2 = m[0],m[1] sig1, sig2 = m[0], m[1]
c = m[2:] c = m[2:]
if self.logSigma: if self.logSigma:
sig1, sig2 = np.exp(sig1), np.exp(sig2) sig1, sig2 = np.exp(sig1), np.exp(sig2)
#2D # 2D
if self.mesh.dim == 2: if self.mesh.dim == 2:
X = self.mesh.gridCC[:,0] X = self.mesh.gridCC[:, 0]
Y = self.mesh.gridCC[:,1] Y = self.mesh.gridCC[:, 1]
self.spl = UnivariateSpline(self.pts, c, k=self.order, s=0) self.spl = UnivariateSpline(self.pts, c, k=self.order, s=0)
if self.normal =='X': if self.normal == 'X':
f = self.spl(Y) - X f = self.spl(Y) - X
elif self.normal =='Y': elif self.normal == 'Y':
f = self.spl(X) - Y f = self.spl(X) - Y
else: else:
raise(Exception("Input for normal = X or Y or Z")) raise(Exception("Input for normal = X or Y or Z"))
@@ -862,18 +994,18 @@ class SplineMap(IdentityMap):
# Using 2D interpolation is possible # Using 2D interpolation is possible
elif self.mesh.dim == 3: elif self.mesh.dim == 3:
X = self.mesh.gridCC[:,0] X = self.mesh.gridCC[:, 0]
Y = self.mesh.gridCC[:,1] Y = self.mesh.gridCC[:, 1]
Z = self.mesh.gridCC[:,2] Z = self.mesh.gridCC[:, 2]
npts = np.size(self.pts) npts = np.size(self.pts)
if np.mod(c.size, 2): if np.mod(c.size, 2):
raise(Exception("Put even points!")) raise(Exception("Put even points!"))
self.spl = {"splb":UnivariateSpline(self.pts, c[:npts], k=self.order, s=0), self.spl = {"splb": UnivariateSpline(self.pts, c[:npts], k=self.order, s=0),
"splt":UnivariateSpline(self.pts, c[npts:], k=self.order, s=0)} "splt": UnivariateSpline(self.pts, c[npts:], k=self.order, s=0)}
if self.normal =='X': if self.normal == 'X':
zb = self.ptsv[0] zb = self.ptsv[0]
zt = self.ptsv[1] zt = self.ptsv[1]
flines = (self.spl["splt"](Y)-self.spl["splb"](Y))*(Z-zb)/(zt-zb) + self.spl["splb"](Y) flines = (self.spl["splt"](Y)-self.spl["splb"](Y))*(Z-zb)/(zt-zb) + self.spl["splb"](Y)
@@ -885,30 +1017,29 @@ class SplineMap(IdentityMap):
else: else:
raise(Exception("Only supports 2D and 3D")) raise(Exception("Only supports 2D and 3D"))
return sig1+(sig2-sig1)*(np.arctan(alpha*f)/np.pi+0.5) return sig1+(sig2-sig1)*(np.arctan(alpha*f)/np.pi+0.5)
def deriv(self, m): def deriv(self, m, v=None):
alpha = self.slope alpha = self.slope
sig1,sig2, c = m[0],m[1],m[2:] sig1, sig2, c = m[0], m[1], m[2:]
if self.logSigma: if self.logSigma:
sig1, sig2 = np.exp(sig1), np.exp(sig2) sig1, sig2 = np.exp(sig1), np.exp(sig2)
#2D #2D
if self.mesh.dim == 2: if self.mesh.dim == 2:
X = self.mesh.gridCC[:,0] X = self.mesh.gridCC[:, 0]
Y = self.mesh.gridCC[:,1] Y = self.mesh.gridCC[:, 1]
if self.normal =='X': if self.normal == 'X':
f = self.spl(Y) - X f = self.spl(Y) - X
elif self.normal =='Y': elif self.normal == 'Y':
f = self.spl(X) - Y f = self.spl(X) - Y
else: else:
raise(Exception("Input for normal = X or Y or Z")) raise(Exception("Input for normal = X or Y or Z"))
#3D #3D
elif self.mesh.dim == 3: elif self.mesh.dim == 3:
X = self.mesh.gridCC[:,0] X = self.mesh.gridCC[:, 0]
Y = self.mesh.gridCC[:,1] Y = self.mesh.gridCC[:, 1]
Z = self.mesh.gridCC[:,2] Z = self.mesh.gridCC[:, 2]
if self.normal =='X': if self.normal =='X':
zb = self.ptsv[0] zb = self.ptsv[0]
zt = self.ptsv[1] zt = self.ptsv[1]
@@ -926,10 +1057,9 @@ class SplineMap(IdentityMap):
g1 = -(np.arctan(alpha*f)/np.pi + 0.5) + 1.0 g1 = -(np.arctan(alpha*f)/np.pi + 0.5) + 1.0
g2 = (np.arctan(alpha*f)/np.pi + 0.5) g2 = (np.arctan(alpha*f)/np.pi + 0.5)
if self.mesh.dim == 2:
if self.mesh.dim ==2:
g3 = np.zeros((self.mesh.nC, self.npts)) g3 = np.zeros((self.mesh.nC, self.npts))
if self.normal =='Y': if self.normal == 'Y':
# Here we use perturbation to compute sensitivity # Here we use perturbation to compute sensitivity
# TODO: bit more generalization of this ... # TODO: bit more generalization of this ...
# Modfications for X and Z directions ... # Modfications for X and Z directions ...
@@ -944,11 +1074,11 @@ class SplineMap(IdentityMap):
spla = UnivariateSpline(self.pts, ca, k=self.order, s=0) spla = UnivariateSpline(self.pts, ca, k=self.order, s=0)
splb = UnivariateSpline(self.pts, cb, k=self.order, s=0) splb = UnivariateSpline(self.pts, cb, k=self.order, s=0)
fderiv = (spla(X)-splb(X))/(2*dy) fderiv = (spla(X)-splb(X))/(2*dy)
g3[:,i] = Utils.sdiag(alpha*(sig2-sig1)/(1.+(alpha*f)**2)/np.pi)*fderiv g3[:, i] = Utils.sdiag(alpha*(sig2-sig1)/(1.+(alpha*f)**2)/np.pi)*fderiv
elif self.mesh.dim==3: elif self.mesh.dim == 3:
g3 = np.zeros((self.mesh.nC, self.npts*2)) g3 = np.zeros((self.mesh.nC, self.npts*2))
if self.normal =='X': if self.normal == 'X':
# Here we use perturbation to compute sensitivity # Here we use perturbation to compute sensitivity
for i in range(self.npts*2): for i in range(self.npts*2):
ctemp = c[i] ctemp = c[i]
@@ -958,26 +1088,40 @@ class SplineMap(IdentityMap):
dy = self.mesh.hy[ind]*1.5 dy = self.mesh.hy[ind]*1.5
ca[i] = ctemp+dy ca[i] = ctemp+dy
cb[i] = ctemp-dy cb[i] = ctemp-dy
#treat bottom boundary
if i< self.npts: # treat bottom boundary
if i < self.npts:
splba = UnivariateSpline(self.pts, ca[:self.npts], k=self.order, s=0) splba = UnivariateSpline(self.pts, ca[:self.npts], k=self.order, s=0)
splbb = UnivariateSpline(self.pts, cb[:self.npts], k=self.order, s=0) splbb = UnivariateSpline(self.pts, cb[:self.npts], k=self.order, s=0)
flinesa = (self.spl["splt"](Y)-splba(Y))*(Z-zb)/(zt-zb) + splba(Y) - X flinesa = (self.spl["splt"](Y)-splba(Y))*(Z-zb)/(zt-zb) + splba(Y) - X
flinesb = (self.spl["splt"](Y)-splbb(Y))*(Z-zb)/(zt-zb) + splbb(Y) - X flinesb = (self.spl["splt"](Y)-splbb(Y))*(Z-zb)/(zt-zb) + splbb(Y) - X
#treat top boundary
# treat top boundary
else: else:
splta = UnivariateSpline(self.pts, ca[self.npts:], k=self.order, s=0) splta = UnivariateSpline(self.pts, ca[self.npts:], k=self.order, s=0)
spltb = UnivariateSpline(self.pts, ca[self.npts:], k=self.order, s=0) spltb = UnivariateSpline(self.pts, ca[self.npts:], k=self.order, s=0)
flinesa = (self.spl["splt"](Y)-splta(Y))*(Z-zb)/(zt-zb) + splta(Y) - X flinesa = (self.spl["splt"](Y)-splta(Y))*(Z-zb)/(zt-zb) + splta(Y) - X
flinesb = (self.spl["splt"](Y)-spltb(Y))*(Z-zb)/(zt-zb) + spltb(Y) - X flinesb = (self.spl["splt"](Y)-spltb(Y))*(Z-zb)/(zt-zb) + spltb(Y) - X
fderiv = (flinesa-flinesb)/(2*dy) fderiv = (flinesa-flinesb)/(2*dy)
g3[:,i] = Utils.sdiag(alpha*(sig2-sig1)/(1.+(alpha*f)**2)/np.pi)*fderiv g3[:, i] = Utils.sdiag(alpha*(sig2-sig1)/(1.+(alpha*f)**2)/np.pi)*fderiv
else : else :
raise(Exception("Not Implemented for Y and Z, your turn :)")) raise(Exception("Not Implemented for Y and Z, your turn :)"))
return sp.csr_matrix(np.c_[g1,g2,g3])
if v is not None:
return sp.csr_matrix(np.c_[g1, g2, g3]) * v
return sp.csr_matrix(np.c_[g1, g2, g3])
class SplineMap(ParametricSplineMap):
"""SplineMap is depreciated. Use ParametricSplineMap instead.
"""
def __init__(self, mesh, pts, ptsv=None, order=3, logSigma=True,
normal='X'):
warnings.warn(
"`SplineMap` is deprecated and will be removed in future "
"versions. Use `ParametricSplineMap` instead",
FutureWarning)
ParametricSplineMap.__init__(self, mesh, pts, ptsv, order, logSigma,
normal)
+122 -64
View File
@@ -2,39 +2,71 @@ import numpy as np
import unittest import unittest
from SimPEG import * from SimPEG import *
from scipy.sparse.linalg import dsolve from scipy.sparse.linalg import dsolve
import inspect
TOL = 1e-14 TOL = 1e-14
MAPS_TO_TEST_2D = ["CircleMap", "ComplexMap", "ExpMap", "IdentityMap", "SurjectVertical1D", "Weighting", "SurjectFull","FullMap"] MAPS_TO_EXCLUDE_2D = ["ComboMap", "ActiveCells", "InjectActiveCells"]
MAPS_TO_TEST_3D = [ "ComplexMap", "ExpMap", "IdentityMap", "SurjectVertical1D", "Weighting", "SurjectFull","FullMap"] MAPS_TO_EXCLUDE_3D = ["ComboMap", "ActiveCells", "InjectActiveCells",
"CircleMap"]
MAPS_TO_TEST_INVERSE = ["ExpMap"]
class MapTests(unittest.TestCase): class MapTests(unittest.TestCase):
def setUp(self): def setUp(self):
maps2test2D = [M for M in dir(Maps) if M not in MAPS_TO_EXCLUDE_2D]
maps2test3D = [M for M in dir(Maps) if M not in MAPS_TO_EXCLUDE_3D]
self.maps2test2D = [getattr(Maps, m) for m in maps2test2D if
inspect.isclass(getattr(Maps, M)) and
issubclass(getattr(Maps, M), Maps.IdentityMap)]
self.maps2test3D = [getattr(Maps, m) for m in maps2test3D if
inspect.isclass(getattr(Maps, M)) and
issubclass(getattr(Maps, M), Maps.IdentityMap)]
a = np.array([1, 1, 1]) a = np.array([1, 1, 1])
b = np.array([1, 2]) b = np.array([1, 2])
self.mesh2 = Mesh.TensorMesh([a, b], x0=np.array([3, 5])) self.mesh2 = Mesh.TensorMesh([a, b], x0=np.array([3, 5]))
self.mesh3 = Mesh.TensorMesh([a, b, [3,4]], x0=np.array([3, 5, 2])) self.mesh3 = Mesh.TensorMesh([a, b, [3, 4]], x0=np.array([3, 5, 2]))
self.mesh22 = Mesh.TensorMesh([b, a], x0=np.array([3, 5])) self.mesh22 = Mesh.TensorMesh([b, a], x0=np.array([3, 5]))
def test_transforms2D(self): def test_transforms2D(self):
for M in MAPS_TO_TEST_2D: for M in self.maps2test2D:
maps = getattr(Maps, M)(self.mesh2) self.assertTrue(M.test())
self.assertTrue(maps.test())
def test_transforms2Dvec(self):
for M in self.maps2test2D:
self.assertTrue(M.testVec())
def test_transforms3D(self): def test_transforms3D(self):
for M in MAPS_TO_TEST_3D: for M in self.maps2test3D:
maps = getattr(Maps, M)(self.mesh3) self.assertTrue(M.test())
self.assertTrue(maps.test())
def test_transforms3Dvec(self):
for M in self.maps2test3D:
self.assertTrue(M.test())
def test_transforms_logMap_reciprocalMap(self): def test_transforms_logMap_reciprocalMap(self):
# Note that log/reciprocal maps can be kinda finicky, so we are being explicit about the random seed.
v2 = np.r_[ 0.40077291, 0.14410044, 0.58452314, 0.96323738, 0.01198519, 0.79754415] # Note that log/reciprocal maps can be kinda finicky, so we are being
dv2 = np.r_[ 0.80653921, 0.13132446, 0.4901117, 0.03358737, 0.65473762, 0.44252488] # explicit about the random seed.
v3 = np.r_[ 0.96084865, 0.34385186, 0.39430044, 0.81671285, 0.65929109, 0.2235217, 0.87897526, 0.5784033, 0.96876393, 0.63535864, 0.84130763, 0.22123854]
dv3 = np.r_[ 0.96827838, 0.26072111, 0.45090749, 0.10573893, 0.65276365, 0.15646586, 0.51679682, 0.23071984, 0.95106218, 0.14201845, 0.25093564, 0.3732866 ] v2 = np.r_[0.40077291, 0.14410044, 0.58452314, 0.96323738, 0.01198519,
0.79754415]
dv2 = np.r_[0.80653921, 0.13132446, 0.4901117, 0.03358737, 0.65473762,
0.44252488]
v3 = np.r_[0.96084865, 0.34385186, 0.39430044, 0.81671285, 0.65929109,
0.2235217, 0.87897526, 0.5784033, 0.96876393, 0.63535864,
0.84130763, 0.22123854]
dv3 = np.r_[0.96827838, 0.26072111, 0.45090749, 0.10573893,
0.65276365, 0.15646586, 0.51679682, 0.23071984,
0.95106218, 0.14201845, 0.25093564, 0.3732866 ]
maps = Maps.LogMap(self.mesh2) maps = Maps.LogMap(self.mesh2)
self.assertTrue(maps.test(v2, dx=dv2)) self.assertTrue(maps.test(v2, dx=dv2))
maps = Maps.LogMap(self.mesh3) maps = Maps.LogMap(self.mesh3)
@@ -49,100 +81,126 @@ class MapTests(unittest.TestCase):
maps = Maps.Mesh2Mesh([self.mesh22, self.mesh2]) maps = Maps.Mesh2Mesh([self.mesh22, self.mesh2])
self.assertTrue(maps.test()) self.assertTrue(maps.test())
def test_Mesh2MeshMapVec(self):
maps = Maps.Mesh2Mesh([self.mesh22, self.mesh2])
self.assertTrue(maps.testVec())
def test_mapMultiplication(self): def test_mapMultiplication(self):
M = Mesh.TensorMesh([2,3]) M = Mesh.TensorMesh([2, 3])
expMap = Maps.ExpMap(M) expMap = Maps.ExpMap(M)
vertMap = Maps.SurjectVertical1D(M) vertMap = Maps.SurjectVertical1D(M)
combo = expMap*vertMap combo = expMap*vertMap
m = np.arange(3.0) m = np.arange(3.0)
t_true = np.exp(np.r_[0,0,1,1,2,2.]) t_true = np.exp(np.r_[0, 0, 1, 1, 2, 2.])
self.assertLess(np.linalg.norm((combo * m)-t_true,np.inf),TOL) self.assertLess(np.linalg.norm((combo * m) - t_true, np.inf), TOL)
self.assertLess(np.linalg.norm((expMap * vertMap * m)-t_true,np.inf),TOL) self.assertLess(np.linalg.norm((expMap * vertMap * m)-t_true, np.inf),
self.assertLess(np.linalg.norm(expMap * (vertMap * m)-t_true,np.inf),TOL) TOL)
self.assertLess(np.linalg.norm((expMap * vertMap) * m-t_true,np.inf),TOL) self.assertLess(np.linalg.norm(expMap * (vertMap * m)-t_true, np.inf),
#Try making a model TOL)
self.assertLess(np.linalg.norm((expMap * vertMap) * m-t_true, np.inf),
TOL)
# Try making a model
mod = Models.Model(m, mapping=combo) mod = Models.Model(m, mapping=combo)
# print mod.transform # print mod.transform
# import matplotlib.pyplot as plt # import matplotlib.pyplot as plt
# plt.colorbar(M.plotImage(mod.transform)[0]) # plt.colorbar(M.plotImage(mod.transform)[0])
# plt.show() # plt.show()
self.assertLess(np.linalg.norm(mod.transform-t_true,np.inf),TOL) self.assertLess(np.linalg.norm(mod.transform - t_true, np.inf), TOL)
self.assertRaises(Exception,Models.Model,np.r_[1.0],mapping=combo) self.assertRaises(Exception, Models.Model, np.r_[1.0], mapping=combo)
self.assertRaises(ValueError, lambda: combo * (vertMap * expMap)) self.assertRaises(ValueError, lambda: combo * (vertMap * expMap))
self.assertRaises(ValueError, lambda: (combo * vertMap) * expMap) self.assertRaises(ValueError, lambda: (combo * vertMap) * expMap)
self.assertRaises(ValueError, lambda: vertMap * expMap) self.assertRaises(ValueError, lambda: vertMap * expMap)
self.assertRaises(ValueError, lambda: expMap * np.ones(100)) self.assertRaises(ValueError, lambda: expMap * np.ones(100))
self.assertRaises(ValueError, lambda: expMap * np.ones((100.0,1))) self.assertRaises(ValueError, lambda: expMap * np.ones((100.0, 1)))
self.assertRaises(ValueError, lambda: expMap * np.ones((100.0,5))) self.assertRaises(ValueError, lambda: expMap * np.ones((100.0, 5)))
self.assertRaises(ValueError, lambda: combo * np.ones(100)) self.assertRaises(ValueError, lambda: combo * np.ones(100))
self.assertRaises(ValueError, lambda: combo * np.ones((100.0,1))) self.assertRaises(ValueError, lambda: combo * np.ones((100.0, 1)))
self.assertRaises(ValueError, lambda: combo * np.ones((100.0,5))) self.assertRaises(ValueError, lambda: combo * np.ones((100.0, 5)))
def test_activeCells(self): def test_activeCells(self):
M = Mesh.TensorMesh([2,4],'0C') M = Mesh.TensorMesh([2, 4], '0C')
expMap = Maps.ExpMap(M) expMap = Maps.ExpMap(M)
for actMap in [Maps.InjectActiveCells(M, M.vectorCCy <=0, 10, nC=M.nCy), Maps.ActiveCells(M, M.vectorCCy <=0, 10, nC=M.nCy)]: for actMap in [Maps.InjectActiveCells(M, M.vectorCCy <= 0, 10,
# actMap = Maps.InjectActiveCells(M, M.vectorCCy <=0, 10, nC=M.nCy) nC=M.nCy), Maps.ActiveCells(M, M.vectorCCy <= 0, 10,
nC=M.nCy)]:
vertMap = Maps.SurjectVertical1D(M) vertMap = Maps.SurjectVertical1D(M)
combo = vertMap * actMap combo = vertMap * actMap
m = np.r_[1,2.] m = np.r_[1., 2.]
mod = Models.Model(m,combo) mod = Models.Model(m, combo)
# import matplotlib.pyplot as plt
# plt.colorbar(M.plotImage(mod.transform)[0]) self.assertLess(np.linalg.norm(mod.transform -
# plt.show() np.r_[1, 1, 2, 2, 10, 10, 10, 10.]), TOL)
self.assertLess(np.linalg.norm(mod.transform - np.r_[1,1,2,2,10,10,10,10.]), TOL) self.assertLess((mod.transformDeriv -
self.assertLess((mod.transformDeriv - combo.deriv(m)).toarray().sum(), TOL) combo.deriv(m)).toarray().sum(), TOL)
def test_tripleMultiply(self): def test_tripleMultiply(self):
M = Mesh.TensorMesh([2,4],'0C') M = Mesh.TensorMesh([2, 4], '0C')
expMap = Maps.ExpMap(M) expMap = Maps.ExpMap(M)
vertMap = Maps.SurjectVertical1D(M) vertMap = Maps.SurjectVertical1D(M)
actMap = Maps.InjectActiveCells(M, M.vectorCCy <=0, 10, nC=M.nCy) actMap = Maps.InjectActiveCells(M, M.vectorCCy <= 0, 10, nC=M.nCy)
m = np.r_[1,2.] m = np.r_[1., 2.]
t_true = np.exp(np.r_[1,1,2,2,10,10,10,10.]) t_true = np.exp(np.r_[1, 1, 2, 2, 10, 10, 10, 10.])
self.assertLess(np.linalg.norm((expMap * vertMap * actMap * m)-t_true,np.inf),TOL)
self.assertLess(np.linalg.norm(((expMap * vertMap * actMap) * m)-t_true,np.inf),TOL)
self.assertLess(np.linalg.norm((expMap * vertMap * (actMap * m))-t_true,np.inf),TOL)
self.assertLess(np.linalg.norm((expMap * (vertMap * actMap) * m)-t_true,np.inf),TOL)
self.assertLess(np.linalg.norm(((expMap * vertMap) * actMap * m)-t_true,np.inf),TOL)
self.assertRaises(ValueError, lambda: expMap * actMap * vertMap ) self.assertLess(np.linalg.norm((expMap * vertMap * actMap * m) -
self.assertRaises(ValueError, lambda: actMap * vertMap * expMap ) t_true, np.inf), TOL)
self.assertLess(np.linalg.norm(((expMap * vertMap * actMap) * m) -
t_true, np.inf), TOL)
self.assertLess(np.linalg.norm((expMap * vertMap * (actMap * m)) -
t_true, np.inf), TOL)
self.assertLess(np.linalg.norm((expMap * (vertMap * actMap) * m) -
t_true, np.inf), TOL)
self.assertLess(np.linalg.norm(((expMap * vertMap) * actMap * m) -
t_true, np.inf), TOL)
self.assertRaises(ValueError, lambda: expMap * actMap * vertMap)
self.assertRaises(ValueError, lambda: actMap * vertMap * expMap)
def test_map2Dto3D_x(self): def test_map2Dto3D_x(self):
M2 = Mesh.TensorMesh([2,4]) M2 = Mesh.TensorMesh([2, 4])
M3 = Mesh.TensorMesh([3,2,4]) M3 = Mesh.TensorMesh([3, 2, 4])
m = np.random.rand(M2.nC) m = np.random.rand(M2.nC)
for m2to3 in [Maps.Surject2Dto3D(M3, normal='X'), Maps.Map2Dto3D(M3, normal='X')]: for m2to3 in [Maps.Surject2Dto3D(M3, normal='X'),
# m2to3 = Maps.Surject2Dto3D(M3, normal='X') Maps.Map2Dto3D(M3, normal='X')]:
# m2to3 = Maps.Surject2Dto3D(M3, normal='X')
m = np.arange(m2to3.nP) m = np.arange(m2to3.nP)
self.assertTrue(m2to3.test()) self.assertTrue(m2to3.test())
self.assertTrue(np.all(Utils.mkvc( (m2to3 * m).reshape(M3.vnC,order='F')[0,:,:] ) == m)) self.assertTrue(m2to3.testVec())
self.assertTrue(np.all(Utils.mkvc((m2to3 * m).reshape(M3.vnC,
order='F')[0, :, :]) == m))
def test_map2Dto3D_y(self): def test_map2Dto3D_y(self):
M2 = Mesh.TensorMesh([3,4]) M2 = Mesh.TensorMesh([3, 4])
M3 = Mesh.TensorMesh([3,2,4]) M3 = Mesh.TensorMesh([3, 2, 4])
m = np.random.rand(M2.nC) m = np.random.rand(M2.nC)
for m2to3 in [Maps.Surject2Dto3D(M3, normal='Y'),Maps.Map2Dto3D(M3, normal='Y')]:
# m2to3 = Maps.Surject2Dto3D(M3, normal='Y') for m2to3 in [Maps.Surject2Dto3D(M3, normal='Y'), Maps.Map2Dto3D(M3,
normal='Y')]:
# m2to3 = Maps.Surject2Dto3D(M3, normal='Y')
m = np.arange(m2to3.nP) m = np.arange(m2to3.nP)
self.assertTrue(m2to3.test()) self.assertTrue(m2to3.test())
self.assertTrue(np.all(Utils.mkvc( (m2to3 * m).reshape(M3.vnC,order='F')[:,0,:] ) == m)) self.assertTrue(m2to3.testVec())
self.assertTrue(np.all(Utils.mkvc((m2to3 * m).reshape(M3.vnC,
order='F')[:, 0, :]) == m))
def test_map2Dto3D_z(self): def test_map2Dto3D_z(self):
M2 = Mesh.TensorMesh([3,2]) M2 = Mesh.TensorMesh([3, 2])
M3 = Mesh.TensorMesh([3,2,4]) M3 = Mesh.TensorMesh([3, 2, 4])
m = np.random.rand(M2.nC) m = np.random.rand(M2.nC)
for m2to3 in [Maps.Surject2Dto3D(M3, normal='Z'),Maps.Map2Dto3D(M3, normal='Z')]:
# m2to3 = Maps.Surject2Dto3D(M3, normal='Z') for m2to3 in [Maps.Surject2Dto3D(M3, normal='Z'), Maps.Map2Dto3D(M3,
normal='Z')]:
# m2to3 = Maps.Surject2Dto3D(M3, normal='Z')
m = np.arange(m2to3.nP) m = np.arange(m2to3.nP)
self.assertTrue(m2to3.test()) self.assertTrue(m2to3.test())
self.assertTrue(np.all(Utils.mkvc( (m2to3 * m).reshape(M3.vnC,order='F')[:,:,0] ) == m)) self.assertTrue(m2to3.testVec())
self.assertTrue(np.all(Utils.mkvc((m2to3 * m).reshape(M3.vnC,
order='F')[:, :, 0]) == m))
if __name__ == '__main__': if __name__ == '__main__':
+3 -3
View File
@@ -5,12 +5,12 @@ from SimPEG import *
class TestTimeProblem(unittest.TestCase): class TestTimeProblem(unittest.TestCase):
def setUp(self): def setUp(self):
mesh = Mesh.TensorMesh([10,10]) mesh = Mesh.TensorMesh([10, 10])
self.prob = Problem.BaseTimeProblem(mesh) self.prob = Problem.BaseTimeProblem(mesh)
def test_timeProblem_setTimeSteps(self): def test_timeProblem_setTimeSteps(self):
self.prob.timeSteps = [(1e-6, 3), 1e-5, (1e-4, 2)] self.prob.timeSteps = [(1e-6, 3), 1e-5, (1e-4, 2)]
trueTS = np.r_[1e-6,1e-6,1e-6,1e-5,1e-4,1e-4] trueTS = np.r_[1e-6, 1e-6, 1e-6, 1e-5, 1e-4, 1e-4]
self.assertTrue(np.all(trueTS == self.prob.timeSteps)) self.assertTrue(np.all(trueTS == self.prob.timeSteps))
self.prob.timeSteps = trueTS self.prob.timeSteps = trueTS
@@ -18,7 +18,7 @@ class TestTimeProblem(unittest.TestCase):
self.assertTrue(self.prob.nT == 6) self.assertTrue(self.prob.nT == 6)
self.assertTrue(np.all(self.prob.times == np.r_[0,trueTS].cumsum())) self.assertTrue(np.all(self.prob.times == np.r_[0, trueTS].cumsum()))
if __name__ == '__main__': if __name__ == '__main__':
+14 -7
View File
@@ -8,6 +8,7 @@ TOL = 1e-20
testReg = True testReg = True
testRegMesh = True testRegMesh = True
class RegularizationTests(unittest.TestCase): class RegularizationTests(unittest.TestCase):
def setUp(self): def setUp(self):
@@ -16,41 +17,47 @@ class RegularizationTests(unittest.TestCase):
mesh1 = Mesh.TensorMesh([hx]) mesh1 = Mesh.TensorMesh([hx])
mesh2 = Mesh.TensorMesh([hx, hy]) mesh2 = Mesh.TensorMesh([hx, hy])
mesh3 = Mesh.TensorMesh([hx, hy, hz]) mesh3 = Mesh.TensorMesh([hx, hy, hz])
self.meshlist = [mesh1,mesh2, mesh3] self.meshlist = [mesh1, mesh2, mesh3]
if testReg: if testReg:
def test_regularization(self): def test_regularization(self):
for R in dir(Regularization): for R in dir(Regularization):
r = getattr(Regularization, R) r = getattr(Regularization, R)
if not inspect.isclass(r): continue if not inspect.isclass(r):
continue
if not issubclass(r, Regularization.BaseRegularization): if not issubclass(r, Regularization.BaseRegularization):
continue continue
for i, mesh in enumerate(self.meshlist): for i, mesh in enumerate(self.meshlist):
print 'Testing %iD'%mesh.dim print 'Testing %iD' % mesh.dim
mapping = r.mapPair(mesh) mapping = r.mapPair(mesh)
reg = r(mesh, mapping=mapping) reg = r(mesh, mapping=mapping)
m = np.random.rand(mapping.nP) m = np.random.rand(mapping.nP)
reg.mref = np.ones_like(m)*np.mean(m) reg.mref = np.ones_like(m)*np.mean(m)
print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref) print 'Check: phi_m (mref) = %f' % reg.eval(reg.mref)
passed = reg.eval(reg.mref) < TOL passed = reg.eval(reg.mref) < TOL
self.assertTrue(passed) self.assertTrue(passed)
print 'Check:', R print 'Check:', R
passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False) passed = Tests.checkDerivative(lambda m: [reg.eval(m),
reg.evalDeriv(m)], m,
plotIt=False)
self.assertTrue(passed) self.assertTrue(passed)
print 'Check 2 Deriv:', R print 'Check 2 Deriv:', R
passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False) passed = Tests.checkDerivative(lambda m: [reg.evalDeriv(m),
reg.eval2Deriv(m)], m,
plotIt=False)
self.assertTrue(passed) self.assertTrue(passed)
def test_regularization_ActiveCells(self): def test_regularization_ActiveCells(self):
for R in dir(Regularization): for R in dir(Regularization):
r = getattr(Regularization, R) r = getattr(Regularization, R)
if not inspect.isclass(r): continue if not inspect.isclass(r):
continue
if not issubclass(r, Regularization.BaseRegularization): if not issubclass(r, Regularization.BaseRegularization):
continue continue
+1 -1
View File
@@ -3,7 +3,7 @@ import unittest
from SimPEG.Tests import OrderTest from SimPEG.Tests import OrderTest
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
#TODO: 'randomTensorMesh' # TODO: 'randomTensorMesh'
MESHTYPES = ['uniformTensorMesh', 'uniformCurv', 'rotateCurv'] MESHTYPES = ['uniformTensorMesh', 'uniformCurv', 'rotateCurv']
call2 = lambda fun, xyz: fun(xyz[:, 0], xyz[:, 1]) call2 = lambda fun, xyz: fun(xyz[:, 0], xyz[:, 1])
call3 = lambda fun, xyz: fun(xyz[:, 0], xyz[:, 1], xyz[:, 2]) call3 = lambda fun, xyz: fun(xyz[:, 0], xyz[:, 1], xyz[:, 2])