OpenMDAO Logo

An open-source framework for efficient multidisciplinary optimization.

OpenMDAO V3.2 is live and it’s a big deal!

OpenMDAO 3.2 is live. You can read the details in the release notes, but I want to specifically highlight something that all current users will notice. You no longer need to manually create any IndepVarComps.

Following POEM 015, we’ve implemented an automatic IndepVarComp feature that means in the vast majority of use cases you do not need to manually create them.

The IndepVarComp was always a bit awkward from a user perspective, but due to some of the details in the math that powers OpenMDAO it is necessary that every single variable have an ultimate source associated with it. The IndepVarComps served as that source for the independent variables in your models.

Since they were necessary, we grew to accept this idiosyncrasy of OpenMDAO syntax. However, recently a series of other updates to setup stack (POEM 003 and POEM 009) made it possible to create I/O in components much later in the setup process. These improvements were not made for the purposes of eliminating manually created IndepVarComps, but they were crucial to being able to add this new functionality.

We’ve made the new feature highly backwards compatible, so your old models should still work with the manually created IndepVarComps in place. For that matter, if you so choose you are still free to create them wherever you like. There are a few corner cases where backwards compatibility was not possible, and if you run into anything that the devs haven’t foreseen please don’t hesitate to reach out!

Upgrade Guide

To help you adopt the new coding style, we’ve put together an upgrade guide for you. This covers all the common cases that we could think of. We’ve also updated all of the docs to use the new auto-ivc capability in all the examples.

There is one use case for the new functionality that I am most excited about. You can leverage the new apis to create pass-through style variables in your groups. The variable name can either be used directly as a design variable or be connected into from some other source.

Here is a contrived example that demonstrates the basic concept. In the first use case, “g0.x” is used directly as a design variable. In the second use case we connect “upstream.x” to “g0.x”. Note that there is no IndepVarComp anywhere in these examples.

import openmdao.api as om

class FancyPassthroughGroup(om.Group): 

    def setup(self): 

        self.add_subsystem('comp0', om.ExecComp('y0 = 3*x', 
                                                 x={'units':'ft'}, 
                                                 y0={'units':'ft'}), 
                           promotes=['*'])        
        self.add_subsystem('comp1', om.ExecComp('y1 = x**2', 
                                                x={'units':'m'}, 
                                                y1={'units':'m'}), 
                           promotes=['*'])

        self.set_input_defaults('x', units='cm', val=3.0)


#############################################################
# First usage of the fancy group is to set up a direct 
# optimization of the group: minimize y1 w.r.t x
#############################################################
prob0 = om.Problem()
prob0.model.add_subsystem('g0', FancyPassthroughGroup())
# note: this design variable will be in 
#       units of `cm` following the input default
prob0.model.add_design_var('g0.x', lower=-10, upper=10) 
prob0.model.add_objective('g0.y1')

prob0.driver = om.ScipyOptimizeDriver()

prob0.setup()

# this will find x=0 to minimize y1=x**2
prob0.run_driver()
print('x: ', prob0.get_val('g0.x')) 
print('y1: ', prob0.get_val('g0.y1')) 


#############################################################
# Second usage of the fancy group is connect add a modifier 
# upstream and connect that into x, then optimize the w.r.t 
# the new variable
#############################################################
prob1 = om.Problem()
prob1.model.add_subsystem('upstream', om.ExecComp('x = x_prime + 3',
                                                  x_prime={'units':'inch'}, 
                                                  x={'units':'inch'}))
prob1.model.add_subsystem('g0', FancyPassthroughGroup())
prob1.model.connect('upstream.x', 'g0.x')
# note: this design variable will be in 
#       units of `inch` following units on the upstream input
prob1.model.add_design_var('upstream.x_prime', lower=-10, upper=10) 
prob1.model.add_objective('g0.y1')

prob1.driver = om.ScipyOptimizeDriver()
prob1.driver.options['tol'] = 1e-6

prob1.setup()

# this will find x=0 to minimize y1=x**3
prob1.run_driver()
print('x_prime: ', prob1.get_val('upstream.x_prime'))
print('y1: ', prob1.get_val('g0.y1'))

Comments are closed.

Fork me on GitHub