Solo project
Unit-Checker
Static analysis for physical dimensions in scientific code
Unit-Checker infers and verifies physical units in scientific code so dimensional mistakes can be caught before a long simulation quietly produces nonsense.
Why this matters
Scientific programs are full of quantities with physical units: meters, seconds, kilograms, pascals. Programming languages do not understand any of that structure by default. As far as the compiler is concerned, they are all just numbers.
That means you can add a force to a velocity, multiply pressure by time when you meant to divide, or pass imperial data into an SI calculation and still get output that looks plausible. That is the kind of bug Unit-Checker is built to expose.
# Mars Climate Orbiter style mismatch
thrust_impulse_lm = 500.0 # lbf*s
thrust_impulse_jpl = 200.0 # N*s
total_impulse = thrust_impulse_lm + thrust_impulse_jpl
error: cannot add imperial impulse
to SI impulse without conversionA concrete Navier-Stokes example
A good project page for Unit-Checker should show a real example, not just a slogan. In the snippet below, the pressure gradient is being added directly to acceleration terms without dividing by density first.
The code still runs, but the dimensions do not make sense. Unit-Checker follows the units through the computation and flags the bad line before the simulation ever reaches runtime.
# @units: rho [kg/m³], v [m/s], P [Pa], mu [Pa·s], g [m/s²], dt [s]
def navier_stokes_step(rho, v_x, v_y, P, mu, dx, dy, dt, g):
dP_dx = (P[1:, :] - P[:-1, :]) / dx
dP_dy = (P[:, 1:] - P[:, :-1]) / dy
laplacian_vx = (v_x[2:,:] - 2*v_x[1:-1,:] + v_x[:-2,:]) / dx**2
visc_x = mu * laplacian_vx / rho
advect_x = v_x * (v_x[1:,:] - v_x[:-1,:]) / dx
# dimensional error
accel_x = -dP_dx + visc_x - advect_x + g
v_x_new = v_x[1:-1,:] + accel_x * dt
return v_x_newHow dimensions are represented
Internally, every quantity is represented as a seven-component SI base-dimension vector. That makes it possible to propagate units algebraically through arbitrary expressions instead of depending on a hand-maintained list of derived-unit names.
| Quantity | Symbol | Unit | Vector |
|---|---|---|---|
| Length | L | m | [1, 0, 0, 0, 0, 0, 0] |
| Mass | M | kg | [0, 1, 0, 0, 0, 0, 0] |
| Time | T | s | [0, 0, 1, 0, 0, 0, 0] |
| Current | I | A | [0, 0, 0, 1, 0, 0, 0] |
| Temperature | Θ | K | [0, 0, 0, 0, 1, 0, 0] |
| Amount | N | mol | [0, 0, 0, 0, 0, 1, 0] |
| Luminous intensity | J | cd | [0, 0, 0, 0, 0, 0, 1] |
| Velocity | v | m/s | [1, 0, -1, 0, 0, 0, 0] |
| Force | F | N | [1, 1, -2, 0, 0, 0, 0] |
| Pressure | P | Pa | [-1, 1, -2, 0, 0, 0, 0] |
| Energy | E | J | [2, 1, -2, 0, 0, 0, 0] |
| Dynamic viscosity | μ | Pa·s | [-1, 1, -1, 0, 0, 0, 0] |
What I want this project page to show
The point of this project page is to make the idea legible very quickly: sparse annotations go in, dimension vectors propagate through code, and the tool surfaces the exact expression where the physics stops making sense.