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.

@@ -18,7 +18,7 @@ class Bastankhah2014(GaussianWakeModel):
18
18
 
19
19
  Attributes
20
20
  ----------
21
- k: float, optional
21
+ k: float
22
22
  The wake growth parameter k. If not given here
23
23
  it will be searched in the farm data.
24
24
  sbeta_factor: float
@@ -18,8 +18,8 @@ class TurbOParkWake(GaussianWakeModel):
18
18
 
19
19
  Attributes
20
20
  ----------
21
- A: float
22
- The wake growth parameter A.
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
- A,
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
- A: float
53
- The wake growth parameter A.
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]}, A={self.A}, induction={iname})"
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
- + self.A
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
- A: float
250
- The wake growth parameter A.
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
- A,
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
- A: float, optional
287
- The wake growth parameter A.
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__}({self.superpositions[FV.WS]}"
316
- s += f", ti={self.ti_var}, dx={self.dx}, A={self.A}, induction={iname})"
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 + self.A * ti_ix[st_sel]
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