Solver Recording
Contents
Solver Recording¶
Solver recording is useful when you want to record the iterations within a solver. The recorder can capture the values of states, errors, and residuals as the solver converges.
Option | Default | Acceptable Values | Acceptable Types | Description |
---|---|---|---|---|
excludes | [] | N/A | ['list'] | Patterns for vars to exclude in recording. (processed post-includes) Paths are relative to solver's Group. Uses fnmatch wildcards |
includes | ['*'] | N/A | ['list'] | Patterns for variables to include in recording. Paths are relative to solver's Group. Uses fnmatch wildcards |
record_abs_error | True | [True, False] | ['bool'] | Set to True to record absolute error at the solver level |
record_inputs | True | [True, False] | ['bool'] | Set to True to record inputs at the solver level |
record_outputs | True | [True, False] | ['bool'] | Set to True to record outputs at the solver level |
record_rel_error | True | [True, False] | ['bool'] | Set to True to record relative error at the solver level |
record_solver_residuals | False | [True, False] | ['bool'] | Set to True to record residuals at the solver level |
Note
Note that the excludes
option takes precedence over the includes
option.
Note
The paths given in the includes
and excludes
options are relative to the Group
that the solver is attached to.
Note
It is currently not possible to record linear solvers.
Solver Recording Example¶
SellarDerivatives
class definition
class SellarDerivatives(om.Group):
"""
Group containing the Sellar MDA. This version uses the disciplines with derivatives.
"""
def initialize(self):
self.options.declare('nonlinear_solver', default=om.NonlinearBlockGS,
desc='Nonlinear solver (class or instance) for Sellar MDA')
self.options.declare('nl_atol', default=None,
desc='User-specified atol for nonlinear solver.')
self.options.declare('nl_maxiter', default=None,
desc='Iteration limit for nonlinear solver.')
self.options.declare('linear_solver', default=om.ScipyKrylov,
desc='Linear solver (class or instance)')
self.options.declare('ln_atol', default=None,
desc='User-specified atol for linear solver.')
self.options.declare('ln_maxiter', default=None,
desc='Iteration limit for linear solver.')
def setup(self):
self.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])
self.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])
self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)', obj=0.0,
x=0.0, z=np.array([0.0, 0.0]), y1=0.0, y2=0.0),
promotes=['obj', 'x', 'z', 'y1', 'y2'])
self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1', con1=0.0, y1=0.0),
promotes=['con1', 'y1'])
self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0', con2=0.0, y2=0.0),
promotes=['con2', 'y2'])
self.set_input_defaults('x', 1.0)
self.set_input_defaults('z', np.array([5.0, 2.0]))
nl = self.options['nonlinear_solver']
self.nonlinear_solver = nl() if inspect.isclass(nl) else nl
if self.options['nl_atol']:
self.nonlinear_solver.options['atol'] = self.options['nl_atol']
if self.options['nl_maxiter']:
self.nonlinear_solver.options['maxiter'] = self.options['nl_maxiter']
ln = self.options['linear_solver']
self.linear_solver = ln() if inspect.isclass(ln) else ln
if self.options['ln_atol']:
self.linear_solver.options['atol'] = self.options['ln_atol']
if self.options['ln_maxiter']:
self.linear_solver.options['maxiter'] = self.options['ln_maxiter']
import openmdao.api as om
from openmdao.test_suite.components.sellar import SellarDerivatives
prob = om.Problem(model=SellarDerivatives())
prob.setup()
recorder = om.SqliteRecorder("cases.sql")
solver = prob.model.nonlinear_solver
solver.add_recorder(recorder)
solver.recording_options['record_abs_error'] = True
solver.options['use_apply_nonlinear'] = True
prob.run_model()
NL: NLBGS Converged in 7 iterations
prob.cleanup()
cr = om.CaseReader("cases.sql")
solver_cases = cr.list_cases('root.nonlinear_solver')
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|0 |
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|1 |
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|2 |
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|3 |
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|4 |
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|5 |
solver |
---|
rank0:root._solve_nonlinear|0|NonlinearBlockGS|6 |
for case_id in solver_cases:
print(cr.get_case(case_id).abs_err)
2.2545141061171243
0.043663258684468076
0.0008635223885384846
1.707062189737485e-05
3.3746495375908125e-07
6.671260877055829e-09
1.318802844707534e-10