{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5d2f6ca3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:35.603762Z",
     "iopub.status.busy": "2026-10-02T14:40:35.603497Z",
     "iopub.status.idle": "2026-10-02T14:40:35.608150Z",
     "shell.execute_reply": "2026-10-02T14:40:35.607528Z"
    },
    "papermill": {
     "duration": 0.007502,
     "end_time": "2026-10-02T14:40:35.608774+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:35.601272+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": "8b1157b8",
   "metadata": {
    "papermill": {
     "duration": 0.015101,
     "end_time": "2026-10-02T14:40:35.625648+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:35.610547+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Linking Variables with Promotion vs. Connection\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7dc00c8c",
   "metadata": {
    "papermill": {
     "duration": 0.001522,
     "end_time": "2026-10-02T14:40:35.628838+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:35.627316+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "In the previous tutorial, we built up a model of the Sellar problem using two disciplinary components and a few `ExecComps`.\n",
    "In order to get OpenMDAO to pass the data between all the components,\n",
    "we linked everything up using promoted variables so that data passed from outputs to inputs with the same promoted name.\n",
    "\n",
    "Promoting variables is often a convenient way to establish the data passing links from outputs to inputs.\n",
    "However, you can also use calls to the `connect` method in order to link outputs to inputs without having to\n",
    "promote anything.\n",
    "Here is how you would define the same Sellar model using:\n",
    "\n",
    "1. Variable promotion\n",
    "2. Connect statements\n",
    "3. Both variable promotion and connect statements\n",
    "\n",
    "All three will give the exact same answer, but the way you address the variables will be slightly different in each one."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ea4207b",
   "metadata": {
    "papermill": {
     "duration": 0.001385,
     "end_time": "2026-10-02T14:40:35.631739+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:35.630354+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Variable Promotion\n",
    "Input and output variables can be promoted when a subsystem is added:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "216635d6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:35.752470Z",
     "iopub.status.busy": "2026-10-02T14:40:35.752319Z",
     "iopub.status.idle": "2026-10-02T14:40:37.773858Z",
     "shell.execute_reply": "2026-10-02T14:40:37.773175Z"
    },
    "papermill": {
     "duration": 2.045715,
     "end_time": "2026-10-02T14:40:37.774449+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:35.728734+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\">SellarDis1</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\">    Component containing Discipline 1 -- no derivatives version.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">execution_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_units</span> <span class=\"o\">=</span> <span class=\"n\">units</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_do_scaling</span> <span class=\"o\">=</span> <span class=\"n\">scaling</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\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_units</span><span class=\"p\">:</span>\n            <span class=\"n\">units</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;ft&#39;</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">units</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_do_scaling</span><span class=\"p\">:</span>\n            <span class=\"n\">ref</span> <span class=\"o\">=</span> <span class=\"mf\">.1</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ref</span> <span class=\"o\">=</span> <span class=\"mf\">1.</span>\n\n        <span class=\"c1\"># Global Design Variable</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;z&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Local Design Variable</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.</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Coupling parameter</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;y2&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Coupling output</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"n\">lower</span><span class=\"o\">=</span><span class=\"mf\">0.1</span><span class=\"p\">,</span> <span class=\"n\">upper</span><span class=\"o\">=</span><span class=\"mf\">1000.</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">,</span> <span class=\"n\">ref</span><span class=\"o\">=</span><span class=\"n\">ref</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=\"c1\"># Finite difference everything</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> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;fd&#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\">        Evaluates the equation</span>\n<span class=\"sd\">        y1 = z1**2 + z2 + x1 - 0.2*y2</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n\n        <span class=\"n\">z1</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">z2</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">x1</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\">y2</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">]</span>\n\n        <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">z1</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"n\">z2</span> <span class=\"o\">+</span> <span class=\"n\">x1</span> <span class=\"o\">-</span> <span class=\"mf\">0.2</span><span class=\"o\">*</span><span class=\"n\">y2</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">execution_count</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{SellarDis1}\\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}{    Component containing Discipline 1 \\PYZhy{}\\PYZhy{} no derivatives version.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb}{super}\\PY{p}{(}\\PY{p}{)}\\PY{o}{.}\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{execution\\PYZus{}count} \\PY{o}{=} \\PY{l+m+mi}{0}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}units} \\PY{o}{=} \\PY{n}{units}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}do\\PYZus{}scaling} \\PY{o}{=} \\PY{n}{scaling}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}units}\\PY{p}{:}\n            \\PY{n}{units} \\PY{o}{=} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ft}\\PY{l+s+s1}{\\PYZsq{}}\n        \\PY{k}{else}\\PY{p}{:}\n            \\PY{n}{units} \\PY{o}{=} \\PY{k+kc}{None}\n\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}do\\PYZus{}scaling}\\PY{p}{:}\n            \\PY{n}{ref} \\PY{o}{=} \\PY{l+m+mf}{.1}\n        \\PY{k}{else}\\PY{p}{:}\n            \\PY{n}{ref} \\PY{o}{=} \\PY{l+m+mf}{1.}\n\n        \\PY{c+c1}{\\PYZsh{} Global Design Variable}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{n}{np}\\PY{o}{.}\\PY{n}{zeros}\\PY{p}{(}\\PY{l+m+mi}{2}\\PY{p}{)}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Local Design Variable}\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.}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Coupling parameter}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Coupling output}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{n}{lower}\\PY{o}{=}\\PY{l+m+mf}{0.1}\\PY{p}{,} \\PY{n}{upper}\\PY{o}{=}\\PY{l+m+mf}{1000.}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{,} \\PY{n}{ref}\\PY{o}{=}\\PY{n}{ref}\\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{c+c1}{\\PYZsh{} Finite difference everything}\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}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{fd}\\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}{        Evaluates the equation}\n\\PY{l+s+sd}{        y1 = z1**2 + z2 + x1 \\PYZhy{} 0.2*y2}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n        \\PY{n}{z1} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{[}\\PY{l+m+mi}{0}\\PY{p}{]}\n        \\PY{n}{z2} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{[}\\PY{l+m+mi}{1}\\PY{p}{]}\n        \\PY{n}{x1} \\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}{y2} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n        \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{z1}\\PY{o}{*}\\PY{o}{*}\\PY{l+m+mi}{2} \\PY{o}{+} \\PY{n}{z2} \\PY{o}{+} \\PY{n}{x1} \\PY{o}{\\PYZhy{}} \\PY{l+m+mf}{0.2}\\PY{o}{*}\\PY{n}{y2}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{execution\\PYZus{}count} \\PY{o}{+}\\PY{o}{=} \\PY{l+m+mi}{1}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SellarDis1(om.ExplicitComponent):\n    \"\"\"\n    Component containing Discipline 1 -- no derivatives version.\n    \"\"\"\n\n    def __init__(self, units=None, scaling=None):\n        super().__init__()\n        self.execution_count = 0\n        self._units = units\n        self._do_scaling = scaling\n\n    def setup(self):\n\n        if self._units:\n            units = 'ft'\n        else:\n            units = None\n\n        if self._do_scaling:\n            ref = .1\n        else:\n            ref = 1.\n\n        # Global Design Variable\n        self.add_input('z', val=np.zeros(2), units=units)\n\n        # Local Design Variable\n        self.add_input('x', val=0., units=units)\n\n        # Coupling parameter\n        self.add_input('y2', val=1.0, units=units)\n\n        # Coupling output\n        self.add_output('y1', val=1.0, lower=0.1, upper=1000., units=units, ref=ref)\n\n    def setup_partials(self):\n        # Finite difference everything\n        self.declare_partials('*', '*', method='fd')\n\n    def compute(self, inputs, outputs):\n        \"\"\"\n        Evaluates the equation\n        y1 = z1**2 + z2 + x1 - 0.2*y2\n        \"\"\"\n\n        z1 = inputs['z'][0]\n        z2 = inputs['z'][1]\n        x1 = inputs['x']\n        y2 = inputs['y2']\n\n        outputs['y1'] = z1**2 + z2 + x1 - 0.2*y2\n\n        self.execution_count += 1"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src5"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src5\", get_code(\"openmdao.test_suite.components.sellar.SellarDis1\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de5d0340",
   "metadata": {
    "papermill": {
     "duration": 0.001245,
     "end_time": "2026-10-02T14:40:37.777316+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:37.776071+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarDis1` class definition \n",
    "\n",
    "{glue:}`code_src5`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "bbfd0cf3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:37.780722Z",
     "iopub.status.busy": "2026-10-02T14:40:37.780499Z",
     "iopub.status.idle": "2026-10-02T14:40:37.788508Z",
     "shell.execute_reply": "2026-10-02T14:40:37.788005Z"
    },
    "papermill": {
     "duration": 0.010442,
     "end_time": "2026-10-02T14:40:37.788952+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:37.778510+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\">SellarDis2</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\">    Component containing Discipline 2 -- no derivatives version.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">execution_count</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_units</span> <span class=\"o\">=</span> <span class=\"n\">units</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_do_scaling</span> <span class=\"o\">=</span> <span class=\"n\">scaling</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=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_units</span><span class=\"p\">:</span>\n            <span class=\"n\">units</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;inch&#39;</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">units</span> <span class=\"o\">=</span> <span class=\"kc\">None</span>\n\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_do_scaling</span><span class=\"p\">:</span>\n            <span class=\"n\">ref</span> <span class=\"o\">=</span> <span class=\"mf\">.18</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">ref</span> <span class=\"o\">=</span> <span class=\"mf\">1.</span>\n\n        <span class=\"c1\"># Global Design Variable</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;z&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Coupling parameter</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;y1&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Coupling output</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"n\">lower</span><span class=\"o\">=</span><span class=\"mf\">0.1</span><span class=\"p\">,</span> <span class=\"n\">upper</span><span class=\"o\">=</span><span class=\"mf\">1000.</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">,</span> <span class=\"n\">ref</span><span class=\"o\">=</span><span class=\"n\">ref</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=\"c1\"># Finite difference everything</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> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;fd&#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\">        Evaluates the equation</span>\n<span class=\"sd\">        y2 = y1**(.5) + z1 + z2</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n\n        <span class=\"n\">z1</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n        <span class=\"n\">z2</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">][</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">y1</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">]</span>\n\n        <span class=\"c1\"># Note: this may cause some issues. However, y1 is constrained to be</span>\n        <span class=\"c1\"># above 3.16, so lets just let it converge, and the optimizer will</span>\n        <span class=\"c1\"># throw it out</span>\n        <span class=\"k\">if</span> <span class=\"n\">y1</span><span class=\"o\">.</span><span class=\"n\">real</span> <span class=\"o\">&lt;</span> <span class=\"mf\">0.0</span><span class=\"p\">:</span>\n            <span class=\"n\">y1</span> <span class=\"o\">*=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n\n        <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">y1</span><span class=\"o\">**</span><span class=\"mf\">.5</span> <span class=\"o\">+</span> <span class=\"n\">z1</span> <span class=\"o\">+</span> <span class=\"n\">z2</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">execution_count</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{SellarDis2}\\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}{    Component containing Discipline 2 \\PYZhy{}\\PYZhy{} no derivatives version.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb}{super}\\PY{p}{(}\\PY{p}{)}\\PY{o}{.}\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{execution\\PYZus{}count} \\PY{o}{=} \\PY{l+m+mi}{0}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}units} \\PY{o}{=} \\PY{n}{units}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}do\\PYZus{}scaling} \\PY{o}{=} \\PY{n}{scaling}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}units}\\PY{p}{:}\n            \\PY{n}{units} \\PY{o}{=} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{inch}\\PY{l+s+s1}{\\PYZsq{}}\n        \\PY{k}{else}\\PY{p}{:}\n            \\PY{n}{units} \\PY{o}{=} \\PY{k+kc}{None}\n\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}do\\PYZus{}scaling}\\PY{p}{:}\n            \\PY{n}{ref} \\PY{o}{=} \\PY{l+m+mf}{.18}\n        \\PY{k}{else}\\PY{p}{:}\n            \\PY{n}{ref} \\PY{o}{=} \\PY{l+m+mf}{1.}\n\n        \\PY{c+c1}{\\PYZsh{} Global Design Variable}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{n}{np}\\PY{o}{.}\\PY{n}{zeros}\\PY{p}{(}\\PY{l+m+mi}{2}\\PY{p}{)}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Coupling parameter}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Coupling output}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{n}{lower}\\PY{o}{=}\\PY{l+m+mf}{0.1}\\PY{p}{,} \\PY{n}{upper}\\PY{o}{=}\\PY{l+m+mf}{1000.}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{,} \\PY{n}{ref}\\PY{o}{=}\\PY{n}{ref}\\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{c+c1}{\\PYZsh{} Finite difference everything}\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}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{fd}\\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}{        Evaluates the equation}\n\\PY{l+s+sd}{        y2 = y1**(.5) + z1 + z2}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n        \\PY{n}{z1} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{[}\\PY{l+m+mi}{0}\\PY{p}{]}\n        \\PY{n}{z2} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{[}\\PY{l+m+mi}{1}\\PY{p}{]}\n        \\PY{n}{y1} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n        \\PY{c+c1}{\\PYZsh{} Note: this may cause some issues. However, y1 is constrained to be}\n        \\PY{c+c1}{\\PYZsh{} above 3.16, so lets just let it converge, and the optimizer will}\n        \\PY{c+c1}{\\PYZsh{} throw it out}\n        \\PY{k}{if} \\PY{n}{y1}\\PY{o}{.}\\PY{n}{real} \\PY{o}{\\PYZlt{}} \\PY{l+m+mf}{0.0}\\PY{p}{:}\n            \\PY{n}{y1} \\PY{o}{*}\\PY{o}{=} \\PY{o}{\\PYZhy{}}\\PY{l+m+mi}{1}\n\n        \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{y1}\\PY{o}{*}\\PY{o}{*}\\PY{l+m+mf}{.5} \\PY{o}{+} \\PY{n}{z1} \\PY{o}{+} \\PY{n}{z2}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{execution\\PYZus{}count} \\PY{o}{+}\\PY{o}{=} \\PY{l+m+mi}{1}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SellarDis2(om.ExplicitComponent):\n    \"\"\"\n    Component containing Discipline 2 -- no derivatives version.\n    \"\"\"\n\n    def __init__(self, units=None, scaling=None):\n        super().__init__()\n        self.execution_count = 0\n        self._units = units\n        self._do_scaling = scaling\n\n    def setup(self):\n        if self._units:\n            units = 'inch'\n        else:\n            units = None\n\n        if self._do_scaling:\n            ref = .18\n        else:\n            ref = 1.\n\n        # Global Design Variable\n        self.add_input('z', val=np.zeros(2), units=units)\n\n        # Coupling parameter\n        self.add_input('y1', val=1.0, units=units)\n\n        # Coupling output\n        self.add_output('y2', val=1.0, lower=0.1, upper=1000., units=units, ref=ref)\n\n    def setup_partials(self):\n        # Finite difference everything\n        self.declare_partials('*', '*', method='fd')\n\n    def compute(self, inputs, outputs):\n        \"\"\"\n        Evaluates the equation\n        y2 = y1**(.5) + z1 + z2\n        \"\"\"\n\n        z1 = inputs['z'][0]\n        z2 = inputs['z'][1]\n        y1 = inputs['y1']\n\n        # Note: this may cause some issues. However, y1 is constrained to be\n        # above 3.16, so lets just let it converge, and the optimizer will\n        # throw it out\n        if y1.real < 0.0:\n            y1 *= -1\n\n        outputs['y2'] = y1**.5 + z1 + z2\n\n        self.execution_count += 1"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src6"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src6\", get_code(\"openmdao.test_suite.components.sellar.SellarDis2\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae2abb7c",
   "metadata": {
    "papermill": {
     "duration": 0.12501,
     "end_time": "2026-10-02T14:40:37.915857+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:37.790847+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarDis2` class definition \n",
    "\n",
    "{glue:}`code_src6`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e778eff0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:37.920951Z",
     "iopub.status.busy": "2026-10-02T14:40:37.920717Z",
     "iopub.status.idle": "2026-10-02T14:40:39.161011Z",
     "shell.execute_reply": "2026-10-02T14:40:39.160119Z"
    },
    "papermill": {
     "duration": 1.243784,
     "end_time": "2026-10-02T14:40:39.161571+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:37.917787+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952039.146869] [runnervm8df0l:5949 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x5638fa641db0 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",
      "[1790952039.147133] [runnervm8df0l:5949 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "\n",
      "=====\n",
      "cycle\n",
      "=====\n",
      "NL: NLBGS Converged in 10 iterations\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:05949] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "from openmdao.test_suite.components.sellar import SellarDis1, SellarDis2\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(),\n",
    "                            promotes_inputs=['x', 'z', 'y2'],\n",
    "                            promotes_outputs=['y1'])\n",
    "        cycle.add_subsystem('d2', SellarDis2(),\n",
    "                            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'),\n",
    "                           promotes=['con1', 'y1'])\n",
    "        self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'),\n",
    "                           promotes=['con2', 'y2'])\n",
    "\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model = SellarMDA()\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 2.0)\n",
    "prob.set_val('z', [-1., -1.])\n",
    "\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "81b7db27",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.167329Z",
     "iopub.status.busy": "2026-10-02T14:40:39.167167Z",
     "iopub.status.idle": "2026-10-02T14:40:39.171534Z",
     "shell.execute_reply": "2026-10-02T14:40:39.170835Z"
    },
    "papermill": {
     "duration": 0.008755,
     "end_time": "2026-10-02T14:40:39.172112+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.163357+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-output",
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.3022994867631257e-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('y1')[0], prob.get_val('y2')[0], prob.get_val('obj')[0], prob.get_val('con1')[0], prob.get_val('con2')[0]),\n",
    "                  (2.10951651, -0.54758253,  6.8385845,  1.05048349, -24.54758253), 1e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15c20a4d",
   "metadata": {
    "papermill": {
     "duration": 0.00149,
     "end_time": "2026-10-02T14:40:39.175200+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.173710+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Alternatively, variables can be promoted when a group is configured:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "61717fc7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.182284Z",
     "iopub.status.busy": "2026-10-02T14:40:39.182129Z",
     "iopub.status.idle": "2026-10-02T14:40:39.191986Z",
     "shell.execute_reply": "2026-10-02T14:40:39.191351Z"
    },
    "papermill": {
     "duration": 0.012535,
     "end_time": "2026-10-02T14:40:39.192461+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.179926+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=====\n",
      "cycle\n",
      "=====\n",
      "NL: NLBGS Converged in 10 iterations\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "from openmdao.test_suite.components.sellar import SellarDis1, SellarDis2\n",
    "\n",
    "class SellarMDA(om.Group):\n",
    "    \"\"\"\n",
    "    Group containing the Sellar MDA.\n",
    "    \"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        # set up model hierarchy\n",
    "        cycle = self.add_subsystem('cycle', om.Group())\n",
    "        cycle.add_subsystem('d1', SellarDis1())\n",
    "        cycle.add_subsystem('d2', SellarDis2())\n",
    "\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",
    "\n",
    "        self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'))\n",
    "        self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'))\n",
    "\n",
    "    def configure(self):\n",
    "        # connect everything via promotes\n",
    "        self.cycle.promotes('d1', inputs=['x', 'z', 'y2'], outputs=['y1'])\n",
    "        self.cycle.promotes('d2', inputs=['z', 'y1'], outputs=['y2'])\n",
    "\n",
    "        self.promotes('cycle', any=['*'])\n",
    "\n",
    "        self.promotes('obj_cmp', any=['x', 'z', 'y1', 'y2', 'obj'])\n",
    "        self.promotes('con_cmp1', any=['con1', 'y1'])\n",
    "        self.promotes('con_cmp2', any=['con2', 'y2'])\n",
    "\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model = SellarMDA()\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 2.0)\n",
    "prob.set_val('z', [-1., -1.])\n",
    "\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "abcf4892",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.234260Z",
     "iopub.status.busy": "2026-10-02T14:40:39.234111Z",
     "iopub.status.idle": "2026-10-02T14:40:39.238213Z",
     "shell.execute_reply": "2026-10-02T14:40:39.237109Z"
    },
    "papermill": {
     "duration": 0.041088,
     "end_time": "2026-10-02T14:40:39.238729+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.197641+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-output",
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.3022994867631257e-10)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal((prob.get_val('y1')[0], prob.get_val('y2')[0], prob.get_val('obj')[0], prob.get_val('con1')[0], prob.get_val('con2')[0]),\n",
    "                  (2.10951651, -0.54758253,  6.8385845,  1.05048349, -24.54758253), 1e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d951c63c",
   "metadata": {
    "papermill": {
     "duration": 0.001585,
     "end_time": "2026-10-02T14:40:39.241943+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.240358+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "There are a few important details to note:\n",
    "\n",
    "- The promoted name of an output has to be unique within that level of the hierarchy (i.e. you can't have two outputs with the same name)\n",
    "- You are allowed to have multiple inputs promoted to the same name.\n",
    "- You can use [glob](https://en.wikipedia.org/wiki/Glob_(programming)) patterns to promote lots of variables without specifying them all, but try to limit your usage of `promotes=['*']`. Though it may seem like a convenient way to do things, it can make it difficult for other people who are reading your code to understand which variables are connected to each other. It is acceptable to use `promotes=['*']` in cases where it won't cause confusion, for example with `cycle`, which only exists to allow for the nonlinear solver to converge the two components. Another example of when it would be safe to use `promotes=['*']` would be if you have `ExecComps` that make it clear what the I/O of that component is anyway.\n",
    "\n",
    "```{Note}\n",
    "For a more detailed set of examples for how to promote variables, check out the [feature doc on adding sub-systems to a group](../../features/core_features/working_with_groups/add_subsystem).There are some more advanced things you can do, such as variable name aliasing and connecting a sub-set of indices from the output array of one component to the input of another.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae243c19",
   "metadata": {
    "papermill": {
     "duration": 0.004631,
     "end_time": "2026-10-02T14:40:39.248145+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.243514+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "(sellar-connect)=\n",
    "## Connect Statements\n",
    "The exact same model results can be achieved using `connect` statements instead of promotions. However, take careful note of how the variables are addressed in those connect and print statements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ca70fc76",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.373974Z",
     "iopub.status.busy": "2026-10-02T14:40:39.373812Z",
     "iopub.status.idle": "2026-10-02T14:40:39.383730Z",
     "shell.execute_reply": "2026-10-02T14:40:39.382730Z"
    },
    "papermill": {
     "duration": 0.134607,
     "end_time": "2026-10-02T14:40:39.384281+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.249674+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=====\n",
      "cycle\n",
      "=====\n",
      "NL: NLBGS Converged in 10 iterations\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "from openmdao.test_suite.components.sellar import SellarDis1, SellarDis2\n",
    "\n",
    "class SellarMDAConnect(om.Group):\n",
    "    \"\"\"\n",
    "    Group containing the Sellar MDA. This version uses the disciplines without derivatives.\n",
    "    \"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        cycle = self.add_subsystem('cycle', om.Group(),\n",
    "                                   promotes_inputs=['x', 'z'])\n",
    "        cycle.add_subsystem('d1', SellarDis1(),\n",
    "                            promotes_inputs=['x', 'z'])\n",
    "        cycle.add_subsystem('d2', SellarDis2(),\n",
    "                            promotes_inputs=['z'])\n",
    "        cycle.connect('d1.y1', 'd2.y1')\n",
    "        cycle.connect('d2.y2', 'd1.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_inputs=['x', 'z'])\n",
    "\n",
    "        self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'))\n",
    "        self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'))\n",
    "\n",
    "        self.connect('cycle.d1.y1', ['obj_cmp.y1', 'con_cmp1.y1'])\n",
    "        self.connect('cycle.d2.y2', ['obj_cmp.y2', 'con_cmp2.y2'])\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model = SellarMDAConnect()\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 2.0)\n",
    "prob.set_val('z', [-1., -1.])\n",
    "\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "043ea29c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.570321Z",
     "iopub.status.busy": "2026-10-02T14:40:39.570158Z",
     "iopub.status.idle": "2026-10-02T14:40:39.574066Z",
     "shell.execute_reply": "2026-10-02T14:40:39.573221Z"
    },
    "papermill": {
     "duration": 0.007429,
     "end_time": "2026-10-02T14:40:39.574539+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.567110+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.3022994867631257e-10)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal((prob.get_val('cycle.d1.y1')[0], prob.get_val('cycle.d2.y2')[0], prob.get_val('obj_cmp.obj')[0], prob.get_val('con_cmp1.con1')[0], prob.get_val('con_cmp2.con2')[0]),\n",
    "                  (2.10951651, -0.54758253, 6.8385845, 1.05048349, -24.54758253), 1e-5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16f5ec07",
   "metadata": {
    "papermill": {
     "duration": 0.001537,
     "end_time": "2026-10-02T14:40:39.577730+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.576193+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Variable Promotion and Connect Statements\n",
    "\n",
    "It is also possible to combine promotion and connection in a single model.\n",
    "Here, notice that we do not have to add \"cycle\" in front of anything, because we promoted all the variables up from that group."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "7620741e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.581342Z",
     "iopub.status.busy": "2026-10-02T14:40:39.581204Z",
     "iopub.status.idle": "2026-10-02T14:40:39.590636Z",
     "shell.execute_reply": "2026-10-02T14:40:39.589895Z"
    },
    "papermill": {
     "duration": 0.011956,
     "end_time": "2026-10-02T14:40:39.591135+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.579179+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=====\n",
      "cycle\n",
      "=====\n",
      "NL: NLBGS Converged in 10 iterations\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "from openmdao.test_suite.components.sellar import SellarDis1, SellarDis2\n",
    "\n",
    "class SellarMDAPromoteConnect(om.Group):\n",
    "    \"\"\"\n",
    "    Group containing the Sellar MDA. This version uses the disciplines without derivatives.\n",
    "    \"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        cycle = self.add_subsystem('cycle', om.Group(), promotes=['*'])\n",
    "        cycle.add_subsystem('d1', SellarDis1(),\n",
    "                            promotes_inputs=['x', 'z'])\n",
    "        cycle.add_subsystem('d2', SellarDis2(),\n",
    "                            promotes_inputs=['z'])\n",
    "        cycle.connect('d1.y1', 'd2.y1')\n",
    "        cycle.connect('d2.y2', 'd1.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_inputs=['x', 'z'])\n",
    "\n",
    "        self.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'))\n",
    "        self.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'))\n",
    "\n",
    "        self.connect('d1.y1', ['con_cmp1.y1', 'obj_cmp.y1'])\n",
    "        self.connect('d2.y2', ['con_cmp2.y2', 'obj_cmp.y2'])\n",
    "\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model = SellarMDAPromoteConnect()\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 2.0)\n",
    "prob.set_val('z', [-1., -1.])\n",
    "\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "35ca11f4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:39.595940Z",
     "iopub.status.busy": "2026-10-02T14:40:39.595769Z",
     "iopub.status.idle": "2026-10-02T14:40:39.599402Z",
     "shell.execute_reply": "2026-10-02T14:40:39.598725Z"
    },
    "papermill": {
     "duration": 0.007166,
     "end_time": "2026-10-02T14:40:39.600045+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:39.592879+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.3022994867631257e-10)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal((prob.get_val('cycle.d1.y1')[0], prob.get_val('cycle.d2.y2')[0], prob.get_val('obj_cmp.obj')[0], prob.get_val('con_cmp1.con1')[0], prob.get_val('con_cmp2.con2')[0]),\n",
    "                  (2.10951651, -0.54758253, 6.8385845, 1.05048349, -24.54758253), 1e-5)"
   ]
  }
 ],
 "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.271641,
   "end_time": "2026-10-02T14:40:40.219509+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/basic_user_guide/multidisciplinary_optimization/linking_vars.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/basic_user_guide/multidisciplinary_optimization/linking_vars.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:40:34.947868+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}