4 ms·
I'd like to point to a separate library for dealing with units: Barril https://github.com/ESSS/barril https://github.com/ESSS/barril Docs at: https://barril.r
by fabioz 5y ago
I'd like to point to a separate library for dealing with units: Barril
https://github.com/ESSS/barril https://github.com/ESSS/barril
Docs at: https://barril.readthedocs.io/en/latest/ 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 https://barril.readthedocs.io/en/latest/units.html and the implementation: https://github.com/ESSS/barril/blob/master/src/barril/units/posc.py 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.
- arnsholt 5y agoI did some code for an O&G company a couple of years ago and was reasonably happy with pint,but barril looks like it might have been even better. The handling of dimensionless stuff like volume by volume was a point I was never quite happy with in pint.
- heisenzombie 5y agoThanks for pointing this out. I was excited to give barril a test because I am a regular user of pint. I'm going to be a bit negative about barril below, but I'm doing it in case other people are looking an interested in a comparison. 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.
- fabioz 5y agoInternally the library has a "quantity type", which defines for a given quantity all the given conversions that are valid in the database and a "category" which is used so that you can create subsets of units which you want to consider valid for your application. 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/unit_database.py#L175 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).
- heisenzombie 5y agoHm, that's very interesting, thanks. I think I'm approaching this from a physics perspective, where units and dimensional analysis are very important, and there's a very specific formalism and philosophy involved. For example, dimensionless quantities are deeply meaningful -- see the Buckingham pi theorem for example. 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/physics6.pdf 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.