Skip to content

Commit

Permalink
Fix for Fahrenheit deltas, degree-days and others. (#1804)
Browse files Browse the repository at this point in the history
### What kind of change does this PR introduce?

* New function `ensure_absolute_temperature` that converts temperature
units to their absolute counterpart _assuming_ they represented a delta.
So °C becomes K and °F becomes °R. Anything else goes unmodified
(including compound units like `°C m` (whatever that means)).
* Use this function in `to_agg_units` to ensure a correct output for
`op` "std", "var" and "integral".

### Does this PR introduce a breaking change?

No.

### Other information:

Pint has "delta_degC" and "delta_degF" for temperature differences, but
CF does not. So this new function helps in the specific case where we
know the data is delta-like, which happens for the given `op`.
  • Loading branch information
Zeitsperre authored Jul 3, 2024
2 parents 86b6bc5 + 9b1889a commit 26a47ef
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 5 deletions.
6 changes: 5 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ Changelog

v0.51.0 (unreleased)
--------------------
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`).
Contributors to this version: Trevor James Smith (:user:`Zeitsperre`), Pascal Bourgault (:user:`aulemahal`).

Bug fixes
^^^^^^^^^
* Units of degree-days computations with Fahrenheit input fixed to yield "°R d". Added a new ``xclim.core.units.ensure_absolute_temperature`` method to convert from delta to absolute temperatures. (:issue:`1789`, :pull:`1804`).

New features and enhancements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions tests/test_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ def index(
("", "sum", "count", 365, "d"),
("kg m-2", "var", "var", 0, "kg2 m-4"),
("°C", "argmax", "doymax", 0, ""),
("°C", "sum", "integral", 365, "K d"),
("°F", "sum", "integral", 365, "d °R"), # not sure why the order is different
],
)
def test_to_agg_units(in_u, opfunc, op, exp, exp_u):
Expand Down
32 changes: 28 additions & 4 deletions xclim/core/units.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,25 @@ def infer_sampling_units(
return out


DELTA_ABSOLUTE_TEMP = {
units.delta_degC: units.kelvin,
units.delta_degF: units.rankine,
}


def ensure_absolute_temperature(units: str):
"""Convert temperature units to their absolute counterpart, assuming they represented a difference (delta).
Celsius becomes Kelvin, Fahrenheit becomes Rankine. Does nothing for other units.
"""
a = str2pint(units)
# ensure a delta pint unit
a = a - 0 * a
if a.units in DELTA_ABSOLUTE_TEMP:
return pint2cfunits(DELTA_ABSOLUTE_TEMP[a.units])
return units


def to_agg_units(
out: xr.DataArray, orig: xr.DataArray, op: str, dim: str = "time"
) -> xr.DataArray:
Expand Down Expand Up @@ -518,19 +537,24 @@ def to_agg_units(
>>> degdays = dt.clip(0).sum("time") # Integral of temperature above a threshold
>>> degdays = to_agg_units(degdays, dt, op="integral")
>>> degdays.units
'week delta_degC'
'K week'
Which we can always convert to the more common "K days":
>>> degdays = convert_units_to(degdays, "K days")
>>> degdays.units
'K d'
"""
if op in ["amin", "min", "amax", "max", "mean", "std", "sum"]:
if op in ["amin", "min", "amax", "max", "mean", "sum"]:
out.attrs["units"] = orig.attrs["units"]

elif op in ["std"]:
out.attrs["units"] = ensure_absolute_temperature(orig.attrs["units"])

elif op in ["var"]:
out.attrs["units"] = pint2cfunits(str2pint(orig.units) ** 2)
out.attrs["units"] = pint2cfunits(
str2pint(ensure_absolute_temperature(orig.units)) ** 2
)

elif op in ["doymin", "doymax"]:
out.attrs.update(
Expand All @@ -539,7 +563,7 @@ def to_agg_units(

elif op in ["count", "integral"]:
m, freq_u_raw = infer_sampling_units(orig[dim])
orig_u = str2pint(orig.units)
orig_u = str2pint(ensure_absolute_temperature(orig.units))
freq_u = str2pint(freq_u_raw)
out = out * m

Expand Down

0 comments on commit 26a47ef

Please sign in to comment.