{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "cell-0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:50.706337Z",
     "iopub.status.busy": "2026-10-02T14:41:50.706093Z",
     "iopub.status.idle": "2026-10-02T14:41:50.710748Z",
     "shell.execute_reply": "2026-10-02T14:41:50.710159Z"
    },
    "papermill": {
     "duration": 0.008243,
     "end_time": "2026-10-02T14:41:50.711211+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:50.702968+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "active-ipynb",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from openmdao.utils.notebook_utils import notebook_mode  # noqa: F401\n",
    "except ImportError:\n",
    "    !python -m pip install openmdao[notebooks]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a08aa8e1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:50.716077Z",
     "iopub.status.busy": "2026-10-02T14:41:50.715923Z",
     "iopub.status.idle": "2026-10-02T14:41:51.058498Z",
     "shell.execute_reply": "2026-10-02T14:41:51.058002Z"
    },
    "papermill": {
     "duration": 0.347021,
     "end_time": "2026-10-02T14:41:51.060344+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:50.713323+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "plt.switch_backend('agg')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-1",
   "metadata": {
    "papermill": {
     "duration": 0.002655,
     "end_time": "2026-10-02T14:41:51.065529+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:51.062874+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# pymooDriver\n",
    "\n",
    "pymooDriver wraps the optimizer package pymoo, which provides a comprehensive suite of evolutionary and swarm-based single- and multi-objective optimization algorithms. Unlike gradient-based drivers, pymooDriver requires no derivatives from the model.\n",
    "\n",
    "In this example, we use the DE (Differential Evolution) optimizer to minimize the objective of the Paraboloid problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "cell-2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:51.071546Z",
     "iopub.status.busy": "2026-10-02T14:41:51.071294Z",
     "iopub.status.idle": "2026-10-02T14:41:52.841915Z",
     "shell.execute_reply": "2026-10-02T14:41:52.841413Z"
    },
    "papermill": {
     "duration": 1.774658,
     "end_time": "2026-10-02T14:41:52.842801+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:51.068143+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/modopt/core/visualization.py:11: UserWarning: matplotlib not found, plotting disabled.\n",
      "  warnings.warn(\"matplotlib not found, plotting disabled.\")\n"
     ]
    },
    {
     "data": {
      "application/papermill.record/text/html": "<style>pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.output_html .hll { background-color: #ffffcc }\n.output_html { background: #f8f8f8; }\n.output_html .c { color: #3D7B7B; font-style: italic } /* Comment */\n.output_html .err { border: 1px solid #F00 } /* Error */\n.output_html .k { color: #008000; font-weight: bold } /* Keyword */\n.output_html .o { color: #666 } /* Operator */\n.output_html .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */\n.output_html .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */\n.output_html .cp { color: #9C6500 } /* Comment.Preproc */\n.output_html .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */\n.output_html .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */\n.output_html .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */\n.output_html .gd { color: #A00000 } /* Generic.Deleted */\n.output_html .ge { font-style: italic } /* Generic.Emph */\n.output_html .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */\n.output_html .gr { color: #E40000 } /* Generic.Error */\n.output_html .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.output_html .gi { color: #008400 } /* Generic.Inserted */\n.output_html .go { color: #717171 } /* Generic.Output */\n.output_html .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.output_html .gs { font-weight: bold } /* Generic.Strong */\n.output_html .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.output_html .gt { color: #04D } /* Generic.Traceback */\n.output_html .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.output_html .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.output_html .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.output_html .kp { color: #008000 } /* Keyword.Pseudo */\n.output_html .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.output_html .kt { color: #B00040 } /* Keyword.Type */\n.output_html .m { color: #666 } /* Literal.Number */\n.output_html .s { color: #BA2121 } /* Literal.String */\n.output_html .na { color: #687822 } /* Name.Attribute */\n.output_html .nb { color: #008000 } /* Name.Builtin */\n.output_html .nc { color: #00F; font-weight: bold } /* Name.Class */\n.output_html .no { color: #800 } /* Name.Constant */\n.output_html .nd { color: #A2F } /* Name.Decorator */\n.output_html .ni { color: #717171; font-weight: bold } /* Name.Entity */\n.output_html .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */\n.output_html .nf { color: #00F } /* Name.Function */\n.output_html .nl { color: #767600 } /* Name.Label */\n.output_html .nn { color: #00F; font-weight: bold } /* Name.Namespace */\n.output_html .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.output_html .nv { color: #19177C } /* Name.Variable */\n.output_html .ow { color: #A2F; font-weight: bold } /* Operator.Word */\n.output_html .w { color: #BBB } /* Text.Whitespace */\n.output_html .mb { color: #666 } /* Literal.Number.Bin */\n.output_html .mf { color: #666 } /* Literal.Number.Float */\n.output_html .mh { color: #666 } /* Literal.Number.Hex */\n.output_html .mi { color: #666 } /* Literal.Number.Integer */\n.output_html .mo { color: #666 } /* Literal.Number.Oct */\n.output_html .sa { color: #BA2121 } /* Literal.String.Affix */\n.output_html .sb { color: #BA2121 } /* Literal.String.Backtick */\n.output_html .sc { color: #BA2121 } /* Literal.String.Char */\n.output_html .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.output_html .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.output_html .s2 { color: #BA2121 } /* Literal.String.Double */\n.output_html .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */\n.output_html .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.output_html .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */\n.output_html .sx { color: #008000 } /* Literal.String.Other */\n.output_html .sr { color: #A45A77 } /* Literal.String.Regex */\n.output_html .s1 { color: #BA2121 } /* Literal.String.Single */\n.output_html .ss { color: #19177C } /* Literal.String.Symbol */\n.output_html .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.output_html .fm { color: #00F } /* Name.Function.Magic */\n.output_html .vc { color: #19177C } /* Name.Variable.Class */\n.output_html .vg { color: #19177C } /* Name.Variable.Global */\n.output_html .vi { color: #19177C } /* Name.Variable.Instance */\n.output_html .vm { color: #19177C } /* Name.Variable.Magic */\n.output_html .il { color: #666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Paraboloid</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ExplicitComponent</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Evaluates the equation f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;f_xy&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;*&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">compute</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">outputs</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3</span>\n\n<span class=\"sd\">        Optimal solution (minimum): x = 6.6667; y = -7.3333</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">]</span>\n\n        <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;f_xy&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">-</span><span class=\"mf\">3.0</span><span class=\"p\">)</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"n\">x</span><span class=\"o\">*</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"p\">(</span><span class=\"n\">y</span><span class=\"o\">+</span><span class=\"mf\">4.0</span><span class=\"p\">)</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">-</span> <span class=\"mf\">3.0</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">compute_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">partials</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Jacobian for our paraboloid.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">]</span>\n\n        <span class=\"n\">partials</span><span class=\"p\">[</span><span class=\"s1\">&#39;f_xy&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;x&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"mf\">6.0</span> <span class=\"o\">+</span> <span class=\"n\">y</span>\n        <span class=\"n\">partials</span><span class=\"p\">[</span><span class=\"s1\">&#39;f_xy&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">y</span> <span class=\"o\">+</span> <span class=\"mf\">8.0</span> <span class=\"o\">+</span> <span class=\"n\">x</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{Paraboloid}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{ExplicitComponent}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{    Evaluates the equation f(x,y) = (x\\PYZhy{}3)\\PYZca{}2 + xy + (y+4)\\PYZca{}2 \\PYZhy{} 3.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{0.0}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{0.0}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{f\\PYZus{}xy}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{0.0}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{compute}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{outputs}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        f(x,y) = (x\\PYZhy{}3)\\PYZca{}2 + xy + (y+4)\\PYZca{}2 \\PYZhy{} 3}\n\n\\PY{l+s+sd}{        Optimal solution (minimum): x = 6.6667; y = \\PYZhy{}7.3333}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n}{x} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{y} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n        \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{f\\PYZus{}xy}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{p}{(}\\PY{n}{x}\\PY{o}{\\PYZhy{}}\\PY{l+m+mf}{3.0}\\PY{p}{)}\\PY{o}{*}\\PY{o}{*}\\PY{l+m+mi}{2} \\PY{o}{+} \\PY{n}{x}\\PY{o}{*}\\PY{n}{y} \\PY{o}{+} \\PY{p}{(}\\PY{n}{y}\\PY{o}{+}\\PY{l+m+mf}{4.0}\\PY{p}{)}\\PY{o}{*}\\PY{o}{*}\\PY{l+m+mi}{2} \\PY{o}{\\PYZhy{}} \\PY{l+m+mf}{3.0}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{compute\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{partials}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Jacobian for our paraboloid.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n}{x} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{y} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n        \\PY{n}{partials}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{f\\PYZus{}xy}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mf}{2.0}\\PY{o}{*}\\PY{n}{x} \\PY{o}{\\PYZhy{}} \\PY{l+m+mf}{6.0} \\PY{o}{+} \\PY{n}{y}\n        \\PY{n}{partials}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{f\\PYZus{}xy}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mf}{2.0}\\PY{o}{*}\\PY{n}{y} \\PY{o}{+} \\PY{l+m+mf}{8.0} \\PY{o}{+} \\PY{n}{x}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class Paraboloid(om.ExplicitComponent):\n    \"\"\"\n    Evaluates the equation f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3.\n    \"\"\"\n\n    def setup(self):\n        self.add_input('x', val=0.0)\n        self.add_input('y', val=0.0)\n\n        self.add_output('f_xy', val=0.0)\n\n    def setup_partials(self):\n        self.declare_partials('*', '*')\n\n    def compute(self, inputs, outputs):\n        \"\"\"\n        f(x,y) = (x-3)^2 + xy + (y+4)^2 - 3\n\n        Optimal solution (minimum): x = 6.6667; y = -7.3333\n        \"\"\"\n        x = inputs['x']\n        y = inputs['y']\n\n        outputs['f_xy'] = (x-3.0)**2 + x*y + (y+4.0)**2 - 3.0\n\n    def compute_partials(self, inputs, partials):\n        \"\"\"\n        Jacobian for our paraboloid.\n        \"\"\"\n        x = inputs['x']\n        y = inputs['y']\n\n        partials['f_xy', 'x'] = 2.0*x - 6.0 + y\n        partials['f_xy', 'y'] = 2.0*y + 8.0 + x"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_pymoo_paraboloid"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue('code_pymoo_paraboloid', get_code('openmdao.test_suite.components.paraboloid.Paraboloid'), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-3",
   "metadata": {
    "papermill": {
     "duration": 0.001672,
     "end_time": "2026-10-02T14:41:52.846416+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:52.844744+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Paraboloid` class definition\n",
    "\n",
    "{glue:}`code_pymoo_paraboloid`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "cell-4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:52.850493Z",
     "iopub.status.busy": "2026-10-02T14:41:52.850300Z",
     "iopub.status.idle": "2026-10-02T14:41:57.122346Z",
     "shell.execute_reply": "2026-10-02T14:41:57.121640Z"
    },
    "papermill": {
     "duration": 4.274852,
     "end_time": "2026-10-02T14:41:57.122964+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:52.848112+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952114.050868] [runnervm8df0l:6903 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55eb457fffb0 failed to create UD QP TX wr:256 sge:6 inl:64 resp:0 RX wr:4096 sge:1 resp:0 failed: Operation not supported\n",
      "[1790952114.051113] [runnervm8df0l:6903 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:06903] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Problem: problem\n",
       "Driver:  pymooDriver\n",
       "  success     : True\n",
       "  iterations  : 10002\n",
       "  runtime     : 2.7425E+00 s\n",
       "  model_evals : 10002\n",
       "  model_time  : 4.5856E-01 s\n",
       "  deriv_evals : 0\n",
       "  deriv_time  : 0.0000E+00 s\n",
       "  exit_status : SUCCESS"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.paraboloid import Paraboloid\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('comp', Paraboloid(), promotes=['*'])\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'DE'\n",
    "prob.driver.options['disp'] = False\n",
    "prob.driver.run_settings['seed'] = 11\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 100)\n",
    "\n",
    "model.add_design_var('x', lower=-50.0, upper=50.0)\n",
    "model.add_design_var('y', lower=-50.0, upper=50.0)\n",
    "model.add_objective('f_xy')\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 50.0)\n",
    "prob.set_val('y', 50.0)\n",
    "\n",
    "prob.run_driver()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "cell-5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:57.129275Z",
     "iopub.status.busy": "2026-10-02T14:41:57.129111Z",
     "iopub.status.idle": "2026-10-02T14:41:57.132003Z",
     "shell.execute_reply": "2026-10-02T14:41:57.131443Z"
    },
    "papermill": {
     "duration": 0.00655,
     "end_time": "2026-10-02T14:41:57.132423+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.125873+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6.66666664]\n",
      "[-7.33333334]\n"
     ]
    }
   ],
   "source": [
    "print(prob.get_val('x'))\n",
    "print(prob.get_val('y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cell-6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:57.274546Z",
     "iopub.status.busy": "2026-10-02T14:41:57.274375Z",
     "iopub.status.idle": "2026-10-02T14:41:57.278173Z",
     "shell.execute_reply": "2026-10-02T14:41:57.277733Z"
    },
    "papermill": {
     "duration": 0.006996,
     "end_time": "2026-10-02T14:41:57.278660+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.271664+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(5.4260736756637066e-09)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "assert_near_equal(prob.get_val('x'), 6.66666667, 1e-3)\n",
    "assert_near_equal(prob.get_val('y'), -7.3333333, 1e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-7",
   "metadata": {
    "papermill": {
     "duration": 0.002131,
     "end_time": "2026-10-02T14:41:57.282765+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.280634+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The `optimizer` option selects which pymoo algorithm to use. pymooDriver supports\n",
    "the following optimizers (case sensitive):\n",
    "\n",
    "**Single-Objective**:\n",
    "- `'GA'` - Genetic Algorithm\n",
    "- `'DE'` - Differential Evolution\n",
    "- `'CMAES'` - Covariance Matrix Adaptation Evolution Strategy\n",
    "- `'NelderMead'` - Nelder-Mead simplex algorithm\n",
    "- `'MixedVariableGA'` - Genetic Algorithm with support for discrete (integer) and mixed integer design variables\n",
    "- and others — see the [pymoo documentation](https://pymoo.org/algorithms/list.html) for the full list\n",
    "\n",
    "**Multi-Objective**:\n",
    "- `'NSGA2'` - Non-dominated Sorting Genetic Algorithm II\n",
    "- `'NSGA3'` - Non-dominated Sorting Genetic Algorithm III\n",
    "- `'MOEAD'` - Multi-Objective Evolutionary Algorithm Based on Decomposition\n",
    "- `'CTAEA'` - Constrained Two-Archive Evolutionary Algorithm\n",
    "- and others — see the [pymoo documentation](https://pymoo.org/algorithms/list.html) for the full list\n",
    "\n",
    "Not all algorithms support constraints. Algorithms that explicitly assert no constraints\n",
    "(e.g. `'DNSGA2'`, `'KGB'`) will raise an error if constraints are added. See the\n",
    "[pymoo algorithm table](https://pymoo.org/algorithms/list.html) for constraint support\n",
    "details per algorithm. Also note that there are some algorithms available in pymoo which are not explicitly documented in the \"algorithms\" page in their documentation."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-8",
   "metadata": {
    "papermill": {
     "duration": 0.002166,
     "end_time": "2026-10-02T14:41:57.287166+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.285000+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## pymooDriver Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "cell-9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:57.292644Z",
     "iopub.status.busy": "2026-10-02T14:41:57.292506Z",
     "iopub.status.idle": "2026-10-02T14:41:57.296614Z",
     "shell.execute_reply": "2026-10-02T14:41:57.295935Z"
    },
    "papermill": {
     "duration": 0.007908,
     "end_time": "2026-10-02T14:41:57.297280+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.289372+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<!DOCTYPE html>\n",
       "<html lang=\"en\">\n",
       "<head>\n",
       "    <style>\n",
       "        h2 {\n",
       "            text-align: center;\n",
       "        }\n",
       "    </style>\n",
       "</head>\n",
       "<body>\n",
       "    <h2></h2>\n",
       "        <table style=\"border: 1px solid #999; border-collapse: collapse;\">\n",
       "        <tr><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Option</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Default</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Values</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Types</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Description</th></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">debug_print</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;desvars&#x27;, &#x27;nl_cons&#x27;, &#x27;ln_cons&#x27;, &#x27;objs&#x27;, &#x27;totals&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;list&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">List of what type of Driver variables to print at each iteration.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">disp</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;, &#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Controls optimizer output verbosity. Not used if &quot;verbose&quot; is manually set in &quot;self.run_settings&quot;.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">invalid_desvar_behavior</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">warn</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;warn&#x27;, &#x27;raise&#x27;, &#x27;ignore&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Behavior 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.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">optimizer</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">GA</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;DNSGA2&#x27;, &#x27;ISRES&#x27;, &#x27;MixedVariableGA&#x27;, &#x27;UNSGA3&#x27;, &#x27;DE&#x27;, &#x27;GA&#x27;, &#x27;Optuna&#x27;, &#x27;AGEMOEA2&#x27;, &#x27;MOPSO_CD&#x27;, &#x27;DIRECT&#x27;, &#x27;RandomSearch&#x27;, &#x27;NSGA3&#x27;, &#x27;RVEA&#x27;, &#x27;MOEAD&#x27;, &#x27;KGB&#x27;, &#x27;NSGA2&#x27;, &#x27;G3PCX&#x27;, &#x27;BRKGA&#x27;, &#x27;NelderMead&#x27;, &#x27;CMAES&#x27;, &#x27;NicheGA&#x27;, &#x27;AGEMOEA&#x27;, &#x27;SMSEMOA&#x27;, &#x27;PINSGA2&#x27;, &#x27;ES&#x27;, &#x27;SRES&#x27;, &#x27;PSO&#x27;, &#x27;EPPSO&#x27;, &#x27;CTAEA&#x27;, &#x27;CMOPSO&#x27;, &#x27;RNSGA3&#x27;, &#x27;NRBO&#x27;, &#x27;RNSGA2&#x27;, &#x27;PatternSearch&#x27;, &#x27;SPEA2&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Name of optimizer to use</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">procs_per_model</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Number of processors to give each model under MPI.</td></tr>\n",
       "    </table>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "om.show_options_table('openmdao.drivers.pymoo_driver.pymooDriver')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-10",
   "metadata": {
    "papermill": {
     "duration": 0.002271,
     "end_time": "2026-10-02T14:41:57.301822+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.299551+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## pymooDriver Constructor\n",
    "\n",
    "The call signature for the *pymooDriver* constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.drivers.pymoo_driver.pymooDriver.__init__\n",
    "       :noindex:\n",
    "```\n",
    "\n",
    "## Using pymooDriver\n",
    "\n",
    "pymooDriver has a small number of unified options that can be set as keyword arguments when it is instantiated or through the `options` dictionary. We have already shown how to set the `optimizer` option. The `disp` option controls whether pymooDriver prints a completion message when the optimization finishes and iteration level outputs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cell-11",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:57.307588Z",
     "iopub.status.busy": "2026-10-02T14:41:57.307412Z",
     "iopub.status.idle": "2026-10-02T14:41:57.473821Z",
     "shell.execute_reply": "2026-10-02T14:41:57.473331Z"
    },
    "papermill": {
     "duration": 0.170113,
     "end_time": "2026-10-02T14:41:57.474473+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.304360+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=================================================\n",
      "n_gen  |  n_eval  |     f_avg     |     f_min    \n",
      "=================================================\n",
      "     1 |      100 |  1.609885E+03 | -5.859455E-01\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     2 |      200 |  8.671655E+02 | -9.761698E+00\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     3 |      300 |  6.154968E+02 | -9.761698E+00\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     4 |      400 |  4.060902E+02 | -2.324155E+01\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "     5 |      500 |  2.987649E+02 | -2.324155E+01\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization Complete\n",
      "-----------------------------------\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Problem: problem2\n",
       "Driver:  pymooDriver\n",
       "  success     : True\n",
       "  iterations  : 502\n",
       "  runtime     : 1.5870E-01 s\n",
       "  model_evals : 502\n",
       "  model_time  : 2.7274E-02 s\n",
       "  deriv_evals : 0\n",
       "  deriv_time  : 0.0000E+00 s\n",
       "  exit_status : SUCCESS"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.paraboloid import Paraboloid\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('comp', Paraboloid(), promotes=['*'])\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'DE'\n",
    "prob.driver.options['disp'] = True\n",
    "prob.driver.run_settings['seed'] = 11\n",
    "# The optimization will fail at only 5 generations, but we purposely make the number\n",
    "# of generations small just to demonstrate the print outs when 'disp' = True\n",
    "# without flooding the page.\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 5)\n",
    "\n",
    "model.add_design_var('x', lower=-50.0, upper=50.0)\n",
    "model.add_design_var('y', lower=-50.0, upper=50.0)\n",
    "model.add_objective('f_xy')\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-12",
   "metadata": {
    "papermill": {
     "duration": 0.003459,
     "end_time": "2026-10-02T14:41:57.480879+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.477420+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Algorithm Settings\n",
    "\n",
    "Each pymoo algorithm has its own set of hyperparameters that control the structure of the algorithm — for example, population size, crossover and mutation operators. These are passed to the algorithm constructor via the `alg_settings` dictionary. See the [pymoo documentation](https://pymoo.org) and navigate to the page for an algorithm to see the available settings.\n",
    "\n",
    "Here, we set the population size for the GA using the `alg_settings`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "cell-13",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:57.485898Z",
     "iopub.status.busy": "2026-10-02T14:41:57.485717Z",
     "iopub.status.idle": "2026-10-02T14:42:03.222633Z",
     "shell.execute_reply": "2026-10-02T14:42:03.221914Z"
    },
    "papermill": {
     "duration": 5.74061,
     "end_time": "2026-10-02T14:42:03.223616+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:57.483006+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6.66946593]\n",
      "[-7.33235093]\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.paraboloid import Paraboloid\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('comp', Paraboloid(), promotes=['*'])\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'GA'\n",
    "prob.driver.options['disp'] = False\n",
    "prob.driver.alg_settings['pop_size'] = 50\n",
    "prob.driver.run_settings['seed'] = 11\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 400)\n",
    "\n",
    "model.add_design_var('x', lower=-50.0, upper=50.0)\n",
    "model.add_design_var('y', lower=-50.0, upper=50.0)\n",
    "model.add_objective('f_xy')\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()\n",
    "\n",
    "print(prob.get_val('x'))\n",
    "print(prob.get_val('y'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-14",
   "metadata": {
    "papermill": {
     "duration": 0.013021,
     "end_time": "2026-10-02T14:42:03.239183+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:03.226162+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Run Settings\n",
    "\n",
    "Run-level settings that control how the optimization executes — such as the random seed, verbosity, termination criterion, and callback — are passed via the `run_settings` dictionary. These are forwarded to `pymoo.optimize.minimize()` and subsequently to `algorithm.setup()`.\n",
    "\n",
    "Common run settings include:\n",
    "\n",
    "- `'seed'` — integer random seed for reproducibility\n",
    "- `'verbose'` — whether to print iteration-level progress (overrides `disp` option if set)\n",
    "- `'termination'` — a pymoo termination object or shorthand tuple such as `('n_gen', 200)`\n",
    "- `'save_history'` — whether to store per-generation history in the results object\n",
    "- `'callback'` — a pymoo callback object called after each generation\n",
    "\n",
    "See the pymoo documentation for the [minimize](https://pymoo.org/interface/minimize.html) function for most of the available settings. Note that depending on which optimizer you choose, there may be slightly different run settings keys available which aren't shown in that link. It is not explicitly documented in pymoo which algorithms allow exactly which run settings. Here, we set a seed for reproducibility and a generation-based termination criterion in the `run_settings`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "cell-15",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:03.245472Z",
     "iopub.status.busy": "2026-10-02T14:42:03.245302Z",
     "iopub.status.idle": "2026-10-02T14:42:13.107137Z",
     "shell.execute_reply": "2026-10-02T14:42:13.106521Z"
    },
    "papermill": {
     "duration": 9.866277,
     "end_time": "2026-10-02T14:42:13.108177+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:03.241900+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6.66666667]\n",
      "[-7.33333335]\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.paraboloid import Paraboloid\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('comp', Paraboloid(), promotes=['*'])\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'DE'\n",
    "prob.driver.options['disp'] = False\n",
    "prob.driver.run_settings['seed'] = 42\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 400)\n",
    "prob.driver.run_settings['verbose'] = False\n",
    "\n",
    "model.add_design_var('x', lower=-50.0, upper=50.0)\n",
    "model.add_design_var('y', lower=-50.0, upper=50.0)\n",
    "model.add_objective('f_xy')\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()\n",
    "\n",
    "print(prob.get_val('x'))\n",
    "print(prob.get_val('y'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ld1qazcyj4j",
   "metadata": {
    "papermill": {
     "duration": 0.003098,
     "end_time": "2026-10-02T14:42:13.114948+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:13.111850+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Constrained Optimization\n",
    "\n",
    "Constraints are supported by most pymoo algorithms (see the optimizer list above). Inequality and equality constraints defined via `add_constraint()` are automatically translated to pymoo's convention and passed to the algorithm. A solution is considered successful if there is a feasible solution found in the final population. Note that pymoo hard codes a small tolerance for equality constraints (1e-4) into its constraint violation calculation by default.\n",
    "\n",
    "Here, we minimize the Paraboloid subject to an inequality constraint `x + y >= 15`, which forces the optimum away from the unconstrained minimum:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "vc5on2mfno",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:13.240422Z",
     "iopub.status.busy": "2026-10-02T14:42:13.240204Z",
     "iopub.status.idle": "2026-10-02T14:42:25.320789Z",
     "shell.execute_reply": "2026-10-02T14:42:25.320030Z"
    },
    "papermill": {
     "duration": 12.085363,
     "end_time": "2026-10-02T14:42:25.321236+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:13.235873+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[14.84206237]\n",
      "[0.15793763]\n",
      "x + y = [15.]\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.paraboloid import Paraboloid\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('comp', Paraboloid(), promotes=['*'])\n",
    "model.add_subsystem('con', om.ExecComp('g = x + y'), promotes=['*'])\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'GA'\n",
    "prob.driver.options['disp'] = False\n",
    "prob.driver.run_settings['seed'] = 11\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 400)\n",
    "\n",
    "model.add_design_var('x', lower=-50.0, upper=50.0)\n",
    "model.add_design_var('y', lower=-50.0, upper=50.0)\n",
    "model.add_objective('f_xy')\n",
    "model.add_constraint('g', lower=15.0)\n",
    "\n",
    "model.set_input_defaults('y', val=0.0)\n",
    "model.set_input_defaults('x', val=0.0)\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()\n",
    "\n",
    "print(prob.get_val('x'))\n",
    "print(prob.get_val('y'))\n",
    "print('x + y =', prob.get_val('x') + prob.get_val('y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2zf996g254i",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:25.326136Z",
     "iopub.status.busy": "2026-10-02T14:42:25.325988Z",
     "iopub.status.idle": "2026-10-02T14:42:25.328975Z",
     "shell.execute_reply": "2026-10-02T14:42:25.328212Z"
    },
    "papermill": {
     "duration": 0.005954,
     "end_time": "2026-10-02T14:42:25.329397+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:25.323443+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-output",
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "# Constraint x + y >= 15 should be satisfied\n",
    "assert prob.get_val('x') + prob.get_val('y') >= 15.0 - 1e-3"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dajko1i29w",
   "metadata": {
    "papermill": {
     "duration": 0.00177,
     "end_time": "2026-10-02T14:42:25.333052+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:25.331282+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Integer and Mixed Integer Optimization\n",
    "\n",
    "Discrete (integer) design variables are supported via the `MixedVariableGA` optimizer. This is the only pymoo algorithm that uses pymoo's mixed-variable-aware sampling and mating operators, which are required to correctly search integer and mixed integer/continuous spaces. Using any other optimizer with discrete design variables will raise an error.\n",
    "\n",
    "In this example, we minimize a simple function of one continuous and one integer design variable. The optimal solution is at `x = 2.5`, `n = 3`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "1zt4g1o9zgp",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:25.337443Z",
     "iopub.status.busy": "2026-10-02T14:42:25.337272Z",
     "iopub.status.idle": "2026-10-02T14:42:28.522069Z",
     "shell.execute_reply": "2026-10-02T14:42:28.521274Z"
    },
    "papermill": {
     "duration": 3.187691,
     "end_time": "2026-10-02T14:42:28.522556+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:25.334865+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x = [2.49988947]\n",
      "n = 3\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "\n",
    "\n",
    "class MixedComp(om.ExplicitComponent):\n",
    "    \"\"\"Minimize f = (x - 2.5)^2 + (n - 3)^2 with x continuous and n integer.\"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        self.add_input('x', val=0.0)\n",
    "        self.add_discrete_input('n', val=0)\n",
    "        self.add_output('f', val=0.0)\n",
    "\n",
    "    def setup_partials(self):\n",
    "        self.declare_partials('f', 'x')\n",
    "\n",
    "    def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):\n",
    "        outputs['f'] = (inputs['x'] - 2.5)**2 + (discrete_inputs['n'] - 3)**2\n",
    "\n",
    "    def compute_partials(self, inputs, partials, discrete_inputs):\n",
    "        partials['f', 'x'] = 2.0 * (inputs['x'] - 2.5)\n",
    "\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model.add_subsystem('comp', MixedComp())\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'MixedVariableGA'\n",
    "prob.driver.options['disp'] = False\n",
    "prob.driver.run_settings['seed'] = 11\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 200)\n",
    "\n",
    "prob.model.add_design_var('comp.x', lower=-10.0, upper=10.0)\n",
    "prob.model.add_design_var('comp.n', lower=0, upper=10)\n",
    "prob.model.add_objective('comp.f')\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()\n",
    "\n",
    "print('x =', prob.get_val('comp.x'))\n",
    "print('n =', prob.get_val('comp.n'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "3vy75yhumra",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:28.527629Z",
     "iopub.status.busy": "2026-10-02T14:42:28.527471Z",
     "iopub.status.idle": "2026-10-02T14:42:28.530198Z",
     "shell.execute_reply": "2026-10-02T14:42:28.529545Z"
    },
    "papermill": {
     "duration": 0.005772,
     "end_time": "2026-10-02T14:42:28.530608+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.524836+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(prob.get_val('comp.x'), 2.5, 1e-2)\n",
    "assert prob.get_val('comp.n') == 3"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-16",
   "metadata": {
    "papermill": {
     "duration": 0.001969,
     "end_time": "2026-10-02T14:42:28.534595+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.532626+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Multi-Objective Optimization\n",
    "\n",
    "pymooDriver supports multi-objective optimization through pymoo's Pareto-based algorithms such as NSGA2. When a multi-objective optimizer is used, the model is left at the state of the last function evaluation after `run_driver()` completes. The full Pareto front is stored on the driver in `driver.pareto`, which contains:\n",
    "\n",
    "- `driver.pareto['X']` — dict mapping each design variable name to its values across all Pareto solutions\n",
    "- `driver.pareto['F']` — dict mapping each objective name to its values across all Pareto solutions\n",
    "- `driver.pareto['X_raw']` — raw design variable array, shape `(n_solutions, n_vars)`, for use with pymoo utilities\n",
    "- `driver.pareto['F_raw']` — raw objective array, shape `(n_solutions, n_objs)`, for use with pymoo utilities\n",
    "\n",
    "In this example, we minimize two competing objectives over a single design variable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "cell-17",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:28.542119Z",
     "iopub.status.busy": "2026-10-02T14:42:28.541986Z",
     "iopub.status.idle": "2026-10-02T14:42:34.313758Z",
     "shell.execute_reply": "2026-10-02T14:42:34.313135Z"
    },
    "papermill": {
     "duration": 5.777982,
     "end_time": "2026-10-02T14:42:34.314549+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.536567+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Problem: problem7\n",
       "Driver:  pymooDriver\n",
       "  success     : True\n",
       "  iterations  : 20001\n",
       "  runtime     : 5.4589E+00 s\n",
       "  model_evals : 20001\n",
       "  model_time  : 8.2912E-01 s\n",
       "  deriv_evals : 0\n",
       "  deriv_time  : 0.0000E+00 s\n",
       "  exit_status : SUCCESS"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "# Two competing objectives: f1 = x^2, f2 = (x - 2)^2\n",
    "# Pareto front spans x in [0, 2]\n",
    "exec_comp = model.add_subsystem('exec', om.ExecComp(['f1 = x**2', 'f2 = (x - 2.0)**2'],\n",
    "                                                    x=0.0, f1=0.0, f2=0.0))\n",
    "\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'NSGA2'\n",
    "prob.driver.options['disp'] = False\n",
    "prob.driver.run_settings['seed'] = 42\n",
    "prob.driver.run_settings['termination'] = ('n_gen', 200)\n",
    "\n",
    "model.add_design_var('exec.x', lower=0.0, upper=3.0)\n",
    "model.add_objective('exec.f1')\n",
    "model.add_objective('exec.f2')\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "cell-18",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:34.322110Z",
     "iopub.status.busy": "2026-10-02T14:42:34.321896Z",
     "iopub.status.idle": "2026-10-02T14:42:34.390827Z",
     "shell.execute_reply": "2026-10-02T14:42:34.390203Z"
    },
    "papermill": {
     "duration": 0.07363,
     "end_time": "2026-10-02T14:42:34.391445+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:34.317815+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pymoo.visualization.scatter.Scatter at 0x7fc480b8f0e0>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pymoo.visualization.scatter import Scatter\n",
    "\n",
    "plot = Scatter()\n",
    "plot.add(prob.driver.pareto['F_raw'], facecolor=\"none\", edgecolor=\"red\")\n",
    "plot.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "815639c9",
   "metadata": {
    "papermill": {
     "duration": 0.002884,
     "end_time": "2026-10-02T14:42:34.397351+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:34.394467+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "![](scatter.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "cell-19",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:34.404303Z",
     "iopub.status.busy": "2026-10-02T14:42:34.404108Z",
     "iopub.status.idle": "2026-10-02T14:42:34.409415Z",
     "shell.execute_reply": "2026-10-02T14:42:34.408774Z"
    },
    "papermill": {
     "duration": 0.009673,
     "end_time": "2026-10-02T14:42:34.409852+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:34.400179+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.0418428389845644e-05)"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "x_pareto = prob.driver.pareto['X']['exec.x']\n",
    "f1_pareto = prob.driver.pareto['F']['exec.f1']\n",
    "f2_pareto = prob.driver.pareto['F']['exec.f2']\n",
    "\n",
    "assert x_pareto is not None\n",
    "assert f1_pareto is not None\n",
    "# Pareto front should span x in [0, 2]\n",
    "assert_near_equal(x_pareto.min(), 0.0, 1e-2)\n",
    "assert_near_equal(x_pareto.max(), 2.0, 1e-2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-20",
   "metadata": {
    "papermill": {
     "duration": 0.002869,
     "end_time": "2026-10-02T14:42:34.415714+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:34.412845+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The raw pymoo result object is also available at `prob.driver.pymoo_results` for any algorithm so users can access additional information such as execution time, algorithm state, and population history (if `save_history=True` was set in `run_settings`)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "td11w4tnuef",
   "metadata": {
    "papermill": {
     "duration": 0.003166,
     "end_time": "2026-10-02T14:42:34.515107+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:34.511941+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Parallel Evaluation with MPI\n",
    "\n",
    "pymooDriver automatically enables population-level parallelism when more than one MPI rank is available. The population is distributed round-robin across ranks so that multiple individuals are evaluated simultaneously.\n",
    "\n",
    "```{note}\n",
    "MPI parallelism requires an MPI installation and must be launched with ``mpirun`` or equivalent.\n",
    "```\n",
    "\n",
    "### Basic parallel usage\n",
    "```bash\n",
    "mpirun -n 4 python my_optimization.py\n",
    "```\n",
    "\n",
    "```python\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'GA'\n",
    "```\n",
    "\n",
    "With 4 ranks this evaluates 4 individuals simultaneously, giving roughly a 4x speedup in function evaluations for computationally expensive models.\n",
    "\n",
    "### Models with parallel components\n",
    "\n",
    "If the model itself contains parallel components (e.g. `ParallelGroup`), set the `procs_per_model` option to the number of MPI ranks each model evaluation requires. The total number of ranks must be evenly divisible by `procs_per_model`.\n",
    "\n",
    "```python\n",
    "prob.driver = om.pymooDriver()\n",
    "prob.driver.options['optimizer'] = 'GA'\n",
    "prob.driver.options['procs_per_model'] = 2  # each model uses 2 ranks\n",
    "```\n",
    "\n",
    "With 8 total ranks and `procs_per_model=2`, there are 4 groups of 2 ranks each. Each group cooperates on one model evaluation, so 4 individuals in the pymoo population are evaluated simultaneously.\n",
    "\n",
    "```bash\n",
    "mpirun -n 8 python my_optimization.py\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "om-dev",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 45.273252,
   "end_time": "2026-10-02T14:42:35.334353+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/drivers/pymoo_driver.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/drivers/pymoo_driver.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:41:50.061101+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}