views:

1059

answers:

3

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. If anyone knows of 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)

+5  A: 

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.

Miles
There is a reason that there are both datetime and timedelta objects. What prevents to do the same for temperature?
J.F. Sebastian
You could do it, you just can't integrate the absolute temperature units into a symbolic math library where unit math is commutative.
Miles
You can integrate it just fine. See my answer http://stackoverflow.com/questions/1025145/units-conversion-in-python/1025258#1025258
J.F. Sebastian
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.
Stefano Borini
+2  A: 

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

Autoplectic
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".
bpowah
A: 

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
J.F. Sebastian
>>> T(0*F + 10*C) # ?
Miles
@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..
bpowah
@bpowah: `T` is `absolute_temperature` here.
J.F. Sebastian
@Miles: 0*F, 10*C - relative temperatures (not absolute) in Fahrenheit and Celsius degrees correspondingly. It is not `physics.units`, just similar syntax.
J.F. Sebastian
@J.F. Ok, I get it now. Spasiba.
bpowah
@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).
Miles
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.
Miles
@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).
J.F. Sebastian