This notebook will help you become familiar with unit support in the MetPy
library. Learn how to apply units to values, calculate new values from united values, and use units in MetPy
functions. MetPy
provides unit support through the Pint
library. You can access the documentation for Pint
by clicking on the image to the right.
units
to track values with physical unitsMetPy
import numpy as np
import metpy.calc as mpcalc
from metpy.units import units
MetPy
provides units support through the Pint
library. Values with units attached to them (quantities) are described by the Pint
documentation as "the product of a numerical value and a unit of measurement." They are used to programatically keep track of physical quantities so we can worry less about unit conversion errors and focus on our coding objective instead.
We can apply units to a numerical value by multiplying that value by the units we desire in a couple of different ways -- either accessing the units as an attribute of units
or passing a string to units
as an argument. Either way, we get the same result:
distance = 5. * units.meter
distance
distance = 5. * units('meter')
distance
Alternatively, we can use the Quantity
constructor to do the same thing.
distance = units.Quantity(5., 'meter')
distance
We are not limited to applying units to scalars. They work with numpy
arrays as well!
distance = np.arange(1., 11.) * units.meter
distance
If our units are not as simple as e.g., distance, we can chain together unit assignments. Say we have a vertical acceleration that we want to apply units to. We can multiply by meters, then divide by seconds twice. Alternatively, we can express this as a string of words, or even a string of abbreviations.
accel = np.arange(10) * units.meter / units.second / units.second
accel
accel = np.arange(10) * units('meter / second ** 2')
accel
accel = np.arange(10) * units('m / s ** 2')
accel
Once units are attached to a quantity, we can do math with other united quantities.
x = np.random.randint(25, size=(5, 5)) * units.meter
y = np.random.randint(25, size=(5, 5)) * units.meter
z = x - y
z
If the dimensionality of the quantities we are operating on don't match, we will get a DimensionalityError
. For example, try uncommenting the last line in the following cell and then running the cell.
distance = np.random.random((5, 5)) * units.meter
time = np.random.random((5, 5)) * units.second
# velocity = distance - time
In the case that the unit dimensionalities are different, but the mathematical operation makes it valid, we won't get an error. Instead we get a quantity with new units, as we expect.
distance = np.random.random((5, 5)) * units.meter
time = np.random.random((5, 5)) * units.second
velocity = distance / time
velocity
When we multiply a value by units, what we are actually doing is building a Quantity
object. A Quantity
has many useful methods and attributes to manipulate its value and give us information about it. Some of the more common and useful ones are:
.magnitude
, and .m
.to()
.units
Say we have a 1-foot long ruler that measures distance in whole inches.
ruler = np.arange(1.0, 13.0) * units.inch
ruler
Perhaps we want to go rogue and create a ruler without units. We can get the magnitude of the ruler with the .magnitude
attribute (or shorthand .m
).
ruler.m
But that probably isn't a great idea. Instead, let's convert the units of the ruler to measure in centimeters. We do this using the .to
method.
ruler = ruler.to('centimeter')
ruler
After working with our ruler for awhile, maybe we forget what units are attached to it. We can check with the .units
attribute.
ruler.units
Many of the functions in MetPy
expect their arguments to have units. Though it may seem like slightly more effort, requiring units saves time for everyone. Let's look at a simple example with u and v wind components. Say we want to calculate wind speed and wind direction from these components.
u = np.array([5., 3., 7., 2., -9.])
v = np.array([-2., 5., -7., 3., 2.])
If we try to calculate wind speed using mpcalc.wind_speed
without applying units, we will get a ValueError
and an explanation for how to apply units to our values. For example, try uncommenting the line in the following cell and running the cell.
# mpcalc.wind_speed(u, v)
Notice that at the bottom of the error message, an explanation is provided that u
needs "[speed]"
. This is not a specific unit, but instead a dimensionality. We can apply any units we like to u
and v
as long as their dimensionality is speed. Let's use meter / second.
u = u * units("meter / second")
v = v * units("meter / second")
wind_speed = mpcalc.wind_speed(u, v)
wind_speed
Great! Now let's get the wind direction with mpcalc.wind_direction
wind_dir = mpcalc.wind_direction(u, v)
wind_dir
Notice that in both cases the results have units attached to them, and wind_dir
has units of degree
as we expect.
There are a few places that one can easily get tripped up when using units in an atmospheric science context. Additionally, sometimes units don't play nicely with the data type we are working with, so we need to handle them in a different way.
We will commonly work with pressure values that have units of millibars, or mb. However, the abbreviation mb means something different to Pint
...
pressure = 500. * units.mb
print(pressure)
A millibarn is a unit of area, which is likely not what we're looking for. To avoid this, we want to spell out millibar when using it as a physical unit.
pressure = 500. * units.millibar
print(pressure)
delta_t = 6. * units.delta_degF
temperature = 72. * units.degF
temperature + delta_t
temperature.to('kelvin') + delta_t
10. * units('degF') - 1. * units('kelvin')
Finally, some data types don't play with units as nicely as we would like them to. A well-known and common example of this occurs with numpy.ma.array
, i.e., numpy
masked arrays. Instead of multiplying a masked array by the units we desire, we need to call the Quantity
constructor directly.
mask = [False, True, False, False, True]
values = [87., 105., 94., 45., 107.]
humidity = units.Quantity(np.ma.array(values, mask=mask), 'percent')
humidity
If you need more examples of working with units, check out the MetPy docs, MetPy example gallery, and Pint docs.
If you feel like you need a bigger challenge, consider working on one or both of the following: