modOptDriver#

modOptDriver wraps the optimizers available through the modOpt optimization framework. modOpt provides access to a variety of gradient-based and gradient-free optimization algorithms, including SLSQP, IPOPT, SNOPT, COBYLA, and others. Some of these are available in the package, some need to be separately installed, and some are commercial products that must be obtained from their respective authors (e.g. SNOPT). The modOptDriver supports sparse specification of constraint Jacobians, but not all optimizers can utilize the sparsity.

In this example, we use the SLSQP optimizer to minimize the objective of the Paraboloid problem.

from openmdao.utils.notebook_utils import get_code
from myst_nb import glue
glue("code_src020", get_code("openmdao.test_suite.components.paraboloid.Paraboloid"), display=False)
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.modOptDriver()
prob.driver.options['optimizer'] = 'SLSQP'
prob.driver.options['maxiter'] = 200
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()
Setting objective name as "f_xy".
Optimization terminated successfully    (Exit mode 0)
            Current function value: -27.33333333333333
            Iterations: 3
            Function evaluations: 4
            Gradient evaluations: 3
Optimization Complete
-----------------------------------
Problem: problem
Driver:  modOptDriver
  success     : True
  iterations  : 6
  runtime     : 3.6305E-02 s
  model_evals : 6
  model_time  : 4.9838E-04 s
  deriv_evals : 0
  deriv_time  : 0.0000E+00 s
  exit_status : SUCCESS

The “optimizer” option lets you choose which optimizer to use. modOptDriver provides access to a wide range of optimizers through the modOpt framework. The supported optimizers are (case sensitive):

Gradient-Based:

  • “SLSQP” - Sequential Least Squares Programming (default optimizer)

  • “PySLSQP” - Pure Python implementation of SLSQP with expanded features

  • “BFGS” - Broyden-Fletcher-Goldfarb-Shanno (unconstrained only)

  • “LBFGSB” - Limited-memory BFGS with bounds

  • “TrustConstr” - Trust-region constrained algorithm

  • “IPOPT” - Interior Point Optimizer

  • “SNOPT” - Sparse Nonlinear Optimizer (requires license)

  • “OpenSQP” - Sequential Quadratic Programming built into modOpt

Gradient-Free:

  • “COBYLA” - Constrained Optimization BY Linear Approximation

  • “COBYQA” - Constrained Optimization BY Quadratic Approximation (improved COBYLA)

  • “NelderMead” - Nelder-Mead simplex algorithm (unconstrained only)

Note

OpenMDAO installs only the base modOpt package. Some optimizers listed above require additional packages that must be installed manually in your environment. Most of the optimizers (SLSQP, BFGS, LBFGSB, TrustConstr, COBYLA, COBYQA, NelderMead) are available through SciPy and are included with the base modOpt installation.

print(prob.get_val('x'))
[6.66666667]
print(prob.get_val('y'))
[-7.33333333]

modOptDriver Options#

om.show_options_table("openmdao.drivers.modopt_driver.modOptDriver")

OptionDefaultAcceptable ValuesAcceptable TypesDescription
debug_print[]['desvars', 'nl_cons', 'ln_cons', 'objs', 'totals']['list']List of what type of Driver variables to print at each iteration.
dispTrueN/A['int', 'bool']Controls optimizer output verbosity. Can be bool (True/False) or int for fine control (0=quiet, higher=more verbose). Automatically maps to optimizer-specific settings. If optimizer specific verbosity settings are provided in the "opt_settings" attribute, then this option will be ignored and those settings will be used instead.
invalid_desvar_behaviorwarn['warn', 'raise', 'ignore']N/ABehavior of driver if the initial value of a design variable exceeds its bounds. The default value may beset using the `OPENMDAO_INVALID_DESVAR_BEHAVIOR` environment variable to one of the valid options.
maxiter200N/AN/AMaximum number of iterations.
optimizerSLSQP['SLSQP', 'IPOPT', 'BFGS', 'COBYQA', 'TrustConstr', 'SNOPT', 'LBFGSB', 'NelderMead', 'OpenSQP', 'PySLSQP', 'CVXOPT', 'COBYLA', 'ConvexQPSolvers']N/AName of optimizer to use
output_dirDEFAULT_REPORTS_DIRN/A['str', '_ReprClass']The directory to store all the output files generated from the optimization.
singular_jac_behaviorwarn['error', 'warn', 'ignore']N/ADefines behavior of a zero row/col check after first call to compute_totals: error - raise an error. warn - raise a warning. ignore - don't perform check.
singular_jac_tol1e-16N/AN/ATolerance for zero row/column check.
turn_off_outputsFalse[True, False]['bool']If True, prevents modOpt from generating any output files.

modOptDriver Constructor#

The call signature for the modOptDriver constructor is:

modOptDriver.__init__(**kwargs)[source]

Initialize the modOptDriver.

Parameters:
**kwargsdict of keyword arguments

Keyword arguments that will be mapped into the Driver options.

Using modOptDriver#

modOptDriver has a small number of unified options that can be specified as keyword arguments when it is instantiated or by using the “options” dictionary. We have already shown how to set the optimizer option. Next we will see how maxiter and disp can be used to control the maxinum number of iterations and what the optimizer displays. The “disp” option controls optimizer output verbosity. You can set it to True/False or an integer for fine control (0=quiet, higher=more verbose). This setting is automatically mapped to the optimizer’s output settings.

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.modOptDriver()
prob.driver.options['maxiter'] = 20
prob.driver.options['disp'] = False

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()
Setting objective name as "f_xy".
Problem: problem2
Driver:  modOptDriver
  success     : True
  iterations  : 6
  runtime     : 6.8236E-03 s
  model_evals : 6
  model_time  : 4.5012E-04 s
  deriv_evals : 0
  deriv_time  : 0.0000E+00 s
  exit_status : SUCCESS
print(prob.get_val('x'))
[6.66666667]
print(prob.get_val('y'))
[-7.33333333]

modOptDriver Optimizer-Specific Options#

Each optimizer in modOpt has its own set of specific options that control its behavior. You can set these optimizer-specific options through the opt_settings dictionary. See the modOpt documentation for detailed information about available settings for each optimizer.

For example, here’s code setting some specific options for the SLSQP optimizer:

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 = driver = om.modOptDriver()
driver.options['optimizer'] = 'SLSQP'
driver.options['maxiter'] = 100
driver.options['disp'] = False

# Set optimizer-specific options through opt_settings. Here we set the precision for
# the final solution with the "ftol" setting specific to SLSQP
driver.opt_settings['ftol'] = 1e-8

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()
Setting objective name as "f_xy".
Problem: problem3
Driver:  modOptDriver
  success     : True
  iterations  : 6
  runtime     : 5.8466E-03 s
  model_evals : 6
  model_time  : 4.6127E-04 s
  deriv_evals : 0
  deriv_time  : 0.0000E+00 s
  exit_status : SUCCESS