openenergyid 0.1.17__py2.py3-none-any.whl → 0.1.19__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of openenergyid might be problematic. Click here for more details.

openenergyid/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Open Energy ID Python SDK."""
2
2
 
3
- __version__ = "0.1.17"
3
+ __version__ = "0.1.19"
4
4
 
5
5
  from .enums import Granularity
6
6
  from .models import TimeDataFrame, TimeSeries
@@ -16,3 +16,7 @@ SPP_WEIGHTED_PRICE_EXPORTED = "spp_weighted_price_exported"
16
16
  HEATMAP_DELIVERED = "heatmap_delivered"
17
17
  HEATMAP_EXPORTED = "heatmap_exported"
18
18
  HEATMAP_TOTAL = "heatmap_total"
19
+
20
+ HEATMAP_DELIVERED_DESCRIPTION = "heatmap_delivered_description"
21
+ HEATMAP_EXPORTED_DESCRIPTION = "heatmap_exported_description"
22
+ HEATMAP_TOTAL_DESCRIPTION = "heatmap_total_description"
@@ -26,18 +26,18 @@ from .const import (
26
26
  HEATMAP_DELIVERED,
27
27
  HEATMAP_EXPORTED,
28
28
  HEATMAP_TOTAL,
29
+ HEATMAP_DELIVERED_DESCRIPTION,
30
+ HEATMAP_EXPORTED_DESCRIPTION,
31
+ HEATMAP_TOTAL_DESCRIPTION,
29
32
  )
30
33
 
31
34
 
32
- def weigh_by_monthly_profile(series: pd.Series, profile: pd.Series) -> pd.Series:
35
+ def weigh_by_monthly_profile(df: pd.DataFrame, series_name, profile_name) -> pd.Series:
33
36
  """Weigh a time series by a monthly profile."""
34
- df = pd.DataFrame({"series": series, "profile": profile})
35
- results = []
36
- for _, frame in df.groupby(pd.Grouper(freq="MS")):
37
- frame = frame.copy()
38
- frame["weighted"] = frame["series"].sum() * (frame["profile"] / frame["profile"].sum())
39
- results.append(frame)
40
- return pd.concat(results)["weighted"]
37
+ grouped = df.groupby(pd.Grouper(freq="MS"))
38
+ return grouped[series_name].transform("sum") * grouped[profile_name].transform(
39
+ lambda x: x / x.sum()
40
+ )
41
41
 
42
42
 
43
43
  def extend_dataframe_with_smr2(df: pd.DataFrame, inplace: bool = False) -> pd.DataFrame | None:
@@ -47,12 +47,8 @@ def extend_dataframe_with_smr2(df: pd.DataFrame, inplace: bool = False) -> pd.Da
47
47
  else:
48
48
  result_df = df
49
49
 
50
- result_df[ELECTRICITY_DELIVERED_SMR2] = weigh_by_monthly_profile(
51
- df[ELECTRICITY_DELIVERED], df[RLP]
52
- )
53
- result_df[ELECTRICITY_EXPORTED_SMR2] = weigh_by_monthly_profile(
54
- df[ELECTRICITY_EXPORTED], df[SPP]
55
- )
50
+ result_df[ELECTRICITY_DELIVERED_SMR2] = weigh_by_monthly_profile(df, ELECTRICITY_DELIVERED, RLP)
51
+ result_df[ELECTRICITY_EXPORTED_SMR2] = weigh_by_monthly_profile(df, ELECTRICITY_EXPORTED, SPP)
56
52
 
57
53
  result_df.rename(
58
54
  columns={
@@ -78,14 +74,14 @@ def extend_dataframe_with_costs(df: pd.DataFrame, inplace: bool = False) -> pd.D
78
74
  df[ELECTRICITY_DELIVERED_SMR2] * df[PRICE_ELECTRICITY_DELIVERED]
79
75
  )
80
76
  result_df[COST_ELECTRICITY_EXPORTED_SMR2] = (
81
- df[ELECTRICITY_EXPORTED_SMR2] * df[PRICE_ELECTRICITY_EXPORTED]
77
+ df[ELECTRICITY_EXPORTED_SMR2] * df[PRICE_ELECTRICITY_EXPORTED] * -1
82
78
  )
83
79
 
84
80
  result_df[COST_ELECTRICITY_DELIVERED_SMR3] = (
85
81
  df[ELECTRICITY_DELIVERED_SMR3] * df[PRICE_ELECTRICITY_DELIVERED]
86
82
  )
87
83
  result_df[COST_ELECTRICITY_EXPORTED_SMR3] = (
88
- df[ELECTRICITY_EXPORTED_SMR3] * df[PRICE_ELECTRICITY_EXPORTED]
84
+ df[ELECTRICITY_EXPORTED_SMR3] * df[PRICE_ELECTRICITY_EXPORTED] * -1
89
85
  )
90
86
 
91
87
  if not inplace:
@@ -147,8 +143,7 @@ def extend_dataframe_with_heatmap(df: pd.DataFrame, inplace: bool = False) -> pd
147
143
 
148
144
  # Invert scores so that positive values indicate a positive impact
149
145
  heatmap_score_delivered = -heatmap_score_delivered
150
- heatmap_score_exported = -heatmap_score_exported
151
- heatmap_score_combined = heatmap_score_delivered - heatmap_score_exported
146
+ heatmap_score_combined = heatmap_score_delivered + heatmap_score_exported
152
147
 
153
148
  df[HEATMAP_DELIVERED] = heatmap_score_delivered
154
149
  df[HEATMAP_EXPORTED] = heatmap_score_exported
@@ -159,6 +154,85 @@ def extend_dataframe_with_heatmap(df: pd.DataFrame, inplace: bool = False) -> pd
159
154
  return None
160
155
 
161
156
 
157
+ def map_delivery_description(
158
+ price_delivered, price_rlp, electricity_delivered_smr3, electricity_delivered_smr2
159
+ ):
160
+ """Map the delivery description."""
161
+ if price_delivered > price_rlp and electricity_delivered_smr3 > electricity_delivered_smr2:
162
+ return 1
163
+ if price_delivered > price_rlp and electricity_delivered_smr3 < electricity_delivered_smr2:
164
+ return 2
165
+ if price_delivered < price_rlp and electricity_delivered_smr3 > electricity_delivered_smr2:
166
+ return 3
167
+ if price_delivered < price_rlp and electricity_delivered_smr3 < electricity_delivered_smr2:
168
+ return 4
169
+ return 0
170
+
171
+
172
+ def map_export_description(
173
+ price_exported, price_spp, electricity_exported_smr3, electricity_exported_smr2
174
+ ):
175
+ """Map the export description."""
176
+ if price_exported > price_spp and electricity_exported_smr3 > electricity_exported_smr2:
177
+ return 5
178
+ if price_exported > price_spp and electricity_exported_smr3 < electricity_exported_smr2:
179
+ return 6
180
+ if price_exported < price_spp and electricity_exported_smr3 > electricity_exported_smr2:
181
+ return 7
182
+ if price_exported < price_spp and electricity_exported_smr3 < electricity_exported_smr2:
183
+ return 8
184
+ return 0
185
+
186
+
187
+ def map_total_description(
188
+ abs_heatmap_delivered, abs_heatmap_exported, delivered_description, exported_description
189
+ ):
190
+ """Map the total description."""
191
+ if abs_heatmap_delivered > abs_heatmap_exported:
192
+ return delivered_description
193
+ return exported_description
194
+
195
+
196
+ def extend_dataframe_with_heatmap_description(
197
+ df: pd.DataFrame, inplace: bool = False
198
+ ) -> pd.DataFrame | None:
199
+ """Extend a DataFrame with the heatmap description columns."""
200
+ if not inplace:
201
+ df = df.copy()
202
+
203
+ df[HEATMAP_DELIVERED_DESCRIPTION] = list(
204
+ map(
205
+ map_delivery_description,
206
+ df[PRICE_ELECTRICITY_DELIVERED],
207
+ df[RLP_WEIGHTED_PRICE_DELIVERED],
208
+ df[ELECTRICITY_DELIVERED_SMR3],
209
+ df[ELECTRICITY_DELIVERED_SMR2],
210
+ )
211
+ )
212
+ df[HEATMAP_EXPORTED_DESCRIPTION] = list(
213
+ map(
214
+ map_export_description,
215
+ df[PRICE_ELECTRICITY_EXPORTED],
216
+ df[SPP_WEIGHTED_PRICE_EXPORTED],
217
+ df[ELECTRICITY_EXPORTED_SMR3],
218
+ df[ELECTRICITY_EXPORTED_SMR2],
219
+ )
220
+ )
221
+
222
+ df[HEATMAP_TOTAL_DESCRIPTION] = list(
223
+ map(
224
+ map_total_description,
225
+ df[HEATMAP_DELIVERED].abs(),
226
+ df[HEATMAP_EXPORTED].abs(),
227
+ df[HEATMAP_DELIVERED_DESCRIPTION],
228
+ df[HEATMAP_EXPORTED_DESCRIPTION],
229
+ )
230
+ )
231
+
232
+ if not inplace:
233
+ return df
234
+
235
+
162
236
  def calculate_dyntar_columns(df: pd.DataFrame, inplace: bool = False) -> pd.DataFrame | None:
163
237
  """Calculate all columns required for the dynamic tariff analysis."""
164
238
  if not inplace:
@@ -168,6 +242,7 @@ def calculate_dyntar_columns(df: pd.DataFrame, inplace: bool = False) -> pd.Data
168
242
  extend_dataframe_with_costs(df, inplace=True)
169
243
  extend_dataframe_with_weighted_prices(df, inplace=True)
170
244
  extend_dataframe_with_heatmap(df, inplace=True)
245
+ extend_dataframe_with_heatmap_description(df, inplace=True)
171
246
 
172
247
  if not inplace:
173
248
  return df
@@ -1,7 +1,7 @@
1
1
  """Models for dynamic tariff analysis."""
2
2
 
3
3
  from typing import Literal
4
- from pydantic import Field, conlist
4
+ from pydantic import Field, conlist, confloat
5
5
 
6
6
  from openenergyid.models import TimeDataFrame
7
7
 
@@ -33,6 +33,9 @@ OutputColumns = Literal[
33
33
  "heatmap_delivered",
34
34
  "heatmap_exported",
35
35
  "heatmap_total",
36
+ "heatmap_delivered_description",
37
+ "heatmap_exported_description",
38
+ "heatmap_total_description",
36
39
  ]
37
40
 
38
41
 
@@ -46,11 +49,11 @@ class DynamicTariffAnalysisInput(TimeDataFrame):
46
49
  )
47
50
  data: list[
48
51
  conlist(
49
- item_type=float,
52
+ item_type=confloat(allow_inf_nan=True),
50
53
  min_length=len(RequiredColumns.__args__),
51
54
  max_length=len(RequiredColumns.__args__),
52
55
  ) # type: ignore
53
- ] = Field(examples=[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
56
+ ] = Field(examples=[[0.0] * len(RequiredColumns.__args__)])
54
57
 
55
58
 
56
59
  class DynamicTariffAnalysisOutput(TimeDataFrame):
@@ -62,5 +65,9 @@ class DynamicTariffAnalysisOutput(TimeDataFrame):
62
65
  examples=[OutputColumns.__args__],
63
66
  )
64
67
  data: list[
65
- conlist(item_type=float, min_length=1, max_length=len(OutputColumns.__args__)) # type: ignore
66
- ] = Field(examples=[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]])
68
+ conlist(
69
+ item_type=confloat(allow_inf_nan=True),
70
+ min_length=1,
71
+ max_length=len(OutputColumns.__args__),
72
+ ) # type: ignore
73
+ ] = Field(examples=[[0.0] * len(OutputColumns.__args__)])
openenergyid/models.py CHANGED
@@ -6,7 +6,7 @@ from typing import overload
6
6
  from typing import Self
7
7
 
8
8
  import pandas as pd
9
- from pydantic import BaseModel, field_validator
9
+ from pydantic import BaseModel
10
10
 
11
11
 
12
12
  class TimeSeriesBase(BaseModel):
@@ -78,13 +78,7 @@ class TimeSeries(TimeSeriesBase):
78
78
  """
79
79
 
80
80
  name: str | None = None
81
- data: list[float | None]
82
-
83
- @field_validator("data")
84
- @classmethod
85
- def replace_nan_with_none(cls, data: list[float]) -> list[float | None]:
86
- """Replace NaN values with None."""
87
- return [None if pd.isna(value) else value for value in data]
81
+ data: list[float]
88
82
 
89
83
  @classmethod
90
84
  def from_pandas(cls, data: pd.Series) -> Self:
@@ -102,13 +96,7 @@ class TimeDataFrame(TimeSeriesBase):
102
96
  """Time series data with multiple columns."""
103
97
 
104
98
  columns: list[str]
105
- data: list[list[float | None]]
106
-
107
- @field_validator("data")
108
- @classmethod
109
- def replace_nan_with_none(cls, data: list[list[float]]) -> list[list[float | None]]:
110
- """Replace NaN values with None."""
111
- return [[None if pd.isna(value) else value for value in row] for row in data]
99
+ data: list[list[float]]
112
100
 
113
101
  @classmethod
114
102
  def from_pandas(cls, data: pd.DataFrame) -> Self:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openenergyid
3
- Version: 0.1.17
3
+ Version: 0.1.19
4
4
  Summary: Open Source Python library for energy analytics and simulations
5
5
  Project-URL: Homepage, https://energyid.eu
6
6
  Project-URL: Repository, https://github.com/EnergieID/OpenEnergyID
@@ -1,14 +1,14 @@
1
- openenergyid/__init__.py,sha256=lFC4Rf6_0_VJqZZEGDBxHt7gMCsy39hvF-0pUBErI80,193
1
+ openenergyid/__init__.py,sha256=Rw7W-OZewpvJwVPQ0xjjsiXdeT-QpbmEmBER7arAMYo,193
2
2
  openenergyid/const.py,sha256=D-xUnUyVuLmphClkePgxpFP6z0RDhw_6m7rX0BHBgrw,823
3
3
  openenergyid/enums.py,sha256=jdw4CB1gkisx0re_SesrTEyh_T-UxYp6uieE7iYlHdA,357
4
- openenergyid/models.py,sha256=F-7BOB-UxIcmR0Y02NHWWjoM_yWwkVOeRtIwZl72KgI,4877
4
+ openenergyid/models.py,sha256=CO6VdthCOQ9hNXqVSan_4IOBpiQvOix-ea3U6TR7Vgc,4343
5
5
  openenergyid/capacity/__init__.py,sha256=1En96HlPV8kd1hOJO9RjRbXNInp5ZSkmjsjp0jfZlcQ,221
6
6
  openenergyid/capacity/main.py,sha256=G6_EtXs1k_W-fxS33pFrCNKajuH81skdI32zp5RX9bI,3674
7
7
  openenergyid/capacity/models.py,sha256=qi0IFyF_QOVleSzN8g0U2Fzqcc9ZDfNKt8oteFLY6Q0,832
8
8
  openenergyid/dyntar/__init__.py,sha256=iQXQXrEQOiVNeeF6LRmUf3oOhKlGjMNF7o4T04IWTGA,371
9
- openenergyid/dyntar/const.py,sha256=K7X6nHIl9DNyC6hU8jLtvOy3-IBGuYC449evOpImuJE,773
10
- openenergyid/dyntar/main.py,sha256=Q8_0vizBe__GZIcfOK5HqYTncRQHMjGJ5bk_TEBwuA8,5673
11
- openenergyid/dyntar/models.py,sha256=BbGdHj7eUOMepblWJNsNd21xULluv6m7TtdhSggvVbY,1873
9
+ openenergyid/dyntar/const.py,sha256=17qL0-S0SImsqrDEDrGS2GLyJYcJRw6GmmcTiML7tR0,956
10
+ openenergyid/dyntar/main.py,sha256=yRPamC5dHwpiDj07RM2iVKk3gZk8a81zKSjOsjewACo,8247
11
+ openenergyid/dyntar/models.py,sha256=FZq7HI1F-3nVeHwPkuB38-8u32JzdvsZaCzrhirFD2g,2094
12
12
  openenergyid/energysharing/__init__.py,sha256=A4JfrUYf-hBCzhUm0qL1GGlNMvpO8OwXJo80dJxFIvw,274
13
13
  openenergyid/energysharing/const.py,sha256=X2zEPtTlsmZ66w6RmLS_h8NmdzObAEi5N6-0yrLN5V4,219
14
14
  openenergyid/energysharing/data_formatting.py,sha256=Kwuhyn6ao_8Brdm9frlA6VzYOqimNYZsRbYwNXnE7yc,2583
@@ -19,7 +19,7 @@ openenergyid/mvlr/helpers.py,sha256=Uzbfrj3IpH26wA206KOl0hNucKE-n9guJNC_EROBVKA,
19
19
  openenergyid/mvlr/main.py,sha256=cn7jZ98cHn2eh-0zG9q8Pad0Ft_FuI-u3a-eeHeF8jA,1304
20
20
  openenergyid/mvlr/models.py,sha256=XvkViOLlYqi0ffgF3AD4Jvk3yL05gsoKdKgBAsGJ7L4,8581
21
21
  openenergyid/mvlr/mvlr.py,sha256=F7WvWnZQtqUmK1vsguemsn9n8pDDk3tQ1weOlv-bo0c,18626
22
- openenergyid-0.1.17.dist-info/METADATA,sha256=MBxbfpJfYtdTtxCJy6MeysE_NAc6Q1r1ICFg5gc3j6I,2477
23
- openenergyid-0.1.17.dist-info/WHEEL,sha256=fl6v0VwpzfGBVsGtkAkhILUlJxROXbA3HvRL6Fe3140,105
24
- openenergyid-0.1.17.dist-info/licenses/LICENSE,sha256=NgRdcNHwyXVCXZ8sJwoTp0DCowThJ9LWWl4xhbV1IUY,1074
25
- openenergyid-0.1.17.dist-info/RECORD,,
22
+ openenergyid-0.1.19.dist-info/METADATA,sha256=q8cD0GQr7JDOoStIRDI8r5z-9gvgt4dkuh98vBDWJBw,2477
23
+ openenergyid-0.1.19.dist-info/WHEEL,sha256=fl6v0VwpzfGBVsGtkAkhILUlJxROXbA3HvRL6Fe3140,105
24
+ openenergyid-0.1.19.dist-info/licenses/LICENSE,sha256=NgRdcNHwyXVCXZ8sJwoTp0DCowThJ9LWWl4xhbV1IUY,1074
25
+ openenergyid-0.1.19.dist-info/RECORD,,