#69 Removed most solvers, replaced by wrappers.

This commit is contained in:
rowanc1
2014-05-16 18:33:57 -07:00
parent 1f0e37d773
commit f3170a8a7f
11 changed files with 92 additions and 670 deletions
+10 -9
View File
@@ -23,7 +23,7 @@ class LinearProblem(Problem.BaseProblem):
return self.G.T.dot(v)
def run(N):
def run(N, plotIt=True):
mesh = Mesh.TensorMesh([N])
nk = 20
@@ -59,13 +59,14 @@ def run(N):
mrec = inv.run(m0)
import matplotlib.pyplot as plt
plt.figure(1)
for i in range(prob.G.shape[0]):
plt.plot(prob.G[i,:])
if plotIt:
import matplotlib.pyplot as plt
plt.figure(1)
for i in range(prob.G.shape[0]):
plt.plot(prob.G[i,:])
plt.figure(2)
plt.plot(M.vectorCCx, survey.mtrue, 'b-')
plt.plot(M.vectorCCx, mrec, 'r-')
plt.figure(2)
plt.plot(M.vectorCCx, survey.mtrue, 'b-')
plt.plot(M.vectorCCx, mrec, 'r-')
return prob, survey, mesh
return prob, survey, mesh, mrec
+2 -2
View File
@@ -1,5 +1,5 @@
import Utils, numpy as np, scipy.sparse as sp
from Solver import Solver
from Solver import Solver, SolverCG
norm = np.linalg.norm
@@ -778,7 +778,7 @@ class InexactGaussNewton(BFGS, Minimize, Remember):
@Utils.timeIt
def findSearchDirection(self):
Hinv = Solver(self.H, doDirect=False, options={'iterSolver': 'CG', 'M': self.approxHinv, 'tol': self.tolCG, 'maxIter': self.maxIterCG})
Hinv = SolverCG(self.H, M=self.approxHinv, tol=self.tolCG, maxiter=self.maxIterCG)
p = Hinv.solve(-self.g)
return p
+4 -403
View File
@@ -1,405 +1,6 @@
import numpy as np
import scipy.sparse as sp
import scipy.sparse.linalg as linalg
from Utils import mkvc, sdiag
import warnings
from SimPEG.Utils import SolverUtils
DEFAULTS = {'direct':'scipy', 'iter':'scipy', 'triangular':'fortran', 'diagonal':'python'}
OPTIONS = {'direct':['scipy'], 'iter':['scipy'], 'triangular':['python'], 'diagonal':['python']}
HELP = []
try:
import Utils.TriSolve as TriSolve
OPTIONS['triangular'].append('fortran')
except Exception, e:
HELP += ['Warning: Python backend is being used for solver. Run setup.py from the command line.']
DEFAULTS['triangular'] = 'python'
try:
import mumps
OPTIONS['direct'].append('mumps')
except Exception, e:
HELP += ['Warning: mumps solver not available.']
class Solver(object):
"""
Solver is a light wrapper on the various types of
linear solvers available in python.
:param scipy.sparse A: Matrix
:param bool doDirect: if you want a direct solver
:param string flag: Matrix type flag for special solves: [None, 'L', 'U', 'D']
:param dict options: options which are passed to each sub solver, see each for details.
:rtype: Solver
:return: Solver
To use for direct solvers::
solve = Solver(A, doDirect=True, flag=None, options={'factorize':True,'backend':'scipy'})
x = solve.solve(rhs)
Or in one line::
x = Solver(A).solve(rhs)
The flag can be set to None, 'L', 'U', or 'D', for general, lower, upper, and diagonal matrices, respectively.
"""
def __init__(self, A, doDirect=True, flag=None, options={}):
assert type(doDirect) is bool, 'doDirect must be a boolean'
assert flag in [None, 'L', 'U', 'D'], "flag must be set to None, 'L', 'U', or 'D'"
assert type(options) is dict, 'options must be a dictionary object'
self.A = A
self.dsolve = None
self.doDirect = doDirect
self.flag = flag
self.options = options
if doDirect: return
# Now deal with iterative stuff only
if 'M' not in options:
warnings.warn("You should provide a preconditioner, M.", UserWarning)
return
M = options['M']
if isinstance(M, sp.linalg.LinearOperator):
return
PreconditionerList = ['J','GS']
if type(M) is str:
assert M in PreconditionerList, "M must be in the known preconditioner list. ['J','GS']"
M = (M,A) # use A as the base for the preconditioner.
if type(M) is tuple:
assert type(M[0]) is str and M[0] in PreconditionerList, "M as a tuple must be (str, Matrix) where str is in ['J','GS']: e.g. ('J', WtW) where J stands for Jacobi, and WtW is a sparse matrix."
if M[0] is 'J':
Jacobi = sdiag(1.0/M[1].diagonal())
options['M'] = Jacobi
elif M[0] is 'GS':
DD = sdiag(M[1].diagonal())
Uinv = Solver(M[1], flag='U')
Linv = Solver(M[1], flag='L')
def GS(f):
return Uinv.solve(DD*Linv.solve(f))
options['M'] = sp.linalg.LinearOperator( A.shape, GS, dtype=A.dtype )
else:
raise Exception('M must be a LinearOperator or a tuple')
def solve(self, b):
"""
Solves the linear system.
.. math::
Ax=b
:param numpy.ndarray b: the right hand side
:rtype: numpy.ndarray
:return: x
"""
if self.flag is None and self.doDirect:
return self.solveDirect(b, **self.options)
elif self.flag is None and not self.doDirect:
return self.solveIter(b, **self.options)
elif self.flag == 'U':
return self.solveBackward(b, **self.options)
elif self.flag == 'L':
return self.solveForward(b, **self.options)
elif self.flag == 'D':
return self.solveDiagonal(b, **self.options)
else:
raise Exception('Unknown flag.')
pass
def clean(self):
"""Cleans up the memory"""
if self.options.has_key('backend'):
if self.options['backend'] == 'mumps':
self.mctx.destroy()
del self.dsolve
self.dsolve = None
def solveDirect(self, b, factorize=False, backend=None):
"""
Use solve instead of this interface.
:param numpy.ndarray b: the right hand side
:param bool factorize: if you want to factorize and store factors
:param str backend: which backend to use. Default is scipy
:rtype: numpy.ndarray
:return: x
"""
if backend is None: backend = DEFAULTS['direct']
assert np.shape(self.A)[1] == np.shape(b)[0], 'Dimension mismatch'
if backend == 'scipy':
X = self.solveDirect_scipy(b, factorize)
elif backend == 'mumps':
X = self.solveDirect_mumps(b, factorize)
return X
def solveDirect_scipy(self, b, factorize):
"""
Use solve instead of this interface.
:param numpy.ndarray b: the right hand side
:param bool factorize: if you want to factorize and store factors
:rtype: numpy.ndarray
:return: x
"""
if factorize and self.dsolve is None:
self.A = self.A.tocsc() # for efficiency
self.dsolve = linalg.factorized(self.A)
if len(b.shape) == 1 or b.shape[1] == 1:
# Just one RHS
if factorize:
return self.dsolve(b.flatten())
else:
return linalg.dsolve.spsolve(self.A, b)
# Multiple RHSs
X = np.empty_like(b)
for i in range(b.shape[1]):
if factorize:
X[:,i] = self.dsolve(b[:,i])
else:
X[:,i] = linalg.dsolve.spsolve(self.A,b[:,i])
return X
def solveDirect_mumps(self, b, factorize):
"""
Use solve instead of this interface.
:param numpy.ndarray b: the right hand side
:param bool factorize: if you want to factorize and store factors
:rtype: numpy.ndarray
:return: x
"""
if factorize and self.dsolve is None:
self.mctx = mumps.DMumpsContext()
self.mctx.set_icntl(14, 60)
# self.mctx.set_silent()
self.mctx.set_centralized_sparse(self.A)
self.mctx.run(job=4)
def mdsolve(rhs):
x = rhs.copy()
self.mctx.set_rhs(x)
self.mctx.run(job=3)
return x
self.dsolve = mdsolve
if len(b.shape) == 1 or b.shape[1] == 1:
# Just one RHS
if factorize:
X = self.dsolve(b)
else:
X = mumps.spsolve(self.A, b)
else:
# Multiple RHSs
X = np.empty_like(b)
for i in range(b.shape[1]):
if factorize:
X[:,i] = self.dsolve(b[:,i])
else:
X[:,i] = mumps.spsolve(self.A,b[:,i])
return X
def solveIter(self, b, backend=None, M=None, iterSolver='CG', tol=1e-6, maxIter=50):
if backend is None: backend = DEFAULTS['iter']
algorithms = {'CG':sp.linalg.cg, 'QMR':sp.linalg.qmr}
assert iterSolver in algorithms, "iterSolver must be 'CG', or implement it yourself and add it here!"
alg = algorithms[iterSolver]
if iterSolver == 'CG':
opts = {'M':M}
elif iterSolver == 'QMR':
#TODO: make preconditioner better.
opts = {'M1':np.sqrt(M), 'M2':np.sqrt(M)}
if len(b.shape) == 1 or b.shape[1] == 1:
x, self.info = alg(self.A, b, tol=tol, maxiter=maxIter)
else:
x = np.empty_like(b)
for i in range(b.shape[1]):
x[:,i], self.info = alg(self.A, b[:,i], M=M, tol=tol, maxiter=maxIter)
return x
def solveBackward(self, b, backend=None):
"""
Use solve instead of this interface.
Perform a backwards solve with upper triangular A in CSR format (best, if not, it will be converted).
:param str backend: which backend to use. Default is python.
:rtype: numpy.ndarray
:return: x
"""
if backend is None: backend = DEFAULTS['triangular']
if backend not in OPTIONS['triangular']:
print 'Warning: %s-backend not being used, %s-default will be used instead.'%(backend,DEFAULTS['triangular'])
backend = DEFAULTS['triangular']
if type(self.A) is not sp.csr.csr_matrix:
self.A = sp.csr_matrix(self.A)
vals = self.A.data
rowptr = self.A.indptr
colind = self.A.indices
if backend == 'fortran':
if len(b.shape) == 1 or b.shape[1] == 1:
x = TriSolve.backward(vals, rowptr, colind, b, self.A.data.size, b.size, 1)
x = mkvc(x)
else:
x = TriSolve.backward(vals, rowptr, colind, b, self.A.data.size, b.shape[0], b.shape[1])
elif backend == 'python':
x = np.empty_like(b) # empty() is faster than zeros().
for i in reversed(xrange(self.A.shape[0])):
ith_row = vals[rowptr[i] : rowptr[i+1]]
cols = colind[rowptr[i] : rowptr[i+1]]
x_vals = x[cols]
x[i] = (b[i] - np.dot(ith_row[1:], x_vals[1:])) / ith_row[0]
return x
def solveForward(self, b, backend=None):
"""
Use solve instead of this interface.
Perform a forward solve with lower triangular A in CSR format (best, if not, it will be converted).
:param str backend: which backend to use. Default is python.
:rtype: numpy.ndarray
:return: x
"""
if backend is None: backend = DEFAULTS['triangular']
if backend not in OPTIONS['triangular']:
print 'Warning: %s-backend not being used, %s-default will be used instead.'%(backend,DEFAULTS['triangular'])
backend = DEFAULTS['triangular']
if type(self.A) is not sp.csr.csr_matrix:
from scipy.sparse import csr_matrix
self.A = csr_matrix(self.A)
vals = self.A.data
rowptr = self.A.indptr
colind = self.A.indices
if backend == 'fortran':
if len(b.shape) == 1 or b.shape[1] == 1:
x = TriSolve.forward(vals, rowptr, colind, b, self.A.data.size, b.size, 1)
x = mkvc(x)
else:
x = TriSolve.forward(vals, rowptr, colind, b, self.A.data.size, b.shape[0], b.shape[1])
elif backend == 'python':
x = np.empty_like(b) # empty() is faster than zeros().
for i in xrange(self.A.shape[0]):
ith_row = vals[rowptr[i] : rowptr[i+1]]
cols = colind[rowptr[i] : rowptr[i+1]]
x_vals = x[cols]
x[i] = (b[i] - np.dot(ith_row[:-1], x_vals[:-1])) / ith_row[-1]
return x
def solveDiagonal(self, b, backend=None):
"""
Use solve instead of this interface.
Perform a diagonal solve with diagonal matrix A.
:param str backend: which backend to use. Default is python.
:rtype: numpy.ndarray
:return: x
"""
if backend is None: backend = DEFAULTS['diagonal']
diagA = self.A.diagonal()
if len(b.shape) == 1 or b.shape[1] == 1:
# Just one RHS
return b/diagA
# Multiple RHSs
X = np.empty_like(b)
for i in range(b.shape[1]):
X[:,i] = b[:,i]/diagA
return X
if __name__ == '__main__':
from SimPEG.Mesh import TensorMesh
from time import time
h1 = np.ones(20)*100.
h2 = np.ones(20)*100.
h3 = np.ones(20)*100.
h = [h1,h2,h3]
M = TensorMesh(h)
D = M.faceDiv
G = M.cellGrad
Msig = M.getFaceInnerProduct()
A = D*Msig*G
A[0,0] *= 10 # remove the constant null space from the matrix
e = np.ones(M.nC)
rhs = A.dot(e)
tic = time()
solve = Solver(A, options={'factorize':True})
x = solve.solve(rhs)
print 'Factorized', time() - tic
print np.linalg.norm(e-x,np.inf)
tic = time()
solve = Solver(A, options={'factorize':False})
x = solve.solve(rhs)
print 'spsolve', time() - tic
print np.linalg.norm(e-x,np.inf)
n = 600
A_dense = np.random.random((n,n))
L = np.tril(np.dot(A_dense, A_dense)) # Positive definite is better conditioned.
e = np.ones(n)
b = np.dot(L, e)
A = sp.csr_matrix(L)
pSolve = Solver(A,flag='L',options={'backend':'python'});
fSolve = Solver(A,flag='L',options={'backend':'fortran'})
tic = time()
x = pSolve.solve(b)
toc = time() - tic
print 'Error Forward Python = ', np.linalg.norm(x-e, np.inf), 'Time: ', toc
tic = time()
x = fSolve.solve(b)
toc = time() - tic
print 'Error Forward Fortran = ', np.linalg.norm(x-e, np.inf), 'Time: ', toc
A = -D*D.T
A[0,0] *= 10 # remove the constant null space from the matrix
e = np.ones(M.nC)
b = A.dot(e)
iSolve = Solver(A, doDirect=False,options={'M':('GS',A)})
tic = time()
x = iSolve.solve(b)
toc = time() - tic
print x
print 'Error CG = ', np.linalg.norm(x-e, np.inf), 'Time: ', toc, 'Info: ', iSolve.info
A = -D*D.T
A[0,0] *= 10 # remove the constant null space from the matrix
e = np.ones(M.nC)
b = A.dot(e)
iSolve = Solver(A, doDirect=False, options={'iterSolver': 'QMR', 'M':'J'})
tic = time()
x = iSolve.solve(b)
toc = time() - tic
print x
print 'Error QMR = ', np.linalg.norm(x-e, np.inf), 'Time: ', toc, 'Info: ', iSolve.info
Solver = SolverUtils.DSolverWrap(sp.linalg.spsolve, factorize=False)
SolverLU = SolverUtils.DSolverWrap(sp.linalg.splu, factorize=True)
SolverCG = SolverUtils.ISolverWrap(sp.linalg.cg)
-28
View File
@@ -1,28 +0,0 @@
from mumps import DMumpsContext
class MumpsSolver():
A = None
ctx = None
x = None
def __init__(self, A, **kwagrs):
self.ctx = DMumpsContext(sym=0, par=1)
if self.ctx.myid ==0:
self.A = A
self.ctx.set_icntl(14, 60)
self.ctx.set_centralized_sparse(A)
self.ctx.set_silent()
self.ctx.run(job=4) # Factorization
def solve(self,b):
self.x = b.copy()
self.ctx.set_rhs(self.x)
self.ctx.run(job=3) # Solve
return self.x
def clean(self):
self.ctx.destroy()
-4
View File
@@ -1,4 +0,0 @@
try:
from Mumps import MumpsSolver
except Exception, e:
pass
+31 -126
View File
@@ -1,5 +1,5 @@
import unittest
from SimPEG import Solver
from SimPEG import *
from SimPEG.Mesh import TensorMesh
from SimPEG.Utils import sdiag
import numpy as np
@@ -8,136 +8,41 @@ import scipy.sparse as sparse
TOL = 1e-10
numRHS = 5
def dotest(solver, multi=False, **solverOpts):
h1 = np.ones(10)*100.
h2 = np.ones(10)*100.
h3 = np.ones(10)*100.
h = [h1,h2,h3]
M = TensorMesh(h)
D = M.faceDiv
G = -M.faceDiv.T
Msig = M.getFaceInnerProduct()
A = D*Msig*G
A[0,0] *= 10 # remove the constant null space from the matrix
Ainv = Solver(A, **solverOpts)
if multi:
e = np.ones(M.nC)
else:
e = np.ones((M.nC, numRHS))
rhs = A * e
x = Ainv * rhs
return np.linalg.norm(e-x,np.inf) < TOL
class TestSolver(unittest.TestCase):
def setUp(self):
h1 = np.ones(10)*100.
h2 = np.ones(10)*100.
h3 = np.ones(10)*100.
def test_direct_spsolve_1(self): self.assertTrue(dotest(Solver, False))
def test_direct_spsolve_M(self): self.assertTrue(dotest(Solver, True))
h = [h1,h2,h3]
def test_direct_splu_1(self): self.assertTrue(dotest(SolverLU, False))
def test_direct_splu_M(self): self.assertTrue(dotest(SolverLU, True))
M = TensorMesh(h)
D = M.faceDiv
G = M.cellGrad
Msig = M.getFaceInnerProduct()
A = D*Msig*G
A[0,0] *= 10 # remove the constant null space from the matrix
self.A = A
self.M = M
def test_directFactored_1(self):
solve = Solver(self.A, doDirect=True, flag=None, options={'factorize':True,'backend':'scipy'})
e = np.ones(self.M.nC)
rhs = self.A.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directFactored_M(self):
solve = Solver(self.A, doDirect=True, flag=None, options={'factorize':True,'backend':'scipy'})
e = np.ones((self.M.nC,numRHS))
rhs = self.A.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directSpsolve_1(self):
solve = Solver(self.A, doDirect=True, flag=None, options={'factorize':False,'backend':'scipy'})
e = np.ones(self.M.nC)
rhs = self.A.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directSpsolve_M(self):
solve = Solver(self.A, doDirect=True, flag=None, options={'factorize':False,'backend':'scipy'})
e = np.ones((self.M.nC, numRHS))
rhs = self.A.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directLower_1_python(self):
AL = sparse.tril(self.A)
solve = Solver(AL, doDirect=True, flag='L', options={'backend':'python'})
e = np.ones(self.M.nC)
rhs = AL.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directLower_M_python(self):
AL = sparse.tril(self.A)
solve = Solver(AL, doDirect=True, flag='L', options={'backend':'python'})
e = np.ones((self.M.nC,numRHS))
rhs = AL.dot(e)
x = solve.solve(rhs)
def test_directLower_1_fortran(self):
AL = sparse.tril(self.A)
solve = Solver(AL, doDirect=True, flag='L', options={'backend':'fortran'})
e = np.ones(self.M.nC)
rhs = AL.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directLower_M_fortran(self):
AL = sparse.tril(self.A)
solve = Solver(AL, doDirect=True, flag='L', options={'backend':'fortran'})
e = np.ones((self.M.nC,numRHS))
rhs = AL.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directUpper_1_python(self):
AU = sparse.triu(self.A)
solve = Solver(AU, doDirect=True, flag='U', options={})
e = np.ones(self.M.nC)
rhs = AU.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directUpper_M_python(self):
AU = sparse.triu(self.A)
solve = Solver(AU, doDirect=True, flag='U', options={})
e = np.ones((self.M.nC,numRHS))
rhs = AU.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directUpper_1_fortran(self):
AU = sparse.triu(self.A)
solve = Solver(AU, doDirect=True, flag='U', options={'backend':'fortran'})
e = np.ones(self.M.nC)
rhs = AU.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directUpper_M_fortran(self):
AU = sparse.triu(self.A)
solve = Solver(AU, doDirect=True, flag='U', options={'backend':'fortran'})
e = np.ones((self.M.nC,numRHS))
rhs = AU.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directDiagonal_1(self):
AD = sdiag(self.A.diagonal())
solve = Solver(AD, doDirect=True, flag='D', options={})
e = np.ones(self.M.nC)
rhs = AD.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_directDiagonal_M(self):
AD = sdiag(self.A.diagonal())
solve = Solver(AD, doDirect=True, flag='D', options={})
e = np.ones((self.M.nC,numRHS))
rhs = AD.dot(e)
x = solve.solve(rhs)
self.assertTrue(np.linalg.norm(e-x,np.inf) < TOL, True)
def test_iterative_cg_1(self): self.assertTrue(dotest(SolverLU, False))
def test_iterative_cg_M(self): self.assertTrue(dotest(SolverLU, True))
if __name__ == '__main__':
+14 -14
View File
@@ -3,7 +3,7 @@ import scipy.sparse as sp
import unittest
from TestUtils import OrderTest
import matplotlib.pyplot as plt
from SimPEG import Utils, Solver
from SimPEG import *
MESHTYPES = ['uniformTensorMesh']
@@ -54,7 +54,7 @@ class Test1D_InhomogeneousDirichlet(OrderTest):
err = np.linalg.norm((q-V*q_anal), np.inf)
elif self.myTest == 'xc':
#TODO: fix the null space
solver = Solver(A, doDirect=False, options={'M':'J','iterSolver':'CG','backend':'scipy','maxIter':1000})
solver = SolverCG(A, maxiter=1000)
xc = solver.solve(rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
err = np.linalg.norm((xc-xc_anal), np.inf)
@@ -220,7 +220,7 @@ class Test1D_InhomogeneousNeumann(OrderTest):
err = np.linalg.norm((xc-xc_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
elif self.myTest == 'xcJ':
#TODO: fix the null space
xc, info = sp.linalg.minres(A, rhs, tol = 1e-6)
@@ -228,7 +228,7 @@ class Test1D_InhomogeneousNeumann(OrderTest):
err = np.linalg.norm((Pin*j-Pin*j_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
return err
def test_orderJ(self):
@@ -268,12 +268,12 @@ class Test2D_InhomogeneousNeumann(OrderTest):
j_anal = np.r_[jX_anal,jY_anal]
#TODO: Check where our boundary conditions are CCx or Nx
cxm,cxp,cym,cyp = self.M.cellBoundaryInd
fxm,fxp,fym,fyp = self.M.faceBoundaryInd
gBFx = self.M.gridFx[(fxm|fxp),:]
gBFy = self.M.gridFy[(fym|fyp),:]
gBFy = self.M.gridFy[(fym|fyp),:]
gBCx = self.M.gridCC[(cxm|cxp),:]
gBCy = self.M.gridCC[(cym|cyp),:]
@@ -307,7 +307,7 @@ class Test2D_InhomogeneousNeumann(OrderTest):
err = np.linalg.norm((xc-xc_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
elif self.myTest == 'xcJ':
#TODO: fix the null space
xc, info = sp.linalg.minres(A, rhs, tol = 1e-6)
@@ -315,7 +315,7 @@ class Test2D_InhomogeneousNeumann(OrderTest):
err = np.linalg.norm((Pin*j-Pin*j_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
return err
def test_orderJ(self):
@@ -384,7 +384,7 @@ class Test1D_InhomogeneousMixed(OrderTest):
err = np.linalg.norm((xc-xc_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
elif self.myTest == 'xcJ':
#TODO: fix the null space
xc, info = sp.linalg.minres(A, rhs, tol = 1e-6)
@@ -392,7 +392,7 @@ class Test1D_InhomogeneousMixed(OrderTest):
err = np.linalg.norm((Pin*j-Pin*j_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
return err
def test_orderJ(self):
@@ -432,12 +432,12 @@ class Test2D_InhomogeneousMixed(OrderTest):
j_anal = np.r_[jX_anal,jY_anal]
#TODO: Check where our boundary conditions are CCx or Nx
cxm,cxp,cym,cyp = self.M.cellBoundaryInd
fxm,fxp,fym,fyp = self.M.faceBoundaryInd
gBFx = self.M.gridFx[(fxm|fxp),:]
gBFy = self.M.gridFy[(fym|fyp),:]
gBFy = self.M.gridFy[(fym|fyp),:]
gBCx = self.M.gridCC[(cxm|cxp),:]
gBCy = self.M.gridCC[(cym|cyp),:]
@@ -471,7 +471,7 @@ class Test2D_InhomogeneousMixed(OrderTest):
err = np.linalg.norm((xc-xc_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
elif self.myTest == 'xcJ':
#TODO: fix the null space
xc, info = sp.linalg.minres(A, rhs, tol = 1e-6)
@@ -479,7 +479,7 @@ class Test2D_InhomogeneousMixed(OrderTest):
err = np.linalg.norm((Pin*j-Pin*j_anal), np.inf)
if info > 0:
print 'Solve does not work well'
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
print 'ACCURACY', np.linalg.norm(Utils.mkvc(A*xc) - rhs)
return err
def test_orderJ(self):
+1 -1
View File
@@ -6,7 +6,7 @@ import numpy as np
class TestLinear(unittest.TestCase):
def test_running(self):
Linear.run(100)
Linear.run(100, plotIt=False)
self.assertTrue(True)
if __name__ == '__main__':
+29 -18
View File
@@ -2,10 +2,20 @@ import numpy as np
from matutils import mkvc
import warnings
def DSolverWrap(fun, factorize=True, destroy = False, checkAccuracy=True, accuracyTol=1e-6):
def _checkAccuracy(A, b, X, accuracyTol):
nrm = np.linalg.norm(mkvc(A*X - b), np.inf)
nrm_b = np.linalg.norm(mkvc(b), np.inf)
if nrm_b > 0:
nrm /= nrm_b
if nrm > accuracyTol:
msg = '### SolverWarning ###: Accuracy on solve is above tolerance: %e > %e' % (nrm, accuracyTol)
print msg
warnings.warn(msg, RuntimeWarning)
def DSolverWrap(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6):
def __init__(self, A, **kwargs):
self.A = A.tocsc()
self.kwargs = kwargs
if factorize:
@@ -28,27 +38,27 @@ def DSolverWrap(fun, factorize=True, destroy = False, checkAccuracy=True, accura
X[:,i] = fun(self.A, b[:,i], **self.kwargs)
if checkAccuracy:
nrm = np.linalg.norm(mkvc(self.A*X - b)) / np.linalg.norm(mkvc(b))
if nrm > accuracyTol:
msg = '### SolverWarning ###: Accuracy on solve is above tolerance: %e > %e' % (nrm, accuracyTol)
print msg
warnings.warn(msg, RuntimeWarning)
_checkAccuracy(self.A, b, X, accuracyTol)
return X
def clean(self):
if destroy == True:
if hasattr(self.solver, 'clean'):
return self.solver.clean()
else:
return True
return type(fun.__name__, (object,), {"__init__": __init__, "solve": solve, "clean": clean})
def __mul__(self, val):
if type(val) is np.ndarray:
return self.solve(val)
raise TypeError('Can only multiply by a numpy array.')
return type(fun.__name__, (object,), {"__init__": __init__, "solve": solve, "clean": clean, "__mul__": __mul__})
def ISolverWrap(fun, checkAccuracy=True, accuracyTol=1e-5):
def __init__(self, A, **kwargs):
self.A = A.tocsc()
self.A = A
self.kwargs = kwargs
def solve(self, b):
@@ -74,11 +84,12 @@ def ISolverWrap(fun, checkAccuracy=True, accuracyTol=1e-5):
X[:,i] = out
if checkAccuracy:
nrm = np.linalg.norm(mkvc(self.A*X - b)) / np.linalg.norm(mkvc(b))
if nrm > accuracyTol:
msg = '### SolverWarning ###: Accuracy on solve is above tolerance: %e > %e' % (nrm, accuracyTol)
print msg
warnings.warn(msg, RuntimeWarning)
_checkAccuracy(self.A, b, X, accuracyTol)
return X
return type(fun.__name__, (object,), {"__init__": __init__, "solve": solve})
def __mul__(self, val):
if type(val) is np.ndarray:
return self.solve(val)
raise TypeError('Can only multiply by a numpy array.')
return type(fun.__name__, (object,), {"__init__": __init__, "solve": solve, "__mul__": __mul__})
-64
View File
@@ -1,64 +0,0 @@
c File TriSolve.f
subroutine forward(al, ial, jal, b, nv, n, nRHS, x)
double precision al(nv)
integer ial(n+1)
integer jal(nv)
double precision b(n,nRHS)
double precision x(n,nRHS)
integer nv
integer n
integer nRHS
integer rhs
cf2py intent(in) :: al
cf2py intent(in) :: ial
cf2py intent(in) :: jal
cf2py intent(in) :: b
cf2py intent(in) :: nv
cf2py intent(in) :: n
cf2py intent(in) :: nRHS
cf2py intent(out) :: x
real ( kind = 8 ) t
do rhs = 1, nRHS
do k = 1, n
t = b(k,rhs)
do j = ial(k)+1, ial(k+1)
t = t - al(j) * x(jal(j)+1,rhs)
end do
x(k,rhs) = t/al(ial(k+1))
end do
end do
end subroutine forward
subroutine backward(au,iau, jau, b, nv, n, nRHS, x)
double precision au(nv)
integer iau(n+1)
integer jau(nv)
double precision b(n,nRHS)
double precision x(n,nRHS)
integer nv
integer n
integer nRHS
integer rhs
cf2py intent(in) :: au
cf2py intent(in) :: iau
cf2py intent(in) :: jau
cf2py intent(in) :: b
cf2py intent(in) :: nv
cf2py intent(in) :: n
cf2py intent(in) :: nRHS
cf2py intent(out) :: x
real ( kind = 8 ) t
do rhs = 1, nRHS
do k = n, 1, -1
t = b(k,rhs)
do j = iau(k)+1, iau(k+1)
t = t - au(j) * x(jau(j)+1,rhs)
end do
x(k,rhs) = t/au(iau(k)+1)
end do
end do
end subroutine backward
+1 -1
View File
@@ -1,7 +1,7 @@
import numpy as np
import scipy.sparse as sp
import Utils
from Solver import Solver
from Solver import *
import Mesh
import Maps
import Problem