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.

OptionDefaultAcceptable ValuesAcceptable TypesDescription
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_errorTrue[True, False]['bool']Set to True to record absolute error at the solver level
record_inputsTrue[True, False]['bool']Set to True to record inputs at the solver level
record_outputsTrue[True, False]['bool']Set to True to record outputs at the solver level
record_rel_errorTrue[True, False]['bool']Set to True to record relative error at the solver level
record_solver_residualsFalse[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 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]))

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

prob = om.Problem(name='solver_recording', model=SellarDerivatives())
prob.setup()

recorder = om.SqliteRecorder("solver_recording.sql")

solver = prob.model.nonlinear_solver = om.NonlinearBlockGS()
solver.add_recorder(recorder)
solver.recording_options['record_abs_error'] = True
solver.options['use_apply_nonlinear'] = True

prob.run_model()
[1790952391.834932] [runnervm8df0l:10579:0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x555c673a9fb0 failed to create UD QP TX wr:256 sge:6 inl:64 resp:0 RX wr:4096 sge:1 resp:0 failed: Operation not supported
[1790952391.835190] [runnervm8df0l:10579:0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error
[runnervm8df0l:10579] pml_ucx.c:313  Error: Failed to create UCP worker
NL: NLBGS Converged in 7 iterations
prob.cleanup()
cr = om.CaseReader(prob.get_outputs_dir() / "solver_recording.sql")
solver_cases = cr.list_cases('root.nonlinear_solver')

root.nonlinear_solver
rank0:root._solve_nonlinear|0|NonlinearBlockGS|0
rank0:root._solve_nonlinear|0|NonlinearBlockGS|1
rank0:root._solve_nonlinear|0|NonlinearBlockGS|2
rank0:root._solve_nonlinear|0|NonlinearBlockGS|3
rank0:root._solve_nonlinear|0|NonlinearBlockGS|4
rank0:root._solve_nonlinear|0|NonlinearBlockGS|5
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