Repository: yt-project/unyt (python)

Issue:
Temperature unit degree Celcius with SI prefixes has wrong value.
* unyt version: v2.7.2
* Python version: 3.8.6
* Operating System: Ubuntu 18.04

### Description

NIST SP811 permits the use of SI prefixes with degree Celcius, but `unyt` gives the wrong value.

### What I Did

```
>>> from unyt.testing import allclose_units
>>> from unyt import mdegC, degC, K
>>> (1*mdegC).in_base()
unyt_quantity(0.27415, 'K')
>>> (0.001*degC).in_base()
unyt_quantity(273.151, 'K')
>>>allclose_units(1*mdegC, 0.001*degC)
False
```


Pull request:
Fix SI prefix scaling of degree Celsius
Closes #175

Patch:
diff --git a/unyt/unit_object.py b/unyt/unit_object.py
index 54f74ed..be2546f 100644
--- a/unyt/unit_object.py
+++ b/unyt/unit_object.py
@@ -936,13 +936,25 @@ def _get_conversion_factor(old_units, new_units, dtype):
         raise UnitConversionError(
             old_units, old_units.dimensions, new_units, new_units.dimensions
         )
-    ratio = old_units.base_value / new_units.base_value
-    if old_units.base_offset == 0 and new_units.base_offset == 0:
+    old_basevalue = old_units.base_value
+    old_baseoffset = old_units.base_offset
+    new_basevalue = new_units.base_value
+    new_baseoffset = new_units.base_offset
+    ratio = old_basevalue / new_basevalue
+    if old_baseoffset == 0 and new_baseoffset == 0:
         return (ratio, None)
     else:
-        # the dimensions are the same, so both are temperatures, where
-        # it's legal to convert units so no need to do error checking
-        return ratio, ratio * old_units.base_offset - new_units.base_offset
+        # the dimensions are either temperature or angle (lat, lon)
+        if old_units.dimensions == temperature:
+            # for degree Celsius, back out the SI prefix scaling from
+            # offset scaling for degree Fahrenheit
+            old_prefix, _ = _split_prefix(str(old_units), old_units.registry.lut)
+            if old_prefix != "":
+                old_baseoffset /= old_basevalue
+            new_prefix, _ = _split_prefix(str(new_units), new_units.registry.lut)
+            if new_prefix != "":
+                new_baseoffset /= new_basevalue
+        return ratio, ratio * old_baseoffset - new_baseoffset
 
 
 #


Test patch:
diff --git a/unyt/tests/test_units.py b/unyt/tests/test_units.py
index cc509fd..66a16a4 100644
--- a/unyt/tests/test_units.py
+++ b/unyt/tests/test_units.py
@@ -858,6 +858,16 @@ def test_degC():
     assert str(a) == "1 °C"
 
 
+def test_degC_with_SIprefixes():
+    assert_allclose_units(1 * Unit("mdegC"), 0.001 * Unit("degC"))
+    assert_allclose_units(1 * Unit("degC"), 1000 * Unit("mdegC"))
+    assert_allclose_units(73 * Unit("degF"), 22777.779 * Unit("mdegC"))
+    assert_allclose_units(22777.779 * Unit("mdegC"), 73 * Unit("degF"))
+    assert_allclose_units(22777.779 * Unit("mdegC"), 532.67 * Unit("R"))
+    assert_allclose_units(1 * Unit("mK"), -273149.0 * Unit("mdegC"))
+    assert_allclose_units(1 * Unit("mdegC"), 273151.0 * Unit("mK"))
+
+
 def test_delta_degC():
     a = 1 * Unit("delta_degC")
     assert str(a) == "1 Δ°C"