{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Units and Quantities\n", "\n", "## Objectives\n", "\n", "- Use units\n", "- Create functions that accept quantities as arguments\n", "- Create new units" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basics\n", "\n", "How do we define a Quantity and which parts does it have?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import astropy.units as u" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Define a quantity length\n", "length = 26.2 * u.meter\n", "# print it\n", "print(length) # length is a quantity" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Type of quantity\n", "type(length)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Type of unit\n", "type(u.meter)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Quantity\n", "length" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# value\n", "length.value" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# unit\n", "length.unit" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# information\n", "length.info" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quantities can be converted to other units systems or factors by using `to()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Convert it to: km, lyr\n", "print(length.to(u.km))\n", "print(length.to(u.lightyear))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can do arithmetic operations when the quantities have the compatible units:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# arithmetic with distances\n", "distance_start = 10 * u.mm\n", "distance_end = 23 * u.km\n", "length = distance_end - distance_start\n", "print(length)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quantities can also be combined, for example to measure speed" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# calculate a speed\n", "time = 15 * u.minute\n", "speed = length / time\n", "print(speed)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# decompose it\n", "print(speed.decompose())\n", "print(speed.si)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "
\n", "
\n", "

Unit conversions

\n", "
\n", "\n", "\n", "
\n", "\n", "
    \n", "
  1. Convert the speed in imperial units (miles/hour) using:\n", " from astropy.units import imperial
  2. \n", "
  3. Calculate whether a pint is more than half litre.\n", " You can compare quantities as comparing variables.\n", " Something strange? Check what deffinition of pint astropy is using.
  4. \n", "
  5. Does units work with areas? calculate the area of a rectangle of 3 km of side and 5 meter of width. Show them in $m^2$ and convert them to yards$^2$
  6. \n", "
\n", "\n", "
\n", "\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#1\n", "from astropy.units import imperial\n", "print(speed.to(imperial.mile/u.hour))\n", "\n", "#2\n", "print(imperial.pint > 0.5 * u.l)\n", "print(imperial.pint.to(u.ml))\n", " # A liquid pint in US is 473 ml; in UK is 568 ml\n", "\n", "#3\n", "rectangle_area = 3 * u.km * 5 * u.m\n", "print(rectangle_area)\n", "print(rectangle_area.decompose())\n", "print(rectangle_area.to(imperial.yard ** 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Composed units\n", "\n", "Many units are compositions of others, for example, one could create new combinationes for ease of use:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# create a composite unit\n", "cms = u.cm / u.s\n", "speed.to(cms)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# and in the imperial system\n", "mph = imperial.mile / u.hour\n", "speed.to(mph)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and others are already a composition:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# what can be converted from s-1?\n", "(u.s ** -1).compose()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# or Jules?\n", "(u.joule).compose()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Unity of R\n", "(13.605692 * u.eV).to(u.Ry)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometime we get *no units* quantitites" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# no units\n", "nounits = 20. * u.cm / (1. * u.m)\n", "nounits" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What happen if we add a number to this?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# arithmetic with no units\n", "nounits + 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# final value of a no unit quantity\n", "nounits.decompose() # It's a unitless quantity" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Equivalencies\n", "\n", "Some conversions are not done by a conversion factor as between miles and kilometers, for example converting between wavelength and frequency." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# converting spectral quantities\n", "(656.281 * u.nm).to(u.Hz) # Fails because they are not compatible" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# but doing it right\n", "(656.281 * u.nm).to(u.Hz, equivalencies=u.spectral())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other built-in equivalencies are: \n", " - `parallax()`\n", " - Doppler (`dopplr_radio`, `doppler_optical`, `doppler_relativistic`)\n", " - spectral flux density\n", " - brigthness temperature\n", " - temperature energy\n", " - and you can [build your own](http://astropy.readthedocs.org/en/stable/units/equivalencies.html#writing-new-equivalencies)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# finding the equivalencies\n", "u.Hz.find_equivalent_units()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# but also using other systems\n", "u.Hz.find_equivalent_units(equivalencies=u.spectral())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Printing the quantities" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Printing values with different formats\n", "print(\"{0.value:0.03f} {0.unit:FITS}\".format(speed))\n", "print(\"{0.value:0.03f} {0.unit:latex_inline}\".format(speed))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arrays\n", "\n", "Quantities can also be applied to arrays" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# different ways of defining a quantity for a single value\n", "length = 44 * u.m\n", "time = u.Quantity(23, u.s)\n", "speed = length / time\n", "speed" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# now with lists\n", "length_list = [1, 2, 3] * u.m\n", "\n", "# and arrays\n", "import numpy as np\n", "time_array = np.array([1, 2, 3]) * u.s\n", "\n", "# and its arithmetics\n", "length_list / time_array" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# angles are smart!\n", "angle = u.Quantity(np.arange(180), u.deg)\n", "print(angle[[0, -1]])\n", "print(np.sin(angle[[0, -1]]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting quantities\n", "\n", "To work nicely with matplotlib we need to do as follows:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# allowing for plotting\n", "from astropy.visualization import quantity_support\n", "quantity_support()\n", "\n", "# loading matplotlib\n", "%matplotlib inline\n", "from matplotlib import pyplot as plt" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Ploting the previous array\n", "plt.plot(angle, np.sin(angle))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Creating functions with quantities as units\n", "\n", "We want to have functions that contain the information of the untis, and with them we can be sure that we will be always have the *right* result." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create a function for the Kinetic energy\n", "@u.quantity_input(mass=u.kg, speed=u.m/u.s)\n", "def kinetic(mass, speed):\n", " return (mass * speed ** 2 / 2.).to(u.joule)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# run without units\n", "kinetic(5, 10) # Fails! it doesn't specify the units." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Run with units\n", "kinetic(5 * u.kg, 100 * cms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "
\n", "
\n", "

Using `quantity_input`

\n", "
\n", "\n", "\n", "
\n", "\n", "
    \n", "
  1. Create a function that calculates potential energy where $g$ defaults to Earth value, but could be used for different planets. Test it for any of the $g$ values for any other planets.
  2. \n", "
\n", "\n", "
\n", "\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#4\n", "@u.quantity_input(mass=u.kg, height=u.m, g=u.m / u.s ** 2)\n", "def potential(mass, height, g=9.8 * u.m / u.s **2):\n", " return (0.5 * mass * g * height).to(u.joule)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# run it for some values\n", "potential(5 * u.kg, 30 *u.cm)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# on Mars:\n", "potential(5 * u.kg, 1 * u.m, g=3.75 * u.m/u.s**2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create your own units\n", "\n", "Some times we want to create our own units:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Create units for a laugh scale\n", "titter = u.def_unit('titter')\n", "chuckle = u.def_unit('chuckle', 5 * titter)\n", "laugh = u.def_unit('laugh', 4 * chuckle)\n", "guffaw = u.def_unit('guffaw', 3 * laugh)\n", "rofl = u.def_unit('rofl', 4 * guffaw)\n", "death_by_laughing = u.def_unit('death_by_laughing', 10 * rofl)\n", "print((1 * rofl).to(titter))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "
\n", "
\n", "

Area with units

\n", "
\n", "\n", "\n", "
\n", "\n", "
    \n", "
  1. Convert the area calculated before rectangle_area in hectares (1 hectare = 100 ares; 1 are = 100 $m^2$).
  2. \n", "
\n", "\n", "
\n", "\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#5\n", "ares = u.def_unit('ares', (10 * u.m)**2)\n", "hectar = u.def_unit('hectares', 100 * ares)\n", "print(rectangle_area.to(hectar))" ] } ], "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.6" } }, "nbformat": 4, "nbformat_minor": 1 }