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
-----------------------------------
False
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 ['COBYLA', 'trust-constr', 'Powell', 'TNC', 'differential_evolution', 'Nelder-Mead', 'CG', 'dual_annealing', 'Newton-CG', 'BFGS', 'L-BFGS-B', 'SLSQP', 'basinhopping', 'shgo']N/A Name of optimizer to use
singular_jac_behaviorwarn ['error', 'warn', 'ignore'] N/A Defines behavior of a zero row/col check after first call tocompute_totals:error - raise an error.warn - raise a warning.ignore - don't perform check.
singular_jac_tol 1e-16 N/A N/A Tolerance for zero row/column check.
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
-----------------------------------
False
   Normal return from subroutine COBYLA

   NFVALS =  124   F =-2.733333E+01    MAXCV = 0.000000E+00
   X = 6.666667E+00  -7.333332E+00
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
-----------------------------------
False
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
-----------------------------------
False
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)
        
        self.declare_partials(of='f', wrt='x', method='cs')

    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', 2*np.ones(size))
prob.run_driver()
/usr/share/miniconda/envs/test/lib/python3.8/site-packages/openmdao/core/total_jac.py:1539: DerivativesWarning:Constraints or objectives [('rastrigin.f', inds=[0])] cannot be impacted by the design variables of the problem.
/usr/share/miniconda/envs/test/lib/python3.8/site-packages/openmdao/core/total_jac.py:1564: DerivativesWarning:Design variables [('x', inds=[0, 1, 2])] have no impact on the constraints or objective.
False
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.