{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output",
     "active-ipynb"
    ]
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from openmdao.utils.notebook_utils import notebook_mode\n",
    "except ImportError:\n",
    "    !python -m pip install openmdao[notebooks]"
   ]
  },
  {
   "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",
    "import os\n",
    "if os.path.exists('cases.sql'):\n",
    "    os.remove('cases.sql')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Driver Recording"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A CaseRecorder is commonly attached to the problem’s Driver in order to gain insight into the convergence of the model as the driver finds a solution. By default, a recorder attached to a driver will record the design variables, constraints and objectives.\n",
    "\n",
    "The driver recorder is capable of capturing any values from any part of the model, not just the design variables, constraints, and objectives."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true,
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "om.show_options_table(\"openmdao.core.driver.Driver\", recording_options=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{note}\n",
    "Note that the `excludes` option takes precedence over the `includes` option.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Driver Recording Example\n",
    "\n",
    "In the example below, we first run a case while recording at the driver level. Then, we examine the objective, constraint, and design variable values at the last recorded case. Lastly, we print the full contents of the last case, including outputs from the problem that are not design variables, constraints, or objectives. \n",
    "\n",
    "Specifically, `y1` and `y2` are some of those intermediate outputs that are recorded due to the use of:\n",
    "\n",
    "`driver.recording_options['includes'] = ['*']`"
   ]
  },
  {
   "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_src89\", get_code(\"openmdao.test_suite.components.sellar.SellarDerivatives\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::{Admonition} `SellarDerivatives` class definition \n",
    ":class: dropdown\n",
    "\n",
    "{glue:}`code_src89`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.sellar import SellarDerivatives\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "prob = om.Problem(model=SellarDerivatives())\n",
    "\n",
    "model = prob.model\n",
    "model.add_design_var('z', lower=np.array([-10.0, 0.0]),\n",
    "                          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",
    "driver = prob.driver = om.ScipyOptimizeDriver(optimizer='SLSQP', tol=1e-9)\n",
    "driver.recording_options['includes'] = ['*']\n",
    "driver.recording_options['record_objectives'] = True\n",
    "driver.recording_options['record_constraints'] = True\n",
    "driver.recording_options['record_desvars'] = True\n",
    "driver.recording_options['record_inputs'] = True\n",
    "driver.recording_options['record_outputs'] = True\n",
    "driver.recording_options['record_residuals'] = True\n",
    "\n",
    "recorder = om.SqliteRecorder(\"cases.sql\")\n",
    "driver.add_recorder(recorder)\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prob.cleanup()\n",
    "cr = om.CaseReader(\"cases.sql\")\n",
    "driver_cases = cr.list_cases('driver')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert len(driver_cases) == 7"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "last_case = cr.get_case(driver_cases[-1])\n",
    "print(last_case)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_case.get_objectives()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(last_case.get_objectives()['obj'], 3.18339395, tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_case.get_design_vars()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "design_vars = last_case.get_design_vars()\n",
    "assert_near_equal(design_vars['x'], 0., tolerance=1e-8)\n",
    "assert_near_equal(design_vars['z'][0], 1.97763888, tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_case.get_constraints()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "constraints = last_case.get_constraints()\n",
    "assert_near_equal(constraints['con1'], 0, tolerance=1e-8)\n",
    "assert_near_equal(constraints['con2'], -20.24472223, tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_case.inputs['obj_cmp.x']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(last_case.inputs['obj_cmp.x'], 0, tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "last_case.outputs['z']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(last_case.outputs['z'][0], 1.97763888, tolerance=1e-8)\n",
    "assert_near_equal(last_case.outputs['z'][1], 0, tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_case.residuals['obj']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(last_case.residuals['obj'], 0, tolerance=1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "last_case['y1']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(last_case['y1'], 3.16, tolerance=1e-8)"
   ]
  }
 ],
 "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"
  },
  "orphan": true
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
