Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Birkhoff Docs #1088

Merged
merged 7 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/dymos_book/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ parts:
- file: examples/length_constrained_brachistochrone/length_constrained_brachistochrone
- file: examples/min_time_climb/min_time_climb
- file: examples/mountain_car/mountain_car
- file: examples/moon_landing/moon_landing
- file: examples/multi_phase_cannonball/multi_phase_cannonball
- file: examples/multibranch_trajectory/multibranch_trajectory
- file: examples/racecar/racecar
Expand Down
24 changes: 24 additions & 0 deletions docs/dymos_book/api/transcriptions_api.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,23 @@
"om.show_options_table(tx)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Birkhoff Options"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tx = dm.transcriptions.Birkhoff(num_nodes=5, grid_type='cgl')\n",
"om.show_options_table(tx)"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -122,6 +139,13 @@
"tx = dm.transcriptions.ExplicitShooting(num_segments=1, order=5)\n",
"om.show_options_table(tx)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
287 changes: 287 additions & 0 deletions docs/dymos_book/examples/moon_landing/moon_landing.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "8f7334f0",
"metadata": {
"tags": [
"active-ipynb",
"remove-input",
"remove-output"
]
},
"outputs": [],
"source": [
"# This cell is mandatory in all Dymos documentation notebooks.\n",
"missing_packages = []\n",
"try:\n",
" import openmdao.api as om\n",
"except ImportError:\n",
" if 'google.colab' in str(get_ipython()):\n",
" !python -m pip install openmdao[notebooks]\n",
" else:\n",
" missing_packages.append('openmdao')\n",
"try:\n",
" import dymos as dm\n",
"except ImportError:\n",
" if 'google.colab' in str(get_ipython()):\n",
" !python -m pip install dymos\n",
" else:\n",
" missing_packages.append('dymos')\n",
"try:\n",
" import pyoptsparse\n",
"except ImportError:\n",
" if 'google.colab' in str(get_ipython()):\n",
" !pip install -q condacolab\n",
" import condacolab\n",
" condacolab.install_miniconda()\n",
" !conda install -c conda-forge pyoptsparse\n",
" else:\n",
" missing_packages.append('pyoptsparse')\n",
"if missing_packages:\n",
" raise EnvironmentError('This notebook requires the following packages '\n",
" 'please install them and restart this notebook\\'s runtime: {\",\".join(missing_packages)}')"
]
},
{
"cell_type": "markdown",
"id": "c9df3b73",
"metadata": {},
"source": [
"# Moon Landing Problem\n",
"\n",
"The Moon landing problem is a version of the soft landing problem presented in {cite}`Meditch1964`. The problem is simplified to have one degree-of-freedom and normalized such that the Moon's gravity is unity. The goal is to minimize the amount of fuel consumed or, stated differently, maximize the final mass, while bringing the lander down to the surface for a soft landing."
]
},
{
"cell_type": "markdown",
"id": "a8b1357a",
"metadata": {},
"source": [
"## State and control variables\n",
"\n",
"This system has three state variables, the altitude ($h$), velocity ($v$), and mass ($m$) of the lander.\n",
"\n",
"This system has one control variable, ($T$), the thrust applied to the vehicle.\n",
"\n",
"The dynamics of the system are given by\n",
"\n",
"\\begin{align}\n",
" \\dot{h} &= v \\\\\n",
" \\dot{v} &= -1 + \\frac{T}{m} \\\\\n",
" \\dot{m} &= -\\frac{T}{2.349}\n",
"\\end{align}"
]
},
{
"cell_type": "markdown",
"id": "71a99c51",
"metadata": {},
"source": [
"## Problem Definition\n",
"\n",
"We seek to maximize the final mass of the vehicle while bringing it to a soft landing.\n",
"\n",
"\\begin{align}\n",
" \\mathrm{Minimize} \\, J &= m_f\n",
"\\end{align}\n",
"\n",
"The initial conditions are\n",
"\\begin{align}\n",
" h_0 &= 1 \\\\\n",
" v_0 &= -0.783 \\\\\n",
" m_0 &= 1\n",
"\\end{align}\n",
"and the terminal constraints are\n",
"\\begin{align}\n",
" h_f &= 0 \\\\\n",
" v_f &= 0\n",
"\\end{align}\n",
"\n",
"Additionally, the thrust is constrained to be positive but remain under 1.227.\n",
"\n",
"\\begin{align}\n",
" 0 \\le T \\le 1.227 \n",
"\\end{align}"
]
},
{
"cell_type": "markdown",
"id": "48fa15f1",
"metadata": {},
"source": [
"## Defining the ODE\n",
"\n",
"The following implements the dynamics of the Moon landing problem described above."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d1fa5d91",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import openmdao.api as om\n",
"\n",
"\n",
"class MoonLandingProblemODE(om.ExplicitComponent):\n",
" def initialize(self):\n",
" self.options.declare('num_nodes', types=int)\n",
"\n",
" def setup(self):\n",
" nn = self.options['num_nodes']\n",
"\n",
" # inputs\n",
" self.add_input('h', val=np.ones(nn), units=None, desc='Altitude')\n",
" self.add_input('v', val=np.ones(nn), units='1/s', desc='Velocity')\n",
" self.add_input('m', val=np.ones(nn), units=None, desc='Mass')\n",
" self.add_input('T', val=np.ones(nn), units=None, desc='Thrust')\n",
"\n",
" # outputs\n",
" self.add_output('h_dot', val=np.ones(nn), units='1/s', desc='Rate of change of Altitude')\n",
" self.add_output('v_dot', val=np.ones(nn), units='1/s**2', desc='Rate of change of Velocity')\n",
" self.add_output('m_dot', val=np.ones(nn), units='1/s', desc='Rate of change of Mass')\n",
"\n",
" # partials\n",
" ar = np.arange(nn)\n",
" self.declare_partials(of='h_dot', wrt='v', rows=ar, cols=ar, val=1.0)\n",
" self.declare_partials(of='v_dot', wrt='m', rows=ar, cols=ar)\n",
" self.declare_partials(of='v_dot', wrt='T', rows=ar, cols=ar)\n",
" self.declare_partials(of='m_dot', wrt='T', rows=ar, cols=ar, val=-1/2.349)\n",
" self.declare_partials(of='m_dot', wrt='T', rows=ar, cols=ar, val=-1/2.349)\n",
"\n",
" def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):\n",
" v = inputs['v']\n",
" m = inputs['m']\n",
" T = inputs['T']\n",
"\n",
" outputs['h_dot'] = v\n",
" outputs['v_dot'] = -1 + T/m\n",
" outputs['m_dot'] = -T/2.349\n",
"\n",
" def compute_partials(self, inputs, partials, discrete_inputs=None):\n",
" m = inputs['m']\n",
" T = inputs['T']\n",
"\n",
" partials['v_dot', 'T'] = 1/m\n",
" partials['v_dot', 'm'] = -T/m**2"
]
},
{
"cell_type": "markdown",
"id": "18e69427",
"metadata": {},
"source": [
"## Solving the Moon landing problem with Dymos\n",
"\n",
"The optimal solution to this problem is known to have _bang-bang_ control. That is, the control has a \"jump\" that render it discontinuous in time. Capturing this behavior accurately requires the use of grid refinement for the Gauss-Lobatto and Radau pseudospectral transcriptions but the Birkhoff pseudospectral transcription can be used to handle this behavior without the use of any grid refinement. The following code shows the use of the Birkhoff pseudospectral transcription to solve the problem."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "65ab9d17",
"metadata": {},
"outputs": [],
"source": [
"import dymos as dm\n",
"import matplotlib.pyplot as plt\n",
"\n",
"p = om.Problem(model=om.Group())\n",
"p.driver = om.pyOptSparseDriver()\n",
"p.driver.declare_coloring()\n",
"p.driver.options['optimizer'] = 'IPOPT'\n",
"p.driver.opt_settings['hessian_approximation'] = 'limited-memory'\n",
"p.driver.opt_settings['print_level'] = 0\n",
"p.driver.opt_settings['linear_solver'] = 'mumps'\n",
"p.driver.declare_coloring()\n",
"\n",
"t = dm.Birkhoff(num_nodes=20)\n",
"\n",
"traj = p.model.add_subsystem('traj', dm.Trajectory())\n",
"phase = dm.Phase(ode_class=MoonLandingProblemODE, transcription=t)\n",
"\n",
"phase.set_time_options(fix_initial=True, fix_duration=False)\n",
"phase.add_state('h', fix_initial=True, rate_source='h_dot')\n",
"phase.add_state('v', fix_initial=True, rate_source='v_dot')\n",
"phase.add_state('m', fix_initial=True, lower=1e-3, rate_source='m_dot')\n",
"phase.add_control('T', lower=0.0, upper=1.227)\n",
"\n",
"phase.add_boundary_constraint('h', loc='final', equals=0.0)\n",
"phase.add_boundary_constraint('v', loc='final', equals=0.0)\n",
"\n",
"phase.add_objective('m', scaler=-1)\n",
"phase.set_simulate_options(atol=1.0E-1, rtol=1.0E-2)\n",
"\n",
"traj.add_phase('phase', phase)\n",
"\n",
"p.setup(check=True, force_alloc_complex=True)\n",
"\n",
"phase.set_time_val(initial=0.0, duration=1.0)\n",
"phase.set_state_val('h', [1.0, 0.0])\n",
"phase.set_state_val('v', [-0.783, 0.0])\n",
"phase.set_state_val('m', [1.0, 0.2])\n",
"phase.set_control_val('T', [0.0, 1.227])\n",
"dm.run_problem(p, simulate=False, simulate_kwargs={'times_per_seg': 100}, make_plots=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9b266ef1",
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import IFrame\n",
"IFrame(src=str(p.get_reports_dir() / 'traj_results_report.html'), width=800, height=1200)"
]
},
{
"cell_type": "markdown",
"id": "59334e2c",
"metadata": {},
"source": [
"### Notes on the solution\n",
"\n",
"We can see that the collocation solution accurately captures the jump in the thrust. The oscillatory behavior observed is a result of interpolation performed post solution rather than a property of the solution itself."
]
},
{
"cell_type": "markdown",
"id": "2e64faca",
"metadata": {},
"source": [
"## References\n",
"\n",
"```{bibliography}\n",
":filter: docname in docnames\n",
"```"
]
}
],
"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.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading
Loading