Units conversion in Python
Asked Answered
O

4

11

SymPy is a great tool for doing units conversions in Python:

>>> from sympy.physics import units
>>> 12. * units.inch / units.m
0.304800000000000

You can easily roll your own:

>>> units.BTU = 1055.05585 * units.J
>>> units.BTU
1055.05585*m**2*kg/s**2

However, I cannot implement this into my application unless I can convert degrees C (absolute) to K to degrees F to degrees R, or any combo thereof.

I thought maybe something like this would work:

units.degC = <<somefunc of units.K>>

But clearly that is the wrong path to go down. Any suggestions for cleanly implementing "offset"-type units conversions in SymPy?

Note: I'm open to trying other units conversion modules, but don't know of any besides Unum, and found it to be cumbersome.

Edit: OK, it is now clear that what I want to do is first determine if the two quantities to be compared are in the same coordinate system. (like time units reference to different epochs or time zones or dB to straight amplitude), make the appropriate transformation, then make the conversion. Are there any general coordinate system management tools? That would be great.

I would make the assumption that °F and °C always refer to Δ°F Δ°C within an expression but refer to absolute when standing alone. I was just wondering if there was a way to make units.degF a function and slap a decorator property() on it to deal with those two conditions.

But for now, I'll set units.C == units.K and try to make it very clear in the documentation to use functions convertCtoK(...) and convertFtoR(...) when dealing with absolute units. (Just kidding. No I won't.)

Oppression answered 22/6, 2009 at 0:41 Comment(3)
Too bad sympy.physics.units has no documentation.Tadd
GNU Units separates them into degF and tempF(x): gnu.org/software/units/manual/…Belanger
Also sympy.physics.units works completely different now, it does not return simple floats anymore.Generalist
N
4

I personally like Quantities thanks to its NumPy integration, however it only does relative temperatures, not absolute.

Nonie answered 22/6, 2009 at 1:7 Comment(1)
I think you might have me sold on Quantities. Nice and lightwieght, numpy integration, and /uncertainties/ to boot. Thank you. ..still looking for a decent work-around for the "offset coordinate system problem".Oppression
G
8

The Unum documentation has a pretty good writeup on why this is hard:

Unum is unable to handle reliably conversions between °Celsius and Kelvin. The issue is referred as the 'false origin problem' : the 0°Celsius is defined as 273.15 K. This is really a special and annoying case, since in general the value 0 is unaffected by unit conversion, e.g. 0 [m] = 0 [miles] = ... . Here, the conversion Kelvin/°Celsius is characterized by a factor 1 and an offset of 273.15 K. The offset is not feasible in the current version of Unum.

Moreover it will presumably never be integrated in a future version because there is also a conceptual problem : the offset should be applied if the quantity represents an absolute temperature, but it shouldn't if the quantity represents a difference of temperatures. For instance, a raise of temperature of 1° Celsius is equivalent to a raise of 1 K. It is impossible to guess what is in the user mind, whether it's an absolute or a relative temperature. The question of absolute vs relative quantities is unimportant for other units since the answer does not impact the conversion rule. Unum is unable to make the distinction between the two cases.

It's pretty easy to conceptually see the problems with trying to represent absolute temperature conversion symbolically. With any normal relative unit, (x unit) * 2 == (x * 2) unit—unit math is commutative. With absolute temperatures, that breaks down—it's difficult to do anything more complex than straight temperature conversions with no other unit dimensions. You're probably best off keeping all calculations in Kelvin, and converting to and from other temperature units only at the entry and exit points of your code.

Gentilesse answered 22/6, 2009 at 1:0 Comment(5)
There is a reason that there are both datetime and timedelta objects. What prevents to do the same for temperature?Rotman
You could do it, you just can't integrate the absolute temperature units into a symbolic math library where unit math is commutative.Gentilesse
You can integrate it just fine. See my answer https://mcmap.net/q/999107/-units-conversion-in-python/…Rotman
To any future reader: please be VERY careful with Unum. Unum is unmaintained since ages, and it uses a function called as, which is a reserved keyword in python 2.6. Consider the Quantities module instead.Nikolas
That's a pretty weak excuse. GNU Units can handle both degC (relative) and tempC (absolute). It can handle decibels, too, which involve a logarithm for conversion.Belanger
N
4

I personally like Quantities thanks to its NumPy integration, however it only does relative temperatures, not absolute.

Nonie answered 22/6, 2009 at 1:7 Comment(1)
I think you might have me sold on Quantities. Nice and lightwieght, numpy integration, and /uncertainties/ to boot. Thank you. ..still looking for a decent work-around for the "offset coordinate system problem".Oppression
R
0

Example, how it could work:

>>> T(0*F) + 10*C
T(265.37222222222221*K) # or T(47767/180*K)
>>> T(0*F + 10*C)
T(283.15*K)
>>> 0*F + T(10*C)
T(283.15*K)
>>> 0*F + 10*C
10*K
>>> T(0*F) + T(10*C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'absolute_temperature' and \
'absolute_temperature'
>>> T(0*F) - T(10*C)
T(245.37222222222223*K) # or T(44167/180*K)
>>> 0*F - 10*C
-10*K
Rotman answered 22/6, 2009 at 2:4 Comment(6)
@Miles: Thanks for making your comment as cryptic as the answer! Something got left out of the copy/paste. T is a Tesla in physics.units. But I assume I'm to redefine it myself..Oppression
@bpowah: T is absolute_temperature here.Rotman
@Miles: 0*F, 10*C - relative temperatures (not absolute) in Fahrenheit and Celsius degrees correspondingly. It is not physics.units, just similar syntax.Rotman
@J.F. Sebastian: I understand that. My comment is that T(0*F + 10*C) == T(283.15*K) doesn't make any sense, because that's saying T(10*K) == T(283.15*K). It's difficult to have 10*C == 10*K while having T(10*C) == T(283.15*K).Gentilesse
I'm not denying that it's possible to have a way to represent absolute and relative temperature units. I'm just saying that it's tricky to get right, especially when it comes time to use them in physical formulas like the ideal gas laws.Gentilesse
@Miles: You're right. To be consistent T(0*F+10*C) should be T(10*K) in the above examples. If we allow 10*C -> 10*K replacement then T() needs second argument that specifies temperature scale: TC(10*K)==TC(10*C)==TC(18*F)==TF(50*F)==TF(250/9*C)==TF(250/9*K)==T(283.15*K)==T(283.15*C)==T(509.67*F).Rotman
M
0

The natu package handles units of temperature. For instance, you can do this:

>>> from natu.units import K, degC, degF
>>> T = 25*degC
>>> T/K
298.1500
>>> T/degF
77.0000
>>> 0*degC + 100*K
100.0 degC

Prefixes are supported too:

>>> from natu.units import mdegC
>>> 100*mdegC/K
273.2500

natu also handles nonlinear units such as the decibel, not just those with offsets like degree Celsius and degree Fahrenheit.

Relating to the first example you gave, you can do this:

>>> from natu import units
>>> 12*units.inch/units.m
0.3048

BTU is already built in. You can change its display unit to m**2*kg/s**2, but by default natu simplifies the unit to J:

>>> from natu.units import BTU
>>> BTU.display = 'm2*kg/s2'
>>> 1*BTU
1055.05585262 J
Molybdenite answered 8/8, 2014 at 20:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.