Source code for openmdao.solvers.scipy_gmres
""" OpenMDAO LinearSolver that uses Scipy's GMRES to solve for derivatives."""
from __future__ import print_function
from six import iteritems
from scipy.sparse.linalg import gmres, LinearOperator
from openmdao.solvers.solver_base import LinearSolver
[docs]class ScipyGMRES(LinearSolver):
""" Scipy's GMRES Solver. This is a serial solver, so
it should never be used in an MPI setting.
"""
def __init__(self):
super(ScipyGMRES, self).__init__()
opt = self.options
opt.add_option('atol', 1e-12,
desc='Absolute convergence tolerance.')
opt.add_option('maxiter', 100,
desc='Maximum number of iterations.')
opt.add_option('mode', 'fwd', values=['fwd', 'rev', 'auto'],
desc="Derivative calculation mode, set to 'fwd' for " + \
"forward mode, 'rev' for reverse mode, or 'auto' to " + \
"let OpenMDAO determine the best mode.")
# These are defined whenever we call solve to provide info we need in
# the callback.
self.system = None
self.voi = None
self.mode = None
[docs] def solve(self, rhs_mat, system, mode):
""" Solves the linear system for the problem in self.system. The
full solution vector is returned.
Args
----
rhs_mat : dict of ndarray
Dictionary containing one ndarry per top level quantity of
interest. Each array contains the right-hand side for the linear
solve.
system : `System`
Parent `System` object.
mode : string
Derivative mode, can be 'fwd' or 'rev'.
Returns
-------
dict of ndarray : Solution vectors
"""
unknowns_mat = {}
for voi, rhs in iteritems(rhs_mat):
# Scipy can only handle one right-hand-side at a time.
self.voi = voi
n_edge = len(rhs)
A = LinearOperator((n_edge, n_edge),
matvec=self.mult,
dtype=float)
self.system = system
options = self.options
self.mode = mode
# Call GMRES to solve the linear system
d_unknowns, info = gmres(A, rhs,
tol=options['atol'],
maxiter=options['maxiter'])
if info > 0:
msg = "ERROR in solve in '{}': gmres failed to converge " \
"after {} iterations"
print(msg.format(system.name, options['maxiter']))
#logger.error(msg, system.name, info)
elif info < 0:
msg = "ERROR in solve in '{}': gmres failed"
print(msg.format(system.name))
#logger.error(msg, system.name)
unknowns_mat[voi] = d_unknowns
#print system.name, 'Linear solution vec', d_unknowns
self.system = None
return unknowns_mat
[docs] def mult(self, arg):
""" GMRES Callback: applies Jacobian matrix. Mode is determined by the
system.
Args
----
arg : ndarray
Incoming vector
Returns
-------
ndarray : Matrix vector product of arg with jacobian
"""
system = self.system
mode = self.mode
voi = self.voi
if mode == 'fwd':
sol_vec, rhs_vec = system.dumat[voi], system.drmat[voi]
else:
sol_vec, rhs_vec = system.drmat[voi], system.dumat[voi]
# Set incoming vector
sol_vec.vec[:] = arg[:]
# Start with a clean slate
rhs_vec.vec[:] = 0.0
system.clear_dparams()
system.apply_linear(mode, ls_inputs=self.system._ls_inputs, vois=[voi])
#debug("arg", arg)
#debug("result", rhs_vec.vec)
return rhs_vec.vec[:]