{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "c7a74dd6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:05.197330Z",
     "iopub.status.busy": "2026-10-02T14:40:05.197110Z",
     "iopub.status.idle": "2026-10-02T14:40:05.202502Z",
     "shell.execute_reply": "2026-10-02T14:40:05.201505Z"
    },
    "papermill": {
     "duration": 0.008398,
     "end_time": "2026-10-02T14:40:05.203212+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:05.194814+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": "a408f75f",
   "metadata": {
    "papermill": {
     "duration": 0.037509,
     "end_time": "2026-10-02T14:40:05.242084+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:05.204575+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "OpenMDAO considers component derivatives to be **partial derivatives**. The framework uses these partial derivatives in order to compute the **total derivatives** across your whole model. This tutorial is focused on how to define the partial derivatives for components that inherit from [ExplicitComponent](../../features/core_features/working_with_components/explicit_component.ipynb).\n",
    "\n",
    "# Defining Partial Derivatives on Explicit Components\n",
    "\n",
    "For any [ExplicitComponent](../../features/core_features/working_with_components/explicit_component.ipynb) you are going to provide derivatives of the **outputs with respect to the inputs**. Whenever you are going to define derivatives, there are two things you're required to do:\n",
    "\n",
    "1. Declare the partial derivatives via `declare_partials`.\n",
    "2. Specify their values via `compute_partials`.\n",
    "\n",
    "Here is an example, based on the [Betz Limit Example](../../examples/betz_limit.ipynb):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b75ff9ab",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:05.260119Z",
     "iopub.status.busy": "2026-10-02T14:40:05.259851Z",
     "iopub.status.idle": "2026-10-02T14:40:15.455243Z",
     "shell.execute_reply": "2026-10-02T14:40:15.454490Z"
    },
    "papermill": {
     "duration": 10.212429,
     "end_time": "2026-10-02T14:40:15.456269+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:05.243840+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/modopt/external_libraries/cvxopt/cvxopt.py:237: SyntaxWarning: invalid escape sequence '\\c'\n",
      "  z_0 \\nabla^2f_0(x) + z_1 \\nabla^2f_1(x) + \\cdots + z_m \\nabla^2f_m(x).\n"
     ]
    }
   ],
   "source": [
    "import openmdao.api as om\n",
    "\n",
    "\n",
    "class ActuatorDisc(om.ExplicitComponent):\n",
    "    \"\"\"Simple wind turbine model based on actuator disc theory\"\"\"\n",
    "\n",
    "    def setup(self):\n",
    "        # Inputs\n",
    "        self.add_input('a', 0.5, desc=\"Induced Velocity Factor\")\n",
    "        self.add_input('Area', 10.0, units=\"m**2\", desc=\"Rotor disc area\")\n",
    "        self.add_input('rho', 1.225, units=\"kg/m**3\", desc=\"Air density\")\n",
    "        self.add_input('Vu', 10.0, units=\"m/s\", desc=\"Freestream air velocity, upstream of rotor\")\n",
    "\n",
    "        # Outputs\n",
    "        self.add_output('Vr', 0.0, units=\"m/s\",\n",
    "                        desc=\"Air velocity at rotor exit plane\")\n",
    "        self.add_output('Vd', 0.0, units=\"m/s\",\n",
    "                        desc=\"Slipstream air velocity, downstream of rotor\")\n",
    "        self.add_output('Ct', 0.0, desc=\"Thrust Coefficient\")\n",
    "        self.add_output('thrust', 0.0, units=\"N\",\n",
    "                        desc=\"Thrust produced by the rotor\")\n",
    "        self.add_output('Cp', 0.0, desc=\"Power Coefficient\")\n",
    "        self.add_output('power', 0.0, units=\"W\", desc=\"Power produced by the rotor\")\n",
    "\n",
    "    def setup_partials(self):\n",
    "        self.declare_partials('Vr', ['a', 'Vu'])\n",
    "        self.declare_partials('Vd', 'a')\n",
    "        self.declare_partials('Ct', 'a')\n",
    "        self.declare_partials('thrust', ['a', 'Area', 'rho', 'Vu'])\n",
    "        self.declare_partials('Cp', 'a')\n",
    "        self.declare_partials('power', ['a', 'Area', 'rho', 'Vu'])\n",
    "\n",
    "    def compute(self, inputs, outputs):\n",
    "        \"\"\" Considering the entire rotor as a single disc that extracts\n",
    "        velocity uniformly from the incoming flow and converts it to\n",
    "        power.\"\"\"\n",
    "\n",
    "        a = inputs['a']\n",
    "        Vu = inputs['Vu']\n",
    "\n",
    "        qA = .5 * inputs['rho'] * inputs['Area'] * Vu**2\n",
    "\n",
    "        outputs['Vd'] = Vd = Vu * (1 - 2 * a)\n",
    "        outputs['Vr'] = .5 * (Vu + Vd)\n",
    "\n",
    "        outputs['Ct'] = Ct = 4 * a * (1 - a)\n",
    "        outputs['thrust'] = Ct * qA\n",
    "\n",
    "        outputs['Cp'] = Cp = Ct * (1 - a)\n",
    "        outputs['power'] = Cp * qA * Vu\n",
    "\n",
    "    def compute_partials(self, inputs, J):\n",
    "        \"\"\" Jacobian of partial derivatives.\"\"\"\n",
    "\n",
    "        a = inputs['a']\n",
    "        Vu = inputs['Vu']\n",
    "        Area = inputs['Area']\n",
    "        rho = inputs['rho']\n",
    "\n",
    "        # pre-compute commonly needed quantities\n",
    "        a_times_area = a * Area\n",
    "        one_minus_a = 1.0 - a\n",
    "        a_area_rho_vu = a_times_area * rho * Vu\n",
    "\n",
    "        J['Vr', 'a'] = -Vu\n",
    "        J['Vr', 'Vu'] = one_minus_a\n",
    "\n",
    "        J['Vd', 'a'] = -2.0 * Vu\n",
    "\n",
    "        J['Ct', 'a'] = 4.0 - 8.0 * a\n",
    "\n",
    "        J['thrust', 'a'] = .5 * rho * Vu**2 * Area * J['Ct', 'a']\n",
    "        J['thrust', 'Area'] = 2.0 * Vu**2 * a * rho * one_minus_a\n",
    "        J['thrust', 'rho'] = 2.0 * a_times_area * Vu ** 2 * (one_minus_a)\n",
    "        J['thrust', 'Vu'] = 4.0 * a_area_rho_vu * (one_minus_a)\n",
    "\n",
    "        J['Cp', 'a'] = 4.0 * a * (2.0 * a - 2.0) + 4.0 * (one_minus_a)**2\n",
    "\n",
    "        J['power', 'a'] = 2.0 * Area * Vu**3 * a * rho * (\n",
    "            2.0 * a - 2.0) + 2.0 * Area * Vu**3 * rho * one_minus_a**2\n",
    "        J['power', 'Area'] = 2.0 * Vu**3 * a * rho * one_minus_a**2\n",
    "        J['power', 'rho'] = 2.0 * a_times_area * Vu ** 3 * (one_minus_a)**2\n",
    "        J['power', 'Vu'] = 6.0 * Area * Vu**2 * a * rho * one_minus_a**2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bfd58e0",
   "metadata": {
    "papermill": {
     "duration": 0.000928,
     "end_time": "2026-10-02T14:40:15.458337+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:15.457409+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "The calls to `declare_partials` tell OpenMDAO which partial derivatives to expect. This should be done inside the `setup_partials` method.  It's not illegal to do it in `setup`, but there are some cases where it must be called in `setup_partials`, for example the case where a component has dynamically sized variables. `setup_partials` iscalled after all shapes, even dynamic ones, are known, so it works on all cases.  For the sake of consistency then, it's best to always call `declare_partials` in `setup_partials`. In this example, not all the outputs depend on all the inputs, and you'll see that if you look at the derivative declarations. Any partial that is not declared is assumed to be zero. You may declare all the partials in just one line as follows (see the documentation on [specifying partials](../../features/core_features/working_with_derivatives/specifying_partials.ipynb) for more details):\n",
    "\n",
    "```\n",
    "self.declare_partials('*', '*')\n",
    "```\n",
    "\n",
    "Declaring the partials in this fashion, however, indicates to OpenMDAO that all the partials are nonzero.\n",
    "While you may save yourself a few lines of code using this method, the line savings could come at the expense of performance. Generally, it is better to be more specific, and declare only the nonzero partials.\n",
    "\n",
    "```{important}\n",
    "There are a few more options to `declare_partials` that are worth taking a look at. There is support for when your derivatives are constant, and there is support for specifying derivatives in a sparse AIJ format. The full details can be found in the documentation on [specifying partials](../../features/core_features/working_with_derivatives/specifying_partials.ipynb).\n",
    "```\n",
    "\n",
    "After you declare the nonzero partial derivatives, you need to implement the `compute_partials` method to perform the actual derivative computations. OpenMDAO will call this method whenever it needs to work with the partial derivatives. The values are stored in the Jacobian object, `J`, and get used in the linear solutions that are necessary to compute model-level total derivatives. This API results in the assembly of a Jacobian matrix in memory. The `compute_partials` API is the most appropriate way to declare derivatives in the vast majority of circumstances, and you should use it unless you have a good reason not to.\n",
    "\n",
    "## Providing Derivatives Using the Matrix-Free API\n",
    "\n",
    "Sometimes you don't want to assemble the full partial-derivative Jacobian of your component in memory.\n",
    "The reasons why you might not want this are beyond the scope of this tutorial. For now, let's assume that if matrix assembly won't work for your application, that you are likely already well aware of this issue. So if you can't imagine why you would want to use a matrix-free API, you may disregard the following link. If you do need to work matrix-free, there is a `compute_jacvec_product` API, examples of which can be found in the feature document for [ExplicitComponent](../../features/core_features/working_with_components/explicit_component.ipynb).\n",
    "\n",
    "\n",
    "## How Do I Know If My Derivatives Are Correct?\n",
    "\n",
    "It is really important, if you are going to provide analytic derivatives, that you make sure they are correct.\n",
    "It is hard to overstate the importance of accurate derivatives in the convergence of analysis and optimization problems. OpenMDAO provides a helper function to make it easier to verify your partial derivatives. Any time you implement analytic derivatives, or change the nonlinear equations of your analysis, you should check your partial derivatives this way."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1b8bcc57",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:40:15.460953Z",
     "iopub.status.busy": "2026-10-02T14:40:15.460641Z",
     "iopub.status.idle": "2026-10-02T14:40:17.206194Z",
     "shell.execute_reply": "2026-10-02T14:40:17.205465Z"
    },
    "papermill": {
     "duration": 1.747652,
     "end_time": "2026-10-02T14:40:17.206862+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:15.459210+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952017.174899] [runnervm8df0l:5694 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55e4d89a04c0 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",
      "[1790952017.175160] [runnervm8df0l:5694 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:05694] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">---------------------------------------------------------------------\n",
       "Component: ActuatorDisc '<span style=\"color: #00ffff; text-decoration-color: #00ffff; font-weight: bold\">a_disk</span>'\n",
       "---------------------------------------------------------------------\n",
       "\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| 'of' variable | 'wrt' variable | calc val @ max viol | fd val @ max viol | (calc-fd) - (a + r*fd) | error desc        |\n",
       "+===============+================+=====================+===================+========================+===================+\n",
       "| Cp            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Cp            | Vu             |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Cp            | a              |       -1.000000e+00 |     -1.000002e+00 |           3.802334e-11 |  3.802334e-11&gt;TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Cp            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | Vu             |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | a              |        0.000000e+00 |     -4.000023e-06 |           3.000019e-06 |  3.000019e-06&gt;TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | Vu             |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | a              |       -2.000000e+01 |     -2.000000e+01 |        (-2.099942e-05) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | Vu             |        5.000000e-01 |      5.000000e-01 |        (-1.499626e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | a              |       -1.000000e+01 |     -1.000000e+01 |        (-1.099949e-05) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | Area           |        3.062500e+02 |      3.062500e+02 |        (-3.072442e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | Vu             |        9.187500e+02 |      9.187501e+02 |        (-8.288181e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | a              |       -6.125000e+03 |     -6.125012e+03 |           6.124310e-03 |  6.124310e-03&gt;TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | rho            |        2.500000e+03 |      2.500000e+03 |        (-2.500945e-03) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | Area           |        6.125000e+01 |      6.125000e+01 |        (-6.220569e-05) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | Vu             |        1.225000e+02 |      1.225000e+02 |        (-1.174997e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | a              |        0.000000e+00 |     -2.450065e-03 |           2.449063e-03 |  2.449063e-03&gt;TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | rho            |        5.000000e+02 |      5.000000e+02 |        (-5.009882e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "\n",
       "</pre>\n"
      ],
      "text/plain": [
       "---------------------------------------------------------------------\n",
       "Component: ActuatorDisc '\u001b[1;96ma_disk\u001b[0m'\n",
       "---------------------------------------------------------------------\n",
       "\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| 'of' variable | 'wrt' variable | calc val @ max viol | fd val @ max viol | (calc-fd) - (a + r*fd) | error desc        |\n",
       "+===============+================+=====================+===================+========================+===================+\n",
       "| Cp            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Cp            | Vu             |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Cp            | a              |       -1.000000e+00 |     -1.000002e+00 |           3.802334e-11 |  3.802334e-11>TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Cp            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | Vu             |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | a              |        0.000000e+00 |     -4.000023e-06 |           3.000019e-06 |  3.000019e-06>TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Ct            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | Vu             |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | a              |       -2.000000e+01 |     -2.000000e+01 |        (-2.099942e-05) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vd            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | Area           |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | Vu             |        5.000000e-01 |      5.000000e-01 |        (-1.499626e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | a              |       -1.000000e+01 |     -1.000000e+01 |        (-1.099949e-05) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| Vr            | rho            |        0.000000e+00 |      0.000000e+00 |        (-1.000000e-06) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | Area           |        3.062500e+02 |      3.062500e+02 |        (-3.072442e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | Vu             |        9.187500e+02 |      9.187501e+02 |        (-8.288181e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | a              |       -6.125000e+03 |     -6.125012e+03 |           6.124310e-03 |  6.124310e-03>TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| power         | rho            |        2.500000e+03 |      2.500000e+03 |        (-2.500945e-03) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | Area           |        6.125000e+01 |      6.125000e+01 |        (-6.220569e-05) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | Vu             |        1.225000e+02 |      1.225000e+02 |        (-1.174997e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | a              |        0.000000e+00 |     -2.450065e-03 |           2.449063e-03 |  2.449063e-03>TOL |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "| thrust        | rho            |        5.000000e+02 |      5.000000e+02 |        (-5.009882e-04) |                   |\n",
       "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
       "\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "####################################################################\n",
      "Sub Jacobian with Largest Tolerance Violation: ActuatorDisc 'a_disk'\n",
      "####################################################################\n",
      "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n",
      "| 'of' variable | 'wrt' variable | calc val @ max viol | fd val @ max viol | (calc-fd) - (a + r*fd) | error desc        |\n",
      "+===============+================+=====================+===================+========================+===================+\n",
      "| power         | a              |       -6.125000e+03 |     -6.125012e+03 |           6.124310e-03 |  6.124310e-03>TOL |\n",
      "+---------------+----------------+---------------------+-------------------+------------------------+-------------------+\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.test_examples.test_betz_limit import ActuatorDisc\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "prob.model.add_subsystem('a_disk', ActuatorDisc())\n",
    "\n",
    "prob.setup()\n",
    "prob.check_partials(compact_print=True, abs_err_tol=1.0E-6, rel_err_tol=1.0E-6);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f171196",
   "metadata": {
    "papermill": {
     "duration": 0.01588,
     "end_time": "2026-10-02T14:40:17.224501+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:17.208621+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "```{important}\n",
    "`check_partials` is **really** important when you're coding derivatives. It has some options to give you more detailed outputs for debugging and to let you limit which components get tested. You should look over the complete documentation on [check_partials](../../features/core_features/working_with_derivatives/basic_check_partials.ipynb) before you start doing heavy development with derivatives.\n",
    "```\n",
    "\n",
    "### Colorized Output\n",
    "If you have the Python package [rich](https://github.com/Textualize/rich) installed, any errors found when printing out check partials will be colorized.\n",
    "- Red numbers indicate errors.\n",
    "- When `compact_print=False`, any elements in the Jacobian not included in the sparsity pattern will be printed with a faded font. If nonzeros appear in these faded elements, they will be colored red to indicate an error.\n",
    "\n",
    "There is a lot of information there, but for now, just take a look at the `(calc-fd) - (a + r*fd)`.  This shows the absolute value between the calculated jacobian and the finite differenced jacobian `(calc-fd)`, minus the sum of the absolute tolerance and the relative tolerance times the baseline value. In short, this expression tests the accuracy of the derivative in a way that naturally shifts from checking the relative tolerance to the absolute tolerance when the nominal value is near zero. Here, all the numbers are really small, and that's what you want to see. It's rare, except for linear functions, that the finite difference and analytic derivatives will match exactly, but they should be pretty close."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3518db9",
   "metadata": {
    "papermill": {
     "duration": 0.005115,
     "end_time": "2026-10-02T14:40:17.230861+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:40:17.225746+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py312_jup",
   "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"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 15.896991,
   "end_time": "2026-10-02T14:40:17.848458+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/advanced_user_guide/analytic_derivatives/partial_derivs_explicit.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/advanced_user_guide/analytic_derivatives/partial_derivs_explicit.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:40:01.951467+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}