detquantlib 5.1.2__tar.gz → 5.3.0__tar.gz

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.
Files changed (33) hide show
  1. {detquantlib-5.1.2 → detquantlib-5.3.0}/PKG-INFO +1 -1
  2. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/assets/wind_turbine.py +70 -32
  3. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/dates/dates.py +37 -2
  4. {detquantlib-5.1.2 → detquantlib-5.3.0}/pyproject.toml +1 -1
  5. {detquantlib-5.1.2 → detquantlib-5.3.0}/LICENSE.txt +0 -0
  6. {detquantlib-5.1.2 → detquantlib-5.3.0}/README.md +0 -0
  7. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/__init__.py +0 -0
  8. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/assets/__init__.py +0 -0
  9. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/assets/battery.py +0 -0
  10. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/converters/__init__.py +0 -0
  11. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/converters/definitions.py +0 -0
  12. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/converters/energy.py +0 -0
  13. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/converters/helpers.py +0 -0
  14. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/converters/price.py +0 -0
  15. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/data/__init__.py +0 -0
  16. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/data/databases/detdatabase.py +0 -0
  17. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/data/databases/helpers.py +0 -0
  18. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/data/entsoe/entsoe.py +0 -0
  19. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/data/sftp/sftp.py +0 -0
  20. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/dates/__init__.py +0 -0
  21. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/figures/__init__.py +0 -0
  22. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/figures/plotly_figures.py +0 -0
  23. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/forecasting/__init__.py +0 -0
  24. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/forecasting/forecasting.py +0 -0
  25. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/outputs/__init__.py +0 -0
  26. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/outputs/outputs_interface.py +0 -0
  27. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/stats/__init__.py +0 -0
  28. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/stats/data_analysis.py +0 -0
  29. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/tradable_products/__init__.py +0 -0
  30. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/tradable_products/tradable_products.py +0 -0
  31. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/utils/__init__.py +0 -0
  32. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/utils/logging.py +0 -0
  33. {detquantlib-5.1.2 → detquantlib-5.3.0}/detquantlib/utils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detquantlib
3
- Version: 5.1.2
3
+ Version: 5.3.0
4
4
  Summary: An internal library containing functions and classes that can be used across Quant models.
5
5
  License-File: LICENSE.txt
6
6
  Author: Dynamic Energy Trading
@@ -5,6 +5,7 @@ from scipy.interpolate import CubicSpline
5
5
 
6
6
  # Internal modules
7
7
  from detquantlib.converters import power_to_energy
8
+ from detquantlib.utils import list_to_str
8
9
 
9
10
 
10
11
  class WindTurbine:
@@ -35,6 +36,73 @@ class WindTurbine:
35
36
  self.nr_turbines = nr_turbines
36
37
  self.power_curve = power_curve
37
38
 
39
+ @staticmethod
40
+ def list_models() -> list[str]:
41
+ """Gets the list of available wind turbine models."""
42
+ return [d for d in WindTurbineModels.__dict__ if not d.startswith("__")]
43
+
44
+ @staticmethod
45
+ def get_model(model_name: str) -> dict:
46
+ """Gets the model information of a given wind turbine."""
47
+ try:
48
+ return getattr(WindTurbineModels, model_name)
49
+ except AttributeError as e:
50
+ raise ValueError(
51
+ f"Invalid model name '{model_name}'. Available models: "
52
+ f"{list_to_str(WindTurbine.list_models())}."
53
+ ) from e
54
+
55
+ @staticmethod
56
+ def build_from_model(model_name: str = None, model_info: dict = None, nr_turbines: int = 1):
57
+ """
58
+ Builds a WindTurbine object from a known wind turbine model.
59
+
60
+ Args:
61
+ model_name: Wind turbine model name, as given in the WindTurbineModels class. If not
62
+ provided, argument 'model_info' should be provided.
63
+ model_info: Wind turbine model information. The dictionary can be taken from the
64
+ list of models in the WindTurbineModels class. Otherwise, the dictionary should
65
+ have the same structure as those in the WindTurbineModels class. If not provided,
66
+ argument 'model_name' should be provided.
67
+ nr_turbines: Number of turbines in the wind farm
68
+
69
+ Returns:
70
+ WindTurbine object
71
+
72
+ Raises:
73
+ ValueError: Raises an error if both 'model_name' and 'model_info' are missing.
74
+ ValueError: Raises an error if both 'model_name' and 'model_info' are provided.
75
+ """
76
+ # Inputs validation
77
+ if model_name is None and model_info is None:
78
+ raise ValueError(
79
+ "Cannot determine turbine model. Please provide either argument 'model_name' "
80
+ "or 'model_info'."
81
+ )
82
+ elif model_name is not None and model_info is not None:
83
+ raise ValueError(
84
+ "Cannot determine turbine model. Please provide either argument 'model_name' "
85
+ "or 'model_info', but not both."
86
+ )
87
+ elif model_name is not None:
88
+ model_info = WindTurbine.get_model(model_name)
89
+
90
+ # Create object
91
+ obj = WindTurbine(
92
+ rated_power_mw=model_info["rated_power_mw"],
93
+ cut_in=model_info["cut_in"],
94
+ cut_out=model_info["cut_out"],
95
+ nr_turbines=nr_turbines,
96
+ )
97
+
98
+ # Set power_curve attribute
99
+ obj.fit_power_curve(
100
+ wind_speed=[d["wind_speed_(m/s)"] for d in model_info["power_curve"]],
101
+ power_mw=[d["power(mw)"] for d in model_info["power_curve"]],
102
+ )
103
+
104
+ return obj
105
+
38
106
  def fit_power_curve(
39
107
  self, wind_speed: list | np.ndarray | pd.Series, power_mw: list | np.ndarray | pd.Series
40
108
  ):
@@ -92,8 +160,8 @@ class WindTurbine:
92
160
  # Cubic spline interpolation
93
161
  power_mw = self.power_curve(wind_speed)
94
162
 
95
- # Cap to rated power
96
- power_mw = np.minimum(power_mw, self.rated_power_mw)
163
+ # Bound between 0 and rated power
164
+ power_mw = np.clip(a=power_mw, a_min=0.0, a_max=self.rated_power_mw)
97
165
 
98
166
  # Adjust values outside of cut-in - cut-out bounds
99
167
  idx = (wind_speed < self.cut_in) | (wind_speed > self.cut_out)
@@ -121,36 +189,6 @@ class WindTurbine:
121
189
  )
122
190
  return energy_mwh
123
191
 
124
- @staticmethod
125
- def build_from_model(model: dict, nr_turbines: int):
126
- """
127
- Builds a WindTurbine object from a known wind turbine model.
128
-
129
- Args:
130
- model: Wind turbine model. The dictionary can be taken from the list of models in
131
- the WindTurbineModels class. Otherwise, the dictionary should have the same
132
- structure as those in the WindTurbineModels class.
133
- nr_turbines: Number of wind turbines in the wind farm
134
-
135
- Returns:
136
- WindTurbine object
137
- """
138
- # Create object
139
- obj = WindTurbine(
140
- rated_power_mw=model["rated_power_mw"],
141
- cut_in=model["cut_in"],
142
- cut_out=model["cut_out"],
143
- nr_turbines=nr_turbines,
144
- )
145
-
146
- # Set power_curve attribute
147
- obj.fit_power_curve(
148
- wind_speed=[d["wind_speed_(m/s)"] for d in model["power_curve"]],
149
- power_mw=[d["power(mw)"] for d in model["power_curve"]],
150
- )
151
-
152
- return obj
153
-
154
192
 
155
193
  class WindTurbineModels:
156
194
  """
@@ -3,10 +3,45 @@ from datetime import datetime, timezone
3
3
  from typing import Literal
4
4
 
5
5
  # Third-party packages
6
- from dateutil.relativedelta import *
6
+ import pandas as pd
7
+ from dateutil.relativedelta import relativedelta
7
8
 
8
9
  # Specify functions to expose
9
- __all__ = ["count_nr_hours", "calc_months_diff", "datetime_to_month_code"]
10
+ __all__ = ["ts_ceil", "ts_floor", "count_nr_hours", "calc_months_diff", "datetime_to_month_code"]
11
+
12
+
13
+ def ts_ceil(ts: pd.Timestamp, freq: str) -> pd.Timestamp:
14
+ """
15
+ Short wrapper function around the pd.Timestamp object.ceil() method that also supports
16
+ October DST timestamps (i.e. between 02:00:00+0200 and 03:00:00+0100), because the built-in
17
+ method raises an error in those cases.
18
+
19
+ Args:
20
+ ts: Timestamp
21
+ freq: Frequency
22
+
23
+ Returns:
24
+ Ceiled timestamp
25
+ """
26
+ local_tz = ts.tz
27
+ return ts.tz_convert("UTC").ceil(freq).tz_convert(local_tz)
28
+
29
+
30
+ def ts_floor(ts: pd.Timestamp, freq: str) -> pd.Timestamp:
31
+ """
32
+ Short wrapper function around the pd.Timestamp object.floor() method that also supports
33
+ October DST timestamps (i.e. between 02:00:00+0200 and 03:00:00+0100), because the built-in
34
+ method raises an error in those cases.
35
+
36
+ Args:
37
+ ts: Timestamp
38
+ freq: Frequency
39
+
40
+ Returns:
41
+ Floored timestamp
42
+ """
43
+ local_tz = ts.tz
44
+ return ts.tz_convert("UTC").floor(freq).tz_convert(local_tz)
10
45
 
11
46
 
12
47
  def count_nr_hours(start_date: datetime, end_date: datetime) -> float:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "detquantlib"
3
- version = "5.1.2"
3
+ version = "5.3.0"
4
4
  description = "An internal library containing functions and classes that can be used across Quant models."
5
5
  authors = ["Dynamic Energy Trading"]
6
6
  readme = "README.md"
File without changes
File without changes