{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e0f011dc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:43:01.879619Z",
     "iopub.status.busy": "2026-10-02T14:43:01.879397Z",
     "iopub.status.idle": "2026-10-02T14:43:01.883563Z",
     "shell.execute_reply": "2026-10-02T14:43:01.883203Z"
    },
    "papermill": {
     "duration": 0.007615,
     "end_time": "2026-10-02T14:43:01.884586+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:01.876971+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": "8b44d684",
   "metadata": {
    "papermill": {
     "duration": 0.001186,
     "end_time": "2026-10-02T14:43:01.887462+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:01.886276+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# NearestNeighbor\n",
    "\n",
    "Surrogate model based on the N-Dimensional Interpolation library by Stephen Marone.\n",
    "\n",
    "Here is a simple example where the *NearestNeighbor* surrogate is used to approximate the output of a sinusoidal component."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "74ecc69e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:43:01.969215Z",
     "iopub.status.busy": "2026-10-02T14:43:01.969023Z",
     "iopub.status.idle": "2026-10-02T14:43:04.330136Z",
     "shell.execute_reply": "2026-10-02T14:43:04.329654Z"
    },
    "papermill": {
     "duration": 2.397222,
     "end_time": "2026-10-02T14:43:04.330733+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:01.933511+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952184.311357] [runnervm8df0l:7473 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55ed1698d530 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",
      "[1790952184.311614] [runnervm8df0l:7473 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "[0.4309673]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:07473] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "import openmdao.api as om\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "sin_mm = om.MetaModelUnStructuredComp()\n",
    "sin_mm.add_input('x', 2.1)\n",
    "sin_mm.add_output('f_x', 0., surrogate=om.NearestNeighbor(interpolant_type='linear'))\n",
    "\n",
    "prob.model.add_subsystem('sin_mm', sin_mm)\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "# train the surrogate and check predicted value\n",
    "sin_mm.options['train_x'] = np.linspace(0,10,20)\n",
    "sin_mm.options['train_f_x'] = .5*np.sin(sin_mm.options['train_x'])\n",
    "\n",
    "prob.set_val('sin_mm.x', 2.1)\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('sin_mm.f_x'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "fc21dab1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:43:04.334420Z",
     "iopub.status.busy": "2026-10-02T14:43:04.334180Z",
     "iopub.status.idle": "2026-10-02T14:43:04.339543Z",
     "shell.execute_reply": "2026-10-02T14:43:04.338489Z"
    },
    "papermill": {
     "duration": 0.007758,
     "end_time": "2026-10-02T14:43:04.340041+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.332283+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0014767724994455675)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "assert_near_equal(prob.get_val('sin_mm.f_x'), .5*np.sin(prob.get_val('sin_mm.x')), 2e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1de597c",
   "metadata": {
    "papermill": {
     "duration": 0.001225,
     "end_time": "2026-10-02T14:43:04.342553+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.341328+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## NearestNeighbor Options\n",
    "\n",
    "All options can be passed in as arguments or set later by accessing the *options* dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "bebe55a2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:43:04.346394Z",
     "iopub.status.busy": "2026-10-02T14:43:04.346253Z",
     "iopub.status.idle": "2026-10-02T14:43:04.350375Z",
     "shell.execute_reply": "2026-10-02T14:43:04.349637Z"
    },
    "papermill": {
     "duration": 0.007135,
     "end_time": "2026-10-02T14:43:04.350890+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.343755+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;\">interpolant_type</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rbf</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;linear&#x27;, &#x27;weighted&#x27;, &#x27;rbf&#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;\">Type of interpolant, must be &#x27;linear&#x27;, &#x27;weighted&#x27;, or &#x27;rbf&#x27;</td></tr>\n",
       "    </table>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "om.show_options_table(\"openmdao.surrogate_models.nearest_neighbor.NearestNeighbor\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0badfc1c",
   "metadata": {
    "papermill": {
     "duration": 0.000929,
     "end_time": "2026-10-02T14:43:04.352866+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.351937+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "Additional interpolant-specific options can be passed in as call arguments.\n",
    "\n",
    "## NearestNeighbor Constructor\n",
    "\n",
    "The call signature for the *NearestNeighbor* constructor is:\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.surrogate_models.nearest_neighbor.NearestNeighbor.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## NearestNeighbor Option Examples\n",
    "\n",
    "**interpolant_type**\n",
    "\n",
    "The NearestNeighbor surrogate allows you to choose from three different interpolant types.\n",
    "\n",
    "| Interpolant | Description |\n",
    "| --- | --- |\n",
    "| linear | Interpolates values by forming a hyperplane between the points closest to the prescribed inputs |\n",
    "| weighted | Computes the weights based on the distance and distance effect. |\n",
    "| rbf | Compactly Supported Radial Basis Function. (Default) |\n",
    "\n",
    "**rbf interpolator arguments**\n",
    "\n",
    "When the \"interpolant_type\" option is set to \"rbf\", there are some additional arguments that can be used to control the radial basis function interpolant.\n",
    "\n",
    "For example, here we use the rbf interpolant for our simple sine model and set the number of neighbors (\"num_neighbors\") to 3."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "a88677b1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:43:04.355588Z",
     "iopub.status.busy": "2026-10-02T14:43:04.355452Z",
     "iopub.status.idle": "2026-10-02T14:43:04.362739Z",
     "shell.execute_reply": "2026-10-02T14:43:04.361934Z"
    },
    "papermill": {
     "duration": 0.009366,
     "end_time": "2026-10-02T14:43:04.363253+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.353887+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.42963226]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "import openmdao.api as om\n",
    "\n",
    "prob = om.Problem()\n",
    "\n",
    "sin_mm = om.MetaModelUnStructuredComp()\n",
    "sin_mm.add_input('x', 2.1)\n",
    "sin_mm.add_output('f_x', 0., surrogate=om.NearestNeighbor(interpolant_type='rbf', num_neighbors=3))\n",
    "\n",
    "prob.model.add_subsystem('sin_mm', sin_mm)\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "# train the surrogate and check predicted value\n",
    "sin_mm.options['train_x'] = np.linspace(0,10,20)\n",
    "sin_mm.options['train_f_x'] = .5*np.sin(sin_mm.options['train_x'])\n",
    "\n",
    "prob.set_val('sin_mm.x', 2.1)\n",
    "\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('sin_mm.f_x'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "eebbed71",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:43:04.366413Z",
     "iopub.status.busy": "2026-10-02T14:43:04.366285Z",
     "iopub.status.idle": "2026-10-02T14:43:04.369325Z",
     "shell.execute_reply": "2026-10-02T14:43:04.368720Z"
    },
    "papermill": {
     "duration": 0.005169,
     "end_time": "2026-10-02T14:43:04.369812+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.364643+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.004569969886522734)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(prob.get_val('sin_mm.f_x'), .5*np.sin(prob.get_val('sin_mm.x')), 5e-3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d940f34",
   "metadata": {
    "papermill": {
     "duration": 0.001003,
     "end_time": "2026-10-02T14:43:04.371909+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:43:04.370906+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "\n",
    "The following parameters are available to be adjusted:\n",
    "\n",
    "**num_neighbors** (int)\n",
    "    \n",
    "The number of neighbors to use for interpolation.\n",
    "    \n",
    "**rbf_family** (int)\n",
    "    \n",
    "Specifies the order of the radial basis function to be used.\n",
    "  \n",
    " - -2 uses an 11th order\n",
    " - -1 uses a 9th order\n",
    " - any value from 0 to 4 uses an order equal to floor((dimensions-1)/2) + (3\\*comp) +1"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 3.663767,
   "end_time": "2026-10-02T14:43:04.887668+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/surrogates/nearestneighbor.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/surrogates/nearestneighbor.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:43:01.223901+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}