{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "active-ipynb",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from openmdao.utils.notebook_utils import notebook_mode\n",
    "except ImportError:\n",
    "    !python -m pip install openmdao[notebooks]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "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": null,
   "metadata": {
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "om.show_options_table(\"openmdao.components.multifi_meta_model_unstructured_comp.MultiFiMetaModelUnStructuredComp\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "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": null,
   "metadata": {},
   "outputs": [],
   "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": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "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.8.5"
  },
  "orphan": true
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
