{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b4385091",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:53.875300Z",
     "iopub.status.busy": "2026-10-02T14:42:53.875096Z",
     "iopub.status.idle": "2026-10-02T14:42:53.879415Z",
     "shell.execute_reply": "2026-10-02T14:42:53.878562Z"
    },
    "papermill": {
     "duration": 0.008543,
     "end_time": "2026-10-02T14:42:53.880358+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:53.871815+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": "8f2a6b71",
   "metadata": {
    "papermill": {
     "duration": 0.002045,
     "end_time": "2026-10-02T14:42:53.897875+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:53.895830+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# PETScKrylov\n",
    "\n",
    "PETScKrylov is an iterative linear solver that wraps the linear solution methods found in PETSc via petsc4py.\n",
    "The default method is \"fgmres\", or the Flexible Generalized Minimal RESidual method, though you may choose any of\n",
    "the other methods in PETSc. This linear solver is capable of handling any system topology\n",
    "effectively. It also solves all subsystems below it in the hierarchy, so assigning different solvers to\n",
    "subsystems will have no effect on the solution at this level.\n",
    "\n",
    "This solver works under MPI, so it is a good alternative to\n",
    "[ScipyKrylov](../../../_srcdocs/packages/solvers.linear/scipy_iter_solver).\n",
    "This solver is also re-entrant, so there are no problems if it is nested during preconditioning.\n",
    "\n",
    "Here, we calculate the total derivatives across the Sellar system."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9c6d6c4e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:53.903168Z",
     "iopub.status.busy": "2026-10-02T14:42:53.903045Z",
     "iopub.status.idle": "2026-10-02T14:42:55.979915Z",
     "shell.execute_reply": "2026-10-02T14:42:55.977137Z"
    },
    "papermill": {
     "duration": 2.080083,
     "end_time": "2026-10-02T14:42:55.980404+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:53.900321+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_src39"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src39\", get_code(\"openmdao.test_suite.components.sellar.SellarDis1withDerivatives\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c0b48b0",
   "metadata": {
    "papermill": {
     "duration": 0.001604,
     "end_time": "2026-10-02T14:42:55.983827+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:55.982223+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarDis1withDerivatives` class definition \n",
    "\n",
    "{glue:}`code_src39`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "98d9c3a0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:55.987397Z",
     "iopub.status.busy": "2026-10-02T14:42:55.987258Z",
     "iopub.status.idle": "2026-10-02T14:42:55.992754Z",
     "shell.execute_reply": "2026-10-02T14:42:55.992185Z"
    },
    "papermill": {
     "duration": 0.007925,
     "end_time": "2026-10-02T14:42:55.993236+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:55.985311+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_src40"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src40\", get_code(\"openmdao.test_suite.components.sellar.SellarDis2withDerivatives\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "260e7bb0",
   "metadata": {
    "papermill": {
     "duration": 0.001522,
     "end_time": "2026-10-02T14:42:55.996398+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:55.994876+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `SellarDis2withDerivatives` class definition \n",
    "\n",
    "{glue:}`code_src40`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "0bffb629",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:56.000178Z",
     "iopub.status.busy": "2026-10-02T14:42:56.000039Z",
     "iopub.status.idle": "2026-10-02T14:42:57.263771Z",
     "shell.execute_reply": "2026-10-02T14:42:57.263305Z"
    },
    "papermill": {
     "duration": 1.266332,
     "end_time": "2026-10-02T14:42:57.264266+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:55.997934+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952177.226930] [runnervm8df0l:7390 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x561f9f8d5080 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",
      "[1790952177.227193] [runnervm8df0l:7390 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "NL: NLBGS Converged in 8 iterations\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:07390] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np \n",
    "import openmdao.api as om\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.nonlinear_solver = om.NonlinearBlockGS()\n",
    "\n",
    "model.linear_solver = om.PETScKrylov()\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",
    "wrt = ['z']\n",
    "of = ['obj']\n",
    "\n",
    "J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0116488a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.317873Z",
     "iopub.status.busy": "2026-10-02T14:42:57.317424Z",
     "iopub.status.idle": "2026-10-02T14:42:57.320672Z",
     "shell.execute_reply": "2026-10-02T14:42:57.320071Z"
    },
    "papermill": {
     "duration": 0.054294,
     "end_time": "2026-10-02T14:42:57.321385+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.267091+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.610010556989945 9.61001056 1e-05\n",
      "1.7844853356313641 1.78448534 1e-05\n"
     ]
    }
   ],
   "source": [
    "print(J['obj', 'z'][0][0], 9.61001056, .00001)\n",
    "print(J['obj', 'z'][0][1], 1.78448534, .00001)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cadbc1c8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.325550Z",
     "iopub.status.busy": "2026-10-02T14:42:57.325411Z",
     "iopub.status.idle": "2026-10-02T14:42:57.329152Z",
     "shell.execute_reply": "2026-10-02T14:42:57.328516Z"
    },
    "papermill": {
     "duration": 0.006487,
     "end_time": "2026-10-02T14:42:57.329655+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.323168+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.4481209229088745e-09)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(J['obj', 'z'][0][0], 9.61001056, .00001)\n",
    "assert_near_equal(J['obj', 'z'][0][1], 1.78448534, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "937f763a",
   "metadata": {
    "papermill": {
     "duration": 0.001631,
     "end_time": "2026-10-02T14:42:57.333027+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.331396+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## PETScKrylov Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "35160d90",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.337035Z",
     "iopub.status.busy": "2026-10-02T14:42:57.336918Z",
     "iopub.status.idle": "2026-10-02T14:42:57.340327Z",
     "shell.execute_reply": "2026-10-02T14:42:57.339713Z"
    },
    "papermill": {
     "duration": 0.006067,
     "end_time": "2026-10-02T14:42:57.340742+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.334675+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;\">assemble_jac</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;\">Activates use of assembled jacobian by this solver.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">atol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">absolute error tolerance</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">divtol</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;\">[&#x27;float&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Divergence tolerance.</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;\">ksp_type</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">fgmres</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;richardson&#x27;, &#x27;chebyshev&#x27;, &#x27;cg&#x27;, &#x27;groppcg&#x27;, &#x27;pipecg&#x27;, &#x27;pipecgrr&#x27;, &#x27;cgne&#x27;, &#x27;nash&#x27;, &#x27;stcg&#x27;, &#x27;gltr&#x27;, &#x27;fcg&#x27;, &#x27;pipefcg&#x27;, &#x27;gmres&#x27;, &#x27;pipefgmres&#x27;, &#x27;fgmres&#x27;, &#x27;lgmres&#x27;, &#x27;dgmres&#x27;, &#x27;pgmres&#x27;, &#x27;tcqmr&#x27;, &#x27;bcgs&#x27;, &#x27;ibcgs&#x27;, &#x27;fbcgs&#x27;, &#x27;fbcgsr&#x27;, &#x27;bcgsl&#x27;, &#x27;cgs&#x27;, &#x27;tfqmr&#x27;, &#x27;cr&#x27;, &#x27;pipecr&#x27;, &#x27;lsqr&#x27;, &#x27;preonly&#x27;, &#x27;qcg&#x27;, &#x27;bicg&#x27;, &#x27;minres&#x27;, &#x27;symmlq&#x27;, &#x27;lcd&#x27;, &#x27;python&#x27;, &#x27;gcr&#x27;, &#x27;pipegcr&#x27;, &#x27;tsirm&#x27;, &#x27;cgls&#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;\">KSP algorithm to use. Default is &#x27;fgmres&#x27;.</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;\">100</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;\">precon_side</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">right</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;left&#x27;, &#x27;right&#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;\">Preconditioner side, default is right.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">restart</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1000</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;\">Number of iterations between restarts. Larger values increase iteration cost, but may be necessary for convergence</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rhs_checking</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;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;, &#x27;dict&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, check RHS vs. cache and/or zero to avoid some solves.Can also be set to a dict of options for the LinearRHSChecker to allow finer control over it. Allowed options are: (&#x27;check_zero&#x27;, &#x27;rtol&#x27;, &#x27;atol&#x27;, &#x27;max_cache_entries&#x27;, &#x27;collect_stats&#x27;, &#x27;auto&#x27;, &#x27;verbose&#x27;)</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rtol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">relative error tolerance</td></tr>\n",
       "    </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.linear.petsc_ksp.PETScKrylov\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ffe3db5",
   "metadata": {
    "papermill": {
     "duration": 0.00168,
     "end_time": "2026-10-02T14:42:57.344196+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.342516+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## PETScKrylov Constructor\n",
    "\n",
    "The call signature for the `PETScKrylov` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.solvers.linear.petsc_ksp.PETScKrylov.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## PETScKrylov Option Examples\n",
    "\n",
    "**maxiter**\n",
    "\n",
    "  `maxiter` lets you specify the maximum number of GMRES (or other algorithm) iterations to apply. The default maximum is 100, which\n",
    "  is much higher than the other linear solvers because each multiplication by the system Jacobian is considered\n",
    "  to be an iteration. You may have to decrease this value if you have a coupled system that is converging\n",
    "  very slowly. (Of course, in such a case, it may be better to add a preconditioner.)  Alternatively, you\n",
    "  may have to raise `maxiter` if you have an extremely large number of components in your system (a 1000-component\n",
    "  ring would need 1000 iterations just to make it around once.)\n",
    "\n",
    "  This example shows what happens if you set `maxiter` too low (the derivatives should be nonzero, but it stops too\n",
    "  soon.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "efce4b3b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.348155Z",
     "iopub.status.busy": "2026-10-02T14:42:57.348049Z",
     "iopub.status.idle": "2026-10-02T14:42:57.361136Z",
     "shell.execute_reply": "2026-10-02T14:42:57.360512Z"
    },
    "papermill": {
     "duration": 0.015946,
     "end_time": "2026-10-02T14:42:57.361872+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.345926+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NLBGS Converged in 8 iterations\n",
      "LN: PETScKrylovSolver 'LN: PETScKrylov' on system '' failed to converge in 4 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.nonlinear_solver = om.NonlinearBlockGS()\n",
    "\n",
    "model.linear_solver = om.PETScKrylov()\n",
    "model.linear_solver.options['maxiter'] = 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",
    "wrt = ['z']\n",
    "of = ['obj']\n",
    "\n",
    "J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a55dc17c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.496122Z",
     "iopub.status.busy": "2026-10-02T14:42:57.495909Z",
     "iopub.status.idle": "2026-10-02T14:42:57.499190Z",
     "shell.execute_reply": "2026-10-02T14:42:57.498468Z"
    },
    "papermill": {
     "duration": 0.136271,
     "end_time": "2026-10-02T14:42:57.499941+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.363670+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.26540544430977\n",
      "1.8724662355885662\n"
     ]
    }
   ],
   "source": [
    "print(J['obj', 'z'][0][0])\n",
    "print(J['obj', 'z'][0][1])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ae8184a",
   "metadata": {
    "papermill": {
     "duration": 0.118062,
     "end_time": "2026-10-02T14:42:57.620474+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.502412+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**atol**\n",
    "\n",
    "  The absolute convergence tolerance, the absolute size of the (possibly preconditioned) residual norm.\n",
    "\n",
    "  You may need to adjust this setting if you have abnormally large or small values in your global Jacobian."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "7f79ada5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.625680Z",
     "iopub.status.busy": "2026-10-02T14:42:57.625491Z",
     "iopub.status.idle": "2026-10-02T14:42:57.638773Z",
     "shell.execute_reply": "2026-10-02T14:42:57.638151Z"
    },
    "papermill": {
     "duration": 0.016668,
     "end_time": "2026-10-02T14:42:57.639244+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.622576+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NLBGS Converged in 8 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.nonlinear_solver = om.NonlinearBlockGS()\n",
    "\n",
    "model.linear_solver = om.PETScKrylov()\n",
    "model.linear_solver.options['atol'] = 1.0e-20\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",
    "wrt = ['z']\n",
    "of = ['obj']\n",
    "\n",
    "J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b0729b7c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.655552Z",
     "iopub.status.busy": "2026-10-02T14:42:57.655401Z",
     "iopub.status.idle": "2026-10-02T14:42:57.657875Z",
     "shell.execute_reply": "2026-10-02T14:42:57.657339Z"
    },
    "papermill": {
     "duration": 0.005975,
     "end_time": "2026-10-02T14:42:57.658494+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.652519+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.610010556989945\n",
      "1.7844853356313641\n"
     ]
    }
   ],
   "source": [
    "print(J['obj', 'z'][0][0])\n",
    "print(J['obj', 'z'][0][1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "3797c013",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.662938Z",
     "iopub.status.busy": "2026-10-02T14:42:57.662806Z",
     "iopub.status.idle": "2026-10-02T14:42:57.665891Z",
     "shell.execute_reply": "2026-10-02T14:42:57.665337Z"
    },
    "papermill": {
     "duration": 0.005978,
     "end_time": "2026-10-02T14:42:57.666356+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.660378+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(7.645016887615702e-13)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(J['obj', 'z'][0][0], 9.61001055699, .00001)\n",
    "assert_near_equal(J['obj', 'z'][0][1], 1.78448533563, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de9e2a0c",
   "metadata": {
    "papermill": {
     "duration": 0.001975,
     "end_time": "2026-10-02T14:42:57.670297+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.668322+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**rtol**\n",
    "\n",
    "  The relative convergence tolerance, the relative decrease in the (possibly preconditioned) residual norm."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "016e2f2b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.674767Z",
     "iopub.status.busy": "2026-10-02T14:42:57.674613Z",
     "iopub.status.idle": "2026-10-02T14:42:57.686849Z",
     "shell.execute_reply": "2026-10-02T14:42:57.686404Z"
    },
    "papermill": {
     "duration": 0.015264,
     "end_time": "2026-10-02T14:42:57.687469+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.672205+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NLBGS Converged in 8 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",
    "\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.nonlinear_solver = om.NonlinearBlockGS()\n",
    "\n",
    "model.linear_solver = om.PETScKrylov()\n",
    "model.linear_solver.options['rtol'] = 1.0e-20\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",
    "wrt = ['z']\n",
    "of = ['obj']\n",
    "\n",
    "J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "50f334c6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.692023Z",
     "iopub.status.busy": "2026-10-02T14:42:57.691893Z",
     "iopub.status.idle": "2026-10-02T14:42:57.694313Z",
     "shell.execute_reply": "2026-10-02T14:42:57.693772Z"
    },
    "papermill": {
     "duration": 0.00537,
     "end_time": "2026-10-02T14:42:57.694812+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.689442+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.610010556989945\n",
      "1.7844853356313641\n"
     ]
    }
   ],
   "source": [
    "print(J['obj', 'z'][0][0])\n",
    "print(J['obj', 'z'][0][1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "122eb7e8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.699651Z",
     "iopub.status.busy": "2026-10-02T14:42:57.699531Z",
     "iopub.status.idle": "2026-10-02T14:42:57.702358Z",
     "shell.execute_reply": "2026-10-02T14:42:57.701983Z"
    },
    "papermill": {
     "duration": 0.006084,
     "end_time": "2026-10-02T14:42:57.703103+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.697019+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(7.645016887615702e-13)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(J['obj', 'z'][0][0], 9.61001055699, .00001)\n",
    "assert_near_equal(J['obj', 'z'][0][1], 1.78448533563, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a550f0a5",
   "metadata": {
    "papermill": {
     "duration": 0.001897,
     "end_time": "2026-10-02T14:42:57.706957+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.705060+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**ksp_type**\n",
    "\n",
    "  You can specify which PETSc algorithm to use in place of 'fgmres' by settng the \"ksp_type\" in the options\n",
    "  dictionary.  Here, we use 'gmres' instead."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "64877295",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.711432Z",
     "iopub.status.busy": "2026-10-02T14:42:57.711305Z",
     "iopub.status.idle": "2026-10-02T14:42:57.725956Z",
     "shell.execute_reply": "2026-10-02T14:42:57.725446Z"
    },
    "papermill": {
     "duration": 0.017733,
     "end_time": "2026-10-02T14:42:57.726566+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.708833+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NLBGS Converged in 8 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.nonlinear_solver = om.NonlinearBlockGS()\n",
    "\n",
    "model.linear_solver = om.PETScKrylov()\n",
    "model.linear_solver.options['ksp_type'] = 'gmres'\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",
    "wrt = ['z']\n",
    "of = ['obj']\n",
    "\n",
    "J = prob.compute_totals(of=of, wrt=wrt, return_format='flat_dict')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "2c5b284e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.731189Z",
     "iopub.status.busy": "2026-10-02T14:42:57.731065Z",
     "iopub.status.idle": "2026-10-02T14:42:57.733516Z",
     "shell.execute_reply": "2026-10-02T14:42:57.732982Z"
    },
    "papermill": {
     "duration": 0.005374,
     "end_time": "2026-10-02T14:42:57.733896+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.728522+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9.610010556989945\n",
      "1.7844853356313641\n"
     ]
    }
   ],
   "source": [
    "print(J['obj', 'z'][0][0])\n",
    "print(J['obj', 'z'][0][1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "cf862a88",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.745075Z",
     "iopub.status.busy": "2026-10-02T14:42:57.744956Z",
     "iopub.status.idle": "2026-10-02T14:42:57.748031Z",
     "shell.execute_reply": "2026-10-02T14:42:57.747330Z"
    },
    "papermill": {
     "duration": 0.012563,
     "end_time": "2026-10-02T14:42:57.748463+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.735900+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(2.4481209229088745e-09)"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(J['obj', 'z'][0][0], 9.61001056, .00001)\n",
    "assert_near_equal(J['obj', 'z'][0][1], 1.78448534, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e2ece39",
   "metadata": {
    "papermill": {
     "duration": 0.012563,
     "end_time": "2026-10-02T14:42:57.763060+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.750497+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "(petsckrylov-precon)=\n",
    "## Specifying a Preconditioner\n",
    "\n",
    "You can specify a preconditioner to improve the convergence of the iterative linear solution by setting the `precon` attribute. The motivation for using a preconditioner is the observation that iterative methods have better convergence properties if the linear system has a smaller condition number, so the goal of the preconditioner is to\n",
    "improve the condition number in part or all of the Jacobian.\n",
    "\n",
    "Here, we add a Gauss-Seidel preconditioner to the simple Sellar solution with Newton. Note that the number of GMRES iterations is lower when using the preconditioner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "3e692138",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.767821Z",
     "iopub.status.busy": "2026-10-02T14:42:57.767670Z",
     "iopub.status.idle": "2026-10-02T14:42:57.910844Z",
     "shell.execute_reply": "2026-10-02T14:42:57.910125Z"
    },
    "papermill": {
     "duration": 0.146145,
     "end_time": "2026-10-02T14:42:57.911327+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.765182+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "|  | precon:LN: LNBGSSolver 'LN: LNBGS' on system '' failed to converge in 2 iterations.\n",
      "|  | precon:LN: LNBGSSolver 'LN: LNBGS' on system '' failed to converge in 2 iterations.\n",
      "|  | precon:LN: LNBGSSolver 'LN: LNBGS' on system '' failed to converge in 2 iterations.\n",
      "|  | precon:LN: LNBGSSolver 'LN: LNBGS' on system '' failed to converge in 2 iterations.\n",
      "|  | precon:LN: LNBGSSolver 'LN: LNBGS' on system '' failed to converge in 2 iterations.\n",
      "|  | precon:LN: LNBGSSolver 'LN: LNBGS' on system '' failed to converge in 2 iterations.\n",
      "NL: Newton Converged in 3 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.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "model.linear_solver = om.PETScKrylov()\n",
    "\n",
    "model.linear_solver.precon = om.LinearBlockGS()\n",
    "model.linear_solver.precon.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()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "40107643",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:57.916511Z",
     "iopub.status.busy": "2026-10-02T14:42:57.916356Z",
     "iopub.status.idle": "2026-10-02T14:42:57.919103Z",
     "shell.execute_reply": "2026-10-02T14:42:57.918552Z"
    },
    "papermill": {
     "duration": 0.005953,
     "end_time": "2026-10-02T14:42:57.919591+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:57.913638+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[25.58830237]\n",
      "[12.05848815]\n"
     ]
    }
   ],
   "source": [
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "dc178767",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:58.045256Z",
     "iopub.status.busy": "2026-10-02T14:42:58.045103Z",
     "iopub.status.idle": "2026-10-02T14:42:58.048792Z",
     "shell.execute_reply": "2026-10-02T14:42:58.048123Z"
    },
    "papermill": {
     "duration": 0.007445,
     "end_time": "2026-10-02T14:42:58.049526+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:58.042081+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(3.250496081716797e-09)"
      ]
     },
     "execution_count": 21,
     "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": "d700c6d2",
   "metadata": {
    "papermill": {
     "duration": 0.002042,
     "end_time": "2026-10-02T14:42:58.053805+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:58.051763+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "While the default preconditioning \"side\" is right-preconditioning, you can also use left-preconditioning provided that you choose a \"ksp_type\" that supports it. Here we solve the same problem with left-preconditioning using the Richardson method and a `DirectSolver`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "20297446",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:58.059010Z",
     "iopub.status.busy": "2026-10-02T14:42:58.058875Z",
     "iopub.status.idle": "2026-10-02T14:42:58.069842Z",
     "shell.execute_reply": "2026-10-02T14:42:58.069335Z"
    },
    "papermill": {
     "duration": 0.014275,
     "end_time": "2026-10-02T14:42:58.070453+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:58.056178+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton Converged in 3 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.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "model.linear_solver = om.PETScKrylov()\n",
    "\n",
    "model.linear_solver.precon = om.DirectSolver()\n",
    "model.linear_solver.options['precon_side'] = 'left'\n",
    "model.linear_solver.options['ksp_type'] = 'richardson'\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()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "ffdb11e3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:58.081999Z",
     "iopub.status.busy": "2026-10-02T14:42:58.081867Z",
     "iopub.status.idle": "2026-10-02T14:42:58.084903Z",
     "shell.execute_reply": "2026-10-02T14:42:58.084243Z"
    },
    "papermill": {
     "duration": 0.012724,
     "end_time": "2026-10-02T14:42:58.085515+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:58.072791+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[25.58830237]\n",
      "[12.05848815]\n"
     ]
    }
   ],
   "source": [
    "print(prob.get_val('y1'))\n",
    "print(prob.get_val('y2'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "879c0b07",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:58.091868Z",
     "iopub.status.busy": "2026-10-02T14:42:58.091676Z",
     "iopub.status.idle": "2026-10-02T14:42:58.095463Z",
     "shell.execute_reply": "2026-10-02T14:42:58.094632Z"
    },
    "papermill": {
     "duration": 0.007483,
     "end_time": "2026-10-02T14:42:58.095936+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:58.088453+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(3.250496376340271e-09)"
      ]
     },
     "execution_count": 24,
     "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)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 5.491223,
   "end_time": "2026-10-02T14:42:58.714149+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/solvers/petsc_krylov.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/solvers/petsc_krylov.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:42:53.222926+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}