detquantlib 3.15.0__tar.gz → 4.0.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 (35) hide show
  1. {detquantlib-3.15.0 → detquantlib-4.0.0}/PKG-INFO +7 -1
  2. {detquantlib-3.15.0 → detquantlib-4.0.0}/README.md +6 -0
  3. detquantlib-4.0.0/detquantlib/assets/__init__.py +4 -0
  4. detquantlib-4.0.0/detquantlib/assets/wind_turbine.py +345 -0
  5. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/outputs/outputs_interface.py +5 -12
  6. {detquantlib-3.15.0 → detquantlib-4.0.0}/pyproject.toml +1 -1
  7. detquantlib-3.15.0/detquantlib/assets/__init__.py +0 -4
  8. detquantlib-3.15.0/detquantlib/assets/wind_turbine.py +0 -92
  9. {detquantlib-3.15.0 → detquantlib-4.0.0}/LICENSE.txt +0 -0
  10. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/__init__.py +0 -0
  11. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/assets/battery.py +0 -0
  12. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/converters/__init__.py +0 -0
  13. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/converters/definitions.py +0 -0
  14. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/converters/energy.py +0 -0
  15. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/converters/helpers.py +0 -0
  16. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/converters/price.py +0 -0
  17. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/data/__init__.py +0 -0
  18. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/data/databases/detdatabase.py +0 -0
  19. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/data/databases/helpers.py +0 -0
  20. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/data/entsoe/entsoe.py +0 -0
  21. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/data/sftp/sftp.py +0 -0
  22. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/dates/__init__.py +0 -0
  23. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/dates/dates.py +0 -0
  24. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/figures/__init__.py +0 -0
  25. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/figures/plotly_figures.py +0 -0
  26. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/forecasting/__init__.py +0 -0
  27. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/forecasting/forecasting.py +0 -0
  28. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/outputs/__init__.py +0 -0
  29. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/stats/__init__.py +0 -0
  30. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/stats/data_analysis.py +0 -0
  31. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/tradable_products/__init__.py +0 -0
  32. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/tradable_products/tradable_products.py +0 -0
  33. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/utils/__init__.py +0 -0
  34. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/utils/logging.py +0 -0
  35. {detquantlib-3.15.0 → detquantlib-4.0.0}/detquantlib/utils/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: detquantlib
3
- Version: 3.15.0
3
+ Version: 4.0.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
@@ -80,6 +80,9 @@ poetry run python docs.py
80
80
 
81
81
  Classes:
82
82
 
83
+ - `Battery`:
84
+ - `from detquantlib.assets import Battery`
85
+ - `from detquantlib.assets.battery import Battery`
83
86
  - `DetDatabase`:
84
87
  - `from detquantlib.data import DetDatabase`
85
88
  - `from detquantlib.data.databases.detdatabase import DetDatabase`
@@ -98,6 +101,9 @@ Classes:
98
101
  - `Sftp`:
99
102
  - `from detquantlib.data import Sftp`
100
103
  - `from detquantlib.data.sftp.sftp import Sftp`
104
+ - `WindTurbine`:
105
+ - `from detquantlib.assets import WindTurbine`
106
+ - `from detquantlib.assets.wind_turbine import WindTurbine`
101
107
 
102
108
  Functions:
103
109
 
@@ -54,6 +54,9 @@ poetry run python docs.py
54
54
 
55
55
  Classes:
56
56
 
57
+ - `Battery`:
58
+ - `from detquantlib.assets import Battery`
59
+ - `from detquantlib.assets.battery import Battery`
57
60
  - `DetDatabase`:
58
61
  - `from detquantlib.data import DetDatabase`
59
62
  - `from detquantlib.data.databases.detdatabase import DetDatabase`
@@ -72,6 +75,9 @@ Classes:
72
75
  - `Sftp`:
73
76
  - `from detquantlib.data import Sftp`
74
77
  - `from detquantlib.data.sftp.sftp import Sftp`
78
+ - `WindTurbine`:
79
+ - `from detquantlib.assets import WindTurbine`
80
+ - `from detquantlib.assets.wind_turbine import WindTurbine`
75
81
 
76
82
  Functions:
77
83
 
@@ -0,0 +1,4 @@
1
+ from .battery import Battery
2
+ from .wind_turbine import WindTurbine, WindTurbineModels
3
+
4
+ __all__ = ["Battery", "WindTurbine", "WindTurbineModels"]
@@ -0,0 +1,345 @@
1
+ # Third-party packages
2
+ import numpy as np
3
+ import pandas as pd
4
+ from scipy.interpolate import CubicSpline
5
+
6
+ # Internal modules
7
+ from detquantlib.converters import power_to_energy
8
+
9
+
10
+ class WindTurbine:
11
+ """A class to store wind turbine information and perform wind turbine-related calculations."""
12
+
13
+ def __init__(
14
+ self,
15
+ rated_power_mw: float,
16
+ cut_in: float,
17
+ cut_out: float,
18
+ nr_turbines: int,
19
+ power_curve: CubicSpline = None,
20
+ ):
21
+ """
22
+ Constructor method.
23
+
24
+ Args:
25
+ rated_power_mw: Rated power of a single wind turbine (in MW)
26
+ cut_in: Cut-in wind speed
27
+ cut_out: Cut-out wind speed
28
+ nr_turbines: Number of wind turbines in the wind farm
29
+ power_curve: Power curve of a single wind turbine, stored as a cubic spline object.
30
+ If not provided, can be set via the 'fit_power_curve()' method below.
31
+ """
32
+ self.rated_power_mw = rated_power_mw
33
+ self.cut_in = cut_in
34
+ self.cut_out = cut_out
35
+ self.nr_turbines = nr_turbines
36
+ self.power_curve = power_curve
37
+
38
+ def fit_power_curve(
39
+ self, wind_speed: list | np.ndarray | pd.Series, power_mw: list | np.ndarray | pd.Series
40
+ ):
41
+ """
42
+ Fits the wind turbine's power curve with a cubic spline, and stores the resulting spline
43
+ object in attribute self.power_curve.
44
+
45
+ Args:
46
+ wind_speed: Wind speeds
47
+ power_mw: Corresponding power in MW (for a single wind turbine)
48
+ """
49
+ # Make sure input data is stored as numpy array
50
+ wind_speed, power_mw = np.array(wind_speed), np.array(power_mw)
51
+
52
+ # Trim data to cut-in - cut-out interval
53
+ idx = (wind_speed >= self.cut_in) & (wind_speed <= self.cut_out)
54
+ wind_speed_trim, power_trim = wind_speed[idx], power_mw[idx]
55
+
56
+ # Add data point with power=0.0 before cut-in to ensure smooth behaviour of spline
57
+ # interpolation
58
+ w0 = wind_speed_trim[0] - np.diff(wind_speed_trim[:2])
59
+ p0 = [0]
60
+ wind_speed_trim, power_trim = np.concat([w0, wind_speed_trim]), np.concat([p0, power_trim])
61
+
62
+ # Fit cubic spline
63
+ cs = CubicSpline(wind_speed_trim, power_trim)
64
+
65
+ # Store spline object
66
+ self.power_curve = cs
67
+
68
+ def wind_to_power(self, wind_speed: list | np.ndarray | pd.Series) -> np.ndarray:
69
+ """
70
+ Converts wind speeds to generated power, aggregated over the total number of turbines.
71
+
72
+ Args:
73
+ wind_speed: Wind speeds
74
+
75
+ Returns:
76
+ Corresponding power in MW (total over the number of turbines set in the object)
77
+
78
+ Raises:
79
+ ValueError: Raises an error if self.power_curve is None.
80
+ """
81
+ # Check that power curve attribute is defined
82
+ if self.power_curve is None:
83
+ raise ValueError(
84
+ "Cannot execute method self.wind_to_power() if attribute self.power_curve is "
85
+ "None. Use method self.fit_power_curve() to set self.power_curve based on power "
86
+ "curve data."
87
+ )
88
+
89
+ # Make sure input data is stored as numpy array
90
+ wind_speed = np.array(wind_speed)
91
+
92
+ # Cubic spline interpolation
93
+ power_mw = self.power_curve(wind_speed)
94
+
95
+ # Cap to rated power
96
+ power_mw = np.minimum(power_mw, self.rated_power_mw)
97
+
98
+ # Adjust values outside of cut-in - cut-out bounds
99
+ idx = (wind_speed < self.cut_in) | (wind_speed > self.cut_out)
100
+ power_mw[idx] = 0.0
101
+
102
+ # Rescale power to number of wind turbines
103
+ power_mw *= self.nr_turbines
104
+
105
+ return power_mw
106
+
107
+ def wind_to_energy(self, wind_speed: list | np.ndarray | pd.Series, tenor: str) -> np.ndarray:
108
+ """
109
+ Converts wind speeds to generated energy, aggregated over the total number of turbines.
110
+
111
+ Args:
112
+ wind_speed: Wind speeds
113
+ tenor: Product tenor
114
+
115
+ Returns:
116
+ Corresponding energy in MWh (total over the number of turbines set in the object)
117
+ """
118
+ power_mw = self.wind_to_power(wind_speed)
119
+ energy_mwh = power_to_energy(
120
+ power=power_mw, power_unit="MW", energy_unit="MWh", tenor=tenor
121
+ )
122
+ return energy_mwh
123
+
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
+
155
+ class WindTurbineModels:
156
+ """
157
+ An inventory of known wind turbine models. Each model is stored as an object attribute. All
158
+ attribute dictionaries must have the same structure.
159
+ """
160
+
161
+ enercon_e126_ep3_4mw = dict(
162
+ brand="Enercon",
163
+ model="E-126 EP3 4.0MW",
164
+ rated_power_mw=4.0,
165
+ cut_in=2.5,
166
+ cut_out=25.0,
167
+ power_curve_source="https://www.thewindpower.net/turbine_en_1576_enercon_e126-4000.php",
168
+ power_curve=[
169
+ {"wind_speed_(m/s)": 0.0, "power(mw)": 0.0},
170
+ {"wind_speed_(m/s)": 0.5, "power(mw)": 0.0},
171
+ {"wind_speed_(m/s)": 1.0, "power(mw)": 0.0},
172
+ {"wind_speed_(m/s)": 1.5, "power(mw)": 0.0},
173
+ {"wind_speed_(m/s)": 2.0, "power(mw)": 0.0},
174
+ {"wind_speed_(m/s)": 2.5, "power(mw)": 0.02},
175
+ {"wind_speed_(m/s)": 3.0, "power(mw)": 0.047},
176
+ {"wind_speed_(m/s)": 3.5, "power(mw)": 0.095},
177
+ {"wind_speed_(m/s)": 4.0, "power(mw)": 0.15},
178
+ {"wind_speed_(m/s)": 4.5, "power(mw)": 0.29},
179
+ {"wind_speed_(m/s)": 5.0, "power(mw)": 0.441},
180
+ {"wind_speed_(m/s)": 5.5, "power(mw)": 0.582},
181
+ {"wind_speed_(m/s)": 6.0, "power(mw)": 0.732},
182
+ {"wind_speed_(m/s)": 6.5, "power(mw)": 0.945},
183
+ {"wind_speed_(m/s)": 7.0, "power(mw)": 1.165},
184
+ {"wind_speed_(m/s)": 7.5, "power(mw)": 1.43},
185
+ {"wind_speed_(m/s)": 8.0, "power(mw)": 1.7},
186
+ {"wind_speed_(m/s)": 8.5, "power(mw)": 2.012},
187
+ {"wind_speed_(m/s)": 9.0, "power(mw)": 2.323},
188
+ {"wind_speed_(m/s)": 9.5, "power(mw)": 2.677},
189
+ {"wind_speed_(m/s)": 10.0, "power(mw)": 3.023},
190
+ {"wind_speed_(m/s)": 10.5, "power(mw)": 3.27},
191
+ {"wind_speed_(m/s)": 11.0, "power(mw)": 3.504},
192
+ {"wind_speed_(m/s)": 11.5, "power(mw)": 3.698},
193
+ {"wind_speed_(m/s)": 12.0, "power(mw)": 3.88},
194
+ {"wind_speed_(m/s)": 12.5, "power(mw)": 3.917},
195
+ {"wind_speed_(m/s)": 13.0, "power(mw)": 3.945},
196
+ {"wind_speed_(m/s)": 13.5, "power(mw)": 3.959},
197
+ {"wind_speed_(m/s)": 14.0, "power(mw)": 3.969},
198
+ {"wind_speed_(m/s)": 14.5, "power(mw)": 3.995},
199
+ {"wind_speed_(m/s)": 15.0, "power(mw)": 4.0},
200
+ {"wind_speed_(m/s)": 15.5, "power(mw)": 4.0},
201
+ {"wind_speed_(m/s)": 16.0, "power(mw)": 4.0},
202
+ {"wind_speed_(m/s)": 16.5, "power(mw)": 4.0},
203
+ {"wind_speed_(m/s)": 17.0, "power(mw)": 4.0},
204
+ {"wind_speed_(m/s)": 17.5, "power(mw)": 4.0},
205
+ {"wind_speed_(m/s)": 18.0, "power(mw)": 4.0},
206
+ {"wind_speed_(m/s)": 18.5, "power(mw)": 4.0},
207
+ {"wind_speed_(m/s)": 19.0, "power(mw)": 4.0},
208
+ {"wind_speed_(m/s)": 19.5, "power(mw)": 4.0},
209
+ {"wind_speed_(m/s)": 20.0, "power(mw)": 4.0},
210
+ {"wind_speed_(m/s)": 20.5, "power(mw)": 4.0},
211
+ {"wind_speed_(m/s)": 21.0, "power(mw)": 4.0},
212
+ {"wind_speed_(m/s)": 21.5, "power(mw)": 4.0},
213
+ {"wind_speed_(m/s)": 22.0, "power(mw)": 4.0},
214
+ {"wind_speed_(m/s)": 22.5, "power(mw)": 3.985},
215
+ {"wind_speed_(m/s)": 23.0, "power(mw)": 3.96},
216
+ {"wind_speed_(m/s)": 23.5, "power(mw)": 3.96},
217
+ {"wind_speed_(m/s)": 24.0, "power(mw)": 3.952},
218
+ {"wind_speed_(m/s)": 24.5, "power(mw)": 3.93},
219
+ {"wind_speed_(m/s)": 25.0, "power(mw)": 3.898},
220
+ ],
221
+ )
222
+
223
+ enercon_e53_800 = dict(
224
+ brand="Enercon",
225
+ model="E-53 800kW",
226
+ rated_power_mw=0.81,
227
+ cut_in=2.0,
228
+ cut_out=25.0,
229
+ power_curve_source="https://www.thewindpower.net/turbine_en_4_enercon_e53-800.php",
230
+ power_curve=[
231
+ {"wind_speed_(m/s)": 0.0, "power(mw)": 0.0},
232
+ {"wind_speed_(m/s)": 0.5, "power(mw)": 0.0},
233
+ {"wind_speed_(m/s)": 1.0, "power(mw)": 0.0},
234
+ {"wind_speed_(m/s)": 1.5, "power(mw)": 0.0},
235
+ {"wind_speed_(m/s)": 2.0, "power(mw)": 0.002},
236
+ {"wind_speed_(m/s)": 2.5, "power(mw)": 0.008},
237
+ {"wind_speed_(m/s)": 3.0, "power(mw)": 0.014},
238
+ {"wind_speed_(m/s)": 3.5, "power(mw)": 0.026},
239
+ {"wind_speed_(m/s)": 4.0, "power(mw)": 0.038},
240
+ {"wind_speed_(m/s)": 4.5, "power(mw)": 0.057},
241
+ {"wind_speed_(m/s)": 5.0, "power(mw)": 0.077},
242
+ {"wind_speed_(m/s)": 5.5, "power(mw)": 0.109},
243
+ {"wind_speed_(m/s)": 6.0, "power(mw)": 0.141},
244
+ {"wind_speed_(m/s)": 6.5, "power(mw)": 0.185},
245
+ {"wind_speed_(m/s)": 7.0, "power(mw)": 0.228},
246
+ {"wind_speed_(m/s)": 7.5, "power(mw)": 0.282},
247
+ {"wind_speed_(m/s)": 8.0, "power(mw)": 0.336},
248
+ {"wind_speed_(m/s)": 8.5, "power(mw)": 0.408},
249
+ {"wind_speed_(m/s)": 9.0, "power(mw)": 0.48},
250
+ {"wind_speed_(m/s)": 9.5, "power(mw)": 0.562},
251
+ {"wind_speed_(m/s)": 10.0, "power(mw)": 0.645},
252
+ {"wind_speed_(m/s)": 10.5, "power(mw)": 0.71},
253
+ {"wind_speed_(m/s)": 11.0, "power(mw)": 0.744},
254
+ {"wind_speed_(m/s)": 11.5, "power(mw)": 0.765},
255
+ {"wind_speed_(m/s)": 12.0, "power(mw)": 0.785},
256
+ {"wind_speed_(m/s)": 12.5, "power(mw)": 0.802},
257
+ {"wind_speed_(m/s)": 13.0, "power(mw)": 0.81},
258
+ {"wind_speed_(m/s)": 13.5, "power(mw)": 0.81},
259
+ {"wind_speed_(m/s)": 14.0, "power(mw)": 0.81},
260
+ {"wind_speed_(m/s)": 14.5, "power(mw)": 0.81},
261
+ {"wind_speed_(m/s)": 15.0, "power(mw)": 0.81},
262
+ {"wind_speed_(m/s)": 15.5, "power(mw)": 0.81},
263
+ {"wind_speed_(m/s)": 16.0, "power(mw)": 0.81},
264
+ {"wind_speed_(m/s)": 16.5, "power(mw)": 0.81},
265
+ {"wind_speed_(m/s)": 17.0, "power(mw)": 0.81},
266
+ {"wind_speed_(m/s)": 17.5, "power(mw)": 0.81},
267
+ {"wind_speed_(m/s)": 18.0, "power(mw)": 0.81},
268
+ {"wind_speed_(m/s)": 18.5, "power(mw)": 0.81},
269
+ {"wind_speed_(m/s)": 19.0, "power(mw)": 0.81},
270
+ {"wind_speed_(m/s)": 19.5, "power(mw)": 0.81},
271
+ {"wind_speed_(m/s)": 20.0, "power(mw)": 0.81},
272
+ {"wind_speed_(m/s)": 20.5, "power(mw)": 0.81},
273
+ {"wind_speed_(m/s)": 21.0, "power(mw)": 0.81},
274
+ {"wind_speed_(m/s)": 21.5, "power(mw)": 0.81},
275
+ {"wind_speed_(m/s)": 22.0, "power(mw)": 0.81},
276
+ {"wind_speed_(m/s)": 22.5, "power(mw)": 0.81},
277
+ {"wind_speed_(m/s)": 23.0, "power(mw)": 0.81},
278
+ {"wind_speed_(m/s)": 23.5, "power(mw)": 0.81},
279
+ {"wind_speed_(m/s)": 24.0, "power(mw)": 0.81},
280
+ {"wind_speed_(m/s)": 24.5, "power(mw)": 0.81},
281
+ {"wind_speed_(m/s)": 25.0, "power(mw)": 0.81},
282
+ ],
283
+ )
284
+
285
+ vestas_v52_850 = dict(
286
+ brand="Vestas",
287
+ model="V52 850kW",
288
+ rated_power_mw=0.85,
289
+ cut_in=3.0,
290
+ cut_out=25.0,
291
+ power_curve_source="https://www.thewindpower.net/turbine_en_27_vestas_v52-850.php",
292
+ power_curve=[
293
+ {"wind_speed_(m/s)": 0.0, "power(mw)": 0.0},
294
+ {"wind_speed_(m/s)": 0.5, "power(mw)": 0.0},
295
+ {"wind_speed_(m/s)": 1.0, "power(mw)": 0.0},
296
+ {"wind_speed_(m/s)": 1.5, "power(mw)": 0.0},
297
+ {"wind_speed_(m/s)": 2.0, "power(mw)": 0.0},
298
+ {"wind_speed_(m/s)": 2.5, "power(mw)": 0.0},
299
+ {"wind_speed_(m/s)": 3.0, "power(mw)": 0.005},
300
+ {"wind_speed_(m/s)": 3.5, "power(mw)": 0.015},
301
+ {"wind_speed_(m/s)": 4.0, "power(mw)": 0.03},
302
+ {"wind_speed_(m/s)": 4.5, "power(mw)": 0.049},
303
+ {"wind_speed_(m/s)": 5.0, "power(mw)": 0.067},
304
+ {"wind_speed_(m/s)": 5.5, "power(mw)": 0.097},
305
+ {"wind_speed_(m/s)": 6.0, "power(mw)": 0.127},
306
+ {"wind_speed_(m/s)": 6.5, "power(mw)": 0.162},
307
+ {"wind_speed_(m/s)": 7.0, "power(mw)": 0.197},
308
+ {"wind_speed_(m/s)": 7.5, "power(mw)": 0.244},
309
+ {"wind_speed_(m/s)": 8.0, "power(mw)": 0.29},
310
+ {"wind_speed_(m/s)": 8.5, "power(mw)": 0.35},
311
+ {"wind_speed_(m/s)": 9.0, "power(mw)": 0.41},
312
+ {"wind_speed_(m/s)": 9.5, "power(mw)": 0.475},
313
+ {"wind_speed_(m/s)": 10.0, "power(mw)": 0.539},
314
+ {"wind_speed_(m/s)": 10.5, "power(mw)": 0.6},
315
+ {"wind_speed_(m/s)": 11.0, "power(mw)": 0.66},
316
+ {"wind_speed_(m/s)": 11.5, "power(mw)": 0.71},
317
+ {"wind_speed_(m/s)": 12.0, "power(mw)": 0.751},
318
+ {"wind_speed_(m/s)": 12.5, "power(mw)": 0.784},
319
+ {"wind_speed_(m/s)": 13.0, "power(mw)": 0.816},
320
+ {"wind_speed_(m/s)": 13.5, "power(mw)": 0.84},
321
+ {"wind_speed_(m/s)": 14.0, "power(mw)": 0.85},
322
+ {"wind_speed_(m/s)": 14.5, "power(mw)": 0.85},
323
+ {"wind_speed_(m/s)": 15.0, "power(mw)": 0.85},
324
+ {"wind_speed_(m/s)": 15.5, "power(mw)": 0.85},
325
+ {"wind_speed_(m/s)": 16.0, "power(mw)": 0.85},
326
+ {"wind_speed_(m/s)": 16.5, "power(mw)": 0.85},
327
+ {"wind_speed_(m/s)": 17.0, "power(mw)": 0.85},
328
+ {"wind_speed_(m/s)": 17.5, "power(mw)": 0.85},
329
+ {"wind_speed_(m/s)": 18.0, "power(mw)": 0.85},
330
+ {"wind_speed_(m/s)": 18.5, "power(mw)": 0.85},
331
+ {"wind_speed_(m/s)": 19.0, "power(mw)": 0.85},
332
+ {"wind_speed_(m/s)": 19.5, "power(mw)": 0.85},
333
+ {"wind_speed_(m/s)": 20.0, "power(mw)": 0.85},
334
+ {"wind_speed_(m/s)": 20.5, "power(mw)": 0.85},
335
+ {"wind_speed_(m/s)": 21.0, "power(mw)": 0.85},
336
+ {"wind_speed_(m/s)": 21.5, "power(mw)": 0.85},
337
+ {"wind_speed_(m/s)": 22.0, "power(mw)": 0.85},
338
+ {"wind_speed_(m/s)": 22.5, "power(mw)": 0.85},
339
+ {"wind_speed_(m/s)": 23.0, "power(mw)": 0.85},
340
+ {"wind_speed_(m/s)": 23.5, "power(mw)": 0.85},
341
+ {"wind_speed_(m/s)": 24.0, "power(mw)": 0.85},
342
+ {"wind_speed_(m/s)": 24.5, "power(mw)": 0.85},
343
+ {"wind_speed_(m/s)": 25.0, "power(mw)": 0.85},
344
+ ],
345
+ )
@@ -184,26 +184,19 @@ class OutputSet:
184
184
  class PathDefinitions:
185
185
  """A class containing hard-coded path definitions."""
186
186
 
187
- @staticmethod
188
- def default_outputs_folder_name():
189
- return "Outputs"
190
-
191
187
  @staticmethod
192
188
  def outputs_plotly_folder_name():
193
189
  return "PlotlyFigures"
194
190
 
195
191
  @staticmethod
196
- def get_outputs_folder_name():
197
- # Get name from environment variable if it exists, otherwise use default name
198
- folder_name = os.getenv("OUTPUTS_FOLDER")
199
- if folder_name is None:
200
- folder_name = PathDefinitions.default_outputs_folder_name()
201
- return folder_name
192
+ def default_outputs_folder_dir():
193
+ return Path.cwd().joinpath("Outputs")
202
194
 
203
195
  @staticmethod
204
196
  def get_outputs_folder_dir():
205
- # Base directory of the folder containing all model outputs
206
- return Path.cwd().joinpath(PathDefinitions.get_outputs_folder_name())
197
+ # Get path from environment variable if it exists, otherwise use default path
198
+ output_dir = os.getenv("OUTPUT_DIR")
199
+ return Path(output_dir) if output_dir else PathDefinitions.default_outputs_folder_dir()
207
200
 
208
201
  @staticmethod
209
202
  def get_outputs_plotly_folder_dir():
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "detquantlib"
3
- version = "3.15.0"
3
+ version = "4.0.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"
@@ -1,4 +0,0 @@
1
- from .battery import Battery
2
- from .wind_turbine import WindTurbine
3
-
4
- __all__ = ["Battery", "WindTurbine"]
@@ -1,92 +0,0 @@
1
- # Third-party packages
2
- import numpy as np
3
- import pandas as pd
4
- from scipy.interpolate import CubicSpline
5
-
6
-
7
- class WindTurbine:
8
- """A class to store wind turbine information and perform wind turbine-related calculations."""
9
-
10
- def __init__(
11
- self, rated_power: float, cut_in: float, cut_out: float, power_curve: CubicSpline = None
12
- ):
13
- """
14
- Constructor method.
15
-
16
- Args:
17
- rated_power: Rated power
18
- cut_in: Cut-in wind speed
19
- cut_out: Cut-out wind speed
20
- power_curve: Power curve, stored as a cubic spline object. If not provided, can be
21
- set via the 'fit_power_curve()' method below.
22
- """
23
- self.rated_power = rated_power
24
- self.cut_in = cut_in
25
- self.cut_out = cut_out
26
- self.power_curve = power_curve
27
-
28
- def fit_power_curve(
29
- self, wind_speed: list | np.ndarray | pd.Series, power: list | np.ndarray | pd.Series
30
- ):
31
- """
32
- Fits the wind turbine's power curve with a cubic spline, and stores the resulting spline
33
- object in attribute self.power_curve.
34
-
35
- Args:
36
- wind_speed: Wind speeds
37
- power: Corresponding power
38
- """
39
- # Make sure input data is stored as numpy array
40
- wind_speed, power = np.array(wind_speed), np.array(power)
41
-
42
- # Trim data to cut-in - cut-out interval
43
- idx = (wind_speed >= self.cut_in) & (wind_speed <= self.cut_out)
44
- wind_speed_trim, power_trim = wind_speed[idx], power[idx]
45
-
46
- # Add data point with power=0.0 before cut-in to ensure smooth behaviour of spline
47
- # interpolation
48
- w0 = wind_speed_trim[0] - np.diff(wind_speed_trim[:2])
49
- p0 = [0]
50
- wind_speed_trim, power_trim = np.concat([w0, wind_speed_trim]), np.concat([p0, power_trim])
51
-
52
- # Fit cubic spline
53
- cs = CubicSpline(wind_speed_trim, power_trim)
54
-
55
- # Store spline object
56
- self.power_curve = cs
57
-
58
- def wind_to_power(self, wind_speed: list | np.ndarray | pd.Series) -> np.ndarray:
59
- """
60
- Converts wind speeds to wind turbine power.
61
-
62
- Args:
63
- wind_speed: Wind speeds
64
-
65
- Returns:
66
- Corresponding power
67
-
68
- Raises:
69
- ValueError: Raises an error if self.power_curve is None.
70
- """
71
- # Check that power curve attribute is defined
72
- if self.power_curve is None:
73
- raise ValueError(
74
- "Cannot execute method self.wind_to_power() if attribute self.power_curve is "
75
- "None. Use method self.fit_power_curve() to set self.power_curve based on power "
76
- "curve data."
77
- )
78
-
79
- # Make sure input data is stored as numpy array
80
- wind_speed = np.array(wind_speed)
81
-
82
- # Cubic spline interpolation
83
- power = self.power_curve(wind_speed)
84
-
85
- # Cap to rated power
86
- power = np.minimum(power, self.rated_power)
87
-
88
- # Adjust values outside of cut-in - cut-out bounds
89
- idx = (wind_speed < self.cut_in) | (wind_speed > self.cut_out)
90
- power[idx] = 0.0
91
-
92
- return power
File without changes