OpenMDAO
Define a problem in OpenMDAO
This example does not intend to cover all the features of OpenMDAO For more details and tutorials on OpenMDAO, please refer to OpenMDAO’s documentation. In this example, we solve a constrained problem given by
We know the solution of this problem is \(x_1=1\), and \(x_2=0\). However, we start from an initial guess of \(x_1=500.0\), and \(x_2=5.0\) for the purposes of this tutorial.
The problem functions are written using OpenMDAO components (and groups) as follows:
import openmdao.api as om
# minimize x^2 + y^2 subject to x>=0, x+y=1, x-y>=1.
class QuadraticComp(om.ExplicitComponent):
def setup(self):
# add_inputs
self.add_input('x', 1.)
self.add_input('y', 1.)
# add_outputs
self.add_output('objective')
self.add_output('constraint_1')
self.add_output('constraint_2')
# declare_partials
self.declare_partials(of='objective', wrt='*')
self.declare_partials(of='constraint_1', wrt='x', val=1.)
self.declare_partials(of='constraint_1', wrt='y', val=1.)
self.declare_partials(of='constraint_2', wrt='x', val=1.)
self.declare_partials(of='constraint_2', wrt='y', val=-1.)
def compute(self, inputs, outputs):
x = inputs['x']
y = inputs['y']
outputs['objective'] = x**2 + y**2
outputs['constraint_1'] = x + y
outputs['constraint_2'] = x - y
def compute_partials(self, inputs, partials):
x = inputs['x']
y = inputs['y']
partials['objective', 'x'] = 2 * x
partials['objective', 'y'] = 2 * y
Once your functions are defined within an OpenMDAO Component or Group,
create an OpenMDAO Problem object and add the Component or Group object
as a subsystem of the Problem object’s model.
Next, specify the model’s design variables, objective, and constraints.
Lastly, set up the problem and define the initial values for the design variables.
# Create an OpenMDAO Problem object
om_prob = om.Problem()
# Add QuadraticFunc() as a subsystem to the OpenMDAO Problem object
om_prob.model.add_subsystem('quadratic', QuadraticComp(), promotes=['*'])
# Add optimization variables and functions to the Problem model
om_prob.model.add_design_var('x', lower=0.)
om_prob.model.add_design_var('y')
om_prob.model.add_objective('objective')
om_prob.model.add_constraint('constraint_1', equals=1.)
om_prob.model.add_constraint('constraint_2', lower=1.)
# Setup the OpenMDAO problem
om_prob.setup()
# Set initial values for the design variables
om_prob.set_val('x', 500.)
om_prob.set_val('y', 5.)
After the OpenMDAO’s Problem object is set up with initial values for all variables,
create an OpenMDAOProblem object that wraps the Problem object for interfacing with modOpt.
import modopt as mo
# Instantiate the modopt.OpenMDAOProblem() object that wraps for modopt
# the Problem() object defined earlier, and name your problem
prob = mo.OpenMDAOProblem(problem_name='quadratic_openmdao',
om_problem=om_prob)
/Users/modopt/modopt/external_libraries/openmdao/openmdao_problem.py:47: UserWarning: This version of OpenMDAO wrapper does not support SURF paradigm.
warnings.warn('This version of OpenMDAO wrapper does not support SURF paradigm.')
Solve your problem using an optimizer
Once your problem model is wrapped for modOpt, import your preferred optimizer
from modOpt and solve it, following the standard procedure.
Here we will use the SLSQP optimizer from the SciPy library.
# Setup your preferred optimizer (SLSQP) with the Problem object
# Pass in the options for your chosen optimizer
optimizer = mo.SLSQP(prob, solver_options={'maxiter':20})
# Check first derivatives at the initial guess, if needed
optimizer.check_first_derivatives(prob.x0)
# Solve your optimization problem
optimizer.solve()
# Print results of optimization
optimizer.print_results()
----------------------------------------------------------------------------
Derivative type | Calc norm | FD norm | Abs error norm | Rel error norm
----------------------------------------------------------------------------
Gradient | 1.0000e+03 | 1.0000e+03 | 1.5473e-05 | 1.5472e-08
Jacobian | 2.0000e+00 | 2.0000e+00 | 5.0495e-09 | 2.5248e-09
----------------------------------------------------------------------------
Solution from Scipy SLSQP:
----------------------------------------------------------------------------------------------------
Problem : quadratic_openmdao
Solver : scipy-slsqp
Success : True
Message : Optimization terminated successfully
Status : 0
Total time : 0.013110160827636719
Objective : 1.0000000068019972
Gradient norm : 2.000000006801997
Total function evals : 2
Total gradient evals : 2
Major iterations : 2
Total callbacks : 17
Reused callbacks : 0
obj callbacks : 5
grad callbacks : 3
hess callbacks : 0
con callbacks : 6
jac callbacks : 3
----------------------------------------------------------------------------------------------------
Scaling API
Please refer to the code snippet below as a guide for scaling the design variables, objective, and constraints independent of their definitions.
Warning
The results provided by the optimizer will always be scaled, while the values from the models will remain unscaled.
# Add optimization variables and functions to the Problem model
om_prob.model.add_design_var('x', lower=0., scaler=2.)
om_prob.model.add_design_var('y', scaler=2.)
om_prob.model.add_objective('objective', scaler=5.)
om_prob.model.add_constraint('constraint_1', equals=1., scaler=10.)
om_prob.model.add_constraint('constraint_2', lower=1., scaler=100.)