foxes 0.7.0.6__py3-none-any.whl → 0.7.2__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 foxes might be problematic. Click here for more details.
- foxes/VERSION +1 -1
- foxes/algorithms/downwind/downwind.py +6 -4
- foxes/core/wake_frame.py +4 -4
- foxes/models/__init__.py +1 -1
- foxes/models/model_book.py +385 -248
- foxes/models/wake_models/wind/bastankhah14.py +1 -1
- foxes/models/wake_models/wind/turbopark.py +67 -17
- foxes/models/wake_superpositions/__init__.py +4 -4
- foxes/models/wake_superpositions/ws_linear.py +156 -0
- foxes/models/wake_superpositions/ws_max.py +159 -0
- foxes/models/wake_superpositions/ws_pow.py +162 -0
- foxes/models/wake_superpositions/ws_quadratic.py +156 -0
- foxes/utils/__init__.py +1 -0
- foxes/utils/factory.py +349 -0
- {foxes-0.7.0.6.dist-info → foxes-0.7.2.dist-info}/METADATA +1 -1
- {foxes-0.7.0.6.dist-info → foxes-0.7.2.dist-info}/RECORD +23 -22
- /foxes/models/{axial_induction_models → axial_induction}/__init__.py +0 -0
- /foxes/models/{axial_induction_models → axial_induction}/betz.py +0 -0
- /foxes/models/{axial_induction_models → axial_induction}/madsen.py +0 -0
- {foxes-0.7.0.6.dist-info → foxes-0.7.2.dist-info}/LICENSE +0 -0
- {foxes-0.7.0.6.dist-info → foxes-0.7.2.dist-info}/WHEEL +0 -0
- {foxes-0.7.0.6.dist-info → foxes-0.7.2.dist-info}/top_level.txt +0 -0
- {foxes-0.7.0.6.dist-info → foxes-0.7.2.dist-info}/zip-safe +0 -0
|
@@ -18,8 +18,8 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
18
18
|
|
|
19
19
|
Attributes
|
|
20
20
|
----------
|
|
21
|
-
|
|
22
|
-
The wake growth parameter
|
|
21
|
+
k: float
|
|
22
|
+
The wake growth parameter k.
|
|
23
23
|
sbeta_factor: float
|
|
24
24
|
Factor multiplying sbeta
|
|
25
25
|
c1: float
|
|
@@ -36,10 +36,11 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
36
36
|
def __init__(
|
|
37
37
|
self,
|
|
38
38
|
superposition,
|
|
39
|
-
|
|
39
|
+
k=None,
|
|
40
40
|
sbeta_factor=0.25,
|
|
41
41
|
c1=1.5,
|
|
42
42
|
c2=0.8,
|
|
43
|
+
k_var=FV.K,
|
|
43
44
|
induction="Madsen",
|
|
44
45
|
):
|
|
45
46
|
"""
|
|
@@ -49,32 +50,43 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
49
50
|
----------
|
|
50
51
|
superposition: str
|
|
51
52
|
The wind deficit superposition
|
|
52
|
-
|
|
53
|
-
The wake growth parameter
|
|
53
|
+
k: float, optional
|
|
54
|
+
The wake growth parameter k. If not given here
|
|
55
|
+
it will be searched in the farm data.
|
|
54
56
|
sbeta_factor: float
|
|
55
57
|
Factor multiplying sbeta
|
|
56
58
|
c1: float
|
|
57
59
|
Factor from Frandsen turbulence model
|
|
58
60
|
c2: float
|
|
59
61
|
Factor from Frandsen turbulence model
|
|
62
|
+
k_var: str
|
|
63
|
+
The variable name for k
|
|
60
64
|
induction: foxes.core.AxialInductionModel or str
|
|
61
65
|
The induction model
|
|
62
66
|
|
|
63
67
|
"""
|
|
64
68
|
super().__init__(superpositions={FV.WS: superposition})
|
|
65
69
|
|
|
66
|
-
self.A = A
|
|
67
70
|
self.sbeta_factor = sbeta_factor
|
|
68
71
|
self.c1 = c1
|
|
69
72
|
self.c2 = c2
|
|
73
|
+
self.k_var = k_var
|
|
70
74
|
self.induction = induction
|
|
71
75
|
|
|
76
|
+
setattr(self, k_var, k)
|
|
77
|
+
|
|
72
78
|
def __repr__(self):
|
|
79
|
+
k = getattr(self, self.k_var)
|
|
73
80
|
iname = (
|
|
74
81
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
75
82
|
)
|
|
76
83
|
s = f"{type(self).__name__}"
|
|
77
|
-
s += f"({self.superpositions[FV.WS]},
|
|
84
|
+
s += f"({self.superpositions[FV.WS]}, induction={iname}"
|
|
85
|
+
if k is None:
|
|
86
|
+
s += f", k_var={self.k_var}"
|
|
87
|
+
else:
|
|
88
|
+
s += f", {self.k_var}={k}"
|
|
89
|
+
s += ")"
|
|
78
90
|
return s
|
|
79
91
|
|
|
80
92
|
def sub_models(self):
|
|
@@ -188,6 +200,18 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
188
200
|
upcast=True,
|
|
189
201
|
)[st_sel]
|
|
190
202
|
|
|
203
|
+
# get k:
|
|
204
|
+
k = self.get_data(
|
|
205
|
+
self.k_var,
|
|
206
|
+
FC.STATE_TARGET,
|
|
207
|
+
lookup="sw",
|
|
208
|
+
algo=algo,
|
|
209
|
+
fdata=fdata,
|
|
210
|
+
tdata=tdata,
|
|
211
|
+
downwind_index=downwind_index,
|
|
212
|
+
upcast=True,
|
|
213
|
+
)[st_sel]
|
|
214
|
+
|
|
191
215
|
# calculate sigma:
|
|
192
216
|
# beta = np.sqrt(0.5 * (1 + np.sqrt(1.0 - ct)) / np.sqrt(1.0 - ct))
|
|
193
217
|
a = self.induction.ct2a(ct)
|
|
@@ -201,7 +225,7 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
201
225
|
# calculate sigma (eqn 4)
|
|
202
226
|
sigma = D * (
|
|
203
227
|
epsilon
|
|
204
|
-
+
|
|
228
|
+
+ k
|
|
205
229
|
* ati
|
|
206
230
|
/ beta
|
|
207
231
|
* (
|
|
@@ -246,10 +270,12 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
246
270
|
----------
|
|
247
271
|
dx: float
|
|
248
272
|
The step size of the integral
|
|
249
|
-
|
|
250
|
-
The wake growth parameter
|
|
273
|
+
k: float
|
|
274
|
+
The wake growth parameter k.
|
|
251
275
|
sbeta_factor: float
|
|
252
276
|
Factor multiplying sbeta
|
|
277
|
+
k_var: str
|
|
278
|
+
The variable name for k
|
|
253
279
|
ti_var: str
|
|
254
280
|
The TI variable
|
|
255
281
|
self_wake: bool
|
|
@@ -267,8 +293,9 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
267
293
|
self,
|
|
268
294
|
superposition,
|
|
269
295
|
dx,
|
|
270
|
-
|
|
296
|
+
k=None,
|
|
271
297
|
sbeta_factor=0.25,
|
|
298
|
+
k_var=FV.K,
|
|
272
299
|
ti_var=FV.TI,
|
|
273
300
|
self_wake=True,
|
|
274
301
|
induction="Madsen",
|
|
@@ -283,10 +310,13 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
283
310
|
The wind deficit superposition
|
|
284
311
|
dx: float
|
|
285
312
|
The step size of the integral
|
|
286
|
-
|
|
287
|
-
The wake growth parameter
|
|
313
|
+
k: float, optional
|
|
314
|
+
The wake growth parameter k. If not given here
|
|
315
|
+
it will be searched in the farm data.
|
|
288
316
|
sbeta_factor: float
|
|
289
317
|
Factor multiplying sbeta
|
|
318
|
+
k_var: str
|
|
319
|
+
The variable name for k
|
|
290
320
|
ti_var: str
|
|
291
321
|
The TI variable
|
|
292
322
|
self_wake: bool
|
|
@@ -300,20 +330,28 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
300
330
|
super().__init__(superpositions={FV.WS: superposition})
|
|
301
331
|
|
|
302
332
|
self.dx = dx
|
|
303
|
-
self.A = A
|
|
304
333
|
self.sbeta_factor = sbeta_factor
|
|
334
|
+
self.k_var = k_var
|
|
305
335
|
self.ti_var = ti_var
|
|
306
336
|
self.ipars = ipars
|
|
307
337
|
self._tiwakes = None
|
|
308
338
|
self.self_wake = self_wake
|
|
309
339
|
self.induction = induction
|
|
310
340
|
|
|
341
|
+
setattr(self, k_var, k)
|
|
342
|
+
|
|
311
343
|
def __repr__(self):
|
|
344
|
+
k = getattr(self, self.k_var)
|
|
312
345
|
iname = (
|
|
313
346
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
314
347
|
)
|
|
315
|
-
s = f"{type(self).__name__}
|
|
316
|
-
s += f"
|
|
348
|
+
s = f"{type(self).__name__}"
|
|
349
|
+
s += f"({self.superpositions[FV.WS]}, induction={iname}, dx={self.dx}"
|
|
350
|
+
if k is None:
|
|
351
|
+
s += f", k_var={self.k_var}"
|
|
352
|
+
else:
|
|
353
|
+
s += f", {self.k_var}={k}"
|
|
354
|
+
s += f", ti_var={self.ti_var})"
|
|
317
355
|
return s
|
|
318
356
|
|
|
319
357
|
def sub_models(self):
|
|
@@ -451,6 +489,18 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
451
489
|
upcast=True,
|
|
452
490
|
)[st_sel]
|
|
453
491
|
|
|
492
|
+
# get k:
|
|
493
|
+
k = self.get_data(
|
|
494
|
+
self.k_var,
|
|
495
|
+
FC.STATE_TARGET,
|
|
496
|
+
lookup="sw",
|
|
497
|
+
algo=algo,
|
|
498
|
+
fdata=fdata,
|
|
499
|
+
tdata=tdata,
|
|
500
|
+
downwind_index=downwind_index,
|
|
501
|
+
upcast=True,
|
|
502
|
+
)[st_sel]
|
|
503
|
+
|
|
454
504
|
# calculate sigma:
|
|
455
505
|
# beta = np.sqrt(0.5 * (1 + np.sqrt(1.0 - ct)) / np.sqrt(1.0 - ct))
|
|
456
506
|
a = self.induction.ct2a(ct)
|
|
@@ -473,7 +523,7 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
473
523
|
)[:, :, 0]
|
|
474
524
|
|
|
475
525
|
# calculate sigma (eqn 1, plus epsilon from eqn 4 for x = 0)
|
|
476
|
-
sigma = D * epsilon +
|
|
526
|
+
sigma = D * epsilon + k * ti_ix[st_sel]
|
|
477
527
|
del x, epsilon
|
|
478
528
|
|
|
479
529
|
# calculate amplitude, same as in Bastankhah model (eqn 7)
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
Wake superposition models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .ws_linear import WSLinear
|
|
6
|
-
from .ws_quadratic import WSQuadratic
|
|
7
|
-
from .ws_pow import WSPow
|
|
8
|
-
from .ws_max import WSMax
|
|
5
|
+
from .ws_linear import WSLinear, WSLinearLocal
|
|
6
|
+
from .ws_quadratic import WSQuadratic, WSQuadraticLocal
|
|
7
|
+
from .ws_pow import WSPow, WSPowLocal
|
|
8
|
+
from .ws_max import WSMax, WSMaxLocal
|
|
9
9
|
from .ws_product import WSProduct
|
|
10
10
|
from .ti_linear import TILinear
|
|
11
11
|
from .ti_quadratic import TIQuadratic
|
|
@@ -178,3 +178,159 @@ class WSLinear(WakeSuperposition):
|
|
|
178
178
|
if self.lim_high is not None:
|
|
179
179
|
w = np.minimum(w, self.lim_high - amb_results)
|
|
180
180
|
return w
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class WSLinearLocal(WakeSuperposition):
|
|
184
|
+
"""
|
|
185
|
+
Local linear supersposition of wind deficit results
|
|
186
|
+
|
|
187
|
+
Attributes
|
|
188
|
+
----------
|
|
189
|
+
lim_low: float
|
|
190
|
+
Lower limit of the final waked wind speed
|
|
191
|
+
lim_high: float
|
|
192
|
+
Upper limit of the final waked wind speed
|
|
193
|
+
|
|
194
|
+
:group: models.wake_superpositions
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
def __init__(self, lim_low=None, lim_high=None):
|
|
199
|
+
"""
|
|
200
|
+
Constructor.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
lim_low: float
|
|
205
|
+
Lower limit of the final waked wind speed
|
|
206
|
+
lim_high: float
|
|
207
|
+
Upper limit of the final waked wind speed
|
|
208
|
+
|
|
209
|
+
"""
|
|
210
|
+
super().__init__()
|
|
211
|
+
self.lim_low = lim_low
|
|
212
|
+
self.lim_high = lim_high
|
|
213
|
+
|
|
214
|
+
def __repr__(self):
|
|
215
|
+
a = f"lim_low={self.lim_low}, lim_high={self.lim_high}"
|
|
216
|
+
return f"{type(self).__name__}({a})"
|
|
217
|
+
|
|
218
|
+
def input_farm_vars(self, algo):
|
|
219
|
+
"""
|
|
220
|
+
The variables which are needed for running
|
|
221
|
+
the model.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
algo: foxes.core.Algorithm
|
|
226
|
+
The calculation algorithm
|
|
227
|
+
|
|
228
|
+
Returns
|
|
229
|
+
-------
|
|
230
|
+
input_vars: list of str
|
|
231
|
+
The input variable names
|
|
232
|
+
|
|
233
|
+
"""
|
|
234
|
+
return []
|
|
235
|
+
|
|
236
|
+
def add_wake(
|
|
237
|
+
self,
|
|
238
|
+
algo,
|
|
239
|
+
mdata,
|
|
240
|
+
fdata,
|
|
241
|
+
tdata,
|
|
242
|
+
downwind_index,
|
|
243
|
+
st_sel,
|
|
244
|
+
variable,
|
|
245
|
+
wake_delta,
|
|
246
|
+
wake_model_result,
|
|
247
|
+
):
|
|
248
|
+
"""
|
|
249
|
+
Add a wake delta to previous wake deltas,
|
|
250
|
+
at rotor points.
|
|
251
|
+
|
|
252
|
+
Parameters
|
|
253
|
+
----------
|
|
254
|
+
algo: foxes.core.Algorithm
|
|
255
|
+
The calculation algorithm
|
|
256
|
+
mdata: foxes.core.MData
|
|
257
|
+
The model data
|
|
258
|
+
fdata: foxes.core.FData
|
|
259
|
+
The farm data
|
|
260
|
+
tdata: foxes.core.TData
|
|
261
|
+
The target point data
|
|
262
|
+
downwind_index: int
|
|
263
|
+
The index of the wake causing turbine
|
|
264
|
+
in the downwnd order
|
|
265
|
+
st_sel: numpy.ndarray of bool
|
|
266
|
+
The selection of targets, shape: (n_states, n_targets)
|
|
267
|
+
variable: str
|
|
268
|
+
The variable name for which the wake deltas applies
|
|
269
|
+
wake_delta: numpy.ndarray
|
|
270
|
+
The original wake deltas, shape:
|
|
271
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
272
|
+
wake_model_result: numpy.ndarray
|
|
273
|
+
The new wake deltas of the selected rotors,
|
|
274
|
+
shape: (n_st_sel, n_tpoints, ...)
|
|
275
|
+
|
|
276
|
+
Returns
|
|
277
|
+
-------
|
|
278
|
+
wdelta: numpy.ndarray
|
|
279
|
+
The updated wake deltas, shape:
|
|
280
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
281
|
+
|
|
282
|
+
"""
|
|
283
|
+
if variable not in [FV.REWS, FV.REWS2, FV.REWS3, FV.WS]:
|
|
284
|
+
raise ValueError(
|
|
285
|
+
f"Superposition '{self.name}': Expecting wind speed variable, got {variable}"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if np.any(st_sel):
|
|
289
|
+
wake_delta[st_sel] += wake_model_result
|
|
290
|
+
|
|
291
|
+
return wake_delta
|
|
292
|
+
|
|
293
|
+
def calc_final_wake_delta(
|
|
294
|
+
self,
|
|
295
|
+
algo,
|
|
296
|
+
mdata,
|
|
297
|
+
fdata,
|
|
298
|
+
variable,
|
|
299
|
+
amb_results,
|
|
300
|
+
wake_delta,
|
|
301
|
+
):
|
|
302
|
+
"""
|
|
303
|
+
Calculate the final wake delta after adding all
|
|
304
|
+
contributions.
|
|
305
|
+
|
|
306
|
+
Parameters
|
|
307
|
+
----------
|
|
308
|
+
algo: foxes.core.Algorithm
|
|
309
|
+
The calculation algorithm
|
|
310
|
+
mdata: foxes.core.MData
|
|
311
|
+
The model data
|
|
312
|
+
fdata: foxes.core.FData
|
|
313
|
+
The farm data
|
|
314
|
+
variable: str
|
|
315
|
+
The variable name for which the wake deltas applies
|
|
316
|
+
amb_results: numpy.ndarray
|
|
317
|
+
The ambient results at targets,
|
|
318
|
+
shape: (n_states, n_targets, n_tpoints)
|
|
319
|
+
wake_delta: numpy.ndarray
|
|
320
|
+
The wake deltas at targets, shape:
|
|
321
|
+
(n_states, n_targets, n_tpoints)
|
|
322
|
+
|
|
323
|
+
Returns
|
|
324
|
+
-------
|
|
325
|
+
final_wake_delta: numpy.ndarray
|
|
326
|
+
The final wake delta, which will be added to the ambient
|
|
327
|
+
results by simple plus operation. Shape:
|
|
328
|
+
(n_states, n_targets, n_tpoints)
|
|
329
|
+
|
|
330
|
+
"""
|
|
331
|
+
w = wake_delta * amb_results
|
|
332
|
+
if self.lim_low is not None:
|
|
333
|
+
w = np.maximum(w, self.lim_low - amb_results)
|
|
334
|
+
if self.lim_high is not None:
|
|
335
|
+
w = np.minimum(w, self.lim_high - amb_results)
|
|
336
|
+
return w
|
|
@@ -181,3 +181,162 @@ class WSMax(WakeSuperposition):
|
|
|
181
181
|
if self.lim_high is not None:
|
|
182
182
|
w = np.minimum(w, self.lim_high - amb_results)
|
|
183
183
|
return w
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class WSMaxLocal(WakeSuperposition):
|
|
187
|
+
"""
|
|
188
|
+
Local max supersposition of wind deficit results
|
|
189
|
+
|
|
190
|
+
Attributes
|
|
191
|
+
----------
|
|
192
|
+
lim_low: float
|
|
193
|
+
Lower limit of the final waked wind speed
|
|
194
|
+
lim_high: float
|
|
195
|
+
Upper limit of the final waked wind speed
|
|
196
|
+
|
|
197
|
+
:group: models.wake_superpositions
|
|
198
|
+
|
|
199
|
+
"""
|
|
200
|
+
|
|
201
|
+
def __init__(self, lim_low=None, lim_high=None):
|
|
202
|
+
"""
|
|
203
|
+
Constructor.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
lim_low: float
|
|
208
|
+
Lower limit of the final waked wind speed
|
|
209
|
+
lim_high: float
|
|
210
|
+
Upper limit of the final waked wind speed
|
|
211
|
+
|
|
212
|
+
"""
|
|
213
|
+
super().__init__()
|
|
214
|
+
self.lim_low = lim_low
|
|
215
|
+
self.lim_high = lim_high
|
|
216
|
+
|
|
217
|
+
def __repr__(self):
|
|
218
|
+
a = f"lim_low={self.lim_low}, lim_high={self.lim_high}"
|
|
219
|
+
return f"{type(self).__name__}({a})"
|
|
220
|
+
|
|
221
|
+
def input_farm_vars(self, algo):
|
|
222
|
+
"""
|
|
223
|
+
The variables which are needed for running
|
|
224
|
+
the model.
|
|
225
|
+
|
|
226
|
+
Parameters
|
|
227
|
+
----------
|
|
228
|
+
algo: foxes.core.Algorithm
|
|
229
|
+
The calculation algorithm
|
|
230
|
+
|
|
231
|
+
Returns
|
|
232
|
+
-------
|
|
233
|
+
input_vars: list of str
|
|
234
|
+
The input variable names
|
|
235
|
+
|
|
236
|
+
"""
|
|
237
|
+
return []
|
|
238
|
+
|
|
239
|
+
def add_wake(
|
|
240
|
+
self,
|
|
241
|
+
algo,
|
|
242
|
+
mdata,
|
|
243
|
+
fdata,
|
|
244
|
+
tdata,
|
|
245
|
+
downwind_index,
|
|
246
|
+
st_sel,
|
|
247
|
+
variable,
|
|
248
|
+
wake_delta,
|
|
249
|
+
wake_model_result,
|
|
250
|
+
):
|
|
251
|
+
"""
|
|
252
|
+
Add a wake delta to previous wake deltas,
|
|
253
|
+
at rotor points.
|
|
254
|
+
|
|
255
|
+
Parameters
|
|
256
|
+
----------
|
|
257
|
+
algo: foxes.core.Algorithm
|
|
258
|
+
The calculation algorithm
|
|
259
|
+
mdata: foxes.core.MData
|
|
260
|
+
The model data
|
|
261
|
+
fdata: foxes.core.FData
|
|
262
|
+
The farm data
|
|
263
|
+
tdata: foxes.core.TData
|
|
264
|
+
The target point data
|
|
265
|
+
downwind_index: int
|
|
266
|
+
The index of the wake causing turbine
|
|
267
|
+
in the downwnd order
|
|
268
|
+
st_sel: numpy.ndarray of bool
|
|
269
|
+
The selection of targets, shape: (n_states, n_targets)
|
|
270
|
+
variable: str
|
|
271
|
+
The variable name for which the wake deltas applies
|
|
272
|
+
wake_delta: numpy.ndarray
|
|
273
|
+
The original wake deltas, shape:
|
|
274
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
275
|
+
wake_model_result: numpy.ndarray
|
|
276
|
+
The new wake deltas of the selected rotors,
|
|
277
|
+
shape: (n_st_sel, n_tpoints, ...)
|
|
278
|
+
|
|
279
|
+
Returns
|
|
280
|
+
-------
|
|
281
|
+
wdelta: numpy.ndarray
|
|
282
|
+
The updated wake deltas, shape:
|
|
283
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
284
|
+
|
|
285
|
+
"""
|
|
286
|
+
if variable not in [FV.REWS, FV.REWS2, FV.REWS3, FV.WS]:
|
|
287
|
+
raise ValueError(
|
|
288
|
+
f"Superposition '{self.name}': Expecting wind speed variable, got {variable}"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if np.any(st_sel):
|
|
292
|
+
wake_model_result = np.abs(wake_model_result)
|
|
293
|
+
odelta = wake_delta[st_sel]
|
|
294
|
+
|
|
295
|
+
wake_delta[st_sel] = np.maximum(odelta, wake_model_result)
|
|
296
|
+
|
|
297
|
+
return wake_delta
|
|
298
|
+
|
|
299
|
+
def calc_final_wake_delta(
|
|
300
|
+
self,
|
|
301
|
+
algo,
|
|
302
|
+
mdata,
|
|
303
|
+
fdata,
|
|
304
|
+
variable,
|
|
305
|
+
amb_results,
|
|
306
|
+
wake_delta,
|
|
307
|
+
):
|
|
308
|
+
"""
|
|
309
|
+
Calculate the final wake delta after adding all
|
|
310
|
+
contributions.
|
|
311
|
+
|
|
312
|
+
Parameters
|
|
313
|
+
----------
|
|
314
|
+
algo: foxes.core.Algorithm
|
|
315
|
+
The calculation algorithm
|
|
316
|
+
mdata: foxes.core.MData
|
|
317
|
+
The model data
|
|
318
|
+
fdata: foxes.core.FData
|
|
319
|
+
The farm data
|
|
320
|
+
variable: str
|
|
321
|
+
The variable name for which the wake deltas applies
|
|
322
|
+
amb_results: numpy.ndarray
|
|
323
|
+
The ambient results at targets,
|
|
324
|
+
shape: (n_states, n_targets, n_tpoints)
|
|
325
|
+
wake_delta: numpy.ndarray
|
|
326
|
+
The wake deltas at targets, shape:
|
|
327
|
+
(n_states, n_targets, n_tpoints)
|
|
328
|
+
|
|
329
|
+
Returns
|
|
330
|
+
-------
|
|
331
|
+
final_wake_delta: numpy.ndarray
|
|
332
|
+
The final wake delta, which will be added to the ambient
|
|
333
|
+
results by simple plus operation. Shape:
|
|
334
|
+
(n_states, n_targets, n_tpoints)
|
|
335
|
+
|
|
336
|
+
"""
|
|
337
|
+
w = -wake_delta * amb_results
|
|
338
|
+
if self.lim_low is not None:
|
|
339
|
+
w = np.maximum(w, self.lim_low - amb_results)
|
|
340
|
+
if self.lim_high is not None:
|
|
341
|
+
w = np.minimum(w, self.lim_high - amb_results)
|
|
342
|
+
return w
|
|
@@ -183,3 +183,165 @@ class WSPow(WakeSuperposition):
|
|
|
183
183
|
if self.lim_high is not None:
|
|
184
184
|
w = np.minimum(w, self.lim_high - amb_results)
|
|
185
185
|
return w
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class WSPowLocal(WakeSuperposition):
|
|
189
|
+
"""
|
|
190
|
+
Local power supersposition of wind deficit results
|
|
191
|
+
|
|
192
|
+
Attributes
|
|
193
|
+
----------
|
|
194
|
+
pow: float
|
|
195
|
+
The power to which to take the wake results
|
|
196
|
+
lim_low: float
|
|
197
|
+
Lower limit of the final waked wind speed
|
|
198
|
+
lim_high: float
|
|
199
|
+
Upper limit of the final waked wind speed
|
|
200
|
+
|
|
201
|
+
:group: models.wake_superpositions
|
|
202
|
+
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
def __init__(self, pow, lim_low=None, lim_high=None):
|
|
206
|
+
"""
|
|
207
|
+
Constructor.
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
pow: float
|
|
212
|
+
The power to which to take the wake results
|
|
213
|
+
lim_low: float
|
|
214
|
+
Lower limit of the final waked wind speed
|
|
215
|
+
lim_high: float
|
|
216
|
+
Upper limit of the final waked wind speed
|
|
217
|
+
|
|
218
|
+
"""
|
|
219
|
+
super().__init__()
|
|
220
|
+
|
|
221
|
+
self.pow = pow
|
|
222
|
+
self.lim_low = lim_low
|
|
223
|
+
self.lim_high = lim_high
|
|
224
|
+
|
|
225
|
+
def __repr__(self):
|
|
226
|
+
a = f"pow={self.pow}, lim_low={self.lim_low}, lim_high={self.lim_high}"
|
|
227
|
+
return f"{type(self).__name__}({a})"
|
|
228
|
+
|
|
229
|
+
def input_farm_vars(self, algo):
|
|
230
|
+
"""
|
|
231
|
+
The variables which are needed for running
|
|
232
|
+
the model.
|
|
233
|
+
|
|
234
|
+
Parameters
|
|
235
|
+
----------
|
|
236
|
+
algo: foxes.core.Algorithm
|
|
237
|
+
The calculation algorithm
|
|
238
|
+
|
|
239
|
+
Returns
|
|
240
|
+
-------
|
|
241
|
+
input_vars: list of str
|
|
242
|
+
The input variable names
|
|
243
|
+
|
|
244
|
+
"""
|
|
245
|
+
return []
|
|
246
|
+
|
|
247
|
+
def add_wake(
|
|
248
|
+
self,
|
|
249
|
+
algo,
|
|
250
|
+
mdata,
|
|
251
|
+
fdata,
|
|
252
|
+
tdata,
|
|
253
|
+
downwind_index,
|
|
254
|
+
st_sel,
|
|
255
|
+
variable,
|
|
256
|
+
wake_delta,
|
|
257
|
+
wake_model_result,
|
|
258
|
+
):
|
|
259
|
+
"""
|
|
260
|
+
Add a wake delta to previous wake deltas,
|
|
261
|
+
at rotor points.
|
|
262
|
+
|
|
263
|
+
Parameters
|
|
264
|
+
----------
|
|
265
|
+
algo: foxes.core.Algorithm
|
|
266
|
+
The calculation algorithm
|
|
267
|
+
mdata: foxes.core.MData
|
|
268
|
+
The model data
|
|
269
|
+
fdata: foxes.core.FData
|
|
270
|
+
The farm data
|
|
271
|
+
tdata: foxes.core.TData
|
|
272
|
+
The target point data
|
|
273
|
+
downwind_index: int
|
|
274
|
+
The index of the wake causing turbine
|
|
275
|
+
in the downwnd order
|
|
276
|
+
st_sel: numpy.ndarray of bool
|
|
277
|
+
The selection of targets, shape: (n_states, n_targets)
|
|
278
|
+
variable: str
|
|
279
|
+
The variable name for which the wake deltas applies
|
|
280
|
+
wake_delta: numpy.ndarray
|
|
281
|
+
The original wake deltas, shape:
|
|
282
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
283
|
+
wake_model_result: numpy.ndarray
|
|
284
|
+
The new wake deltas of the selected rotors,
|
|
285
|
+
shape: (n_st_sel, n_tpoints, ...)
|
|
286
|
+
|
|
287
|
+
Returns
|
|
288
|
+
-------
|
|
289
|
+
wdelta: numpy.ndarray
|
|
290
|
+
The updated wake deltas, shape:
|
|
291
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
292
|
+
|
|
293
|
+
"""
|
|
294
|
+
if variable not in [FV.REWS, FV.REWS2, FV.REWS3, FV.WS]:
|
|
295
|
+
raise ValueError(
|
|
296
|
+
f"Superposition '{self.name}': Expecting wind speed variable, got {variable}"
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
if np.any(st_sel):
|
|
300
|
+
wake_delta[st_sel] += np.abs(wake_model_result) ** self.pow
|
|
301
|
+
|
|
302
|
+
return wake_delta
|
|
303
|
+
|
|
304
|
+
def calc_final_wake_delta(
|
|
305
|
+
self,
|
|
306
|
+
algo,
|
|
307
|
+
mdata,
|
|
308
|
+
fdata,
|
|
309
|
+
variable,
|
|
310
|
+
amb_results,
|
|
311
|
+
wake_delta,
|
|
312
|
+
):
|
|
313
|
+
"""
|
|
314
|
+
Calculate the final wake delta after adding all
|
|
315
|
+
contributions.
|
|
316
|
+
|
|
317
|
+
Parameters
|
|
318
|
+
----------
|
|
319
|
+
algo: foxes.core.Algorithm
|
|
320
|
+
The calculation algorithm
|
|
321
|
+
mdata: foxes.core.MData
|
|
322
|
+
The model data
|
|
323
|
+
fdata: foxes.core.FData
|
|
324
|
+
The farm data
|
|
325
|
+
variable: str
|
|
326
|
+
The variable name for which the wake deltas applies
|
|
327
|
+
amb_results: numpy.ndarray
|
|
328
|
+
The ambient results at targets,
|
|
329
|
+
shape: (n_states, n_targets, n_tpoints)
|
|
330
|
+
wake_delta: numpy.ndarray
|
|
331
|
+
The wake deltas at targets, shape:
|
|
332
|
+
(n_states, n_targets, n_tpoints)
|
|
333
|
+
|
|
334
|
+
Returns
|
|
335
|
+
-------
|
|
336
|
+
final_wake_delta: numpy.ndarray
|
|
337
|
+
The final wake delta, which will be added to the ambient
|
|
338
|
+
results by simple plus operation. Shape:
|
|
339
|
+
(n_states, n_targets, n_tpoints)
|
|
340
|
+
|
|
341
|
+
"""
|
|
342
|
+
w = -(wake_delta ** (1 / self.pow)) * amb_results
|
|
343
|
+
if self.lim_low is not None:
|
|
344
|
+
w = np.maximum(w, self.lim_low - amb_results)
|
|
345
|
+
if self.lim_high is not None:
|
|
346
|
+
w = np.minimum(w, self.lim_high - amb_results)
|
|
347
|
+
return w
|