{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "525f6895",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:39.383603Z",
     "iopub.status.busy": "2026-10-02T14:41:39.383372Z",
     "iopub.status.idle": "2026-10-02T14:41:39.388369Z",
     "shell.execute_reply": "2026-10-02T14:41:39.387670Z"
    },
    "papermill": {
     "duration": 0.00808,
     "end_time": "2026-10-02T14:41:39.388937+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:39.380857+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": "5ef070de",
   "metadata": {
    "papermill": {
     "duration": 0.001438,
     "end_time": "2026-10-02T14:41:39.391811+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:39.390373+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# MultiFiMetaModelUnStructuredComp\n",
    "\n",
    "`MultiFiMetaModelUnStructuredComp` is a component that allows you to create a surrogate model where\n",
    "the training data has been gathered from sources with multiple levels of fidelity. This approach\n",
    "can be beneficial when a high-fidelity model is expensive to evaluate but a low-fidelity model\n",
    "exists that can be evaluated more efficiently at the cost of some accuracy; the main benefit comes\n",
    "from replacing some of the expensive evaluation points with a larger set of cheaper points while\n",
    "maintaining confidence in the overall prediction.\n",
    "\n",
    "`MultiFiMetaModelUnStructuredComp` inherits from [MetaModelUnStructuredComp](metamodelunstructured_comp), so its interface and\n",
    "usage are mostly the same. However, it does not use the same SurrogateModels. The only available\n",
    "SurrogateModel is the `MultiFiCoKrigingSurrogate`, which implements the Multi-Fidelity Co-Kriging\n",
    "method as found in Scikit-Learn.\n",
    "\n",
    "## MultiFiMetaModelUnStructuredComp Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e2298ca2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:39.394653Z",
     "iopub.status.busy": "2026-10-02T14:41:39.394476Z",
     "iopub.status.idle": "2026-10-02T14:41:40.727179Z",
     "shell.execute_reply": "2026-10-02T14:41:40.726523Z"
    },
    "papermill": {
     "duration": 1.334791,
     "end_time": "2026-10-02T14:41:40.727653+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:39.392862+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;\">default_surrogate</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;SurrogateModel&#x27;, &#x27;NoneType&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Surrogate that will be used for all outputs that don&#x27;t have a specific surrogate assigned to them.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">derivs_method</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;jax&#x27;, &#x27;cs&#x27;, &#x27;fd&#x27;, None]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">The method to use for computing derivatives</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">distributed</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, set all variables in this component as distributed across multiple processes</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">nfi</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 levels of fidelity.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">run_root_only</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, call compute, compute_partials, linearize, apply_linear, apply_nonlinear, solve_linear, solve_nonlinear, and compute_jacvec_product only on rank 0 and broadcast the results to the other ranks.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">use_jit</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, attempt to use jit on compute_primal, assuming jax or some other AD package capable of jitting is active.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">vec_size</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Number of points that will be simultaneously predicted by the surrogate.</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.multifi_meta_model_unstructured_comp.MultiFiMetaModelUnStructuredComp\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44e3aa79",
   "metadata": {
    "papermill": {
     "duration": 0.000862,
     "end_time": "2026-10-02T14:41:40.729655+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:40.728793+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## MultiFiMetaModelUnStructuredComp Constructor\n",
    "\n",
    "The call signature for the `MultiFiMetaModelUnStructuredComp` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.components.multifi_meta_model_unstructured_comp.MultiFiMetaModelUnStructuredComp.__init__()\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## Simple Example\n",
    "\n",
    "The following example shows a `MultiFiMetaModelUnStructuredComp` used to model the 2D Branin\n",
    "function, where the output is a function of two inputs, and we have pre-computed the training\n",
    "point location and values at a variety of points using models with two different fidelity\n",
    "levels. Adding an input or output named 'x' spawns entries in the \"options\" dictionary where the\n",
    "training data can be specified. The naming convention is 'train_y' for the highest fidelity, and\n",
    "'train_y_fi2' for the lowest fidelity level (or in the case of more than 2 fidelity levels, the\n",
    "next highest level.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "24290919",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:40.732090Z",
     "iopub.status.busy": "2026-10-02T14:41:40.731800Z",
     "iopub.status.idle": "2026-10-02T14:41:42.400448Z",
     "shell.execute_reply": "2026-10-02T14:41:42.399399Z"
    },
    "papermill": {
     "duration": 1.67051,
     "end_time": "2026-10-02T14:41:42.400963+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:40.730453+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952101.934874] [runnervm8df0l:6745 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x557da2811430 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",
      "[1790952101.935115] [runnervm8df0l:6745 :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:06745] pml_ucx.c:313  Error: Failed to create UCP worker\n",
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/openmdao/components/meta_model_unstructured_comp.py:306: DerivativesWarning:Because the MetaModelUnStructuredComp 'mm' uses a surrogate which does not define a linearize method,\n",
      "OpenMDAO will use finite differences to compute derivatives. Some of the derivatives will be computed\n",
      "using default finite difference options because they were not explicitly declared.\n",
      "The derivatives computed using the defaults are:\n",
      "    mm.y, mm.x\n",
      "\n",
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/openmdao/surrogate_models/multifi_cokriging.py:625: OptimizeWarning: Unknown solver options: rhoend\n",
      "  sol = minimize(rlf_transform, x0, method='COBYLA',\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[26.26678588]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/openmdao/surrogate_models/multifi_cokriging.py:731: LinAlgWarning: An ill-conditioned matrix detected: slice 0 has rcond = 5.177184471970157e-19.\n",
      "  i] * linalg.inv(np.dot(G.T, G))[:self.q[i], :self.q[i]]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "mm = om.MultiFiMetaModelUnStructuredComp(nfi=2)\n",
    "mm.add_input('x', np.zeros((1, 2)))\n",
    "mm.add_output('y', np.zeros((1, )))\n",
    "\n",
    "# Surrrogate model that implements the multifidelity cokriging method.\n",
    "mm.options['default_surrogate'] = om.MultiFiCoKrigingSurrogate(normalize=False)\n",
    "\n",
    "prob = om.Problem()\n",
    "prob.model.add_subsystem('mm', mm)\n",
    "\n",
    "prob.setup()\n",
    "\n",
    "x_hifi = np.array([[ 0.13073587,  0.24909577],  # expensive (hifi) doe\n",
    "                   [ 0.91915571,  0.4735261 ],\n",
    "                   [ 0.75830543,  0.13321705],\n",
    "                   [ 0.51760477,  0.34594101],\n",
    "                   [ 0.03531219,  0.77765831],\n",
    "                   [ 0.27249206,  0.5306115 ],\n",
    "                   [ 0.62762489,  0.65778471],\n",
    "                   [ 0.3914706 ,  0.09852519],\n",
    "                   [ 0.86565585,  0.85350002],\n",
    "                   [ 0.40806563,  0.91465314]])\n",
    "\n",
    "y_hifi = np.array([69.22687251161716,\n",
    "                   28.427292491743817,\n",
    "                   20.36175030334259,\n",
    "                   7.840766670948326,\n",
    "                   23.950783505007422,\n",
    "                   16.0326610719367,\n",
    "                   77.32264403894713,\n",
    "                   26.625242780670835,\n",
    "                   135.85615334210993,\n",
    "                   101.43980212355875])\n",
    "\n",
    "x_lofi = np.array([[ 0.91430235,  0.17029894],  # cheap (lowfi) doe\n",
    "                   [ 0.99329651,  0.76431519],\n",
    "                   [ 0.2012252 ,  0.35006032],\n",
    "                   [ 0.61707854,  0.90210676],\n",
    "                   [ 0.15113004,  0.0133355 ],\n",
    "                   [ 0.07108082,  0.55344447],\n",
    "                   [ 0.4483159 ,  0.52182902],\n",
    "                   [ 0.5926638 ,  0.06595122],\n",
    "                   [ 0.66305449,  0.48579608],\n",
    "                   [ 0.47965045,  0.7407793 ],\n",
    "                   [ 0.13073587,  0.24909577],  # notice hifi doe inclusion\n",
    "                   [ 0.91915571,  0.4735261 ],\n",
    "                   [ 0.75830543,  0.13321705],\n",
    "                   [ 0.51760477,  0.34594101],\n",
    "                   [ 0.03531219,  0.77765831],\n",
    "                   [ 0.27249206,  0.5306115 ],\n",
    "                   [ 0.62762489,  0.65778471],\n",
    "                   [ 0.3914706 ,  0.09852519],\n",
    "                   [ 0.86565585,  0.85350002],\n",
    "                   [ 0.40806563,  0.91465314]])\n",
    "\n",
    "y_lofi = list([18.204898470295255,\n",
    "               107.66640600958577,\n",
    "               46.11717344625053,\n",
    "               186.002239934648,\n",
    "               135.12480249921992,\n",
    "               65.3605467926758,\n",
    "               51.72316385370553,\n",
    "               15.541873662737451,\n",
    "               72.77648156410065,\n",
    "               100.33324800434931,\n",
    "               86.69974561161716,\n",
    "               52.63307549174382,\n",
    "               34.358261803342586,\n",
    "               28.218996970948325,\n",
    "               57.280532805007425,\n",
    "               41.9510060719367,\n",
    "               107.05618533894713,\n",
    "               39.580998480670836,\n",
    "               171.46115394210995,\n",
    "               138.87939632355875])\n",
    "\n",
    "mm.options['train_x'] = x_hifi\n",
    "mm.options['train_y'] = y_hifi\n",
    "mm.options['train_x_fi2'] = x_lofi\n",
    "mm.options['train_y_fi2'] = y_lofi\n",
    "\n",
    "prob.set_val('mm.x', np.array([[2./3., 1./3.]]))\n",
    "prob.run_model()\n",
    "\n",
    "print(prob.get_val('mm.y'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "b3fddd3e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:41:42.405970Z",
     "iopub.status.busy": "2026-10-02T14:41:42.405819Z",
     "iopub.status.idle": "2026-10-02T14:41:42.409863Z",
     "shell.execute_reply": "2026-10-02T14:41:42.409146Z"
    },
    "papermill": {
     "duration": 0.008163,
     "end_time": "2026-10-02T14:41:42.410290+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:41:42.402127+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.00025841132911400976)"
      ]
     },
     "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('mm.y'), 26.26, tolerance=0.02)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 4.309204,
   "end_time": "2026-10-02T14:41:42.841825+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/components/multifi_metamodelunstructured_comp.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/components/multifi_metamodelunstructured_comp.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:41:38.532621+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}