From cefabed6674aecef6168b6b42b81b8d2433d66b4 Mon Sep 17 00:00:00 2001 From: Felix Claessen <30658763+flix6x@users.noreply.github.com> Date: Tue, 5 Apr 2022 13:28:52 +0200 Subject: [PATCH] Backport PR #412: Prefer conversion to short stock units (#412) Catch another case of converting flow units to sensible stock units: t/h to t (tonne) instead of to Mg. * Add test case Signed-off-by: F.N. Claessen * Return shortest unit of stock Signed-off-by: F.N. Claessen * Sneak in some type annotation fixes Signed-off-by: F.N. Claessen * Changelog entry Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 22 +++++++++++++++++++ .../data/models/charts/belief_charts.py | 5 +++++ flexmeasures/data/models/time_series.py | 6 +++++ flexmeasures/data/queries/annotations.py | 6 ++--- flexmeasures/utils/tests/test_unit_utils.py | 1 + flexmeasures/utils/unit_utils.py | 11 +++++++--- 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 22b923537..a4be3ac24 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -2,6 +2,28 @@ FlexMeasures Changelog ********************** +v0.10.0 | April XX, 2022 +=========================== + + +New features +----------- + +Bugfixes +----------- + +Infrastructure / Support +---------------------- + + +v0.9.2 | April XX, 2022 +=========================== + +Bugfixes +-------- +* Prefer unit conversions to short stock units [see `PR #412 `_] + + v0.9.1 | March 31, 2022 =========================== diff --git a/flexmeasures/data/models/charts/belief_charts.py b/flexmeasures/data/models/charts/belief_charts.py index d14623e7a..4be558883 100644 --- a/flexmeasures/data/models/charts/belief_charts.py +++ b/flexmeasures/data/models/charts/belief_charts.py @@ -1,9 +1,12 @@ +from __future__ import annotations + from flexmeasures.data.models.charts.defaults import FIELD_DEFINITIONS from flexmeasures.utils.flexmeasures_inflection import capitalize def bar_chart( sensor: "Sensor", # noqa F821 + unique_source_names: list[str] | None = None, **override_chart_specs: dict, ): unit = sensor.unit if sensor.unit else "a.u." @@ -13,6 +16,8 @@ def bar_chart( stack=None, **FIELD_DEFINITIONS["event_value"], ) + color_definition = FIELD_DEFINITIONS["source"] + color_definition["scale"] = {"domain": unique_source_names} chart_specs = { "description": "A simple bar chart.", "title": capitalize(sensor.name), diff --git a/flexmeasures/data/models/time_series.py b/flexmeasures/data/models/time_series.py index 4faa6c35e..b30a5cf38 100644 --- a/flexmeasures/data/models/time_series.py +++ b/flexmeasures/data/models/time_series.py @@ -141,6 +141,11 @@ def is_strictly_non_negative(self) -> bool: "is_consumer", True ) + @property + def unique_sources(self) -> List[DataSource]: + """List unique sources that have registered data for this sensor, ordered by id.""" + return DataSource.query.join(TimedBelief).filter(TimedBelief.sensor_id == self.id).filter(TimedBelief.source_id == DataSource.id).order_by(DataSource.id).all() + def get_attribute(self, attribute: str, default: Any = None) -> Any: """Looks for the attribute on the Sensor. If not found, looks for the attribute on the Sensor's GenericAsset. @@ -334,6 +339,7 @@ def chart( chart_specs = chart_type_to_chart_specs( chart_type, sensor=self, + unique_source_names=[source.name for source in self.unique_sources], dataset_name=dataset_name, **kwargs, ) diff --git a/flexmeasures/data/queries/annotations.py b/flexmeasures/data/queries/annotations.py index 86aa0a269..daf53ad4a 100644 --- a/flexmeasures/data/queries/annotations.py +++ b/flexmeasures/data/queries/annotations.py @@ -12,9 +12,9 @@ def query_asset_annotations( asset_id: int, - annotation_starts_after: Optional[datetime], - annotation_ends_before: Optional[datetime], - sources: List[DataSource], + annotation_starts_after: Optional[datetime] = None, + annotation_ends_before: Optional[datetime] = None, + sources: Optional[List[DataSource]] = None, annotation_type: str = None, ) -> Query: """Match annotations assigned to the given asset.""" diff --git a/flexmeasures/utils/tests/test_unit_utils.py b/flexmeasures/utils/tests/test_unit_utils.py index 726cfdde1..7ed9f7f6d 100644 --- a/flexmeasures/utils/tests/test_unit_utils.py +++ b/flexmeasures/utils/tests/test_unit_utils.py @@ -91,6 +91,7 @@ def test_determine_flow_unit( ("kW", None, "kWh"), ("m/s", "s", "m"), ("m/s", "h", "km"), + ("t/h", None, "t"), ], ) def test_determine_stock_unit( diff --git a/flexmeasures/utils/unit_utils.py b/flexmeasures/utils/unit_utils.py index cfeeaa791..a02c6a9d5 100644 --- a/flexmeasures/utils/unit_utils.py +++ b/flexmeasures/utils/unit_utils.py @@ -120,12 +120,17 @@ def determine_flow_unit(stock_unit: str, time_unit: str = "h"): def determine_stock_unit(flow_unit: str, time_unit: str = "h"): - """For example: + """Determine the shortest unit of stock, given a unit of flow. + + For example: >>> determine_stock_unit("m³/h") # m³ >>> determine_stock_unit("kW") # kWh """ - stock = to_preferred(ur.Quantity(flow_unit) * ur.Quantity(time_unit)) - return "{:~P}".format(stock.units) + stock = ur.Quantity(flow_unit) * ur.Quantity(time_unit) + return min( + ["{:~P}".format(stock.units), "{:~P}".format(to_preferred(stock).units)], + key=len, + ) def units_are_convertible(