From 7460255638532989f43eeebce832a1acd99ec8ec Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Mon, 31 Jan 2022 20:45:12 +0100 Subject: [PATCH 1/3] Use FlexMeasures unit registry Signed-off-by: F.N. Claessen --- flexmeasures/utils/unit_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flexmeasures/utils/unit_utils.py b/flexmeasures/utils/unit_utils.py index 3aed31249..652d92e45 100644 --- a/flexmeasures/utils/unit_utils.py +++ b/flexmeasures/utils/unit_utils.py @@ -164,15 +164,15 @@ def convert_units( try: if isinstance(data, pd.Series): data = pd.Series( - pint.Quantity(data.values, from_unit) - .to(pint.Quantity(to_unit)) + ur.Quantity(data.values, from_unit) + .to(ur.Quantity(to_unit)) .magnitude, index=data.index, name=data.name, ) else: data = list( - pint.Quantity(data, from_unit).to(pint.Quantity(to_unit)).magnitude + ur.Quantity(data, from_unit).to(ur.Quantity(to_unit)).magnitude ) except pint.errors.DimensionalityError: multiplier = determine_unit_conversion_multiplier( From 5a1a61b7d4cf2fb5eb7bb29831c0714b93013934 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Mon, 31 Jan 2022 21:02:51 +0100 Subject: [PATCH 2/3] Fix and test conversion from -W to W Signed-off-by: F.N. Claessen --- flexmeasures/utils/tests/test_unit_utils.py | 5 +++++ flexmeasures/utils/unit_utils.py | 17 +++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/flexmeasures/utils/tests/test_unit_utils.py b/flexmeasures/utils/tests/test_unit_utils.py index 140a1fec2..0061a1a57 100644 --- a/flexmeasures/utils/tests/test_unit_utils.py +++ b/flexmeasures/utils/tests/test_unit_utils.py @@ -25,7 +25,12 @@ ("m³", "m³/h", 4, None), ("MW", "kW", 1000, None), ("kWh", "kW", 4, None), + ("-W", "W", -1, None), + ("l/(100km)", "l/km", 0.01, None), ("°C", "K", None, [273.15, 283.15, 284.15]), + # no support for combining an offset unit with a scaling factor, but this is also overly specific + # ("-°C", "K", None, [273.15, 263.15, 262.15]), + # ("l/(10°C)", "l/(°C)", 0.1, None), ], ) def test_convert_unit( diff --git a/flexmeasures/utils/unit_utils.py b/flexmeasures/utils/unit_utils.py index 652d92e45..c5c56c08a 100644 --- a/flexmeasures/utils/unit_utils.py +++ b/flexmeasures/utils/unit_utils.py @@ -161,19 +161,24 @@ def convert_units( """Updates data values to reflect the given unit conversion.""" if from_unit != to_unit: + magnitudes = data.values if isinstance(data, pd.Series) else data + try: + from_quantities = ur.Quantity(magnitudes, from_unit) + except ValueError as e: + # Catch units like "-W" and "100km" + if str(e) == "Unit expression cannot have a scaling factor.": + from_quantities = ur.Quantity(from_unit) * magnitudes + else: + raise e # reraise try: if isinstance(data, pd.Series): data = pd.Series( - ur.Quantity(data.values, from_unit) - .to(ur.Quantity(to_unit)) - .magnitude, + from_quantities.to(ur.Quantity(to_unit)).magnitude, index=data.index, name=data.name, ) else: - data = list( - ur.Quantity(data, from_unit).to(ur.Quantity(to_unit)).magnitude - ) + data = list(from_quantities.to(ur.Quantity(to_unit)).magnitude) except pint.errors.DimensionalityError: multiplier = determine_unit_conversion_multiplier( from_unit, to_unit, event_resolution From 79bb8c02744df30495cc74cbecb24a6f41c9ac11 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Mon, 31 Jan 2022 21:29:39 +0100 Subject: [PATCH 3/3] Refactor Signed-off-by: F.N. Claessen --- flexmeasures/utils/unit_utils.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/flexmeasures/utils/unit_utils.py b/flexmeasures/utils/unit_utils.py index c5c56c08a..264415659 100644 --- a/flexmeasures/utils/unit_utils.py +++ b/flexmeasures/utils/unit_utils.py @@ -3,6 +3,7 @@ from moneyed import list_all_currencies import importlib.resources as pkg_resources +import numpy as np import pandas as pd import pint @@ -161,30 +162,31 @@ def convert_units( """Updates data values to reflect the given unit conversion.""" if from_unit != to_unit: - magnitudes = data.values if isinstance(data, pd.Series) else data + from_magnitudes = ( + data.to_numpy() if isinstance(data, pd.Series) else np.asarray(data) + ) try: - from_quantities = ur.Quantity(magnitudes, from_unit) + from_quantities = ur.Quantity(from_magnitudes, from_unit) except ValueError as e: # Catch units like "-W" and "100km" if str(e) == "Unit expression cannot have a scaling factor.": - from_quantities = ur.Quantity(from_unit) * magnitudes + from_quantities = ur.Quantity(from_unit) * from_magnitudes else: raise e # reraise try: - if isinstance(data, pd.Series): - data = pd.Series( - from_quantities.to(ur.Quantity(to_unit)).magnitude, - index=data.index, - name=data.name, - ) - else: - data = list(from_quantities.to(ur.Quantity(to_unit)).magnitude) + to_magnitudes = from_quantities.to(ur.Quantity(to_unit)).magnitude except pint.errors.DimensionalityError: + # Catch multiplicative conversions that use the resolution, like "kWh/15min" to "kW" multiplier = determine_unit_conversion_multiplier( from_unit, to_unit, event_resolution ) - if isinstance(data, pd.Series): - data = multiplier * data - else: - data = [multiplier * value for value in data] + to_magnitudes = from_magnitudes * multiplier + if isinstance(data, pd.Series): + data = pd.Series( + to_magnitudes, + index=data.index, + name=data.name, + ) + else: + data = list(to_magnitudes) return data