foxes 0.7.0.5__py3-none-any.whl → 0.7.1__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,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,161 @@ 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
+ class WSMaxLocal(WakeSuperposition):
186
+ """
187
+ Local max supersposition of wind deficit results
188
+
189
+ Attributes
190
+ ----------
191
+ lim_low: float
192
+ Lower limit of the final waked wind speed
193
+ lim_high: float
194
+ Upper limit of the final waked wind speed
195
+
196
+ :group: models.wake_superpositions
197
+
198
+ """
199
+
200
+ def __init__(self, lim_low=None, lim_high=None):
201
+ """
202
+ Constructor.
203
+
204
+ Parameters
205
+ ----------
206
+ lim_low: float
207
+ Lower limit of the final waked wind speed
208
+ lim_high: float
209
+ Upper limit of the final waked wind speed
210
+
211
+ """
212
+ super().__init__()
213
+ self.lim_low = lim_low
214
+ self.lim_high = lim_high
215
+
216
+ def __repr__(self):
217
+ a = f"lim_low={self.lim_low}, lim_high={self.lim_high}"
218
+ return f"{type(self).__name__}({a})"
219
+
220
+ def input_farm_vars(self, algo):
221
+ """
222
+ The variables which are needed for running
223
+ the model.
224
+
225
+ Parameters
226
+ ----------
227
+ algo: foxes.core.Algorithm
228
+ The calculation algorithm
229
+
230
+ Returns
231
+ -------
232
+ input_vars: list of str
233
+ The input variable names
234
+
235
+ """
236
+ return []
237
+
238
+ def add_wake(
239
+ self,
240
+ algo,
241
+ mdata,
242
+ fdata,
243
+ tdata,
244
+ downwind_index,
245
+ st_sel,
246
+ variable,
247
+ wake_delta,
248
+ wake_model_result,
249
+ ):
250
+ """
251
+ Add a wake delta to previous wake deltas,
252
+ at rotor points.
253
+
254
+ Parameters
255
+ ----------
256
+ algo: foxes.core.Algorithm
257
+ The calculation algorithm
258
+ mdata: foxes.core.MData
259
+ The model data
260
+ fdata: foxes.core.FData
261
+ The farm data
262
+ tdata: foxes.core.TData
263
+ The target point data
264
+ downwind_index: int
265
+ The index of the wake causing turbine
266
+ in the downwnd order
267
+ st_sel: numpy.ndarray of bool
268
+ The selection of targets, shape: (n_states, n_targets)
269
+ variable: str
270
+ The variable name for which the wake deltas applies
271
+ wake_delta: numpy.ndarray
272
+ The original wake deltas, shape:
273
+ (n_states, n_targets, n_tpoints, ...)
274
+ wake_model_result: numpy.ndarray
275
+ The new wake deltas of the selected rotors,
276
+ shape: (n_st_sel, n_tpoints, ...)
277
+
278
+ Returns
279
+ -------
280
+ wdelta: numpy.ndarray
281
+ The updated wake deltas, shape:
282
+ (n_states, n_targets, n_tpoints, ...)
283
+
284
+ """
285
+ if variable not in [FV.REWS, FV.REWS2, FV.REWS3, FV.WS]:
286
+ raise ValueError(
287
+ f"Superposition '{self.name}': Expecting wind speed variable, got {variable}"
288
+ )
289
+
290
+ if np.any(st_sel):
291
+ wake_model_result = np.abs(wake_model_result)
292
+ odelta = wake_delta[st_sel]
293
+
294
+ wake_delta[st_sel] = np.maximum(odelta, wake_model_result)
295
+
296
+ return wake_delta
297
+
298
+ def calc_final_wake_delta(
299
+ self,
300
+ algo,
301
+ mdata,
302
+ fdata,
303
+ variable,
304
+ amb_results,
305
+ wake_delta,
306
+ ):
307
+ """
308
+ Calculate the final wake delta after adding all
309
+ contributions.
310
+
311
+ Parameters
312
+ ----------
313
+ algo: foxes.core.Algorithm
314
+ The calculation algorithm
315
+ mdata: foxes.core.MData
316
+ The model data
317
+ fdata: foxes.core.FData
318
+ The farm data
319
+ variable: str
320
+ The variable name for which the wake deltas applies
321
+ amb_results: numpy.ndarray
322
+ The ambient results at targets,
323
+ shape: (n_states, n_targets, n_tpoints)
324
+ wake_delta: numpy.ndarray
325
+ The wake deltas at targets, shape:
326
+ (n_states, n_targets, n_tpoints)
327
+
328
+ Returns
329
+ -------
330
+ final_wake_delta: numpy.ndarray
331
+ The final wake delta, which will be added to the ambient
332
+ results by simple plus operation. Shape:
333
+ (n_states, n_targets, n_tpoints)
334
+
335
+ """
336
+ w = -wake_delta * amb_results
337
+ if self.lim_low is not None:
338
+ w = np.maximum(w, self.lim_low - amb_results)
339
+ if self.lim_high is not None:
340
+ w = np.minimum(w, self.lim_high - amb_results)
341
+ return w
@@ -183,3 +183,164 @@ 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
+ class WSPowLocal(WakeSuperposition):
188
+ """
189
+ Local power supersposition of wind deficit results
190
+
191
+ Attributes
192
+ ----------
193
+ pow: float
194
+ The power to which to take the wake results
195
+ lim_low: float
196
+ Lower limit of the final waked wind speed
197
+ lim_high: float
198
+ Upper limit of the final waked wind speed
199
+
200
+ :group: models.wake_superpositions
201
+
202
+ """
203
+
204
+ def __init__(self, pow, lim_low=None, lim_high=None):
205
+ """
206
+ Constructor.
207
+
208
+ Parameters
209
+ ----------
210
+ pow: float
211
+ The power to which to take the wake results
212
+ lim_low: float
213
+ Lower limit of the final waked wind speed
214
+ lim_high: float
215
+ Upper limit of the final waked wind speed
216
+
217
+ """
218
+ super().__init__()
219
+
220
+ self.pow = pow
221
+ self.lim_low = lim_low
222
+ self.lim_high = lim_high
223
+
224
+ def __repr__(self):
225
+ a = f"pow={self.pow}, lim_low={self.lim_low}, lim_high={self.lim_high}"
226
+ return f"{type(self).__name__}({a})"
227
+
228
+ def input_farm_vars(self, algo):
229
+ """
230
+ The variables which are needed for running
231
+ the model.
232
+
233
+ Parameters
234
+ ----------
235
+ algo: foxes.core.Algorithm
236
+ The calculation algorithm
237
+
238
+ Returns
239
+ -------
240
+ input_vars: list of str
241
+ The input variable names
242
+
243
+ """
244
+ return []
245
+
246
+ def add_wake(
247
+ self,
248
+ algo,
249
+ mdata,
250
+ fdata,
251
+ tdata,
252
+ downwind_index,
253
+ st_sel,
254
+ variable,
255
+ wake_delta,
256
+ wake_model_result,
257
+ ):
258
+ """
259
+ Add a wake delta to previous wake deltas,
260
+ at rotor points.
261
+
262
+ Parameters
263
+ ----------
264
+ algo: foxes.core.Algorithm
265
+ The calculation algorithm
266
+ mdata: foxes.core.MData
267
+ The model data
268
+ fdata: foxes.core.FData
269
+ The farm data
270
+ tdata: foxes.core.TData
271
+ The target point data
272
+ downwind_index: int
273
+ The index of the wake causing turbine
274
+ in the downwnd order
275
+ st_sel: numpy.ndarray of bool
276
+ The selection of targets, shape: (n_states, n_targets)
277
+ variable: str
278
+ The variable name for which the wake deltas applies
279
+ wake_delta: numpy.ndarray
280
+ The original wake deltas, shape:
281
+ (n_states, n_targets, n_tpoints, ...)
282
+ wake_model_result: numpy.ndarray
283
+ The new wake deltas of the selected rotors,
284
+ shape: (n_st_sel, n_tpoints, ...)
285
+
286
+ Returns
287
+ -------
288
+ wdelta: numpy.ndarray
289
+ The updated wake deltas, shape:
290
+ (n_states, n_targets, n_tpoints, ...)
291
+
292
+ """
293
+ if variable not in [FV.REWS, FV.REWS2, FV.REWS3, FV.WS]:
294
+ raise ValueError(
295
+ f"Superposition '{self.name}': Expecting wind speed variable, got {variable}"
296
+ )
297
+
298
+ if np.any(st_sel):
299
+ wake_delta[st_sel] += np.abs(wake_model_result) ** self.pow
300
+
301
+ return wake_delta
302
+
303
+ def calc_final_wake_delta(
304
+ self,
305
+ algo,
306
+ mdata,
307
+ fdata,
308
+ variable,
309
+ amb_results,
310
+ wake_delta,
311
+ ):
312
+ """
313
+ Calculate the final wake delta after adding all
314
+ contributions.
315
+
316
+ Parameters
317
+ ----------
318
+ algo: foxes.core.Algorithm
319
+ The calculation algorithm
320
+ mdata: foxes.core.MData
321
+ The model data
322
+ fdata: foxes.core.FData
323
+ The farm data
324
+ variable: str
325
+ The variable name for which the wake deltas applies
326
+ amb_results: numpy.ndarray
327
+ The ambient results at targets,
328
+ shape: (n_states, n_targets, n_tpoints)
329
+ wake_delta: numpy.ndarray
330
+ The wake deltas at targets, shape:
331
+ (n_states, n_targets, n_tpoints)
332
+
333
+ Returns
334
+ -------
335
+ final_wake_delta: numpy.ndarray
336
+ The final wake delta, which will be added to the ambient
337
+ results by simple plus operation. Shape:
338
+ (n_states, n_targets, n_tpoints)
339
+
340
+ """
341
+ w = -(wake_delta ** (1 / self.pow)) * amb_results
342
+ if self.lim_low is not None:
343
+ w = np.maximum(w, self.lim_low - amb_results)
344
+ if self.lim_high is not None:
345
+ w = np.minimum(w, self.lim_high - amb_results)
346
+ return w