Carry units through a calculation by converting to SI at the edges, checking dimensions, and using a units library such as pint.
Why this matters
In 1999 NASA lost the Mars Climate Orbiter because one team's software reported thruster impulse in pound-force seconds while the navigation software expected newton seconds. Every number was computed correctly; the units were not. Smaller versions of that mistake happen every day: a pressure in kPa used as if it were Pa, a flow in L/min mixed with m³/s, a drawing in millimetres read as inches, a concentration in mg/L confused with mmol/L. Python's floats carry no units, so you have to.
Strategy 1: convert to SI at the edges
The simplest reliable habit: convert every input to SI base units (m, kg, s, A, K, mol) as soon as it enters your code, compute in SI, and convert back only for output.
MM = 1e-3 # metres per millimetre
KPA = 1e3 # pascals per kilopascal
MIN = 60.0 # seconds per minute
L = 1e-3 # cubic metres per litre
d = 25 * MM # pipe diameter, m
flow = 40 * L / MIN # 40 L/min in m^3/s
area = 3.14159 * d**2 / 4 # m^2
velocity = flow / area # m/s
print(f"{velocity:.2f} m/s") # 1.36 m/s
Naming the constants (MM, KPA) makes the conversions readable and searchable. Put units in variable names or comments when they are not SI: temp_C, length_mm, pressure_kPa. Your future self will thank you.
Temperature is special: °C and K differ by an offset, not just a factor. A temperature difference of 10 °C is 10 K, but a temperature of 10 °C is 283.15 K. Formulas such as the ideal gas law and radiation need absolute temperatures.
Strategy 2: dimensional analysis
Every physical quantity has dimensions built from length L, mass M, time T, current I, temperature Θ and amount N. Force is M L T⁻²; energy is M L² T⁻²; pressure is M L⁻¹ T⁻². Three rules catch most unit errors:
- You can only add, subtract or compare quantities with the same dimensions. Adding a length to a time is a bug.
- Multiplying and dividing combine dimensions: exponents add and subtract.
- Arguments of
exp,logandsinmust be dimensionless. Ine^(-t/τ),tandτmust share units.
You can check a formula on paper before you run it. For example, the kinetic energy ½ m v² has dimensions M (L T⁻¹)² = M L² T⁻², which is energy, as it should be.
Worked example: a tiny dimension checker
Representing dimensions as exponent tuples lets code enforce those rules:
class Q:
def __init__(self, value, dims): # dims = (L, M, T)
self.value, self.dims = value, tuple(dims)
def __mul__(self, other):
return Q(self.value * other.value,
[a + b for a, b in zip(self.dims, other.dims)])
def __add__(self, other):
if self.dims != other.dims:
raise ValueError(f"cannot add {self.dims} and {other.dims}")
return Q(self.value + other.value, self.dims)
m = Q(1.0, (1, 0, 0)); s = Q(1.0, (0, 0, 1))
m + s # ValueError: cannot add (1, 0, 0) and (0, 0, 1)
That is the core idea behind every units library.
Strategy 3: a units library (pint)
For real work, use a library. pint is the common choice in scientific Python:
import pint
ureg = pint.UnitRegistry()
Q_ = ureg.Quantity
force = 2.5 * ureg.kilonewton
area = (40 * ureg.mm) * (10 * ureg.mm)
stress = (force / area).to("MPa")
print(stress) # 6.25 megapascal
flow = 40 * ureg("L/min")
print(flow.to("m**3/s")) # 0.000667 m³/s
T = Q_(25, ureg.degC).to("K") # 298.15 kelvin (handles the offset)
(3 * ureg.m) + (2 * ureg.s) # raises DimensionalityError
pint works with NumPy arrays (np.array([1, 2, 3]) * ureg.m), and .magnitude / .m_as("unit") give you the plain number when a function needs one. Other options are astropy.units (astronomy and physics) and unyt. pint is not loaded in this course's browser exercises, so the Do tab builds the dimension-checking idea yourself; install pint with pip install pint for local work.
Significant figures and reporting
Units come with precision. Report results with a sensible number of significant figures and the unit, 6.25 MPa, not 6.249999999 MPa or a bare 6.25. In tables, put the unit in the column header (Stress (MPa)).
Common mistakes
- Mixing mm and m in one formula, especially in areas and volumes, where the error is a factor of 10⁶ or 10⁹.
- °C in an absolute-temperature formula (ideal gas, Arrhenius, Stefan-Boltzmann).
- Gauge versus absolute pressure (psig versus psia, or kPa(g) versus kPa(a)).
- Degrees versus radians:
np.sin(30)is the sine of 30 radians. - Pound-mass versus pound-force, and kWh versus kW.
- Converting halfway through a calculation instead of at the edges.
Quick recap
- Convert inputs to SI on entry, compute in SI, convert on output; name conversion constants.
- Only add or compare quantities with equal dimensions;
exp,log,sinneed dimensionless arguments. - Use pint (or astropy.units) to make the computer enforce this; watch temperature offsets.
- Report results with units and sensible precision.
Try it
In the Do tab you will finish a small Quantity class that tracks dimensions, then use it to compute a speed and a force and catch an illegal addition.