Source code for openmdao.solvers.solverbase

""" Base class for linear and nonlinear solvers."""

from __future__ import print_function

from openmdao.core.options import OptionsDictionary


[docs]class SolverBase(object): """ Common base class for Linear and Nonlinear solver. Should not be used by users. Always inherit from `LinearSolver` or `NonlinearSolver`.""" def __init__(self): self.iter_count = 0 self.options = OptionsDictionary() desc = 'Set to 0 to disable printing, set to 1 to print the ' \ 'residual to stdout each iteration, set to 2 to print ' \ 'subiteration residuals as well.' self.options.add_option('iprint', 0, values=[0, 1, 2], desc=desc) self.recorders = [] self.local_meta = None
[docs] def print_norm(self, solver_string, metadata, iteration, res, res0, msg=None, indent=0, solver='NL'): """ Prints out the norm of the residual in a neat readable format. Args ---- solver_string: string Unique string to identify your solver type (e.g., 'LN_GS' or 'NEWTON'). metadata: dict OpenMDAO execution metadata containing iteration info. iteration: int Current iteration number res: float Absolute residual value. res0: float Baseline initial residual for relative comparison. msg: string, optional Message that indicates convergence. ident: int, optional Additional indentation levels for subiterations. solver: string, optional Solver type if not LN or NL (mostly for line search operations.) """ name = metadata['name'] # Find indentation level level = sum(len(item) for item in metadata['coord'] if not isinstance(item, str)) # No indentation for driver; top solver is no indentation. level = level + indent - 2 indent = ' ' * level if msg is not None: form = indent + '[%s] %s: %s %d | %s' print(form % (name, solver, solver_string, iteration, msg)) return form = indent + '[%s] %s: %s %d | %.9g %.9g' print(form % (name, solver, solver_string, iteration, res, res/res0))
[docs]class LinearSolver(SolverBase): """ Base class for all linear solvers. Inherit from this class to create a new custom linear solver."""
[docs] def add_recorder(self, recorder): """Appends the given recorder to this solver's list of recorders. Args ---- recorder: `BaseRecorder` A recorder object. """ self.recorders.append(recorder)
[docs] def solve(self, rhs, system, mode): """ Solves the linear system for the problem in self.system. The full solution vector is returned. This function must be defined when inheriting. Args ---- rhs : ndarray Array containing the right-hand side for the linear solve. Also possibly a 2D array with multiple right-hand sides. system : `System` Parent `System` object. mode : string Derivative mode, can be 'fwd' or 'rev'. Returns ------- ndarray : Solution vector """ pass
[docs]class NonLinearSolver(SolverBase): """ Base class for all nonlinear solvers. Inherit from this class to create a new custom nonlinear solver."""
[docs] def add_recorder(self, recorder): """Appends the given recorder to this solver's list of recorders. Args ---- recorder: `BaseRecorder` A recorder object. """ self.recorders.append(recorder)
[docs] def solve(self, params, unknowns, resids, system, metadata=None): """ Drive all residuals in self.system and all subsystems to zero. This includes all implicit components. This function must be defined when inheriting. Args ---- params : `VecWrapper` `VecWrapper` containing parameters. (p) unknowns : `VecWrapper` `VecWrapper` containing outputs and states. (u) resids : `VecWrapper` `VecWrapper` containing residuals. (r) system : `System` Parent `System` object. metadata : dict, optional Dictionary containing execution metadata (e.g. iteration coordinate). """ pass