{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "upset-transaction",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:43.170733Z",
     "iopub.status.busy": "2026-10-02T14:44:43.170484Z",
     "iopub.status.idle": "2026-10-02T14:44:43.175742Z",
     "shell.execute_reply": "2026-10-02T14:44:43.175149Z"
    },
    "papermill": {
     "duration": 0.008591,
     "end_time": "2026-10-02T14:44:43.176324+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:43.167733+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output",
     "active-ipynb"
    ]
   },
   "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": "allied-means",
   "metadata": {
    "papermill": {
     "duration": 0.000966,
     "end_time": "2026-10-02T14:44:43.178520+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:43.177554+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# Determining Variable Shapes at Runtime\n",
    "\n",
    "It's sometimes useful to create a component where the shapes of its inputs and/or outputs are\n",
    "determined by their connections.  This allows us to create components representing general\n",
    "purpose vector or matrix operations such as norms, summations, integrators, etc., that size\n",
    "themselves appropriately based on the model that they're added to.\n",
    "\n",
    "Turning on dynamic shape computation is straightforward.  You just specify `shape_by_conn`, `copy_shape`\n",
    "and/or `compute_shape` in your `add_input` or `add_output` calls when you add variables\n",
    "to your component.\n",
    "\n",
    "Setting `shape_by_conn=True` when adding an input or output variable will allow the shape\n",
    "of that variable to be determined at runtime based on the variable that connects to it.\n",
    "\n",
    "Setting `copy_shape=<var_name>`, where `<var_name>` is the local name of another variable in your\n",
    "component, will take the shape of the variable specified in `<var_name>` and use that\n",
    "shape for the variable you're adding.\n",
    "\n",
    "Setting `compute_shape=<func>`, where `<func>` is a function taking a dict arg that maps variable\n",
    "names to shapes and returning the computed shape, will set the shape of the variable you're adding\n",
    "as a function of the other variables in the same component of the opposite io type.  For example,\n",
    "setting `compute_shape` for an output `z` on a component with inputs `x` and `y`, would cause the\n",
    "supplied function to be called with a dict of the form {`x`: x_shape, `y`: y_shape}, so\n",
    "the computed shape of `z` could be a function of the shapes of `x_shape` and `y_shape`.  Note that the \n",
    "compute_shape function is not called until all shapes of the opposite io type are known for that \n",
    "component.\n",
    "\n",
    "Note that `shape_by_conn` can be specified for outputs as well as for inputs, as can `copy_shape`\n",
    "and `compute_shape`.\n",
    "This means that shape information can propagate through the model in either forward or reverse. If\n",
    "you specify both `shape_by_conn` and either `copy_shape` or `compute_shape` for your component's \n",
    "dynamically shaped variables, it will allow their shapes to be resolved whether known shapes have \n",
    "been defined upstream or downstream of your component in the model.  One important caveat is that\n",
    "solving for the shape in reverse is usually not possible if the connection between the input and \n",
    "output uses src_indices.\n",
    "\n",
    "The following component with input `x` and output `y` can have its shapes set by known shapes \n",
    "that are either upstream or downstream. Note that this component also has sparse partials, diagonal in this case, \n",
    "and those are specified within the `setup_partials` method which is called after all shapes have been computed.\n",
    "It uses the `_get_var_meta` method to get the size of its variables in order to determine the size\n",
    "of the partials.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "acute-wellington",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:43.188489Z",
     "iopub.status.busy": "2026-10-02T14:44:43.188296Z",
     "iopub.status.idle": "2026-10-02T14:44:44.361126Z",
     "shell.execute_reply": "2026-10-02T14:44:44.360451Z"
    },
    "papermill": {
     "duration": 1.182246,
     "end_time": "2026-10-02T14:44:44.361754+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:43.179508+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "\n",
    "\n",
    "class DynPartialsComp(om.ExplicitComponent):\n",
    "    def setup(self):\n",
    "        self.add_input('x', shape_by_conn=True, copy_shape='y')\n",
    "        self.add_output('y', shape_by_conn=True, copy_shape='x')\n",
    "\n",
    "    def setup_partials(self):\n",
    "        size = self._get_var_meta('x', 'size')\n",
    "        self.mat = np.eye(size) * 3.\n",
    "        self.declare_partials('y', 'x', diagonal=True, val=3.0)\n",
    "\n",
    "    def compute(self, inputs, outputs):\n",
    "        outputs['y'] = self.mat.dot(inputs['x'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "involved-advantage",
   "metadata": {
    "papermill": {
     "duration": 0.015125,
     "end_time": "2026-10-02T14:44:44.378048+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:44.362923+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The following example demonstrates the flow of shape information in the forward direction, where the IndepVarComp has a known size, and the DynPartialsComp and the ExecComp are sized dynamically."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "preliminary-liver",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:44.383348Z",
     "iopub.status.busy": "2026-10-02T14:44:44.383018Z",
     "iopub.status.idle": "2026-10-02T14:44:45.612616Z",
     "shell.execute_reply": "2026-10-02T14:44:45.611955Z"
    },
    "papermill": {
     "duration": 1.234274,
     "end_time": "2026-10-02T14:44:45.613424+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:44.379150+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952285.575405] [runnervm8df0l:8872 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x56032cbd1a60 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",
      "[1790952285.575648] [runnervm8df0l:8872 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "[[ 3. -0. -0. -0. -0.]\n",
      " [-0.  3. -0. -0. -0.]\n",
      " [-0. -0.  3. -0. -0.]\n",
      " [-0. -0. -0.  3. -0.]\n",
      " [-0. -0. -0. -0.  3.]]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:08872] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "p = om.Problem()\n",
    "p.model.add_subsystem('indeps', om.IndepVarComp('x', val=np.ones(5)))\n",
    "p.model.add_subsystem('comp', DynPartialsComp())\n",
    "p.model.add_subsystem('sink', om.ExecComp('y=x',\n",
    "                                          x={'shape_by_conn': True, 'copy_shape': 'y'},\n",
    "                                          y={'shape_by_conn': True, 'copy_shape': 'x'}))\n",
    "p.model.connect('indeps.x', 'comp.x')\n",
    "p.model.connect('comp.y', 'sink.x')\n",
    "p.setup()\n",
    "p.run_model()\n",
    "J = p.compute_totals(of=['sink.y'], wrt=['indeps.x'])\n",
    "print(J['sink.y', 'indeps.x'])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a5ae0ae9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:45.617112Z",
     "iopub.status.busy": "2026-10-02T14:44:45.616887Z",
     "iopub.status.idle": "2026-10-02T14:44:45.619425Z",
     "shell.execute_reply": "2026-10-02T14:44:45.618935Z"
    },
    "hide_input": true,
    "papermill": {
     "duration": 0.004931,
     "end_time": "2026-10-02T14:44:45.620137+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.615206+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output",
     "active-ipynb",
     "hide-input"
    ]
   },
   "outputs": [],
   "source": [
    "np.testing.assert_allclose(J['sink.y', 'indeps.x'], np.eye(5) * 3.)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "welcome-white",
   "metadata": {
    "papermill": {
     "duration": 0.249279,
     "end_time": "2026-10-02T14:44:45.870592+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.621313+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "And the following shows shape information flowing in reverse, from the known shape of `sink.x` to the unknown shape of the output `comp.y`, then to the input `comp.x`, then on to the connected auto-IndepVarComp output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "modified-allowance",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:45.876534Z",
     "iopub.status.busy": "2026-10-02T14:44:45.876303Z",
     "iopub.status.idle": "2026-10-02T14:44:45.887292Z",
     "shell.execute_reply": "2026-10-02T14:44:45.886541Z"
    },
    "papermill": {
     "duration": 0.015702,
     "end_time": "2026-10-02T14:44:45.887934+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.872232+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 3. -0. -0. -0. -0.]\n",
      " [-0.  3. -0. -0. -0.]\n",
      " [-0. -0.  3. -0. -0.]\n",
      " [-0. -0. -0.  3. -0.]\n",
      " [-0. -0. -0. -0.  3.]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "p = om.Problem()\n",
    "p.model.add_subsystem('comp', DynPartialsComp())\n",
    "p.model.add_subsystem('sink', om.ExecComp('y=x', shape=5))\n",
    "p.model.connect('comp.y', 'sink.x')\n",
    "p.setup()\n",
    "p.run_model()\n",
    "J = p.compute_totals(of=['sink.y'], wrt=['comp.x'])\n",
    "print(J['sink.y', 'comp.x'])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fd15ab26",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:45.892346Z",
     "iopub.status.busy": "2026-10-02T14:44:45.892149Z",
     "iopub.status.idle": "2026-10-02T14:44:45.895614Z",
     "shell.execute_reply": "2026-10-02T14:44:45.894943Z"
    },
    "hide_input": true,
    "papermill": {
     "duration": 0.006568,
     "end_time": "2026-10-02T14:44:45.896121+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.889553+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output",
     "active-ipynb",
     "hide-input"
    ]
   },
   "outputs": [],
   "source": [
    "np.testing.assert_allclose(J['sink.y', 'comp.x'], np.eye(5) * 3.)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1187cc1c",
   "metadata": {
    "papermill": {
     "duration": 0.001522,
     "end_time": "2026-10-02T14:44:45.899239+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.897717+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Finally, an example use of `compute_shape` is shown below.  We have a dynamically shaped component that multiplies two matrices, so the output `O` shape is determined by the shapes of both inputs, `M` and `N`.  In this case we use a lambda function to compute the output shape."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "af9ef572",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:45.902951Z",
     "iopub.status.busy": "2026-10-02T14:44:45.902810Z",
     "iopub.status.idle": "2026-10-02T14:44:45.912546Z",
     "shell.execute_reply": "2026-10-02T14:44:45.911817Z"
    },
    "papermill": {
     "duration": 0.01223,
     "end_time": "2026-10-02T14:44:45.913024+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.900794+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "input shapes: (3, 2) and (2, 5)\n",
      "output shape: (3, 5)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "class DynComputeComp(om.ExplicitComponent):\n",
    "    def setup(self):\n",
    "        self.add_input('M', shape_by_conn=True)\n",
    "        self.add_input('N', shape_by_conn=True)\n",
    "\n",
    "        # use a lambda function to compute the output shape based on the input shapes\n",
    "        self.add_output('O', compute_shape=lambda shapes: (shapes['M'][0], shapes['N'][1]))\n",
    "\n",
    "    def compute(self, inputs, outputs):\n",
    "        outputs['O'] = inputs['M'] @ inputs['N']\n",
    "\n",
    "p = om.Problem()\n",
    "indeps = p.model.add_subsystem('indeps', om.IndepVarComp())\n",
    "indeps.add_output('M', val=np.ones((3, 2)))\n",
    "indeps.add_output('N', val=np.ones((2, 5)))\n",
    "p.model.add_subsystem('comp', DynComputeComp())\n",
    "p.model.connect('indeps.M', 'comp.M')\n",
    "p.model.connect('indeps.N', 'comp.N')\n",
    "p.setup()\n",
    "p.run_model()\n",
    "print('input shapes:', p['indeps.M'].shape, 'and', p['indeps.N'].shape)\n",
    "print('output shape:', p['comp.O'].shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "599780f4",
   "metadata": {
    "papermill": {
     "duration": 0.002493,
     "end_time": "2026-10-02T14:44:45.916913+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.914420+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Residuals, like partials, have shapes which depend upon the shapes of the inputs of the component.\n",
    "The `add_residual` method for implicit components is typically used in the `setup` method, but in situations where the inputs are dynamically shaped, this information is not known at this time.\n",
    "\n",
    "For this reason, implicit components support a `setup_residuals` method.  This method is called in `final_setup` after the shapes of all inputs and outputs is known.\n",
    "\n",
    "For instance, the `InputResidsComp` in OpenMDAO adds a corresponding residual for each input.  Since these inputs may use dynamic sizing, we cannot assume to know their shapes during setup.  As a result, the `setup_residuals` method is used in `InputResidsComp` to add the residuals once their shapes are known:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "70377beb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:45.920141Z",
     "iopub.status.busy": "2026-10-02T14:44:45.919994Z",
     "iopub.status.idle": "2026-10-02T14:44:46.657350Z",
     "shell.execute_reply": "2026-10-02T14:44:46.656802Z"
    },
    "papermill": {
     "duration": 0.74024,
     "end_time": "2026-10-02T14:44:46.658443+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:45.918203+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "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\">InputResidsComp</span><span class=\"p\">(</span><span class=\"n\">ImplicitComponent</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Class definition for the InputResidsComp.</span>\n\n<span class=\"sd\">    Uses all inputs as residuals while allowing individual outputs that are not necessarily</span>\n<span class=\"sd\">    associated with a specific residual.</span>\n\n<span class=\"sd\">    Parameters</span>\n<span class=\"sd\">    ----------</span>\n<span class=\"sd\">    **kwargs : dict</span>\n<span class=\"sd\">        Dictionary of optional arguments.</span>\n\n<span class=\"sd\">    Attributes</span>\n<span class=\"sd\">    ----------</span>\n<span class=\"sd\">    _refs : dict</span>\n<span class=\"sd\">        Residual ref values that are cached during calls to the overloaded add_input method.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Initialize the InputResidsComp.</span>\n\n<span class=\"sd\">        Parameters</span>\n<span class=\"sd\">        ----------</span>\n<span class=\"sd\">        **kwargs : dict</span>\n<span class=\"sd\">            Keyword arguments passed to the __init__ method of ImplicitComponent</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_refs</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">add_input</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">ref</span><span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Add an input to be used as a residual.</span>\n\n<span class=\"sd\">        Parameters</span>\n<span class=\"sd\">        ----------</span>\n<span class=\"sd\">        name : str</span>\n<span class=\"sd\">            Name of the variable in this component&#39;s namespace.</span>\n<span class=\"sd\">        ref : float or ndarray or None</span>\n<span class=\"sd\">            Scaling parameter. The value in the user-defined units of this residual</span>\n<span class=\"sd\">            when the scaled value is 1. Default is 1.</span>\n<span class=\"sd\">        **kwargs : dict</span>\n<span class=\"sd\">            Additional arguments passed to the add_input method of ImplicitComponent.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_refs</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">ref</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_residuals</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delay calls for add_residual for this component.</span>\n\n<span class=\"sd\">        This method is used since input/residual sizes may not</span>\n<span class=\"sd\">        be known until final setup.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">for</span> <span class=\"n\">name</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_var_rel_names</span><span class=\"p\">[</span><span class=\"s1\">&#39;input&#39;</span><span class=\"p\">]:</span>\n            <span class=\"n\">meta</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_var_rel2meta</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">]</span>\n            <span class=\"n\">resid_name</span> <span class=\"o\">=</span> <span class=\"sa\">f</span><span class=\"s1\">&#39;resid_</span><span class=\"si\">{</span><span class=\"n\">name</span><span class=\"si\">}</span><span class=\"s1\">&#39;</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_residual</span><span class=\"p\">(</span><span class=\"n\">resid_name</span><span class=\"p\">,</span> <span class=\"n\">shape</span><span class=\"o\">=</span><span class=\"n\">meta</span><span class=\"p\">[</span><span class=\"s1\">&#39;shape&#39;</span><span class=\"p\">],</span> <span class=\"n\">units</span><span class=\"o\">=</span><span class=\"n\">meta</span><span class=\"p\">[</span><span class=\"s1\">&#39;units&#39;</span><span class=\"p\">],</span>\n                              <span class=\"n\">desc</span><span class=\"o\">=</span><span class=\"n\">meta</span><span class=\"p\">[</span><span class=\"s1\">&#39;desc&#39;</span><span class=\"p\">],</span> <span class=\"n\">ref</span><span class=\"o\">=</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_refs</span><span class=\"p\">[</span><span class=\"n\">name</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=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Delay calls to declare_partials for the component.</span>\n\n<span class=\"sd\">        This method is used because input/residual sizes</span>\n<span class=\"sd\">        may not be known until final setup.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">for</span> <span class=\"n\">name</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_var_rel_names</span><span class=\"p\">[</span><span class=\"s1\">&#39;input&#39;</span><span class=\"p\">]:</span>\n            <span class=\"n\">resid_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;resid_&#39;</span> <span class=\"o\">+</span> <span class=\"n\">name</span>\n            <span class=\"n\">size</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_var_rel2meta</span><span class=\"p\">[</span><span class=\"n\">name</span><span class=\"p\">][</span><span class=\"s1\">&#39;size&#39;</span><span class=\"p\">]</span>\n            <span class=\"n\">ar</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"nb\">int</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=\"n\">of</span><span class=\"o\">=</span><span class=\"n\">resid_name</span><span class=\"p\">,</span> <span class=\"n\">wrt</span><span class=\"o\">=</span><span class=\"n\">name</span><span class=\"p\">,</span> <span class=\"n\">rows</span><span class=\"o\">=</span><span class=\"n\">ar</span><span class=\"p\">,</span> <span class=\"n\">cols</span><span class=\"o\">=</span><span class=\"n\">ar</span><span class=\"p\">,</span> <span class=\"n\">val</span><span class=\"o\">=</span><span class=\"mf\">1.0</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=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Compute residuals given inputs and outputs.</span>\n\n<span class=\"sd\">        The model is assumed to be in an unscaled state.</span>\n\n<span class=\"sd\">        Parameters</span>\n<span class=\"sd\">        ----------</span>\n<span class=\"sd\">        inputs : Vector</span>\n<span class=\"sd\">            Unscaled, dimensional input variables read via inputs[key].</span>\n<span class=\"sd\">        outputs : Vector</span>\n<span class=\"sd\">            Unscaled, dimensional output variables read via outputs[key].</span>\n<span class=\"sd\">        residuals : Vector</span>\n<span class=\"sd\">            Unscaled, dimensional residuals written to via residuals[key].</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">residuals</span><span class=\"o\">.</span><span class=\"n\">set_val</span><span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"o\">.</span><span class=\"n\">asarray</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}{InputResidsComp}\\PY{p}{(}\\PY{n}{ImplicitComponent}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{    Class definition for the InputResidsComp.}\n\n\\PY{l+s+sd}{    Uses all inputs as residuals while allowing individual outputs that are not necessarily}\n\\PY{l+s+sd}{    associated with a specific residual.}\n\n\\PY{l+s+sd}{    Parameters}\n\\PY{l+s+sd}{    \\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}}\n\\PY{l+s+sd}{    **kwargs : dict}\n\\PY{l+s+sd}{        Dictionary of optional arguments.}\n\n\\PY{l+s+sd}{    Attributes}\n\\PY{l+s+sd}{    \\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}}\n\\PY{l+s+sd}{    \\PYZus{}refs : dict}\n\\PY{l+s+sd}{        Residual ref values that are cached during calls to the overloaded add\\PYZus{}input method.}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Initialize the InputResidsComp.}\n\n\\PY{l+s+sd}{        Parameters}\n\\PY{l+s+sd}{        \\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}}\n\\PY{l+s+sd}{        **kwargs : dict}\n\\PY{l+s+sd}{            Keyword arguments passed to the \\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{} method of ImplicitComponent}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}refs} \\PY{o}{=} \\PY{p}{\\PYZob{}}\\PY{p}{\\PYZcb{}}\n        \\PY{n+nb}{super}\\PY{p}{(}\\PY{p}{)}\\PY{o}{.}\\PY{n+nf+fm}{\\PYZus{}\\PYZus{}init\\PYZus{}\\PYZus{}}\\PY{p}{(}\\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{add\\PYZus{}input}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{name}\\PY{p}{,} \\PY{n}{ref}\\PY{o}{=}\\PY{k+kc}{None}\\PY{p}{,} \\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Add an input to be used as a residual.}\n\n\\PY{l+s+sd}{        Parameters}\n\\PY{l+s+sd}{        \\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}}\n\\PY{l+s+sd}{        name : str}\n\\PY{l+s+sd}{            Name of the variable in this component\\PYZsq{}s namespace.}\n\\PY{l+s+sd}{        ref : float or ndarray or None}\n\\PY{l+s+sd}{            Scaling parameter. The value in the user\\PYZhy{}defined units of this residual}\n\\PY{l+s+sd}{            when the scaled value is 1. Default is 1.}\n\\PY{l+s+sd}{        **kwargs : dict}\n\\PY{l+s+sd}{            Additional arguments passed to the add\\PYZus{}input method of ImplicitComponent.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}refs}\\PY{p}{[}\\PY{n}{name}\\PY{p}{]} \\PY{o}{=} \\PY{n}{ref}\n        \\PY{n+nb}{super}\\PY{p}{(}\\PY{p}{)}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{n}{name}\\PY{p}{,} \\PY{o}{*}\\PY{o}{*}\\PY{n}{kwargs}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}residuals}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Delay calls for add\\PYZus{}residual for this component.}\n\n\\PY{l+s+sd}{        This method is used since input/residual sizes may not}\n\\PY{l+s+sd}{        be known until final setup.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{k}{for} \\PY{n}{name} \\PY{o+ow}{in} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}var\\PYZus{}rel\\PYZus{}names}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{input}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{:}\n            \\PY{n}{meta} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}var\\PYZus{}rel2meta}\\PY{p}{[}\\PY{n}{name}\\PY{p}{]}\n            \\PY{n}{resid\\PYZus{}name} \\PY{o}{=} \\PY{l+s+sa}{f}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{resid\\PYZus{}}\\PY{l+s+si}{\\PYZob{}}\\PY{n}{name}\\PY{l+s+si}{\\PYZcb{}}\\PY{l+s+s1}{\\PYZsq{}}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}residual}\\PY{p}{(}\\PY{n}{resid\\PYZus{}name}\\PY{p}{,} \\PY{n}{shape}\\PY{o}{=}\\PY{n}{meta}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{shape}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{,} \\PY{n}{units}\\PY{o}{=}\\PY{n}{meta}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{units}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{,}\n                              \\PY{n}{desc}\\PY{o}{=}\\PY{n}{meta}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{desc}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{,} \\PY{n}{ref}\\PY{o}{=}\\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}refs}\\PY{p}{[}\\PY{n}{name}\\PY{p}{]}\\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{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Delay calls to declare\\PYZus{}partials for the component.}\n\n\\PY{l+s+sd}{        This method is used because input/residual sizes}\n\\PY{l+s+sd}{        may not be known until final setup.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{k}{for} \\PY{n}{name} \\PY{o+ow}{in} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}var\\PYZus{}rel\\PYZus{}names}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{input}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\\PY{p}{:}\n            \\PY{n}{resid\\PYZus{}name} \\PY{o}{=} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{resid\\PYZus{}}\\PY{l+s+s1}{\\PYZsq{}} \\PY{o}{+} \\PY{n}{name}\n            \\PY{n}{size} \\PY{o}{=} \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{\\PYZus{}var\\PYZus{}rel2meta}\\PY{p}{[}\\PY{n}{name}\\PY{p}{]}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{size}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n            \\PY{n}{ar} \\PY{o}{=} \\PY{n}{np}\\PY{o}{.}\\PY{n}{arange}\\PY{p}{(}\\PY{n}{size}\\PY{p}{,} \\PY{n}{dtype}\\PY{o}{=}\\PY{n+nb}{int}\\PY{p}{)}\n            \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{n}{of}\\PY{o}{=}\\PY{n}{resid\\PYZus{}name}\\PY{p}{,} \\PY{n}{wrt}\\PY{o}{=}\\PY{n}{name}\\PY{p}{,} \\PY{n}{rows}\\PY{o}{=}\\PY{n}{ar}\\PY{p}{,} \\PY{n}{cols}\\PY{o}{=}\\PY{n}{ar}\\PY{p}{,} \\PY{n}{val}\\PY{o}{=}\\PY{l+m+mf}{1.0}\\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{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Compute residuals given inputs and outputs.}\n\n\\PY{l+s+sd}{        The model is assumed to be in an unscaled state.}\n\n\\PY{l+s+sd}{        Parameters}\n\\PY{l+s+sd}{        \\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}\\PYZhy{}}\n\\PY{l+s+sd}{        inputs : Vector}\n\\PY{l+s+sd}{            Unscaled, dimensional input variables read via inputs[key].}\n\\PY{l+s+sd}{        outputs : Vector}\n\\PY{l+s+sd}{            Unscaled, dimensional output variables read via outputs[key].}\n\\PY{l+s+sd}{        residuals : Vector}\n\\PY{l+s+sd}{            Unscaled, dimensional residuals written to via residuals[key].}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n        \\PY{n}{residuals}\\PY{o}{.}\\PY{n}{set\\PYZus{}val}\\PY{p}{(}\\PY{n}{inputs}\\PY{o}{.}\\PY{n}{asarray}\\PY{p}{(}\\PY{p}{)}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class InputResidsComp(ImplicitComponent):\n    \"\"\"\n    Class definition for the InputResidsComp.\n\n    Uses all inputs as residuals while allowing individual outputs that are not necessarily\n    associated with a specific residual.\n\n    Parameters\n    ----------\n    **kwargs : dict\n        Dictionary of optional arguments.\n\n    Attributes\n    ----------\n    _refs : dict\n        Residual ref values that are cached during calls to the overloaded add_input method.\n    \"\"\"\n\n    def __init__(self, **kwargs):\n        \"\"\"\n        Initialize the InputResidsComp.\n\n        Parameters\n        ----------\n        **kwargs : dict\n            Keyword arguments passed to the __init__ method of ImplicitComponent\n        \"\"\"\n        self._refs = {}\n        super().__init__(**kwargs)\n\n    def add_input(self, name, ref=None, **kwargs):\n        \"\"\"\n        Add an input to be used as a residual.\n\n        Parameters\n        ----------\n        name : str\n            Name of the variable in this component's namespace.\n        ref : float or ndarray or None\n            Scaling parameter. The value in the user-defined units of this residual\n            when the scaled value is 1. Default is 1.\n        **kwargs : dict\n            Additional arguments passed to the add_input method of ImplicitComponent.\n        \"\"\"\n        self._refs[name] = ref\n        super().add_input(name, **kwargs)\n\n    def setup_residuals(self):\n        \"\"\"\n        Delay calls for add_residual for this component.\n\n        This method is used since input/residual sizes may not\n        be known until final setup.\n        \"\"\"\n        for name in self._var_rel_names['input']:\n            meta = self._var_rel2meta[name]\n            resid_name = f'resid_{name}'\n            self.add_residual(resid_name, shape=meta['shape'], units=meta['units'],\n                              desc=meta['desc'], ref=self._refs[name])\n\n    def setup_partials(self):\n        \"\"\"\n        Delay calls to declare_partials for the component.\n\n        This method is used because input/residual sizes\n        may not be known until final setup.\n        \"\"\"\n        for name in self._var_rel_names['input']:\n            resid_name = 'resid_' + name\n            size = self._var_rel2meta[name]['size']\n            ar = np.arange(size, dtype=int)\n            self.declare_partials(of=resid_name, wrt=name, rows=ar, cols=ar, val=1.0)\n\n    def apply_nonlinear(self, inputs, outputs, residuals):\n        \"\"\"\n        Compute residuals given inputs and outputs.\n\n        The model is assumed to be in an unscaled state.\n\n        Parameters\n        ----------\n        inputs : Vector\n            Unscaled, dimensional input variables read via inputs[key].\n        outputs : Vector\n            Unscaled, dimensional output variables read via outputs[key].\n        residuals : Vector\n            Unscaled, dimensional residuals written to via residuals[key].\n        \"\"\"\n        residuals.set_val(inputs.asarray())"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "input_resids_comp_src"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"input_resids_comp_src\", get_code(\"openmdao.components.input_resids_comp.InputResidsComp\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "tight-mining",
   "metadata": {
    "papermill": {
     "duration": 0.004361,
     "end_time": "2026-10-02T14:44:46.667911+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:46.663550+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Debugging\n",
    "\n",
    "Sometimes, when the shapes of some variables are unresolvable, it can be difficult to understand\n",
    "why.  There is an OpenMDAO command line tool, `openmdao view_dyn_shapes`, that can be used to\n",
    "show a graph of the dynamically shaped variables and any statically shaped variables that\n",
    "connect directly to them.  Each node in the graph is a variable, and each edge is a connection\n",
    "between that variable and another.  Note that this connection does not have to be a\n",
    "connection in the normal OpenMDAO sense.  It could be a connection internal to a component\n",
    "created by declaring a `copy_shape` in the metadata of one variable that refers to another\n",
    "variable.\n",
    "\n",
    "The nodes in the graph are colored to make it easier to locate static/dynamic/unresolved\n",
    "variable shapes.  Statically shaped variables are colored green, dynamically shaped\n",
    "variables that have been resolved are colored blue, and any variables with unresolved shapes\n",
    "are colored red.  Each node is labeled with the shape of the variable, if known, or a '?' if\n",
    "unknown, followed by the absolute pathname of the variable in the model.\n",
    "\n",
    "The plot is somewhat crude and the node labels sometimes overlap, but it's possible to zoom\n",
    "in to part of the graph to make it more readable using the button that looks like a magnifying glass.\n",
    "\n",
    "Below is an example plot for a simple model with three components and no unresolved shapes.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "instant-state",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:44:46.682861Z",
     "iopub.status.busy": "2026-10-02T14:44:46.682633Z",
     "iopub.status.idle": "2026-10-02T14:44:46.804020Z",
     "shell.execute_reply": "2026-10-02T14:44:46.803394Z"
    },
    "hide_input": true,
    "papermill": {
     "duration": 0.133656,
     "end_time": "2026-10-02T14:44:46.804779+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:46.671123+00:00",
     "status": "completed"
    },
    "scrolled": true,
    "tags": [
     "remove_input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.visualization.dyn_shape_plot import view_dyn_shapes\n",
    "p = om.Problem()\n",
    "indep = p.model.add_subsystem('indep', om.IndepVarComp('x1', val=np.ones((2,3))))\n",
    "indep.add_output('x2', val=np.ones((4,2)))\n",
    "\n",
    "p.model.add_subsystem('C1', om.ExecComp('y1, y2 = x1*2, x2*2',\n",
    "                                                x1={'shape_by_conn': True, 'copy_shape': 'y1'},\n",
    "                                                x2={'shape_by_conn': True, 'copy_shape': 'y2'},\n",
    "                                                y1={'shape_by_conn': True, 'copy_shape': 'x1'},\n",
    "                                                y2={'shape_by_conn': True, 'copy_shape': 'x2'}))\n",
    "\n",
    "p.model.add_subsystem('C2', om.ExecComp('y1, y2 = x1*2, x2*2',\n",
    "                                                x1={'shape_by_conn': True, 'copy_shape': 'y1'},\n",
    "                                                x2={'shape_by_conn': True, 'copy_shape': 'y2'},\n",
    "                                                y1={'shape_by_conn': True, 'copy_shape': 'x1'},\n",
    "                                                y2={'shape_by_conn': True, 'copy_shape': 'x2'}))\n",
    "\n",
    "p.model.connect('indep.x1', 'C1.x1')\n",
    "p.model.connect('indep.x2', 'C1.x2')\n",
    "p.model.connect('C1.y1', 'C2.x1')\n",
    "p.model.connect('C1.y2', 'C2.x2')\n",
    "\n",
    "p.setup()\n",
    "p.final_setup()\n",
    "\n",
    "view_dyn_shapes(p.model)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "residential-theme",
   "metadata": {
    "papermill": {
     "duration": 0.001901,
     "end_time": "2026-10-02T14:44:46.808793+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:44:46.806892+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Connecting Non-Distributed and Distributed Variables\n",
    "\n",
    "Dynamically shaped connections between distributed outputs and non-distributed inputs are not allowed because OpenMDAO assumes data will be transferred locally when computing variable shapes.  Since non-distributed variables must be identical in size and value on all ranks where they exist, the distributed output would have to also be identical in size and value on all ranks.  If that is the case, then the output should just be non-distributed as well.\n",
    "\n",
    "Dynamically shaped connections between non-distributed outputs and distributed inputs are currently allowed, though their use is not recommended. Such connections require that all src_indices in all ranks of the distributed input are identical."
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Edit Metadata",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 5.004364,
   "end_time": "2026-10-02T14:44:47.525677+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/experimental/dyn_shapes.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/experimental/dyn_shapes.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:44:42.521313+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}