{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "6ddfb544",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:34.931240Z",
     "iopub.status.busy": "2026-10-02T14:45:34.930963Z",
     "iopub.status.idle": "2026-10-02T14:45:34.946170Z",
     "shell.execute_reply": "2026-10-02T14:45:34.945554Z"
    },
    "papermill": {
     "duration": 0.024249,
     "end_time": "2026-10-02T14:45:34.949381+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:34.925132+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": "3a7b9daf",
   "metadata": {
    "papermill": {
     "duration": 0.004045,
     "end_time": "2026-10-02T14:45:34.957899+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:34.953854+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Details of the N2 Model Visualizations\n",
    "\n",
    "The N2 diagram has a number of sections:\n",
    "\n",
    "- Model hierarchy\n",
    "- Connection matrix\n",
    "- Solver hierarchy\n",
    "- Toolbar\n",
    "- Search bar\n",
    "- Legend\n",
    "- Show/Hide Optimization Variables\n",
    "\n",
    "This page will go into the details of each section.\n",
    "\n",
    "Just like in the [N2 Basics](../n2_basics/n2_basics.ipynb) section of this documentation, we will use the\n",
    "circuit model that is missing a connection as our example code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "497eba91",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:34.966796Z",
     "iopub.status.busy": "2026-10-02T14:45:34.966577Z",
     "iopub.status.idle": "2026-10-02T14:45:42.357825Z",
     "shell.execute_reply": "2026-10-02T14:45:42.356751Z"
    },
    "papermill": {
     "duration": 7.396711,
     "end_time": "2026-10-02T14:45:42.358524+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:34.961813+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_src77"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src77\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Resistor\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bb61ce6",
   "metadata": {
    "papermill": {
     "duration": 0.004022,
     "end_time": "2026-10-02T14:45:42.366921+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:42.362899+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Resistor` class definition \n",
    "\n",
    "{glue:}`code_src77`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b0c2ac27",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:42.446842Z",
     "iopub.status.busy": "2026-10-02T14:45:42.446574Z",
     "iopub.status.idle": "2026-10-02T14:45:42.465958Z",
     "shell.execute_reply": "2026-10-02T14:45:42.465512Z"
    },
    "papermill": {
     "duration": 0.027237,
     "end_time": "2026-10-02T14:45:42.467507+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:42.440270+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_src78"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src78\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Diode\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e7e8782",
   "metadata": {
    "papermill": {
     "duration": 0.00706,
     "end_time": "2026-10-02T14:45:42.478931+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:42.471871+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Diode` class definition \n",
    "\n",
    "{glue:}`code_src78`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1ff2dc1e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:42.492211Z",
     "iopub.status.busy": "2026-10-02T14:45:42.492010Z",
     "iopub.status.idle": "2026-10-02T14:45:42.514164Z",
     "shell.execute_reply": "2026-10-02T14:45:42.513736Z"
    },
    "papermill": {
     "duration": 0.032284,
     "end_time": "2026-10-02T14:45:42.515115+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:42.482831+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_src79"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src79\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Node\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c45e5427",
   "metadata": {
    "papermill": {
     "duration": 0.003515,
     "end_time": "2026-10-02T14:45:42.526946+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:42.523431+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `Node` class definition \n",
    "\n",
    "{glue:}`code_src79`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f7adbb43",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:42.540021Z",
     "iopub.status.busy": "2026-10-02T14:45:42.539387Z",
     "iopub.status.idle": "2026-10-02T14:45:44.100121Z",
     "shell.execute_reply": "2026-10-02T14:45:44.099733Z"
    },
    "papermill": {
     "duration": 1.572346,
     "end_time": "2026-10-02T14:45:44.103190+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:42.530844+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-output"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952344.043747] [runnervm8df0l:10094:0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55af70fa1df0 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",
      "[1790952344.046716] [runnervm8df0l:10094: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.000493 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:10094] 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",
    "\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": "6febcebf",
   "metadata": {
    "papermill": {
     "duration": 0.004527,
     "end_time": "2026-10-02T14:45:44.109926+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:44.105399+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Here is the N2 diagram that is generated from this model. There are three parts to the N2 diagram. The model hierarchy is on the left, the connection matrix is displayed in the center, and the solver hierarchy is shown on the right."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "53ae46bb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:45:44.119240Z",
     "iopub.status.busy": "2026-10-02T14:45:44.118975Z",
     "iopub.status.idle": "2026-10-02T14:45:44.245938Z",
     "shell.execute_reply": "2026-10-02T14:45:44.244748Z"
    },
    "papermill": {
     "duration": 0.132643,
     "end_time": "2026-10-02T14:45:44.246499+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:44.113856+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 0x7f91d13178c0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "om.n2(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "241a703c",
   "metadata": {
    "papermill": {
     "duration": 0.004009,
     "end_time": "2026-10-02T14:45:44.254928+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:45:44.250919+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Model Hierarchy\n",
    "\n",
    "The model hierarchy is on the left side of the diagram. It is a mix of Systems and variables, both\n",
    "inputs and outputs.\n",
    "\n",
    "The top System, the root of the model, is on the left and the subsystem hierarchy is displayed to its right.\n",
    "\n",
    "The colors indicate the type of item in the hierarchy. To see what the colors represent, an optional legend can be displayed using the <img src=\"../images/show_legend.png\" alt=\"show_legend\" width=\"25\" height=\"25\"> button. Here is the part of the legend that explains the colors of the model hierarchy.\n",
    "\n",
    "![systems_and_variables_legend](../images/systems_and_variables_legend.png)\n",
    "\n",
    "You can click in the model hierarchy to zoom into, and also collapse and expand sections of the hierarchy. Left clicking on a subsystem zooms the hierarchy display to just that subsystem in the hierarchy. Right clicking on a subsystem collapses all of the hierarchy to the right of it.\n",
    "\n",
    "Buttons on the toolbar, which are explained in the `Toolbar` section,\n",
    "also can be used to control what is displayed in the hierarchy.\n",
    "\n",
    "## Connection Matrix\n",
    "\n",
    "The matrix in the middle of the diagram shows what items in the model are connected.\n",
    "\n",
    "The color of an item on a diagonal cell matches the color of the rightmost element in the model hierarchy. The colors\n",
    "for the off-diagonal items, which indicate connections, are always black.\n",
    "\n",
    "The symbol of an item in the connection matrix indicates whether the variable is a scalar, vector, or collapsed variable.\n",
    "\n",
    "![connection_matrix_legend](../images/connection_matrix_legend.png)\n",
    "\n",
    "Boxes, with thin black line borders, outline items in the matrix to show the grouping of the variables of the lowest level Systems.\n",
    "\n",
    "When you hover over a connection in the matrix, arrows are drawn to indicate connections. The behavior is different\n",
    "depending on whether you hover over a diagonal or an off-diagonal cell.\n",
    "\n",
    "When hovering over a diagonal item, the explicit connections to/from that variable are displayed. Salmon colored arrows indicate that element is the target of the connection. A green arrow indicates it is the source.\n",
    "\n",
    "When hovering over an off-diagonal, the behavior differs depending on whether the cell is in the lower or upper\n",
    "triangular part of the diagram.\n",
    "\n",
    "In the lower triangular, the marked cells represent upstream (in the sense of execution order of the\n",
    "components) connections. All the connections involved in that cycle\n",
    "are drawn to indicate which systems and components are involved in the convergence loop. Downstream connection arrows are green and upstream connections are salmon colored.\n",
    "\n",
    "In the upper triangular, the marked cells represent downstream connections. The salmon colored arrow that is drawn shows that connection.\n",
    "\n",
    "Clicking in the matrix on a connection or diagonal, lets you pin connection arrows so that they don't\n",
    "disappear when you hover away from the cell. You can clear these connections arrows by using the\n",
    "`Hide all connection arrow button` <img src=\"../images/hide_conn_arrows.png\" alt=\"hide_conn_arrows\" width=\"25\" height=\"25\"> in the toolbar.\n",
    "\n",
    "## Solver Hierarchy\n",
    "\n",
    "Each System in a model can potentially have a linear and nonlinear solver associated with it. On the right side\n",
    "of the N2 diagram, the hierarchy of the solvers is shown. This time the hierarchy goes from right to left with the root of the model on the right.\n",
    "\n",
    "There are three states of the solver hierarchy display. Use these buttons to switch between them. Hiding the\n",
    "solver hierarchy creates more space for the rest of the N2 display.\n",
    " \n",
    "| Button                                                                                               \t| Title                   \t| Description                                 \t|\n",
    "|------------------------------------------------------------------------------------------------------\t|-------------------------\t|---------------------------------------------\t|\n",
    "| <img src=\"../images/show_nonlinear_solvers.png\" alt=\"show_nonlinear_solvers\" width=\"50\" height=\"50\"> \t| Show linear solvers     \t| Show linear solvers in solver hierarchy     \t|\n",
    "| <img src=\"../images/show_linear_solvers.png\" alt=\"show_linear_solvers\" width=\"50\" height=\"50\">       \t| Show non-linear solvers \t| Show non-linear solvers in solver hierarchy \t|\n",
    "| <img src=\"../images/hide_solvers.png\" alt=\"hide_solvers\" width=\"50\" height=\"50\">                     \t| Hide Solvers            \t| Hide the solver hierarchy                   \t|\n",
    "\n",
    "The colors indicate the type of solver. The colors are shown in the legend. The section of the legend showing\n",
    "the colors of the solver types changes depending on which are displayed in the solver structure.\n",
    "Here is what the section of the legend looks like for both linear and non-linear solvers.\n",
    "\n",
    "| Non-Linear Solver Legend                                                        \t| Linear Solver Legend                                                        \t|\n",
    "|---------------------------------------------------------------------------------\t|-----------------------------------------------------------------------------\t|\n",
    "| <img src=\"../images/nonlinear_solvers_legend.png\" alt=\"show_nonlinear_solvers\"> \t| <img src=\"../images/linear_solvers_legend.png\" alt=\"linear_solvers_legend\"> \t|\n",
    "\n",
    "```{Note}\n",
    "When a System has a Newton non-linear solver and the `solve_subsystems` option is set to True for that solver,\n",
    "the Solver hierarchy box for that System has the text `NL: Newton (sub_solve)`.\n",
    "```\n",
    "\n",
    "As in the model hierarchy, you can also do zooming, collapsing, and expanding in the Solver hierarchy using left and\n",
    "right mouse clicks.\n",
    "\n",
    "## Toolbar\n",
    "\n",
    "The toolbar to the left of the N2 diagram provides many useful capabilities. Explanations for all the buttons\n",
    "is below. Tooltips are also provided for all the buttons as you hover over them.\n",
    "\n",
    "### View Control\n",
    "\n",
    "The model hierarchy display has the notion of a `view`. The `view` is defined by the node in the hierarchy\n",
    "that is visible in the diagram. Initially, it is the root of the model but if you click on a subsystem, then\n",
    "only the part of the hierarchy beginning at that subsystem is shown.\n",
    "\n",
    "You can change the view and zoom into a System by left clicking on it. Other parts of the hierarchy are no longer\n",
    "visible.\n",
    "\n",
    "The diagram keeps track of the view history and then lets you go back and forth through the history similar to undo and\n",
    "redo in apps.\n",
    "\n",
    "| Button                                                                               \t| Title          \t| Description                          \t|\n",
    "|--------------------------------------------------------------------------------------\t|----------------\t|--------------------------------------\t|\n",
    "| <img src=\"../images/home.png\" alt=\"return_to_root\" width=\"50\" height=\"50\"> \t| Return to root \t| View entire model starting from root \t|\n",
    "| <img src=\"../images/back.png\" alt=\"back\" width=\"50\" height=\"50\">                     \t| Back           \t| Move back in view history            \t|\n",
    "| <img src=\"../images/forward.png\" alt=\"forward\" width=\"50\" height=\"50\">               \t| Forward        \t| Move forward in view history         \t|\n",
    "\n",
    "### Collapsing and Expanding the System Hierarchy\n",
    "\n",
    "The next set of buttons lets you control the collapsing and expanding of elements in the System hierarchy. The first four buttons are revealed as a fly-out menu as you hover over this button, <img src=\"../images/control_collapse.png\" alt=\"forward\" width=\"50\" height=\"50\"> .\n",
    "\n",
    "| Button                                                                               | Title                           | Description                                          |\n",
    "|--------------------------------------------------------------------------------------|---------------------------------|------------------------------------------------------|\n",
    "| <img src=\"../images/collapse_view.png\" alt=\"collapse_view\" width=\"50\" height=\"50\">   | Collapse variables in view only | Collapse only the variables in the current view      |\n",
    "| <img src=\"../images/expand_view.png\" alt=\"expand_view\" width=\"50\" height=\"50\">       | Expand variables in view only   | Expand only the variables in the current view        |\n",
    "| <img src=\"../images/collapse_all.png\" alt=\"collapse_all\" width=\"50\" height=\"50\">     | Collapse all variables          | Collapse all the variables in the entire model       |\n",
    "| <img src=\"../images/expand_all.png\" alt=\"expand_all\" width=\"50\" height=\"50\">         | Expand all variables            | Expand all the variables in the entire model         |\n",
    "| <img src=\"../images/collapse_depth.png\" alt=\"collapse_depth\" width=\"50\" height=\"50\"> | Collapse depth                  | Set the number of hierarchy levels shown in the view |\n",
    "\n",
    "### Connections Arrow Visibility\n",
    "\n",
    "The connections visibility is controlled using the buttons that appear when hovering over\n",
    "the <img src=\"../images/connection_visibility.png\" alt=\"connections_visibility\" width=\"50\" height=\"50\"> button.\n",
    "\n",
    "| Button                                                                                           | Title                        | Description                                |\n",
    "|--------------------------------------------------------------------------------------------------|------------------------------|--------------------------------------------|\n",
    "| <img src=\"../images/hide_conn_arrows.png\" alt=\"hide_conn_arrows\" width=\"50\" height=\"50\">         | Hide all connection arrows   | Hide all pinned connection arrows.         |\n",
    "| <img src=\"../images/show_all_conn_arrows.png\" alt=\"show_all_conn_arrows\" width=\"50\" height=\"50\"> | Show all connections in view | Show all connections in view and pin them. |\n",
    "\n",
    "### Remaining Toolbar Buttons\n",
    "\n",
    "The buttons in the remaining part of the toolbar offer a variety of other options:\n",
    "\n",
    "| Button                                                                                   | Title                         | Description                                                       |\n",
    "|------------------------------------------------------------------------------------------|-------------------------------|-------------------------------------------------------------------|\n",
    "| <img src=\"../images/show_legend.png\" alt=\"show_legend\" width=\"50\" height=\"50\">               | Show legend / Hide legend     | Show the legend explaining the colors and icons in the diagram    |\n",
    "| <img src=\"../images/model_opt_button.png\" alt=\"model_opt_button\" width=\"50\" height=\"50\"> | Show opt vars / Hide opt vars | Show the optimization variables in the diagram                    |\n",
    "| <img src=\"../images/font_size.png\" alt=\"font_size\" width=\"50\" height=\"50\">               | Font Size                     | Set the font size for the text in the diagram                     |\n",
    "| <img src=\"../images/collapse_depth.png\" alt=\"collapse_depth\" width=\"50\" height=\"50\">     | Set collapse depth            | Set how many levels are shown in the System hierarchy on the left |\n",
    "| <img src=\"../images/model_height.png\" alt=\"model_height\" width=\"50\" height=\"50\">         | Model Height                  | Set the height of the diagram in pixels                           |\n",
    "| <img src=\"../images/save_svg.png\" alt=\"save_svg\" width=\"50\" height=\"50\">                 | Save SVG                      | Save the current view of the diagram to an SVG file               |\n",
    "| <img src=\"../images/show_node_info.png\" alt=\"show_node_info\" width=\"50\" height=\"50\">     | Show / Hide Node Info         | Toggle info box that is displayed on hover                        |\n",
    "| <img src=\"../images/help.png\" alt=\"help\" width=\"50\" height=\"50\">                         | Help                          | Bring up the help window                                          |\n",
    "\n",
    "\n",
    "## Show Legend\n",
    "\n",
    "If you click on the legend button <img src=\"../images/show_legend.png\" alt=\"show_legend\" width=\"50\" height=\"50\">, you will see the legend appear below the N2 diagram.\n",
    "The Legend window can then be dragged to a location of the user's choice.\n",
    "\n",
    "![legend](../images/legend.png)\n",
    "\n",
    "Here are explanations of the sections in the legend:\n",
    "\n",
    "- The System & Variables section shows the colors for the different items in the model hierarchy.\n",
    "- The N2 Symbols section shows the icons used to indicate the type of connection in the connection matrix. The shape of the icon in the matrix shows whether the connection is between scalars, vectors, or groups. The color of the icon is based on the color associated with the variable of that type as shown in the System & Variables part of the legend.\n",
    "- The Solvers section shows the colors used for the different solvers on the right side of the N2. Either the Linear or Nonlinear solvers are shown depending on the state of the Toggle Solver Names button.\n",
    "\n",
    "\n",
    "## Show/Hide Optimization Variables\n",
    "\n",
    "Selecting this button <img src=\"../images/model_opt_button.png\" alt=\"model_opt_button\" width=\"50\" height=\"50\"> allows you to see your model's design variables, constraints, and objectives which are highlighted in purple. If your optimization variable is an Auto IVC, the Auto IVC cell will be highlighted as well which can be seen below.\n",
    "\n",
    "| Hidden                                                           | Shown                                                        |\n",
    "|------------------------------------------------------------------|--------------------------------------------------------------|\n",
    "| <img src=\"../images/model_opt_not_selected.png\" alt=\"model_opt_not_selected\"> | <img src=\"../images/model_opt_selected.png\" alt=\"model_opt_selected\"> |\n",
    "\n",
    "\n",
    "## Show Node Info\n",
    "\n",
    "The Show Node Info button |show_node_info|, brings up a small window that displays information about the item the\n",
    "cursor is hovering over.\n",
    "Here are some examples of what the user can see when hovering over variables, Systems, connection matrix cells, and\n",
    "Solvers.\n",
    "\n",
    "| Variable                                                                                     | System                                                                       | Connection                                                                 | Solver                                                                       |\n",
    "|----------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|----------------------------------------------------------------------------|------------------------------------------------------------------------------|\n",
    "| <img src=\"../images/variable_node_info.png\" alt=\"variable_node_info\" width=\"200\" height=\"200\"> | <img src=\"../images/system_node_info.png\" alt=\"hide\" width=\"200\" height=\"200\"> | <img src=\"../images/cell_node_info.png\" alt=\"hide\" width=\"200\" height=\"200\"> | <img src=\"../images/solver_node_info.png\" alt=\"hide\" width=\"200\" height=\"200\"> |\n",
    "\n",
    "## Search bar\n",
    "\n",
    "The search bar below the Toolbar lets you search for variables in the model. This can be very useful when working\n",
    "with very large models.\n",
    "\n",
    "When you enter a variable name into the search box and click the search button <img src=\"../images/search.png\" alt=\"search\" width=\"50\" height=\"50\"> or hit the Enter key, the N2\n",
    "diagram will redraw such that it collapses and shows only variables that were searched for.\n",
    "\n",
    "A search could find multiple instances of variables with the same name. For example, in the diagram above,\n",
    "a search for `V_in` would find `R1.V_in`, `R2.V_in`, and `D1.V_in`.\n",
    "\n",
    "To return to a view that is not filtered by the variable search, clear the search box and hit the Enter key or the\n",
    "Search button.\n",
    "\n",
    "## Show external connections\n",
    "\n",
    "When you zoom into a System, it is useful to see external connections into that System from other Systems\n",
    "that are no longer visible as a result of zooming. In that situation, the N2 diagram indicates external connections\n",
    "with dashed line arrows. For example:\n",
    "\n",
    "![external_connection](../images/external_connection.png)\n",
    "\n",
    "The dashed line arrow shows that `R2.V_out` variable is connected to `circuit.n2.V` even though that variable is no longer visible in the diagram."
   ]
  }
 ],
 "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": 13.452624,
   "end_time": "2026-10-02T14:45:46.800358+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/model_visualization/n2_details/n2_details.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/model_visualization/n2_details/n2_details.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:45:33.347734+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}