Setting Nonlinear and Linear Solvers

A nonlinear solver, like NonlinearBlockGS or Newton, is used to converge the nonlinear analysis. A nonlinear solver is needed whenever there is a cyclic dependency between components in your model. It might also be needed if you have an ImplicitComponent in your model that expects the framework to handle its convergence.

Whenever you use a nonlinear solver on a Group or Component, if you’re going to be working with analytic derivatives, you will also need a linear solver. A linear solver, like LinearBlockGS or DirectSolver, is used to solve the linear system that provides total derivatives across the model.

You can add nonlinear and linear solvers at any level of the model hierarchy, letting you build a hierarchical solver setup to efficiently converge your model and solve for total derivatives across it.

Solvers for the Sellar Problem

The Sellar Problem has two components with a cyclic dependency, so the appropriate nonlinear solver is necessary. We’ll use the Newton nonlinear solver, which requires derivatives, so we’ll also use the DirectSolver linear solver.

import openmdao.api as om
from openmdao.test_suite.components.sellar import SellarDerivatives

prob = om.Problem()
model = prob.model = SellarDerivatives()

model.nonlinear_solver = newton = om.NewtonSolver(solve_subsystems=False)

# using a different linear solver for Newton with a looser tolerance
newton.linear_solver = om.ScipyKrylov(atol=1e-4)

# used for analytic derivatives
model.linear_solver = om.DirectSolver()

prob.setup()
prob.run_model()

print(prob.get_val('y1'))
print(prob.get_val('y2'))
NL: NLBGS Converged in 8 iterations
[25.58830237]
[12.05848815]

Some models have more complex coupling. There could be top-level cycles between groups as well as lower-level groups that have cycles of their own. openmdao.test_suite.components.double_sellar.DoubleSellar is a simple example of this kind of model structure. In these problems, you might want to specify a more complex hierarchical solver structure for both nonlinear and linear solvers.

from openmdao.test_suite.components.double_sellar import DoubleSellar

prob = om.Problem()
model = prob.model = DoubleSellar()

# each SubSellar group converges itself
g1 = model.g1
g1.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
g1.linear_solver = om.DirectSolver()  # used for derivatives

g2 = model.g2
g2.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
g2.linear_solver = om.DirectSolver()

# Converge the outer loop with Gauss Seidel, with a looser tolerance.
model.nonlinear_solver = om.NonlinearBlockGS(rtol=1.0e-5)
model.linear_solver = om.ScipyKrylov()
model.linear_solver.precon = om.LinearBlockGS()

prob.setup()
prob.run_model()

print(prob.get_val('g1.y1'))
print(prob.get_val('g1.y2'))
print(prob.get_val('g2.y1'))
print(prob.get_val('g2.y2'))
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 3 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 3 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 3 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 3 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 3 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 2 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 1 iterations
|  
|  ==
|  g1
|  ==
|  NL: Newton Converged in 1 iterations
|  
|  ==
|  g2
|  ==
|  NL: Newton Converged in 1 iterations
NL: NLBGSSolver 'NL: NLBGS' on system '' failed to converge in 10 iterations.
[0.64000398]
[0.80000249]
[0.64000221]
[0.80000138]