{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sympy import *\n",
    "init_printing()\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy import linalg\n",
    "import scipy.integrate as integrate\n",
    "import numpy as np\n",
    "from numpy import linalg as LA\n",
    "from matplotlib.backends.backend_pdf import PdfPages\n",
    "from collections import deque"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def equals(a,b):\n",
    "    assert np.isclose(float(simplify(a - b)), 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 5288 characters]\n",
      "text/latex": [
       "$\\displaystyle 0.5 m \\left(- g \\left(- h_{0}^{2} + h_{f}^{2}\\right) - 0.333333333333333 v_{0}^{3} + 0.333333333333333 v_{f}^{3}\\right)$"
      ],
      "text/plain": [
       "      ⎛    ⎛    2      2⎞                       3                        3⎞\n",
       "0.5⋅m⋅⎝- g⋅⎝- h₀  + h_f ⎠ - 0.333333333333333⋅v₀  + 0.333333333333333⋅v_f ⎠"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t, v0, vf, g, c1, c2, h0, hf, m = symbols('t, v_0, v_f, g, c_1, c_2, h_0, h_f, m')\n",
    "e1 = ((1/2) * m)*( ((1/3)*(vf**3) + c1)-((1/3)*(v0**3) + c1) ) - m*g*( ((1/2)*(hf**2) + c2) - ((1/2)*(h0**2) + c2))\n",
    "e2 = (1/2)*m*( (1/3)*(vf**3-v0**3) - g*(hf**2-h0**2))\n",
    "equals(e1,e2)\n",
    "e2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1 = (1/2)*m*( (1/3)*(vf**3-v0**3) - g*(hf**2-h0**2))\n",
    "e1 = ( (1/3)*(vf**3-v0**3) - g*(hf**2-h0**2))\n",
    "e2 = (1/3)*vf**3-(1/3)*v0**3 - g*hf**2 + g*h0**2\n",
    "e2 = (1/3)*vf**3 - g*hf**2 + g*h0**2 -(1/3)*v0**3\n",
    "equals(e1,e2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/latex": [
       "$\\displaystyle - \\frac{g v_{f}^{2}}{3} - 20 h_{f} v_{f}$"
      ],
      "text/plain": [
       "       2             \n",
       "  g⋅v_f              \n",
       "- ────── - 20⋅h_f⋅v_f\n",
       "    3                "
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "poly = e2.subs(h0,0).subs(v0,10)\n",
    "polydiff = -20*hf*vf - (g/3)*vf**2\n",
    "polydiff"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hf = -(1/20)*(g/3)*vf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/latex": [
       "$\\displaystyle 0.333333333333333 v_{f}^{3} - 0.277777777777778 v_{f}^{2} - 333.333333333333$"
      ],
      "text/plain": [
       "                     3                        2                   \n",
       "0.333333333333333⋅v_f  - 0.277777777777778⋅v_f  - 333.333333333333"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "poly.subs(hf, -(1/20)*(g/3)*vf).subs(g, 10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "t, v0, t1, t2, g, m, e = symbols('t, v0, t1, t2, g, m, e')\n",
    "\n",
    "a_t = v0*t - 0.5 * g * t**2\n",
    "\n",
    "def constants(expr):\n",
    "    return expr.subs(v0, 50.0).subs(g, 10.0).subs(m, 1.0)\n",
    "\n",
    "def T_f(u_t):\n",
    "    dot_u = u_t.diff(t)\n",
    "    return 0.5 * m * (dot_u)**2\n",
    "\n",
    "def V_f(u_t):\n",
    "    return m * g * u_t\n",
    "\n",
    "def perturbed(u_t):\n",
    "    w_t = 5**2 - (t-5)**2\n",
    "    return u_t + e*w_t\n",
    "\n",
    "def I(u_t):\n",
    "    integrand = T_f(u_t) - V_f(u_t)\n",
    "    integrand_t = constants(integrand)\n",
    "    result, tol = integrate.quad(lambda t_val: integrand_t.subs(t, t_val), 0, 10.0)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 66176 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "ts = np.linspace(0.0, 10.0, 1000)\n",
    "es = np.linspace(-1, 1.0, 10)\n",
    "\n",
    "def compute_t(expr):\n",
    "    return [ constants(expr).subs(t, t_val) for t_val in ts]\n",
    "\n",
    "plt.figure(1)\n",
    "for e_val in es:\n",
    "    u_t_e = compute_t(perturbed(a_t).subs(e, e_val)) \n",
    "    plt.plot(ts, u_t_e, label='u_t (e=)'+str(e_val))\n",
    "    \n",
    "plt.xlabel('t (s)')\n",
    "\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 17472 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "Is = [I(perturbed(a_t).subs(e, e_val)) for e_val in es]\n",
    "\n",
    "plt.figure(1)\n",
    "    \n",
    "plt.xlabel('t (s)')\n",
    "\n",
    "plt.plot(es, Is, label='I')\n",
    "\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 54120 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "b_t = 2*a_t\n",
    "\n",
    "plt.figure(1)\n",
    "for e_val in es:\n",
    "    u_t_e = compute_t(perturbed(b_t).subs(e, e_val)) \n",
    "    plt.plot(ts, u_t_e, label='u_t (e=)'+str(e_val))\n",
    "    \n",
    "plt.xlabel('t (s)')\n",
    "\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 14752 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "Is = [I(perturbed(b_t).subs(e, e_val)) for e_val in es]\n",
    "\n",
    "plt.figure(1)\n",
    "\n",
    "plt.xlabel('t (s)')\n",
    "\n",
    "plt.plot(es, Is, label='I')\n",
    "\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Rewrite the previous equation into the form $av + b$, so that we can define the analytical solution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/latex": [
       "$\\displaystyle \\frac{k vd}{m} - \\frac{v \\left(d + k\\right)}{m}$"
      ],
      "text/plain": [
       "k⋅vd   v⋅(d + k)\n",
       "──── - ─────────\n",
       " m         m    "
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = -(1/m)*(k+d)\n",
    "b = (1/m)*(k*vd)\n",
    "dv_dt_norm = (a*v + b)\n",
    "equals(dv_dt, dv_dt_norm) # Proves correct rewrite.\n",
    "dv_dt_norm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define analytical solution, and prove that it is indeed a solution by differentiating it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 4852 characters]\n",
      "text/latex": [
       "$\\displaystyle \\frac{k vd}{d + k} + \\left(- \\frac{k vd}{d + k} + v_{0}\\right) e^{- \\frac{t \\left(d + k\\right)}{m}}$"
      ],
      "text/plain": [
       "                        -t⋅(d + k) \n",
       "                        ───────────\n",
       " k⋅vd   ⎛   k⋅vd     ⎞       m     \n",
       "───── + ⎜- ───── + v₀⎟⋅ℯ           \n",
       "d + k   ⎝  d + k     ⎠             "
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v_t = exp(a*t)*(v0 + b/a) - b/a\n",
    "equals(dv_dt.subs(v, v_t), diff(v_t, t))\n",
    "equals(v_t.subs(t, 0), v0)\n",
    "v_t"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following represents the explicit euler method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Explicit_Euler:\n",
    "    def simulate(self, f, x0, t0, h, max_steps):\n",
    "        x = x0\n",
    "        xs = [x]\n",
    "        for i in range(1, max_steps):\n",
    "            x = x + f(x)*h\n",
    "            xs.append(x)\n",
    "        return xs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following appplies the previous numerical solver to the cruise control example. \n",
    "The results are plotting against the analytical solution `v_t` obtained earlier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 15596 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Instantiate the symbolic equations to the example.\n",
    "v0_num = 0.0\n",
    "v_t_example = v_t.subs(m,1576.0).subs(vd,40).subs(v0,v0_num).subs(k,1000).subs(d,0.5)\n",
    "dv_dt_example = dv_dt.subs(m,1576.0).subs(vd,40).subs(v0,v0_num).subs(k,1000).subs(d,0.5)\n",
    "\n",
    "# Define simulation step size, time range, and total number of steps to be taken.\n",
    "h=0.2\n",
    "t_range = np.arange(0,7,h)\n",
    "num_steps = len(t_range)\n",
    "\n",
    "# Compute analytical trajectory\n",
    "xs_c = [v_t_example.subs(t, x) for x in t_range]\n",
    "\n",
    "# Compute approximate trajectories\n",
    "xs_ee = Explicit_Euler().simulate(lambda v_val: dv_dt_example.subs(v,v_val), \n",
    "                                      v0_num, 0.0, h, num_steps)\n",
    "\n",
    "plt.figure(1)\n",
    "plt.plot(t_range,xs_c, label='v')\n",
    "plt.plot(t_range,xs_ee, 'o', markersize=3, label='v_exEuler')\n",
    "plt.xlabel('t (s)')\n",
    "plt.ylabel('speed (m/s)')\n",
    "\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exercise: Implement the Midpoint Method"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The midpoint method approximates the solution of a given IVP in the form of\n",
    "$$ \\dot{x} = f(x) $$\n",
    "by the following:\n",
    "$$ \\mathit{aux} = x(t) + f(x(t))\\frac{h}{2}$$\n",
    "$$ x(t+h) = x(t) + f(aux)h$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Midpoint:\n",
    "    def simulate(self, f, x0, t0, h, max_steps):\n",
    "        x = x0\n",
    "        xs = [x]\n",
    "        for i in range(1, max_steps):\n",
    "            # TODO: implement the following \n",
    "            x = ...\n",
    "            xs.append(x)\n",
    "        return xs\n",
    "\n",
    "# Run solver and plot\n",
    "xs_mid = Midpoint().simulate(lambda v_val: dv_dt_example.subs(v,v_val), \n",
    "                                v0_num, 0.0, h, num_steps)\n",
    "plt.figure(1)\n",
    "plt.plot(t_range, xs_c, label='v')\n",
    "plt.plot(t_range, xs_ee, 'o', markersize=3, label='v_exEuler')\n",
    "plt.plot(t_range, xs_mid, 'o', markersize=3, label='v_mid')\n",
    "plt.xlabel('t (s)')\n",
    "plt.ylabel('speed (m/s)')\n",
    "\n",
    "plt.legend()\n",
    "\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "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.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
