test_sensor.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import pytest
  2. from flexmeasures import Sensor
  3. from flexmeasures.data.schemas.sensors import (
  4. QuantityOrSensor,
  5. VariableQuantityField,
  6. )
  7. from flexmeasures.utils.unit_utils import ur
  8. from marshmallow import ValidationError
  9. @pytest.mark.parametrize(
  10. "src_quantity, dst_unit, fails, exp_dst_quantity",
  11. [
  12. # deserialize a sensor
  13. ({"sensor": 1}, "MWh", False, None),
  14. ({"sensor": 1}, "kWh", False, None),
  15. ({"sensor": 1}, "kW", False, None),
  16. ({"sensor": 1}, "EUR", True, None),
  17. ({"sensor": 1}, "/h", False, None), # convertable to MWh²/h
  18. ({"sensor": 2}, "EUR/kWh", False, None),
  19. ({"sensor": 2}, "EUR", True, None),
  20. # deserialize a quantity
  21. (1, "%", False, "100.0 %"),
  22. (5, "%", False, "500.0 %"),
  23. ("1MWh", "MWh", False, "1 MWh"),
  24. ("1 MWh", "kWh", False, "1000.0 kWh"),
  25. ("1 MWh", "kW", True, None),
  26. ("100 EUR/MWh", "EUR/kWh", False, "0.1 EUR/kWh"),
  27. ("100 EUR/MWh", "EUR", True, None),
  28. ("1 EUR/kWh", "/MWh", False, "1.0 kEUR/MWh"),
  29. ("50%", "/MWh", False, "500.0 kWh/MWh"),
  30. ("/", "/MWh", True, None),
  31. ("/", "MWh", True, None),
  32. ("10 batteries", "MWh", True, None),
  33. # deserialize a time series specification
  34. (
  35. [{"start": "2024-08-17T11:00+02", "duration": "PT1H", "value": "2 MWh"}],
  36. "kWh",
  37. False,
  38. "2000.0 kWh",
  39. ),
  40. (
  41. [
  42. {
  43. "start": "2024-08-17T11:00+02",
  44. "duration": "PT1H",
  45. "value": "829.4 Wh/kWh",
  46. }
  47. ],
  48. "/MWh",
  49. False,
  50. "829.4 kWh/MWh",
  51. ),
  52. (
  53. [
  54. {
  55. "start": "2024-08-17T11:00+02",
  56. "duration": "PT1H",
  57. "value": "914.7 EUR/kWh",
  58. }
  59. ],
  60. "/MWh",
  61. False,
  62. "914.7 kEUR/MWh",
  63. ),
  64. # todo: uncomment after to_preferred gets rid of mEUR
  65. # (
  66. # [{"start": "2024-08-17T11:00+02", "duration": "PT1H", "value": "120.8 EUR/MWh"}],
  67. # "/kWh",
  68. # False,
  69. # "0.1208 EUR/kWh",
  70. # ),
  71. ],
  72. )
  73. def test_quantity_or_sensor_deserialize(
  74. setup_dummy_sensors, src_quantity, dst_unit, fails, exp_dst_quantity
  75. ):
  76. schema = VariableQuantityField(to_unit=dst_unit, return_magnitude=False)
  77. try:
  78. dst_quantity = schema.deserialize(src_quantity)
  79. if isinstance(src_quantity, (ur.Quantity, int, float)):
  80. assert dst_quantity == ur.Quantity(exp_dst_quantity)
  81. assert str(dst_quantity) == exp_dst_quantity
  82. elif isinstance(src_quantity, list):
  83. assert dst_quantity[0]["value"] == ur.Quantity(exp_dst_quantity)
  84. assert str(dst_quantity[0]["value"]) == exp_dst_quantity
  85. assert not fails
  86. except ValidationError as e:
  87. assert fails, e
  88. @pytest.mark.parametrize(
  89. "src_quantity, expected_magnitude",
  90. [
  91. ("1 kW", 0.001),
  92. ("10 kW", 0.01),
  93. ("100 kW", 0.1),
  94. ("1 MW", 1),
  95. ("1.2 GW", 1200),
  96. ("2000 kVA", 2),
  97. ("3600/4.184 cal/h", 1e-6),
  98. ],
  99. )
  100. def test_quantity_or_sensor_conversion(
  101. setup_dummy_sensors, src_quantity, expected_magnitude
  102. ):
  103. schema = QuantityOrSensor(to_unit="MW")
  104. assert schema.deserialize(src_quantity).magnitude == expected_magnitude
  105. @pytest.mark.parametrize(
  106. "sensor_id, input_param, dst_unit, fails",
  107. [
  108. # deserialize a sensor
  109. (1, "sensor:1", "MWh", False),
  110. (1, "sensor:1", "kWh", False),
  111. (1, "sensor:1", "kW", False),
  112. (1, "sensor:1", "EUR", True),
  113. (2, "sensor:2", "EUR/kWh", False),
  114. (2, "sensor:2", "EUR", True),
  115. # deserialize a quantity
  116. (None, "1MWh", "MWh", False),
  117. (None, "1 MWh", "kWh", False),
  118. (None, "1 MWh", "kW", True),
  119. (None, "100 EUR/MWh", "EUR/kWh", False),
  120. (None, "100 EUR/MWh", "EUR", True),
  121. ],
  122. )
  123. def test_quantity_or_sensor_field(
  124. setup_dummy_sensors, sensor_id, input_param, dst_unit, fails, db
  125. ):
  126. field = QuantityOrSensor(to_unit=dst_unit)
  127. try:
  128. if sensor_id is None:
  129. val = field.convert(input_param, None, None)
  130. assert val.units == ur.Unit(dst_unit)
  131. else:
  132. val = field.convert(input_param, None, None)
  133. assert val == db.session.get(Sensor, sensor_id)
  134. assert not fails
  135. except Exception as e:
  136. assert fails, e
  137. @pytest.mark.parametrize(
  138. "input_param, dst_unit, fails",
  139. [
  140. # deserialize a quantity
  141. ([{"value": 1, "datetime": "2024-07-21T00:15+07"}], "MWh", False),
  142. ([{"value": "1", "datetime": "2024-07-21T00:15+07"}], "MWh", True),
  143. ([{"value": "1MWh", "datetime": "2024-07-21T00:15+07"}], "MWh", False),
  144. ([{"value": "1000 kWh", "datetime": "2024-07-21T00:15+07"}], "MWh", False),
  145. ([{"value": "1 MW", "datetime": "2024-07-21T00:15+07"}], "MWh", True),
  146. ],
  147. )
  148. def test_time_series_field(input_param, dst_unit, fails, db):
  149. field = VariableQuantityField(
  150. to_unit=dst_unit,
  151. default_src_unit="MWh",
  152. return_magnitude=False,
  153. )
  154. try:
  155. val = field.convert(input_param, None, None)
  156. assert val[0]["value"].units == ur.Unit(dst_unit)
  157. assert val[0]["value"].magnitude == 1
  158. assert not fails
  159. except Exception as e:
  160. assert fails, e