Warning Control#
OpenMDAO has several classes of warnings that may be raised during operation. In general, these warnings are useful and the user should pay attention to them. Sometimes these warnings can be unnecessarily noisy. Filtering out noisy “low-priority” warnings can make other more important ones more obvious.
OpenMDAO-Specific Warning Categories#
Class OpenMDAOWarning serves as the base-class for all OpenMDAO-specific warnings. All OpenMDAO-specific warnings default to a filter of ‘always’. The following table shows all OpenMDAOWarning-derived classes.
Warning Class |
Description |
---|---|
CacheWarning |
Issued when cache is invalid and must be discarded. |
CaseRecorderWarning |
Issued when a problem is encountered by a case recorder or case reader. |
DerivativesWarning |
Issued when the approximated partials or coloring cannot be evaluated as expected. |
DriverWarning |
Issued when a problem is encountered during driver execution. |
OMDeprecationWarning |
Issued when a deprecated OpenMDAO feature is used. |
SetupWarning |
Issued when a problem is encountered during setup. |
SolverWarning |
Issued when a problem is encountered during solver execution. |
UnusedOptionWarning |
Issued when a given option or argument has no effect. |
Note that the OpenMDAO-Specific OMDeprecationWarning behaves a bit differently than the default Python DeprecationWarning. OMDeprecationWarning is is always displayed by default, but can be silenced by the user.
For finer control over which warnings are displayed during setup, the following warning classes derive from SetupWarning. Using a filter to silence SetupWarning will silence all of the following.
Warning Class |
Description |
---|---|
DistributedComponentWarning |
Issued when problems arise with a distributed component. |
MPIWarning |
Issued when MPI is not available or cannot be used. |
PromotionWarning |
Issued when there is ambiguity due to variable promotion. |
UnitsWarning |
Issued when unitless variable is connected to a variable with units. |
Filtering Warnings#
Python’s built-in warning filtering system can be used to control which warnings are displayed when using OpenMDAO. The following script generates an OpenMDAO model which will generate UnitsWarning due to connecting unitless outputs to inputs with units.
In the following code, the UnitsWarning will be displayed as expected:
"""
Test nominal UnitsWarning.
"""
import warnings
import openmdao.api as om
class AComp(om.ExplicitComponent):
def initialize(self):
pass
def setup(self):
self.add_input('a', shape=(10,), units='m')
self.add_input('x', shape=(10,), units='1/s')
self.add_input('b', shape=(10,), units='m/s')
self.add_output('y', shape=(10,), units='m')
self.add_output('z', shape=(10,), units='m/s')
self.declare_coloring(wrt='*', form='cs')
def compute(self, inputs, outputs):
outputs['y'] = inputs['a'] * inputs['x'] + inputs['b']
outputs['z'] = inputs['b'] * inputs['x']
p = om.Problem()
p.model.add_subsystem('a_comp', AComp())
p.model.add_subsystem('exec_comp',
om.ExecComp('foo = y + z',
y={'shape': (10,)},
z={'shape': (10,)},
foo={'shape': (10,)}))
p.model.connect('a_comp.y', 'exec_comp.y')
p.model.connect('a_comp.z', 'exec_comp.z')
p.driver.declare_coloring()
p.setup()
with warnings.catch_warnings(record=True) as w:
p.setup()
unit_warnings = [wm for wm in w if wm.category is om.UnitsWarning]
assert(len(unit_warnings) == 2)
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/core/group.py:2974: UnitsWarning:<model> <class Group>: Output 'a_comp.y' with units of 'm' is connected to input 'exec_comp.y' which has no units.
/usr/share/miniconda/envs/test/lib/python3.11/site-packages/openmdao/core/group.py:2974: UnitsWarning:<model> <class Group>: Output 'a_comp.z' with units of 'm/s' is connected to input 'exec_comp.z' which has no units.
The warnings can be completely turned off by filtering them using Python’s filterwarnings function:
"""
Test the ability to ignore UnitsWarning
"""
import warnings
import openmdao.api as om
class AComp(om.ExplicitComponent):
def initialize(self):
pass
def setup(self):
self.add_input('a', shape=(10,), units='m')
self.add_input('x', shape=(10,), units='1/s')
self.add_input('b', shape=(10,), units='m/s')
self.add_output('y', shape=(10,), units='m')
self.add_output('z', shape=(10,), units='m/s')
self.declare_coloring(wrt='*', form='cs')
def compute(self, inputs, outputs):
outputs['y'] = inputs['a'] * inputs['x'] + inputs['b']
outputs['z'] = inputs['b'] * inputs['x']
p = om.Problem()
p.model.add_subsystem('a_comp', AComp())
p.model.add_subsystem('exec_comp',
om.ExecComp('foo = y + z',
y={'shape': (10,)},
z={'shape': (10,)},
foo={'shape': (10,)}))
p.model.connect('a_comp.y', 'exec_comp.y')
p.model.connect('a_comp.z', 'exec_comp.z')
p.driver.declare_coloring()
warnings.filterwarnings('ignore', category=om.UnitsWarning)
with warnings.catch_warnings(record=True) as w:
p.setup()
unit_warnings = [wm for wm in w if wm.category is om.UnitsWarning]
assert (len(unit_warnings) == 0)
If you want to clean your code and remove warnings, it can be useful to promote them to errors so that they cannot be ignored. The following code filters all OpenMDAO associated warnings to Errors:
"""
Test the ability to raise a UnitWarning to an error.
"""
import warnings
import openmdao.api as om
class AComp(om.ExplicitComponent):
def initialize(self):
pass
def setup(self):
self.add_input('a', shape=(10,), units='m')
self.add_input('x', shape=(10,), units='1/s')
self.add_input('b', shape=(10,), units='m/s')
self.add_output('y', shape=(10,), units='m')
self.add_output('z', shape=(10,), units='m/s')
self.declare_coloring(wrt='*', form='cs')
def compute(self, inputs, outputs):
outputs['y'] = inputs['a'] * inputs['x'] + inputs['b']
outputs['z'] = inputs['b'] * inputs['x']
p = om.Problem(name='warn_to_error')
p.model.add_subsystem('a_comp', AComp())
p.model.add_subsystem('exec_comp',
om.ExecComp('foo = y + z',
y={'shape': (10,)},
z={'shape': (10,)},
foo={'shape': (10,)}))
p.model.connect('a_comp.y', 'exec_comp.y')
p.model.connect('a_comp.z', 'exec_comp.z')
p.driver.declare_coloring()
warnings.filterwarnings('error', category=om.OpenMDAOWarning)
expected = "\nCollected errors for problem 'warn_to_error':\n <model> <class Group>: Output 'a_comp.y' with units of 'm' is connected to " \
"input 'exec_comp.y' which has no units."
try:
p.setup()
except om.UnitsWarning as e:
if str(e) != expected:
raise RuntimeError(f"{str(e)} != {expected}")
else:
print(str(e))
else:
raise RuntimeError(f"Exception '{expected}' not raised")
Collected errors for problem 'warn_to_error':
<model> <class Group>: Output 'a_comp.y' with units of 'm' is connected to input 'exec_comp.y' which has no units.
Notes for Developers#
Python’s treatment of warnings inside UnitTest tests can be somewhat confusing.
If you wish to test that certain warnings are filtered during testing, we recommend using the om.reset_warnings()
method in the setUp
method that is run before each test in a TestCase
.
import unittest
import openmdao.api as om
class MyTestCase(unittest.TestCase):
def setUp(self):
"""
Ensure that OpenMDAO warnings are using their default filter action.
"""
om.reset_warnings()
def test_a(self):
...