{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "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",
   "metadata": {},
   "source": [
    "# InputResidsComp\n",
    "\n",
    "`InputResidsComp` is a specialized implementation of [ImplicitComponent](../../core_features/working_with_components/implicit_component.ipynb) that is intended to allow the user to simply add residuals to a system by treating any inputs to the components as the value of the associated residual.\n",
    "\n",
    "Unlike `BalanceComp`, implicit outputs do not map one-to-one with the inputs. That is, the number of output variables for `InputResidsComp` does not have to match the number of input variables, but **the total size of the inputs and outputs must be the same**.\n",
    "\n",
    "`InputResidsComp` can make it easier to convert an MDO problem from a \"SAND\" (simultaneous analysis and design) formumlation to an \"MDF\" (multiple design feasible) formulation by adding zero-valued equality constraints to it as inputs, and the associated design variables to it as implicit outputs."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## InputResidsComp Constructor\n",
    "\n",
    "The call signature for the `InputResidsComp` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.components.input_resids_comp.InputResidsComp.__init__()\n",
    "        :noindex:\n",
    "```"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example:  Single state vector, multiple equations of constraint\n",
    "\n",
    "The following example uses a InputResidsComp to implicitly solve the\n",
    "equations:\n",
    "\n",
    "\\begin{align}\n",
    "    x_0 + x_1 &= 5 \\\\\n",
    "    x_2 + x_3 &= 10 \\\\\n",
    "    x_0 &= x_3 \\\\\n",
    "    \\left\\Vert \\bar{x} \\right\\Vert &= 9\n",
    "\\end{align}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "bal = om.BalanceComp()\n",
    "bal.add_balance('x', use_mult=True)\n",
    "\n",
    "exec_comp = om.ExecComp(['y[0]=x[0] + x[1] - 5',\n",
    "                         'y[1]=x[2] + x[3] - 10',\n",
    "                         'y[2]=x[0] - x[3]',\n",
    "                         'z=dot(x, x)**0.5 - 9'],\n",
    "                        x={'shape': (4,)},\n",
    "                        y={'val': [1., 1., 1.]},\n",
    "                        z={'val': 2.})\n",
    "\n",
    "prob.model.add_subsystem(name='exec', subsys=exec_comp)\n",
    "resids = prob.model.add_subsystem(name='resids', subsys=om.InputResidsComp())\n",
    "\n",
    "resids.add_output('x', shape_by_conn=True)\n",
    "resids.add_input('res_0', shape_by_conn=True)\n",
    "resids.add_input('res_1', shape_by_conn=True)\n",
    "\n",
    "prob.model.connect('resids.x', 'exec.x')\n",
    "prob.model.connect('exec.y', 'resids.res_0')\n",
    "prob.model.connect('exec.z', 'resids.res_1')\n",
    "\n",
    "prob.model.linear_solver = om.DirectSolver(assemble_jac=True)\n",
    "prob.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False, maxiter=100, iprint=0)\n",
    "prob.set_solver_print(2)\n",
    "\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('resids.x', [1., 1., 10, 5])\n",
    "\n",
    "prob.final_setup()\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "prob.model.list_vars(print_arrays=True);\n"
   ]
  }
 ],
 "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.11.4"
  },
  "orphan": true
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
