{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc559df2",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output",
     "active-ipynb"
    ]
   },
   "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": "code",
   "execution_count": null,
   "id": "0907ee01",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "from openmdao.api import clean_outputs\n",
    "\n",
    "clean_outputs(prompt=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ecca6536",
   "metadata": {},
   "source": [
    "# Problem Recording\n",
    "\n",
    "You might also want to attach a recorder to the `Problem` itself. This allows you to record an arbitrary case at a point of your choosing. This feature can be useful if you only record a limited number of variables during the run but would like to see a more complete list of values after the run.\n",
    "\n",
    "The options are a subset of those for driver recording."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c16224f0",
   "metadata": {
    "scrolled": true,
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "om.show_options_table(\"openmdao.core.problem.Problem\", options_dict=\"recording_options\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ace496d9",
   "metadata": {},
   "source": [
    "```{note}\n",
    "Note that the `excludes` option takes precedence over the `includes` option.\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c4cbfcd",
   "metadata": {},
   "source": [
    "## Problem Recording Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ee6d354",
   "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_src90\", get_code(\"openmdao.test_suite.components.sellar_feature.SellarDerivatives\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "853e3fd4",
   "metadata": {},
   "source": [
    ":::{Admonition} `SellarDerivatives` class definition \n",
    ":class: dropdown\n",
    "\n",
    "{glue:}`code_src90`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "427bc212",
   "metadata": {},
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.components.sellar_feature import SellarDerivatives\n",
    "\n",
    "import numpy as np\n",
    "\n",
    "model = SellarDerivatives()\n",
    "\n",
    "model.nonlinear_solver = om.NonlinearBlockGS()\n",
    "model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "\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 = om.ScipyOptimizeDriver(optimizer='SLSQP', tol=1e-9)\n",
    "\n",
    "prob = om.Problem(model, driver)\n",
    "\n",
    "prob.add_recorder(om.SqliteRecorder(\"cases.sql\"))\n",
    "\n",
    "prob.recording_options['includes'] = []\n",
    "prob.recording_options['record_objectives'] = True\n",
    "prob.recording_options['record_constraints'] = True\n",
    "prob.recording_options['record_desvars'] = True\n",
    "\n",
    "prob.setup()\n",
    "prob.run_driver()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "542f463e",
   "metadata": {},
   "outputs": [],
   "source": [
    "prob.record('final')\n",
    "prob.cleanup()\n",
    "\n",
    "cr = om.CaseReader(prob.get_outputs_dir() / \"cases.sql\")\n",
    "\n",
    "# get list of cases recorded on problem\n",
    "problem_cases = cr.list_cases('problem')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41ccd2c9",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert problem_cases == ['final']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39d07a9c",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# get list of output variables recorded on problem\n",
    "cr.list_source_vars('problem')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "06261b04",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "problem_vars = cr.list_source_vars('problem', out_stream=None)\n",
    "assert sorted(problem_vars['outputs']) == ['con1', 'con2', 'obj', 'x', 'z']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "782af4f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# get the recorded case\n",
    "case = cr.get_case('final')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7063cdf4",
   "metadata": {},
   "outputs": [],
   "source": [
    "case.get_objectives()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40304d37",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "assert_near_equal(case.get_objectives()['obj'], 3.18339395, 1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4cf1c8c3",
   "metadata": {},
   "outputs": [],
   "source": [
    "case.get_design_vars()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef6dba7f",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "des_vars = case.get_design_vars()\n",
    "assert_near_equal(des_vars['z'], [1.97763888, 5.87897722e-15], 1e-8)\n",
    "assert_near_equal(des_vars['x'], 0., 1e-8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90f4387a",
   "metadata": {},
   "outputs": [],
   "source": [
    "case.get_constraints()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c7ada097",
   "metadata": {
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "constraints = case.get_constraints()\n",
    "assert_near_equal(constraints['con1'], 0, 1e-8)\n",
    "assert_near_equal(constraints['con2'], -20.24472223, 1e-8)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.11.4"
  },
  "orphan": true
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
