foxes 0.6.1__py3-none-any.whl → 0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of foxes might be problematic. Click here for more details.
- foxes/VERSION +1 -1
- foxes/algorithms/downwind/downwind.py +131 -65
- foxes/algorithms/downwind/models/__init__.py +2 -1
- foxes/algorithms/downwind/models/farm_wakes_calc.py +87 -55
- foxes/algorithms/downwind/models/init_farm_data.py +134 -0
- foxes/algorithms/downwind/models/point_wakes_calc.py +54 -65
- foxes/algorithms/downwind/models/{calc_order.py → reorder_farm_output.py} +28 -26
- foxes/algorithms/iterative/iterative.py +100 -51
- foxes/algorithms/iterative/models/convergence.py +3 -3
- foxes/algorithms/iterative/models/farm_wakes_calc.py +55 -48
- foxes/algorithms/sequential/models/seq_state.py +7 -6
- foxes/algorithms/sequential/sequential.py +81 -44
- foxes/constants.py +33 -18
- foxes/core/__init__.py +2 -2
- foxes/core/algorithm.py +31 -12
- foxes/core/data.py +335 -41
- foxes/core/data_calc_model.py +27 -23
- foxes/core/farm_controller.py +27 -28
- foxes/core/farm_data_model.py +26 -4
- foxes/core/model.py +186 -129
- foxes/core/partial_wakes_model.py +84 -81
- foxes/core/point_data_model.py +51 -18
- foxes/core/rotor_model.py +59 -77
- foxes/core/states.py +6 -6
- foxes/core/turbine_model.py +4 -4
- foxes/core/turbine_type.py +24 -0
- foxes/core/vertical_profile.py +3 -3
- foxes/core/wake_frame.py +91 -50
- foxes/core/wake_model.py +74 -43
- foxes/core/wake_superposition.py +29 -26
- foxes/input/farm_layout/__init__.py +1 -0
- foxes/input/farm_layout/from_random.py +49 -0
- foxes/input/states/__init__.py +1 -1
- foxes/input/states/create/__init__.py +1 -0
- foxes/input/states/create/random_abl_states.py +6 -2
- foxes/input/states/create/random_timeseries.py +56 -0
- foxes/input/states/field_data_nc.py +12 -8
- foxes/input/states/multi_height.py +24 -14
- foxes/input/states/scan_ws.py +13 -17
- foxes/input/states/single.py +28 -20
- foxes/input/states/states_table.py +22 -18
- foxes/models/axial_induction_models/betz.py +1 -1
- foxes/models/farm_models/turbine2farm.py +2 -2
- foxes/models/model_book.py +40 -14
- foxes/models/partial_wakes/__init__.py +2 -2
- foxes/models/partial_wakes/axiwake.py +73 -200
- foxes/models/partial_wakes/centre.py +40 -0
- foxes/models/partial_wakes/grid.py +7 -63
- foxes/models/partial_wakes/rotor_points.py +53 -147
- foxes/models/partial_wakes/segregated.py +158 -0
- foxes/models/partial_wakes/top_hat.py +88 -196
- foxes/models/point_models/set_uniform_data.py +4 -4
- foxes/models/point_models/tke2ti.py +4 -4
- foxes/models/point_models/wake_deltas.py +4 -4
- foxes/models/rotor_models/centre.py +15 -19
- foxes/models/rotor_models/grid.py +2 -1
- foxes/models/rotor_models/levels.py +2 -1
- foxes/models/turbine_models/__init__.py +0 -1
- foxes/models/turbine_models/calculator.py +11 -7
- foxes/models/turbine_models/kTI_model.py +13 -11
- foxes/models/turbine_models/lookup_table.py +22 -9
- foxes/models/turbine_models/power_mask.py +81 -51
- foxes/models/turbine_models/rotor_centre_calc.py +17 -20
- foxes/models/turbine_models/sector_management.py +5 -6
- foxes/models/turbine_models/set_farm_vars.py +49 -20
- foxes/models/turbine_models/table_factors.py +5 -5
- foxes/models/turbine_models/thrust2ct.py +9 -5
- foxes/models/turbine_models/yaw2yawm.py +7 -13
- foxes/models/turbine_models/yawm2yaw.py +7 -11
- foxes/models/turbine_types/PCt_file.py +84 -3
- foxes/models/turbine_types/PCt_from_two.py +7 -3
- foxes/models/turbine_types/null_type.py +2 -2
- foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -2
- foxes/models/turbine_types/wsti2PCt_from_two.py +6 -2
- foxes/models/wake_frames/farm_order.py +26 -22
- foxes/models/wake_frames/rotor_wd.py +32 -31
- foxes/models/wake_frames/seq_dynamic_wakes.py +112 -64
- foxes/models/wake_frames/streamlines.py +51 -47
- foxes/models/wake_frames/timelines.py +59 -47
- foxes/models/wake_frames/yawed_wakes.py +63 -40
- foxes/models/wake_models/axisymmetric.py +31 -35
- foxes/models/wake_models/dist_sliced.py +50 -56
- foxes/models/wake_models/gaussian.py +33 -35
- foxes/models/wake_models/induction/rankine_half_body.py +79 -87
- foxes/models/wake_models/induction/rathmann.py +56 -63
- foxes/models/wake_models/induction/self_similar.py +59 -62
- foxes/models/wake_models/ti/crespo_hernandez.py +83 -74
- foxes/models/wake_models/ti/iec_ti.py +65 -75
- foxes/models/wake_models/top_hat.py +60 -69
- foxes/models/wake_models/wake_mirror.py +49 -54
- foxes/models/wake_models/wind/bastankhah14.py +44 -66
- foxes/models/wake_models/wind/bastankhah16.py +84 -111
- foxes/models/wake_models/wind/jensen.py +67 -89
- foxes/models/wake_models/wind/turbopark.py +93 -133
- foxes/models/wake_superpositions/ti_linear.py +33 -27
- foxes/models/wake_superpositions/ti_max.py +33 -27
- foxes/models/wake_superpositions/ti_pow.py +35 -27
- foxes/models/wake_superpositions/ti_quadratic.py +33 -27
- foxes/models/wake_superpositions/ws_linear.py +39 -32
- foxes/models/wake_superpositions/ws_max.py +40 -33
- foxes/models/wake_superpositions/ws_pow.py +39 -32
- foxes/models/wake_superpositions/ws_product.py +35 -28
- foxes/models/wake_superpositions/ws_quadratic.py +39 -32
- foxes/opt/constraints/min_dist.py +1 -1
- foxes/opt/objectives/farm_vars.py +1 -1
- foxes/opt/problems/layout/farm_layout.py +38 -97
- foxes/output/__init__.py +1 -0
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/flow_plots_2d/flow_plots.py +2 -0
- foxes/output/flow_plots_2d/get_fig.py +2 -0
- foxes/output/grids.py +1 -1
- foxes/output/rose_plot.py +3 -3
- foxes/output/rotor_point_plots.py +117 -0
- foxes/output/turbine_type_curves.py +2 -2
- foxes/utils/__init__.py +2 -1
- foxes/utils/load.py +29 -0
- foxes/utils/random_xy.py +56 -0
- foxes/utils/runners/runners.py +13 -1
- foxes/utils/windrose_plot.py +1 -1
- foxes/variables.py +10 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/METADATA +13 -7
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/RECORD +126 -122
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/WHEEL +1 -1
- foxes/models/partial_wakes/distsliced.py +0 -322
- foxes/models/partial_wakes/mapped.py +0 -252
- foxes/models/turbine_models/set_XYHD.py +0 -130
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/LICENSE +0 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/top_level.txt +0 -0
- {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/zip-safe +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
+
import numpy as np
|
|
2
3
|
|
|
3
4
|
from foxes.core import WakeModel
|
|
4
5
|
|
|
@@ -73,13 +74,13 @@ class DistSlicedWakeModel(WakeModel):
|
|
|
73
74
|
super().initialize(algo, verbosity, force)
|
|
74
75
|
|
|
75
76
|
@abstractmethod
|
|
76
|
-
def
|
|
77
|
+
def calc_wakes_x_yz(
|
|
77
78
|
self,
|
|
78
79
|
algo,
|
|
79
80
|
mdata,
|
|
80
81
|
fdata,
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
tdata,
|
|
83
|
+
downwind_index,
|
|
83
84
|
x,
|
|
84
85
|
yz,
|
|
85
86
|
):
|
|
@@ -90,77 +91,74 @@ class DistSlicedWakeModel(WakeModel):
|
|
|
90
91
|
----------
|
|
91
92
|
algo: foxes.core.Algorithm
|
|
92
93
|
The calculation algorithm
|
|
93
|
-
mdata: foxes.core.
|
|
94
|
+
mdata: foxes.core.MData
|
|
94
95
|
The model data
|
|
95
|
-
fdata: foxes.core.
|
|
96
|
+
fdata: foxes.core.FData
|
|
96
97
|
The farm data
|
|
97
|
-
|
|
98
|
-
The
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
wake causing turbine. Shape: (n_states,)
|
|
98
|
+
tdata: foxes.core.TData
|
|
99
|
+
The target point data
|
|
100
|
+
downwind_index: int
|
|
101
|
+
The index in the downwind order
|
|
102
102
|
x: numpy.ndarray
|
|
103
|
-
The x values, shape: (n_states,
|
|
103
|
+
The x values, shape: (n_states, n_targets)
|
|
104
104
|
yz: numpy.ndarray
|
|
105
105
|
The yz values for each x value, shape:
|
|
106
|
-
(n_states,
|
|
106
|
+
(n_states, n_targets, n_yz_per_target, 2)
|
|
107
107
|
|
|
108
108
|
Returns
|
|
109
109
|
-------
|
|
110
110
|
wdeltas: dict
|
|
111
111
|
The wake deltas. Key: variable name str,
|
|
112
|
-
value: numpy.ndarray, shape: (
|
|
113
|
-
|
|
114
|
-
The state-
|
|
115
|
-
is non-zero, shape: (n_states,
|
|
112
|
+
value: numpy.ndarray, shape: (n_st_sel, n_yz_per_target)
|
|
113
|
+
st_sel: numpy.ndarray of bool
|
|
114
|
+
The state-target selection, for which the wake
|
|
115
|
+
is non-zero, shape: (n_states, n_targets)
|
|
116
116
|
|
|
117
117
|
"""
|
|
118
118
|
pass
|
|
119
119
|
|
|
120
|
-
def
|
|
120
|
+
def contribute(
|
|
121
121
|
self,
|
|
122
122
|
algo,
|
|
123
123
|
mdata,
|
|
124
124
|
fdata,
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
tdata,
|
|
126
|
+
downwind_index,
|
|
127
127
|
wake_coos,
|
|
128
128
|
wake_deltas,
|
|
129
129
|
):
|
|
130
130
|
"""
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Modifies wake_deltas on the fly.
|
|
131
|
+
Modifies wake deltas at target points by
|
|
132
|
+
contributions from the specified wake source turbines.
|
|
135
133
|
|
|
136
134
|
Parameters
|
|
137
135
|
----------
|
|
138
136
|
algo: foxes.core.Algorithm
|
|
139
137
|
The calculation algorithm
|
|
140
|
-
mdata: foxes.core.
|
|
138
|
+
mdata: foxes.core.MData
|
|
141
139
|
The model data
|
|
142
|
-
fdata: foxes.core.
|
|
140
|
+
fdata: foxes.core.FData
|
|
143
141
|
The farm data
|
|
144
|
-
|
|
145
|
-
The
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
142
|
+
tdata: foxes.core.TData
|
|
143
|
+
The target point data
|
|
144
|
+
downwind_index: int
|
|
145
|
+
The index of the wake causing turbine
|
|
146
|
+
in the downwnd order
|
|
149
147
|
wake_coos: numpy.ndarray
|
|
150
148
|
The wake frame coordinates of the evaluation
|
|
151
|
-
points, shape: (n_states,
|
|
149
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
152
150
|
wake_deltas: dict
|
|
153
|
-
The wake deltas
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
shape (n_states, n_points, ...)
|
|
151
|
+
The wake deltas. Key: variable name,
|
|
152
|
+
value: numpy.ndarray with shape
|
|
153
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
157
154
|
|
|
158
155
|
"""
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
# rounding for safe x > 0 conditions
|
|
157
|
+
x = np.round(wake_coos[:, :, 0, 0], 12)
|
|
158
|
+
yz = wake_coos[..., 1:3]
|
|
161
159
|
|
|
162
|
-
wdeltas,
|
|
163
|
-
algo, mdata, fdata,
|
|
160
|
+
wdeltas, st_sel = self.calc_wakes_x_yz(
|
|
161
|
+
algo, mdata, fdata, tdata, downwind_index, x, yz
|
|
164
162
|
)
|
|
165
163
|
|
|
166
164
|
for v, hdel in wdeltas.items():
|
|
@@ -171,16 +169,16 @@ class DistSlicedWakeModel(WakeModel):
|
|
|
171
169
|
f"Model '{self.name}': Missing wake superposition entry for variable '{v}', found {sorted(list(self.superp.keys()))}"
|
|
172
170
|
)
|
|
173
171
|
|
|
174
|
-
wake_deltas[v] = superp.
|
|
172
|
+
wake_deltas[v] = superp.add_wake(
|
|
175
173
|
algo,
|
|
176
174
|
mdata,
|
|
177
175
|
fdata,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
tdata,
|
|
177
|
+
downwind_index,
|
|
178
|
+
st_sel,
|
|
181
179
|
v,
|
|
182
180
|
wake_deltas[v],
|
|
183
|
-
hdel
|
|
181
|
+
hdel,
|
|
184
182
|
)
|
|
185
183
|
|
|
186
184
|
def finalize_wake_deltas(
|
|
@@ -188,7 +186,6 @@ class DistSlicedWakeModel(WakeModel):
|
|
|
188
186
|
algo,
|
|
189
187
|
mdata,
|
|
190
188
|
fdata,
|
|
191
|
-
pdata,
|
|
192
189
|
amb_results,
|
|
193
190
|
wake_deltas,
|
|
194
191
|
):
|
|
@@ -201,24 +198,21 @@ class DistSlicedWakeModel(WakeModel):
|
|
|
201
198
|
----------
|
|
202
199
|
algo: foxes.core.Algorithm
|
|
203
200
|
The calculation algorithm
|
|
204
|
-
mdata: foxes.core.
|
|
201
|
+
mdata: foxes.core.MData
|
|
205
202
|
The model data
|
|
206
|
-
fdata: foxes.core.
|
|
203
|
+
fdata: foxes.core.FData
|
|
207
204
|
The farm data
|
|
208
|
-
pdata: foxes.core.Data
|
|
209
|
-
The evaluation point data
|
|
210
205
|
amb_results: dict
|
|
211
206
|
The ambient results, key: variable name str,
|
|
212
|
-
values: numpy.ndarray with shape
|
|
207
|
+
values: numpy.ndarray with shape
|
|
208
|
+
(n_states, n_targets, n_tpoints)
|
|
213
209
|
wake_deltas: dict
|
|
214
|
-
The wake deltas
|
|
215
|
-
Key:
|
|
216
|
-
|
|
217
|
-
(n_states, n_points, ...) before evaluation,
|
|
218
|
-
numpy.ndarray with shape (n_states, n_points) afterwards
|
|
210
|
+
The wake deltas object at the selected target
|
|
211
|
+
turbines. Key: variable str, value: numpy.ndarray
|
|
212
|
+
with shape (n_states, n_targets, n_tpoints)
|
|
219
213
|
|
|
220
214
|
"""
|
|
221
215
|
for v, s in self.superp.items():
|
|
222
216
|
wake_deltas[v] = s.calc_final_wake_delta(
|
|
223
|
-
algo, mdata, fdata,
|
|
217
|
+
algo, mdata, fdata, v, amb_results[v], wake_deltas[v]
|
|
224
218
|
)
|
|
@@ -13,13 +13,13 @@ class GaussianWakeModel(AxisymmetricWakeModel):
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
@abstractmethod
|
|
16
|
-
def
|
|
16
|
+
def calc_amplitude_sigma(
|
|
17
17
|
self,
|
|
18
18
|
algo,
|
|
19
19
|
mdata,
|
|
20
20
|
fdata,
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
tdata,
|
|
22
|
+
downwind_index,
|
|
23
23
|
x,
|
|
24
24
|
):
|
|
25
25
|
"""
|
|
@@ -30,37 +30,36 @@ class GaussianWakeModel(AxisymmetricWakeModel):
|
|
|
30
30
|
----------
|
|
31
31
|
algo: foxes.core.Algorithm
|
|
32
32
|
The calculation algorithm
|
|
33
|
-
mdata: foxes.core.
|
|
33
|
+
mdata: foxes.core.MData
|
|
34
34
|
The model data
|
|
35
|
-
fdata: foxes.core.
|
|
35
|
+
fdata: foxes.core.FData
|
|
36
36
|
The farm data
|
|
37
|
-
|
|
38
|
-
The
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
wake causing turbine. Shape: (n_states,)
|
|
37
|
+
tdata: foxes.core.TData
|
|
38
|
+
The target point data
|
|
39
|
+
downwind_index: int
|
|
40
|
+
The index in the downwind order
|
|
42
41
|
x: numpy.ndarray
|
|
43
|
-
The x values, shape: (n_states,
|
|
42
|
+
The x values, shape: (n_states, n_targets)
|
|
44
43
|
|
|
45
44
|
Returns
|
|
46
45
|
-------
|
|
47
46
|
amsi: tuple
|
|
48
47
|
The amplitude and sigma, both numpy.ndarray
|
|
49
|
-
with shape (
|
|
50
|
-
|
|
51
|
-
The state-
|
|
52
|
-
is non-zero, shape: (n_states,
|
|
48
|
+
with shape (n_st_sel,)
|
|
49
|
+
st_sel: numpy.ndarray of bool
|
|
50
|
+
The state-target selection, for which the wake
|
|
51
|
+
is non-zero, shape: (n_states, n_targets)
|
|
53
52
|
|
|
54
53
|
"""
|
|
55
54
|
pass
|
|
56
55
|
|
|
57
|
-
def
|
|
56
|
+
def calc_wakes_x_r(
|
|
58
57
|
self,
|
|
59
58
|
algo,
|
|
60
59
|
mdata,
|
|
61
60
|
fdata,
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
tdata,
|
|
62
|
+
downwind_index,
|
|
64
63
|
x,
|
|
65
64
|
r,
|
|
66
65
|
):
|
|
@@ -71,38 +70,37 @@ class GaussianWakeModel(AxisymmetricWakeModel):
|
|
|
71
70
|
----------
|
|
72
71
|
algo: foxes.core.Algorithm
|
|
73
72
|
The calculation algorithm
|
|
74
|
-
mdata: foxes.core.
|
|
73
|
+
mdata: foxes.core.MData
|
|
75
74
|
The model data
|
|
76
|
-
fdata: foxes.core.
|
|
75
|
+
fdata: foxes.core.FData
|
|
77
76
|
The farm data
|
|
78
|
-
|
|
79
|
-
The
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
wake causing turbine. Shape: (n_states,)
|
|
77
|
+
tdata: foxes.core.TData
|
|
78
|
+
The target point data
|
|
79
|
+
downwind_index: int
|
|
80
|
+
The index in the downwind order
|
|
83
81
|
x: numpy.ndarray
|
|
84
|
-
The x values, shape: (n_states,
|
|
82
|
+
The x values, shape: (n_states, n_targets)
|
|
85
83
|
r: numpy.ndarray
|
|
86
84
|
The radial values for each x value, shape:
|
|
87
|
-
(n_states,
|
|
85
|
+
(n_states, n_targets, n_yz_per_target)
|
|
88
86
|
|
|
89
87
|
Returns
|
|
90
88
|
-------
|
|
91
89
|
wdeltas: dict
|
|
92
90
|
The wake deltas. Key: variable name str,
|
|
93
|
-
value: numpy.ndarray, shape: (
|
|
94
|
-
|
|
95
|
-
The state-
|
|
96
|
-
is non-zero, shape: (n_states,
|
|
91
|
+
value: numpy.ndarray, shape: (n_st_sel, n_r_per_x)
|
|
92
|
+
st_sel: numpy.ndarray of bool
|
|
93
|
+
The state-target selection, for which the wake
|
|
94
|
+
is non-zero, shape: (n_states, n_targets)
|
|
97
95
|
|
|
98
96
|
"""
|
|
99
|
-
amsi,
|
|
100
|
-
algo, mdata, fdata,
|
|
97
|
+
amsi, st_sel = self.calc_amplitude_sigma(
|
|
98
|
+
algo, mdata, fdata, tdata, downwind_index, x
|
|
101
99
|
)
|
|
102
100
|
wdeltas = {}
|
|
103
|
-
rsel = r[
|
|
101
|
+
rsel = r[st_sel]
|
|
104
102
|
for v in amsi.keys():
|
|
105
103
|
ampld, sigma = amsi[v]
|
|
106
104
|
wdeltas[v] = ampld[:, None] * np.exp(-0.5 * (rsel / sigma[:, None]) ** 2)
|
|
107
105
|
|
|
108
|
-
return wdeltas,
|
|
106
|
+
return wdeltas, st_sel
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
|
-
from foxes.core import
|
|
3
|
+
from foxes.core import TurbineInductionModel
|
|
4
4
|
from foxes.utils import uv2wd, wd2uv
|
|
5
5
|
import foxes.variables as FV
|
|
6
6
|
import foxes.constants as FC
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
class RankineHalfBody(
|
|
9
|
+
class RankineHalfBody(TurbineInductionModel):
|
|
10
10
|
"""
|
|
11
11
|
The Rankine half body induction wake model
|
|
12
12
|
|
|
@@ -43,6 +43,12 @@ class RankineHalfBody(WakeModel):
|
|
|
43
43
|
super().__init__()
|
|
44
44
|
self.induction = induction
|
|
45
45
|
|
|
46
|
+
def __repr__(self):
|
|
47
|
+
iname = (
|
|
48
|
+
self.induction if isinstance(self.induction, str) else self.induction.name
|
|
49
|
+
)
|
|
50
|
+
return f"{type(self).__name__}(induction={iname})"
|
|
51
|
+
|
|
46
52
|
def sub_models(self):
|
|
47
53
|
"""
|
|
48
54
|
List of all sub-models
|
|
@@ -73,122 +79,113 @@ class RankineHalfBody(WakeModel):
|
|
|
73
79
|
self.induction = algo.mbook.axial_induction[self.induction]
|
|
74
80
|
super().initialize(algo, verbosity, force)
|
|
75
81
|
|
|
76
|
-
def
|
|
82
|
+
def new_wake_deltas(self, algo, mdata, fdata, tdata):
|
|
77
83
|
"""
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
They are added on the fly to the wake_deltas dict.
|
|
84
|
+
Creates new empty wake delta arrays.
|
|
81
85
|
|
|
82
86
|
Parameters
|
|
83
87
|
----------
|
|
84
88
|
algo: foxes.core.Algorithm
|
|
85
89
|
The calculation algorithm
|
|
86
|
-
mdata: foxes.core.
|
|
90
|
+
mdata: foxes.core.MData
|
|
87
91
|
The model data
|
|
88
|
-
fdata: foxes.core.
|
|
92
|
+
fdata: foxes.core.FData
|
|
89
93
|
The farm data
|
|
90
|
-
|
|
91
|
-
The
|
|
94
|
+
tdata: foxes.core.TData
|
|
95
|
+
The target point data
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
92
99
|
wake_deltas: dict
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
wake delta applies, values: numpy.ndarray with
|
|
96
|
-
shape (n_states, n_points, ...)
|
|
100
|
+
Key: variable name, value: The zero filled
|
|
101
|
+
wake deltas, shape: (n_states, n_turbines, n_rpoints, ...)
|
|
97
102
|
|
|
98
103
|
"""
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def
|
|
104
|
+
return {
|
|
105
|
+
FV.WS: np.zeros_like(tdata[FC.TARGETS][..., 0]),
|
|
106
|
+
FV.WD: np.zeros_like(tdata[FC.TARGETS][..., 0]),
|
|
107
|
+
"U": np.zeros_like(tdata[FC.TARGETS][..., 0]),
|
|
108
|
+
"V": np.zeros_like(tdata[FC.TARGETS][..., 0]),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
def contribute(
|
|
107
112
|
self,
|
|
108
113
|
algo,
|
|
109
114
|
mdata,
|
|
110
115
|
fdata,
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
tdata,
|
|
117
|
+
downwind_index,
|
|
113
118
|
wake_coos,
|
|
114
119
|
wake_deltas,
|
|
115
120
|
):
|
|
116
121
|
"""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Modifies wake_deltas on the fly.
|
|
122
|
+
Modifies wake deltas at target points by
|
|
123
|
+
contributions from the specified wake source turbines.
|
|
121
124
|
|
|
122
125
|
Parameters
|
|
123
126
|
----------
|
|
124
127
|
algo: foxes.core.Algorithm
|
|
125
128
|
The calculation algorithm
|
|
126
|
-
mdata: foxes.core.
|
|
129
|
+
mdata: foxes.core.MData
|
|
127
130
|
The model data
|
|
128
|
-
fdata: foxes.core.
|
|
131
|
+
fdata: foxes.core.FData
|
|
129
132
|
The farm data
|
|
130
|
-
|
|
131
|
-
The
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
tdata: foxes.core.TData
|
|
134
|
+
The target point data
|
|
135
|
+
downwind_index: int
|
|
136
|
+
The index of the wake causing turbine
|
|
137
|
+
in the downwnd order
|
|
135
138
|
wake_coos: numpy.ndarray
|
|
136
139
|
The wake frame coordinates of the evaluation
|
|
137
|
-
points, shape: (n_states,
|
|
140
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
138
141
|
wake_deltas: dict
|
|
139
|
-
The wake deltas
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
shape (n_states, n_points, ...)
|
|
142
|
+
The wake deltas. Key: variable name,
|
|
143
|
+
value: numpy.ndarray with shape
|
|
144
|
+
(n_states, n_targets, n_tpoints, ...)
|
|
143
145
|
|
|
144
146
|
"""
|
|
145
|
-
|
|
146
|
-
# get x, y and z
|
|
147
|
-
x = wake_coos[:, :, 0]
|
|
148
|
-
y = wake_coos[:, :, 1]
|
|
149
|
-
z = wake_coos[:, :, 2]
|
|
150
|
-
|
|
151
147
|
# get ct:
|
|
152
148
|
ct = self.get_data(
|
|
153
149
|
FV.CT,
|
|
154
|
-
FC.
|
|
150
|
+
FC.STATE_TARGET_TPOINT,
|
|
155
151
|
lookup="w",
|
|
156
152
|
algo=algo,
|
|
157
153
|
fdata=fdata,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
tdata=tdata,
|
|
155
|
+
downwind_index=downwind_index,
|
|
156
|
+
upcast=False,
|
|
161
157
|
)
|
|
162
158
|
|
|
163
159
|
# get ws:
|
|
164
160
|
ws = self.get_data(
|
|
165
161
|
FV.REWS,
|
|
166
|
-
FC.
|
|
162
|
+
FC.STATE_TARGET_TPOINT,
|
|
167
163
|
lookup="w",
|
|
168
164
|
algo=algo,
|
|
169
165
|
fdata=fdata,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
166
|
+
tdata=tdata,
|
|
167
|
+
downwind_index=downwind_index,
|
|
168
|
+
upcast=False,
|
|
173
169
|
)
|
|
174
170
|
|
|
175
171
|
# get D
|
|
176
172
|
D = self.get_data(
|
|
177
173
|
FV.D,
|
|
178
|
-
FC.
|
|
174
|
+
FC.STATE_TARGET_TPOINT,
|
|
179
175
|
lookup="w",
|
|
180
176
|
algo=algo,
|
|
181
177
|
fdata=fdata,
|
|
182
|
-
|
|
178
|
+
tdata=tdata,
|
|
179
|
+
downwind_index=downwind_index,
|
|
183
180
|
upcast=True,
|
|
184
|
-
states_source_turbine=states_source_turbine,
|
|
185
181
|
)
|
|
186
182
|
|
|
187
183
|
# calc m (page 7, skipping pi everywhere)
|
|
188
184
|
m = 2 * ws * self.induction.ct2a(ct) * (D / 2) ** 2
|
|
189
185
|
|
|
190
186
|
# get r and theta
|
|
191
|
-
|
|
187
|
+
x = np.round(wake_coos[..., 0], 12)
|
|
188
|
+
r = np.linalg.norm(wake_coos[..., 1:], axis=-1)
|
|
192
189
|
r_sph = np.sqrt(r**2 + x**2)
|
|
193
190
|
theta = np.arctan2(r, x)
|
|
194
191
|
|
|
@@ -201,35 +198,32 @@ class RankineHalfBody(WakeModel):
|
|
|
201
198
|
xs = -np.sqrt(m / (4 * ws))
|
|
202
199
|
|
|
203
200
|
# set values out of body shape
|
|
204
|
-
|
|
205
|
-
if np.any(
|
|
201
|
+
st_sel = (ct > 0) & ((RHB_shape < -1) | (x < xs))
|
|
202
|
+
if np.any(st_sel):
|
|
206
203
|
# apply selection
|
|
207
|
-
xyz = wake_coos[
|
|
204
|
+
xyz = wake_coos[st_sel]
|
|
208
205
|
|
|
209
206
|
# calc velocity components
|
|
210
|
-
vel_factor = m[
|
|
211
|
-
wake_deltas["U"][
|
|
212
|
-
wake_deltas["V"][
|
|
207
|
+
vel_factor = m[st_sel] / (4 * np.linalg.norm(xyz, axis=-1) ** 3)
|
|
208
|
+
wake_deltas["U"][st_sel] += vel_factor * xyz[:, 0]
|
|
209
|
+
wake_deltas["V"][st_sel] += vel_factor * xyz[:, 1]
|
|
213
210
|
|
|
214
211
|
# set values inside body shape
|
|
215
|
-
|
|
216
|
-
if np.any(
|
|
212
|
+
st_sel = (ct > 0) & (RHB_shape >= -1) & (x >= xs) & (x <= 0)
|
|
213
|
+
if np.any(st_sel):
|
|
217
214
|
# apply selection
|
|
218
|
-
xyz = np.zeros_like(wake_coos[
|
|
219
|
-
xyz[:, 0] = xs[
|
|
215
|
+
xyz = np.zeros_like(wake_coos[st_sel])
|
|
216
|
+
xyz[:, 0] = xs[st_sel]
|
|
220
217
|
|
|
221
218
|
# calc velocity components
|
|
222
|
-
vel_factor = m[
|
|
223
|
-
wake_deltas["U"][
|
|
224
|
-
|
|
225
|
-
return wake_deltas
|
|
219
|
+
vel_factor = m[st_sel] / (4 * np.linalg.norm(xyz, axis=-1) ** 3)
|
|
220
|
+
wake_deltas["U"][st_sel] += vel_factor * xyz[:, 0]
|
|
226
221
|
|
|
227
222
|
def finalize_wake_deltas(
|
|
228
223
|
self,
|
|
229
224
|
algo,
|
|
230
225
|
mdata,
|
|
231
226
|
fdata,
|
|
232
|
-
pdata,
|
|
233
227
|
amb_results,
|
|
234
228
|
wake_deltas,
|
|
235
229
|
):
|
|
@@ -242,32 +236,30 @@ class RankineHalfBody(WakeModel):
|
|
|
242
236
|
----------
|
|
243
237
|
algo: foxes.core.Algorithm
|
|
244
238
|
The calculation algorithm
|
|
245
|
-
mdata: foxes.core.
|
|
239
|
+
mdata: foxes.core.MData
|
|
246
240
|
The model data
|
|
247
|
-
fdata: foxes.core.
|
|
241
|
+
fdata: foxes.core.FData
|
|
248
242
|
The farm data
|
|
249
|
-
pdata: foxes.core.Data
|
|
250
|
-
The evaluation point data
|
|
251
243
|
amb_results: dict
|
|
252
244
|
The ambient results, key: variable name str,
|
|
253
|
-
values: numpy.ndarray with shape
|
|
245
|
+
values: numpy.ndarray with shape
|
|
246
|
+
(n_states, n_targets, n_tpoints)
|
|
254
247
|
wake_deltas: dict
|
|
255
|
-
The wake deltas
|
|
256
|
-
Key:
|
|
257
|
-
|
|
258
|
-
(n_states, n_points, ...) before evaluation,
|
|
259
|
-
numpy.ndarray with shape (n_states, n_points) afterwards
|
|
248
|
+
The wake deltas object at the selected target
|
|
249
|
+
turbines. Key: variable str, value: numpy.ndarray
|
|
250
|
+
with shape (n_states, n_targets, n_tpoints)
|
|
260
251
|
|
|
261
252
|
"""
|
|
262
|
-
|
|
263
253
|
# calc ambient wind vector:
|
|
264
254
|
ws0 = amb_results[FV.WS]
|
|
265
255
|
nx = wd2uv(amb_results[FV.WD])
|
|
266
|
-
wind_vec = nx * ws0[:, :, None]
|
|
256
|
+
wind_vec = nx * ws0[:, :, :, None]
|
|
267
257
|
|
|
268
258
|
# wake deltas are in wake frame, rotate back to global frame:
|
|
269
|
-
ny = np.stack((-nx[
|
|
270
|
-
delta_uv =
|
|
259
|
+
ny = np.stack((-nx[..., 1], nx[..., 0]), axis=-1)
|
|
260
|
+
delta_uv = (
|
|
261
|
+
wake_deltas["U"][:, :, :, None] * nx + wake_deltas["V"][:, :, :, None] * ny
|
|
262
|
+
)
|
|
271
263
|
del ws0, nx, ny
|
|
272
264
|
|
|
273
265
|
# add ambient result to wake deltas:
|