{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# MetPy Constants and Units" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Complete list of constants at: https://unidata.github.io/MetPy/latest/api/generated/metpy.constants.html" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from metpy.units import units\n", "import metpy.constants as c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Invoking constants in MetPy\n", "All constants have a long name, short name, and associated units:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "9.80665 meter / second ** 2 9.80665 meter / second ** 2\n" ] } ], "source": [ "print(c.earth_gravity, ' ', c.g)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Units functionality comes from the `pint` library. All arithmetic carries units with it:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.2870579959589441 joule / gram / kelvin \n", " 1005 meter ** 2 / kelvin / second ** 2 \n", " 0.0002856298467253175 joule * second ** 2 / gram / meter ** 2\n" ] } ], "source": [ "print(c.Rd,'\\n' ,c.Cp_d,'\\n' , c.Rd / c.Cp_d)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simplifying units\n", "You can see that there can be some ugly units going on sometimes. In `pint` there is a method `to_base_units()` that will sort this out and convert to the simplist SI units:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.2856298467253175 dimensionless\n" ] } ], "source": [ "diatomic_gas_ratio = c.Rd / c.Cp_d\n", "print(diatomic_gas_ratio.to_base_units())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Automatic dimensional analysis as a debugger\n", "If you try to mix units, you will be reprimanded! This is a good thing - you can catch a lot of code bugs this way." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "ename": "DimensionalityError", "evalue": "Cannot convert from 'meter ** 2 / second ** 2' ([length] ** 2 / [time] ** 2) to 'joule / gram / kelvin' ([length] ** 2 / [temperature] / [time] ** 2)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mDimensionalityError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mabomination\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwater_heat_vaporization\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwater_gas_constant\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m~/.conda/envs/aoes/lib/python3.6/site-packages/pint/quantity.py\u001b[0m in \u001b[0;36m__add__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 969\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_timedelta\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 970\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 971\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_add_sub\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moperator\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 972\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 973\u001b[0m \u001b[0m__radd__\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m__add__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/.conda/envs/aoes/lib/python3.6/site-packages/pint/quantity.py\u001b[0m in \u001b[0;36mwrapped\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 104\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mother\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtype\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 105\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mNotImplemented\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 106\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 107\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mresult\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 108\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m~/.conda/envs/aoes/lib/python3.6/site-packages/pint/quantity.py\u001b[0m in \u001b[0;36m_add_sub\u001b[0;34m(self, other, op)\u001b[0m\n\u001b[1;32m 882\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimensionality\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimensionality\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 883\u001b[0m raise DimensionalityError(\n\u001b[0;32m--> 884\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_units\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_units\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimensionality\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdimensionality\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 885\u001b[0m )\n\u001b[1;32m 886\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDimensionalityError\u001b[0m: Cannot convert from 'meter ** 2 / second ** 2' ([length] ** 2 / [time] ** 2) to 'joule / gram / kelvin' ([length] ** 2 / [temperature] / [time] ** 2)" ] } ], "source": [ "abomination = c.water_heat_vaporization + c.water_gas_constant" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Changing units\n", "Sometimes you have to add or change units. This is easy to do:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mean_slp = 101325.0 * units.pascal\n", "print(mean_slp)\n", "mean_slp" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the different formatting of a variable with units between the print statement and inline printing. This is a `pint` feature - you will see this in other editors too, such as `spyder`. Note there is no such difference with \"ordinary\" numbers:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "aa = 1.0\n", "print(aa)\n", "aa" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The real usefulness is for units conversions. The obvious example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "freezing = 32.0 * units.fahrenheit\n", "freezing.to(units.degC)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "freezing.to(units.kelvin)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that a united variable (which can be a series, array, element of a dictionary, etc.) has two parts - the units and the magnitude. These can be parsed out separately:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "freezing.magnitude\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "freezing.units" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python (aoes)", "language": "python", "name": "aoes" }, "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.7" } }, "nbformat": 4, "nbformat_minor": 4 }