ScipyOptimizeDriver

ScipyOptimizeDriver wraps the optimizers in scipy.optimize.minimize. In this example, we use the SLSQP optimizer to find the minimum of the Paraboloid problem.

import openmdao.api as om
from openmdao.test_suite.components.paraboloid import Paraboloid

prob = om.Problem()
model = prob.model

model.add_subsystem('comp', Paraboloid(), promotes=['*'])

prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.driver.options['tol'] = 1e-9
prob.driver.options['disp'] = True

model.add_design_var('x', lower=-50.0, upper=50.0)
model.add_design_var('y', lower=-50.0, upper=50.0)
model.add_objective('f_xy')

prob.setup()

prob.set_val('x', 50.0)
prob.set_val('y', 50.0)

prob.run_driver()
Optimization terminated successfully.    (Exit mode 0)
            Current function value: -27.33333333333333
            Iterations: 3
            Function evaluations: 4
            Gradient evaluations: 3
Optimization Complete
-----------------------------------
print(prob.get_val('x'))
[6.66666667]
print(prob.get_val('y'))
[-7.33333333]

ScipyOptimizeDriver Options

Option

Default

Acceptable Values

Acceptable Types

Description

debug_print

[]

N/A

[‘list’]

List of what type of Driver variables to print at each iteration. Valid items in list are ‘desvars’, ‘ln_cons’, ‘nl_cons’, ‘objs’, ‘totals’

disp

True

[True, False]

[‘bool’]

Set to False to prevent printing of Scipy convergence messages

maxiter

200

N/A

N/A

Maximum number of iterations.

optimizer

SLSQP

[‘BFGS’, ‘Newton-CG’, ‘COBYLA’, ‘SLSQP’, ‘trust-constr’, ‘dual_annealing’, ‘shgo’, ‘differential_evolution’, ‘basinhopping’, ‘CG’, ‘L-BFGS-B’, ‘TNC’, ‘Nelder-Mead’, ‘Powell’]

N/A

Name of optimizer to use

tol

1e-06

N/A

N/A

Tolerance for termination. For detailed control, use solver-specific options.

ScipyOptimizeDriver Constructor

The call signature for the ScipyOptimizeDriver constructor is:

ScipyOptimizeDriver.__init__(**kwargs)[source]

Initialize the ScipyOptimizeDriver.

Parameters
**kwargsdict of keyword arguments

Keyword arguments that will be mapped into the Driver options.

ScipyOptimizeDriver Option Examples

optimizer

The “optimizer” option lets you choose which optimizer to use. ScipyOptimizeDriver supports all of the optimizers in scipy.optimize except for ‘dogleg’ and ‘trust-ncg’. Generally, the optimizers that you are most likely to use are “COBYLA” and “SLSQP”, as these are the only ones that support constraints. Only SLSQP supports equality constraints. SLSQP also uses gradients provided by OpenMDAO, while COBYLA is gradient-free. Also, SLSQP supports both equality and inequality constraints, but COBYLA only supports inequality constraints.

Here we pass the optimizer option as a keyword argument.

import openmdao.api as om
from openmdao.test_suite.components.paraboloid import Paraboloid

prob = om.Problem()
model = prob.model

model.add_subsystem('comp', Paraboloid(), promotes=['*'])

prob.driver = om.ScipyOptimizeDriver(optimizer='COBYLA')

model.add_design_var('x', lower=-50.0, upper=50.0)
model.add_design_var('y', lower=-50.0, upper=50.0)
model.add_objective('f_xy')

prob.setup()

prob.set_val('x', 50.0)
prob.set_val('y', 50.0)

prob.run_driver()
Optimization Complete
-----------------------------------
print(prob.get_val('x'))
[6.66666669]
print(prob.get_val('y'))
[-7.33333239]

maxiter

The “maxiter” option is used to specify the maximum number of major iterations before termination. It is generally a valid option across all of the available options.

import openmdao.api as om
from openmdao.test_suite.components.paraboloid import Paraboloid

prob = om.Problem()
model = prob.model

model.add_subsystem('comp', Paraboloid(), promotes=['*'])

prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['maxiter'] = 20

model.add_design_var('x', lower=-50.0, upper=50.0)
model.add_design_var('y', lower=-50.0, upper=50.0)
model.add_objective('f_xy')

prob.setup()

prob.set_val('x', 50.0)
prob.set_val('y', 50.0)

prob.run_driver()
Optimization terminated successfully.    (Exit mode 0)
            Current function value: -27.33333333333333
            Iterations: 3
            Function evaluations: 4
            Gradient evaluations: 3
Optimization Complete
-----------------------------------
print(prob.get_val('x'))
[6.66666667]
print(prob.get_val('y'))
[-7.33333333]

tol

The “tol” option allows you to specify the tolerance for termination.

import openmdao.api as om
from openmdao.test_suite.components.paraboloid import Paraboloid

prob = om.Problem()
model = prob.model

model.add_subsystem('comp', Paraboloid(), promotes=['*'])

prob.driver = om.ScipyOptimizeDriver()
prob.driver.options['tol'] = 1.0e-9

model.add_design_var('x', lower=-50.0, upper=50.0)
model.add_design_var('y', lower=-50.0, upper=50.0)
model.add_objective('f_xy')

prob.setup()

prob.set_val('x', 50.0)
prob.set_val('y', 50.0)

prob.run_driver()
Optimization terminated successfully.    (Exit mode 0)
            Current function value: -27.33333333333333
            Iterations: 3
            Function evaluations: 4
            Gradient evaluations: 3
Optimization Complete
-----------------------------------
print(prob.get_val('x'))
[6.66666667]
print(prob.get_val('y'))
[-7.33333333]

ScipyOptimizeDriver Driver Specific Options

Optimizers in scipy.optimize.minimize have optimizer specific options. To let the user specify values for these options, OpenMDAO provides an option in the form of a dictionary named opt_settings. See the scipy.optimize.minimize documentation for more information about the driver specific options that are available.

As an example, here is code using some opt_settings for the shgo optimizer:

# Source of example: https://stefan-endres.github.io/shgo/

import numpy as np
import openmdao.api as om

size = 3  # size of the design variable

def rastrigin(x):
    a = 10  # constant
    return np.sum(np.square(x) - a * np.cos(2 * np.pi * x)) + a * np.size(x)

class Rastrigin(om.ExplicitComponent):

    def setup(self):
        self.add_input('x', np.ones(size))
        self.add_output('f', 0.0)

    def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
        x = inputs['x']
        outputs['f'] = rastrigin(x)

prob = om.Problem()
model = prob.model

model.add_subsystem('rastrigin', Rastrigin(), promotes=['*'])

prob.driver = driver = om.ScipyOptimizeDriver()
driver.options['optimizer'] = 'shgo'
driver.options['disp'] = False
driver.opt_settings['maxtime'] = 10  # seconds
driver.opt_settings['iters'] = 3
driver.opt_settings['maxiter'] = None

model.add_design_var('x', lower=-5.12*np.ones(size), upper=5.12*np.ones(size))
model.add_objective('f')
prob.setup()

prob.set_val('x', np.ones(size))
prob.run_driver()

print(prob.get_val('x'))
[0. 0. 0.]
print(prob.get_val('f'))
[0.]

Notice that when using the shgo optimizer, setting the opt_settings[‘maxiter’] to None overrides ScipyOptimizeDriver’s options[‘maxiter’] value. It is not possible to set options[‘maxiter’] to anything other than an integer so the opt_settings[‘maxiter’] option provides a way to set the maxiter value for the shgo optimizer to None.