{
 "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": [
    "# Basic Recording Example\n",
    "## Recording Terminology\n",
    "- **Case**: A Case stores a snapshot of all the variable values, metadata, and options of a model, or a sub-set of a model, at a particular point in time\n",
    "- **Case Recorder**: An OpenMDAO module used to store a snapshot of a model before, during, or after execution in an SQL file.\n",
    "- **Sources**: The OpenMDAO object responsible for recording the case. Can be `Problem`, `Driver` or a specific `System` or `Solver` identified by pathname.\n",
    "\n",
    "## Basic Recording Example\n",
    "\n",
    "Below is a basic example of how to create a recorder, attach it to a Problem, save the information,\n",
    "and retrieve the data from the recorder. `list_outputs` is a quick way to show all of your outputs\n",
    "and their values at the time the case was recorded, and should you need to isolate a single value OpenMDAO provides two ways to\n",
    "retrieve them. To view all the design variables, constraints, and\n",
    "objectives, you can use their methods like the example below.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "import os\n",
    "if os.path.exists('cases.sql'):\n",
    "    os.remove('cases.sql')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src8\", get_code(\"openmdao.test_suite.components.sellar_feature.SellarMDAWithUnits\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::{Admonition} `SellarMDAWithUnits` class definition \n",
    ":class: dropdown\n",
    "\n",
    "{glue:}`code_src8`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from openmdao.test_suite.components.sellar_feature import SellarMDAWithUnits\n",
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "# build the model\n",
    "prob = om.Problem(model=SellarMDAWithUnits())\n",
    "\n",
    "model = prob.model\n",
    "model.add_design_var('z', lower=np.array([-10.0, 0.0]), upper=np.array([10.0, 10.0]))\n",
    "model.add_design_var('x', lower=0.0, upper=10.0)\n",
    "model.add_objective('obj')\n",
    "model.add_constraint('con1', upper=0.0)\n",
    "model.add_constraint('con2', upper=0.0)\n",
    "\n",
    "# setup the optimization\n",
    "driver = prob.driver = om.ScipyOptimizeDriver(optimizer='SLSQP', tol=1e-9, disp=False)\n",
    "\n",
    "# Create a recorder variable\n",
    "recorder = om.SqliteRecorder('cases.sql')\n",
    "# Attach a recorder to the problem\n",
    "prob.add_recorder(recorder)\n",
    "\n",
    "prob.setup()\n",
    "prob.set_solver_print(0)\n",
    "prob.run_driver()\n",
    "prob.record(\"after_run_driver\")\n",
    "\n",
    "# Instantiate your CaseReader\n",
    "cr = om.CaseReader(\"cases.sql\")\n",
    "# Isolate \"problem\" as your source\n",
    "driver_cases = cr.list_cases('problem', out_stream=None)\n",
    "# Get the first case from the recorder\n",
    "case = cr.get_case('after_run_driver')\n",
    "\n",
    "# These options will give outputs as the model sees them\n",
    "# Gets value but will not convert units\n",
    "const = case['con1']\n",
    "print(const)\n",
    "\n",
    "# get_val can convert your result's units if desired\n",
    "const_K = case.get_val(\"con1\", units='K')\n",
    "\n",
    "print(const_K)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "assert_near_equal(const, -1.68550507e-10, 1e-3)\n",
    "assert_near_equal(const_K, 273.15, 1e-3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# list_outputs will list your model's outputs and return a list of them too\n",
    "print(case.list_outputs())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This code below will find all the objectives, design variables, and constraints that the\n",
    "# problem source contains\n",
    "objectives = case.get_objectives()\n",
    "print(objectives['obj'])\n",
    "\n",
    "design_vars = case.get_design_vars()\n",
    "print(design_vars['x'])\n",
    "\n",
    "constraints = case.get_constraints()\n",
    "print(constraints['con1'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(objectives['obj'], 3.18339395, 1e-4)\n",
    "assert_near_equal(design_vars['x'], 0., 1e-4)\n",
    "assert_near_equal(constraints['con1'], -1.68550507e-10, 1e-4)"
   ]
  }
 ],
 "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.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
