Accessing Recorded Metadata#
In addition to the cases themselves, a CaseReader
may also record
certain metadata about the model and its constituent systems and solvers.
Problem Metadata#
By default, a case recorder will save metadata about the model to assist in later visualization
and debugging. This information is made available via the problem_metadata
attribute of
a CaseReader
.
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(SellarDerivatives())
prob.model.nonlinear_solver = om.NonlinearBlockGS()
prob.model.linear_solver = om.ScipyKrylov()
recorder = om.SqliteRecorder("cases.sql")
prob.driver.add_recorder(recorder)
prob.setup()
prob.run_driver()
prob.cleanup()
cr = om.CaseReader(prob.get_outputs_dir() / "cases.sql")
NL: NLBGS Converged in 8 iterations
# access list of connections stored in metadata
cr.problem_metadata['connections_list']
[{'src': '_auto_ivc.v0', 'tgt': 'd1.z'},
{'src': '_auto_ivc.v0', 'tgt': 'd2.z'},
{'src': '_auto_ivc.v0', 'tgt': 'obj_cmp.z'},
{'src': '_auto_ivc.v1', 'tgt': 'd1.x'},
{'src': '_auto_ivc.v1', 'tgt': 'obj_cmp.x'},
{'src': 'd1.y1', 'tgt': 'con_cmp1.y1'},
{'src': 'd1.y1', 'tgt': 'd2.y1'},
{'src': 'd1.y1', 'tgt': 'obj_cmp.y1'},
{'src': 'd2.y2', 'tgt': 'con_cmp2.y2'},
{'src': 'd2.y2', 'tgt': 'd1.y2'},
{'src': 'd2.y2', 'tgt': 'obj_cmp.y2'}]
# access the model tree stored in metadata
cr.problem_metadata['tree']
{'name': 'root',
'type': 'root',
'class': 'openmdao.test_suite.components.sellar_feature:SellarDerivatives',
'expressions': None,
'nonlinear_solver': 'NL: NLBGS',
'nonlinear_solver_options': {'maxiter': 10,
'atol': 1e-10,
'rtol': 1e-10,
'iprint': 1,
'err_on_non_converge': False,
'debug_print': False,
'stall_limit': 0,
'stall_tol': 1e-12,
'stall_tol_type': 'rel',
'restart_from_successful': False,
'use_aitken': False,
'aitken_min_factor': 0.1,
'aitken_max_factor': 1.5,
'aitken_initial_factor': 1.0,
'cs_reconverge': True,
'use_apply_nonlinear': False,
'reraise_child_analysiserror': False},
'linear_solver': 'LN: SCIPY',
'linear_solver_options': {'maxiter': 1000,
'atol': 1e-12,
'rtol': 1e-10,
'iprint': 1,
'err_on_non_converge': False,
'assemble_jac': False,
'solver': 'gmres',
'restart': 20,
'rhs_checking': False},
'component_type': None,
'subsystem_type': 'group',
'is_parallel': False,
'children': [{'name': '_auto_ivc',
'type': 'subsystem',
'class': 'openmdao.core.indepvarcomp:_AutoIndepVarComp',
'expressions': None,
'nonlinear_solver': '',
'nonlinear_solver_options': None,
'linear_solver': '',
'linear_solver_options': None,
'subsystem_type': 'component',
'is_parallel': False,
'component_type': 'indep',
'children': [{'name': 'v0',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(2,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [5.0, 2.0],
'val_min_indices': [1],
'val_min': 2.0,
'val_max_indices': [0],
'val_max': 5.0},
{'name': 'v1',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0}],
'options': {'derivs_method': None,
'distributed': False,
'run_root_only': False,
'always_opt': False,
'use_jit': True,
'name': 'UNDEFINED',
'val': 1.0,
'shape': None,
'units': None,
'res_units': None,
'desc': None,
'lower': None,
'upper': None,
'ref': 1.0,
'ref0': 0.0,
'res_ref': None,
'tags': None}},
{'name': 'd1',
'type': 'subsystem',
'class': 'openmdao.test_suite.components.sellar:SellarDis1withDerivatives',
'expressions': None,
'nonlinear_solver': '',
'nonlinear_solver_options': None,
'linear_solver': '',
'linear_solver_options': None,
'subsystem_type': 'component',
'is_parallel': False,
'component_type': 'explicit',
'children': [{'name': 'z',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(2,)',
'desc': '',
'units': 'None',
'val': [5.0, 2.0],
'val_min_indices': [1],
'val_min': 2.0,
'val_max_indices': [0],
'val_max': 5.0},
{'name': 'x',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'y2',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'y1',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0}],
'options': {'derivs_method': None,
'distributed': False,
'run_root_only': False,
'always_opt': False,
'use_jit': True}},
{'name': 'd2',
'type': 'subsystem',
'class': 'openmdao.test_suite.components.sellar:SellarDis2withDerivatives',
'expressions': None,
'nonlinear_solver': '',
'nonlinear_solver_options': None,
'linear_solver': '',
'linear_solver_options': None,
'subsystem_type': 'component',
'is_parallel': False,
'component_type': 'explicit',
'children': [{'name': 'z',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(2,)',
'desc': '',
'units': 'None',
'val': [5.0, 2.0],
'val_min_indices': [1],
'val_min': 2.0,
'val_max_indices': [0],
'val_max': 5.0},
{'name': 'y1',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'y2',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0}],
'options': {'derivs_method': None,
'distributed': False,
'run_root_only': False,
'always_opt': False,
'use_jit': True}},
{'name': 'obj_cmp',
'type': 'subsystem',
'class': 'openmdao.components.exec_comp:ExecComp',
'expressions': ['obj = x**2 + z[1] + y1 + exp(-y2)'],
'nonlinear_solver': '',
'nonlinear_solver_options': None,
'linear_solver': '',
'linear_solver_options': None,
'subsystem_type': 'component',
'is_parallel': False,
'component_type': 'exec',
'children': [{'name': 'x',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'y1',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'y2',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'z',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(2,)',
'desc': '',
'units': 'None',
'val': [5.0, 2.0],
'val_min_indices': [1],
'val_min': 2.0,
'val_max_indices': [0],
'val_max': 5.0},
{'name': 'obj',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [0.0],
'val_min_indices': [0],
'val_min': 0.0,
'val_max_indices': [0],
'val_max': 0.0}],
'options': {'derivs_method': None,
'run_root_only': False,
'always_opt': False,
'use_jit': True,
'has_diag_partials': False,
'units': None,
'shape': None,
'shape_by_conn': False,
'do_coloring': False}},
{'name': 'con_cmp1',
'type': 'subsystem',
'class': 'openmdao.components.exec_comp:ExecComp',
'expressions': ['con1 = 3.16 - y1'],
'nonlinear_solver': '',
'nonlinear_solver_options': None,
'linear_solver': '',
'linear_solver_options': None,
'subsystem_type': 'component',
'is_parallel': False,
'component_type': 'exec',
'children': [{'name': 'y1',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'con1',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [0.0],
'val_min_indices': [0],
'val_min': 0.0,
'val_max_indices': [0],
'val_max': 0.0}],
'options': {'derivs_method': None,
'run_root_only': False,
'always_opt': False,
'use_jit': True,
'has_diag_partials': False,
'units': None,
'shape': None,
'shape_by_conn': False,
'do_coloring': False}},
{'name': 'con_cmp2',
'type': 'subsystem',
'class': 'openmdao.components.exec_comp:ExecComp',
'expressions': ['con2 = y2 - 24.0'],
'nonlinear_solver': '',
'nonlinear_solver_options': None,
'linear_solver': '',
'linear_solver_options': None,
'subsystem_type': 'component',
'is_parallel': False,
'component_type': 'exec',
'children': [{'name': 'y2',
'type': 'input',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'units': 'None',
'val': [1.0],
'val_min_indices': [0],
'val_min': 1.0,
'val_max_indices': [0],
'val_max': 1.0},
{'name': 'con2',
'type': 'output',
'dtype': 'ndarray',
'is_discrete': False,
'distributed': False,
'shape': '(1,)',
'desc': '',
'implicit': False,
'units': 'None',
'val': [0.0],
'val_min_indices': [0],
'val_min': 0.0,
'val_max_indices': [0],
'val_max': 0.0}],
'options': {'derivs_method': None,
'run_root_only': False,
'always_opt': False,
'use_jit': True,
'has_diag_partials': False,
'units': None,
'shape': None,
'shape_by_conn': False,
'do_coloring': False}}],
'options': {'assembled_jac_type': 'csc',
'derivs_method': None,
'auto_order': False}}
System Options#
All case recorders record the component options and scaling factors for all systems in the model.
These values are accessible using the list_model_options
function of a case reader object.
This function displays and returns a dictionary of the option values for each system in the model.
If the model has been run multiple times, you can specify the run for which to get/display options.
The following examples use the SellarDerivsGrouped
model, which provides system-level options to set and control the solvers.
SellarDerivativesGrouped
class definition
class SellarDerivativesGrouped(om.Group):
"""
Group containing the Sellar MDA. This version uses the disciplines with derivatives.
"""
def initialize(self):
self.options.declare('nonlinear_solver', default=None, recordable=False,
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=None, recordable=False,
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.')
self.options.declare('mda_nonlinear_solver', default=None, recordable=False,
desc='Nonlinear solver (class or instance)')
self.options.declare('mda_linear_solver', default=None, recordable=False,
desc='Linear solver (class or instance) for Sellar MDA')
def setup(self):
self.mda = mda = self.add_subsystem('mda', om.Group(), promotes=['x', 'z', 'y1', 'y2'])
mda.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])
mda.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])
self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',
z=np.array([0.0, 0.0]), x=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'), promotes=['con1', 'y1'])
self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.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']
if nl:
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']
if ln:
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']
nl = self.options['mda_nonlinear_solver']
if nl:
self.mda.nonlinear_solver = nl() if inspect.isclass(nl) else nl
ln = self.options['mda_linear_solver']
if ln:
self.mda.linear_solver = ln() if inspect.isclass(ln) else ln
import openmdao.api as om
from openmdao.test_suite.components.sellar import SellarDerivativesGrouped
prob = om.Problem(model=SellarDerivativesGrouped())
prob.add_recorder(om.SqliteRecorder("cases.sql"))
# set option and run model
prob.model.options['nonlinear_solver'] = om.NonlinearBlockGS()
prob.model.options['nl_maxiter'] = 1
prob.setup()
prob.run_model()
# change option and run again
prob.model.options['nl_maxiter'] = 9
prob.setup()
prob.run_model()
# clean up after runs and open a case reader
prob.cleanup()
cr = om.CaseReader(prob.get_outputs_dir() / "cases.sql")
NL: NLBGSSolver 'NL: NLBGS' on system '' failed to converge in 1 iterations.
Model viewer data has already been recorded for Driver.
NL: NLBGS Converged in 8 iterations
# get/display options for initial run
options = cr.list_model_options()
Run Number: 0
Subsystem : root
assembled_jac_type: csc
derivs_method: None
nl_atol: None
nl_maxiter: 1
ln_atol: None
ln_maxiter: None
auto_order: False
Subsystem : _auto_ivc
derivs_method: None
distributed: False
run_root_only: False
always_opt: False
use_jit: True
name: UNDEFINED
val: 1.0
shape: None
units: None
res_units: None
desc: None
lower: None
upper: None
ref: 1.0
ref0: 0.0
res_ref: None
tags: None
Subsystem : mda
assembled_jac_type: csc
derivs_method: None
auto_order: False
Subsystem : mda.d1
derivs_method: None
distributed: False
run_root_only: False
always_opt: False
use_jit: True
Subsystem : mda.d2
derivs_method: None
distributed: False
run_root_only: False
always_opt: False
use_jit: True
Subsystem : obj_cmp
derivs_method: None
run_root_only: False
always_opt: False
use_jit: True
has_diag_partials: False
units: None
shape: None
shape_by_conn: False
do_coloring: False
Subsystem : con_cmp1
derivs_method: None
run_root_only: False
always_opt: False
use_jit: True
has_diag_partials: False
units: None
shape: None
shape_by_conn: False
do_coloring: False
Subsystem : con_cmp2
derivs_method: None
run_root_only: False
always_opt: False
use_jit: True
has_diag_partials: False
units: None
shape: None
shape_by_conn: False
do_coloring: False
# check nl_maxiter option for the second run
options = cr.list_model_options(run_number=1, out_stream=None)
options['root']['nl_maxiter']
9
Solver Options#
All case recorders record the solver options for all solvers in the model.
These values are accessible using the list_solver_options
function of a case reader object.
This function displays and returns a dictionary of the option values for each solver in the model. If the model has been run multiple times, you can specify the run for which to get/display options.
import openmdao.api as om
from openmdao.test_suite.components.sellar import SellarDerivativesGrouped
prob = om.Problem(model=SellarDerivativesGrouped())
prob.model.options['nonlinear_solver'] = om.NonlinearBlockGS()
prob.model.options['linear_solver'] = om.ScipyKrylov()
# configure a Newton solver with linesearch for the Sellar MDA Group
newton = om.NewtonSolver(solve_subsystems=True, max_sub_solves=4)
newton.linesearch = om.BoundsEnforceLS()
prob.model.options['mda_nonlinear_solver'] = newton
prob.model.options['mda_linear_solver'] = om.ScipyKrylov()
prob.add_recorder(om.SqliteRecorder("cases.sql"))
prob.setup()
# initial run
newton.linesearch.options['bound_enforcement'] = 'vector'
prob.run_model()
# change linesearch and run again
newton.linesearch.options['bound_enforcement'] = 'wall'
prob.run_model()
# clean up after runs and open a case reader
prob.cleanup()
cr = om.CaseReader(prob.get_outputs_dir() / "cases.sql")
|
| ===
| mda
| ===
| NL: Newton Converged in 2 iterations
|
| ===
| mda
| ===
| NL: Newton Converged in 0 iterations
NL: NLBGS Converged in 2 iterations
Model viewer data has already been recorded for Driver.
|
| ===
| mda
| ===
| NL: Newton Converged in 0 iterations
NL: NLBGS Converged in 1 iterations
# get/display options for initial run
options = cr.list_solver_options()
Run Number: 0
Solver: root.NonlinearBlockGS
maxiter: 10
atol: 1e-10
rtol: 1e-10
iprint: 1
err_on_non_converge: False
debug_print: False
stall_limit: 0
stall_tol: 1e-12
stall_tol_type: rel
restart_from_successful: False
use_aitken: False
aitken_min_factor: 0.1
aitken_max_factor: 1.5
aitken_initial_factor: 1.0
cs_reconverge: True
use_apply_nonlinear: False
reraise_child_analysiserror: False
Solver: root.ScipyKrylov
maxiter: 1000
atol: 1e-12
rtol: 1e-10
iprint: 1
err_on_non_converge: False
assemble_jac: False
solver: gmres
restart: 20
rhs_checking: False
Solver: mda.NewtonSolver
maxiter: 10
atol: 1e-10
rtol: 1e-10
iprint: 1
err_on_non_converge: False
debug_print: False
stall_limit: 0
stall_tol: 1e-12
stall_tol_type: rel
restart_from_successful: False
solve_subsystems: True
max_sub_solves: 4
cs_reconverge: True
reraise_child_analysiserror: False
Solver: mda.BoundsEnforceLS
iprint: 1
debug_print: False
stall_limit: 0
stall_tol: 1e-12
stall_tol_type: rel
bound_enforcement: vector
print_bound_enforce: False
Solver: mda.ScipyKrylov
maxiter: 1000
atol: 1e-12
rtol: 1e-10
iprint: 1
err_on_non_converge: False
assemble_jac: False
solver: gmres
restart: 20
rhs_checking: False
print(sorted(options.keys()))
['mda.BoundsEnforceLS', 'mda.NewtonSolver', 'mda.ScipyKrylov', 'root.NonlinearBlockGS', 'root.ScipyKrylov']
print(options['root.NonlinearBlockGS']['maxiter'])
10
print(options['root.ScipyKrylov']['maxiter'])
1000
print(options['mda.NewtonSolver']['maxiter'])
10
print(options['mda.NewtonSolver']['solve_subsystems'])
True
print(options['mda.NewtonSolver']['max_sub_solves'])
4
print(options['mda.BoundsEnforceLS']['bound_enforcement'])
vector
# get options for second run
options = cr.list_solver_options(run_number=1, out_stream=None)
print(options['mda.BoundsEnforceLS']['bound_enforcement'])
wall