{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Mass-Spring System"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this exercise, you will apply Newton's Laws of Motion to derive the differential equations of a mass-spring system.\n",
    "\n",
    "The mass spring system is illustrated in the following figure."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![MS](resources/mass-spring.png \"MS\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The $x(t)$ denotes the position of the mass over time (in meters), and $v(t) = x'(t)$ its velocity (in meters per second). \n",
    "$x'(t)$ denotes the time derivative of $x(t)$.\n",
    "\n",
    "It is assumed that when the mass moves to the right, its position increases. The mass can only move horizontally.\n",
    "\n",
    "The constant $m$ denotes the mass of the mass (in kg).\n",
    "\n",
    "Force $f_e(t)$ denotes an external force exerted on the mass.\n",
    "\n",
    "The spring, when relaxed, that is, when $x(t)=0$, does not exert any force on the mass. However, when the spring is displaced by $x(t)$ meters, it exerts the force of $cx(t)$ newtons on the mass, where $c$ denotes the spring stiffness constant.\n",
    "\n",
    "Complete the following code with the differential equation for $v'(t)$ (the acceleration of the mass)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import required libraries\n",
    "\n",
    "# Simbolic equations\n",
    "from sympy import *\n",
    "init_printing()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Variables used to derive equations\n",
    "x, v, m, c, fe = symbols('x, v, m, c, fe')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAJCAYAAAALpr0TAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAApElEQVQYGU2QDQ3CQAyFe1OwBAegAQfgYFhAAmgYEnBAJoUEB5sEhoPje00L95Lee/15aXOl1mqllN7MzsSOmKndYAe9GTGaBiWCD+hVOoNcg1OHY4t4EsKJeLv6P1fkorRv3Cv5JXMx0JahXaGCOj9jDLqxo5E4IhaanywEb8TtoG59RdOJ+wfEQ0k7qIM17Igv27PBzSXuyOaEkEFfovvvYuELSc5ZBrApgdcAAAAASUVORK5CYII=\n",
      "text/latex": [
       "$\\displaystyle v$"
      ],
      "text/plain": [
       "v"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Derivative of position is velocity\n",
    "dx_dt = v\n",
    "dx_dt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Derivative of velocity is acceleration, \n",
    "# and acceleration is given by applying Newton's law F=ma, where F is the total acting force.\n",
    "\n",
    "# TODO: Compute resulting force.\n",
    "F = 0 \n",
    "\n",
    "#>Solution\n",
    "F = -c*x + fe\n",
    "#<\n",
    "\n",
    "dv_dt = (1/m)*(F)\n",
    "# TODO: uncomment to print equation\n",
    "# dv_dt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Solving the Mass-Spring System  Equations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The code below uses the `scipy.integrate` package to approximate the solution to the differential equations that you produced above.\n",
    "First, define the initial position of the mass, and the remaining parameters (sample values are provided, against which a plot of the correct solution is shown below)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "m_val = 1.0\n",
    "c_val = 1.0\n",
    "init_position = 1.0\n",
    "init_speed = 0.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now define the force $f_e(t)$ function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fe_val(t):\n",
    "    if t>10.0:\n",
    "        return 1.0\n",
    "    else:\n",
    "        return 0.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define how long do you want to observe the behavior of the mass, and how detailed do you want to see it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "stop_time = 30.0\n",
    "resolution = 1000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, run the following code to get the solution:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 33176 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Import the numerical solver and solve the above differential equation\n",
    "\n",
    "import numpy as np\n",
    "from scipy.integrate import odeint\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# Function that returns the mass-spring system derivatives, given the position and velocity of the mass at time t.\n",
    "# This is the main input to the numerical solver.\n",
    "def ode(state_vector, t):\n",
    "    \n",
    "    # Obtain current values for position and velocity\n",
    "    x_val = state_vector[0]\n",
    "    v_val = state_vector[1]\n",
    "    \n",
    "    # Compute derivatives by replacing the symbols of your equation by their real values.\n",
    "    dx_dt_val = dx_dt.subs(v, v_val)\n",
    "    dv_dt_val = dv_dt.subs(m, m_val).subs(c, c_val).subs(fe, fe_val(t)).subs(x, x_val)\n",
    "    \n",
    "    # Return list of derivatives\n",
    "    return [dx_dt_val, dv_dt_val]\n",
    "\n",
    "# Create time grid.\n",
    "time_grid = np.linspace(0,stop_time, resolution)\n",
    "\n",
    "# Compute approximation\n",
    "approx_solution = odeint(ode,[init_position, init_speed],time_grid)\n",
    "\n",
    "# Extract individual trajectories from solution matrix.\n",
    "x_t = [p[0] for p in approx_solution]\n",
    "v_t = [p[1] for p in approx_solution]\n",
    "\n",
    "# Plot results\n",
    "plt.plot(time_grid, x_t, label='x(t)', linewidth=2)\n",
    "plt.plot(time_grid, v_t, label='v(t)', linewidth=2)\n",
    "plt.xlabel('time')\n",
    "plt.legend()\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
}
