{
 "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": [
    "# Command Line Tools\n",
    "\n",
    "OpenMDAO has a number of command line tools that are available via the `openmdao`\n",
    "command.\n",
    "\n",
    "```{note}\n",
    "The `openmdao` sub-commands, as well as any other console scripts associated with OpenMDAO, will\n",
    "only be available if you have installed OpenMDAO using *pip*. See [Getting Started](../getting_started/getting_started.ipynb)\n",
    "```\n",
    "\n",
    "```{note}\n",
    "When using a command line tool on a script that takes its own command line arguments, those\n",
    "arguments must be placed after a `--` on the command line.  Anything to the right of the\n",
    "`--` will be ignored by the openmdao command line parser and passed on to the user script.\n",
    "For example: `openmdao n2 -o foo.html myscript.py -- -x --myarg=bar` would pass\n",
    "`-x` and `--myarg=bar` as args to `myscript.py`.\n",
    "```\n",
    "\n",
    "All available `openmdao` sub-commands can be shown using the following command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao -h "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get further info on any sub-command, follow the command with a *-h*.  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao n2 -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```{note}\n",
    "Several of the example commands below make use of the files `circuit.py` and `circle_opt.py`. These files are located in the openmdao/test_suite/scripts directory.\n",
    "```\n",
    "\n",
    "## Viewing and Checking Commands\n",
    "\n",
    "Usually these commands will exit after executing, rather than continuing to the end of the user's\n",
    "run script. This makes it convenient to view or check the configuration of a model in any\n",
    "run script without having to wait around for the entire script to run.\n",
    "\n",
    "\n",
    "### openmdao check\n",
    "\n",
    "The `openmdao check` command will perform a number of checks on a model and display\n",
    "errors, warnings, or informational messages describing what it finds. Some of the available\n",
    "checks are *unconnected_inputs*, which lists any input variables that are not connected, and\n",
    "*out_of_order*, which displays any systems that are being executed out-of-order.\n",
    "You can supply individual checks on the command line using *-c* args.  For example:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": [
     "remove-input"
    ]
   },
   "source": [
    "If you are in colab, the shell command will not find the file because it is a single notebook without the included file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao check -c cycles circuit.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Otherwise, a set of default checks will be done. To see lists of the available and default checks, run the following command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao check -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(om-command-n2)=\n",
    "### openmdao n2\n",
    "\n",
    "The `openmdao n2` command will generate an $N^2$ diagram of the model that is\n",
    "viewable in a browser, for example:\n",
    "\n",
    "```\n",
    "openmdao n2 circuit.py\n",
    "```\n",
    "\n",
    "will generate an $N^2$ diagram like the one below."
   ]
  },
  {
   "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_src93\", get_code(\"openmdao.test_suite.scripts.circuit_analysis.Circuit\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    ":::{Admonition} `Circuit` class definition \n",
    ":class: dropdown\n",
    "\n",
    "{glue:}`code_src93`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "import openmdao.api as om\n",
    "from openmdao.test_suite.scripts.circuit_analysis import Circuit\n",
    "\n",
    "p = om.Problem()\n",
    "model = p.model\n",
    "model.add_subsystem('circuit', Circuit())\n",
    "\n",
    "p.setup()\n",
    "\n",
    "om.n2(p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the test module happens to be part of a python package, then you can also use the dotted\n",
    "module pathname of the test module instead of the filename.\n",
    "\n",
    "A number of other openmdao commands, includng `view_connections` and `tree`, also support this\n",
    "functionality\n",
    "\n",
    "(om-command-view-connections)=\n",
    "### openmdao view_connections\n",
    "\n",
    "The `openmdao view_connections` command generates a table of connection information for all input and\n",
    "output variables in the model.  Its primary purpose is to help debug a model by making the following\n",
    "things easier:\n",
    "\n",
    "\n",
    "- Identifying unconnected inputs\n",
    "- Highlighting unit conversions or missing units\n",
    "- Identifying missing or unwanted implicit connections\n",
    "\n",
    "\n",
    "The table can be sorted by any column by clicking on the\n",
    "column header, and a column can be filtered by typing text into the 'filter column' field found\n",
    "at the top of each column.  Also, any column can be shown or hidden using the toggle buttons at\n",
    "the bottom of the table.  When input and output units differ, they are highlighted in\n",
    "red.  In the promoted input and output columns, variables that are promoted at some level in\n",
    "the model are shown in blue, while variables that are never promoted are shown in black.\n",
    "\n",
    "Below is an example of a connection viewer for a pycycle propulsor model obtained using the command:\n",
    "\n",
    "```\n",
    "openmdao view_connections -v propulsor.py\n",
    "```\n",
    "\n",
    "![An example of a connection viewer](images/view_connections.png)\n",
    "\n",
    "<div align=\"center\"><b>An example of a connection viewer</b></div>\n",
    "<br>\n",
    "\n",
    "By default the promoted names columns of both inputs and outputs are shown and their absolute\n",
    "names are hidden.\n",
    "\n",
    "Unconnected inputs can easily be identified by typing '[NO CONNECTION]' or '[', into\n",
    "the filter field of either the absolute or promoted *output* column.  Unconnected outputs can\n",
    "be shown similarly by typing '[NO CONNECTION]' or '[' into the filter field of either the absolute\n",
    "or promoted *input* column.\n",
    "\n",
    "When showing promoted output and promoted input columns, if the promoted output name equals the\n",
    "promoted input name, that means the connection is an implicit connection.  Otherwise the\n",
    "connection is explicit, meaning somewhere in the model there is an explicit call to `connect`\n",
    "that produced the connection.\n",
    "\n",
    "In OpenMDAO, multiple inputs can be promoted to the same name, and by sorting the promoted inputs\n",
    "column, all such inputs will be grouped together.  This can make it much easier to spot either\n",
    "missing or unwanted implicit connections.\n",
    "\n",
    "(om-command-scaling)=\n",
    "### openmdao scaling\n",
    "The `openmdao scaling` command generates tables of information for design variables, objectives,\n",
    "and constraints, as well as a viewer that shows magnitudes of subjacobians of the total jacobian.\n",
    "\n",
    "#### Design variable/objective/constraint tables\n",
    "\n",
    "Any of the columns in the design variable, objective, and constraint tables can be sorted by clicking on\n",
    "the header of the desired column.  Each row in a table corresponds to an individual design variable,\n",
    "objective, or constraint, and if that variable happens to be an array then the row can be expanded\n",
    "vertically using the \"+\" button on the far left to show a row for each entry in that array.  In\n",
    "the constraints table, if a constraint is linear it will have a green check mark in the \"linear\"\n",
    "column.\n",
    "\n",
    "\n",
    "#### Jacobian viewer\n",
    "\n",
    "The jacobian viewer displays magnitude information for each subjacobian of the total jacobian. It\n",
    "contains one column for each design variable and one row for each objective and constraint.  If there\n",
    "are linear constraints, the part of the total jacobian that depends on them will be displayed in\n",
    "a separate tab.  A detailed view of a given sub-jacobian can be see by left clicking on the corresponding\n",
    "cell in the total jacobian view.  It will open a new tab containing the detailed sub-jacobian view.\n",
    "The detailed sub-jacobian view can be closed by right clicking on the tab.\n",
    "\n",
    "Cells in both the top level and detailed sub-jacobian views will be colored based on the maximum\n",
    "absolute value found in that location.  If the location is known to be zero because a total coloring\n",
    "has been computed, it will be dark gray in color.  If the location happens to have a value of zero\n",
    "for some other reason, it will be colored light gray.  All other values will be displayed using a color\n",
    "map that goes from red at large values down to blue for small values.\n",
    "\n",
    "\n",
    "Below is an example of what the driver scaling tables and the jacobian view look like:\n",
    "\n",
    "![An example of driver scaling report tables](images/scaling_report_tables.png)\n",
    "\n",
    "<div align=\"center\"><b>An example of driver scaling report tables.</b></div>\n",
    "<br>\n",
    "\n",
    "![An example of driver scaling report jacobian view](images/scaling_report_jac.png)\n",
    "\n",
    "<div align=\"center\"><b>An example of driver scaling report jacobian view.</b></div>\n",
    "<br>\n",
    "\n",
    "#### openmdao tree\n",
    "\n",
    "The `openmdao tree` command prints an indented list of all systems in the model tree.  Each system's\n",
    "type and name are shown, along with their linear and nonlinear solvers if\n",
    "they differ from the defaults, which are LinearRunOnce and NonlinearRunOnce respectively.\n",
    "If the `-c` option is used, the tree will print in color if the terminal supports it and\n",
    "the *colorama* package is installed. If colors are used, implicit and explicit components will be\n",
    "displayed using different colors.\n",
    "\n",
    "The input and output sizes can also be displayed using the `--sizes` arg, and the `--approx` arg\n",
    "will display the approximation method and the number of approximated partials for systems that use\n",
    "approximated derivatives.\n",
    "\n",
    "The tree command also allows specific attributes and/or vector variables to be printed out along with their\n",
    "corresponding system in the tree using the `--attr` and `--var` args respectively.\n",
    "\n",
    "Here's an example of the tree output for a simple circuit model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao tree --sizes --approx circuit.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### openmdao summary\n",
    "\n",
    "The `openmdao summary` command prints a high level summary of the model.  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao summary circle_opt.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### openmdao cite\n",
    "\n",
    "The `openmdao cite` command prints citations for any classes in the model that have them.\n",
    "It supports optional `-c` arguments to allow you to limit displayed citations to\n",
    "only those belonging to a particular class or group of classes.  By default, all citations for\n",
    "any class used in the problem will be displayed. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao cite circuit.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Profiling and Tracing Commands\n",
    "\n",
    "The following commands perform profiling or tracing on a run script, filtering their target\n",
    "functions based on pre-defined groups of functions that can be displayed using the `-h` command\n",
    "line option.  For example, here's the usage output for the `openmdao trace` command, which includes\n",
    "the function groups available at the time of this writing:\n",
    "\n",
    "```\n",
    "usage: openmdao trace [-h] [-g METHODS] [-v] file\n",
    "\n",
    "positional arguments:\n",
    "  file                  Python file to be traced.\n",
    "\n",
    "optional arguments:\n",
    "  -h, --help            show this help message and exit\n",
    "  -g METHODS, --group METHODS\n",
    "                        Determines which group of methods will be traced.\n",
    "                        Default is \"openmdao\". Options are: ['dataflow',\n",
    "                        'linear', 'mpi', 'openmdao', 'openmdao_all', 'setup']\n",
    "  -v, --verbose         Show function locals and return values.\n",
    "\n",
    "```\n",
    "\n",
    "### openmdao iprof\n",
    "\n",
    "The `openmdao iprof` command will display an icicle plot showing the time elapsed in all of the target\n",
    "methods corresponding to each object instance that they were called on.  For more details, see\n",
    "[Instance-based Profiling](../features/debugging/profiling/inst_profile.ipynb).\n",
    "\n",
    "\n",
    "\n",
    "### openmdao iprof_totals\n",
    "\n",
    "The `openmdao iprof_totals` command performs the same profiling as `openmdao iprof`, but it outputs a simple,\n",
    "text-based summary of the total time spent in each method.  The [Instance-based Profiling](../features/debugging/profiling/inst_profile.ipynb) section contains more details.\n",
    "\n",
    "### openmdao trace\n",
    "\n",
    "The `openmdao trace` command prints a call trace for a specified set of functions.  Optionally it can\n",
    "display values of function locals and return values.  For more detail, see [Instance-based Call Tracing](../features/debugging/profiling/inst_call_tracing.ipynb).\n",
    "\n",
    "\n",
    "Memory Profiling\n",
    "\n",
    "### openmdao mem\n",
    "\n",
    "The `openmdao mem` command profiles the memory usage of python functions.  For more detail,\n",
    "see [Memory Profiling](../features/debugging/profiling/inst_mem_profile.ipynb).\n",
    "\n",
    "### openmdao mempost\n",
    "\n",
    "The `openmdao mempost` postprocesses the raw memory dump file generated by `openmdao mem`.\n",
    "For more detail, see [Memory Profiling](../features/debugging/profiling/inst_mem_profile.ipynb).\n",
    "\n",
    "\n",
    "## Other Commands\n",
    "\n",
    "### openmdao call_tree\n",
    "\n",
    "The `openmdao call_tree` command takes the full module path of a class method and displays the\n",
    "call tree for that method.  It's purpose is to show which class 'owns' the specified method\n",
    "call and any other 'self.*' methods that it calls. Note that it shows all of the methods called,\n",
    "regardless of the result of conditionals within any function, so the displayed tree does not\n",
    "necessarily represent a trace of the function as it executes.  The functions are ordered top to\n",
    "bottom as they are encountered in the source code, and a given subfunction is only displayed\n",
    "once within a given function, even if it is actually called in multiple places within the function.\n",
    "Here's an example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao call_tree openmdao.api.LinearBlockGS.solve"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(ref-scaffold)=\n",
    "### openmdao scaffold\n",
    "\n",
    "The `openmdao scaffold` command generates simple scaffolding, or 'skeleton' code for\n",
    "a class that inherits from an allowed OpenMDAO base class.  The allowed base classes are shown as\n",
    "part of the description of the `--base` arg below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao scaffold -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition, the command will generate the scaffolding for a simple\n",
    "test file for that class, and if the `--package` option is used, it will generate the directory\n",
    "structure for a simple installable python package and will declare an entry point in the\n",
    "`setup.py` file so that the given class can be discoverable as an OpenMDAO plugin when installed.\n",
    "\n",
    "To build scaffolding for an OpenMDAO command line tool plugin, use the `--cmd` option.\n",
    "\n",
    "(list-installed)=\n",
    "### openmdao list_installed\n",
    "\n",
    "The `openmdao list_installed` command lists installed classes of the specified type(s).\n",
    "Its options are shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao list_installed -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, installed types from all installed packages are shown, but the output can be filtered\n",
    "by the use of the `-i` option to include only specified packages, or the `-x` option\n",
    "to exclude specified packages.\n",
    "\n",
    "For example, to show only those linear and nonlinear solver types that are part of the `openmdao`\n",
    "package, do the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao list_installed lin_solver nl_solver -i openmdao"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly, to hide all of the built-in (openmdao) solver types and only see installed plugin\n",
    "solver types, do the following.\n",
    "\n",
    "```\n",
    "openmdao list_installed lin_solver nl_solver -x openmdao\n",
    "```\n",
    "\n",
    "### openmdao find_plugins\n",
    "\n",
    "The `openmdao find_plugins` command finds github repositories containing openmdao plugins.\n",
    "Its options are shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao find_plugins -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One example of its use would be to display any github repositories containing openmdao command\n",
    "line tools.  At the time this documentation was created, the following repositories were found:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao find_plugins command"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(compute-entry-points)=\n",
    "### openmdao compute_entry_points\n",
    "\n",
    "The `openmdao compute_entry_points` command lists entry point groups and entry points for\n",
    "any openmdao compatible classes, e.g., Component, Group, etc., that it finds within a given\n",
    "python package. Its options are shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!openmdao compute_entry_points -h"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For example, to show all of the potential openmdao entry point groups and entry points for an\n",
    "installed python package called `mypackage`, you would do the following:\n",
    "\n",
    "```\n",
    "openmdao compute_entry_points mypackage\n",
    "```\n",
    "\n",
    "The entry point information will be printed in a form that can easily be pasted into the\n",
    "`setup.py` file for the specified package.\n",
    "\n",
    "## Using Commands under MPI\n",
    "\n",
    "In general, usage of openmdao subcommands under MPI is the same as usual, except the command will\n",
    "be preceded by `mpirun -n <num_procs>`.  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!mpirun -n 2 openmdao summary multipoint_beam_opt.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "============== Problem Summary ============\n",
    "Groups:               4\n",
    "Components:          10\n",
    "Max tree depth:       3\n",
    "\n",
    "Design variables:            1   Total size:        5\n",
    "\n",
    "Nonlinear Constraints:       1   Total size:        1\n",
    "    equality:                1                      1\n",
    "    inequality:              0                      0\n",
    "\n",
    "Linear Constraints:          0   Total size:        0\n",
    "    equality:                0                      0\n",
    "    inequality:              0                      0\n",
    "\n",
    "Objectives:                  1   Total size:        1\n",
    "\n",
    "Input variables:            10   Total size:     1961\n",
    "Output variables:           10   Total size:     1117\n",
    "\n",
    "Total connections: 10   Total transfer data size: 1961\n",
    "\n",
    "Driver type: ScipyOptimizeDriver\n",
    "Linear Solvers: [LinearRunOnce x 4]\n",
    "Nonlinear Solvers: [NonlinearRunOnce x 4]\n",
    "```"
   ]
  }
 ],
 "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
}
