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:2978: 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:2978: 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):
            ...