Source code for openmdao.solvers.nl_gauss_seidel

""" Gauss Seidel non-linear solver."""

from math import isnan

import numpy as np

from openmdao.core.system import AnalysisError
from openmdao.solvers.solver_base import error_wrap_nl, NonLinearSolver
from openmdao.util.record_util import update_local_meta, create_local_meta


[docs]class NLGaussSeidel(NonLinearSolver): """ Nonlinear Gauss Seidel solver. This is the default solver for a `Group`. If there are no cycles, then the system will solve its subsystems once and terminate. Equivalent to fixed point iteration in cases with cycles. Options ------- options['atol'] : float(1e-06) Absolute convergence tolerance. options['err_on_maxiter'] : bool(False) If True, raise an AnalysisError if not converged at maxiter. options['iprint'] : int(0) Set to 0 to print only failures, set to 1 to print iteration totals to stdout, set to 2 to print the residual each iteration to stdout, or -1 to suppress all printing. options['maxiter'] : int(100) Maximum number of iterations. options['rtol'] : float(1e-06) Relative convergence tolerance. options['utol'] : float(1e-12) Convergence tolerance on the change in the unknowns. """ def __init__(self): super(NLGaussSeidel, self).__init__() opt = self.options opt.add_option('atol', 1e-6, lower=0.0, desc='Absolute convergence tolerance.') opt.add_option('rtol', 1e-6, lower=0.0, desc='Relative convergence tolerance.') opt.add_option('utol', 1e-12, lower=0.0, desc='Convergence tolerance on the change in the unknowns.') opt.add_option('maxiter', 100, lower=0, desc='Maximum number of iterations.') self.print_name = 'NLN_GS'
[docs] def setup(self, sub): """ Initialize this solver. Args ---- sub: `System` System that owns this solver. """ if sub.is_active(): self.unknowns_cache = np.empty(sub.unknowns.vec.shape)
@error_wrap_nl
[docs] def solve(self, params, unknowns, resids, system, metadata=None): """ Solves the system using Gauss Seidel. 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). """ atol = self.options['atol'] rtol = self.options['rtol'] utol = self.options['utol'] maxiter = self.options['maxiter'] iprint = self.options['iprint'] unknowns_cache = self.unknowns_cache # Initial run self.iter_count = 1 # Metadata setup local_meta = create_local_meta(metadata, system.pathname) system.ln_solver.local_meta = local_meta update_local_meta(local_meta, (self.iter_count,)) # Initial Solve system.children_solve_nonlinear(local_meta) self.recorders.record_iteration(system, local_meta) # Bail early if the user wants to. if maxiter == 1: return resids = system.resids unknowns_cache = np.zeros(unknowns.vec.shape) # Evaluate Norm system.apply_nonlinear(params, unknowns, resids) normval = resids.norm() basenorm = normval if normval > atol else 1.0 u_norm = 1.0e99 if iprint == 2: self.print_norm(self.print_name, system, 1, normval, basenorm) while self.iter_count < maxiter and \ normval > atol and \ normval/basenorm > rtol and \ u_norm > utol: # Metadata update self.iter_count += 1 update_local_meta(local_meta, (self.iter_count,)) unknowns_cache[:] = unknowns.vec # Runs an iteration system.children_solve_nonlinear(local_meta) self.recorders.record_iteration(system, local_meta) # Evaluate Norm system.apply_nonlinear(params, unknowns, resids) normval = resids.norm() u_norm = np.linalg.norm(unknowns.vec - unknowns_cache) if iprint == 2: self.print_norm(self.print_name, system, self.iter_count, normval, basenorm, u_norm=u_norm) # Final residual print if you only want the last one if iprint == 1: self.print_norm(self.print_name, system, self.iter_count, normval, basenorm, u_norm=u_norm) if self.iter_count >= maxiter or isnan(normval): msg = 'FAILED to converge after %d iterations' % self.iter_count fail = True else: fail = False if iprint > 0 or (fail and iprint > -1 ): if not fail: msg = 'Converged in %d iterations' % self.iter_count self.print_norm(self.print_name, system, self.iter_count, normval, basenorm, msg=msg) if fail and self.options['err_on_maxiter']: raise AnalysisError("Solve in '%s': NLGaussSeidel %s" % (system.pathname, msg))