{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4864c680",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:41.970306Z",
     "iopub.status.busy": "2026-10-02T14:40:41.970118Z",
     "iopub.status.idle": "2026-10-02T14:40:41.974409Z",
     "shell.execute_reply": "2026-10-02T14:40:41.973792Z"
    },
    "papermill": {
     "duration": 0.006919,
     "end_time": "2026-10-02T14:40:41.974919+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:41.968000+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": "markdown",
   "id": "8c9d48ed",
   "metadata": {
    "papermill": {
     "duration": 0.000707,
     "end_time": "2026-10-02T14:40:41.976668+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:41.975961+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Optimizing the Sellar Problem\n",
    "In the previous tutorials we showed you how to define the Sellar model and run it directly. Now let’s see how we can optimize the Sellar problem to minimize the objective function. Here is the mathematical problem formulation for the Sellar optimization problem:\n",
    "\n",
    "\\begin{align}\n",
    "\\text{min}: & \\ \\ \\ & x_1^2 + z_2 + y_1 + e^{-y_2} \\\\\n",
    "\\text{w.r.t.}: & \\ \\ \\ &  x_1, z_1, z_2 \\\\\n",
    "\\text{subject to}: & \\ \\ \\ & \\\\\n",
    "& \\ \\ \\ & 3.16 - y_1 <=0 \\\\\n",
    "& \\ \\ \\ & y_2 - 24.0 <=0\n",
    "\\end{align}\n",
    "\n",
    "Remember that we built our Sellar model as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "197ff093",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:41.979056Z",
     "iopub.status.busy": "2026-10-02T14:40:41.978886Z",
     "iopub.status.idle": "2026-10-02T14:40:43.437506Z",
     "shell.execute_reply": "2026-10-02T14:40:43.436808Z"
    },
    "papermill": {
     "duration": 1.460814,
     "end_time": "2026-10-02T14:40:43.438306+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:41.977492+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "from openmdao.test_suite.components.sellar import SellarDis1, SellarDis2\n",
    "\n",
    "\n",
    "class SellarMDA(om.Group):\n",
    "    \"\"\"\n",
    "    Group containing the Sellar MDA.\n",
    "    \"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])\n",
    "        cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'],\n",
    "                            promotes_outputs=['y1'])\n",
    "        cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'],\n",
    "                            promotes_outputs=['y2'])\n",
    "\n",
    "        self.set_input_defaults('x', 1.0)\n",
    "        self.set_input_defaults('z', np.array([5.0, 2.0]))\n",
    "\n",
    "        # Nonlinear Block Gauss Seidel is a gradient free solver\n",
    "        cycle.nonlinear_solver = om.NonlinearBlockGS()\n",
    "\n",
    "        self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                                  z=np.array([0.0, 0.0]), x=0.0),\n",
    "                           promotes=['x', 'z', 'y1', 'y2', 'obj'])\n",
    "\n",
    "        self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "        self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec842dbe",
   "metadata": {
    "papermill": {
     "duration": 0.001194,
     "end_time": "2026-10-02T14:40:43.440937+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:43.439743+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "All the variables we need to set up the optimization are there. So now we just need the run script to execute the optimization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "33fa049e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:43.444430Z",
     "iopub.status.busy": "2026-10-02T14:40:43.444021Z",
     "iopub.status.idle": "2026-10-02T14:40:44.309581Z",
     "shell.execute_reply": "2026-10-02T14:40:44.309044Z"
    },
    "papermill": {
     "duration": 0.86792,
     "end_time": "2026-10-02T14:40:44.310037+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:43.442117+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "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\">SellarMDA</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">Group</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Group containing the Sellar MDA.</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=\"n\">cycle</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;cycle&#39;</span><span class=\"p\">,</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">Group</span><span class=\"p\">(),</span> <span class=\"n\">promotes</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">])</span>\n        <span class=\"n\">cycle</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;d1&#39;</span><span class=\"p\">,</span> <span class=\"n\">SellarDis1</span><span class=\"p\">(),</span> <span class=\"n\">promotes_inputs</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">],</span>\n                            <span class=\"n\">promotes_outputs</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">])</span>\n        <span class=\"n\">cycle</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;d2&#39;</span><span class=\"p\">,</span> <span class=\"n\">SellarDis2</span><span class=\"p\">(),</span> <span class=\"n\">promotes_inputs</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">],</span>\n                            <span class=\"n\">promotes_outputs</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">set_input_defaults</span><span class=\"p\">(</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">set_input_defaults</span><span class=\"p\">(</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">5.0</span><span class=\"p\">,</span> <span class=\"mf\">2.0</span><span class=\"p\">]))</span>\n\n        <span class=\"c1\"># Nonlinear Block Gauss Seidel is a gradient free solver</span>\n        <span class=\"n\">cycle</span><span class=\"o\">.</span><span class=\"n\">nonlinear_solver</span> <span class=\"o\">=</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">NonlinearBlockGS</span><span class=\"p\">()</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;obj_cmp&#39;</span><span class=\"p\">,</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ExecComp</span><span class=\"p\">(</span><span class=\"s1\">&#39;obj = x**2 + z[1] + y1 + exp(-y2)&#39;</span><span class=\"p\">,</span>\n                                                  <span class=\"n\">z</span><span class=\"o\">=</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.0</span><span class=\"p\">]),</span> <span class=\"n\">x</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">),</span>\n                           <span class=\"n\">promotes</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;obj&#39;</span><span class=\"p\">])</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;con_cmp1&#39;</span><span class=\"p\">,</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ExecComp</span><span class=\"p\">(</span><span class=\"s1\">&#39;con1 = 3.16 - y1&#39;</span><span class=\"p\">),</span> <span class=\"n\">promotes</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;con1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;con_cmp2&#39;</span><span class=\"p\">,</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ExecComp</span><span class=\"p\">(</span><span class=\"s1\">&#39;con2 = y2 - 24.0&#39;</span><span class=\"p\">),</span> <span class=\"n\">promotes</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;con2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">])</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{SellarMDA}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{    Group containing the Sellar MDA.}\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}{cycle} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{cycle}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n}{cycle}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{SellarDis1}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes\\PYZus{}inputs}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{,}\n                            \\PY{n}{promotes\\PYZus{}outputs}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n}{cycle}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{SellarDis2}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes\\PYZus{}inputs}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{,}\n                            \\PY{n}{promotes\\PYZus{}outputs}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{set\\PYZus{}input\\PYZus{}defaults}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{set\\PYZus{}input\\PYZus{}defaults}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{l+m+mf}{5.0}\\PY{p}{,} \\PY{l+m+mf}{2.0}\\PY{p}{]}\\PY{p}{)}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Nonlinear Block Gauss Seidel is a gradient free solver}\n        \\PY{n}{cycle}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{om}\\PY{o}{.}\\PY{n}{NonlinearBlockGS}\\PY{p}{(}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{obj\\PYZus{}cmp}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{om}\\PY{o}{.}\\PY{n}{ExecComp}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{obj = x**2 + z[1] + y1 + exp(\\PYZhy{}y2)}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,}\n                                                  \\PY{n}{z}\\PY{o}{=}\\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{l+m+mf}{0.0}\\PY{p}{,} \\PY{l+m+mf}{0.0}\\PY{p}{]}\\PY{p}{)}\\PY{p}{,} \\PY{n}{x}\\PY{o}{=}\\PY{l+m+mf}{0.0}\\PY{p}{)}\\PY{p}{,}\n                           \\PY{n}{promotes}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{obj}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con\\PYZus{}cmp1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{om}\\PY{o}{.}\\PY{n}{ExecComp}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con1 = 3.16 \\PYZhy{} y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con\\PYZus{}cmp2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{om}\\PY{o}{.}\\PY{n}{ExecComp}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con2 = y2 \\PYZhy{} 24.0}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SellarMDA(om.Group):\n    \"\"\"\n    Group containing the Sellar MDA.\n    \"\"\"\n\n    def setup(self):\n        cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])\n        cycle.add_subsystem('d1', SellarDis1(), promotes_inputs=['x', 'z', 'y2'],\n                            promotes_outputs=['y1'])\n        cycle.add_subsystem('d2', SellarDis2(), promotes_inputs=['z', 'y1'],\n                            promotes_outputs=['y2'])\n\n        self.set_input_defaults('x', 1.0)\n        self.set_input_defaults('z', np.array([5.0, 2.0]))\n\n        # Nonlinear Block Gauss Seidel is a gradient free solver\n        cycle.nonlinear_solver = om.NonlinearBlockGS()\n\n        self.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n                                                  z=np.array([0.0, 0.0]), x=0.0),\n                           promotes=['x', 'z', 'y1', 'y2', 'obj'])\n\n        self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n        self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src7"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src7\", get_code(\"openmdao.test_suite.components.sellar_feature.SellarMDA\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56820ba1",
   "metadata": {
    "papermill": {
     "duration": 0.001041,
     "end_time": "2026-10-02T14:40:44.312561+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:44.311520+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarMDA` class definition \n",
    "\n",
    "{glue:}`code_src7`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "06eab25a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:44.315234Z",
     "iopub.status.busy": "2026-10-02T14:40:44.315086Z",
     "iopub.status.idle": "2026-10-02T14:40:45.600066Z",
     "shell.execute_reply": "2026-10-02T14:40:45.599406Z"
    },
    "papermill": {
     "duration": 1.287014,
     "end_time": "2026-10-02T14:40:45.600533+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:44.313519+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952045.574875] [runnervm8df0l:5998 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55e18c60ef70 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",
      "[1790952045.575144] [runnervm8df0l:5998 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Optimization terminated successfully    (Exit mode 0)\n",
      "            Current function value: 3.183393951732658\n",
      "            Iterations: 6\n",
      "            Function evaluations: 6\n",
      "            Gradient evaluations: 6\n",
      "Optimization Complete\n",
      "-----------------------------------\n",
      "minimum found at\n",
      "1.3006157808748532e-14\n",
      "[1.97763888 0.        ]\n",
      "minumum objective\n",
      "3.183393951732658\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:05998] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.sellar_feature import SellarMDA\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model = SellarMDA()\n",
    "\n",
    "prob.driver = om.ScipyOptimizeDriver()\n",
    "prob.driver.options['optimizer'] = 'SLSQP'\n",
    "# prob.driver.options['maxiter'] = 100\n",
    "prob.driver.options['tol'] = 1e-8\n",
    "\n",
    "prob.model.add_design_var('x', lower=0, upper=10)\n",
    "prob.model.add_design_var('z', lower=0, upper=10)\n",
    "prob.model.add_objective('obj')\n",
    "prob.model.add_constraint('con1', upper=0)\n",
    "prob.model.add_constraint('con2', upper=0)\n",
    "\n",
    "# Ask OpenMDAO to finite-difference across the model to compute the gradients for the optimizer\n",
    "prob.model.approx_totals()\n",
    "\n",
    "prob.setup()\n",
    "prob.set_solver_print(level=0)\n",
    "\n",
    "prob.run_driver()\n",
    "\n",
    "print('minimum found at')\n",
    "print(prob.get_val('x')[0])\n",
    "print(prob.get_val('z'))\n",
    "\n",
    "print('minumum objective')\n",
    "print(prob.get_val('obj')[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "064b97d7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:45.603681Z",
     "iopub.status.busy": "2026-10-02T14:40:45.603536Z",
     "iopub.status.idle": "2026-10-02T14:40:45.607461Z",
     "shell.execute_reply": "2026-10-02T14:40:45.606867Z"
    },
    "papermill": {
     "duration": 0.006039,
     "end_time": "2026-10-02T14:40:45.607883+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:45.601844+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(4.029215358806951e-10)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(prob.get_val('x')[0], 0., 1e-5)\n",
    "assert_near_equal(prob.get_val('z'), [1.977639, 0.], 1e-5)\n",
    "assert_near_equal(prob.get_val('obj')[0], 3.18339395045, 1e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e4ccc6d",
   "metadata": {
    "papermill": {
     "duration": 0.001023,
     "end_time": "2026-10-02T14:40:45.610068+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:45.609045+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Controlling the Solver Print Output\n",
    "Notice the call to `prob.set_solver_print()`,\n",
    "which sets the solver output to level 0.\n",
    "This is the semi-quiet setting where you will only be notified if the solver failed to converge.\n",
    "There are lots of ways to [configure the solver print](../../features/core_features/controlling_solver_behavior/solver_options) output in your model to suit your needs.\n",
    "\n",
    "\n",
    "## Approximate the total derivatives with finite difference\n",
    "\n",
    "In this case we're using the `SLSQP` algorithm, which is a gradient-based optimization approach.\n",
    "Up to this point, none of our components have provided any analytic derivatives,\n",
    "so we'll just finite difference across the whole model to approximate the derivatives.\n",
    "This is accomplished by this line of code:\n",
    "```\n",
    "prob.model.approx_totals()\n",
    "```\n",
    "\n",
    "```{Note}\n",
    "We're using finite difference here for simplicity, but for larger models, finite differencing results in a high computational cost, and can have limited accuracy.\n",
    "It's much better to use analytic derivatives with your models. You can learn more about that in the [Advanced User Guide](../../advanced_user_guide/advanced_user_guide).\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "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"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 5.040608,
   "end_time": "2026-10-02T14:40:46.226411+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/basic_user_guide/multidisciplinary_optimization/sellar_opt.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/basic_user_guide/multidisciplinary_optimization/sellar_opt.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:40:41.185803+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}