{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "90ee6ab4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:16.488399Z",
     "iopub.status.busy": "2026-10-02T14:45:16.488162Z",
     "iopub.status.idle": "2026-10-02T14:45:16.497351Z",
     "shell.execute_reply": "2026-10-02T14:45:16.496149Z"
    },
    "papermill": {
     "duration": 0.018402,
     "end_time": "2026-10-02T14:45:16.498300+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:16.479898+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": "5dda7775",
   "metadata": {
    "papermill": {
     "duration": 0.078582,
     "end_time": "2026-10-02T14:45:16.580508+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:16.501926+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Basics of Creating N2 Model Visualizations\n",
    "\n",
    "An OpenMDAO model can have a number of connections, and several different residuals being converged.\n",
    "Trying to keep track of all the connections in your head can be a bit challenging, but OpenMDAO offers\n",
    "some visualization tools to help see what's going on. This page explains the basics of generating an N2 diagram\n",
    "either from the command line or from a script.\n",
    "\n",
    "An N2 diagram, also known as an N-squared diagram, is a diagram in the shape of a matrix, representing functional or\n",
    "physical interfaces between system elements. It is used to systematically identify, define, tabulate, design, and\n",
    "analyze functional and physical interfaces. It applies to system interfaces and hardware and/or software interfaces.\n",
    "For more information, see [N2_chart](https://en.wikipedia.org/wiki/N2_chart).\n",
    "\n",
    "For this page, we will be using this code example. Notice that there is an error in this code because one of the\n",
    "connection lines has been commented out. This was done to show how the N2 diagram can help point out unconnected\n",
    "inputs quickly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "450586c2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:16.591002Z",
     "iopub.status.busy": "2026-10-02T14:45:16.588432Z",
     "iopub.status.idle": "2026-10-02T14:45:22.288729Z",
     "shell.execute_reply": "2026-10-02T14:45:22.288233Z"
    },
    "papermill": {
     "duration": 5.706008,
     "end_time": "2026-10-02T14:45:22.289772+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:16.583764+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\">Resistor</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ExplicitComponent</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;Computes current across a resistor using Ohm&#39;s law.&quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">initialize</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;R&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">1.</span><span class=\"p\">,</span> <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Resistance in Ohms&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;V_in&#39;</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;A&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;V_in&#39;</span><span class=\"p\">,</span> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;cs&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">,</span> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;cs&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">compute</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">outputs</span><span class=\"p\">):</span>\n        <span class=\"n\">deltaV</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;V_in&#39;</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">deltaV</span> <span class=\"o\">/</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;R&#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}{Resistor}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{ExplicitComponent}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}Computes current across a resistor using Ohm\\PYZsq{}s law.\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{initialize}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{l+m+mf}{1.}\\PY{p}{,} \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Resistance in Ohms}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{A}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{cs}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{cs}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{compute}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{outputs}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n}{deltaV} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{\\PYZhy{}} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{deltaV} \\PY{o}{/} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{R}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class Resistor(om.ExplicitComponent):\n    \"\"\"Computes current across a resistor using Ohm's law.\"\"\"\n\n    def initialize(self):\n        self.options.declare('R', default=1., desc='Resistance in Ohms')\n\n    def setup(self):\n        self.add_input('V_in', units='V')\n        self.add_input('V_out', units='V')\n        self.add_output('I', units='A')\n\n    def setup_partials(self):\n        self.declare_partials('I', 'V_in', method='cs')\n        self.declare_partials('I', 'V_out', method='cs')\n\n    def compute(self, inputs, outputs):\n        deltaV = inputs['V_in'] - inputs['V_out']\n        outputs['I'] = deltaV / self.options['R']"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src74"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src74\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Resistor\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2b0c60b",
   "metadata": {
    "papermill": {
     "duration": 0.001637,
     "end_time": "2026-10-02T14:45:22.295541+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:22.293904+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Resistor` class definition \n",
    "\n",
    "{glue:}`code_src74`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "136befb4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:22.301879Z",
     "iopub.status.busy": "2026-10-02T14:45:22.301520Z",
     "iopub.status.idle": "2026-10-02T14:45:22.313116Z",
     "shell.execute_reply": "2026-10-02T14:45:22.312235Z"
    },
    "papermill": {
     "duration": 0.015012,
     "end_time": "2026-10-02T14:45:22.313575+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:22.298563+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\">Diode</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ExplicitComponent</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;Computes current across a diode using the Shockley diode equation.&quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">initialize</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;Is&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">1e-15</span><span class=\"p\">,</span> <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Saturation current in Amps&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;Vt&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mf\">.025875</span><span class=\"p\">,</span> <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;Thermal voltage in Volts&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;V_in&#39;</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;A&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;V_in&#39;</span><span class=\"p\">,</span> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;cs&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">,</span> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;cs&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">compute</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">outputs</span><span class=\"p\">):</span>\n        <span class=\"n\">deltaV</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;V_in&#39;</span><span class=\"p\">]</span> <span class=\"o\">-</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;V_out&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">Is</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;Is&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">Vt</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;Vt&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;I&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">Is</span> <span class=\"o\">*</span> <span class=\"p\">(</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">deltaV</span> <span class=\"o\">/</span> <span class=\"n\">Vt</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</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}{Diode}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{ExplicitComponent}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}Computes current across a diode using the Shockley diode equation.\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{initialize}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Is}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{l+m+mf}{1e\\PYZhy{}15}\\PY{p}{,} \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Saturation current in Amps}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Vt}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{l+m+mf}{.025875}\\PY{p}{,} \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Thermal voltage in Volts}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{A}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{cs}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{cs}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{compute}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{outputs}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n}{deltaV} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{\\PYZhy{}} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{Is} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Is}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{Vt} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{Vt}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{Is} \\PY{o}{*} \\PY{p}{(}\\PY{n}{np}\\PY{o}{.}\\PY{n}{exp}\\PY{p}{(}\\PY{n}{deltaV} \\PY{o}{/} \\PY{n}{Vt}\\PY{p}{)} \\PY{o}{\\PYZhy{}} \\PY{l+m+mi}{1}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class Diode(om.ExplicitComponent):\n    \"\"\"Computes current across a diode using the Shockley diode equation.\"\"\"\n\n    def initialize(self):\n        self.options.declare('Is', default=1e-15, desc='Saturation current in Amps')\n        self.options.declare('Vt', default=.025875, desc='Thermal voltage in Volts')\n\n    def setup(self):\n        self.add_input('V_in', units='V')\n        self.add_input('V_out', units='V')\n        self.add_output('I', units='A')\n\n    def setup_partials(self):\n        self.declare_partials('I', 'V_in', method='cs')\n        self.declare_partials('I', 'V_out', method='cs')\n\n    def compute(self, inputs, outputs):\n        deltaV = inputs['V_in'] - inputs['V_out']\n        Is = self.options['Is']\n        Vt = self.options['Vt']\n        outputs['I'] = Is * (np.exp(deltaV / Vt) - 1)"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src75"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src75\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Diode\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7aa11ec",
   "metadata": {
    "papermill": {
     "duration": 0.001807,
     "end_time": "2026-10-02T14:45:22.316982+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:22.315175+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Diode` class definition \n",
    "\n",
    "{glue:}`code_src75`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "11641b42",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:22.324068Z",
     "iopub.status.busy": "2026-10-02T14:45:22.323443Z",
     "iopub.status.idle": "2026-10-02T14:45:22.344416Z",
     "shell.execute_reply": "2026-10-02T14:45:22.344036Z"
    },
    "papermill": {
     "duration": 0.024705,
     "end_time": "2026-10-02T14:45:22.345522+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:22.320817+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\">Node</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ImplicitComponent</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;Computes voltage residual across a node based on incoming and outgoing current.&quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">initialize</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;n_in&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">types</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;number of connections with + assumed in&#39;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"o\">.</span><span class=\"n\">declare</span><span class=\"p\">(</span><span class=\"s1\">&#39;n_out&#39;</span><span class=\"p\">,</span> <span class=\"n\">default</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">types</span><span class=\"o\">=</span><span class=\"nb\">int</span><span class=\"p\">,</span> <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"s1\">&#39;number of current connections + assumed out&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">5.</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;n_in&#39;</span><span class=\"p\">]):</span>\n            <span class=\"n\">i_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;I_in:</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"n\">i_name</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;A&#39;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;n_out&#39;</span><span class=\"p\">]):</span>\n            <span class=\"n\">i_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;I_out:</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">i</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"n\">i_name</span><span class=\"p\">,</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"s1\">&#39;A&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"c1\">#note: we don&#39;t declare any partials wrt `V` here,</span>\n        <span class=\"c1\">#      because the residual doesn&#39;t directly depend on it</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;I*&#39;</span><span class=\"p\">,</span> <span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;cs&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">apply_nonlinear</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">outputs</span><span class=\"p\">,</span> <span class=\"n\">residuals</span><span class=\"p\">):</span>\n        <span class=\"n\">residuals</span><span class=\"p\">[</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.</span>\n        <span class=\"k\">for</span> <span class=\"n\">i_conn</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;n_in&#39;</span><span class=\"p\">]):</span>\n            <span class=\"n\">residuals</span><span class=\"p\">[</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">]</span> <span class=\"o\">+=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;I_in:</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">i_conn</span><span class=\"p\">)]</span>\n        <span class=\"k\">for</span> <span class=\"n\">i_conn</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">options</span><span class=\"p\">[</span><span class=\"s1\">&#39;n_out&#39;</span><span class=\"p\">]):</span>\n            <span class=\"n\">residuals</span><span class=\"p\">[</span><span class=\"s1\">&#39;V&#39;</span><span class=\"p\">]</span> <span class=\"o\">-=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;I_out:</span><span class=\"si\">{}</span><span class=\"s1\">&#39;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">i_conn</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}{Node}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{ImplicitComponent}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}Computes voltage residual across a node based on incoming and outgoing current.\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{initialize}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{l+m+mi}{1}\\PY{p}{,} \\PY{n}{types}\\PY{o}{=}\\PY{n+nb}{int}\\PY{p}{,} \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{number of connections with + assumed in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{o}{.}\\PY{n}{declare}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{default}\\PY{o}{=}\\PY{l+m+mi}{1}\\PY{p}{,} \\PY{n}{types}\\PY{o}{=}\\PY{n+nb}{int}\\PY{p}{,} \\PY{n}{desc}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{number of current connections + assumed out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{5.}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n        \\PY{k}{for} \\PY{n}{i} \\PY{o+ow}{in} \\PY{n+nb}{range}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\\PY{p}{:}\n            \\PY{n}{i\\PYZus{}name} \\PY{o}{=} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I\\PYZus{}in:}\\PY{l+s+si}{\\PYZob{}\\PYZcb{}}\\PY{l+s+s1}{\\PYZsq{}}\\PY{o}{.}\\PY{n}{format}\\PY{p}{(}\\PY{n}{i}\\PY{p}{)}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{n}{i\\PYZus{}name}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{A}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n        \\PY{k}{for} \\PY{n}{i} \\PY{o+ow}{in} \\PY{n+nb}{range}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\\PY{p}{:}\n            \\PY{n}{i\\PYZus{}name} \\PY{o}{=} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I\\PYZus{}out:}\\PY{l+s+si}{\\PYZob{}\\PYZcb{}}\\PY{l+s+s1}{\\PYZsq{}}\\PY{o}{.}\\PY{n}{format}\\PY{p}{(}\\PY{n}{i}\\PY{p}{)}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{n}{i\\PYZus{}name}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{A}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{c+c1}{\\PYZsh{}note: we don\\PYZsq{}t declare any partials wrt `V` here,}\n        \\PY{c+c1}{\\PYZsh{}      because the residual doesn\\PYZsq{}t directly depend on it}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{method}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{cs}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{apply\\PYZus{}nonlinear}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{outputs}\\PY{p}{,} \\PY{n}{residuals}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n}{residuals}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{l+m+mf}{0.}\n        \\PY{k}{for} \\PY{n}{i\\PYZus{}conn} \\PY{o+ow}{in} \\PY{n+nb}{range}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n\\PYZus{}in}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\\PY{p}{:}\n            \\PY{n}{residuals}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{+}\\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I\\PYZus{}in:}\\PY{l+s+si}{\\PYZob{}\\PYZcb{}}\\PY{l+s+s1}{\\PYZsq{}}\\PY{o}{.}\\PY{n}{format}\\PY{p}{(}\\PY{n}{i\\PYZus{}conn}\\PY{p}{)}\\PY{p}{]}\n        \\PY{k}{for} \\PY{n}{i\\PYZus{}conn} \\PY{o+ow}{in} \\PY{n+nb}{range}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{options}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{n\\PYZus{}out}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{)}\\PY{p}{:}\n            \\PY{n}{residuals}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{V}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{\\PYZhy{}}\\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{I\\PYZus{}out:}\\PY{l+s+si}{\\PYZob{}\\PYZcb{}}\\PY{l+s+s1}{\\PYZsq{}}\\PY{o}{.}\\PY{n}{format}\\PY{p}{(}\\PY{n}{i\\PYZus{}conn}\\PY{p}{)}\\PY{p}{]}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class Node(om.ImplicitComponent):\n    \"\"\"Computes voltage residual across a node based on incoming and outgoing current.\"\"\"\n\n    def initialize(self):\n        self.options.declare('n_in', default=1, types=int, desc='number of connections with + assumed in')\n        self.options.declare('n_out', default=1, types=int, desc='number of current connections + assumed out')\n\n    def setup(self):\n        self.add_output('V', val=5., units='V')\n\n        for i in range(self.options['n_in']):\n            i_name = 'I_in:{}'.format(i)\n            self.add_input(i_name, units='A')\n\n        for i in range(self.options['n_out']):\n            i_name = 'I_out:{}'.format(i)\n            self.add_input(i_name, units='A')\n\n    def setup_partials(self):\n        #note: we don't declare any partials wrt `V` here,\n        #      because the residual doesn't directly depend on it\n        self.declare_partials('V', 'I*', method='cs')\n\n    def apply_nonlinear(self, inputs, outputs, residuals):\n        residuals['V'] = 0.\n        for i_conn in range(self.options['n_in']):\n            residuals['V'] += inputs['I_in:{}'.format(i_conn)]\n        for i_conn in range(self.options['n_out']):\n            residuals['V'] -= inputs['I_out:{}'.format(i_conn)]"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src76"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src76\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Node\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8e52ce1",
   "metadata": {
    "papermill": {
     "duration": 0.02468,
     "end_time": "2026-10-02T14:45:22.375079+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:22.350399+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Node` class definition \n",
    "\n",
    "{glue:}`code_src76`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2b6fdd74",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:22.384382Z",
     "iopub.status.busy": "2026-10-02T14:45:22.384209Z",
     "iopub.status.idle": "2026-10-02T14:45:23.912312Z",
     "shell.execute_reply": "2026-10-02T14:45:23.911827Z"
    },
    "papermill": {
     "duration": 1.536008,
     "end_time": "2026-10-02T14:45:23.915407+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:22.379399+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952323.833084] [runnervm8df0l:9769 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55be7cc7c280 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",
      "[1790952323.833351] [runnervm8df0l:9769 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "INFO: checking unconnected_inputs...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING: The following inputs are connected to Auto IVC output variables:\n",
      "  circuit.n2.I_out:0 (circuit.n2.I_out:0)\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:     unconnected_inputs check complete (0.000527 sec).\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=======\n",
      "circuit\n",
      "=======\n",
      "NL: Newton 0 ; 59.9046598 1\n",
      "NL: Newton 1 ; 23734524.6 396204.981\n",
      "NL: Newton 2 ; 1e-15 1.66931922e-17\n",
      "NL: Newton Converged\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:09769] pml_ucx.c:313  Error: Failed to create UCP worker\n",
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/openmdao/utils/relevance.py:1294: OpenMDAOWarning:The following groups have a nonlinear solver that computes gradients and will be treated as atomic for the purposes of determining which systems are included in the optimization iteration: \n",
      "circuit\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.scripts.circuit_analysis import Resistor, Diode, Node\n",
    "\n",
    "\n",
    "class Circuit(om.Group):\n",
    "\n",
    "    def setup(self):\n",
    "        self.add_subsystem('n1', Node(n_in=1, n_out=2), promotes_inputs=[('I_in:0', 'I_in')])\n",
    "        self.add_subsystem('n2', Node())  # leaving defaults\n",
    "\n",
    "        self.add_subsystem('R1', Resistor(R=100.), promotes_inputs=[('V_out', 'Vg')])\n",
    "        self.add_subsystem('R2', Resistor(R=10000.))\n",
    "        self.add_subsystem('D1', Diode(), promotes_inputs=[('V_out', 'Vg')])\n",
    "\n",
    "        self.connect('n1.V', ['R1.V_in', 'R2.V_in'])\n",
    "        self.connect('R1.I', 'n1.I_out:0')\n",
    "        self.connect('R2.I', 'n1.I_out:1')\n",
    "\n",
    "        self.connect('n2.V', ['R2.V_out', 'D1.V_in'])\n",
    "        self.connect('R2.I', 'n2.I_in:0')\n",
    "        # self.connect('D1.I', 'n2.I_out:0') # commented out so there is an unconnected input\n",
    "                                             # example for docs for the N2 diagram\n",
    "\n",
    "        self.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "        self.nonlinear_solver.options['iprint'] = 2\n",
    "        self.nonlinear_solver.options['maxiter'] = 20\n",
    "        self.linear_solver = om.DirectSolver()\n",
    "\n",
    "p = om.Problem()\n",
    "model = p.model\n",
    "\n",
    "model.set_input_defaults('ground.V', 0., units='V')\n",
    "model.set_input_defaults('source.I', 0.1, units='A')\n",
    "model.add_subsystem('circuit', Circuit(),\n",
    "                    promotes_inputs=[('Vg', 'ground.V'), ('I_in', 'source.I')])\n",
    "\n",
    "model.add_design_var('ground.V')\n",
    "model.add_design_var('source.I')\n",
    "model.add_objective('circuit.D1.I')\n",
    "\n",
    "p.setup()\n",
    "p.final_setup()\n",
    "p.check_config(checks=['unconnected_inputs'], out_file=None)\n",
    "\n",
    "# set some initial guesses\n",
    "p['circuit.n1.V'] = 10.\n",
    "p['circuit.n2.V'] = 1.\n",
    "\n",
    "p.run_model()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53788201",
   "metadata": {
    "papermill": {
     "duration": 0.02396,
     "end_time": "2026-10-02T14:45:23.945412+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:23.921452+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## From the Command Line\n",
    "\n",
    "Generating an N2 diagram for a model from the command line is easy. First, you need either a Python\n",
    "script that runs the model or a case recording file that was created when running the model.\n",
    "\n",
    "```{Note}\n",
    "If using a script and `final_setup` isn't called in the script (either directly or as a\n",
    "result of `run_model` or `run_driver`) then nothing will happen. Also, when using\n",
    "the command line version, even if the script does call `run_model` or `run_driver`,\n",
    "the script will terminate after `final_setup` and will not actually run the model.\n",
    "```\n",
    "\n",
    "The `openmdao n2` command will generate an N2 diagram of the model that is\n",
    "viewable in a browser, for example:\n",
    "\n",
    "```\n",
    "openmdao n2 openmdao/test_suite/scripts/circuit_with_unconnected_input.py\n",
    "```\n",
    "\n",
    "will generate an N2 diagram like the one below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "84bef351",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:23.956749Z",
     "iopub.status.busy": "2026-10-02T14:45:23.956447Z",
     "iopub.status.idle": "2026-10-02T14:45:24.104465Z",
     "shell.execute_reply": "2026-10-02T14:45:24.101004Z"
    },
    "papermill": {
     "duration": 0.155959,
     "end_time": "2026-10-02T14:45:24.105820+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:23.949861+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"100%\"\n",
       "            height=\"700\"\n",
       "            src=\"n2.html\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "            \n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.IFrame at 0x7f12479f3a10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "om.n2(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3fb9dc12",
   "metadata": {
    "papermill": {
     "duration": 0.007267,
     "end_time": "2026-10-02T14:45:24.117154+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:24.109887+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The `openmdao n2` has several options:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80718764",
   "metadata": {
    "papermill": {
     "duration": 0.007091,
     "end_time": "2026-10-02T14:45:24.128938+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:24.121847+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "```\n",
    "openmdao n2 -h\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "3d0cedca",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:24.137918Z",
     "iopub.status.busy": "2026-10-02T14:45:24.137689Z",
     "iopub.status.idle": "2026-10-02T14:45:32.851924Z",
     "shell.execute_reply": "2026-10-02T14:45:32.848664Z"
    },
    "papermill": {
     "duration": 8.722367,
     "end_time": "2026-10-02T14:45:32.855215+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:24.132848+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952331.270970] [runnervm8df0l:10014:0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x5622f6710c60 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\r\n",
      "[1790952331.271238] [runnervm8df0l:10014:0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\r\n",
      "[runnervm8df0l:10014] pml_ucx.c:313  Error: Failed to create UCP worker\r\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "usage: openmdao n2 [-h] [-o OUTFILE] [--no_values] [--no_browser] [--embed]\r\n",
      "                   [--title TITLE] [--path PATH] [--problem PROBLEM_NAME]\r\n",
      "                   file\r\n",
      "\r\n",
      "positional arguments:\r\n",
      "  file                  Python script or recording containing the model. If\r\n",
      "                        metadata from a parallel run was recorded in a\r\n",
      "                        separate file, specify both database filenames\r\n",
      "                        delimited with a comma.\r\n",
      "\r\n",
      "options:\r\n",
      "  -h, --help            show this help message and exit\r\n",
      "  -o OUTFILE            html output file.\r\n",
      "  --no_values           don't display variable values.\r\n",
      "  --no_browser          don't display in a browser.\r\n",
      "  --embed               create embeddable version.\r\n",
      "  --title TITLE         diagram title.\r\n",
      "  --path PATH           initial system path to zoom into.\r\n",
      "  --problem PROBLEM_NAME\r\n",
      "                        name of sub-problem, if target is a sub-problem\r\n"
     ]
    }
   ],
   "source": [
    "!openmdao n2 -h"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b2b8c15",
   "metadata": {
    "papermill": {
     "duration": 0.016627,
     "end_time": "2026-10-02T14:45:32.879575+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:32.862948+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## From a Script\n",
    "\n",
    "You can do the same thing programmatically by calling the `n2` function.\n",
    "\n",
    "```{eval-rst}\n",
    "    .. autofunction:: openmdao.visualization.n2_viewer.n2_viewer.n2\n",
    "       :noindex:\n",
    "```\n",
    "\n",
    "Notice that the data source can be either a `Problem` or case recorder database containing\n",
    "the model or model data. The latter is indicated by a string giving the file path to the case\n",
    "recorder file.\n",
    "\n",
    "Here are some code snippets showing the two cases.\n",
    "\n",
    "### Problem as Data Source\n",
    "\n",
    "```python\n",
    "p.setup()\n",
    "\n",
    "om.n2(p)\n",
    "```\n",
    "\n",
    "Case Recorder as Data Source\n",
    "****************************\n",
    "\n",
    "```python\n",
    "r = om.SqliteRecorder('circuit.sqlite')\n",
    "p.driver.add_recorder(r)\n",
    "\n",
    "p.setup()\n",
    "p.final_setup()\n",
    "r.shutdown()\n",
    "\n",
    "om.n2('circuit.sqlite', outfile='circuit.html')\n",
    "```\n",
    "\n",
    "In the latter case, you could view the N2 diagram at a later time using the command:\n",
    "\n",
    "```\n",
    "openmdao n2 circuit.sqlite\n",
    "```\n",
    "\n",
    "For more details on N2 diagrams, see the [N2 Details](../n2_details/n2_details.ipynb) section."
   ]
  }
 ],
 "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": 20.301317,
   "end_time": "2026-10-02T14:45:35.652345+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/model_visualization/n2_basics/n2_basics.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/model_visualization/n2_basics/n2_basics.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:45:15.351028+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}