{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "66fbfe68",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:25.623179Z",
     "iopub.status.busy": "2026-10-02T14:42:25.622938Z",
     "iopub.status.idle": "2026-10-02T14:42:25.628481Z",
     "shell.execute_reply": "2026-10-02T14:42:25.627586Z"
    },
    "papermill": {
     "duration": 0.00928,
     "end_time": "2026-10-02T14:42:25.629361+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:25.620081+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": "c69e3e4e",
   "metadata": {
    "papermill": {
     "duration": 0.002429,
     "end_time": "2026-10-02T14:42:25.633507+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:25.631078+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# BroydenSolver\n",
    "\n",
    "BroydenSolver is a quasi-Newton solver that implements Broyden's second method to solve for values of the model's states that drive their residuals to zero. It does so by maintaining an approximation to the inverse of the Jacobian of the model or a subset of the model. In some cases this can be more efficient than NewtonSolver because updating the approximated inverse Jacobian is cheaper than solving the linear system. It may take more iterations because the search direction depends on an approximation, but the iterations take fewer operations.\n",
    "\n",
    "The BroydenSolver has two different modes of operation. It can operate on the entire model and solve for every state in the containing system and all subsystems. Alternatively, it can operate on a subset of the model and only solve for a list of states that you provide. The advantage of full-model mode is that you don't have to worry about forgetting a state, particularly in large models where you might not be familiar with every component or variable. The disadvantage is that you are computing the inverse of a larger matrix every time you recalculate the inverse jacobian, though ideally you are not recomputing this very often. Operating on a subset of states is more efficient in both the linear solve and the Broyden update, but you do run the risk of missing a state. The BroydenSolver will print a warning if it finds any states in the model that aren't covered by a solver.\n",
    "\n",
    "\n",
    "## BroydenSolver Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "6153af4d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:25.639209Z",
     "iopub.status.busy": "2026-10-02T14:42:25.639053Z",
     "iopub.status.idle": "2026-10-02T14:42:26.841745Z",
     "shell.execute_reply": "2026-10-02T14:42:26.841122Z"
    },
    "papermill": {
     "duration": 1.206508,
     "end_time": "2026-10-02T14:42:26.842426+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:25.635918+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<!DOCTYPE html>\n",
       "<html lang=\"en\">\n",
       "<head>\n",
       "    <style>\n",
       "        h2 {\n",
       "            text-align: center;\n",
       "        }\n",
       "    </style>\n",
       "</head>\n",
       "<body>\n",
       "    <h2></h2>\n",
       "        <table style=\"border: 1px solid #999; border-collapse: collapse;\">\n",
       "        <tr><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Option</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Default</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Values</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Types</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Description</th></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">alpha</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">0.4</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Value to scale the starting Jacobian, which is Identity. This option does nothing if you compute the initial Jacobian instead.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">atol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">absolute error tolerance</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">compute_jacobian</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When True, compute an initial Jacobian, otherwise start with Identity scaled by alpha. Further Jacobians may also be computed depending on the other options.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">converge_limit</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1.0</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Ratio of current residual to previous residual above which the convergence is considered a failure. The Jacobian will be regenerated once this condition has been reached a number of consecutive times as specified in max_converge_failures.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">cs_reconverge</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When True, when this driver solves under a complex step, nudge the Solution vector by a small amount so that it reconverges.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">debug_print</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, the values of input and output variables at the start of iteration are printed and written to a file after a failure to converge or when encountering aninvalid value in the residual.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">diverge_limit</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">2.0</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Ratio of current residual to previous residual above which the Jacobian will be immediately regenerated.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">err_on_non_converge</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When True, AnalysisError will be raised if we don&#x27;t converge.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">iprint</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">whether to print output</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">max_converge_failures</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">3</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">The number of convergence failures before regenerating the Jacobian.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">max_jacobians</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Maximum number of jacobians to compute.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">maxiter</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">maximum number of iterations</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">reraise_child_analysiserror</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When the option is true, a solver will reraise any AnalysisError that arises during subsolve; when false, it will continue solving.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">restart_from_successful</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, the states are cached after a successful solve and used to restart the solver in the case of a failed solve.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rtol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">relative error tolerance</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">stall_limit</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">0</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Number of iterations after which, if the residual norms are identical within the stall_tol, then terminate as if max iterations were reached. Default is 0, which disables this feature.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">stall_tol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-12</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When stall checking is enabled, the threshold below which the residual norm is considered unchanged.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">stall_tol_type</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rel</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;abs&#x27;, &#x27;rel&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Specifies whether the absolute or relative norm of the residual is used for stall detection.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">state_vars</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">List of the state-variable/residuals that are to be solved here.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">update_broyden</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Flag controls whether to perform Broyden update to the Jacobian. There are some applications where it may be useful to turn this off.</td></tr>\n",
       "    </table>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "om.show_options_table(\"openmdao.solvers.nonlinear.broyden.BroydenSolver\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "211871ac",
   "metadata": {
    "papermill": {
     "duration": 0.001408,
     "end_time": "2026-10-02T14:42:26.845526+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:26.844118+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The BroydenSolver also contains a slot for a linear solver and a slot for a linesearch. See the [linesearch section](linesearch-section) for more about these.\n",
    "\n",
    "## BroydenSolver Constructor\n",
    "\n",
    "The call signature for the `BroydenSolver` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.solvers.nonlinear.broyden.BroydenSolver.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## BroydenSolver on a Full Model\n",
    "\n",
    "Here we show an example that uses the [electrical circuit model](../../../advanced_user_guide/models_implicit_components/models_with_solvers_implicit.ipynb) from the\n",
    "advanced guide. We have replaced the `NewtonSolver` with a `BroydenSolver`, and set the maximum number of iterations to 20. We also assign a `DirectSolver` into the \"linear_solver\" slot on the `BroydenSolver`.  This is the linear solver that will be used to assemble the Jacobian and compute its inverse. Since we don't specify any states in the `state_vars` option, the BroydenSolver operates on the entire model. If you don't specify a linear_solver here, then the BroydenSolver will use the one from the system.\n",
    "\n",
    "```{Note}\n",
    "In this mode, only the `DirectSolver` can be used as the linear_solver.\n",
    "```\n",
    "\n",
    "Depending on the values of some of the other options such as \"converge_limit\", \"diverge_limit\", and \"max_converge_failures\", the Jacobian might be recalculated if convergence stalls, though this doesn't happen in the electrical circuit example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "68ad6c43",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:26.849231Z",
     "iopub.status.busy": "2026-10-02T14:42:26.848916Z",
     "iopub.status.idle": "2026-10-02T14:42:27.711051Z",
     "shell.execute_reply": "2026-10-02T14:42:27.710486Z"
    },
    "papermill": {
     "duration": 0.864965,
     "end_time": "2026-10-02T14:42:27.711870+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:26.846905+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\">Circuit</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">Group</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;n1&#39;</span><span class=\"p\">,</span> <span class=\"n\">Node</span><span class=\"p\">(</span><span class=\"n\">n_in</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">n_out</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"n\">promotes_inputs</span><span class=\"o\">=</span><span class=\"p\">[(</span><span class=\"s1\">&#39;I_in:0&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;I_in&#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;n2&#39;</span><span class=\"p\">,</span> <span class=\"n\">Node</span><span class=\"p\">())</span>  <span class=\"c1\"># leaving defaults</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;R1&#39;</span><span class=\"p\">,</span> <span class=\"n\">Resistor</span><span class=\"p\">(</span><span class=\"n\">R</span><span class=\"o\">=</span><span class=\"mf\">100.</span><span class=\"p\">),</span> <span class=\"n\">promotes_inputs</span><span class=\"o\">=</span><span class=\"p\">[(</span><span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Vg&#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;R2&#39;</span><span class=\"p\">,</span> <span class=\"n\">Resistor</span><span class=\"p\">(</span><span class=\"n\">R</span><span class=\"o\">=</span><span class=\"mf\">10000.</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;D1&#39;</span><span class=\"p\">,</span> <span class=\"n\">Diode</span><span class=\"p\">(),</span> <span class=\"n\">promotes_inputs</span><span class=\"o\">=</span><span class=\"p\">[(</span><span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Vg&#39;</span><span class=\"p\">)])</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;n1.V&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"s1\">&#39;R1.V_in&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;R2.V_in&#39;</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;R1.I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;n1.I_out:0&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;R2.I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;n1.I_out:1&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;n2.V&#39;</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"s1\">&#39;R2.V_out&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;D1.V_in&#39;</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;R2.I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;n2.I_in:0&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;D1.I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;n2.I_out:0&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"bp\">self</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\">NewtonSolver</span><span class=\"p\">(</span><span class=\"n\">solve_subsystems</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nonlinear_solver</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;iprint&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">2</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nonlinear_solver</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;maxiter&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mi\">20</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linear_solver</span> <span class=\"o\">=</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">DirectSolver</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}{Circuit}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{)}\\PY{p}{:}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{Node}\\PY{p}{(}\\PY{n}{n\\PYZus{}in}\\PY{o}{=}\\PY{l+m+mi}{1}\\PY{p}{,} \\PY{n}{n\\PYZus{}out}\\PY{o}{=}\\PY{l+m+mi}{2}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes\\PYZus{}inputs}\\PY{o}{=}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I\\PYZus{}in:0}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\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}{n2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{Node}\\PY{p}{(}\\PY{p}{)}\\PY{p}{)}  \\PY{c+c1}{\\PYZsh{} leaving defaults}\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}{R1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{Resistor}\\PY{p}{(}\\PY{n}{R}\\PY{o}{=}\\PY{l+m+mf}{100.}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes\\PYZus{}inputs}\\PY{o}{=}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Vg}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\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}{R2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{Resistor}\\PY{p}{(}\\PY{n}{R}\\PY{o}{=}\\PY{l+m+mf}{10000.}\\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}{D1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{Diode}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes\\PYZus{}inputs}\\PY{o}{=}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Vg}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{]}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n1.V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R1.V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R2.V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R1.I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n1.I\\PYZus{}out:0}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R2.I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n1.I\\PYZus{}out:1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n2.V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R2.V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{D1.V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R2.I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n2.I\\PYZus{}in:0}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{D1.I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n2.I\\PYZus{}out:0}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{om}\\PY{o}{.}\\PY{n}{NewtonSolver}\\PY{p}{(}\\PY{n}{solve\\PYZus{}subsystems}\\PY{o}{=}\\PY{k+kc}{False}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{iprint}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mi}{2}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mi}{20}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{linear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{om}\\PY{o}{.}\\PY{n}{DirectSolver}\\PY{p}{(}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class Circuit(om.Group):\n\n    def setup(self):\n        self.add_subsystem('n1', Node(n_in=1, n_out=2), promotes_inputs=[('I_in:0', 'I_in')])\n        self.add_subsystem('n2', Node())  # leaving defaults\n\n        self.add_subsystem('R1', Resistor(R=100.), promotes_inputs=[('V_out', 'Vg')])\n        self.add_subsystem('R2', Resistor(R=10000.))\n        self.add_subsystem('D1', Diode(), promotes_inputs=[('V_out', 'Vg')])\n\n        self.connect('n1.V', ['R1.V_in', 'R2.V_in'])\n        self.connect('R1.I', 'n1.I_out:0')\n        self.connect('R2.I', 'n1.I_out:1')\n\n        self.connect('n2.V', ['R2.V_out', 'D1.V_in'])\n        self.connect('R2.I', 'n2.I_in:0')\n        self.connect('D1.I', 'n2.I_out:0')\n\n        self.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n        self.nonlinear_solver.options['iprint'] = 2\n        self.nonlinear_solver.options['maxiter'] = 20\n        self.linear_solver = om.DirectSolver()"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src21"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src21\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Circuit\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40dff939",
   "metadata": {
    "papermill": {
     "duration": 0.001717,
     "end_time": "2026-10-02T14:42:27.715621+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:27.713904+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Circuit` class definition \n",
    "\n",
    "{glue:}`code_src21`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d820513a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:27.720113Z",
     "iopub.status.busy": "2026-10-02T14:42:27.719903Z",
     "iopub.status.idle": "2026-10-02T14:42:28.939154Z",
     "shell.execute_reply": "2026-10-02T14:42:28.938249Z"
    },
    "papermill": {
     "duration": 1.222449,
     "end_time": "2026-10-02T14:42:28.939776+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:27.717327+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952148.915498] [runnervm8df0l:7123 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x5614fcfe9ba0 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",
      "[1790952148.915780] [runnervm8df0l:7123 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "\n",
      "=======\n",
      "circuit\n",
      "=======\n",
      "NL: BROYDEN 0 ; 60.8585191 1\n",
      "NL: BROYDEN 1 ; 22.3883642 0.367875599\n",
      "NL: BROYDEN 2 ; 12.5102871 0.205563449\n",
      "NL: BROYDEN 3 ; 5.98610005 0.0983609219\n",
      "NL: BROYDEN 4 ; 3.04362478 0.0500114827\n",
      "NL: BROYDEN 5 ; 1.51173342 0.0248401283\n",
      "NL: BROYDEN 6 ; 0.757580648 0.0124482268\n",
      "NL: BROYDEN 7 ; 0.378232039 0.0062149399\n",
      "NL: BROYDEN 8 ; 0.188996739 0.00310550999\n",
      "NL: BROYDEN 9 ; 0.0942941723 0.00154939972\n",
      "NL: BROYDEN 10 ; 0.0469594187 0.000771616191\n",
      "NL: BROYDEN 11 ; 0.0232895486 0.000382683459\n",
      "NL: BROYDEN 12 ; 0.0114569328 0.000188255201\n",
      "NL: BROYDEN 13 ; 0.00554426212 9.11008384e-05\n",
      "NL: BROYDEN 14 ; 0.00259566267 4.26507694e-05\n",
      "NL: BROYDEN 15 ; 0.00113639853 1.8672793e-05\n",
      "NL: BROYDEN 16 ; 0.000434036582 7.13189523e-06\n",
      "NL: BROYDEN 17 ; 0.000125653739 2.0646861e-06\n",
      "NL: BROYDEN 18 ; 2.10695157e-05 3.46204869e-07\n",
      "NL: BROYDEN 19 ; 1.29547486e-06 2.12866642e-08\n",
      "NL: BROYDEN 20 ; 1.45259789e-08 2.38684396e-10\n",
      "NL: BROYDENSolver 'NL: BROYDEN' on system 'circuit' failed to converge in 20 iterations.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:07123] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.scripts.circuit_analysis import Circuit\n",
    "\n",
    "p = om.Problem()\n",
    "model = p.model\n",
    "\n",
    "model.add_subsystem('circuit', Circuit(), promotes_inputs=[('Vg', 'V'), ('I_in', 'I')])\n",
    "model.set_input_defaults('V', 0., units='V')\n",
    "model.set_input_defaults('I', 0.1, units='A')\n",
    "\n",
    "p.setup()\n",
    "\n",
    "# Replace existing solver with BroydenSolver\n",
    "model.circuit.nonlinear_solver = om.BroydenSolver()\n",
    "model.circuit.nonlinear_solver.options['maxiter'] = 20\n",
    "model.circuit.nonlinear_solver.linear_solver = om.DirectSolver()\n",
    "\n",
    "# set some initial guesses\n",
    "p.set_val('circuit.n1.V', 10.)\n",
    "p.set_val('circuit.n2.V', 1.)\n",
    "\n",
    "p.set_solver_print(level=2)\n",
    "p.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d8cdf2b3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:28.945916Z",
     "iopub.status.busy": "2026-10-02T14:42:28.945747Z",
     "iopub.status.idle": "2026-10-02T14:42:28.948773Z",
     "shell.execute_reply": "2026-10-02T14:42:28.948311Z"
    },
    "papermill": {
     "duration": 0.006663,
     "end_time": "2026-10-02T14:42:28.949188+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.942525+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[9.90804735]\n",
      "[0.71278226]\n",
      "[0.10000001]\n"
     ]
    }
   ],
   "source": [
    "print(p.get_val('circuit.n1.V'))\n",
    "print(p.get_val('circuit.n2.V'))\n",
    "\n",
    "# sanity check: should sum to .1 Amps\n",
    "print(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e531b2e4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:28.953633Z",
     "iopub.status.busy": "2026-10-02T14:42:28.953460Z",
     "iopub.status.idle": "2026-10-02T14:42:28.958715Z",
     "shell.execute_reply": "2026-10-02T14:42:28.958128Z"
    },
    "papermill": {
     "duration": 0.008321,
     "end_time": "2026-10-02T14:42:28.959278+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.950957+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.4525978864199374e-07)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(p.get_val('circuit.n1.V'), 9.90804735, 1e-5)\n",
    "assert_near_equal(p.get_val('circuit.n2.V'), 0.71278226, 1e-5)\n",
    "\n",
    "# sanity check: should sum to .1 Amps\n",
    "assert_near_equal(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'), .1, 1e-6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90e44856",
   "metadata": {
    "papermill": {
     "duration": 0.001796,
     "end_time": "2026-10-02T14:42:28.962919+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.961123+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## BroydenSolver on a Subset of States\n",
    "\n",
    "The `BroydenSolver` can also be used to solve for specific states. Here we consider the same circuit example, but instead we specify the two voltages n1.V' and 'n2.V' as our \"state_vars\".  In this mode, we aren't limited to just using the `DirectSolver`, and in this example we choose `LinearBlockGS` instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "8712ec48",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:28.966967Z",
     "iopub.status.busy": "2026-10-02T14:42:28.966835Z",
     "iopub.status.idle": "2026-10-02T14:42:28.981622Z",
     "shell.execute_reply": "2026-10-02T14:42:28.981128Z"
    },
    "papermill": {
     "duration": 0.017565,
     "end_time": "2026-10-02T14:42:28.982256+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:28.964691+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=======\n",
      "circuit\n",
      "=======\n",
      "NL: BROYDEN 0 ; 60.8585191 1\n",
      "NL: BROYDEN 1 ; 22.3883642 0.367875599\n",
      "NL: BROYDEN 2 ; 12.5102871 0.205563449\n",
      "NL: BROYDEN 3 ; 5.98610005 0.0983609219\n",
      "NL: BROYDEN 4 ; 3.04362478 0.0500114827\n",
      "NL: BROYDEN 5 ; 1.51173342 0.0248401283\n",
      "NL: BROYDEN 6 ; 0.757580648 0.0124482268\n",
      "NL: BROYDEN 7 ; 0.378232039 0.0062149399\n",
      "NL: BROYDEN 8 ; 0.188996739 0.00310550999\n",
      "NL: BROYDEN 9 ; 0.0942941723 0.00154939972\n",
      "NL: BROYDEN 10 ; 0.0469594187 0.000771616191\n",
      "NL: BROYDEN 11 ; 0.0232895486 0.000382683459\n",
      "NL: BROYDEN 12 ; 0.0114569328 0.000188255201\n",
      "NL: BROYDEN 13 ; 0.00554426212 9.11008384e-05\n",
      "NL: BROYDEN 14 ; 0.00259566267 4.26507694e-05\n",
      "NL: BROYDEN 15 ; 0.00113639853 1.8672793e-05\n",
      "NL: BROYDEN 16 ; 0.000434036582 7.13189523e-06\n",
      "NL: BROYDEN 17 ; 0.000125653739 2.0646861e-06\n",
      "NL: BROYDEN 18 ; 2.10695157e-05 3.46204869e-07\n",
      "NL: BROYDEN 19 ; 1.29547486e-06 2.12866642e-08\n",
      "NL: BROYDEN 20 ; 1.45259789e-08 2.38684396e-10\n",
      "NL: BROYDENSolver 'NL: BROYDEN' on system 'circuit' failed to converge in 20 iterations.\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.scripts.circuit_analysis import Circuit\n",
    "\n",
    "p = om.Problem()\n",
    "model = p.model\n",
    "\n",
    "model.add_subsystem('circuit', Circuit(), promotes_inputs=[('Vg', 'V'), ('I_in', 'I')])\n",
    "model.set_input_defaults('V', 0., units='V')\n",
    "model.set_input_defaults('I', 0.1, units='A')\n",
    "\n",
    "p.setup()\n",
    "\n",
    "# Replace existing solver with om.BroydenSolver\n",
    "model.circuit.nonlinear_solver = om.BroydenSolver()\n",
    "model.circuit.nonlinear_solver.options['maxiter'] = 20\n",
    "\n",
    "# Specify states for Broyden to solve\n",
    "model.circuit.nonlinear_solver.options['state_vars'] = ['n1.V', 'n2.V']\n",
    "\n",
    "model.nonlinear_solver.linear_solver = om.LinearBlockGS()\n",
    "\n",
    "# set some initial guesses\n",
    "p.set_val('circuit.n1.V', 10.)\n",
    "p.set_val('circuit.n2.V', 1.)\n",
    "\n",
    "p.set_solver_print(level=2)\n",
    "p.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "47dcb401",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.319484Z",
     "iopub.status.busy": "2026-10-02T14:42:29.319293Z",
     "iopub.status.idle": "2026-10-02T14:42:29.322168Z",
     "shell.execute_reply": "2026-10-02T14:42:29.321728Z"
    },
    "papermill": {
     "duration": 0.007956,
     "end_time": "2026-10-02T14:42:29.323315+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.315359+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[9.90804735]\n",
      "[0.71278226]\n"
     ]
    }
   ],
   "source": [
    "print(p.get_val('circuit.n1.V'))\n",
    "print(p.get_val('circuit.n2.V'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ddab4474",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.329448Z",
     "iopub.status.busy": "2026-10-02T14:42:29.329224Z",
     "iopub.status.idle": "2026-10-02T14:42:29.332814Z",
     "shell.execute_reply": "2026-10-02T14:42:29.332312Z"
    },
    "papermill": {
     "duration": 0.007264,
     "end_time": "2026-10-02T14:42:29.333283+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.326019+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.10000001]\n"
     ]
    }
   ],
   "source": [
    "# sanity check: should sum to .1 Amps\n",
    "print(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "aa437d30",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.338152Z",
     "iopub.status.busy": "2026-10-02T14:42:29.338013Z",
     "iopub.status.idle": "2026-10-02T14:42:29.342420Z",
     "shell.execute_reply": "2026-10-02T14:42:29.341732Z"
    },
    "papermill": {
     "duration": 0.007438,
     "end_time": "2026-10-02T14:42:29.342850+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.335412+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.4525978864199374e-07)"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(p.get_val('circuit.n1.V'), 9.90804735, 1e-5)\n",
    "assert_near_equal(p.get_val('circuit.n2.V'), 0.71278226, 1e-5)\n",
    "\n",
    "# sanity check: should sum to .1 Amps\n",
    "assert_near_equal(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'), .1, 1e-6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7f4832a",
   "metadata": {
    "papermill": {
     "duration": 0.001558,
     "end_time": "2026-10-02T14:42:29.346279+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.344721+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## BroydenSolver for Models Without Derivatives\n",
    "\n",
    "The `BroydenSolver` can be used for models where you don't have any partial derivatives defined, and don't wish to use finite difference to calculate them. This behavior is activated by setting the \"compute_jacobian\" option to False. Instead of calculating an initial Jacobian, we start with an estimate that is just the identity matrix scaled by a tunable parameter in the options called \"alpha\". As the `BroydenSolver` iterates, this estimate of the Jacobian is improved, and for some problems, a solution can be reached that satisfies the residual equations.\n",
    "\n",
    "In this example, we solve for the coupling variable in a version of the Sellar model that severs the cycle\n",
    "and expresses the difference across the broken cycle as an implicit state, which the `BroydenSolver` will\n",
    "solve."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "9027dfb1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.350368Z",
     "iopub.status.busy": "2026-10-02T14:42:29.350185Z",
     "iopub.status.idle": "2026-10-02T14:42:29.370728Z",
     "shell.execute_reply": "2026-10-02T14:42:29.370203Z"
    },
    "papermill": {
     "duration": 0.023267,
     "end_time": "2026-10-02T14:42:29.371188+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.347921+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\">SellarStateConnection</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. This version uses the disciplines with derivatives.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">initialize</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;nonlinear_solver&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">NewtonSolver</span><span class=\"p\">(</span><span class=\"n\">solve_subsystems</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">),</span>\n                             <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Nonlinear solver (class or instance) for Sellar MDA&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;nl_atol&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span>\n                             <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;User-specified atol for nonlinear solver.&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;nl_maxiter&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span>\n                             <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Iteration limit for nonlinear solver.&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;linear_solver&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ScipyKrylov</span><span class=\"p\">,</span>\n                             <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Linear solver (class or instance)&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;ln_atol&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span>\n                             <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;User-specified atol for linear solver.&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;ln_maxiter&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span>\n                             <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Iteration limit for linear solver.&#39;</span><span class=\"p\">)</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\">sub</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;sub&#39;</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=\"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>\n                                           <span class=\"s1\">&#39;state_eq.y2_actual&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;state_eq.y2_command&#39;</span><span class=\"p\">,</span>\n                                           <span class=\"s1\">&#39;d1.y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;d2.y2&#39;</span><span class=\"p\">])</span>\n\n        <span class=\"n\">subgrp</span> <span class=\"o\">=</span> <span class=\"n\">sub</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;state_eq_group&#39;</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=\"n\">promotes</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;state_eq.y2_actual&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;state_eq.y2_command&#39;</span><span class=\"p\">])</span>\n        <span class=\"n\">subgrp</span><span class=\"o\">.</span><span class=\"n\">add_subsystem</span><span class=\"p\">(</span><span class=\"s1\">&#39;state_eq&#39;</span><span class=\"p\">,</span> <span class=\"n\">StateConnection</span><span class=\"p\">())</span>\n\n        <span class=\"n\">sub</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\">SellarDis1withDerivatives</span><span class=\"p\">(),</span> <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>\n        <span class=\"n\">sub</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\">SellarDis2withDerivatives</span><span class=\"p\">(),</span> <span class=\"n\">promotes</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\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;state_eq.y2_command&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;d1.y2&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;d2.y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;state_eq.y2_actual&#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;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> <span class=\"n\">y1</span><span class=\"o\">=</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"n\">y2</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;obj&#39;</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;d2.y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;obj_cmp.y2&#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>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">connect</span><span class=\"p\">(</span><span class=\"s1\">&#39;d2.y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;con_cmp2.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=\"n\">nl</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;nonlinear_solver&#39;</span><span class=\"p\">]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nonlinear_solver</span> <span class=\"o\">=</span> <span class=\"n\">nl</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">inspect</span><span class=\"o\">.</span><span class=\"n\">isclass</span><span class=\"p\">(</span><span class=\"n\">nl</span><span class=\"p\">)</span> <span class=\"k\">else</span> <span class=\"n\">nl</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;nl_atol&#39;</span><span class=\"p\">]:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nonlinear_solver</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;atol&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;nl_atol&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;nl_maxiter&#39;</span><span class=\"p\">]:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">nonlinear_solver</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;maxiter&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;nl_maxiter&#39;</span><span class=\"p\">]</span>\n\n        <span class=\"n\">ln</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;linear_solver&#39;</span><span class=\"p\">]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linear_solver</span> <span class=\"o\">=</span> <span class=\"n\">ln</span><span class=\"p\">()</span> <span class=\"k\">if</span> <span class=\"n\">inspect</span><span class=\"o\">.</span><span class=\"n\">isclass</span><span class=\"p\">(</span><span class=\"n\">ln</span><span class=\"p\">)</span> <span class=\"k\">else</span> <span class=\"n\">ln</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;ln_atol&#39;</span><span class=\"p\">]:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linear_solver</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;atol&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;ln_atol&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;ln_maxiter&#39;</span><span class=\"p\">]:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">linear_solver</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;maxiter&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;ln_maxiter&#39;</span><span class=\"p\">]</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">configure</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">sub</span><span class=\"o\">.</span><span class=\"n\">linear_solver</span> <span class=\"o\">=</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ScipyKrylov</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">sub</span><span class=\"o\">.</span><span class=\"n\">state_eq_group</span><span class=\"o\">.</span><span class=\"n\">linear_solver</span> <span class=\"o\">=</span> <span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ScipyKrylov</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}{SellarStateConnection}\\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. This version uses the disciplines with derivatives.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{initialize}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nonlinear\\PYZus{}solver}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{n}{om}\\PY{o}{.}\\PY{n}{NewtonSolver}\\PY{p}{(}\\PY{n}{solve\\PYZus{}subsystems}\\PY{o}{=}\\PY{k+kc}{False}\\PY{p}{)}\\PY{p}{,}\n                             \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Nonlinear solver (class or instance) for Sellar MDA}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nl\\PYZus{}atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,}\n                             \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{User\\PYZhy{}specified atol for nonlinear solver.}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nl\\PYZus{}maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,}\n                             \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Iteration limit for nonlinear solver.}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{linear\\PYZus{}solver}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{n}{om}\\PY{o}{.}\\PY{n}{ScipyKrylov}\\PY{p}{,}\n                             \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Linear solver (class or instance)}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ln\\PYZus{}atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,}\n                             \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{User\\PYZhy{}specified atol for linear solver.}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ln\\PYZus{}maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,}\n                             \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Iteration limit for linear solver.}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\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}{sub} \\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}{sub}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{(}\\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}{,}\n                                           \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq.y2\\PYZus{}actual}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq.y2\\PYZus{}command}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,}\n                                           \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d1.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d2.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n\n        \\PY{n}{subgrp} \\PY{o}{=} \\PY{n}{sub}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq\\PYZus{}group}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,}\n                                   \\PY{n}{promotes}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq.y2\\PYZus{}actual}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq.y2\\PYZus{}command}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n}{subgrp}\\PY{o}{.}\\PY{n}{add\\PYZus{}subsystem}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{StateConnection}\\PY{p}{(}\\PY{p}{)}\\PY{p}{)}\n\n        \\PY{n}{sub}\\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}{SellarDis1withDerivatives}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,} \\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{p}{)}\n        \\PY{n}{sub}\\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}{SellarDis2withDerivatives}\\PY{p}{(}\\PY{p}{)}\\PY{p}{,} \\PY{n}{promotes}\\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\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq.y2\\PYZus{}command}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d1.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d2.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{state\\PYZus{}eq.y2\\PYZus{}actual}\\PY{l+s+s1}{\\PYZsq{}}\\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{n}{y1}\\PY{o}{=}\\PY{l+m+mf}{0.0}\\PY{p}{,} \\PY{n}{y2}\\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}{obj}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d2.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{obj\\PYZus{}cmp.y2}\\PY{l+s+s1}{\\PYZsq{}}\\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{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{connect}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{d2.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{con\\PYZus{}cmp2.y2}\\PY{l+s+s1}{\\PYZsq{}}\\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{n}{nl} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nonlinear\\PYZus{}solver}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{nl}\\PY{p}{(}\\PY{p}{)} \\PY{k}{if} \\PY{n}{inspect}\\PY{o}{.}\\PY{n}{isclass}\\PY{p}{(}\\PY{n}{nl}\\PY{p}{)} \\PY{k}{else} \\PY{n}{nl}\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nl\\PYZus{}atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{:}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nl\\PYZus{}atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nl\\PYZus{}maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{:}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{nonlinear\\PYZus{}solver}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{nl\\PYZus{}maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n        \\PY{n}{ln} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{linear\\PYZus{}solver}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{linear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{ln}\\PY{p}{(}\\PY{p}{)} \\PY{k}{if} \\PY{n}{inspect}\\PY{o}{.}\\PY{n}{isclass}\\PY{p}{(}\\PY{n}{ln}\\PY{p}{)} \\PY{k}{else} \\PY{n}{ln}\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ln\\PYZus{}atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{:}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{linear\\PYZus{}solver}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ln\\PYZus{}atol}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{k}{if} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ln\\PYZus{}maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{:}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{linear\\PYZus{}solver}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ln\\PYZus{}maxiter}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{configure}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{sub}\\PY{o}{.}\\PY{n}{linear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{om}\\PY{o}{.}\\PY{n}{ScipyKrylov}\\PY{p}{(}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{sub}\\PY{o}{.}\\PY{n}{state\\PYZus{}eq\\PYZus{}group}\\PY{o}{.}\\PY{n}{linear\\PYZus{}solver} \\PY{o}{=} \\PY{n}{om}\\PY{o}{.}\\PY{n}{ScipyKrylov}\\PY{p}{(}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SellarStateConnection(om.Group):\n    \"\"\"\n    Group containing the Sellar MDA. This version uses the disciplines with derivatives.\n    \"\"\"\n\n    def initialize(self):\n        self.options.declare('nonlinear_solver', default=om.NewtonSolver(solve_subsystems=False),\n                             desc='Nonlinear solver (class or instance) for Sellar MDA')\n        self.options.declare('nl_atol', default=None,\n                             desc='User-specified atol for nonlinear solver.')\n        self.options.declare('nl_maxiter', default=None,\n                             desc='Iteration limit for nonlinear solver.')\n        self.options.declare('linear_solver', default=om.ScipyKrylov,\n                             desc='Linear solver (class or instance)')\n        self.options.declare('ln_atol', default=None,\n                             desc='User-specified atol for linear solver.')\n        self.options.declare('ln_maxiter', default=None,\n                             desc='Iteration limit for linear solver.')\n\n    def setup(self):\n        sub = self.add_subsystem('sub', om.Group(),\n                                 promotes=['x', 'z', 'y1',\n                                           'state_eq.y2_actual', 'state_eq.y2_command',\n                                           'd1.y2', 'd2.y2'])\n\n        subgrp = sub.add_subsystem('state_eq_group', om.Group(),\n                                   promotes=['state_eq.y2_actual', 'state_eq.y2_command'])\n        subgrp.add_subsystem('state_eq', StateConnection())\n\n        sub.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1'])\n        sub.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1'])\n\n        self.connect('state_eq.y2_command', 'd1.y2')\n        self.connect('d2.y2', 'state_eq.y2_actual')\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, y1=0.0, y2=0.0),\n                           promotes=['x', 'z', 'y1', 'obj'])\n        self.connect('d2.y2', 'obj_cmp.y2')\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'])\n        self.connect('d2.y2', 'con_cmp2.y2')\n\n        self.set_input_defaults('x', 1.0)\n        self.set_input_defaults('z', np.array([5.0, 2.0]))\n\n        nl = self.options['nonlinear_solver']\n        self.nonlinear_solver = nl() if inspect.isclass(nl) else nl\n        if self.options['nl_atol']:\n            self.nonlinear_solver.options['atol'] = self.options['nl_atol']\n        if self.options['nl_maxiter']:\n            self.nonlinear_solver.options['maxiter'] = self.options['nl_maxiter']\n\n        ln = self.options['linear_solver']\n        self.linear_solver = ln() if inspect.isclass(ln) else ln\n        if self.options['ln_atol']:\n            self.linear_solver.options['atol'] = self.options['ln_atol']\n        if self.options['ln_maxiter']:\n            self.linear_solver.options['maxiter'] = self.options['ln_maxiter']\n\n    def configure(self):\n        self.sub.linear_solver = om.ScipyKrylov()\n        self.sub.state_eq_group.linear_solver = om.ScipyKrylov()"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src22"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src22\", get_code(\"openmdao.test_suite.components.sellar.SellarStateConnection\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "268cce37",
   "metadata": {
    "papermill": {
     "duration": 0.183698,
     "end_time": "2026-10-02T14:42:29.557554+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.373856+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarStateConnection` class definition \n",
    "\n",
    "{glue:}`code_src22`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "b4cc1b61",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.568612Z",
     "iopub.status.busy": "2026-10-02T14:42:29.567996Z",
     "iopub.status.idle": "2026-10-02T14:42:29.583611Z",
     "shell.execute_reply": "2026-10-02T14:42:29.583135Z"
    },
    "papermill": {
     "duration": 0.021478,
     "end_time": "2026-10-02T14:42:29.584113+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.562635+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: BROYDEN 0 ; 11.2725705 1\n",
      "|  LS: BCHK 0 ; 6.82339784 0.605309838\n",
      "NL: BROYDEN 1 ; 6.67731871 0.592351025\n",
      "|  LS: BCHK 0 ; 1.31638163 0.197142249\n",
      "NL: BROYDEN 2 ; 0.00261878643 0.00023231493\n",
      "|  LS: BCHK 0 ; 0.000516169776 0.197102661\n",
      "NL: BROYDEN 3 ; 6.33742047e-07 5.62198343e-08\n",
      "|  LS: BCHK 0 ; 1.2489701e-07 0.197078624\n",
      "NL: BROYDEN 4 ; 6.21724894e-14 5.51537817e-15\n",
      "NL: BROYDEN Converged\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.sellar import SellarStateConnection\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model = SellarStateConnection(nonlinear_solver=om.BroydenSolver(),\n",
    "                                           linear_solver=om.LinearRunOnce())\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "model.nonlinear_solver.options['state_vars'] = ['state_eq.y2_command']\n",
    "model.nonlinear_solver.options['compute_jacobian'] = False\n",
    "\n",
    "prob.set_solver_print(level=2)\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "7a7767b0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.588827Z",
     "iopub.status.busy": "2026-10-02T14:42:29.588683Z",
     "iopub.status.idle": "2026-10-02T14:42:29.591421Z",
     "shell.execute_reply": "2026-10-02T14:42:29.590939Z"
    },
    "papermill": {
     "duration": 0.005493,
     "end_time": "2026-10-02T14:42:29.591807+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.586314+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[25.58830237]\n",
      "[12.05848815]\n"
     ]
    }
   ],
   "source": [
    "print(prob['y1'])\n",
    "print(prob['state_eq.y2_command'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "0025079f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.597034Z",
     "iopub.status.busy": "2026-10-02T14:42:29.596782Z",
     "iopub.status.idle": "2026-10-02T14:42:29.599637Z",
     "shell.execute_reply": "2026-10-02T14:42:29.599257Z"
    },
    "papermill": {
     "duration": 0.006133,
     "end_time": "2026-10-02T14:42:29.600132+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.593999+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(3.266453330990709e-09)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob['y1'], 25.58830273, .00001)\n",
    "assert_near_equal(prob['state_eq.y2_command'], 12.05848819, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df3b0b8d",
   "metadata": {
    "papermill": {
     "duration": 0.002122,
     "end_time": "2026-10-02T14:42:29.604559+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.602437+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## BroydenSolver Option Examples\n",
    "\n",
    "There are a few additional options that give you more control over when and how often the Jacobian is recomputed.\n",
    "The \"diverge_limit\" option allows you to define a limit to the ratio of current residual and the previous iteration's residual above which the solution is considered to be diverging. If this limit is exceeded, then the Jacobian is always recomputed on the next iteration. There is also a \"converge_limit\" that allows you similarly define a limit above which the solution is considered to be non-converging. When this limit is exceeded, the Jacobian is not immediately recomputed until the limit has been exceeded a number of consecutive times as defined by the \"max_converge_failures\" option. The default value for \"max_converge_failures\" is 3, and the default \"converge_limit\" is 1.0. Exploring these options can help you solve more quickly (or in some cases solve at all) some tougher problems.\n",
    "\n",
    "Here, we take the same circuit example from above and specify a much lower \"converge_limit\" and \"max_converge_failures\" to force recomputation of the Jacobian much more frequently. This results in a quicker convergence in terms of the number of iterations, though keep in mind that solving for the derivatives adds computational cost."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "826aac2d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.615608Z",
     "iopub.status.busy": "2026-10-02T14:42:29.615450Z",
     "iopub.status.idle": "2026-10-02T14:42:29.639485Z",
     "shell.execute_reply": "2026-10-02T14:42:29.639007Z"
    },
    "papermill": {
     "duration": 0.027873,
     "end_time": "2026-10-02T14:42:29.640035+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.612162+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=======\n",
      "circuit\n",
      "=======\n",
      "NL: BROYDEN 0 ; 60.8585191 1\n",
      "NL: BROYDEN 1 ; 22.3883642 0.367875599\n",
      "NL: BROYDEN 2 ; 8.23598116 0.135329963\n",
      "NL: BROYDEN 3 ; 3.02960973 0.0497811937\n",
      "NL: BROYDEN 4 ; 1.11429207 0.0183095495\n",
      "NL: BROYDEN 5 ; 0.409685491 0.00673176898\n",
      "NL: BROYDEN 6 ; 0.150474776 0.0024725343\n",
      "NL: BROYDEN 7 ; 0.055116451 0.000905648902\n",
      "NL: BROYDEN 8 ; 0.0200371642 0.000329241731\n",
      "NL: BROYDEN 9 ; 0.00713629394 0.000117260394\n",
      "NL: BROYDEN 10 ; 0.00240228312 3.94732431e-05\n",
      "NL: BROYDEN 11 ; 0.000691815028 1.13675955e-05\n",
      "NL: BROYDEN 12 ; 0.000282709816 4.6453614e-06\n",
      "NL: BROYDEN 13 ; 6.22512906e-05 1.0228854e-06\n",
      "NL: BROYDEN 14 ; 7.63617209e-06 1.25474169e-07\n",
      "NL: BROYDEN 15 ; 2.44772377e-07 4.02199035e-09\n",
      "NL: BROYDEN 16 ; 1.00501245e-09 1.65139156e-11\n",
      "NL: BROYDEN Converged\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.scripts.circuit_analysis import Circuit\n",
    "\n",
    "p = om.Problem()\n",
    "model = p.model\n",
    "\n",
    "model.add_subsystem('circuit', Circuit(), promotes_inputs=[('Vg', 'V'), ('I_in', 'I')])\n",
    "model.set_input_defaults('V', 0., units='V')\n",
    "model.set_input_defaults('I', 0.1, units='A')\n",
    "\n",
    "p.setup()\n",
    "\n",
    "# Replace existing solver with BroydenSolver\n",
    "model.circuit.nonlinear_solver = om.BroydenSolver()\n",
    "model.circuit.nonlinear_solver.options['maxiter'] = 20\n",
    "model.circuit.nonlinear_solver.options['converge_limit'] = 0.1\n",
    "model.circuit.nonlinear_solver.options['max_converge_failures'] = 1\n",
    "\n",
    "# Specify states for Broyden to solve\n",
    "model.circuit.nonlinear_solver.options['state_vars'] = ['n1.V', 'n2.V']\n",
    "\n",
    "# set some initial guesses\n",
    "p.set_val('circuit.n1.V', 10.)\n",
    "p.set_val('circuit.n2.V', 1.)\n",
    "\n",
    "p.set_solver_print(level=2)\n",
    "p.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "b553d8d3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.646350Z",
     "iopub.status.busy": "2026-10-02T14:42:29.646174Z",
     "iopub.status.idle": "2026-10-02T14:42:29.649166Z",
     "shell.execute_reply": "2026-10-02T14:42:29.648657Z"
    },
    "papermill": {
     "duration": 0.007018,
     "end_time": "2026-10-02T14:42:29.649831+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.642813+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[9.90804735]\n",
      "[0.71278188]\n"
     ]
    }
   ],
   "source": [
    "print(p.get_val('circuit.n1.V'))\n",
    "print(p.get_val('circuit.n2.V'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "817930d7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.656204Z",
     "iopub.status.busy": "2026-10-02T14:42:29.656035Z",
     "iopub.status.idle": "2026-10-02T14:42:29.659329Z",
     "shell.execute_reply": "2026-10-02T14:42:29.658530Z"
    },
    "papermill": {
     "duration": 0.007352,
     "end_time": "2026-10-02T14:42:29.659926+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.652574+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.1]\n"
     ]
    }
   ],
   "source": [
    "# sanity check: should sum to .1 Amps\n",
    "print(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "0be119a2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.666349Z",
     "iopub.status.busy": "2026-10-02T14:42:29.666184Z",
     "iopub.status.idle": "2026-10-02T14:42:29.670087Z",
     "shell.execute_reply": "2026-10-02T14:42:29.669642Z"
    },
    "papermill": {
     "duration": 0.008322,
     "end_time": "2026-10-02T14:42:29.671049+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.662727+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.0050124482630096e-08)"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(p.get_val('circuit.n1.V'), 9.90804735, 1e-5)\n",
    "assert_near_equal(p.get_val('circuit.n2.V'), 0.71278226, 1e-5)\n",
    "\n",
    "# sanity check: should sum to .1 Amps\n",
    "assert_near_equal(p.get_val('circuit.R1.I') + p.get_val('circuit.D1.I'), .1, 1e-6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bae367e",
   "metadata": {
    "papermill": {
     "duration": 0.002264,
     "end_time": "2026-10-02T14:42:29.676035+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.673771+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**stall_limit, stall_tol, and stall_tol_type **\n",
    "\n",
    "  In some cases, nonlinear solvers can stall out where the norm of the residual stops changing at all. This\n",
    "  can happen for a couple of reasons. You can hit numerical noise problems and just be wandering around in\n",
    "  a circle, or you can get stuck on a bound and the line search just keeps running into the same spot no\n",
    "  matter what. Either way, if you have say 100 max iterations and you stall at 15 ... you waste a lot of\n",
    "  compute time. To remedy this, you can turn on stall detection in all nonlinear solvers by setting the\n",
    "  \"stall_limit\" option to a number greater than zero.\n",
    "\n",
    "  In this example, we set stall_limit to 3. While the solver iterates, it will compare the value of the\n",
    "  residual norm to the value computed in the previous iteration.  If the value matches for three iterations\n",
    "  in a row, then iteration will terminate due to detection of a stall. If \"err_on_non_converge\" is set\n",
    "  to True, then an ``AnalysisError`` will be raised just as if we had reached the iteration count limit.\n",
    "\n",
    "  We also set the `stall_tol` to 1e-6, which is the threshold below which a change in the relative residual\n",
    "  norm is considered to be unchanged. The option also exists to use the absolute residual norm by setting\n",
    "  `stall_tol_type` to `'abs'`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "11938f50",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:29.681545Z",
     "iopub.status.busy": "2026-10-02T14:42:29.681405Z",
     "iopub.status.idle": "2026-10-02T14:42:29.691194Z",
     "shell.execute_reply": "2026-10-02T14:42:29.690791Z"
    },
    "papermill": {
     "duration": 0.013546,
     "end_time": "2026-10-02T14:42:29.691885+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:29.678339+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: BROYDEN 0 ; 4 1\n",
      "|  LS: BCHK 0 ; 4.76340215 1.50632002\n",
      "NL: BROYDEN 1 ; 0.7 0.175\n",
      "|  LS: BCHK 0 ; 0.63953754 0.913625056\n",
      "NL: BROYDEN 2 ; 0.7 0.175\n",
      "|  LS: BCHK 0 ; 0.63953754 0.913625056\n",
      "NL: BROYDEN 3 ; 0.7 0.175\n",
      "|  LS: BCHK 0 ; 0.63953754 0.913625056\n",
      "NL: BROYDEN 4 ; 0.7 0.175\n",
      "NL: BROYDENSolver 'NL: BROYDEN' on system '' stalled after 4 iterations.\n"
     ]
    }
   ],
   "source": [
    "prob = om.Problem()\n",
    "\n",
    "prob.model.add_subsystem('comp', om.ExecComp('y=3*x+1'), promotes=['*'])\n",
    "\n",
    "balance = prob.model.add_subsystem('balance', om.BalanceComp(),\n",
    "                                   promotes=['*'])\n",
    "balance.add_balance('x', lower=-.1, upper=10, rhs_val=0, lhs_name='y')\n",
    "\n",
    "nl_solver = prob.model.nonlinear_solver = om.BroydenSolver()\n",
    "nl_solver.options['stall_limit'] = 3\n",
    "nl_solver.options['stall_tol'] = 1e-8\n",
    "nl_solver.options['maxiter'] = 100\n",
    "\n",
    "prob.model.linear_solver = om.DirectSolver()\n",
    "\n",
    "prob.setup()\n",
    "prob.set_solver_print()\n",
    "\n",
    "prob.run_model()"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 5.553214,
   "end_time": "2026-10-02T14:42:30.510048+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/solvers/broyden.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/solvers/broyden.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:42:24.956834+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}