Pint – A Python package to define, operate and manipulate physical quantities
pint.readthedocs.io
pint.readthedocs.io
https://docs.sympy.org/latest/modules/physics/units/index.ht...
(edit: I'm very biased; Sympy's docs and code gave me a lot of fundamental mathematical intuitions -in python- that my education hasn't.)
Dependency free: it depends only on Python and its standard library. It interacts with other packages like numpy and uncertainties if they are installed
https://github.com/ESSS/barril
Docs at: https://barril.readthedocs.io/en/latest/
While it does have support for creating "random" units from computation (such as Pint, unum, etc), it's more tailored to having a database of units (which the library has by default -- see: https://barril.readthedocs.io/en/latest/units.html and the implementation: https://github.com/ESSS/barril/blob/master/src/barril/units/...) and then you can query and transform based on the related units.
One thing it supports that does a lot of difference in that regard is dealing with unit conversions which would be "dimentionless" -- such as m3/m3 (i.e.:`volume per volume`) and then converting to `cm3/m3` and keeping the dimension.
i.e.: in pint:
>>> import pint
>>> ureg = pint.UnitRegistry()
>>> m = ureg.meter
>>> v = 1 \* (m\*3)/(m\*3)
>>> v
<Quantity(1.0, 'dimensionless')>
And then, after that (as far as I know), it's not really possible to do additional unit conversions properly knowing that it was m3/m3.In barril:
>>> from barril.units import Scalar
>>> a = Scalar(3, 'm3/m3')
>>> a.GetValue('cm3/m3')
3000000.0
>>> a.category
'volume per volume'
>>> a.unit
'm3/m3'
and something as `a.GetValue('m3')` (with an invalid value) would give an error saying that the conversion is actually invalid.The unit database (which was initially based on the POSC Units of Measure Dictionary) is a bit more tailored for the Oil & Gas field, but should be usable outside of it too.
First off, you can definitely do conversions between different dimensionless quantities:
from pint import Quantity
a = Quantity(3, 'm^3/m^3')
a.to('cm^3/m^3')
does what you'd expect. There's no problem with converting between different "dimensionless" units.I don't really understand what the "category" is, though, so maybe I'm missing the point? I notice that some units can be in multiple categories, e.g. "J" can be a "moment of force" or an "energy", but I can still do:
a = Scalar(5.0, 'J', 'moment of force')
b = Scalar(10.0, 'J', 'energy')
c = a / b
c.category
>>> ''
d = a + b
d.category
>>> 'moment of force'
That seems a bit inscrutable. What is a category and why am I keeping track of it? I think this might be the core of why barril is useful to some people but I don't understand it.The biggest thing I found playing with barril is that while I can multiply 3 lengths together to get a volume; if I multiply a density by a volume and ask for a mass it throws an exception. Like they've just special-cased some specific conversions rather than doing dimensional analysis? This seems like the core functionality of a units library so I'm a bit confused again if I've missed something.
It's helpful in the context that you want to restrict what's valid for such a category (see: https://github.com/ESSS/barril/blob/master/src/barril/units/... for what that means -- think of defining a "cylinder width" as a subset of "length").
As a note, it's main use-case is NOT doing computations such as dividing/multiplying Scalars (albeit that's supported it does have some caveats -- so, while it also does dimensional analysis, it's really not the core functionality), rather the core functionality is making the conversions based on what's available in the unit database (so, you're not supposed to be creating units out of the unit database, rather, you want to collect input from the units you support and then make your conversions to other units you still support -- think of doing validation of input, converting to values in units expected by the user, defining a unit-system for input, converting to your internal unit-system for actual computation in C/C++, ...).
So, I guess it depends on what you consider as core for a units library. As I mentioned, it's created for an Oil & Gas use-case -- albeit it's also used in other engineering-related projects -- where the units are all pretty much well mapped in the application and you're worried that you are getting into units you're not expecting and that'd actually be an error.
p.s.: if you have specific use-cases which don't work as you expect, I suggest contacting the library maintainers -- once that was me, but it's been a while ;)
p.s.: thanks for letting me know about how to deal with dimensionless units in pint (I wasn't aware of that).
On the other hand, I think this library seems very pragmatic: It doesn't match my "rigorous" ideas about units but that's fine because it's actually trying to do something else.
As I understand it, the idea is that I can't /necessarily/ give a quantity of "250 mm" to a function that expects a length because, for example, the quantity might be of category "rod length" and the function expects a "cylinder width". The /units/ match, but the /category/ does not.
That's very interesting and I see why it's useful. It strikes me as trying to be something like a type system, with pre-defined types for physical units that you "subclass" or "parameterize". I think this is something I will think about quite a bit more.
I should also thank you because (over) thinking about this has already led me to discover the idea of "parametric units":
http://ingvar.web03.cefit.se/wp-content/uploads/2016/02/phys...
... which seems related even if I can't quite put my finger on exactly how.
- buy me a fluid dram
- buy me a pint
- buy me a liter
- buy me a quart
- buy me a barrel
- buy me a cubic yard
- but me a cubic meter
For command line, if you haven't experienced GNU Units, I highly recommend it. [1]
Anyway, cool project.
>>> [3, 4] * ureg.meter + [4, 3] * ureg.cm
<Quantity([ 3.04 4.03], 'meter')>
This numpy example was confusing to me because of the digit reuse; it looked to me like the second quantity should have been in metres. I think something like this would have been better: >>> [3, 4] * ureg.meter + [5, 6] * ureg.cm
<Quantity([ 3.05 4.06], 'meter')> >>> 3 * units.meter + 4 * units.cm
So the `units` variable should be named that way to accommodate.I'm not a fan of either. To the point where I'm wondering about the feasibility of having the API work like:
from pint.default import meter, cm
length = 3 * meter + 4 * cm from pint.units import meter, cm
:) Or whatever you fancy! I'm just someone in the comment section after all.I’d be presuming this library caters mainly to the US variant?
[0] https://en.m.wikipedia.org/wiki/Comparison_of_the_imperial_a...
Plus it also looks like the author has thought this through in a very comprehensive manner:
* Using contexts for unit redefinition
The exact definition of a unit of measure can change slightly depending on the country, year, and more in general convention. For example, the ISO board released over the years several revisions of its whitepapers, which subtly change the value of some of the more obscure units. And as soon as one steps out of the SI system and starts wandering into imperial and colonial measuring systems, the same unit may start being defined slightly differently every time - with no clear ‘right’ or ‘wrong’ definition.
The default pint definitions file (default_en.txt) tries to mitigate the problem by offering multiple variants of the same unit by calling them with different names; for example, one will find multiple definitions of a “BTU”:
british_thermal_unit = 1055.056 * joule = Btu = BTU = Btu_iso international_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * international_calorie = Btu_it thermochemical_british_thermal_unit = 1e3 * pound / kilogram * degR / kelvin * calorie = Btu_th That’s sometimes insufficient, as Wikipedia reports no less than 6 different definitions for BTU, and it’s entirely possible that some companies in the energy sector, or even individual energy contracts, may redefine it to something new entirely, e.g. with a different rounding.
Pint allows changing the definition of a unit within the scope of a context. This allows layering; in the example above, a company may use the global definition of BTU from default_en.txt above, then override it with a customer-specific one in a context, and then override it again with a contract-specific one on top of it.*
How truly wonderful. I’m delighted to see this level of diligence. Too often you see these “clickbait” libraries that seem to do something great but then you scratch the surface and see there’s a lot of stuff not fully thought out.
Top marks.
Take the kilogram for example, the definition of the kilogram drifted until the relatively recent decision to define it based on the Planck constant (because previously it used physical Prototypes and those are subject to change over time like any object), but the drift was tiny, less than 30ppm over centuries. If you have an ordinary mass of something, the drift in definition of the kilogram makes far less difference than inaccuracies of your measuring scales, dust settling on the object measured and other factors.
You don't in fact care whether that's a 1885 kilogram of potatoes or a 2021 kilogram of potatoes, because you won't be measuring potatoes to a precision where the difference matters.
In contrast you would presumably care whether you were served a US pint of beer of ~473ml or a UK pint of beer of ~568ml. Quite a difference to a hobbit at least.
[0] https://reference.wolfram.com/language/ref/Quantity.html
ureg = pint.UnitRegistry()
3 * ureg.meter + 4 * ureg.cm
Why is this an object? Shouldn't this be static?(though I can't actually tell if this is the US pint or the UK pint)
It was actually university that taught me the millilitre size of a pint: the SU bars at my alma mater, Imperial, are named Metric & 568.
I think the US pint is something like 476ml (checked; it's 473), and the UK pint is 20 /slightly/ smaller than US oz instead of 16.
Sadly this is also why I dropped Pint quickly. It does not integrate with annotations nicely.