Source code for pudl.metadata.units
"""PUDL unit registry built on top of Pint's default registry.
Extends Pint with energy-industry units (MMBtu, Mcf, MMcf, TBtu), reactive
power (VAr), and a currency dimension (USD). All PUDL
code that needs to parse or validate unit strings should import
PUDL_UNIT_REGISTRY from here rather than constructing a bare UnitRegistry.
Unit strings used in field metadata follow Pint expression syntax with a
slash-with-spaces convention for compound units, e.g. ``MMBtu / MWh``,
``USD / MWh``, ``short_ton / hour``.
"""
import pint
# Pint definition strings for every custom unit and dimension. The ordering
# matters: dimensions must be defined before units that reference them.
[docs]
PUDL_UNIT_DEFINITIONS: list[str] = [
# Energy-industry volume and heat units
"MMBtu = 1e6 * BTU = MMBTU",
"Mcf = 1000 * cubic_foot",
"MMcf = 1e6 * cubic_foot",
"TBtu = 1e12 * BTU",
# Reactive power — dimensionally equal to watt in SI, but conventionally
# labeled VAr in power systems to distinguish from real power.
"VAr = watt = volt_ampere_reactive",
"MVAr = 1e6 * VAr",
# Currency — a custom dimension so that compound units like USD / MWh are
# parseable. Exchange-rate conversions are outside Pint's scope.
"USD = [currency]",
]
[docs]
PUDL_UNIT_REGISTRY: pint.UnitRegistry = pint.UnitRegistry()
for _defn in PUDL_UNIT_DEFINITIONS:
PUDL_UNIT_REGISTRY.define(_defn)
[docs]
def unit_registry_to_frictionless() -> dict:
"""Return a JSON-serializable dict describing PUDL's custom unit definitions.
The returned dict is suitable for embedding as ``unit_registry`` in a
Frictionless datapackage descriptor. Consumers can reconstruct the registry
by calling ``pint.UnitRegistry().define(unit_def)`` for each definition string.
"""
return {"format": "pint", "definitions": PUDL_UNIT_DEFINITIONS}