{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3e8a1996",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:43.021123Z",
     "iopub.status.busy": "2026-10-02T14:42:43.020891Z",
     "iopub.status.idle": "2026-10-02T14:42:43.025661Z",
     "shell.execute_reply": "2026-10-02T14:42:43.025051Z"
    },
    "papermill": {
     "duration": 0.0098,
     "end_time": "2026-10-02T14:42:43.026781+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:43.016981+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": "b328049d",
   "metadata": {
    "papermill": {
     "duration": 0.004455,
     "end_time": "2026-10-02T14:42:43.034289+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:43.029834+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# NewtonSolver\n",
    "\n",
    "NewtonSolver implements Newton's method to solve the system that contains it. This\n",
    "is the most general solver in OpenMDAO, in that it can solve any topology including cyclic\n",
    "connections and implicit states in the system or subsystems. Newton's method requires derivatives,\n",
    "so a linear solver can also be specified. By default, NewtonSolver uses the linear solver\n",
    "that is slotted in the containing system.\n",
    "\n",
    "OpenMDAO's implementation is very close to pure Newton's method, but adds line searches,\n",
    "bounds on state variables, and techniques to unstick the solver if it stalls. For an intuitive\n",
    "understanding of how Newton's method works and how it extends to multiple dimensions, take a look\n",
    "at the following video:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "aeb64355",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:43.040140Z",
     "iopub.status.busy": "2026-10-02T14:42:43.039936Z",
     "iopub.status.idle": "2026-10-02T14:42:43.045604Z",
     "shell.execute_reply": "2026-10-02T14:42:43.044922Z"
    },
    "papermill": {
     "duration": 0.009345,
     "end_time": "2026-10-02T14:42:43.046094+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:43.036749+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"1\"\n",
       "            height=\"1\"\n",
       "            src=\"https://www.youtube-nocookie.com/embed/fuHl4bgCQTI\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "            title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" style=\"width: 85%; height: 100%; aspect-ratio: 16 / 9; margin-left: auto; margin-right: auto; display: block;\"\n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.IFrame at 0x7fc69440ea50>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import IFrame\n",
    "IFrame(\n",
    "    \"https://www.youtube-nocookie.com/embed/fuHl4bgCQTI\",\n",
    "    width=1,\n",
    "    height=1,\n",
    "    extras=[\n",
    "        \"title=\\\"YouTube video player\\\"\",\n",
    "        \"frameborder=\\\"0\\\"\",\n",
    "        \"allow=\\\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\\\"\",\n",
    "        \"style=\\\"width: 85%; height: 100%; aspect-ratio: 16 / 9; margin-left: auto; margin-right: auto; display: block;\\\"\"\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7f5bf1e9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:43.051873Z",
     "iopub.status.busy": "2026-10-02T14:42:43.051714Z",
     "iopub.status.idle": "2026-10-02T14:42:45.193027Z",
     "shell.execute_reply": "2026-10-02T14:42:45.192295Z"
    },
    "papermill": {
     "duration": 2.14554,
     "end_time": "2026-10-02T14:42:45.194117+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:43.048577+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\">SellarDis1withDerivatives</span><span class=\"p\">(</span><span class=\"n\">SellarDis1</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Component containing Discipline 1 -- derivatives version.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Analytic Derivs</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"n\">of</span><span class=\"o\">=</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">,</span> <span class=\"n\">wrt</span><span class=\"o\">=</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">compute_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">partials</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Jacobian for Sellar discipline 1.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">partials</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mf\">0.2</span>\n        <span class=\"n\">partials</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">]</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\">2.0</span> <span class=\"o\">*</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">][</span><span class=\"mi\">0</span><span class=\"p\">],</span> <span class=\"mf\">1.0</span><span class=\"p\">]])</span>\n        <span class=\"n\">partials</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;x&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{SellarDis1withDerivatives}\\PY{p}{(}\\PY{n}{SellarDis1}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{    Component containing Discipline 1 \\PYZhy{}\\PYZhy{} derivatives version.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{c+c1}{\\PYZsh{} Analytic Derivs}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{n}{of}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{wrt}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{compute\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{partials}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Jacobian for Sellar discipline 1.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n}{partials}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{o}{\\PYZhy{}}\\PY{l+m+mf}{0.2}\n        \\PY{n}{partials}\\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}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{p}{[}\\PY{l+m+mf}{2.0} \\PY{o}{*} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{[}\\PY{l+m+mi}{0}\\PY{p}{]}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{]}\\PY{p}{]}\\PY{p}{)}\n        \\PY{n}{partials}\\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}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mf}{1.0}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SellarDis1withDerivatives(SellarDis1):\n    \"\"\"\n    Component containing Discipline 1 -- derivatives version.\n    \"\"\"\n\n    def setup_partials(self):\n        # Analytic Derivs\n        self.declare_partials(of='*', wrt='*')\n\n    def compute_partials(self, inputs, partials):\n        \"\"\"\n        Jacobian for Sellar discipline 1.\n        \"\"\"\n        partials['y1', 'y2'] = -0.2\n        partials['y1', 'z'] = np.array([[2.0 * inputs['z'][0], 1.0]])\n        partials['y1', 'x'] = 1.0"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src29"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src29\", get_code(\"openmdao.test_suite.components.sellar.SellarDis1withDerivatives\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c25dbcaf",
   "metadata": {
    "papermill": {
     "duration": 0.002637,
     "end_time": "2026-10-02T14:42:45.199546+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:45.196909+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarDis1withDerivatives` class definition \n",
    "\n",
    "{glue:}`code_src29`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ff2b602b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:45.205589Z",
     "iopub.status.busy": "2026-10-02T14:42:45.205386Z",
     "iopub.status.idle": "2026-10-02T14:42:45.214139Z",
     "shell.execute_reply": "2026-10-02T14:42:45.213481Z"
    },
    "papermill": {
     "duration": 0.01258,
     "end_time": "2026-10-02T14:42:45.214674+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:45.202094+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\">SellarDis2withDerivatives</span><span class=\"p\">(</span><span class=\"n\">SellarDis2</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Component containing Discipline 2 -- derivatives version.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\"># Analytic Derivs</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"n\">of</span><span class=\"o\">=</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">,</span> <span class=\"n\">wrt</span><span class=\"o\">=</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">compute_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">J</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Jacobian for Sellar discipline 2.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">y1</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">]</span>\n        <span class=\"k\">if</span> <span class=\"n\">y1</span><span class=\"o\">.</span><span class=\"n\">real</span> <span class=\"o\">&lt;</span> <span class=\"mf\">0.0</span><span class=\"p\">:</span>\n            <span class=\"n\">y1</span> <span class=\"o\">*=</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">y1</span><span class=\"o\">.</span><span class=\"n\">real</span> <span class=\"o\">&lt;</span> <span class=\"mf\">1e-8</span><span class=\"p\">:</span>\n            <span class=\"n\">y1</span> <span class=\"o\">=</span> <span class=\"mf\">1e-8</span>\n\n        <span class=\"n\">J</span><span class=\"p\">[</span><span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">.5</span><span class=\"o\">*</span><span class=\"n\">y1</span><span class=\"o\">**-</span><span class=\"mf\">.5</span>\n        <span class=\"n\">J</span><span class=\"p\">[</span><span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">]</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\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</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}{SellarDis2withDerivatives}\\PY{p}{(}\\PY{n}{SellarDis2}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{    Component containing Discipline 2 \\PYZhy{}\\PYZhy{} derivatives version.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{c+c1}{\\PYZsh{} Analytic Derivs}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{n}{of}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{wrt}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{compute\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{J}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Jacobian for Sellar discipline 2.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n}{y1} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{k}{if} \\PY{n}{y1}\\PY{o}{.}\\PY{n}{real} \\PY{o}{\\PYZlt{}} \\PY{l+m+mf}{0.0}\\PY{p}{:}\n            \\PY{n}{y1} \\PY{o}{*}\\PY{o}{=} \\PY{o}{\\PYZhy{}}\\PY{l+m+mi}{1}\n        \\PY{k}{if} \\PY{n}{y1}\\PY{o}{.}\\PY{n}{real} \\PY{o}{\\PYZlt{}} \\PY{l+m+mf}{1e\\PYZhy{}8}\\PY{p}{:}\n            \\PY{n}{y1} \\PY{o}{=} \\PY{l+m+mf}{1e\\PYZhy{}8}\n\n        \\PY{n}{J}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mf}{.5}\\PY{o}{*}\\PY{n}{y1}\\PY{o}{*}\\PY{o}{*}\\PY{o}{\\PYZhy{}}\\PY{l+m+mf}{.5}\n        \\PY{n}{J}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{p}{[}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{]}\\PY{p}{]}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SellarDis2withDerivatives(SellarDis2):\n    \"\"\"\n    Component containing Discipline 2 -- derivatives version.\n    \"\"\"\n\n    def setup_partials(self):\n        # Analytic Derivs\n        self.declare_partials(of='*', wrt='*')\n\n    def compute_partials(self, inputs, J):\n        \"\"\"\n        Jacobian for Sellar discipline 2.\n        \"\"\"\n        y1 = inputs['y1']\n        if y1.real < 0.0:\n            y1 *= -1\n        if y1.real < 1e-8:\n            y1 = 1e-8\n\n        J['y2', 'y1'] = .5*y1**-.5\n        J['y2', 'z'] = np.array([[1.0, 1.0]])"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src30"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src30\", get_code(\"openmdao.test_suite.components.sellar.SellarDis2withDerivatives\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f8db0e5",
   "metadata": {
    "papermill": {
     "duration": 0.002601,
     "end_time": "2026-10-02T14:42:45.219949+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:45.217348+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarDis2withDerivatives` class definition \n",
    "\n",
    "{glue:}`code_src30`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "78eca69b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:45.226194Z",
     "iopub.status.busy": "2026-10-02T14:42:45.226026Z",
     "iopub.status.idle": "2026-10-02T14:42:46.457208Z",
     "shell.execute_reply": "2026-10-02T14:42:46.456568Z"
    },
    "papermill": {
     "duration": 1.235535,
     "end_time": "2026-10-02T14:42:46.458080+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:45.222545+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952166.438925] [runnervm8df0l:7276 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55bfe1d2e600 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",
      "[1790952166.439203] [runnervm8df0l:7276 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "NL: Newton Converged in 3 iterations\n",
      "[25.58830237]\n",
      "[12.05848815]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:07276] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])\n",
    "model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                           z=np.array([0.0, 0.0]), x=0.0),\n",
    "                    promotes=['obj', 'x', 'z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n",
    "\n",
    "model.linear_solver = om.DirectSolver()\n",
    "\n",
    "model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 1.)\n",
    "prob.set_val('z', np.array([5.0, 2.0]))\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1fb4ca3b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.463609Z",
     "iopub.status.busy": "2026-10-02T14:42:46.463442Z",
     "iopub.status.idle": "2026-10-02T14:42:46.468089Z",
     "shell.execute_reply": "2026-10-02T14:42:46.467415Z"
    },
    "papermill": {
     "duration": 0.008193,
     "end_time": "2026-10-02T14:42:46.468720+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.460527+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(3.250496376340271e-09)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(prob.get_val('y1'), 25.58830273, .00001)\n",
    "assert_near_equal(prob.get_val('y2'), 12.05848819, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ebf5798",
   "metadata": {
    "papermill": {
     "duration": 0.003277,
     "end_time": "2026-10-02T14:42:46.475233+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.471956+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Most of the solvers in OpenMDAO operate hierarchically, in that you can use solvers on subgroups\n",
    "to subdivide the calculation effort. However, NewtonSolver is an exception. It does not\n",
    "call `solve_nonlinear` on its subsystems, nor does it pass data along the connections. Instead,\n",
    "the Newton solver sets all inputs in all systems and subsystems that it contains, as it follows\n",
    "the gradient, driving the residuals to convergence.  After each iteration, the iteration count and the residual norm are\n",
    "checked to see if termination has been satisfied.\n",
    "\n",
    "NewtonSolver Options\n",
    "--------------------"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "89d9629f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.482286Z",
     "iopub.status.busy": "2026-10-02T14:42:46.482126Z",
     "iopub.status.idle": "2026-10-02T14:42:46.486021Z",
     "shell.execute_reply": "2026-10-02T14:42:46.485353Z"
    },
    "papermill": {
     "duration": 0.008135,
     "end_time": "2026-10-02T14:42:46.486535+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.478400+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;\">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: #F3F3F3;\"><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: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">debug_print</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">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: #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_sub_solves</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 subsystem solves.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><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: #F3F3F3;\"><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: ghostwhite;\"><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: #F3F3F3;\"><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: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">solve_subsystems</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">**Required**</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;\">Set to True to turn on sub-solvers (Hybrid Newton).</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",
       "    </table>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "om.show_options_table(\"openmdao.solvers.nonlinear.newton.NewtonSolver\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78e14f07",
   "metadata": {
    "papermill": {
     "duration": 0.003384,
     "end_time": "2026-10-02T14:42:46.493222+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.489838+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## NewtonSolver Constructor\n",
    "\n",
    "The call signature for the `NewtonSolver` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.solvers.nonlinear.newton.NewtonSolver.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## NewtonSolver Option Examples\n",
    "\n",
    "**maxiter**\n",
    "\n",
    "  `maxiter` lets you specify the maximum number of Newton iterations to apply. In this example, we\n",
    "  cut it back from the default, ten, down to two, so that it terminates a few iterations earlier and doesn't\n",
    "  reach the specified absolute or relative tolerance."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0e3a002b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.500645Z",
     "iopub.status.busy": "2026-10-02T14:42:46.500499Z",
     "iopub.status.idle": "2026-10-02T14:42:46.512891Z",
     "shell.execute_reply": "2026-10-02T14:42:46.512118Z"
    },
    "papermill": {
     "duration": 0.016949,
     "end_time": "2026-10-02T14:42:46.513588+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.496639+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 2 iterations.\n",
      "[25.58785168]\n",
      "[12.06074161]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])\n",
    "model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                        z=np.array([0.0, 0.0]), x=0.0),\n",
    "                    promotes=['obj', 'x', 'z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n",
    "\n",
    "model.linear_solver = om.DirectSolver()\n",
    "\n",
    "newton = model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "newton.options['maxiter'] = 2\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 1.)\n",
    "prob.set_val('z', np.array([5.0, 2.0]))\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d793dc14",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.518925Z",
     "iopub.status.busy": "2026-10-02T14:42:46.518779Z",
     "iopub.status.idle": "2026-10-02T14:42:46.522488Z",
     "shell.execute_reply": "2026-10-02T14:42:46.521771Z"
    },
    "papermill": {
     "duration": 0.007159,
     "end_time": "2026-10-02T14:42:46.523006+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.515847+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.807531673107771e-12)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('y1'), 25.5878516779, .00001)\n",
    "assert_near_equal(prob.get_val('y2'), 12.0607416105, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4fca05b",
   "metadata": {
    "papermill": {
     "duration": 0.002238,
     "end_time": "2026-10-02T14:42:46.527584+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.525346+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**atol**\n",
    "\n",
    "  Here, we set the absolute tolerance to a looser value that will trigger an earlier termination. After\n",
    "  each iteration, the norm of the residuals is calculated by calling `apply_nonlinear` on all of the components.\n",
    "  If this norm value is lower than the absolute\n",
    "  tolerance `atol`, the iteration will terminate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "38ea1bcd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.572434Z",
     "iopub.status.busy": "2026-10-02T14:42:46.572234Z",
     "iopub.status.idle": "2026-10-02T14:42:46.583465Z",
     "shell.execute_reply": "2026-10-02T14:42:46.582840Z"
    },
    "papermill": {
     "duration": 0.037444,
     "end_time": "2026-10-02T14:42:46.584225+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.546781+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton Converged in 3 iterations\n",
      "[25.58830237]\n",
      "[12.05848815]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])\n",
    "model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                        z=np.array([0.0, 0.0]), x=0.0),\n",
    "                    promotes=['obj', 'x', 'z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n",
    "\n",
    "model.linear_solver = om.DirectSolver()\n",
    "\n",
    "newton = model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "newton.options['atol'] = 1e-4\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 1.)\n",
    "prob.set_val('z', np.array([5.0, 2.0]))\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "9fde3968",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.590774Z",
     "iopub.status.busy": "2026-10-02T14:42:46.590584Z",
     "iopub.status.idle": "2026-10-02T14:42:46.593976Z",
     "shell.execute_reply": "2026-10-02T14:42:46.593246Z"
    },
    "papermill": {
     "duration": 0.007145,
     "end_time": "2026-10-02T14:42:46.594450+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.587305+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(3.250496376340271e-09)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('y1'), 25.5882856302, .00001)\n",
    "assert_near_equal(prob.get_val('y2'), 12.05848819, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4f88e20",
   "metadata": {
    "papermill": {
     "duration": 0.00302,
     "end_time": "2026-10-02T14:42:46.599863+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.596843+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**rtol**\n",
    "\n",
    "  Here, we set the relative tolerance to a looser value that will trigger an earlier termination. After\n",
    "  each iteration, the norm of the residuals is calculated by calling `apply_nonlinear` on all of the components.\n",
    "  If the ratio of the currently calculated norm to the\n",
    "  initial residual norm is lower than the relative tolerance `rtol`, the iteration will terminate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "8ddad0b4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.605652Z",
     "iopub.status.busy": "2026-10-02T14:42:46.605504Z",
     "iopub.status.idle": "2026-10-02T14:42:46.616456Z",
     "shell.execute_reply": "2026-10-02T14:42:46.615545Z"
    },
    "papermill": {
     "duration": 0.014628,
     "end_time": "2026-10-02T14:42:46.617024+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.602396+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton Converged in 2 iterations\n",
      "[25.58785168]\n",
      "[12.06074161]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])\n",
    "model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                        z=np.array([0.0, 0.0]), x=0.0),\n",
    "                    promotes=['obj', 'x', 'z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n",
    "\n",
    "model.linear_solver = om.DirectSolver()\n",
    "\n",
    "newton = model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "newton.options['rtol'] = 1e-3\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 1.)\n",
    "prob.set_val('z', np.array([5.0, 2.0]))\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "452d9683",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.622652Z",
     "iopub.status.busy": "2026-10-02T14:42:46.622505Z",
     "iopub.status.idle": "2026-10-02T14:42:46.626166Z",
     "shell.execute_reply": "2026-10-02T14:42:46.625479Z"
    },
    "papermill": {
     "duration": 0.007357,
     "end_time": "2026-10-02T14:42:46.626744+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.619387+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.807531673107771e-12)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('y1'), 25.5878516779, .00001)\n",
    "assert_near_equal(prob.get_val('y2'), 12.0607416105, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86db8e5d",
   "metadata": {
    "papermill": {
     "duration": 0.00229,
     "end_time": "2026-10-02T14:42:46.631599+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.629309+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**solve_subsystems**\n",
    "\n",
    "  If you set this option to True, NewtonSolver will call `solve_nonlinear` on all of its subsystems. You can\n",
    "  use this to solve difficult multi-level problems by attaching solvers to subsystems. This assures that those\n",
    "  subsystems will already be in an internally solved state when the Newton solver goes to solve it.\n",
    "\n",
    "  This example shows two instances of the Sellar model, which we have connected together to form a larger cycle.\n",
    "  We specify a Newton solver in each Sellar subgroup as well as a top-level Newton solver, which we tell to solve\n",
    "  its subsystems."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "313ad362",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.637021Z",
     "iopub.status.busy": "2026-10-02T14:42:46.636893Z",
     "iopub.status.idle": "2026-10-02T14:42:46.643412Z",
     "shell.execute_reply": "2026-10-02T14:42:46.642709Z"
    },
    "papermill": {
     "duration": 0.009846,
     "end_time": "2026-10-02T14:42:46.643880+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.634034+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\">DoubleSellar</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=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</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;g1&#39;</span><span class=\"p\">,</span> <span class=\"n\">SubSellar</span><span class=\"p\">(</span><span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"n\">scaling</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;g2&#39;</span><span class=\"p\">,</span> <span class=\"n\">SubSellar</span><span class=\"p\">(</span><span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"n\">scaling</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;g1.y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;g2.x&#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;g2.y2&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;g1.x&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"c1\"># Converge the outer loop with Gauss Seidel, with a looser tolerance.</span>\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\">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}{DoubleSellar}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{)}\\PY{p}{:}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb}{super}\\PY{p}{(}\\PY{p}{)}\\PY{o}{.}\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\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}{g1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{SubSellar}\\PY{p}{(}\\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{n}{scaling}\\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}{g2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{SubSellar}\\PY{p}{(}\\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{n}{scaling}\\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}{g1.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{g2.x}\\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}{g2.y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{g1.x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} Converge the outer loop with Gauss Seidel, with a looser tolerance.}\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}{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 DoubleSellar(om.Group):\n\n    def __init__(self, units=None, scaling=None, **kwargs):\n        super().__init__(**kwargs)\n\n        self.add_subsystem('g1', SubSellar(units=units, scaling=scaling))\n        self.add_subsystem('g2', SubSellar(units=units, scaling=scaling))\n\n        self.connect('g1.y2', 'g2.x')\n        self.connect('g2.y2', 'g1.x')\n\n        # Converge the outer loop with Gauss Seidel, with a looser tolerance.\n        self.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n        self.linear_solver = om.DirectSolver()"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src31"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src31\", get_code(\"openmdao.test_suite.components.double_sellar.DoubleSellar\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a442b85",
   "metadata": {
    "papermill": {
     "duration": 0.002173,
     "end_time": "2026-10-02T14:42:46.648364+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.646191+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `DoubleSellar` class definition \n",
    "\n",
    "{glue:}`code_src31`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "fb03346f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.653582Z",
     "iopub.status.busy": "2026-10-02T14:42:46.653447Z",
     "iopub.status.idle": "2026-10-02T14:42:46.669652Z",
     "shell.execute_reply": "2026-10-02T14:42:46.668987Z"
    },
    "papermill": {
     "duration": 0.019532,
     "end_time": "2026-10-02T14:42:46.670106+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.650574+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+  \n",
      "+  ==\n",
      "+  g1\n",
      "+  ==\n",
      "+  NL: Newton Converged in 2 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g2\n",
      "+  ==\n",
      "+  NL: Newton Converged in 2 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g1\n",
      "+  ==\n",
      "+  NL: Newton Converged in 2 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g2\n",
      "+  ==\n",
      "+  NL: Newton Converged in 2 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g1\n",
      "+  ==\n",
      "+  NL: Newton Converged in 1 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g2\n",
      "+  ==\n",
      "+  NL: Newton Converged in 1 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g1\n",
      "+  ==\n",
      "+  NL: Newton Converged in 0 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g2\n",
      "+  ==\n",
      "+  NL: Newton Converged in 0 iterations\n",
      "NL: Newton Converged in 3 iterations\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.double_sellar import DoubleSellar\n",
    "\n",
    "prob = om.Problem(model=DoubleSellar())\n",
    "model = prob.model\n",
    "\n",
    "g1 = model.g1\n",
    "g1.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "g1.nonlinear_solver.options['rtol'] = 1.0e-5\n",
    "g1.linear_solver = om.DirectSolver()\n",
    "\n",
    "g2 = model.g2\n",
    "g2.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "g2.nonlinear_solver.options['rtol'] = 1.0e-5\n",
    "g2.linear_solver = om.DirectSolver()\n",
    "\n",
    "model.nonlinear_solver = om.NewtonSolver()\n",
    "model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "model.nonlinear_solver.options['solve_subsystems'] = True\n",
    "\n",
    "prob.setup()\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "5978e66a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.675598Z",
     "iopub.status.busy": "2026-10-02T14:42:46.675416Z",
     "iopub.status.idle": "2026-10-02T14:42:46.679475Z",
     "shell.execute_reply": "2026-10-02T14:42:46.678908Z"
    },
    "papermill": {
     "duration": 0.007625,
     "end_time": "2026-10-02T14:42:46.680053+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.672428+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.64]\n",
      "[0.8]\n",
      "[0.64]\n",
      "[0.8]\n"
     ]
    }
   ],
   "source": [
    "print(prob.get_val('g1.y1'))\n",
    "print(prob.get_val('g1.y2'))\n",
    "print(prob.get_val('g2.y1'))\n",
    "print(prob.get_val('g2.y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "95b4a177",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.685758Z",
     "iopub.status.busy": "2026-10-02T14:42:46.685553Z",
     "iopub.status.idle": "2026-10-02T14:42:46.689242Z",
     "shell.execute_reply": "2026-10-02T14:42:46.688710Z"
    },
    "papermill": {
     "duration": 0.007195,
     "end_time": "2026-10-02T14:42:46.689728+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.682533+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.701153107269704e-11)"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('g1.y1'), 0.64, .00001)\n",
    "assert_near_equal(prob.get_val('g1.y2'), 0.80, .00001)\n",
    "assert_near_equal(prob.get_val('g2.y1'), 0.64, .00001)\n",
    "assert_near_equal(prob.get_val('g2.y2'), 0.80, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6222571",
   "metadata": {
    "papermill": {
     "duration": 0.002269,
     "end_time": "2026-10-02T14:42:46.694307+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.692038+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**max_sub_solves**\n",
    "\n",
    "  This option is used in conjunction with the \"solve_subsystems\" option. It controls the number of iterations for which NewtonSolver will allow subsystems to solve themselves. When the iteration count exceeds `max_sub_solves`,  Newton returns to its default behavior.\n",
    "\n",
    "  For example, if you set `max_sub_solves` to zero, then the solvers on subsystems are executed during the initial\n",
    "  evaluation, but not during any subsequent iteration."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "64905d65",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.699647Z",
     "iopub.status.busy": "2026-10-02T14:42:46.699508Z",
     "iopub.status.idle": "2026-10-02T14:42:46.705225Z",
     "shell.execute_reply": "2026-10-02T14:42:46.704572Z"
    },
    "papermill": {
     "duration": 0.009272,
     "end_time": "2026-10-02T14:42:46.705854+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.696582+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\">SubSellar</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=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</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;d1&#39;</span><span class=\"p\">,</span> <span class=\"n\">SellarDis1withDerivatives</span><span class=\"p\">(</span><span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"n\">scaling</span><span class=\"p\">),</span>\n                           <span class=\"n\">promotes</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">])</span>\n        <span class=\"bp\">self</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\">units</span><span class=\"o\">=</span><span class=\"n\">units</span><span class=\"p\">,</span> <span class=\"n\">scaling</span><span class=\"o\">=</span><span class=\"n\">scaling</span><span class=\"p\">),</span>\n                           <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> <span class=\"s1\">&#39;y2&#39;</span><span class=\"p\">])</span>\n        <span class=\"k\">if</span> <span class=\"n\">units</span><span class=\"p\">:</span>\n             <span class=\"c1\"># auto_ivc update requires this since two &#39;z&#39; inputs have different units</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\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;ft&#39;</span><span class=\"p\">)</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{SubSellar}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{Group}\\PY{p}{)}\\PY{p}{:}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb}{super}\\PY{p}{(}\\PY{p}{)}\\PY{o}{.}\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\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}{d1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{SellarDis1withDerivatives}\\PY{p}{(}\\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{n}{scaling}\\PY{p}{)}\\PY{p}{,}\n                           \\PY{n}{promotes}\\PY{o}{=}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y1}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{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}{d2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{SellarDis2withDerivatives}\\PY{p}{(}\\PY{n}{units}\\PY{o}{=}\\PY{n}{units}\\PY{p}{,} \\PY{n}{scaling}\\PY{o}{=}\\PY{n}{scaling}\\PY{p}{)}\\PY{p}{,}\n                           \\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{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y2}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\n        \\PY{k}{if} \\PY{n}{units}\\PY{p}{:}\n             \\PY{c+c1}{\\PYZsh{} auto\\PYZus{}ivc update requires this since two \\PYZsq{}z\\PYZsq{} inputs have different units}\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}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{ft}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class SubSellar(om.Group):\n\n    def __init__(self, units=None, scaling=None, **kwargs):\n        super().__init__(**kwargs)\n\n        self.add_subsystem('d1', SellarDis1withDerivatives(units=units, scaling=scaling),\n                           promotes=['x', 'z', 'y1', 'y2'])\n        self.add_subsystem('d2', SellarDis2withDerivatives(units=units, scaling=scaling),\n                           promotes=['z', 'y1', 'y2'])\n        if units:\n             # auto_ivc update requires this since two 'z' inputs have different units\n            self.set_input_defaults('z', units='ft')"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src32"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src32\", get_code(\"openmdao.test_suite.components.double_sellar.SubSellar\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf58920d",
   "metadata": {
    "papermill": {
     "duration": 0.003497,
     "end_time": "2026-10-02T14:42:46.712857+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.709360+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SubSellar` class definition \n",
    "\n",
    "{glue:}`code_src32`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "96d54184",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.720071Z",
     "iopub.status.busy": "2026-10-02T14:42:46.719931Z",
     "iopub.status.idle": "2026-10-02T14:42:46.733362Z",
     "shell.execute_reply": "2026-10-02T14:42:46.732877Z"
    },
    "papermill": {
     "duration": 0.017767,
     "end_time": "2026-10-02T14:42:46.734040+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.716273+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "+  \n",
      "+  ==\n",
      "+  g1\n",
      "+  ==\n",
      "+  NL: Newton Converged in 2 iterations\n",
      "+  \n",
      "+  ==\n",
      "+  g2\n",
      "+  ==\n",
      "+  NL: Newton Converged in 2 iterations\n",
      "NL: Newton Converged in 3 iterations\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.double_sellar import SubSellar\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('g1', SubSellar())\n",
    "model.add_subsystem('g2', SubSellar())\n",
    "\n",
    "model.connect('g1.y2', 'g2.x')\n",
    "model.connect('g2.y2', 'g1.x')\n",
    "\n",
    "# Converge the outer loop with Gauss Seidel, with a looser tolerance.\n",
    "model.nonlinear_solver = om.NewtonSolver()\n",
    "model.linear_solver = om.DirectSolver()\n",
    "\n",
    "g1 = model.g1\n",
    "g1.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "g1.nonlinear_solver.options['rtol'] = 1.0e-5\n",
    "g1.linear_solver = om.DirectSolver()\n",
    "\n",
    "g2 = model.g2\n",
    "g2.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "g2.nonlinear_solver.options['rtol'] = 1.0e-5\n",
    "g2.linear_solver = om.DirectSolver()\n",
    "\n",
    "model.nonlinear_solver = om.NewtonSolver()\n",
    "model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "model.nonlinear_solver.options['solve_subsystems'] = True\n",
    "model.nonlinear_solver.options['max_sub_solves'] = 0\n",
    "\n",
    "prob.setup()\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "378a0b25",
   "metadata": {
    "papermill": {
     "duration": 0.002742,
     "end_time": "2026-10-02T14:42:46.739244+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.736502+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**err_on_non_converge**\n",
    "\n",
    "  If you set this to True, then when the solver doesn't converge, either by hitting the iteration limit\n",
    "  without meeting the tolerance criteria, or by encountering a NaN or inf, it\n",
    "  will raise an AnalysisError exception. This is mainly important when coupled with a higher-level solver or\n",
    "  driver (e.g., `pyOptSparseDriver`)that can handle the AnalysisError by adapting the stepsize and retrying. This feature can be set on any iterative nonlinear or linear solver.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "b0c7d01a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.745003Z",
     "iopub.status.busy": "2026-10-02T14:42:46.744865Z",
     "iopub.status.idle": "2026-10-02T14:42:46.753277Z",
     "shell.execute_reply": "2026-10-02T14:42:46.752643Z"
    },
    "papermill": {
     "duration": 0.011918,
     "end_time": "2026-10-02T14:42:46.753733+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.741815+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 1 iterations.\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])\n",
    "model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                        z=np.array([0.0, 0.0]), x=0.0),\n",
    "                    promotes=['obj', 'x', 'z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n",
    "\n",
    "model.linear_solver = om.DirectSolver()\n",
    "\n",
    "newton = model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "newton.options['maxiter'] = 1\n",
    "newton.options['err_on_non_converge'] = True\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 1.)\n",
    "prob.set_val('z', np.array([5.0, 2.0]))\n",
    "\n",
    "try:\n",
    "    prob.run_model()\n",
    "except om.AnalysisError:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e7e02b9",
   "metadata": {
    "papermill": {
     "duration": 0.002674,
     "end_time": "2026-10-02T14:42:46.758834+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.756160+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.\n",
    "\n",
    "  The option `stall_tol_type` is used to specify whether the absolute or relative norm of the residual is\n",
    "  used to detect a stall condition. If an outer solver is used in conjunction with `solve_subsystems`, the\n",
    "  relative change in the residual norm will be small for those residuals converged by the inner solver.\n",
    "  In such cases, setting this option to 'abs' may more reliably detect a stall."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "1e448420",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.764658Z",
     "iopub.status.busy": "2026-10-02T14:42:46.764533Z",
     "iopub.status.idle": "2026-10-02T14:42:46.773362Z",
     "shell.execute_reply": "2026-10-02T14:42:46.772969Z"
    },
    "papermill": {
     "duration": 0.01284,
     "end_time": "2026-10-02T14:42:46.774103+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.761263+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton 0 ; 4 1\n",
      "|  LS: BCHK 0 ; 0.7 0.175\n",
      "NL: Newton 1 ; 0.7 0.175\n",
      "|  LS: BCHK 0 ; 0.7 1\n",
      "NL: Newton 2 ; 0.7 0.175\n",
      "|  LS: BCHK 0 ; 0.7 1\n",
      "NL: Newton 3 ; 0.7 0.175\n",
      "|  LS: BCHK 0 ; 0.7 1\n",
      "NL: Newton 4 ; 0.7 0.175\n",
      "NL: NewtonSolver 'NL: Newton' 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",
    "newton = prob.model.nonlinear_solver = om.NewtonSolver()\n",
    "newton.options['solve_subsystems'] = True\n",
    "newton.options['stall_limit'] = 3\n",
    "newton.options['stall_tol'] = 1e-8\n",
    "newton.options['stall_tol_type'] = 'abs'\n",
    "newton.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()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e8b8911",
   "metadata": {
    "papermill": {
     "duration": 0.003403,
     "end_time": "2026-10-02T14:42:46.780968+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.777565+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Specifying a Linear Solver\n",
    "\n",
    "We can choose a different linear solver for calculating the Newton step by setting the `linear_solver` attribute. The default is to use the linear solver that was specified on the containing system, which by default is LinearBlockGS. In the following example, we modify the model to use [DirectSolver](../../../_srcdocs/packages/solvers.linear/direct) instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "5ad3f446",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.788497Z",
     "iopub.status.busy": "2026-10-02T14:42:46.788367Z",
     "iopub.status.idle": "2026-10-02T14:42:46.797910Z",
     "shell.execute_reply": "2026-10-02T14:42:46.797358Z"
    },
    "papermill": {
     "duration": 0.014089,
     "end_time": "2026-10-02T14:42:46.798480+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.784391+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton Converged in 3 iterations\n",
      "[25.58830237]\n",
      "[12.05848815]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.sellar import SellarDis1withDerivatives, SellarDis2withDerivatives\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('d1', SellarDis1withDerivatives(), promotes=['x', 'z', 'y1', 'y2'])\n",
    "model.add_subsystem('d2', SellarDis2withDerivatives(), promotes=['z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('obj_cmp', om.ExecComp('obj = x**2 + z[1] + y1 + exp(-y2)',\n",
    "                                        z=np.array([0.0, 0.0]), x=0.0),\n",
    "                    promotes=['obj', 'x', 'z', 'y1', 'y2'])\n",
    "\n",
    "model.add_subsystem('con_cmp1', om.ExecComp('con1 = 3.16 - y1'), promotes=['con1', 'y1'])\n",
    "model.add_subsystem('con_cmp2', om.ExecComp('con2 = y2 - 24.0'), promotes=['con2', 'y2'])\n",
    "\n",
    "model.linear_solver = om.LinearBlockGS()\n",
    "\n",
    "newton = model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "\n",
    "newton.linear_solver = om.DirectSolver()\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', 1.)\n",
    "prob.set_val('z', np.array([5.0, 2.0]))\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "895876ee",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.804163Z",
     "iopub.status.busy": "2026-10-02T14:42:46.804031Z",
     "iopub.status.idle": "2026-10-02T14:42:46.807271Z",
     "shell.execute_reply": "2026-10-02T14:42:46.806807Z"
    },
    "papermill": {
     "duration": 0.006953,
     "end_time": "2026-10-02T14:42:46.807949+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.800996+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(3.250496376340271e-09)"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('y1'), 25.58830273, .00001)\n",
    "assert_near_equal(prob.get_val('y2'), 12.05848819, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01b35ec9",
   "metadata": {
    "papermill": {
     "duration": 0.002418,
     "end_time": "2026-10-02T14:42:46.812888+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.810470+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Specifying a Line Search Algorithm\n",
    "\n",
    "NewtonSolver has a `linesearch` attribute, which supports specification of a supplemental algorithm that can find a better point along the Newton search direction. This is typically used for cases where we have declared upper\n",
    "or lower bounds on some of the model outputs and we want to prevent Newton from moving into this non-feasible space during iteration. An algorithm that does this is called a line search.\n",
    "\n",
    "By default, NewtonSolver does not perform a line search. We will show how to specify one. First,\n",
    "let's set up a problem that has implicit bounds on one of its states."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "6b21d7e2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.818684Z",
     "iopub.status.busy": "2026-10-02T14:42:46.818548Z",
     "iopub.status.idle": "2026-10-02T14:42:46.822165Z",
     "shell.execute_reply": "2026-10-02T14:42:46.821293Z"
    },
    "papermill": {
     "duration": 0.007239,
     "end_time": "2026-10-02T14:42:46.822658+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.815419+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from math import atan\n",
    "\n",
    "class CompAtan(om.ImplicitComponent):\n",
    "    \"\"\"\n",
    "    A simple implicit component with the following equation:\n",
    "\n",
    "    F(x, y) = 33.0 * atan(y-20)**2 + x\n",
    "\n",
    "    x is an input, y is the state to be solved.\n",
    "    for x = -100, y should be 19.68734033\n",
    "\n",
    "    This equation poses a challenge because a guess that is far from the solution yields large\n",
    "    gradients and divergence. Additionally, the jacobian becomes singular at y = 20. To address\n",
    "    this, a lower and upper bound are added on y so that a solver with a BoundsEnforceLS does not\n",
    "    allow it to stray into problematic regions.\n",
    "    \"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        self.add_input('x', 1.0)\n",
    "        self.add_output('y', 1.0, lower=1.0, upper=19.9)\n",
    "\n",
    "        self.declare_partials(of='y', wrt='x')\n",
    "        self.declare_partials(of='y', wrt='y')\n",
    "\n",
    "    def apply_nonlinear(self, inputs, outputs, residuals):\n",
    "        x = inputs['x']\n",
    "        y = outputs['y']\n",
    "\n",
    "        residuals['y'] = (33.0 * atan(y-20.0))**2 + x\n",
    "\n",
    "    def linearize(self, inputs, outputs, jacobian):\n",
    "        # x = inputs['x']  # x is not needed\n",
    "        y = outputs['y']\n",
    "\n",
    "        jacobian['y', 'y'] = 2178.0*atan(y-20.0) / (y**2 - 40.0*y + 401.0)\n",
    "        jacobian['y', 'x'] = 1.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec7bb627",
   "metadata": {
    "papermill": {
     "duration": 0.00244,
     "end_time": "2026-10-02T14:42:46.827618+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.825178+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "This equation poses a challenge because a guess that is far from the solution yields large\n",
    "gradients and the solution will diverge. Additionally, the jacobian becomes singular at y = 20. To address\n",
    "both of these problems, a lower and upper bound are added on y so that a solver with a BoundsEnforceLS does not\n",
    "allow it to stray into problematic regions. Without the linsearch, Newton is unable to solve this problem unless you start very close to the solution.\n",
    "\n",
    "Here, we specify [BoundsEnforceLS](../../../_srcdocs/packages/solvers.linesearch/backtracking)\n",
    "as our line search algorithm, and we get the expected solution for \"y\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "9218dc7d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.833423Z",
     "iopub.status.busy": "2026-10-02T14:42:46.833253Z",
     "iopub.status.idle": "2026-10-02T14:42:46.843904Z",
     "shell.execute_reply": "2026-10-02T14:42:46.843187Z"
    },
    "papermill": {
     "duration": 0.014226,
     "end_time": "2026-10-02T14:42:46.844355+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.830129+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton 0 ; 2178.39766 1\n",
      "|  LS: BCHK 0 ; 89.1820479 0.0409392874\n",
      "NL: Newton 1 ; 89.1820479 0.0409392874\n",
      "|  LS: BCHK 0 ; 146.249915 1.63990308\n",
      "NL: Newton 2 ; 146.249915 0.0671364633\n",
      "|  LS: BCHK 0 ; 14.6043983 0.0998591916\n",
      "NL: Newton 3 ; 14.6043983 0.00670419295\n",
      "|  LS: BCHK 0 ; 0.371568958 0.0254422641\n",
      "NL: Newton 4 ; 0.371568958 0.000170569848\n",
      "|  LS: BCHK 0 ; 0.000278617482 0.000749840578\n",
      "NL: Newton 5 ; 0.000278617482 1.27900193e-07\n",
      "|  LS: BCHK 0 ; 1.58237867e-10 5.67939478e-07\n",
      "NL: Newton 6 ; 1.58237867e-10 7.2639569e-14\n",
      "NL: Newton Converged\n",
      "[19.68734036]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.solvers.linesearch.tests.test_backtracking import CompAtan\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "model.add_subsystem('comp', CompAtan(), promotes_inputs=['x'])\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('x', -100.0)\n",
    "\n",
    "# Initial value for the state:\n",
    "prob.set_val('comp.y', 12.0)\n",
    "\n",
    "# You can change the om.NewtonSolver settings after setup is called\n",
    "newton = prob.model.nonlinear_solver = om.NewtonSolver()\n",
    "prob.model.linear_solver = om.DirectSolver()\n",
    "newton.options['iprint'] = 2\n",
    "newton.options['rtol'] = 1e-8\n",
    "newton.options['solve_subsystems'] = True\n",
    "\n",
    "newton.linesearch = om.BoundsEnforceLS()\n",
    "newton.linesearch.options['iprint'] = 2\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('comp.y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "7bd8a71f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:46.850208Z",
     "iopub.status.busy": "2026-10-02T14:42:46.850069Z",
     "iopub.status.idle": "2026-10-02T14:42:46.853432Z",
     "shell.execute_reply": "2026-10-02T14:42:46.852816Z"
    },
    "papermill": {
     "duration": 0.007004,
     "end_time": "2026-10-02T14:42:46.853892+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:46.846888+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.2944685023530126e-09)"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('comp.y'), 19.68734033, 1e-6)"
   ]
  }
 ],
 "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.362386,
   "end_time": "2026-10-02T14:42:47.573246+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/solvers/newton.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/solvers/newton.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:42:42.210860+00:00",
   "version": "2.7.0"
  },
  "vscode": {
   "interpreter": {
    "hash": "9c92b2045504bea896bda7910cf76807d15460aca4268ad16ab9067dbd37dd98"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}