foxes 1.3__py3-none-any.whl → 1.5__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/field_data_nc/run.py +1 -1
- 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 +29 -6
- 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 +19 -9
- foxes/__init__.py +21 -17
- foxes/algorithms/__init__.py +6 -6
- foxes/algorithms/downwind/__init__.py +2 -2
- foxes/algorithms/downwind/downwind.py +49 -17
- 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 +58 -29
- foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
- foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
- 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 +5 -6
- foxes/core/data.py +94 -22
- foxes/core/data_calc_model.py +4 -2
- foxes/core/engine.py +42 -53
- foxes/core/farm_controller.py +2 -2
- foxes/core/farm_data_model.py +16 -13
- foxes/core/ground_model.py +4 -13
- foxes/core/model.py +24 -6
- foxes/core/partial_wakes_model.py +147 -10
- foxes/core/point_data_model.py +21 -17
- foxes/core/rotor_model.py +4 -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/point_cloud_100.nc +0 -0
- foxes/data/states/weibull_cloud_4.nc +0 -0
- foxes/data/states/weibull_grid.nc +0 -0
- 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 +42 -20
- foxes/engines/default.py +2 -2
- foxes/engines/numpy.py +11 -13
- foxes/engines/pool.py +20 -11
- foxes/engines/single.py +8 -6
- foxes/input/__init__.py +3 -3
- foxes/input/farm_layout/__init__.py +9 -8
- foxes/input/farm_layout/from_arrays.py +68 -0
- foxes/input/farm_layout/from_csv.py +1 -1
- foxes/input/farm_layout/ring.py +0 -1
- foxes/input/states/__init__.py +28 -12
- foxes/input/states/create/__init__.py +3 -2
- foxes/input/states/dataset_states.py +710 -0
- foxes/input/states/field_data.py +531 -0
- foxes/input/states/multi_height.py +11 -6
- foxes/input/states/one_point_flow.py +1 -4
- foxes/input/states/point_cloud_data.py +618 -0
- foxes/input/states/scan.py +2 -0
- foxes/input/states/single.py +3 -1
- foxes/input/states/states_table.py +23 -30
- foxes/input/states/weibull_sectors.py +330 -0
- foxes/input/states/wrg_states.py +8 -6
- foxes/input/yaml/__init__.py +9 -3
- foxes/input/yaml/dict.py +42 -41
- foxes/input/yaml/windio/__init__.py +10 -5
- foxes/input/yaml/windio/read_attributes.py +42 -29
- foxes/input/yaml/windio/read_farm.py +17 -15
- foxes/input/yaml/windio/read_fields.py +4 -2
- foxes/input/yaml/windio/read_outputs.py +25 -15
- foxes/input/yaml/windio/read_site.py +172 -11
- foxes/input/yaml/windio/windio.py +23 -11
- foxes/input/yaml/yaml.py +1 -0
- 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 +190 -63
- 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 +4 -3
- foxes/models/rotor_models/centre.py +1 -1
- foxes/models/rotor_models/direct_infusion.py +241 -0
- foxes/models/turbine_models/__init__.py +11 -11
- foxes/models/turbine_models/calculator.py +16 -3
- foxes/models/turbine_models/kTI_model.py +1 -0
- foxes/models/turbine_models/lookup_table.py +2 -0
- foxes/models/turbine_models/power_mask.py +1 -0
- foxes/models/turbine_models/rotor_centre_calc.py +2 -0
- foxes/models/turbine_models/sector_management.py +1 -0
- foxes/models/turbine_models/set_farm_vars.py +3 -9
- foxes/models/turbine_models/table_factors.py +2 -0
- foxes/models/turbine_models/thrust2ct.py +1 -0
- foxes/models/turbine_models/yaw2yawm.py +2 -0
- foxes/models/turbine_models/yawm2yaw.py +2 -0
- foxes/models/turbine_types/PCt_file.py +2 -6
- foxes/models/turbine_types/PCt_from_two.py +1 -2
- foxes/models/turbine_types/__init__.py +10 -9
- foxes/models/turbine_types/calculator_type.py +123 -0
- foxes/models/turbine_types/null_type.py +1 -0
- foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
- foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
- 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 +4 -2
- foxes/output/farm_results_eval.py +19 -16
- foxes/output/flow_plots_2d/__init__.py +2 -2
- foxes/output/flow_plots_2d/flow_plots.py +18 -0
- foxes/output/flow_plots_2d/get_fig.py +5 -2
- foxes/output/output.py +6 -1
- foxes/output/results_writer.py +1 -1
- foxes/output/rose_plot.py +13 -3
- foxes/output/rotor_point_plots.py +3 -0
- 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/state_turbine_map.py +3 -0
- foxes/output/turbine_type_curves.py +10 -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 +49 -37
- foxes/utils/exec_python.py +5 -5
- foxes/utils/factory.py +3 -5
- 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.5.dist-info}/METADATA +34 -63
- foxes-1.5.dist-info/RECORD +328 -0
- {foxes-1.3.dist-info → foxes-1.5.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/input/states/field_data_nc.py +0 -847
- 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.5.dist-info}/entry_points.txt +0 -0
- {foxes-1.3.dist-info → foxes-1.5.dist-info/licenses}/LICENSE +0 -0
- {foxes-1.3.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
|
+
from foxes.config import config
|
|
3
4
|
from foxes.core import TurbineInductionModel
|
|
4
5
|
import foxes.variables as FV
|
|
5
6
|
import foxes.constants as FC
|
|
@@ -45,16 +46,28 @@ class VortexSheet(TurbineInductionModel):
|
|
|
45
46
|
Calculate only the pre-rotor region
|
|
46
47
|
|
|
47
48
|
"""
|
|
48
|
-
super().__init__()
|
|
49
|
+
super().__init__(wind_superposition=superposition)
|
|
49
50
|
self.induction = induction
|
|
50
51
|
self.pre_rotor_only = pre_rotor_only
|
|
51
|
-
self._superp_name = superposition
|
|
52
52
|
|
|
53
53
|
def __repr__(self):
|
|
54
54
|
iname = (
|
|
55
55
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
56
56
|
)
|
|
57
|
-
return f"{type(self).__name__}({self.
|
|
57
|
+
return f"{type(self).__name__}({self.wind_superposition}, induction={iname})"
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def affects_ws(self):
|
|
61
|
+
"""
|
|
62
|
+
Flag for wind speed wake models
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
dws: bool
|
|
67
|
+
If True, this model affects wind speed
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
return True
|
|
58
71
|
|
|
59
72
|
def sub_models(self):
|
|
60
73
|
"""
|
|
@@ -66,7 +79,7 @@ class VortexSheet(TurbineInductionModel):
|
|
|
66
79
|
All sub models
|
|
67
80
|
|
|
68
81
|
"""
|
|
69
|
-
return
|
|
82
|
+
return super().sub_models() + [self.induction]
|
|
70
83
|
|
|
71
84
|
def initialize(self, algo, verbosity=0, force=False):
|
|
72
85
|
"""
|
|
@@ -82,35 +95,44 @@ class VortexSheet(TurbineInductionModel):
|
|
|
82
95
|
Overwrite existing data
|
|
83
96
|
|
|
84
97
|
"""
|
|
85
|
-
self._superp = algo.mbook.wake_superpositions[self._superp_name]
|
|
86
98
|
if isinstance(self.induction, str):
|
|
87
99
|
self.induction = algo.mbook.axial_induction[self.induction]
|
|
88
100
|
super().initialize(algo, verbosity, force)
|
|
89
101
|
|
|
90
102
|
def new_wake_deltas(self, algo, mdata, fdata, tdata):
|
|
91
103
|
"""
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
They are added on the fly to the wake_deltas dict.
|
|
104
|
+
Creates new empty wake delta arrays.
|
|
95
105
|
|
|
96
106
|
Parameters
|
|
97
107
|
----------
|
|
98
108
|
algo: foxes.core.Algorithm
|
|
99
109
|
The calculation algorithm
|
|
100
|
-
mdata: foxes.core.
|
|
110
|
+
mdata: foxes.core.MData
|
|
101
111
|
The model data
|
|
102
|
-
fdata: foxes.core.
|
|
112
|
+
fdata: foxes.core.FData
|
|
103
113
|
The farm data
|
|
104
|
-
|
|
105
|
-
The
|
|
114
|
+
tdata: foxes.core.TData
|
|
115
|
+
The target point data
|
|
116
|
+
|
|
117
|
+
Returns
|
|
118
|
+
-------
|
|
106
119
|
wake_deltas: dict
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
wake delta applies, values: numpy.ndarray with
|
|
110
|
-
shape (n_states, n_points, ...)
|
|
120
|
+
Key: variable name, value: The zero filled
|
|
121
|
+
wake deltas, shape: (n_states, n_targets, n_tpoints, ...)
|
|
111
122
|
|
|
112
123
|
"""
|
|
113
|
-
|
|
124
|
+
if self.has_uv:
|
|
125
|
+
duv = np.zeros(
|
|
126
|
+
(tdata.n_states, tdata.n_targets, tdata.n_tpoints, 2),
|
|
127
|
+
dtype=config.dtype_double,
|
|
128
|
+
)
|
|
129
|
+
return {FV.UV: duv}
|
|
130
|
+
else:
|
|
131
|
+
dws = np.zeros(
|
|
132
|
+
(tdata.n_states, tdata.n_targets, tdata.n_tpoints),
|
|
133
|
+
dtype=config.dtype_double,
|
|
134
|
+
)
|
|
135
|
+
return {FV.WS: dws}
|
|
114
136
|
|
|
115
137
|
def contribute(
|
|
116
138
|
self,
|
|
@@ -186,20 +208,39 @@ class VortexSheet(TurbineInductionModel):
|
|
|
186
208
|
R_sel = D[sp_sel] / 2
|
|
187
209
|
xi = r_sph_sel / R_sel
|
|
188
210
|
|
|
211
|
+
def add_wake(sp_sel, wake_deltas, blockage):
|
|
212
|
+
"""adds to wake deltas"""
|
|
213
|
+
if self.has_vector_wind_superp:
|
|
214
|
+
wdeltas = {FV.WS: blockage}
|
|
215
|
+
self.vec_superp.wdeltas_ws2uv(
|
|
216
|
+
algo, fdata, tdata, downwind_index, wdeltas, sp_sel
|
|
217
|
+
)
|
|
218
|
+
wake_deltas[FV.UV] = self.vec_superp.add_wake_vector(
|
|
219
|
+
algo,
|
|
220
|
+
mdata,
|
|
221
|
+
fdata,
|
|
222
|
+
tdata,
|
|
223
|
+
downwind_index,
|
|
224
|
+
sp_sel,
|
|
225
|
+
wake_deltas[FV.UV],
|
|
226
|
+
wdeltas.pop(FV.UV),
|
|
227
|
+
)
|
|
228
|
+
else:
|
|
229
|
+
self.superp[FV.WS].add_wake(
|
|
230
|
+
algo,
|
|
231
|
+
mdata,
|
|
232
|
+
fdata,
|
|
233
|
+
tdata,
|
|
234
|
+
downwind_index,
|
|
235
|
+
sp_sel,
|
|
236
|
+
FV.WS,
|
|
237
|
+
wake_deltas[FV.WS],
|
|
238
|
+
blockage,
|
|
239
|
+
)
|
|
240
|
+
|
|
189
241
|
if np.any(sp_sel):
|
|
190
242
|
blockage = self.induction.ct2a(ct_sel) * (1 + -xi / np.sqrt(1 + xi**2))
|
|
191
|
-
|
|
192
|
-
self._superp.add_wake(
|
|
193
|
-
algo,
|
|
194
|
-
mdata,
|
|
195
|
-
fdata,
|
|
196
|
-
tdata,
|
|
197
|
-
downwind_index,
|
|
198
|
-
sp_sel,
|
|
199
|
-
FV.WS,
|
|
200
|
-
wake_deltas[FV.WS],
|
|
201
|
-
-blockage,
|
|
202
|
-
)
|
|
243
|
+
add_wake(sp_sel, wake_deltas, -blockage)
|
|
203
244
|
|
|
204
245
|
if not self.pre_rotor_only:
|
|
205
246
|
sp_sel = (
|
|
@@ -211,51 +252,6 @@ class VortexSheet(TurbineInductionModel):
|
|
|
211
252
|
xi = r_sph_sel / R_sel
|
|
212
253
|
if np.any(sp_sel):
|
|
213
254
|
blockage = self.induction.ct2a(ct_sel) * (1 + -xi / np.sqrt(1 + xi**2))
|
|
214
|
-
|
|
215
|
-
algo,
|
|
216
|
-
mdata,
|
|
217
|
-
fdata,
|
|
218
|
-
tdata,
|
|
219
|
-
downwind_index,
|
|
220
|
-
sp_sel,
|
|
221
|
-
FV.WS,
|
|
222
|
-
wake_deltas[FV.WS],
|
|
223
|
-
blockage,
|
|
224
|
-
)
|
|
255
|
+
add_wake(sp_sel, wake_deltas, blockage)
|
|
225
256
|
|
|
226
257
|
return wake_deltas
|
|
227
|
-
|
|
228
|
-
def finalize_wake_deltas(
|
|
229
|
-
self,
|
|
230
|
-
algo,
|
|
231
|
-
mdata,
|
|
232
|
-
fdata,
|
|
233
|
-
amb_results,
|
|
234
|
-
wake_deltas,
|
|
235
|
-
):
|
|
236
|
-
"""
|
|
237
|
-
Finalize the wake calculation.
|
|
238
|
-
|
|
239
|
-
Modifies wake_deltas on the fly.
|
|
240
|
-
|
|
241
|
-
Parameters
|
|
242
|
-
----------
|
|
243
|
-
algo: foxes.core.Algorithm
|
|
244
|
-
The calculation algorithm
|
|
245
|
-
mdata: foxes.core.MData
|
|
246
|
-
The model data
|
|
247
|
-
fdata: foxes.core.FData
|
|
248
|
-
The farm data
|
|
249
|
-
amb_results: dict
|
|
250
|
-
The ambient results, key: variable name str,
|
|
251
|
-
values: numpy.ndarray with shape
|
|
252
|
-
(n_states, n_targets, n_tpoints)
|
|
253
|
-
wake_deltas: dict
|
|
254
|
-
The wake deltas object at the selected target
|
|
255
|
-
turbines. Key: variable str, value: numpy.ndarray
|
|
256
|
-
with shape (n_states, n_targets, n_tpoints)
|
|
257
|
-
|
|
258
|
-
"""
|
|
259
|
-
wake_deltas[FV.WS] = self._superp.calc_final_wake_delta(
|
|
260
|
-
algo, mdata, fdata, FV.WS, amb_results[FV.WS], wake_deltas[FV.WS]
|
|
261
|
-
)
|
|
@@ -98,7 +98,9 @@ class CrespoHernandezTIWake(TopHatWakeModel):
|
|
|
98
98
|
Parameters for the WakeK class
|
|
99
99
|
|
|
100
100
|
"""
|
|
101
|
-
super().__init__(
|
|
101
|
+
super().__init__(
|
|
102
|
+
other_superpositions={FV.TI: superposition}, induction=induction
|
|
103
|
+
)
|
|
102
104
|
|
|
103
105
|
self.a_near = a_near
|
|
104
106
|
self.a_far = a_far
|
|
@@ -115,7 +117,7 @@ class CrespoHernandezTIWake(TopHatWakeModel):
|
|
|
115
117
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
116
118
|
)
|
|
117
119
|
s = f"{type(self).__name__}"
|
|
118
|
-
s += f"({self.
|
|
120
|
+
s += f"({self.other_superpositions[FV.TI]}, induction={iname}, "
|
|
119
121
|
s += self.wake_k.repr() + ")"
|
|
120
122
|
return s
|
|
121
123
|
|
|
@@ -129,7 +131,7 @@ class CrespoHernandezTIWake(TopHatWakeModel):
|
|
|
129
131
|
All sub models
|
|
130
132
|
|
|
131
133
|
"""
|
|
132
|
-
return [self.wake_k]
|
|
134
|
+
return super().sub_models() + [self.wake_k]
|
|
133
135
|
|
|
134
136
|
def new_wake_deltas(self, algo, mdata, fdata, tdata):
|
|
135
137
|
"""
|
|
@@ -53,7 +53,9 @@ class IECTIWake(TopHatWakeModel):
|
|
|
53
53
|
Parameters for the WakeK class
|
|
54
54
|
|
|
55
55
|
"""
|
|
56
|
-
super().__init__(
|
|
56
|
+
super().__init__(
|
|
57
|
+
other_superpositions={FV.TI: superposition}, induction=induction
|
|
58
|
+
)
|
|
57
59
|
self.iec_type = iec_type
|
|
58
60
|
self.wake_k = None
|
|
59
61
|
|
|
@@ -62,7 +64,7 @@ class IECTIWake(TopHatWakeModel):
|
|
|
62
64
|
else:
|
|
63
65
|
if "k" in wake_k or "ka" in wake_k or "kb" in wake_k:
|
|
64
66
|
raise KeyError(
|
|
65
|
-
|
|
67
|
+
"Can handle 'opening_angle' or ('k', 'ka', 'kb') parameters, not both"
|
|
66
68
|
)
|
|
67
69
|
self._k = float(np.tan(np.deg2rad(opening_angle / 2.0)))
|
|
68
70
|
|
|
@@ -71,7 +73,7 @@ class IECTIWake(TopHatWakeModel):
|
|
|
71
73
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
72
74
|
)
|
|
73
75
|
s = f"{type(self).__name__}"
|
|
74
|
-
s += f"({self.
|
|
76
|
+
s += f"({self.other_superpositions[FV.TI]}, induction={iname}"
|
|
75
77
|
if self.wake_k is not None:
|
|
76
78
|
s += ", " + self.wake_k.repr()
|
|
77
79
|
s += ")"
|
|
@@ -87,7 +89,7 @@ class IECTIWake(TopHatWakeModel):
|
|
|
87
89
|
All sub models
|
|
88
90
|
|
|
89
91
|
"""
|
|
90
|
-
return [self.wake_k] if self.wake_k is not None else []
|
|
92
|
+
return super().sub_models() + ([self.wake_k] if self.wake_k is not None else [])
|
|
91
93
|
|
|
92
94
|
def new_wake_deltas(self, algo, mdata, fdata, tdata):
|
|
93
95
|
"""
|
|
@@ -2,6 +2,7 @@ import numpy as np
|
|
|
2
2
|
from abc import abstractmethod
|
|
3
3
|
|
|
4
4
|
from foxes.models.wake_models.axisymmetric import AxisymmetricWakeModel
|
|
5
|
+
from foxes.config import config
|
|
5
6
|
import foxes.variables as FV
|
|
6
7
|
import foxes.constants as FC
|
|
7
8
|
|
|
@@ -19,21 +20,21 @@ class TopHatWakeModel(AxisymmetricWakeModel):
|
|
|
19
20
|
|
|
20
21
|
"""
|
|
21
22
|
|
|
22
|
-
def __init__(self,
|
|
23
|
+
def __init__(self, *args, induction="Betz", **kwargs):
|
|
23
24
|
"""
|
|
24
25
|
Constructor.
|
|
25
26
|
|
|
26
27
|
Parameters
|
|
27
28
|
----------
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
value: The wake superposition model name,
|
|
31
|
-
will be looked up in model book
|
|
29
|
+
args: tuple, optional
|
|
30
|
+
Additional parameters for the base class
|
|
32
31
|
induction: foxes.core.AxialInductionModel or str
|
|
33
32
|
The induction model
|
|
33
|
+
kwargs: dict, optional
|
|
34
|
+
Additional parameters for the base class
|
|
34
35
|
|
|
35
36
|
"""
|
|
36
|
-
super().__init__(
|
|
37
|
+
super().__init__(*args, **kwargs)
|
|
37
38
|
self.induction = induction
|
|
38
39
|
|
|
39
40
|
def sub_models(self):
|
|
@@ -46,7 +47,7 @@ class TopHatWakeModel(AxisymmetricWakeModel):
|
|
|
46
47
|
All sub models
|
|
47
48
|
|
|
48
49
|
"""
|
|
49
|
-
return [self.induction]
|
|
50
|
+
return super().sub_models() + [self.induction]
|
|
50
51
|
|
|
51
52
|
def initialize(self, algo, verbosity=0, force=False):
|
|
52
53
|
"""
|
|
@@ -66,6 +67,41 @@ class TopHatWakeModel(AxisymmetricWakeModel):
|
|
|
66
67
|
self.induction = algo.mbook.axial_induction[self.induction]
|
|
67
68
|
super().initialize(algo, verbosity, force)
|
|
68
69
|
|
|
70
|
+
def new_wake_deltas(self, algo, mdata, fdata, tdata):
|
|
71
|
+
"""
|
|
72
|
+
Creates new empty wake delta arrays.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
algo: foxes.core.Algorithm
|
|
77
|
+
The calculation algorithm
|
|
78
|
+
mdata: foxes.core.MData
|
|
79
|
+
The model data
|
|
80
|
+
fdata: foxes.core.FData
|
|
81
|
+
The farm data
|
|
82
|
+
tdata: foxes.core.TData
|
|
83
|
+
The target point data
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
wake_deltas: dict
|
|
88
|
+
Key: variable name, value: The zero filled
|
|
89
|
+
wake deltas, shape: (n_states, n_targets, n_tpoints, ...)
|
|
90
|
+
|
|
91
|
+
"""
|
|
92
|
+
if self.has_uv:
|
|
93
|
+
duv = np.zeros(
|
|
94
|
+
(tdata.n_states, tdata.n_targets, tdata.n_tpoints, 2),
|
|
95
|
+
dtype=config.dtype_double,
|
|
96
|
+
)
|
|
97
|
+
return {FV.UV: duv}
|
|
98
|
+
else:
|
|
99
|
+
dws = np.zeros(
|
|
100
|
+
(tdata.n_states, tdata.n_targets, tdata.n_tpoints),
|
|
101
|
+
dtype=config.dtype_double,
|
|
102
|
+
)
|
|
103
|
+
return {FV.WS: dws}
|
|
104
|
+
|
|
69
105
|
@abstractmethod
|
|
70
106
|
def calc_wake_radius(
|
|
71
107
|
self,
|
|
@@ -224,4 +260,19 @@ class TopHatWakeModel(AxisymmetricWakeModel):
|
|
|
224
260
|
for v, wdel in cl_del.items():
|
|
225
261
|
wdeltas[v] = np.where(isin, wdel[:, None], 0.0)
|
|
226
262
|
|
|
263
|
+
if self.affects_ws and FV.WS in wdeltas:
|
|
264
|
+
# wake deflection causes wind vector rotation:
|
|
265
|
+
if FC.WDEFL_ROT_ANGLE in tdata:
|
|
266
|
+
dwd_defl = tdata[FC.WDEFL_ROT_ANGLE]
|
|
267
|
+
if FV.WD not in wdeltas:
|
|
268
|
+
wdeltas[FV.WD] = np.zeros_like(wdeltas[FV.WS])
|
|
269
|
+
wdeltas[FV.WD][:] = dwd_defl[st_sel]
|
|
270
|
+
else:
|
|
271
|
+
wdeltas[FV.WD] += dwd_defl[st_sel]
|
|
272
|
+
|
|
273
|
+
# wake deflection causes wind speed reduction:
|
|
274
|
+
if FC.WDEFL_DWS_FACTOR in tdata:
|
|
275
|
+
dws_defl = tdata[FC.WDEFL_DWS_FACTOR]
|
|
276
|
+
wdeltas[FV.WS] *= dws_defl[st_sel]
|
|
277
|
+
|
|
227
278
|
return wdeltas, st_sel
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
Wind deficit wake models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .jensen import JensenWake
|
|
6
|
-
from .bastankhah14 import Bastankhah2014
|
|
7
|
-
from .bastankhah16 import Bastankhah2016Model
|
|
8
|
-
from .
|
|
5
|
+
from .jensen import JensenWake as JensenWake
|
|
6
|
+
from .bastankhah14 import Bastankhah2014 as Bastankhah2014
|
|
7
|
+
from .bastankhah16 import Bastankhah2016Model as Bastankhah2016Model
|
|
8
|
+
from .bastankhah16 import Bastankhah2016 as Bastankhah2016
|
|
9
|
+
from .turbopark import TurbOParkWake as TurbOParkWake
|
|
10
|
+
from .turbopark import TurbOParkWakeIX as TurbOParkWakeIX
|
|
@@ -22,7 +22,7 @@ class Bastankhah2014(GaussianWakeModel):
|
|
|
22
22
|
----------
|
|
23
23
|
sbeta_factor: float
|
|
24
24
|
Factor multiplying sbeta
|
|
25
|
-
induction: foxes.core.AxialInductionModel
|
|
25
|
+
induction: foxes.core.AxialInductionModel
|
|
26
26
|
The induction model
|
|
27
27
|
wake_k: foxes.core.WakeK
|
|
28
28
|
Handler for the wake growth parameter k
|
|
@@ -31,7 +31,13 @@ class Bastankhah2014(GaussianWakeModel):
|
|
|
31
31
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
|
-
def __init__(
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
superposition,
|
|
37
|
+
sbeta_factor=0.2,
|
|
38
|
+
induction="Madsen",
|
|
39
|
+
**wake_k,
|
|
40
|
+
):
|
|
35
41
|
"""
|
|
36
42
|
Constructor.
|
|
37
43
|
|
|
@@ -47,8 +53,7 @@ class Bastankhah2014(GaussianWakeModel):
|
|
|
47
53
|
Parameters for the WakeK class
|
|
48
54
|
|
|
49
55
|
"""
|
|
50
|
-
super().__init__(
|
|
51
|
-
|
|
56
|
+
super().__init__(wind_superposition=superposition)
|
|
52
57
|
self.sbeta_factor = sbeta_factor
|
|
53
58
|
self.induction = induction
|
|
54
59
|
self.wake_k = WakeK(**wake_k)
|
|
@@ -58,10 +63,23 @@ class Bastankhah2014(GaussianWakeModel):
|
|
|
58
63
|
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
59
64
|
)
|
|
60
65
|
s = f"{type(self).__name__}"
|
|
61
|
-
s += f"({self.
|
|
66
|
+
s += f"({self.wind_superposition}, induction={iname}, "
|
|
62
67
|
s += self.wake_k.repr() + ")"
|
|
63
68
|
return s
|
|
64
69
|
|
|
70
|
+
@property
|
|
71
|
+
def affects_ws(self):
|
|
72
|
+
"""
|
|
73
|
+
Flag for wind speed wake models
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
dws: bool
|
|
78
|
+
If True, this model affects wind speed
|
|
79
|
+
|
|
80
|
+
"""
|
|
81
|
+
return True
|
|
82
|
+
|
|
65
83
|
def sub_models(self):
|
|
66
84
|
"""
|
|
67
85
|
List of all sub-models
|
|
@@ -72,7 +90,7 @@ class Bastankhah2014(GaussianWakeModel):
|
|
|
72
90
|
All sub models
|
|
73
91
|
|
|
74
92
|
"""
|
|
75
|
-
return [self.wake_k, self.induction]
|
|
93
|
+
return super().sub_models() + [self.wake_k, self.induction]
|
|
76
94
|
|
|
77
95
|
def initialize(self, algo, verbosity=0, force=False):
|
|
78
96
|
"""
|
|
@@ -182,7 +200,7 @@ class Bastankhah2014(GaussianWakeModel):
|
|
|
182
200
|
|
|
183
201
|
# calculate amplitude:
|
|
184
202
|
ct_eff = ct / (8 * (sigma / D) ** 2)
|
|
185
|
-
ampld = np.maximum(-2 * self.induction.ct2a(ct_eff), -
|
|
203
|
+
ampld = np.maximum(-2 * self.induction.ct2a(ct_eff), -0.9999)
|
|
186
204
|
|
|
187
205
|
# case no targets:
|
|
188
206
|
else:
|
|
@@ -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
|