{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "b45a3e43",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:43.634926Z",
     "iopub.status.busy": "2026-10-02T14:41:43.634636Z",
     "iopub.status.idle": "2026-10-02T14:41:43.640786Z",
     "shell.execute_reply": "2026-10-02T14:41:43.640105Z"
    },
    "papermill": {
     "duration": 0.010491,
     "end_time": "2026-10-02T14:41:43.641432+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:43.630941+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": "c5c921dd",
   "metadata": {
    "papermill": {
     "duration": 0.002063,
     "end_time": "2026-10-02T14:41:43.645559+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:43.643496+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# SplineComp\n",
    "\n",
    "SplineComp allows you to represent a larger dimensional variable with a smaller dimensional variable by\n",
    "using an interpolation algorithm. This is useful for reducing the size of an optimization problem by\n",
    "decreasing the number of design variables it solves. The spatial distribution of the points, in both\n",
    "the original and interpolated spaces is typically uniform but other distributions can be used.\n",
    "\n",
    "```{Note}\n",
    "OpenMDAO contains two components that perform interpolation: `SplineComp` and `MetaModelStructuredComp`.\n",
    "While they provide access to mostly the same algorithms, their usage is subtly different.\n",
    "The fundamental differences between them are as follows:\n",
    "\n",
    "[MetaModelStructuredComp](metamodelstructured_comp) is used when you have a set of known data values y on a structured grid x and\n",
    "want to interpolate a new y value at a new x location that lies inside the grid. In this case, you\n",
    "generally start with a known set of fixed \"training\" values and their locations.\n",
    "\n",
    "`SplineComp` is used when you want to create a smooth curve with a large number of points, but you\n",
    "want to control the shape of the curve with a small number of control points. The x locations of\n",
    "the interpolated points (and where applicable, the control points) are fixed and known, but the\n",
    "y values at the control points vary as the curve shape is modified by an upstream connection.\n",
    "\n",
    "MetaModelStructuredComp can be used for multi-dimensional design spaces, whereas SplineComp is\n",
    "restricted to one dimension.\n",
    "```\n",
    "\n",
    "The following methods are available by setting the 'method' option:\n",
    "\n",
    "```{eval-rst}\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| Method        | Order  | Description                                                      |\n",
    "+===============+========+==================================================================+\n",
    "| slinear       | 1      | Basic linear interpolation                                       |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| lagrange2     | 2      | Second order Lagrange polynomial                                 |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| lagrange3     | 3      | Third order Lagrange polynomial                                  |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| akima         | 3      | Interpolation using Akima splines                                |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| cubic         | 3      | Cubic spline, with continuity of derivatives between segments    |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| bsplines      | var.   | BSplines, default order is 4.                                    |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| scipy_slinear | 1      | Scipy linear interpolation. Same as slinear, though slower       |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| scipy_cubic   | 3      | Scipy cubic interpolation. More accurate than cubic, but slower  |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "| scipy_quintic | 5      | Scipy quintic interpolation. Most accurate, but slowest          |\n",
    "+---------------+--------+------------------------------------------------------------------+\n",
    "```\n",
    "\n",
    "## SplineComp Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "5a9a1721",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:43.705886Z",
     "iopub.status.busy": "2026-10-02T14:41:43.705656Z",
     "iopub.status.idle": "2026-10-02T14:41:44.962467Z",
     "shell.execute_reply": "2026-10-02T14:41:44.962025Z"
    },
    "papermill": {
     "duration": 1.315687,
     "end_time": "2026-10-02T14:41:44.963273+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:43.647586+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;\">interp_options</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">{}</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;dict&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Dict contains the name and value of options specific to the chosen interpolation method.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">method</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">akima</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;slinear&#x27;, &#x27;lagrange2&#x27;, &#x27;lagrange3&#x27;, &#x27;cubic&#x27;, &#x27;akima&#x27;, &#x27;bsplines&#x27;, &#x27;scipy_cubic&#x27;, &#x27;scipy_slinear&#x27;, &#x27;scipy_quintic&#x27;]</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;\">Spline interpolation method to use for all outputs.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">num_cp</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;\">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 spline control points. Optional alternative to x_cp_val. Required for bsplines. If None, num_cp will be a linspace from 0 to 1.</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;\">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: #F3F3F3;\"><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 points to evaluate at once.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">x_cp_val</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;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;list&#x27;, &#x27;ndarray&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">List/array of x control point values, must be monotonically increasing. Optional alternative to num_cp. Not applicable for bsplines. </td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">x_interp_val</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">**Required**</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;list&#x27;, &#x27;ndarray&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">List/array of x interpolated point values.</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.spline_comp.SplineComp\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf5eb277",
   "metadata": {
    "papermill": {
     "duration": 0.001417,
     "end_time": "2026-10-02T14:41:44.966536+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:44.965119+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## SplineComp Constructor\n",
    "\n",
    "The call signature for the `SplineComp` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.components.spline_comp.SplineComp.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## SplineComp Basic Example\n",
    "\n",
    "In our example, we have a pre-generated curve that is described by a series of values `y_cp` at a\n",
    "sequence of locations `x_cp`, and we would like to interpolate new values at multiple locations\n",
    "between these points. We call these new fixed locations at which to interpolate: `x`. When we\n",
    "instantiate a `SplineComp`, we specify these `x_cp` and `x` locations as numpy arrays and pass\n",
    "them in as constructor keyword arguments. (Figure 1). Next we'll add our `y_cp` data in by\n",
    "calling the `add_spline` method and passing the `y_cp` values in as the keyword argument `y_cp_val` (Figure 2).\n",
    "`SplineComp` computes and outputs the `y_interp` values (Figure 3).\n",
    "\n",
    "![figure_1](images/figure_1.png)\n",
    "![figure_2](images/figure_2.png)\n",
    "![figure_3](images/figure_3.png)\n",
    "![figure_4](images/figure_4.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "42697d55",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:44.970127Z",
     "iopub.status.busy": "2026-10-02T14:41:44.969860Z",
     "iopub.status.idle": "2026-10-02T14:41:46.206826Z",
     "shell.execute_reply": "2026-10-02T14:41:46.206265Z"
    },
    "papermill": {
     "duration": 1.23955,
     "end_time": "2026-10-02T14:41:46.207432+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:44.967882+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952106.191863] [runnervm8df0l:6793 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55b450d933d0 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",
      "[1790952106.192105] [runnervm8df0l:6793 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "[[ 5.          7.20902005  9.21276849 10.81097162 11.80335574 12.1278001\n",
      "  12.35869145 12.58588536 12.81022332 13.03254681 13.25369732 13.47451633\n",
      "  13.69584534 13.91852582 14.14281484 14.36710105 14.59128625 14.81544619\n",
      "  15.03965664 15.26399335 15.48853209 15.7133486  15.93851866 16.16573502\n",
      "  16.39927111 16.63928669 16.8857123  17.1384785  17.39751585 17.66275489\n",
      "  17.93412619 18.21156029 18.49498776 18.78433915 19.07954501 19.38053589\n",
      "  19.68724235 19.99959495 20.31752423 20.64096076 20.96983509 21.37579297\n",
      "  21.94811407 22.66809748 23.51629844 24.47327219 25.51957398 26.63575905\n",
      "  27.80238264 29.        ]]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:06793] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0])\n",
    "ycp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "n = 50\n",
    "x = np.linspace(1.0, 12.0, n)\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "akima_option = {'delta_x': 0.1}\n",
    "comp = om.SplineComp(method='akima', x_cp_val=xcp, x_interp_val=x,\n",
    "                     interp_options=akima_option)\n",
    "\n",
    "prob.model.add_subsystem('akima1', comp)\n",
    "\n",
    "comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=ycp)\n",
    "\n",
    "prob.setup(force_alloc_complex=True)\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('akima1.y_val'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "eb6ae4b1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.212534Z",
     "iopub.status.busy": "2026-10-02T14:41:46.212392Z",
     "iopub.status.idle": "2026-10-02T14:41:46.216959Z",
     "shell.execute_reply": "2026-10-02T14:41:46.216223Z"
    },
    "papermill": {
     "duration": 0.007634,
     "end_time": "2026-10-02T14:41:46.217405+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.209771+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.6395847643649563e-10)"
      ]
     },
     "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('akima1.y_val'),\n",
    "                  np.array([[ 5.       ,  7.20902005,  9.21276849, 10.81097162, 11.80335574,\n",
    "                              12.1278001 , 12.35869145, 12.58588536, 12.81022332, 13.03254681,\n",
    "                              13.25369732, 13.47451633, 13.69584534, 13.91852582, 14.14281484,\n",
    "                              14.36710105, 14.59128625, 14.81544619, 15.03965664, 15.26399335,\n",
    "                              15.48853209, 15.7133486 , 15.93851866, 16.16573502, 16.39927111,\n",
    "                              16.63928669, 16.8857123 , 17.1384785 , 17.39751585, 17.66275489,\n",
    "                              17.93412619, 18.21156029, 18.49498776, 18.78433915, 19.07954501,\n",
    "                              19.38053589, 19.68724235, 19.99959495, 20.31752423, 20.64096076,\n",
    "                              20.96983509, 21.37579297, 21.94811407, 22.66809748, 23.51629844,\n",
    "                              24.47327219, 25.51957398, 26.63575905, 27.80238264, 29.        ]]),\n",
    "                  tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86f9aafd",
   "metadata": {
    "papermill": {
     "duration": 0.001874,
     "end_time": "2026-10-02T14:41:46.221317+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.219443+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## SplineComp Multiple Splines\n",
    "\n",
    "`SplineComp` supports multiple splines on a fixed `x_interp` grid. Below is an example of how a user can\n",
    "setup two splines on a fixed grid. To do this the user needs to pass in names to give to the component\n",
    "input and output. The initial values for `y_cp` can also be specified here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "aa24c6c7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.225883Z",
     "iopub.status.busy": "2026-10-02T14:41:46.225744Z",
     "iopub.status.idle": "2026-10-02T14:41:46.240366Z",
     "shell.execute_reply": "2026-10-02T14:41:46.239552Z"
    },
    "papermill": {
     "duration": 0.017513,
     "end_time": "2026-10-02T14:41:46.240827+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.223314+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "x_cp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0])\n",
    "y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "y_cp2 = np.array([1.0, 5.0, 7.0, 8.0, 13.0, 16.0])\n",
    "n = 50\n",
    "x = np.linspace(1.0, 12.0, n)\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x)\n",
    "prob.model.add_subsystem('akima1', comp)\n",
    "\n",
    "comp.add_spline(y_cp_name='ycp1', y_interp_name='y_val1', y_cp_val=y_cp)\n",
    "comp.add_spline(y_cp_name='ycp2', y_interp_name='y_val2', y_cp_val=y_cp2)\n",
    "\n",
    "prob.setup(force_alloc_complex=True)\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1d1999c",
   "metadata": {
    "papermill": {
     "duration": 0.001867,
     "end_time": "2026-10-02T14:41:46.244632+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.242765+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Specifying Options for 'akima'\n",
    "\n",
    "When you are using the 'akima' method, there are two akima-specific options that can be passed in to the\n",
    "`SplineComp` constructor.  The 'delta_x' option is used to define the radius of the smoothing interval\n",
    "that is used in the absolute values functions in the akima calculation in order to make their\n",
    "derivatives continuous.  This is set to zero by default, which effectively turns off the smoothing.\n",
    "The 'eps' option is used to define the value that triggers a division-by-zero\n",
    "safeguard; its default value is 1e-30."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "34ab77ed",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.249176Z",
     "iopub.status.busy": "2026-10-02T14:41:46.249043Z",
     "iopub.status.idle": "2026-10-02T14:41:46.258499Z",
     "shell.execute_reply": "2026-10-02T14:41:46.257826Z"
    },
    "papermill": {
     "duration": 0.012431,
     "end_time": "2026-10-02T14:41:46.258988+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.246557+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "x_cp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0])\n",
    "y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "\n",
    "n = 50\n",
    "x = np.linspace(1.0, 12.0, n)\n",
    "\n",
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "# Set options specific to akima\n",
    "akima_option = {'delta_x': 0.1, 'eps': 1e-30}\n",
    "\n",
    "comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x,\n",
    "                     interp_options=akima_option)\n",
    "\n",
    "prob.model.add_subsystem('atmosphere', comp)\n",
    "\n",
    "comp.add_spline(y_cp_name='alt_cp', y_interp_name='alt', y_cp_val=y_cp, y_units='kft')\n",
    "\n",
    "prob.setup(force_alloc_complex=True)\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb38df1c",
   "metadata": {
    "papermill": {
     "duration": 0.014122,
     "end_time": "2026-10-02T14:41:46.274995+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.260873+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Specifying Options for 'bsplines'\n",
    "\n",
    "When you use the 'bsplines' method, you can specify the bspline order by defining 'order' in an\n",
    "otherwise empty dictionary and passing it in as 'interp_options'.\n",
    "\n",
    "In addition, when using 'bsplines', you cannot specify the 'x_cp' locations because the bspline\n",
    "algorithm places them at fixed locations. The starting and ending control points are at the starting and ending interpolation points respectively. You can specify the number of control points using the 'num_cp' argument.\n",
    "You can also change the mapping of the control points by specifying the location of the first and/or last control point. This is done by defining 'x_cp_start' and/or 'x_cp_end' in the'interp_options' dictionary mentioned above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0f159067",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.279517Z",
     "iopub.status.busy": "2026-10-02T14:41:46.279381Z",
     "iopub.status.idle": "2026-10-02T14:41:46.286956Z",
     "shell.execute_reply": "2026-10-02T14:41:46.286271Z"
    },
    "papermill": {
     "duration": 0.010513,
     "end_time": "2026-10-02T14:41:46.287450+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.276937+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "prob = om.Problem()\n",
    "model = prob.model\n",
    "\n",
    "n_cp = 80\n",
    "n_point = 160\n",
    "\n",
    "t = np.linspace(0, 3.0*np.pi, n_cp)\n",
    "tt = np.linspace(0, 3.0*np.pi, n_point)\n",
    "x = np.sin(t)\n",
    "\n",
    "# Set options specific to bsplines\n",
    "bspline_options = {'order': 3}\n",
    "\n",
    "comp = om.SplineComp(method='bsplines', x_interp_val=tt, num_cp=n_cp,\n",
    "                    interp_options=bspline_options)\n",
    "\n",
    "prob.model.add_subsystem('interp', comp, promotes_inputs=[('h_cp', 'x')])\n",
    "\n",
    "comp.add_spline(y_cp_name='h_cp', y_interp_name='h', y_cp_val=x, y_units=None)\n",
    "\n",
    "prob.setup(force_alloc_complex=True)\n",
    "prob.set_val('x', x)\n",
    "prob.run_model()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d02b8af",
   "metadata": {
    "papermill": {
     "duration": 0.001892,
     "end_time": "2026-10-02T14:41:46.317641+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.315749+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## SplineComp Interpolation Distribution\n",
    "\n",
    "The `cell_centered` function takes the number of cells, and the start and end values, and returns a\n",
    "vector of points that lie at the center of those cells. The 'node_centered' function reproduces the\n",
    "functionality of numpy's linspace.  Finally, the `sine_distribution` function creates a sinusoidal\n",
    "distribution, in which points are clustered towards the ends. A 'phase' argument is also included,\n",
    "and a phase of pi/2.0 clusters the points in the center with fewer points on the ends.\n",
    "\n",
    "```{Note}\n",
    "We have included three different distribution functions for users to replicate functionality that used to be built-in to the individual akima and bsplines components.\n",
    "```\n",
    "\n",
    "```{eval-rst}\n",
    "    .. autofunction:: openmdao.utils.spline_distributions.sine_distribution\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "```{eval-rst}\n",
    "    .. autofunction:: openmdao.utils.spline_distributions.cell_centered\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "```{eval-rst}\n",
    "    .. autofunction:: openmdao.utils.spline_distributions.node_centered\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "Below is an example of `sine_distribution`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "ff9cfb36",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.322213Z",
     "iopub.status.busy": "2026-10-02T14:41:46.322087Z",
     "iopub.status.idle": "2026-10-02T14:41:46.330626Z",
     "shell.execute_reply": "2026-10-02T14:41:46.330019Z"
    },
    "papermill": {
     "duration": 0.011525,
     "end_time": "2026-10-02T14:41:46.331121+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.319596+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 5.          5.32381994  6.28062691  7.79410646  9.64169506 11.35166363\n",
      "  12.26525921 12.99152288 13.77257256 14.58710327 15.41289673 16.28341046\n",
      "  17.96032258 20.14140712 22.31181718 24.40891577 26.27368825 27.74068235\n",
      "  28.67782484 29.        ]]\n"
     ]
    }
   ],
   "source": [
    "x_cp = np.linspace(0., 1., 6)\n",
    "y_cp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "n = 20\n",
    "x = om.sine_distribution(20, start=0, end=1, phase=np.pi)\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "comp = om.SplineComp(method='akima', x_cp_val=x_cp, x_interp_val=x)\n",
    "prob.model.add_subsystem('akima1', comp)\n",
    "\n",
    "comp.add_spline(y_cp_name='ycp', y_interp_name='y_val', y_cp_val=y_cp)\n",
    "\n",
    "prob.setup(force_alloc_complex=True)\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('akima1.y_val'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "65466112",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.335809Z",
     "iopub.status.busy": "2026-10-02T14:41:46.335655Z",
     "iopub.status.idle": "2026-10-02T14:41:46.339062Z",
     "shell.execute_reply": "2026-10-02T14:41:46.338437Z"
    },
    "papermill": {
     "duration": 0.00637,
     "end_time": "2026-10-02T14:41:46.339504+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.333134+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.6095302077063916e-10)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('akima1.y_val'),\n",
    "                  np.array([[5.         , 5.32381994,  6.28062691 , 7.79410646 , 9.64169506, 11.35166363,\n",
    "                             12.26525921, 12.99152288, 13.77257256, 14.58710327, 15.41289673, 16.28341046,\n",
    "                             17.96032258, 20.14140712, 22.31181718, 24.40891577, 26.27368825, 27.74068235,\n",
    "                             28.67782484, 29.        ]]),\n",
    "                  tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "729c44bc",
   "metadata": {
    "papermill": {
     "duration": 0.001423,
     "end_time": "2026-10-02T14:41:46.342460+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.341037+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## Standalone Interface for Spline Evaluation\n",
    "\n",
    "The underlying interpolation algorithms can be used standalone (i.e., outside of the SplineComp) through the\n",
    "`InterpND` class. This can be useful for inclusion in another component. The following example shows how to\n",
    "create and evaluate a standalone Akima spline:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9166f13f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.346533Z",
     "iopub.status.busy": "2026-10-02T14:41:46.346364Z",
     "iopub.status.idle": "2026-10-02T14:41:46.358559Z",
     "shell.execute_reply": "2026-10-02T14:41:46.357845Z"
    },
    "papermill": {
     "duration": 0.014996,
     "end_time": "2026-10-02T14:41:46.359025+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.344029+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 5.          7.20902005  9.21276849 10.81097162 11.80335574 12.1278001\n",
      " 12.35869145 12.58588536 12.81022332 13.03254681 13.25369732 13.47451633\n",
      " 13.69584534 13.91852582 14.14281484 14.36710105 14.59128625 14.81544619\n",
      " 15.03965664 15.26399335 15.48853209 15.7133486  15.93851866 16.16573502\n",
      " 16.39927111 16.63928669 16.8857123  17.1384785  17.39751585 17.66275489\n",
      " 17.93412619 18.21156029 18.49498776 18.78433915 19.07954501 19.38053589\n",
      " 19.68724235 19.99959495 20.31752423 20.64096076 20.96983509 21.37579297\n",
      " 21.94811407 22.66809748 23.51629844 24.47327219 25.51957398 26.63575905\n",
      " 27.80238264 29.        ]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.components.interp_util.interp import InterpND\n",
    "\n",
    "xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0])\n",
    "ycp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "n = 50\n",
    "x = np.linspace(1.0, 12.0, n)\n",
    "\n",
    "interp = InterpND(method='akima', points=xcp, x_interp=x, delta_x=0.1)\n",
    "y = interp.evaluate_spline(ycp)\n",
    "\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "ca809565",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.362703Z",
     "iopub.status.busy": "2026-10-02T14:41:46.362567Z",
     "iopub.status.idle": "2026-10-02T14:41:46.365911Z",
     "shell.execute_reply": "2026-10-02T14:41:46.365369Z"
    },
    "papermill": {
     "duration": 0.006155,
     "end_time": "2026-10-02T14:41:46.366661+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.360506+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.6395847643649563e-10)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(y,\n",
    "                  np.array([ 5.       ,  7.20902005,  9.21276849, 10.81097162, 11.80335574,\n",
    "                             12.1278001 , 12.35869145, 12.58588536, 12.81022332, 13.03254681,\n",
    "                             13.25369732, 13.47451633, 13.69584534, 13.91852582, 14.14281484,\n",
    "                             14.36710105, 14.59128625, 14.81544619, 15.03965664, 15.26399335,\n",
    "                             15.48853209, 15.7133486 , 15.93851866, 16.16573502, 16.39927111,\n",
    "                             16.63928669, 16.8857123 , 17.1384785 , 17.39751585, 17.66275489,\n",
    "                             17.93412619, 18.21156029, 18.49498776, 18.78433915, 19.07954501,\n",
    "                             19.38053589, 19.68724235, 19.99959495, 20.31752423, 20.64096076,\n",
    "                             20.96983509, 21.37579297, 21.94811407, 22.66809748, 23.51629844,\n",
    "                             24.47327219, 25.51957398, 26.63575905, 27.80238264, 29.        ]),\n",
    "                  tolerance=1e-6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95350958",
   "metadata": {
    "papermill": {
     "duration": 0.001486,
     "end_time": "2026-10-02T14:41:46.369687+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.368201+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Similiarly, the following example shows how to create a bspline:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "9dd8675c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.373397Z",
     "iopub.status.busy": "2026-10-02T14:41:46.373264Z",
     "iopub.status.idle": "2026-10-02T14:41:46.377325Z",
     "shell.execute_reply": "2026-10-02T14:41:46.376621Z"
    },
    "papermill": {
     "duration": 0.00661,
     "end_time": "2026-10-02T14:41:46.377782+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.371172+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 5.          6.21958113  7.31225085  8.28604153  9.14898554  9.90911525\n",
      " 10.57446302 11.15306122 11.65294223 12.08213839 12.4486821  12.7606057\n",
      " 13.02594157 13.25272208 13.44897959 13.62274647 13.7820551  13.93461483\n",
      " 14.08438023 14.23288341 14.38161608 14.53206997 14.68573681 14.84410832\n",
      " 15.00867623 15.18093226 15.36236815 15.5544756  15.75874636 15.97667213\n",
      " 16.20974466 16.45945567 16.72729687 17.01478976 17.32524076 17.66472303\n",
      " 18.03954772 18.45602598 18.92046894 19.43918775 20.01849357 20.66469753\n",
      " 21.38411079 22.18304448 23.06780976 24.04471776 25.12007964 26.30020655\n",
      " 27.59140962 29.        ]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.components.interp_util.interp import InterpND\n",
    "\n",
    "xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0])\n",
    "ycp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "n = 50\n",
    "x = np.linspace(1.0, 12.0, n)\n",
    "\n",
    "interp = InterpND(method='bsplines', num_cp=6, x_interp=x)\n",
    "\n",
    "y = interp.evaluate_spline(ycp)\n",
    "\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9e1b5879",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.395451Z",
     "iopub.status.busy": "2026-10-02T14:41:46.395316Z",
     "iopub.status.idle": "2026-10-02T14:41:46.398838Z",
     "shell.execute_reply": "2026-10-02T14:41:46.398273Z"
    },
    "papermill": {
     "duration": 0.019905,
     "end_time": "2026-10-02T14:41:46.399264+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.379359+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.7278031392281835e-10)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(y,\n",
    "                  np.array([ 5.,          6.21958113,  7.31225085,  8.28604153,  9.14898554,  9.90911525,\n",
    "                            10.57446302, 11.15306122, 11.65294223, 12.08213839, 12.4486821,  12.7606057,\n",
    "                            13.02594157, 13.25272208, 13.44897959, 13.62274647, 13.7820551,  13.93461483,\n",
    "                            14.08438023, 14.23288341, 14.38161608, 14.53206997, 14.68573681, 14.84410832,\n",
    "                            15.00867623, 15.18093226, 15.36236815, 15.5544756,  15.75874636, 15.97667213,\n",
    "                            16.20974466, 16.45945567, 16.72729687, 17.01478976, 17.32524076, 17.66472303,\n",
    "                            18.03954772, 18.45602598, 18.92046894, 19.43918775, 20.01849357, 20.66469753,\n",
    "                            21.38411079, 22.18304448, 23.06780976, 24.04471776, 25.12007964, 26.30020655,\n",
    "                            27.59140962, 29.        ]),\n",
    "                  tolerance=1e-6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "664609d9",
   "metadata": {
    "papermill": {
     "duration": 0.001445,
     "end_time": "2026-10-02T14:41:46.402275+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.400830+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "You can also compute the derivative of the interpolated output with respect to the control point values by setting\n",
    "the \"compute_derivate\" argument to True:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "bfdda06c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.406054Z",
     "iopub.status.busy": "2026-10-02T14:41:46.405920Z",
     "iopub.status.idle": "2026-10-02T14:41:46.410118Z",
     "shell.execute_reply": "2026-10-02T14:41:46.409499Z"
    },
    "papermill": {
     "duration": 0.006862,
     "end_time": "2026-10-02T14:41:46.410648+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.403786+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00\n",
      "   0.00000000e+00  0.00000000e+00]\n",
      " [-1.86761492e-06  3.31278014e-02  1.05874907e+00 -9.18750000e-02\n",
      "   0.00000000e+00  0.00000000e+00]\n",
      " [ 0.00000000e+00  0.00000000e+00 -2.10964627e-01  1.19119941e+00\n",
      "   2.02602810e-02 -4.95062934e-04]\n",
      " [ 0.00000000e+00  0.00000000e+00 -2.64126732e-01  5.82784977e-01\n",
      "   6.83151998e-01 -1.81024253e-03]\n",
      " [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00\n",
      "   0.00000000e+00  1.00000000e+00]]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.components.interp_util.interp import InterpND\n",
    "\n",
    "xcp = np.array([1.0, 2.0, 4.0, 6.0, 10.0, 12.0])\n",
    "ycp = np.array([5.0, 12.0, 14.0, 16.0, 21.0, 29.0])\n",
    "n = 5\n",
    "x = np.linspace(1.0, 12.0, n)\n",
    "\n",
    "interp = InterpND(method='akima', points=xcp, x_interp=x, delta_x=0.1)\n",
    "y, dy_dycp = interp.evaluate_spline(ycp, compute_derivative=True)\n",
    "\n",
    "print(dy_dycp)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "c5303504",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:46.414656Z",
     "iopub.status.busy": "2026-10-02T14:41:46.414481Z",
     "iopub.status.idle": "2026-10-02T14:41:46.418385Z",
     "shell.execute_reply": "2026-10-02T14:41:46.417712Z"
    },
    "papermill": {
     "duration": 0.006528,
     "end_time": "2026-10-02T14:41:46.418834+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:46.412306+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(1.7416350929455544e-09)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(dy_dycp,\n",
    "                  np.array([[ 1.00000000e+00,  0.00000000e+00,  0.00000000e+00,\n",
    "                              0.00000000e+00,  0.00000000e+00,  0.00000000e+00],\n",
    "                            [-1.86761492e-06,  3.31278014e-02,  1.05874907e+00,\n",
    "                             -9.18750000e-02,  0.00000000e+00,  0.00000000e+00],\n",
    "                            [ 0.00000000e+00,  0.00000000e+00, -2.10964627e-01,\n",
    "                              1.19119941e+00,  2.02602810e-02, -4.95062934e-04],\n",
    "                            [ 0.00000000e+00,  0.00000000e+00, -2.64126732e-01,\n",
    "                              5.82784977e-01,  6.83151998e-01, -1.81024253e-03],\n",
    "                            [ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00,\n",
    "                              0.00000000e+00,  0.00000000e+00,  1.00000000e+00]]),\n",
    "                  tolerance=1e-6)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "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": 3.978394,
   "end_time": "2026-10-02T14:41:46.945269+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/components/spline_comp.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/components/spline_comp.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:41:42.966875+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}