Repository: Ouranosinc/xclim
Pull request #357 (2020-02-05 19:38:27)

Fix units problem for tas (and atmos.tg)
<!--Please ensure the PR fulfills the following requirements! -->
<!-- If this is your first PR, make sure to add your details to the AUTHORS.rst! -->
### Pull Request Checklist:
- [x] This PR addresses an opened issue (for bug fixes / features)
    - This PR fixes an issue raised in a private internal xclim-mailing list 
- [x] Tests for the changes have been added (for bug fixes / features)
- [x] Documentation has been added / updated (for bug fixes / features)
- [ ] HISTORY.rst has been updated (with summary of main changes)
- [ ] `bumpversion (minor / major / patch)` has been called on this branch
- [ ] Tags have been pushed (`git push --tags`)

* **What kind of change does this PR introduce?** <!--(Bug fix, feature, docs update, etc.)-->

Previous PR #312 had a bug where units of `xclim.indices.tas` (and `atmos.tg`) were set to "K" no matter what the input units were. Now `tasmax` is converted to units of `tasmin` and the output is explicitly set to units of `tasmin`.  If "degC" (or ergs or Rankin or °F) were to be used, then `atmos.tg` would convert them to "K", but `xclim.indices.tas` would keep them the same.

* **Does this PR introduce a breaking change?** <!--(Has there been an API change?)-->

No

* **Other information**:

Do I need to update History.rst for such a minor change? 

coveralls: ## Pull Request Test Coverage Report for [Build 1529](https://coveralls.io/builds/28551837)

* **5** of **5**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.02%**) to **87.976%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/28551837/badge)](https://coveralls.io/builds/28551837) |
| :-- | --: |
| Change from base [Build 1516](https://coveralls.io/builds/28507616): |  0.02% |
| Covered Lines: | 1939 |
| Relevant Lines: | 2204 |

---
##### 💛  - [Coveralls](https://coveralls.io)

coveralls: ## Pull Request Test Coverage Report for [Build 1529](https://coveralls.io/builds/28551837)

* **5** of **5**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.02%**) to **87.976%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/28551837/badge)](https://coveralls.io/builds/28551837) |
| :-- | --: |
| Change from base [Build 1516](https://coveralls.io/builds/28507616): |  0.02% |
| Covered Lines: | 1939 |
| Relevant Lines: | 2204 |

---
##### 💛  - [Coveralls](https://coveralls.io)

aulemahal: I forgot to install pre-commit on my laptop's copy of the repo, toutes mes excuses.

Patch:
diff --git a/xclim/indices/_multivariate.py b/xclim/indices/_multivariate.py
index b608c526..e63ccd46 100644
--- a/xclim/indices/_multivariate.py
+++ b/xclim/indices/_multivariate.py
@@ -965,7 +965,7 @@ def fraction_over_precip_thresh(
     return over / total
 
 
-@declare_units("K", tasmin="[temperature]", tasmax="[temperature]")
+@declare_units("[temperature]", tasmin="[temperature]", tasmax="[temperature]")
 def tas(tasmin: xarray.DataArray, tasmax: xarray.DataArray) -> xarray.DataArray:
     """Average temperature from minimum and maximum temperatures.
 
@@ -981,9 +981,12 @@ def tas(tasmin: xarray.DataArray, tasmax: xarray.DataArray) -> xarray.DataArray:
     Returns
     -------
     xarray.DataArray
-        Mean (daily) temperature [°C]
+        Mean (daily) temperature [same units as tasmin]
     """
-    return (tasmax + tasmin) / 2
+    tasmax = utils.convert_units_to(tasmax, tasmin)
+    tas = (tasmax + tasmin) / 2
+    tas.attrs["units"] = tasmin.attrs["units"]
+    return tas
 
 
 @declare_units("days", tas="[temperature]", t90="[temperature]")


Test patch:
diff --git a/tests/test_indices.py b/tests/test_indices.py
index ac792b81..6e62b54f 100644
--- a/tests/test_indices.py
+++ b/tests/test_indices.py
@@ -733,12 +733,20 @@ class TestTGXN90p:
 
 
 class TestTas:
-    def test_tas(self, tasmin_series, tasmax_series, tas_series):
-        tas = tas_series(np.ones(10))
-        tasmin = tasmin_series(np.zeros(10))
-        tasmax = tasmax_series(np.ones(10) * 2)
+    @pytest.mark.parametrize("tasmin_units", ["K", "degC"])
+    @pytest.mark.parametrize("tasmax_units", ["K", "degC"])
+    def test_tas(
+        self, tasmin_series, tasmax_series, tas_series, tasmin_units, tasmax_units
+    ):
+        tas = tas_series(np.ones(10) + (K2C if tasmin_units == "K" else 0))
+        tas.attrs["units"] = tasmin_units
+        tasmin = tasmin_series(np.zeros(10) + (K2C if tasmin_units == "K" else 0))
+        tasmin.attrs["units"] = tasmin_units
+        tasmax = tasmax_series(np.ones(10) * 2 + (K2C if tasmax_units == "K" else 0))
+        tasmax.attrs["units"] = tasmax_units
 
         tas_xc = xci.tas(tasmin, tasmax)
+        assert tas_xc.attrs["units"] == tasmin_units
         xr.testing.assert_equal(tas, tas_xc)