Skip to content

wgbowley/PicoUnits

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PicoUnits

Explicit units and dimensional analysis for scientific Python – Built with care by William Bowley


Writing experimental physics models? Need to check dimensions at boundaries? Annoyed by vague configuration files? PicoUnits might be what you're looking for.

PicoUnits is a lightweight dimensional analysis library and DSL for writing dimensionally explicit Python code. PicoUnits support real numbers, complex numbers, and arrays based vectors. It is also a custom DSL called .uiv (unit-informed values), which allows for explicit units in configuration or reference libraries.

PicoUnits: Usage

Python Version License

Picounit is a single dependency (numpy) Python package that does dimensional analysis at runtime. Key features:

  • Pluggable unit systems: Define custom "Unit Frames" for your domain
  • Configuration format: .uiv files with embedded, validated units & .ut for unit types
  • Boundary validation: @unit_validator decorators catch errors at function interfaces
  • Full numeric support: Real, complex, and array-based vectors

But instead of talking about it, let's see some examples:

>>> from PicoUnits import MILLI, LENGTH
>>> 12 * MILLI * LENGTH + 10 * LENGTH
>>> 10.012 (m)

As expected, it returns 10.01 meters, but what is a unit? A more exotic feature of PicoUnits is that its fundamental units are fully abstract. We call this the user's "Unit Frame"; by default, it's SI metric, but it could be astronomical units:

# With a custom .picounit file defining light-years as LENGTH:
>>> from PicoUnits import MILLI, LENGTH
>>> 12 * MILLI * LENGTH + 10 * LENGTH
>>> 10.012 (ly)

All depends on the users .picounit file, which can be generated via the command PicoUnits generate. Another feature is the ability to use the .ut (unit types) and .uiv (unit-informed values) formats, which PicoUnits loads in via recursive attribute injection. So instead of a nested list, you get a wonderful object-based loader.

[version]
format: 0.1.0
unit_frame: units.ut

[model]
voltage: 18 (V)
current_limit: 40 (A) 
time_steps: 50 u(s)

Your .picounit file defines your Unit Frame, your .ut defines any derived units and your .uiv files defines value:unit pairs. This ensures consistency-you can't accidentally load a config file expecting SI metric when your code is running in natural units.

>>> from PicoUnits.parser import Parser
>>> p = Parser(parameters.uiv)
>>> p.model.voltage
>>> 18 (V)

Well, we’ve looked at simple calculations, changing unit frames, and importing units. But what about dimensional checks? Well, the main one is the unit_validator, which is a decorator that checks dimensionally out of a function. Let's intentionally pass wrong units to see what happens:

>>> from PicoUnits import unit_validator, VOLTAGE, IMPEDANCE, CURRENT
>>> @unit_validator(VOLTAGE)
>>> def calculate_voltage(current, impedance):
>>>   return current * impedance
>>> 
>>> calculate_voltage((10+1j) * CURRENT ** 2, 10 * IMPEDANCE)
>>> DimensionError: 'calculate_voltage' returned kg·m²·s⁻³, expected kg·m²·s⁻³·A⁻¹

The unit_validator checks the dimensionality of the output to ensure it matches the expected type. It's very useful when prototyping as it compartmentalizes dimensional checking, decreasing mental overhead.

For a complete worked example, see the multi-stage coilgun simulation which uses PicoUnits for electromagnetic physics calculations.

Documentation

Full documentation is available at docs, and simple to advanced examples are available at examples

Installation

To install, simply:

pip install PicoUnits

or use setuptools locally:

git clone https://github.com/wgbowley/PicoUnits.git
cd PicoUnits
pip install -e .

About

Explicit Units and Dimensional Analysis for Scientific Python

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages