foxes 1.3__py3-none-any.whl → 1.4__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.
- docs/source/conf.py +3 -3
- examples/abl_states/run.py +2 -2
- examples/compare_rotors_pwakes/run.py +1 -1
- examples/compare_wakes/run.py +1 -2
- examples/dyn_wakes/run.py +29 -6
- examples/induction/run.py +3 -3
- examples/multi_height/run.py +1 -1
- examples/power_mask/run.py +2 -2
- examples/quickstart/run.py +0 -1
- examples/random_timeseries/run.py +3 -4
- examples/scan_row/run.py +3 -3
- examples/sequential/run.py +33 -10
- examples/single_state/run.py +3 -4
- examples/states_lookup_table/run.py +3 -3
- examples/streamline_wakes/run.py +27 -4
- examples/tab_file/run.py +3 -3
- examples/timelines/run.py +29 -5
- examples/timeseries/run.py +3 -3
- examples/timeseries_slurm/run.py +3 -3
- examples/wind_rose/run.py +3 -3
- examples/yawed_wake/run.py +16 -8
- foxes/__init__.py +21 -17
- foxes/algorithms/__init__.py +6 -6
- foxes/algorithms/downwind/__init__.py +2 -2
- foxes/algorithms/downwind/downwind.py +44 -12
- foxes/algorithms/downwind/models/__init__.py +6 -6
- foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
- foxes/algorithms/downwind/models/init_farm_data.py +0 -1
- foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
- foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
- foxes/algorithms/iterative/__init__.py +7 -3
- foxes/algorithms/iterative/iterative.py +1 -2
- foxes/algorithms/iterative/models/__init__.py +7 -3
- foxes/algorithms/iterative/models/farm_wakes_calc.py +9 -5
- foxes/algorithms/sequential/__init__.py +3 -3
- foxes/algorithms/sequential/models/__init__.py +2 -2
- foxes/algorithms/sequential/sequential.py +3 -4
- foxes/config/__init__.py +5 -1
- foxes/constants.py +16 -0
- foxes/core/__init__.py +45 -22
- foxes/core/algorithm.py +0 -1
- foxes/core/data.py +19 -18
- foxes/core/engine.py +9 -13
- foxes/core/farm_controller.py +2 -2
- foxes/core/ground_model.py +4 -13
- foxes/core/model.py +5 -5
- foxes/core/partial_wakes_model.py +147 -10
- foxes/core/point_data_model.py +2 -3
- foxes/core/rotor_model.py +3 -3
- foxes/core/states.py +2 -3
- foxes/core/turbine.py +2 -1
- foxes/core/wake_deflection.py +130 -0
- foxes/core/wake_model.py +222 -9
- foxes/core/wake_superposition.py +122 -4
- foxes/core/wind_farm.py +6 -6
- foxes/data/__init__.py +7 -2
- foxes/data/states/weibull_sectors_12.csv +13 -0
- foxes/data/states/weibull_sectors_12.nc +0 -0
- foxes/engines/__init__.py +14 -15
- foxes/engines/dask.py +39 -14
- foxes/engines/numpy.py +0 -3
- foxes/input/__init__.py +3 -3
- foxes/input/farm_layout/__init__.py +8 -8
- foxes/input/farm_layout/from_csv.py +1 -1
- foxes/input/farm_layout/ring.py +0 -1
- foxes/input/states/__init__.py +22 -12
- foxes/input/states/create/__init__.py +3 -2
- foxes/input/states/field_data_nc.py +10 -24
- foxes/input/states/multi_height.py +9 -6
- foxes/input/states/one_point_flow.py +0 -4
- foxes/input/states/single.py +1 -1
- foxes/input/states/states_table.py +10 -7
- foxes/input/states/weibull_sectors.py +225 -0
- foxes/input/states/wrg_states.py +7 -5
- foxes/input/yaml/__init__.py +9 -3
- foxes/input/yaml/dict.py +19 -19
- foxes/input/yaml/windio/__init__.py +10 -5
- foxes/input/yaml/windio/read_attributes.py +2 -2
- foxes/input/yaml/windio/read_farm.py +5 -5
- foxes/input/yaml/windio/read_fields.py +4 -2
- foxes/input/yaml/windio/read_site.py +52 -0
- foxes/input/yaml/windio/windio.py +1 -1
- foxes/models/__init__.py +15 -14
- foxes/models/axial_induction/__init__.py +2 -2
- foxes/models/farm_controllers/__init__.py +1 -1
- foxes/models/farm_models/__init__.py +1 -1
- foxes/models/ground_models/__init__.py +3 -2
- foxes/models/ground_models/wake_mirror.py +3 -3
- foxes/models/model_book.py +175 -49
- foxes/models/partial_wakes/__init__.py +6 -6
- foxes/models/partial_wakes/axiwake.py +30 -5
- foxes/models/partial_wakes/centre.py +47 -0
- foxes/models/partial_wakes/rotor_points.py +41 -11
- foxes/models/partial_wakes/segregated.py +2 -25
- foxes/models/partial_wakes/top_hat.py +27 -2
- foxes/models/point_models/__init__.py +4 -4
- foxes/models/rotor_models/__init__.py +3 -3
- foxes/models/turbine_models/__init__.py +11 -11
- foxes/models/turbine_models/set_farm_vars.py +0 -1
- foxes/models/turbine_types/PCt_file.py +0 -2
- foxes/models/turbine_types/PCt_from_two.py +0 -2
- foxes/models/turbine_types/__init__.py +9 -9
- foxes/models/vertical_profiles/__init__.py +7 -7
- foxes/models/wake_deflections/__init__.py +3 -0
- foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
- foxes/models/wake_deflections/jimenez.py +277 -0
- foxes/models/wake_deflections/no_deflection.py +94 -0
- foxes/models/wake_frames/__init__.py +6 -7
- foxes/models/wake_frames/dynamic_wakes.py +12 -3
- foxes/models/wake_frames/rotor_wd.py +3 -1
- foxes/models/wake_frames/seq_dynamic_wakes.py +41 -7
- foxes/models/wake_frames/streamlines.py +8 -6
- foxes/models/wake_frames/timelines.py +9 -3
- foxes/models/wake_models/__init__.py +7 -7
- foxes/models/wake_models/dist_sliced.py +50 -84
- foxes/models/wake_models/gaussian.py +20 -0
- foxes/models/wake_models/induction/__init__.py +5 -5
- foxes/models/wake_models/induction/rankine_half_body.py +30 -71
- foxes/models/wake_models/induction/rathmann.py +65 -64
- foxes/models/wake_models/induction/self_similar.py +65 -68
- foxes/models/wake_models/induction/self_similar2020.py +0 -3
- foxes/models/wake_models/induction/vortex_sheet.py +71 -75
- foxes/models/wake_models/ti/__init__.py +2 -2
- foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
- foxes/models/wake_models/ti/iec_ti.py +6 -4
- foxes/models/wake_models/top_hat.py +58 -7
- foxes/models/wake_models/wind/__init__.py +6 -4
- foxes/models/wake_models/wind/bastankhah14.py +25 -7
- foxes/models/wake_models/wind/bastankhah16.py +35 -3
- foxes/models/wake_models/wind/jensen.py +15 -2
- foxes/models/wake_models/wind/turbopark.py +28 -2
- foxes/models/wake_superpositions/__init__.py +18 -9
- foxes/models/wake_superpositions/ti_linear.py +4 -4
- foxes/models/wake_superpositions/ti_max.py +4 -4
- foxes/models/wake_superpositions/ti_pow.py +4 -4
- foxes/models/wake_superpositions/ti_quadratic.py +4 -4
- foxes/models/wake_superpositions/wind_vector.py +257 -0
- foxes/models/wake_superpositions/ws_linear.py +9 -10
- foxes/models/wake_superpositions/ws_max.py +8 -8
- foxes/models/wake_superpositions/ws_pow.py +8 -8
- foxes/models/wake_superpositions/ws_product.py +4 -4
- foxes/models/wake_superpositions/ws_quadratic.py +8 -8
- foxes/output/__init__.py +21 -19
- foxes/output/farm_layout.py +2 -2
- foxes/output/farm_results_eval.py +15 -15
- foxes/output/flow_plots_2d/__init__.py +2 -2
- foxes/output/flow_plots_2d/get_fig.py +4 -2
- foxes/output/rose_plot.py +3 -3
- foxes/output/seq_plugins/__init__.py +2 -2
- foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
- foxes/output/turbine_type_curves.py +7 -8
- foxes/utils/__init__.py +37 -19
- foxes/utils/abl/__init__.py +4 -4
- foxes/utils/cubic_roots.py +1 -1
- foxes/utils/data_book.py +4 -3
- foxes/utils/dict.py +3 -3
- foxes/utils/exec_python.py +5 -5
- foxes/utils/factory.py +1 -3
- foxes/utils/geom2d/__init__.py +7 -5
- foxes/utils/geopandas_utils.py +2 -2
- foxes/utils/pandas_utils.py +4 -3
- foxes/utils/tab_files.py +0 -1
- foxes/utils/weibull.py +28 -0
- foxes/utils/wrg_utils.py +3 -1
- foxes/utils/xarray_utils.py +9 -2
- foxes/variables.py +67 -9
- {foxes-1.3.dist-info → foxes-1.4.dist-info}/METADATA +6 -15
- foxes-1.4.dist-info/RECORD +320 -0
- {foxes-1.3.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
- tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +1 -1
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +0 -1
- foxes/output/round.py +0 -10
- foxes/utils/pandas_helpers.py +0 -178
- foxes-1.3.dist-info/RECORD +0 -313
- {foxes-1.3.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
- {foxes-1.3.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
- {foxes-1.3.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
|
@@ -447,7 +447,7 @@ class Bastankhah2016(DistSlicedWakeModel):
|
|
|
447
447
|
Parameters for the WakeK class
|
|
448
448
|
|
|
449
449
|
"""
|
|
450
|
-
super().__init__(
|
|
450
|
+
super().__init__(wind_superposition=superposition)
|
|
451
451
|
|
|
452
452
|
self.model = None
|
|
453
453
|
self.alpha = alpha
|
|
@@ -460,10 +460,23 @@ class Bastankhah2016(DistSlicedWakeModel):
|
|
|
460
460
|
def __repr__(self):
|
|
461
461
|
iname = self.induction
|
|
462
462
|
s = f"{type(self).__name__}"
|
|
463
|
-
s += f"({self.
|
|
463
|
+
s += f"({self.wind_superposition}, induction={iname}, "
|
|
464
464
|
s += self.wake_k.repr() + ")"
|
|
465
465
|
return s
|
|
466
466
|
|
|
467
|
+
@property
|
|
468
|
+
def affects_ws(self):
|
|
469
|
+
"""
|
|
470
|
+
Flag for wind speed wake models
|
|
471
|
+
|
|
472
|
+
Returns
|
|
473
|
+
-------
|
|
474
|
+
dws: bool
|
|
475
|
+
If True, this model affects wind speed
|
|
476
|
+
|
|
477
|
+
"""
|
|
478
|
+
return True
|
|
479
|
+
|
|
467
480
|
def sub_models(self):
|
|
468
481
|
"""
|
|
469
482
|
List of all sub-models
|
|
@@ -474,7 +487,7 @@ class Bastankhah2016(DistSlicedWakeModel):
|
|
|
474
487
|
Names of all sub models
|
|
475
488
|
|
|
476
489
|
"""
|
|
477
|
-
return [self.wake_k, self.model]
|
|
490
|
+
return super().sub_models() + [self.wake_k, self.model]
|
|
478
491
|
|
|
479
492
|
def initialize(self, algo, verbosity=0, force=False):
|
|
480
493
|
"""
|
|
@@ -621,4 +634,23 @@ class Bastankhah2016(DistSlicedWakeModel):
|
|
|
621
634
|
* np.exp(-0.5 * (z / sigma_z) ** 2)
|
|
622
635
|
)
|
|
623
636
|
|
|
637
|
+
# wake deflection causes wind vector rotation:
|
|
638
|
+
if FC.WDEFL_ROT_ANGLE in tdata:
|
|
639
|
+
dwd_defl = tdata.pop(FC.WDEFL_ROT_ANGLE)
|
|
640
|
+
if FV.WD not in wdeltas:
|
|
641
|
+
wdeltas[FV.WD] = np.zeros_like(wdeltas[FV.WS])
|
|
642
|
+
wdeltas[FV.WD][:] = dwd_defl[st_sel]
|
|
643
|
+
else:
|
|
644
|
+
wdeltas[FV.WD] += dwd_defl[st_sel]
|
|
645
|
+
|
|
646
|
+
# wake deflection causes wind speed reduction:
|
|
647
|
+
if FC.WDEFL_DWS_FACTOR in tdata:
|
|
648
|
+
dws_defl = tdata.pop(FC.WDEFL_DWS_FACTOR)
|
|
649
|
+
if FV.WS not in wdeltas:
|
|
650
|
+
raise AssertionError(
|
|
651
|
+
f"Wake model '{self.name}': Expecting '{FV.WS}' in wdeltas, found {list(wdeltas.keys())}"
|
|
652
|
+
)
|
|
653
|
+
else:
|
|
654
|
+
wdeltas[FV.WS] *= dws_defl[st_sel]
|
|
655
|
+
|
|
624
656
|
return wdeltas, st_sel
|
|
@@ -31,7 +31,7 @@ class JensenWake(TopHatWakeModel):
|
|
|
31
31
|
Parameters for the WakeK class
|
|
32
32
|
|
|
33
33
|
"""
|
|
34
|
-
super().__init__(
|
|
34
|
+
super().__init__(wind_superposition=superposition, induction=induction)
|
|
35
35
|
self.wake_k = WakeK(**wake_k)
|
|
36
36
|
|
|
37
37
|
def __repr__(self):
|
|
@@ -39,10 +39,23 @@ class JensenWake(TopHatWakeModel):
|
|
|
39
39
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
40
40
|
)
|
|
41
41
|
s = f"{type(self).__name__}"
|
|
42
|
-
s += f"({self.
|
|
42
|
+
s += f"({self.wind_superposition}, induction={iname}, "
|
|
43
43
|
s += self.wake_k.repr() + ")"
|
|
44
44
|
return s
|
|
45
45
|
|
|
46
|
+
@property
|
|
47
|
+
def affects_ws(self):
|
|
48
|
+
"""
|
|
49
|
+
Flag for wind speed wake models
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
dws: bool
|
|
54
|
+
If True, this model affects wind speed
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
return True
|
|
58
|
+
|
|
46
59
|
def calc_wake_radius(
|
|
47
60
|
self,
|
|
48
61
|
algo,
|
|
@@ -63,7 +63,7 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
63
63
|
Parameters for the WakeK class
|
|
64
64
|
|
|
65
65
|
"""
|
|
66
|
-
super().__init__(
|
|
66
|
+
super().__init__(wind_superposition=superposition)
|
|
67
67
|
|
|
68
68
|
self.sbeta_factor = sbeta_factor
|
|
69
69
|
self.c1 = c1
|
|
@@ -76,10 +76,23 @@ class TurbOParkWake(GaussianWakeModel):
|
|
|
76
76
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
77
77
|
)
|
|
78
78
|
s = f"{type(self).__name__}"
|
|
79
|
-
s += f"({self.
|
|
79
|
+
s += f"({self.wind_superposition}, induction={iname}, "
|
|
80
80
|
s += self.wake_k.repr() + ")"
|
|
81
81
|
return s
|
|
82
82
|
|
|
83
|
+
@property
|
|
84
|
+
def affects_ws(self):
|
|
85
|
+
"""
|
|
86
|
+
Flag for wind speed wake models
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
dws: bool
|
|
91
|
+
If True, this model affects wind speed
|
|
92
|
+
|
|
93
|
+
"""
|
|
94
|
+
return True
|
|
95
|
+
|
|
83
96
|
def sub_models(self):
|
|
84
97
|
"""
|
|
85
98
|
List of all sub-models
|
|
@@ -329,6 +342,19 @@ class TurbOParkWakeIX(GaussianWakeModel):
|
|
|
329
342
|
s += self.wake_k.repr() + ")"
|
|
330
343
|
return s
|
|
331
344
|
|
|
345
|
+
@property
|
|
346
|
+
def affects_ws(self):
|
|
347
|
+
"""
|
|
348
|
+
Flag for wind speed wake models
|
|
349
|
+
|
|
350
|
+
Returns
|
|
351
|
+
-------
|
|
352
|
+
dws: bool
|
|
353
|
+
If True, this model affects wind speed
|
|
354
|
+
|
|
355
|
+
"""
|
|
356
|
+
return True
|
|
357
|
+
|
|
332
358
|
def sub_models(self):
|
|
333
359
|
"""
|
|
334
360
|
List of all sub-models
|
|
@@ -2,12 +2,21 @@
|
|
|
2
2
|
Wake superposition models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .ws_linear import WSLinear
|
|
6
|
-
from .
|
|
7
|
-
|
|
8
|
-
from .
|
|
9
|
-
from .
|
|
10
|
-
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
|
|
5
|
+
from .ws_linear import WSLinear as WSLinear
|
|
6
|
+
from .ws_linear import WSLinearLocal as WSLinearLocal
|
|
7
|
+
|
|
8
|
+
from .ws_pow import WSPow as WSPow
|
|
9
|
+
from .ws_pow import WSPowLocal as WSPowLocal
|
|
10
|
+
|
|
11
|
+
from .ws_max import WSMax as WSMax
|
|
12
|
+
from .ws_max import WSMaxLocal as WSMaxLocal
|
|
13
|
+
|
|
14
|
+
from .ws_quadratic import WSQuadratic as WSQuadratic
|
|
15
|
+
from .ws_quadratic import WSQuadraticLocal as WSQuadraticLocal
|
|
16
|
+
|
|
17
|
+
from .wind_vector import WindVectorLinear as WindVectorLinear
|
|
18
|
+
from .ws_product import WSProduct as WSProduct
|
|
19
|
+
from .ti_linear import TILinear as TILinear
|
|
20
|
+
from .ti_quadratic import TIQuadratic as TIQuadratic
|
|
21
|
+
from .ti_pow import TIPow as TIPow
|
|
22
|
+
from .ti_max import TIMax as TIMax
|
|
@@ -95,8 +95,8 @@ class TILinear(WakeSuperposition):
|
|
|
95
95
|
algo,
|
|
96
96
|
mdata,
|
|
97
97
|
fdata,
|
|
98
|
+
tdata,
|
|
98
99
|
variable,
|
|
99
|
-
amb_results,
|
|
100
100
|
wake_delta,
|
|
101
101
|
):
|
|
102
102
|
"""
|
|
@@ -111,11 +111,10 @@ class TILinear(WakeSuperposition):
|
|
|
111
111
|
The model data
|
|
112
112
|
fdata: foxes.core.FData
|
|
113
113
|
The farm data
|
|
114
|
+
tdata: foxes.core.TData
|
|
115
|
+
The target point data
|
|
114
116
|
variable: str
|
|
115
117
|
The variable name for which the wake deltas applies
|
|
116
|
-
amb_results: numpy.ndarray
|
|
117
|
-
The ambient results at targets,
|
|
118
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
119
118
|
wake_delta: numpy.ndarray
|
|
120
119
|
The wake deltas at targets, shape:
|
|
121
120
|
(n_states, n_targets, n_tpoints)
|
|
@@ -134,6 +133,7 @@ class TILinear(WakeSuperposition):
|
|
|
134
133
|
|
|
135
134
|
# quadratic superposition to ambient:
|
|
136
135
|
elif self.superp_to_amb == "quadratic":
|
|
136
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
137
137
|
return np.sqrt(wake_delta**2 + amb_results**2) - amb_results
|
|
138
138
|
|
|
139
139
|
# unknown ti delta:
|
|
@@ -95,8 +95,8 @@ class TIMax(WakeSuperposition):
|
|
|
95
95
|
algo,
|
|
96
96
|
mdata,
|
|
97
97
|
fdata,
|
|
98
|
+
tdata,
|
|
98
99
|
variable,
|
|
99
|
-
amb_results,
|
|
100
100
|
wake_delta,
|
|
101
101
|
):
|
|
102
102
|
"""
|
|
@@ -111,11 +111,10 @@ class TIMax(WakeSuperposition):
|
|
|
111
111
|
The model data
|
|
112
112
|
fdata: foxes.core.FData
|
|
113
113
|
The farm data
|
|
114
|
+
tdata: foxes.core.TData
|
|
115
|
+
The target point data
|
|
114
116
|
variable: str
|
|
115
117
|
The variable name for which the wake deltas applies
|
|
116
|
-
amb_results: numpy.ndarray
|
|
117
|
-
The ambient results at targets,
|
|
118
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
119
118
|
wake_delta: numpy.ndarray
|
|
120
119
|
The wake deltas at targets, shape:
|
|
121
120
|
(n_states, n_targets, n_tpoints)
|
|
@@ -134,6 +133,7 @@ class TIMax(WakeSuperposition):
|
|
|
134
133
|
|
|
135
134
|
# quadratic superposition to ambient:
|
|
136
135
|
elif self.superp_to_amb == "quadratic":
|
|
136
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
137
137
|
return np.sqrt(wake_delta**2 + amb_results**2) - amb_results
|
|
138
138
|
|
|
139
139
|
# unknown ti delta:
|
|
@@ -102,8 +102,8 @@ class TIPow(WakeSuperposition):
|
|
|
102
102
|
algo,
|
|
103
103
|
mdata,
|
|
104
104
|
fdata,
|
|
105
|
+
tdata,
|
|
105
106
|
variable,
|
|
106
|
-
amb_results,
|
|
107
107
|
wake_delta,
|
|
108
108
|
):
|
|
109
109
|
"""
|
|
@@ -118,11 +118,10 @@ class TIPow(WakeSuperposition):
|
|
|
118
118
|
The model data
|
|
119
119
|
fdata: foxes.core.FData
|
|
120
120
|
The farm data
|
|
121
|
+
tdata: foxes.core.TData
|
|
122
|
+
The target point data
|
|
121
123
|
variable: str
|
|
122
124
|
The variable name for which the wake deltas applies
|
|
123
|
-
amb_results: numpy.ndarray
|
|
124
|
-
The ambient results at targets,
|
|
125
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
126
125
|
wake_delta: numpy.ndarray
|
|
127
126
|
The wake deltas at targets, shape:
|
|
128
127
|
(n_states, n_targets, n_tpoints)
|
|
@@ -141,6 +140,7 @@ class TIPow(WakeSuperposition):
|
|
|
141
140
|
|
|
142
141
|
# quadratic superposition to ambient:
|
|
143
142
|
elif self.superp_to_amb == "quadratic":
|
|
143
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
144
144
|
return np.sqrt(wake_delta ** (2 / self.pow) + amb_results**2) - amb_results
|
|
145
145
|
|
|
146
146
|
# unknown ti delta:
|
|
@@ -95,8 +95,8 @@ class TIQuadratic(WakeSuperposition):
|
|
|
95
95
|
algo,
|
|
96
96
|
mdata,
|
|
97
97
|
fdata,
|
|
98
|
+
tdata,
|
|
98
99
|
variable,
|
|
99
|
-
amb_results,
|
|
100
100
|
wake_delta,
|
|
101
101
|
):
|
|
102
102
|
"""
|
|
@@ -111,11 +111,10 @@ class TIQuadratic(WakeSuperposition):
|
|
|
111
111
|
The model data
|
|
112
112
|
fdata: foxes.core.FData
|
|
113
113
|
The farm data
|
|
114
|
+
tdata: foxes.core.TData
|
|
115
|
+
The target point data
|
|
114
116
|
variable: str
|
|
115
117
|
The variable name for which the wake deltas applies
|
|
116
|
-
amb_results: numpy.ndarray
|
|
117
|
-
The ambient results at targets,
|
|
118
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
119
118
|
wake_delta: numpy.ndarray
|
|
120
119
|
The wake deltas at targets, shape:
|
|
121
120
|
(n_states, n_targets, n_tpoints)
|
|
@@ -134,6 +133,7 @@ class TIQuadratic(WakeSuperposition):
|
|
|
134
133
|
|
|
135
134
|
# quadratic superposition to ambient:
|
|
136
135
|
elif self.superp_to_amb == "quadratic":
|
|
136
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
137
137
|
return np.sqrt(wake_delta + amb_results**2) - amb_results
|
|
138
138
|
|
|
139
139
|
# unknown ti delta:
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from foxes.core import WindVectorWakeSuperposition
|
|
4
|
+
from foxes.utils import wd2uv, uv2wd, delta_wd
|
|
5
|
+
import foxes.variables as FV
|
|
6
|
+
import foxes.constants as FC
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class WindVectorLinear(WindVectorWakeSuperposition):
|
|
10
|
+
"""
|
|
11
|
+
Linear superposition of wind deficit vector results
|
|
12
|
+
|
|
13
|
+
Attributes
|
|
14
|
+
----------
|
|
15
|
+
scale_amb: bool
|
|
16
|
+
Flag for scaling wind deficit with ambient wind speed
|
|
17
|
+
instead of waked wind speed
|
|
18
|
+
|
|
19
|
+
:group: models.wake_superpositions
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, scale_amb=False):
|
|
24
|
+
"""
|
|
25
|
+
Constructor.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
scale_amb: bool
|
|
30
|
+
Flag for scaling wind deficit with ambient wind speed
|
|
31
|
+
instead of waked wind speed
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
super().__init__()
|
|
35
|
+
self.scale_amb = scale_amb
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
a = f"scale_amb={self.scale_amb}"
|
|
39
|
+
return f"{type(self).__name__}({a})"
|
|
40
|
+
|
|
41
|
+
def input_farm_vars(self, algo):
|
|
42
|
+
"""
|
|
43
|
+
The variables which are needed for running
|
|
44
|
+
the model.
|
|
45
|
+
|
|
46
|
+
Parameters
|
|
47
|
+
----------
|
|
48
|
+
algo: foxes.core.Algorithm
|
|
49
|
+
The calculation algorithm
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
input_vars: list of str
|
|
54
|
+
The input variable names
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
return [FV.AMB_REWS] if self.scale_amb else [FV.REWS]
|
|
58
|
+
|
|
59
|
+
def wdeltas_ws2uv(self, algo, fdata, tdata, downwind_index, wdeltas, st_sel):
|
|
60
|
+
"""
|
|
61
|
+
Transform results from wind speed to wind vector data
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
algo: foxes.core.Algorithm
|
|
66
|
+
The calculation algorithm
|
|
67
|
+
fdata: foxes.core.FData
|
|
68
|
+
The farm data
|
|
69
|
+
tdata: foxes.core.TData
|
|
70
|
+
The target point data
|
|
71
|
+
downwind_index: int
|
|
72
|
+
The index of the wake causing turbine
|
|
73
|
+
in the downwind order
|
|
74
|
+
wdeltas: dict
|
|
75
|
+
The wake deltas. Key: variable name str,
|
|
76
|
+
value: numpy.ndarray, shape: (n_st_sel, n_tpoints)
|
|
77
|
+
st_sel: numpy.ndarray of bool
|
|
78
|
+
The state-target selection, for which the wake
|
|
79
|
+
is non-zero, shape: (n_states, n_targets)
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
wdeltas: dict
|
|
84
|
+
The wake deltas. Key: variable name str,
|
|
85
|
+
value: numpy.ndarray, now respecting has_uv flag
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
if FV.AMB_UV not in tdata:
|
|
89
|
+
tdata[FV.AMB_UV] = wd2uv(tdata[FV.AMB_WD], tdata[FV.AMB_WS])
|
|
90
|
+
if FV.UV not in wdeltas:
|
|
91
|
+
assert FV.WS in wdeltas, (
|
|
92
|
+
f"{self.name}: Expecting '{FV.WS}' in wdeltas, got {list(wdeltas.keys())}"
|
|
93
|
+
)
|
|
94
|
+
scale = self.get_data(
|
|
95
|
+
FV.AMB_REWS if self.scale_amb else FV.REWS,
|
|
96
|
+
FC.STATE_TARGET_TPOINT,
|
|
97
|
+
lookup="w",
|
|
98
|
+
algo=algo,
|
|
99
|
+
fdata=fdata,
|
|
100
|
+
tdata=tdata,
|
|
101
|
+
downwind_index=downwind_index,
|
|
102
|
+
upcast=False,
|
|
103
|
+
selection=st_sel,
|
|
104
|
+
)
|
|
105
|
+
ws0 = tdata[FV.AMB_WS][st_sel]
|
|
106
|
+
wd0 = tdata[FV.AMB_WD][st_sel]
|
|
107
|
+
dws = scale * wdeltas.pop(FV.WS)
|
|
108
|
+
dwd = wdeltas.pop(FV.WD, 0)
|
|
109
|
+
wdeltas[FV.UV] = wd2uv(wd0 + dwd, ws0 + dws) - tdata[FV.AMB_UV][st_sel]
|
|
110
|
+
|
|
111
|
+
return wdeltas
|
|
112
|
+
|
|
113
|
+
def wdeltas_uv2ws(self, algo, fdata, tdata, downwind_index, wdeltas, st_sel):
|
|
114
|
+
"""
|
|
115
|
+
Transform results from wind vector to wind speed data
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
algo: foxes.core.Algorithm
|
|
120
|
+
The calculation algorithm
|
|
121
|
+
fdata: foxes.core.FData
|
|
122
|
+
The farm data
|
|
123
|
+
tdata: foxes.core.TData
|
|
124
|
+
The target point data
|
|
125
|
+
downwind_index: int
|
|
126
|
+
The index of the wake causing turbine
|
|
127
|
+
in the downwind order
|
|
128
|
+
wdeltas: dict
|
|
129
|
+
The wake deltas. Key: variable name str,
|
|
130
|
+
value: numpy.ndarray, shape: (n_st_sel, n_tpoints)
|
|
131
|
+
st_sel: numpy.ndarray of bool
|
|
132
|
+
The state-target selection, for which the wake
|
|
133
|
+
is non-zero, shape: (n_states, n_targets)
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
wdeltas: dict
|
|
138
|
+
The wake deltas. Key: variable name str,
|
|
139
|
+
value: numpy.ndarray, now respecting has_uv flag
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
if FV.UV in wdeltas:
|
|
143
|
+
scale = self.get_data(
|
|
144
|
+
FV.AMB_REWS if self.scale_amb else FV.REWS,
|
|
145
|
+
FC.STATE_TARGET_TPOINT,
|
|
146
|
+
lookup="w",
|
|
147
|
+
algo=algo,
|
|
148
|
+
fdata=fdata,
|
|
149
|
+
tdata=tdata,
|
|
150
|
+
downwind_index=downwind_index,
|
|
151
|
+
upcast=False,
|
|
152
|
+
selection=st_sel,
|
|
153
|
+
)
|
|
154
|
+
ws0 = tdata[FV.AMB_WS][st_sel]
|
|
155
|
+
wd0 = tdata[FV.AMB_WD][st_sel]
|
|
156
|
+
uv = tdata[FV.AMB_UV][st_sel] + wdeltas.pop(FV.UV)
|
|
157
|
+
wdeltas[FV.WD] = delta_wd(wd0, uv2wd(uv))
|
|
158
|
+
wdeltas[FV.WS] = (np.linalg.norm(uv, axis=-1) - ws0) / scale
|
|
159
|
+
|
|
160
|
+
return wdeltas
|
|
161
|
+
|
|
162
|
+
def add_wake_vector(
|
|
163
|
+
self,
|
|
164
|
+
algo,
|
|
165
|
+
mdata,
|
|
166
|
+
fdata,
|
|
167
|
+
tdata,
|
|
168
|
+
downwind_index,
|
|
169
|
+
st_sel,
|
|
170
|
+
wake_delta_uv,
|
|
171
|
+
wake_model_result_uv,
|
|
172
|
+
):
|
|
173
|
+
"""
|
|
174
|
+
Add a wake delta vector to previous wake deltas,
|
|
175
|
+
at rotor points.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
algo: foxes.core.Algorithm
|
|
180
|
+
The calculation algorithm
|
|
181
|
+
mdata: foxes.core.MData
|
|
182
|
+
The model data
|
|
183
|
+
fdata: foxes.core.FData
|
|
184
|
+
The farm data
|
|
185
|
+
tdata: foxes.core.TData
|
|
186
|
+
The target point data
|
|
187
|
+
downwind_index: int
|
|
188
|
+
The index of the wake causing turbine
|
|
189
|
+
in the downwind order
|
|
190
|
+
st_sel: numpy.ndarray of bool
|
|
191
|
+
The selection of targets, shape: (n_states, n_targets)
|
|
192
|
+
wake_delta_uv: numpy.ndarray
|
|
193
|
+
The original wind vector wake deltas, shape:
|
|
194
|
+
(n_states, n_targets, n_tpoints, 2)
|
|
195
|
+
wake_model_result_uv: numpy.ndarray
|
|
196
|
+
The new wind vector wake deltas of the selected rotors,
|
|
197
|
+
shape: (n_st_sel, n_tpoints, 2, ...)
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
wdelta_uv: numpy.ndarray
|
|
202
|
+
The updated wind vector wake deltas, shape:
|
|
203
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
204
|
+
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
if np.any(st_sel):
|
|
208
|
+
wake_delta_uv[st_sel] += wake_model_result_uv
|
|
209
|
+
|
|
210
|
+
return wake_delta_uv
|
|
211
|
+
|
|
212
|
+
def calc_final_wake_delta_uv(
|
|
213
|
+
self,
|
|
214
|
+
algo,
|
|
215
|
+
mdata,
|
|
216
|
+
fdata,
|
|
217
|
+
tdata,
|
|
218
|
+
wake_delta_uv,
|
|
219
|
+
):
|
|
220
|
+
"""
|
|
221
|
+
Calculate the final wind vector wake delta after adding all
|
|
222
|
+
contributions.
|
|
223
|
+
|
|
224
|
+
Parameters
|
|
225
|
+
----------
|
|
226
|
+
algo: foxes.core.Algorithm
|
|
227
|
+
The calculation algorithm
|
|
228
|
+
mdata: foxes.core.MData
|
|
229
|
+
The model data
|
|
230
|
+
fdata: foxes.core.FData
|
|
231
|
+
The farm data
|
|
232
|
+
tdata: foxes.core.TData
|
|
233
|
+
The target point data
|
|
234
|
+
wake_delta_uv: numpy.ndarray
|
|
235
|
+
The original wind vector wake deltas, shape:
|
|
236
|
+
(n_states, n_targets, n_tpoints, 2)
|
|
237
|
+
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
240
|
+
final_wake_delta_ws: numpy.ndarray
|
|
241
|
+
The final wind speed wake delta, which will be added to
|
|
242
|
+
the ambient results by simple plus operation. Shape:
|
|
243
|
+
(n_states, n_targets, n_tpoints)
|
|
244
|
+
final_wake_delta_wd: numpy.ndarray
|
|
245
|
+
The final wind direction wake delta, which will be added to
|
|
246
|
+
the ambient results by simple plus operation. Shape:
|
|
247
|
+
(n_states, n_targets, n_tpoints)
|
|
248
|
+
|
|
249
|
+
"""
|
|
250
|
+
if FV.AMB_UV not in tdata:
|
|
251
|
+
tdata[FV.AMB_UV] = wd2uv(tdata[FV.AMB_WD], tdata[FV.AMB_WS])
|
|
252
|
+
|
|
253
|
+
uv = tdata[FV.AMB_UV] + wake_delta_uv
|
|
254
|
+
dwd = delta_wd(tdata[FV.AMB_WD], uv2wd(uv))
|
|
255
|
+
dws = np.linalg.norm(uv, axis=-1) - tdata[FV.AMB_WS]
|
|
256
|
+
|
|
257
|
+
return dws, dwd
|
|
@@ -140,8 +140,8 @@ class WSLinear(WakeSuperposition):
|
|
|
140
140
|
algo,
|
|
141
141
|
mdata,
|
|
142
142
|
fdata,
|
|
143
|
+
tdata,
|
|
143
144
|
variable,
|
|
144
|
-
amb_results,
|
|
145
145
|
wake_delta,
|
|
146
146
|
):
|
|
147
147
|
"""
|
|
@@ -156,11 +156,10 @@ class WSLinear(WakeSuperposition):
|
|
|
156
156
|
The model data
|
|
157
157
|
fdata: foxes.core.FData
|
|
158
158
|
The farm data
|
|
159
|
+
tdata: foxes.core.TData
|
|
160
|
+
The target point data
|
|
159
161
|
variable: str
|
|
160
162
|
The variable name for which the wake deltas applies
|
|
161
|
-
amb_results: numpy.ndarray
|
|
162
|
-
The ambient results at targets,
|
|
163
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
164
163
|
wake_delta: numpy.ndarray
|
|
165
164
|
The wake deltas at targets, shape:
|
|
166
165
|
(n_states, n_targets, n_tpoints)
|
|
@@ -175,9 +174,9 @@ class WSLinear(WakeSuperposition):
|
|
|
175
174
|
"""
|
|
176
175
|
w = wake_delta
|
|
177
176
|
if self.lim_low is not None:
|
|
178
|
-
w = np.maximum(w, self.lim_low -
|
|
177
|
+
w = np.maximum(w, self.lim_low - tdata[FV.var2amb[variable]])
|
|
179
178
|
if self.lim_high is not None:
|
|
180
|
-
w = np.minimum(w, self.lim_high -
|
|
179
|
+
w = np.minimum(w, self.lim_high - tdata[FV.var2amb[variable]])
|
|
181
180
|
return w
|
|
182
181
|
|
|
183
182
|
|
|
@@ -296,8 +295,8 @@ class WSLinearLocal(WakeSuperposition):
|
|
|
296
295
|
algo,
|
|
297
296
|
mdata,
|
|
298
297
|
fdata,
|
|
298
|
+
tdata,
|
|
299
299
|
variable,
|
|
300
|
-
amb_results,
|
|
301
300
|
wake_delta,
|
|
302
301
|
):
|
|
303
302
|
"""
|
|
@@ -312,11 +311,10 @@ class WSLinearLocal(WakeSuperposition):
|
|
|
312
311
|
The model data
|
|
313
312
|
fdata: foxes.core.FData
|
|
314
313
|
The farm data
|
|
314
|
+
tdata: foxes.core.TData
|
|
315
|
+
The target point data
|
|
315
316
|
variable: str
|
|
316
317
|
The variable name for which the wake deltas applies
|
|
317
|
-
amb_results: numpy.ndarray
|
|
318
|
-
The ambient results at targets,
|
|
319
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
320
318
|
wake_delta: numpy.ndarray
|
|
321
319
|
The wake deltas at targets, shape:
|
|
322
320
|
(n_states, n_targets, n_tpoints)
|
|
@@ -329,6 +327,7 @@ class WSLinearLocal(WakeSuperposition):
|
|
|
329
327
|
(n_states, n_targets, n_tpoints)
|
|
330
328
|
|
|
331
329
|
"""
|
|
330
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
332
331
|
w = wake_delta * amb_results
|
|
333
332
|
if self.lim_low is not None:
|
|
334
333
|
w = np.maximum(w, self.lim_low - amb_results)
|
|
@@ -143,8 +143,8 @@ class WSMax(WakeSuperposition):
|
|
|
143
143
|
algo,
|
|
144
144
|
mdata,
|
|
145
145
|
fdata,
|
|
146
|
+
tdata,
|
|
146
147
|
variable,
|
|
147
|
-
amb_results,
|
|
148
148
|
wake_delta,
|
|
149
149
|
):
|
|
150
150
|
"""
|
|
@@ -159,11 +159,10 @@ class WSMax(WakeSuperposition):
|
|
|
159
159
|
The model data
|
|
160
160
|
fdata: foxes.core.FData
|
|
161
161
|
The farm data
|
|
162
|
+
tdata: foxes.core.TData
|
|
163
|
+
The target point data
|
|
162
164
|
variable: str
|
|
163
165
|
The variable name for which the wake deltas applies
|
|
164
|
-
amb_results: numpy.ndarray
|
|
165
|
-
The ambient results at targets,
|
|
166
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
167
166
|
wake_delta: numpy.ndarray
|
|
168
167
|
The wake deltas at targets, shape:
|
|
169
168
|
(n_states, n_targets, n_tpoints)
|
|
@@ -176,6 +175,7 @@ class WSMax(WakeSuperposition):
|
|
|
176
175
|
(n_states, n_targets, n_tpoints)
|
|
177
176
|
|
|
178
177
|
"""
|
|
178
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
179
179
|
w = -wake_delta
|
|
180
180
|
if self.lim_low is not None:
|
|
181
181
|
w = np.maximum(w, self.lim_low - amb_results)
|
|
@@ -302,8 +302,8 @@ class WSMaxLocal(WakeSuperposition):
|
|
|
302
302
|
algo,
|
|
303
303
|
mdata,
|
|
304
304
|
fdata,
|
|
305
|
+
tdata,
|
|
305
306
|
variable,
|
|
306
|
-
amb_results,
|
|
307
307
|
wake_delta,
|
|
308
308
|
):
|
|
309
309
|
"""
|
|
@@ -318,11 +318,10 @@ class WSMaxLocal(WakeSuperposition):
|
|
|
318
318
|
The model data
|
|
319
319
|
fdata: foxes.core.FData
|
|
320
320
|
The farm data
|
|
321
|
+
tdata: foxes.core.TData
|
|
322
|
+
The target point data
|
|
321
323
|
variable: str
|
|
322
324
|
The variable name for which the wake deltas applies
|
|
323
|
-
amb_results: numpy.ndarray
|
|
324
|
-
The ambient results at targets,
|
|
325
|
-
shape: (n_states, n_targets, n_tpoints)
|
|
326
325
|
wake_delta: numpy.ndarray
|
|
327
326
|
The wake deltas at targets, shape:
|
|
328
327
|
(n_states, n_targets, n_tpoints)
|
|
@@ -335,6 +334,7 @@ class WSMaxLocal(WakeSuperposition):
|
|
|
335
334
|
(n_states, n_targets, n_tpoints)
|
|
336
335
|
|
|
337
336
|
"""
|
|
337
|
+
amb_results = tdata[FV.var2amb[variable]]
|
|
338
338
|
w = -wake_delta * amb_results
|
|
339
339
|
if self.lim_low is not None:
|
|
340
340
|
w = np.maximum(w, self.lim_low - amb_results)
|