OpenMDAO / OpenMDAO

OpenMDAO repository.
http://openmdao.org
Other
551 stars 251 forks source link

AutoIVC incorrect behavior if system is a single component. Various other issues when `Problem.model` is a Component. #2684

Closed robfalck closed 1 year ago

robfalck commented 2 years ago

Description

A user reported that the AutoIVC feature doesn't work correctly when the system is a single component, as there is no Group in which to put the automatically created IndepVarComp.

While testing this, I uncovered a few other issues with problems in which the model was a single system. Our reliance on AutoIVC has me tempted to say that we should just deprecate this behavior and in the future require that Problem.model be a Group, or at least be derived from Group.

Some of these cases are captured below. Others include the N2 being wonky (but still generated as a report) in this situation.

Example

import unittest

import openmdao.api as om

class TestComponentAsSystem(unittest.TestCase):
    """
    This code shows various issues we encounter when the System _is_ a component.
    """
    def test_component_as_system(self):

        prob = om.Problem()

        prob.model = om.ExecComp('z = x + y')

        prob.setup()

        prob.set_val('x', 2)
        prob.set_val('y', 5)

        prob.run_model()

        assert_near_equal(7.0, prob.get_val('z'))

    def test_promotes_component_as_system(self):
        """
        Promotes error because theres nowhere to promote to, but that isn't necessarily clear.

        The error is

        RuntimeError: <model> <class ExecComp>: arg 'promotes_inputs' in call to ExecComp() does
        not refer to any variable in the expressions ['z = (x - 2)**2']

        Clearly that's not the case.
        """
        prob = om.Problem()

        prob.model = om.ExecComp('z = (x - 2)**2', promotes_inputs=['x'], promotes_outputs=['z'])

        prob.setup()

        prob.set_val('x', 5)

        prob.run_model()

        assert_near_equal(9.0, prob.get_val('z'))

    def test_optimize_component_as_system(self):
        """
        Promotes error because theres nowhere to promote to, but that isn't necessarily clear.

        Errors with 'Output not found for design variable 'x'.
        """
        prob = om.Problem()

        prob.model = om.ExecComp('z = (x - 2)**2')

        prob.model.add_design_var('x')
        prob.model.add_objective('z')
        prob.driver = om.ScipyOptimizeDriver()

        prob.setup()

        prob.set_val('x', 5)

        prob.run_driver()

        assert_near_equal(2.0, prob.get_val('x'))

OpenMDAO Version

3.21.1-dev

Relevant environment information

No response

JustinSGray commented 2 years ago

If your whole model is one component... AutoIVC has no meaning. We simply shouldn't create any, right?

robfalck commented 2 years ago

Say we don't generate the AutoIVC. The third test case should not work then? We're then requiring the root system to be a Group if we do optimization (you need IVCs to hold your design variables). The error message should be something along the lines of Design variables require an IndepVarComp. but since we strongly favor AutoIVC that might be confusing. It may just be simpler and more clear to require the root to be a Group.

Promotes should also fail when promoting from the root system, that would address the second test case.

Kenneth-T-Moore commented 2 years ago

promotes_inputs is an argument on Group.add_subsystem, not ExecComp.__init__. The user should have seen that in the error message. The error you are seeing is because all arguments in ExecComp are supposed to be input or output names with the value being a dictionary of metadata.

I'm all for restricting prob.model to be a Group though.