{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "f59b5184",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:30.274037Z",
     "iopub.status.busy": "2026-10-02T14:41:30.273825Z",
     "iopub.status.idle": "2026-10-02T14:41:30.278190Z",
     "shell.execute_reply": "2026-10-02T14:41:30.277612Z"
    },
    "papermill": {
     "duration": 0.006897,
     "end_time": "2026-10-02T14:41:30.278830+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:30.271933+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": "c7d87ff6",
   "metadata": {
    "papermill": {
     "duration": 0.001176,
     "end_time": "2026-10-02T14:41:30.281515+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:30.280339+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# LinearSystemComp\n",
    "\n",
    "The LinearSystemComp solves the linear system Ax = b where A and b are inputs, and x is the output.\n",
    "\n",
    "## LinearSystemComp Options\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "18d2eb96",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:30.345941Z",
     "iopub.status.busy": "2026-10-02T14:41:30.345811Z",
     "iopub.status.idle": "2026-10-02T14:41:31.509003Z",
     "shell.execute_reply": "2026-10-02T14:41:31.508444Z"
    },
    "papermill": {
     "duration": 1.227003,
     "end_time": "2026-10-02T14:41:31.509739+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:30.282736+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<!DOCTYPE html>\n",
       "<html lang=\"en\">\n",
       "<head>\n",
       "    <style>\n",
       "        h2 {\n",
       "            text-align: center;\n",
       "        }\n",
       "    </style>\n",
       "</head>\n",
       "<body>\n",
       "    <h2></h2>\n",
       "        <table style=\"border: 1px solid #999; border-collapse: collapse;\">\n",
       "        <tr><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Option</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Default</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Values</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Types</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Description</th></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">always_opt</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, force nonlinear operations on this component to be included in the optimization loop even if this component is not relevant to the design variables and responses.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">assembled_jac_type</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;csc&#x27;, &#x27;csr&#x27;, &#x27;dense&#x27;, None]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Linear solver(s) in this group or implicit component, if using an assembled jacobian, will use this type.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">default_shape</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">(1,)</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;tuple&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Default shape for variables that do not set val to a non-scalar value or set shape, shape_by_conn, copy_shape, or compute_shape. Default is (1,).</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">derivs_method</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;jax&#x27;, &#x27;cs&#x27;, &#x27;fd&#x27;, None]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">The method to use for computing derivatives</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">distributed</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, set all variables in this component as distributed across multiple processes</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">run_root_only</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, call compute, compute_partials, linearize, apply_linear, apply_nonlinear, solve_linear, solve_nonlinear, and compute_jacvec_product only on rank 0 and broadcast the results to the other ranks.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">size</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">The size of the linear system.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">use_jit</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, attempt to use jit on compute_primal, assuming jax or some other AD package capable of jitting is active.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">vec_size</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Number of linear systems to solve.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">vectorize_A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Set to True to vectorize the A matrix.</td></tr>\n",
       "    </table>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "om.show_options_table(\"openmdao.components.linear_system_comp.LinearSystemComp\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "140c112d",
   "metadata": {
    "papermill": {
     "duration": 0.001411,
     "end_time": "2026-10-02T14:41:31.512805+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:31.511394+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## LinearSystemComp Constructor\n",
    "\n",
    "The call signature for the `LinearSystemComp` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.components.linear_system_comp.LinearSystemComp.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## LinearSystemComp Example\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "2ed92165",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:31.669095Z",
     "iopub.status.busy": "2026-10-02T14:41:31.668711Z",
     "iopub.status.idle": "2026-10-02T14:41:32.881620Z",
     "shell.execute_reply": "2026-10-02T14:41:32.880939Z"
    },
    "papermill": {
     "duration": 1.216042,
     "end_time": "2026-10-02T14:41:32.882315+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:31.666273+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952092.867845] [runnervm8df0l:6634 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x5644c53664b0 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",
      "[1790952092.868118] [runnervm8df0l:6634 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "[ 0.36423841 -0.00662252 -0.4205298 ]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:06634] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "model = om.Group()\n",
    "\n",
    "A = np.array([[5.0, -3.0, 2.0], [1.0, 7.0, -4.0], [1.0, 0.0, 8.0]])\n",
    "b = np.array([1.0, 2.0, -3.0])\n",
    "\n",
    "lingrp = model.add_subsystem('lingrp', om.Group(), promotes=['*'])\n",
    "lingrp.add_subsystem('lin', om.LinearSystemComp(size=3))\n",
    "\n",
    "prob = om.Problem(model)\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('lin.A', A)\n",
    "prob.set_val('lin.b', b)\n",
    "\n",
    "lingrp.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('lin.x'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "305e5494",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:32.885624Z",
     "iopub.status.busy": "2026-10-02T14:41:32.885469Z",
     "iopub.status.idle": "2026-10-02T14:41:32.889360Z",
     "shell.execute_reply": "2026-10-02T14:41:32.888716Z"
    },
    "papermill": {
     "duration": 0.00618,
     "end_time": "2026-10-02T14:41:32.889824+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:32.883644+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(6.71747714541678e-09)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(prob.get_val('lin.x'), np.array([0.36423841, -0.00662252, -0.4205298 ]), .0001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "04880f1f",
   "metadata": {
    "papermill": {
     "duration": 0.001891,
     "end_time": "2026-10-02T14:41:32.905790+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:32.903899+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "This component can also be vectorized to either solve a single linear system with multiple right hand sides, or to solve multiple independent linear systems.\n",
    "\n",
    "You can solve multiple right hand sides by setting the \"vec_size\" argument, giving it the number of right hand sides. When you do this, the LinearSystemComp creates an input for \"b\" such that each row of b is solved independently."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b5cee228",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:32.965279Z",
     "iopub.status.busy": "2026-10-02T14:41:32.965097Z",
     "iopub.status.idle": "2026-10-02T14:41:32.973130Z",
     "shell.execute_reply": "2026-10-02T14:41:32.972412Z"
    },
    "papermill": {
     "duration": 0.066319,
     "end_time": "2026-10-02T14:41:32.973645+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:32.907326+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.10596026 -0.16556291  0.48675497]\n",
      " [ 0.19205298 -0.11258278 -0.14900662]]\n"
     ]
    }
   ],
   "source": [
    "model = om.Group()\n",
    "\n",
    "A = np.array([[5.0, -3.0, 2.0], [1.0, 7.0, -4.0], [1.0, 0.0, 8.0]])\n",
    "b = np.array([[2.0, -3.0, 4.0], [1.0, 0.0, -1.0]])\n",
    "\n",
    "lingrp = model.add_subsystem('lingrp', om.Group(), promotes=['*'])\n",
    "lingrp.add_subsystem('lin', om.LinearSystemComp(size=3, vec_size=2))\n",
    "\n",
    "prob = om.Problem(model)\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('lin.A', A)\n",
    "prob.set_val('lin.b', b)\n",
    "\n",
    "lingrp.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('lin.x'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "88e5f616",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:32.977186Z",
     "iopub.status.busy": "2026-10-02T14:41:32.977017Z",
     "iopub.status.idle": "2026-10-02T14:41:32.981121Z",
     "shell.execute_reply": "2026-10-02T14:41:32.980439Z"
    },
    "papermill": {
     "duration": 0.006797,
     "end_time": "2026-10-02T14:41:32.981593+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:32.974796+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.2860374400409043e-08)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('lin.x'), np.array([[ 0.10596026, -0.16556291,  0.48675497],\n",
    "                                                   [ 0.19205298, -0.11258278, -0.14900662]]), .0001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38b9dc7a",
   "metadata": {
    "papermill": {
     "duration": 0.001466,
     "end_time": "2026-10-02T14:41:32.984589+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:32.983123+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "To solve multiple linear systems, you just need to set the \"vectorize_A\" option or argument to True. The A\n",
    "matrix is now a 3-dimensional matrix where the first dimension is the number of linear systems to solve."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "5c3981c7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:33.049757Z",
     "iopub.status.busy": "2026-10-02T14:41:33.049544Z",
     "iopub.status.idle": "2026-10-02T14:41:33.057732Z",
     "shell.execute_reply": "2026-10-02T14:41:33.057040Z"
    },
    "papermill": {
     "duration": 0.072141,
     "end_time": "2026-10-02T14:41:33.058218+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:32.986077+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-0.78807947  0.66887417  0.47350993]\n",
      " [ 0.7        -1.8         0.75      ]]\n"
     ]
    }
   ],
   "source": [
    "model = om.Group()\n",
    "\n",
    "A = np.array([[[5.0, -3.0, 2.0], [1.0, 7.0, -4.0], [1.0, 0.0, 8.0]],\n",
    "              [[2.0, 3.0, 4.0], [1.0, -1.0, -2.0], [3.0, 2.0, -2.0]]])\n",
    "b = np.array([[-5.0, 2.0, 3.0], [-1.0, 1.0, -3.0]])\n",
    "\n",
    "lingrp = model.add_subsystem('lingrp', om.Group(), promotes=['*'])\n",
    "lingrp.add_subsystem('lin', om.LinearSystemComp(size=3, vec_size=2, vectorize_A=True))\n",
    "\n",
    "prob = om.Problem(model)\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('lin.A', A)\n",
    "prob.set_val('lin.b', b)\n",
    "\n",
    "lingrp.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('lin.x'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "eaa916f1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:33.118677Z",
     "iopub.status.busy": "2026-10-02T14:41:33.118441Z",
     "iopub.status.idle": "2026-10-02T14:41:33.123455Z",
     "shell.execute_reply": "2026-10-02T14:41:33.122827Z"
    },
    "papermill": {
     "duration": 0.064162,
     "end_time": "2026-10-02T14:41:33.123981+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:33.059819+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.8475641795162215e-09)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('lin.x'), np.array([[-0.78807947,  0.66887417,  0.47350993],\n",
    "                                                [ 0.7       , -1.8       ,  0.75      ]]),\n",
    "                 .0001)"
   ]
  }
 ],
 "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": 4.226448,
   "end_time": "2026-10-02T14:41:33.842091+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/components/linearsystem_comp.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/components/linearsystem_comp.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:41:29.615643+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}