Work With Units#

Estimated reading time: 4 minutes

tephpy takes and returns pint quantities at every boundary carrying scientific data (spec §5). Diagram geometry is the documented exception: the transforms layer trades in bare arrays in the diagram’s native units, and the options that frame or draw a diagram — ax.set_extent(...), a family’s interval — take plain numbers. Three things follow, in the order they tend to surprise people.

Quantities Go In Directly#

If your arrays already carry units, pass them and say nothing else. There is no units= argument in this call:

from metpy.units import units

from tephpy import Sounding

snd = Sounding(
    pressure=[1000.0, 925.0, 850.0, 700.0] * units.hPa,
    temperature=[15.4, 15.4, 10.4, 4.4] * units.degC,
    dewpoint=[14.4, 2.4, 3.4, -17.6] * units.degC,
)

The units= mapping exists for the other case — bare arrays, which is what a pandas.DataFrame hands you. Build a Sounding From Your Own Data is that route.

Any Unit pint Can Parse#

units= is not a shortlist tephpy maintains. It is handed to pint, so anything pint parses in the right dimension is accepted, and the field is stored in that unit rather than converted on the way in:

imperial = Sounding(
    pressure=[29.5, 26.0],
    temperature=[68.0, 60.0],
    units={"pressure": "inHg", "temperature": "degF"},
)

The field is tagged, not rewritten: imperial.pressure reads back [29.5 26.0] inch_Hg, the numbers you gave. That sounding plots and analyses exactly like any other, and where a calculation derives a new quantity it comes back in tephpy’s own units — calc.parcel_path on a °F sounding returns a °C profile, whatever the pressure was spelled in.

That last part is pinned rather than asserted. tests/test_calc.py runs the parcel ascent and every stability index over ten pressure units — hPa, Pa, kPa, mbar, bar, atm, psi, torr, inHg and mmHg — and requires the answers to agree, not merely the calls to succeed (#214).

What Comes Back Is pint#

Every profile field — pressure, temperature, dewpoint and the winds — is a pint.Quantity on MetPy’s registry, so conversion is a method call:

hpa = imperial.pressure.to("hPa")
celsius = imperial.temperature.to("degC")

A sounding’s metadata is not quantified and is not meant to be: station, time and label come back as the string and timestamp you gave.

Being on MetPy’s registry is the part that matters downstream. Quantities out of tephpy go straight into MetPy’s own calculations with no conversion step and no registry mismatch:

from metpy.calc import dewpoint_from_relative_humidity

humid = dewpoint_from_relative_humidity(
    snd.temperature, [0.9, 0.8, 0.7, 0.6] * units.dimensionless
)

Do not check this by comparing registries. metpy.units.units is an ApplicationRegistry proxy and the quantities sit on the pint.UnitRegistry it wraps, so an identity test reports False for a claim that is true.

When the Units Are Wrong#

TephpyUnitsError covers the whole of this subject — units missing, ambiguous, unparsable, or in the wrong dimension. It subclasses TephpyError, the root of tephpy’s hierarchy, so a caller who wants every error tephpy raises about the data itself can catch that instead. tephpy.exceptions documents the hierarchy, and says which mistakes fall outside it and raise a builtin exception instead.

Where to Go Next#

Build a Sounding From Your Own Data puts these units to work on data of your own.