{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "a5429a40",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:19.332106Z",
     "iopub.status.busy": "2026-10-02T14:41:19.331837Z",
     "iopub.status.idle": "2026-10-02T14:41:19.337468Z",
     "shell.execute_reply": "2026-10-02T14:41:19.336914Z"
    },
    "papermill": {
     "duration": 0.009795,
     "end_time": "2026-10-02T14:41:19.338150+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:19.328355+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": "1feae0ac",
   "metadata": {
    "papermill": {
     "duration": 0.001621,
     "end_time": "2026-10-02T14:41:19.341907+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:19.340286+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# ExplicitFuncComp\n",
    "\n",
    "\n",
    "`ExplicitFuncComp` is a component that provides a shortcut for building an ExplicitComponent based\n",
    "on a python function. The function must have one or more differentiable arguments, which can be either\n",
    "floats or numpy arrays, and zero or more arguments that are treated as non-differentiable and are \n",
    "assumed to remain static during the computation of derivatives. The function must also return either a single float or numpy array or a tuple of such values, where each entry in the tuple represents a different output of the OpenMDAO component. The ExplicitFuncComp automatically takes care of all of the component API methods, so you just need to instantiate it with a function.  In most cases that function will need additional metadata that you can add using the [Function Metadata API](../func_api.ipynb).  You should read and understand the [Function Metadata API](../func_api.ipynb) before you continue with this section.\n",
    "\n",
    "## ExplicitFuncComp Options\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b7d61a7f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:19.345810Z",
     "iopub.status.busy": "2026-10-02T14:41:19.345605Z",
     "iopub.status.idle": "2026-10-02T14:41:20.660745Z",
     "shell.execute_reply": "2026-10-02T14:41:20.660149Z"
    },
    "papermill": {
     "duration": 1.31771,
     "end_time": "2026-10-02T14:41:20.661181+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:19.343471+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;\">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: ghostwhite;\"><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: #F3F3F3;\"><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: ghostwhite;\"><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: #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",
       "    </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",
    "def func(a):\n",
    "    y = a * 2.\n",
    "    return y\n",
    "om.show_options_table(om.ExplicitFuncComp(func))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "678185e7",
   "metadata": {
    "papermill": {
     "duration": 0.001448,
     "end_time": "2026-10-02T14:41:20.664125+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:20.662677+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ExplicitFuncComp Constructor\n",
    "\n",
    "The call signature for the `ExplicitFuncComp` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.components.explicit_func_comp.ExplicitFuncComp.__init__\n",
    "        :noindex:\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a1a9cd0",
   "metadata": {
    "papermill": {
     "duration": 0.004648,
     "end_time": "2026-10-02T14:41:20.669971+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:20.665323+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ExplicitFuncComp Example: Simple\n",
    "\n",
    "For example, here is a simple component that takes the input and adds one to it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "57663e21",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:20.674989Z",
     "iopub.status.busy": "2026-10-02T14:41:20.674679Z",
     "iopub.status.idle": "2026-10-02T14:41:21.887760Z",
     "shell.execute_reply": "2026-10-02T14:41:21.886057Z"
    },
    "papermill": {
     "duration": 1.217229,
     "end_time": "2026-10-02T14:41:21.888397+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:20.671168+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952081.874884] [runnervm8df0l:6466 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x561e3f5bc540 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",
      "[1790952081.875145] [runnervm8df0l:6466 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "3.0\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:06466] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "def func(x=2.0):\n",
    "    y = x + 1.\n",
    "    return y\n",
    "\n",
    "model.add_subsystem('comp', om.ExplicitFuncComp(func))\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('comp.y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e94886dc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:21.893601Z",
     "iopub.status.busy": "2026-10-02T14:41:21.893400Z",
     "iopub.status.idle": "2026-10-02T14:41:21.898782Z",
     "shell.execute_reply": "2026-10-02T14:41:21.898152Z"
    },
    "papermill": {
     "duration": 0.009069,
     "end_time": "2026-10-02T14:41:21.899477+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.890408+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "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('comp.y'), 3.0, 0.00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "861bd6d4",
   "metadata": {
    "papermill": {
     "duration": 0.001759,
     "end_time": "2026-10-02T14:41:21.903066+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.901307+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ExplicitFuncComp Example: Arrays\n",
    "\n",
    "You can declare an ExplicitFuncComp with arrays for inputs and outputs.  In the case of inputs,\n",
    "you must either provide default array values or you must set their 'shape' metadata correctly using\n",
    "the [Function Metadata API](../func_api.ipynb).  For outputs you must provide 'shape' \n",
    "metadata as well. In the example below, the input shape of `x` is set via the function default value \n",
    "and the output `y` has its shape set via the `add_output` method of the [Function Metadata API](../func_api.ipynb)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "ac01da23",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:21.907394Z",
     "iopub.status.busy": "2026-10-02T14:41:21.907221Z",
     "iopub.status.idle": "2026-10-02T14:41:21.913903Z",
     "shell.execute_reply": "2026-10-02T14:41:21.913208Z"
    },
    "papermill": {
     "duration": 0.009536,
     "end_time": "2026-10-02T14:41:21.914390+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.904854+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1. 2.]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.func_api as omf\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "def func(x=np.array([1., 2., 3.])):\n",
    "    y = x[:2]\n",
    "    return y\n",
    "\n",
    "f = omf.wrap(func).add_output('y', shape=2)\n",
    "\n",
    "model.add_subsystem('comp', om.ExplicitFuncComp(f))\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('comp.y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b48c6752",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:21.919752Z",
     "iopub.status.busy": "2026-10-02T14:41:21.919562Z",
     "iopub.status.idle": "2026-10-02T14:41:21.924158Z",
     "shell.execute_reply": "2026-10-02T14:41:21.923568Z"
    },
    "papermill": {
     "duration": 0.007974,
     "end_time": "2026-10-02T14:41:21.924644+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.916670+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('comp.y'), np.array([1.0, 2.0]), 0.00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1351559f",
   "metadata": {
    "papermill": {
     "duration": 0.002195,
     "end_time": "2026-10-02T14:41:21.928664+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.926469+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ExplicitFuncComp Example: Variable Properties\n",
    "\n",
    "You can also declare properties like 'units' on the inputs and outputs. In this\n",
    "example we declare all our inputs to be inches to trigger conversion from a variable expressed in feet\n",
    "in one connection source."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b1dd2a8d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:21.933290Z",
     "iopub.status.busy": "2026-10-02T14:41:21.933130Z",
     "iopub.status.idle": "2026-10-02T14:41:21.939153Z",
     "shell.execute_reply": "2026-10-02T14:41:21.938650Z"
    },
    "papermill": {
     "duration": 0.008994,
     "end_time": "2026-10-02T14:41:21.939565+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.930571+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "24.0\n"
     ]
    }
   ],
   "source": [
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "def func(x, y):\n",
    "    z = x + y\n",
    "    return z\n",
    "\n",
    "f = omf.wrap(func).defaults(units='inch')\n",
    "\n",
    "model.add_subsystem('comp', om.ExplicitFuncComp(f))\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('comp.x', 12.0, units='inch')\n",
    "prob.set_val('comp.y', 1.0, units='ft')\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('comp.z'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0791e9b2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:21.943945Z",
     "iopub.status.busy": "2026-10-02T14:41:21.943789Z",
     "iopub.status.idle": "2026-10-02T14:41:21.946740Z",
     "shell.execute_reply": "2026-10-02T14:41:21.946227Z"
    },
    "papermill": {
     "duration": 0.005757,
     "end_time": "2026-10-02T14:41:21.947181+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.941424+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('comp.z'), 24.0, 0.00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3da4067",
   "metadata": {
    "papermill": {
     "duration": 0.002101,
     "end_time": "2026-10-02T14:41:21.951515+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.949414+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ExplicitFuncComp Example: Partial Derivatives\n",
    "\n",
    "All nonzero partial derivatives for an ExplicitFuncComp must be declared when the function is wrapped.\n",
    "Otherwise, OpenMDAO will assume that all partial derivatives for that component are zero.  For\n",
    "example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d4a38c22",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:21.956773Z",
     "iopub.status.busy": "2026-10-02T14:41:21.956593Z",
     "iopub.status.idle": "2026-10-02T14:41:21.997611Z",
     "shell.execute_reply": "2026-10-02T14:41:21.997080Z"
    },
    "papermill": {
     "duration": 0.044143,
     "end_time": "2026-10-02T14:41:21.998035+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:21.953892+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def func(a=2.0, b=3.0):\n",
    "    x = 2. * a\n",
    "    y = b - 1.0 / 3.0\n",
    "    return x, y\n",
    "\n",
    "f = (omf.wrap(func)\n",
    "        .defaults(method='cs')\n",
    "        .declare_partials(of='x', wrt='a')\n",
    "        .declare_partials(of='y', wrt='b'))\n",
    "\n",
    "p = om.Problem()\n",
    "p.model.add_subsystem('comp', om.ExplicitFuncComp(f))\n",
    "p.setup()\n",
    "p.run_model()\n",
    "J = p.compute_totals(of=['comp.x', 'comp.y'], wrt=['comp.a', 'comp.b'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "15f7b0cf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:22.023250Z",
     "iopub.status.busy": "2026-10-02T14:41:22.022779Z",
     "iopub.status.idle": "2026-10-02T14:41:22.025775Z",
     "shell.execute_reply": "2026-10-02T14:41:22.025304Z"
    },
    "papermill": {
     "duration": 0.026173,
     "end_time": "2026-10-02T14:41:22.026195+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.000022+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0\n",
      "1.0\n"
     ]
    }
   ],
   "source": [
    "print(J['comp.x', 'comp.a'][0][0])\n",
    "print(J['comp.y', 'comp.b'][0][0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "4ef07ad4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:22.030896Z",
     "iopub.status.busy": "2026-10-02T14:41:22.030727Z",
     "iopub.status.idle": "2026-10-02T14:41:22.035388Z",
     "shell.execute_reply": "2026-10-02T14:41:22.034761Z"
    },
    "papermill": {
     "duration": 0.007726,
     "end_time": "2026-10-02T14:41:22.035992+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.028266+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "assert_near_equal(J['comp.x', 'comp.a'][0][0], 2.0, .00001)\n",
    "assert_near_equal(J['comp.y', 'comp.b'][0][0], 1.0, .00001)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f73dd60a",
   "metadata": {
    "papermill": {
     "duration": 0.002148,
     "end_time": "2026-10-02T14:41:22.040125+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.037977+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "\n",
    "\n",
    "## ExplicitFuncComp Example: Sparse Partials\n",
    "\n",
    "If you know that some of the partials are sparse, then you should declare them as sparse\n",
    "in order to get the best possible performance when computing derivatives for your component. Here's an example of a function with sparse, in this case diagonal, partials:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "73da1941",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:22.045023Z",
     "iopub.status.busy": "2026-10-02T14:41:22.044861Z",
     "iopub.status.idle": "2026-10-02T14:41:22.048236Z",
     "shell.execute_reply": "2026-10-02T14:41:22.047727Z"
    },
    "papermill": {
     "duration": 0.006764,
     "end_time": "2026-10-02T14:41:22.048979+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.042215+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def func(x=np.ones(5), y=np.ones(5)):\n",
    "    z = x * y\n",
    "    return z\n",
    "\n",
    "f = (omf.wrap(func)\n",
    "        .add_output('z', shape=5)\n",
    "        .declare_partials(of='z', wrt=['x', 'y'], method='cs', rows=np.arange(5), cols=np.arange(5)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "217a13a2",
   "metadata": {
    "papermill": {
     "duration": 0.00196,
     "end_time": "2026-10-02T14:41:22.052951+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.050991+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ExplicitFuncComp Example: Default metadata values\n",
    "\n",
    "Metadata that can apply to all the variables in the component are shape and units.\n",
    "These can be set via the `defaults` method of the [Function Metadata API](../func_api.ipynb). \n",
    "In the following example the variables all share the same shape and units."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "21022e92",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:22.061498Z",
     "iopub.status.busy": "2026-10-02T14:41:22.061329Z",
     "iopub.status.idle": "2026-10-02T14:41:22.072609Z",
     "shell.execute_reply": "2026-10-02T14:41:22.071722Z"
    },
    "papermill": {
     "duration": 0.014662,
     "end_time": "2026-10-02T14:41:22.073147+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.058485+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[6.]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "def func(x=np.ones(5)):\n",
    "    y = 2. * x[2]\n",
    "    return y\n",
    "\n",
    "f = omf.wrap(func).defaults(shape=1, units='m')\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "prob.model.add_subsystem('comp', om.ExplicitFuncComp(f))\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "prob.set_val('comp.x', [100., 200., 300., 400., 500.], units='cm')\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('comp.y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "cb261412",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:22.077945Z",
     "iopub.status.busy": "2026-10-02T14:41:22.077786Z",
     "iopub.status.idle": "2026-10-02T14:41:22.081932Z",
     "shell.execute_reply": "2026-10-02T14:41:22.081185Z"
    },
    "papermill": {
     "duration": 0.007344,
     "end_time": "2026-10-02T14:41:22.082501+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:22.075157+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('comp.y'), [6.], 0.00001)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "interpreter": {
   "hash": "16ed3b9d19aea4081222d83efe886ecdef9297b336d0dad7bfd68d57c9797627"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.081532,
   "end_time": "2026-10-02T14:41:22.700201+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/components/explicit_func_comp.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/components/explicit_func_comp.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:41:18.618669+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}