updates to face innerProducts

Increase Speed
Add derivatives
Add tests
This commit is contained in:
rowanc1
2014-02-28 15:21:39 -08:00
parent 1e5053085d
commit b5c7b11265
5 changed files with 160 additions and 2 deletions
+38 -1
View File
@@ -10,7 +10,8 @@ class InnerProducts(object):
def __init__(self):
raise Exception('InnerProducts is a base class providing inner product matrices for meshes and cannot run on its own. Inherit to your favorite Mesh class.')
def getFaceInnerProduct(self, materialProperty=None, returnP=False, invertProperty=False):
def getFaceInnerProduct(self, materialProperty=None, returnP=False,
invertProperty=False):
"""
:param numpy.array materialProperty: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6))
:param bool returnP: returns the projection matrices
@@ -18,6 +19,14 @@ class InnerProducts(object):
:rtype: scipy.csr_matrix
:return: M, the inner product matrix (nF, nF)
"""
fast = None
if returnP is False and hasattr(self, '_fastFaceInnerProduct'):
fast = self._fastFaceInnerProduct(materialProperty=materialProperty, invertProperty=invertProperty)
if fast is not None:
return fast
if invertProperty:
materialProperty = invPropertyTensor(self, materialProperty)
@@ -62,6 +71,34 @@ class InnerProducts(object):
else:
return A
def getFaceInnerProductDeriv(self, materialProperty=None, P=None):
"""
:param numpy.array materialProperty: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6))
:rtype: scipy.csr_matrix
:return: M, the inner product matrix (nF, nF)
"""
fast = None
if hasattr(self, '_fastFaceInnerProductDeriv'):
fast = self._fastFaceInnerProductDeriv(materialProperty=materialProperty)
if fast is not None:
return fast
raise NotImplementedError('Derivatives for the material property specified are not yet implemented.')
if P is None:
M, P = getFaceInnerProduct(self, materialProperty=materialProperty, returnP=True)
d = self.dim
if d == 1:
P[0].T * sp.identity(n) * P[0]
def getEdgeInnerProduct(self, materialProperty=None, returnP=False, invertProperty=False):
"""
:param numpy.array materialProperty: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6))
+44
View File
@@ -39,6 +39,7 @@ class TensorMesh(BaseRectangularMesh, TensorView, DiffOperators, InnerProducts):
def __init__(self, h_in, x0=None):
assert type(h_in) is list, 'h_in must be a list'
assert len(h_in) in [1,2,3], 'h_in must be of dimension 1, 2, or 3'
h = range(len(h_in))
for i, h_i in enumerate(h_in):
if type(h_i) in [int, long, float]:
@@ -491,6 +492,49 @@ class TensorMesh(BaseRectangularMesh, TensorView, DiffOperators, InnerProducts):
indzu = (self.gridCC[:,2]==max(self.gridCC[:,2]))
return indxd, indxu, indyd, indyu, indzd, indzu
def _fastFaceInnerProduct(self, materialProperty=None, invertProperty=False):
"""
Fast version of getFaceInnerProduct.
This does not handle the case of a full tensor materialProperty.
:param numpy.array materialProperty: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6))
:param bool returnP: returns the projection matrices
:param bool invertProperty: inverts the material property
:rtype: scipy.csr_matrix
:return: M, the inner product matrix (nF, nF)
"""
if materialProperty is None:
materialProperty = np.ones(self.nC)
if materialProperty.size == self.nC:
if invertProperty:
materialProperty = 1./materialProperty
Av = self.aveF2CC
V = Utils.sdiag(self.vol)
return self.dim * Utils.sdiag(Av.T * V * materialProperty)
if materialProperty.size == self.nC*self.dim:
if invertProperty:
materialProperty = 1./materialProperty
Av = self.aveF2CCV
V = sp.kron(sp.identity(self.dim), Utils.sdiag(self.vol))
return Utils.sdiag(Av.T * V * Utils.mkvc(materialProperty))
def _fastFaceInnerProductDeriv(self, materialProperty=None):
"""
:param numpy.array materialProperty: material property (tensor properties are possible) at each cell center (nC, (1, 3, or 6))
:rtype: scipy.csr_matrix
:return: M, the inner product matrix (nF, nF)
"""
if materialProperty is None or materialProperty.size == self.nC:
Av = self.aveF2CC
return self.dim * Av.T * Utils.sdiag(self.vol)
if materialProperty.size == self.nC*self.dim: # anisotropic
Av = self.aveF2CCV
V = sp.kron(sp.identity(self.dim), Utils.sdiag(self.vol))
return Av.T * V
if __name__ == '__main__':
print('Welcome to tensor mesh!')
+1 -1
View File
@@ -30,7 +30,7 @@ class TestInnerProducts(OrderTest):
sigma = np.c_[call(sigma1, Gc)]
analytic = 647./360 # Found using sympy.
elif self.sigmaTest == 3:
sigma = np.c_[call(sigma1, Gc), call(sigma2, Gc), call(sigma3, Gc)]
sigma = np.r_[call(sigma1, Gc), call(sigma2, Gc), call(sigma3, Gc)]
analytic = 37./12 # Found using sympy.
elif self.sigmaTest == 6:
sigma = np.c_[call(sigma1, Gc), call(sigma2, Gc), call(sigma3, Gc),
+40
View File
@@ -0,0 +1,40 @@
import numpy as np
import unittest
from SimPEG import *
from TestUtils import checkDerivative
class TestInnerProductsDerivs(unittest.TestCase):
def setUp(self):
pass
def test_FaceIP_derivs_isotropic(self):
for d in range(3):
mesh = Mesh.TensorMesh([10,5,4][d:])
M,Ps = mesh.getFaceInnerProduct(returnP=True)
v = np.random.rand(mesh.nF)
def fun(sig):
M = mesh.getFaceInnerProduct(sig)
Md = mesh.getFaceInnerProductDeriv(sig)
return M*v, Utils.sdiag(v)*Md
sig = np.random.rand(mesh.nC)
passed = checkDerivative(fun, sig, plotIt=False)
self.assertTrue(passed)
def test_FaceIP_derivs_anisotropic(self):
for d in range(3):
mesh = Mesh.TensorMesh([10,5,4][d:])
M,Ps = mesh.getFaceInnerProduct(returnP=True)
v = np.random.rand(mesh.nF)
def fun(sig):
M = mesh.getFaceInnerProduct(sig)
Md = mesh.getFaceInnerProductDeriv(sig)
return M*v, Utils.sdiag(v)*Md
sig = np.random.rand(mesh.nC*mesh.dim)
passed = checkDerivative(fun, sig, plotIt=False)
self.assertTrue(passed)
if __name__ == '__main__':
unittest.main()