foxes 0.6.2__py3-none-any.whl → 0.7.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of foxes might be problematic. Click here for more details.
- 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/from_random.py +10 -9
- foxes/input/states/create/random_timeseries.py +17 -19
- 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 +39 -14
- foxes/models/partial_wakes/__init__.py +2 -3
- foxes/models/partial_wakes/axiwake.py +73 -200
- foxes/models/partial_wakes/centre.py +11 -79
- 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/problems/layout/farm_layout.py +38 -97
- foxes/output/__init__.py +1 -0
- foxes/output/flow_plots_2d/flow_plots.py +2 -0
- 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 +1 -1
- foxes/utils/load.py +29 -0
- foxes/utils/random_xy.py +11 -10
- foxes/utils/runners/runners.py +3 -4
- foxes/utils/windrose_plot.py +1 -1
- foxes/variables.py +10 -0
- {foxes-0.6.2.dist-info → foxes-0.7.0.2.dist-info}/METADATA +13 -7
- {foxes-0.6.2.dist-info → foxes-0.7.0.2.dist-info}/RECORD +117 -117
- 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.2.dist-info → foxes-0.7.0.2.dist-info}/LICENSE +0 -0
- {foxes-0.6.2.dist-info → foxes-0.7.0.2.dist-info}/WHEEL +0 -0
- {foxes-0.6.2.dist-info → foxes-0.7.0.2.dist-info}/top_level.txt +0 -0
- {foxes-0.6.2.dist-info → foxes-0.7.0.2.dist-info}/zip-safe +0 -0
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
from foxes.core import PartialWakesModel, Data
|
|
4
|
-
from foxes.models.wake_models.dist_sliced import DistSlicedWakeModel
|
|
5
|
-
from foxes.models.rotor_models.grid import GridRotor
|
|
6
|
-
from foxes.utils import wd2uv, uv2wd
|
|
7
|
-
import foxes.variables as FV
|
|
8
|
-
import foxes.constants as FC
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class PartialDistSlicedWake(PartialWakesModel):
|
|
12
|
-
"""
|
|
13
|
-
Partial wakes for distance sliced wake models,
|
|
14
|
-
making use of their structure.
|
|
15
|
-
|
|
16
|
-
The evaluations are optinally done on a grid rotor
|
|
17
|
-
that can differ from the algorithm's rotor model.
|
|
18
|
-
|
|
19
|
-
Attributes
|
|
20
|
-
----------
|
|
21
|
-
rotor_model: foxes.core.RotorModel
|
|
22
|
-
The rotor model, default is the one from the algorithm
|
|
23
|
-
grotor: foxes.models.rotor_models.GridRotor
|
|
24
|
-
The grid rotor model
|
|
25
|
-
|
|
26
|
-
:group: models.partial_wakes
|
|
27
|
-
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
def __init__(
|
|
31
|
-
self, n=None, wake_models=None, wake_frame=None, rotor_model=None, **kwargs
|
|
32
|
-
):
|
|
33
|
-
"""
|
|
34
|
-
Constructor.
|
|
35
|
-
|
|
36
|
-
Parameters
|
|
37
|
-
----------
|
|
38
|
-
n: int, optional
|
|
39
|
-
The `GridRotor`'s `n` parameter
|
|
40
|
-
wake_models: list of foxes.core.WakeModel, optional
|
|
41
|
-
The wake models, default are the ones from the algorithm
|
|
42
|
-
wake_frame: foxes.core.WakeFrame, optional
|
|
43
|
-
The wake frame, default is the one from the algorithm
|
|
44
|
-
rotor_model: foxes.core.RotorModel, optional
|
|
45
|
-
The rotor model, default is the one from the algorithm
|
|
46
|
-
kwargs: dict, optional
|
|
47
|
-
Additional parameters for the `GridRotor`
|
|
48
|
-
|
|
49
|
-
"""
|
|
50
|
-
super().__init__(wake_models, wake_frame)
|
|
51
|
-
|
|
52
|
-
self.rotor_model = rotor_model
|
|
53
|
-
self.grotor = None if n is None else GridRotor(n=n, calc_vars=[], **kwargs)
|
|
54
|
-
|
|
55
|
-
def __repr__(self):
|
|
56
|
-
if self.grotor is not None:
|
|
57
|
-
return super().__repr__() + f"(n={self.grotor.n})"
|
|
58
|
-
elif self.rotor_model is not None and isinstance(self.rotor_model, GridRotor):
|
|
59
|
-
return super().__repr__() + f"(n={self.rotor_model.n})"
|
|
60
|
-
else:
|
|
61
|
-
return super().__repr__()
|
|
62
|
-
|
|
63
|
-
def initialize(self, algo, verbosity=0):
|
|
64
|
-
"""
|
|
65
|
-
Initializes the model.
|
|
66
|
-
|
|
67
|
-
Parameters
|
|
68
|
-
----------
|
|
69
|
-
algo: foxes.core.Algorithm
|
|
70
|
-
The calculation algorithm
|
|
71
|
-
verbosity: int
|
|
72
|
-
The verbosity level, 0 = silent
|
|
73
|
-
|
|
74
|
-
"""
|
|
75
|
-
if self.rotor_model is None:
|
|
76
|
-
self.rotor_model = algo.rotor_model
|
|
77
|
-
if self.grotor is None:
|
|
78
|
-
self.grotor = self.rotor_model
|
|
79
|
-
|
|
80
|
-
super().initialize(algo, verbosity)
|
|
81
|
-
|
|
82
|
-
for w in self.wake_models:
|
|
83
|
-
if not isinstance(w, DistSlicedWakeModel):
|
|
84
|
-
raise TypeError(
|
|
85
|
-
f"Partial wakes '{self.name}': Cannot be applied to wake model '{w.name}', since not an DistSlicedWakeModel"
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
self.YZ = self.var("YZ")
|
|
89
|
-
self.W = self.var(FV.WEIGHT)
|
|
90
|
-
|
|
91
|
-
def sub_models(self):
|
|
92
|
-
"""
|
|
93
|
-
List of all sub-models
|
|
94
|
-
|
|
95
|
-
Returns
|
|
96
|
-
-------
|
|
97
|
-
smdls: list of foxes.core.Model
|
|
98
|
-
Names of all sub models
|
|
99
|
-
|
|
100
|
-
"""
|
|
101
|
-
return super().sub_models() + [self.rotor_model, self.grotor]
|
|
102
|
-
|
|
103
|
-
def new_wake_deltas(self, algo, mdata, fdata):
|
|
104
|
-
"""
|
|
105
|
-
Creates new initial wake deltas, filled
|
|
106
|
-
with zeros.
|
|
107
|
-
|
|
108
|
-
Parameters
|
|
109
|
-
----------
|
|
110
|
-
algo: foxes.core.Algorithm
|
|
111
|
-
The calculation algorithm
|
|
112
|
-
mdata: foxes.core.Data
|
|
113
|
-
The model data
|
|
114
|
-
fdata: foxes.core.Data
|
|
115
|
-
The farm data
|
|
116
|
-
|
|
117
|
-
Returns
|
|
118
|
-
-------
|
|
119
|
-
wake_deltas: dict
|
|
120
|
-
Keys: Variable name str, values: any
|
|
121
|
-
pdata: foxes.core.Data
|
|
122
|
-
The evaluation point data
|
|
123
|
-
|
|
124
|
-
"""
|
|
125
|
-
|
|
126
|
-
n_states = fdata.n_states
|
|
127
|
-
n_rpoints = self.grotor.n_rotor_points()
|
|
128
|
-
n_points = fdata.n_turbines * n_rpoints
|
|
129
|
-
points = self.grotor.get_rotor_points(algo, mdata, fdata).reshape(
|
|
130
|
-
n_states, n_points, 3
|
|
131
|
-
)
|
|
132
|
-
pdata = Data.from_points(points=points)
|
|
133
|
-
|
|
134
|
-
wake_deltas = {}
|
|
135
|
-
for w in self.wake_models:
|
|
136
|
-
w.init_wake_deltas(algo, mdata, fdata, pdata, wake_deltas)
|
|
137
|
-
|
|
138
|
-
return wake_deltas, pdata
|
|
139
|
-
|
|
140
|
-
def contribute_to_wake_deltas(
|
|
141
|
-
self,
|
|
142
|
-
algo,
|
|
143
|
-
mdata,
|
|
144
|
-
fdata,
|
|
145
|
-
pdata,
|
|
146
|
-
states_source_turbine,
|
|
147
|
-
wake_deltas,
|
|
148
|
-
):
|
|
149
|
-
"""
|
|
150
|
-
Modifies wake deltas by contributions from the
|
|
151
|
-
specified wake source turbines.
|
|
152
|
-
|
|
153
|
-
Parameters
|
|
154
|
-
----------
|
|
155
|
-
algo: foxes.core.Algorithm
|
|
156
|
-
The calculation algorithm
|
|
157
|
-
mdata: foxes.core.Data
|
|
158
|
-
The model data
|
|
159
|
-
fdata: foxes.core.Data
|
|
160
|
-
The farm data
|
|
161
|
-
pdata: foxes.core.Data
|
|
162
|
-
The evaluation point data
|
|
163
|
-
states_source_turbine: numpy.ndarray of int
|
|
164
|
-
For each state, one turbine index corresponding
|
|
165
|
-
to the wake causing turbine. Shape: (n_states,)
|
|
166
|
-
wake_deltas: Any
|
|
167
|
-
The wake deltas object created by the
|
|
168
|
-
`new_wake_deltas` function
|
|
169
|
-
|
|
170
|
-
"""
|
|
171
|
-
|
|
172
|
-
# calc x-coordinates of rotor centres:
|
|
173
|
-
hpdata = Data.from_points(points=fdata[FV.TXYH])
|
|
174
|
-
x = self.wake_frame.get_wake_coos(
|
|
175
|
-
algo, mdata, fdata, hpdata, states_source_turbine
|
|
176
|
-
)[:, :, 0]
|
|
177
|
-
|
|
178
|
-
# evaluate grid rotor:
|
|
179
|
-
n_states = fdata.n_states
|
|
180
|
-
n_turbines = fdata.n_turbines
|
|
181
|
-
n_rpoints = self.grotor.n_rotor_points()
|
|
182
|
-
n_points = fdata.n_turbines * n_rpoints
|
|
183
|
-
wcoos = self.wake_frame.get_wake_coos(
|
|
184
|
-
algo, mdata, fdata, pdata, states_source_turbine
|
|
185
|
-
)
|
|
186
|
-
yz = wcoos.reshape(n_states, n_turbines, n_rpoints, 3)[:, :, :, 1:3]
|
|
187
|
-
del wcoos
|
|
188
|
-
|
|
189
|
-
# evaluate wake models:
|
|
190
|
-
for w in self.wake_models:
|
|
191
|
-
wdeltas, sp_sel = w.calc_wakes_spsel_x_yz(
|
|
192
|
-
algo, mdata, fdata, hpdata, states_source_turbine, x, yz
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
wsps = np.zeros((n_states, n_turbines, n_rpoints), dtype=bool)
|
|
196
|
-
wsps[:] = sp_sel[:, :, None]
|
|
197
|
-
wsps = wsps.reshape(n_states, n_points)
|
|
198
|
-
|
|
199
|
-
for v, wdel in wdeltas.items():
|
|
200
|
-
d = np.zeros((n_states, n_turbines, n_rpoints), dtype=FC.DTYPE)
|
|
201
|
-
d[sp_sel] = wdel
|
|
202
|
-
d = d.reshape(n_states, n_points)[wsps]
|
|
203
|
-
|
|
204
|
-
try:
|
|
205
|
-
superp = w.superp[v]
|
|
206
|
-
except KeyError:
|
|
207
|
-
raise KeyError(
|
|
208
|
-
f"Model '{self.name}': Missing wake superposition entry for variable '{v}' in wake model '{w.name}', found {sorted(list(w.superp.keys()))}"
|
|
209
|
-
)
|
|
210
|
-
|
|
211
|
-
wake_deltas[v] = superp.calc_wakes_plus_wake(
|
|
212
|
-
algo,
|
|
213
|
-
mdata,
|
|
214
|
-
fdata,
|
|
215
|
-
pdata,
|
|
216
|
-
states_source_turbine,
|
|
217
|
-
wsps,
|
|
218
|
-
v,
|
|
219
|
-
wake_deltas[v],
|
|
220
|
-
d,
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
def evaluate_results(
|
|
224
|
-
self,
|
|
225
|
-
algo,
|
|
226
|
-
mdata,
|
|
227
|
-
fdata,
|
|
228
|
-
pdata,
|
|
229
|
-
wake_deltas,
|
|
230
|
-
states_turbine,
|
|
231
|
-
amb_res=None,
|
|
232
|
-
):
|
|
233
|
-
"""
|
|
234
|
-
Updates the farm data according to the wake
|
|
235
|
-
deltas.
|
|
236
|
-
|
|
237
|
-
Parameters
|
|
238
|
-
----------
|
|
239
|
-
algo: foxes.core.Algorithm
|
|
240
|
-
The calculation algorithm
|
|
241
|
-
mdata: foxes.core.Data
|
|
242
|
-
The model data
|
|
243
|
-
fdata: foxes.core.Data
|
|
244
|
-
The farm data
|
|
245
|
-
Modified in-place by this function
|
|
246
|
-
pdata: foxes.core.Data
|
|
247
|
-
The evaluation point data
|
|
248
|
-
wake_deltas: Any
|
|
249
|
-
The wake deltas object, created by the
|
|
250
|
-
`new_wake_deltas` function and filled
|
|
251
|
-
by `contribute_to_wake_deltas`
|
|
252
|
-
states_turbine: numpy.ndarray of int
|
|
253
|
-
For each state, the index of one turbine
|
|
254
|
-
for which to evaluate the wake deltas.
|
|
255
|
-
Shape: (n_states,)
|
|
256
|
-
amb_res: dict, optional
|
|
257
|
-
Ambient states results. Keys: var str, values:
|
|
258
|
-
numpy.ndarray of shape (n_states, n_points)
|
|
259
|
-
|
|
260
|
-
"""
|
|
261
|
-
rweights = algo.rotor_model.from_data_or_store(FC.RWEIGHTS, algo, mdata)
|
|
262
|
-
rpoints = algo.rotor_model.from_data_or_store(FC.RPOINTS, algo, mdata)
|
|
263
|
-
n_states, n_turbines, n_rpoints, __ = rpoints.shape
|
|
264
|
-
|
|
265
|
-
amb_res_in = amb_res is not None
|
|
266
|
-
if not amb_res_in:
|
|
267
|
-
amb_res = algo.rotor_model.from_data_or_store(
|
|
268
|
-
FC.AMB_RPOINT_RESULTS, algo, mdata
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
wweights = self.grotor.rotor_point_weights()
|
|
272
|
-
n_wpoints = self.grotor.n_rotor_points()
|
|
273
|
-
n_states, n_turbines, n_rpoints, __ = rpoints.shape
|
|
274
|
-
st_sel = (np.arange(n_states), states_turbine)
|
|
275
|
-
|
|
276
|
-
uv = None
|
|
277
|
-
if (FV.WS in amb_res and FV.WD not in amb_res) or (
|
|
278
|
-
FV.WS not in amb_res and FV.WD in amb_res
|
|
279
|
-
):
|
|
280
|
-
raise KeyError(
|
|
281
|
-
f"Model '{self.name}': Missing one of the variables '{FV.WS}', '{FV.WD}' in ambient rotor results: {list(amb_res.keys())}"
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
elif FV.WD in amb_res and np.any(
|
|
285
|
-
np.min(amb_res[FV.WD], axis=2) != np.max(amb_res[FV.WD], axis=2)
|
|
286
|
-
):
|
|
287
|
-
wd = amb_res[FV.WD].reshape(n_states, n_turbines, n_rpoints)[st_sel]
|
|
288
|
-
ws = amb_res[FV.WS].reshape(n_states, n_turbines, n_rpoints)[st_sel]
|
|
289
|
-
uv = wd2uv(wd, ws, axis=-1)
|
|
290
|
-
uv = np.einsum("spd,p->sd", uv, rweights)
|
|
291
|
-
del ws, wd
|
|
292
|
-
|
|
293
|
-
wres = {}
|
|
294
|
-
for v, ares in amb_res.items():
|
|
295
|
-
if v == FV.WS and uv is not None:
|
|
296
|
-
wres[v] = np.linalg.norm(uv, axis=-1)
|
|
297
|
-
elif v == FV.WD and uv is not None:
|
|
298
|
-
wres[v] = uv2wd(uv, axis=-1)
|
|
299
|
-
else:
|
|
300
|
-
wres[v] = ares.reshape(n_states, n_turbines, n_rpoints)[st_sel]
|
|
301
|
-
wres[v] = np.einsum("sp,p->s", wres[v], rweights)
|
|
302
|
-
wres[v] = wres[v][:, None]
|
|
303
|
-
del uv
|
|
304
|
-
|
|
305
|
-
wdel = {}
|
|
306
|
-
for v, d in wake_deltas.items():
|
|
307
|
-
wdel[v] = d.reshape(n_states, n_turbines, n_wpoints)[st_sel]
|
|
308
|
-
for w in self.wake_models:
|
|
309
|
-
w.finalize_wake_deltas(algo, mdata, fdata, pdata, wres, wdel)
|
|
310
|
-
for v in wdel.keys():
|
|
311
|
-
wdel[v] = np.einsum("sp,p->s", wdel[v], wweights)[:, None]
|
|
312
|
-
|
|
313
|
-
for v in wres.keys():
|
|
314
|
-
if v in wake_deltas:
|
|
315
|
-
wres[v] += wdel[v]
|
|
316
|
-
if amb_res_in:
|
|
317
|
-
amb_res[v][st_sel] = wres[v]
|
|
318
|
-
wres[v] = wres[v][:, None]
|
|
319
|
-
|
|
320
|
-
self.rotor_model.eval_rpoint_results(
|
|
321
|
-
algo, mdata, fdata, wres, np.array([1.0]), states_turbine=states_turbine
|
|
322
|
-
)
|
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
from copy import deepcopy
|
|
2
|
-
|
|
3
|
-
from foxes.core import PartialWakesModel
|
|
4
|
-
from foxes.models.partial_wakes.rotor_points import RotorPoints
|
|
5
|
-
from foxes.models.partial_wakes.top_hat import PartialTopHat
|
|
6
|
-
from foxes.models.partial_wakes.axiwake import PartialAxiwake
|
|
7
|
-
from foxes.models.partial_wakes.distsliced import PartialDistSlicedWake
|
|
8
|
-
from foxes.models.wake_models.top_hat import TopHatWakeModel
|
|
9
|
-
from foxes.models.wake_models.dist_sliced import DistSlicedWakeModel
|
|
10
|
-
from foxes.models.wake_models.axisymmetric import AxisymmetricWakeModel
|
|
11
|
-
import foxes.constants as FC
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class Mapped(PartialWakesModel):
|
|
15
|
-
"""
|
|
16
|
-
Partial wake models depending on the wake model (type).
|
|
17
|
-
|
|
18
|
-
This is required if more than one wake models are
|
|
19
|
-
used and different partial wake models should be invoked.
|
|
20
|
-
|
|
21
|
-
Attributes
|
|
22
|
-
----------
|
|
23
|
-
wname2pwake: dict
|
|
24
|
-
Mapping from wake model name to partial wakes.
|
|
25
|
-
Key: model name str, value: Tuple of length 2,
|
|
26
|
-
(Partial wake class name, parameter dict)
|
|
27
|
-
wtype2pwake: dict
|
|
28
|
-
Mapping from wake model class name to partial wakes.
|
|
29
|
-
Key: wake model class name str, value: Tuple of length 2,
|
|
30
|
-
(Partial wake class name, parameter dict)
|
|
31
|
-
|
|
32
|
-
:group: models.partial_wakes
|
|
33
|
-
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
def __init__(
|
|
37
|
-
self, wname2pwake={}, wtype2pwake=None, wake_models=None, wake_frame=None
|
|
38
|
-
):
|
|
39
|
-
"""
|
|
40
|
-
Constructor.
|
|
41
|
-
|
|
42
|
-
Parameters
|
|
43
|
-
----------
|
|
44
|
-
wname2pwake: dict, optional
|
|
45
|
-
Mapping from wake model name to partial wakes.
|
|
46
|
-
Key: model name str, value: Tuple of length 2,
|
|
47
|
-
(Partial wake class name, parameter dict)
|
|
48
|
-
wtype2pwake: dict, optional
|
|
49
|
-
Mapping from wake model class name to partial wakes.
|
|
50
|
-
Key: wake model class name str, value: Tuple of length 2,
|
|
51
|
-
(Partial wake class name, parameter dict)
|
|
52
|
-
wake_models: list of foxes.core.WakeModel, optional
|
|
53
|
-
The wake models, default are the ones from the algorithm
|
|
54
|
-
wake_frame: foxes.core.WakeFrame, optional
|
|
55
|
-
The wake frame, default is the one from the algorithm
|
|
56
|
-
|
|
57
|
-
"""
|
|
58
|
-
super().__init__(wake_models, wake_frame)
|
|
59
|
-
|
|
60
|
-
self.wname2pwake = wname2pwake
|
|
61
|
-
|
|
62
|
-
if wtype2pwake is None:
|
|
63
|
-
self.wtype2pwake = {
|
|
64
|
-
TopHatWakeModel: (PartialTopHat.__name__, {}),
|
|
65
|
-
AxisymmetricWakeModel: (PartialAxiwake.__name__, {"n": 6}),
|
|
66
|
-
DistSlicedWakeModel: (PartialDistSlicedWake.__name__, {"n": 9}),
|
|
67
|
-
}
|
|
68
|
-
else:
|
|
69
|
-
self.wtype2pwake = wtype2pwake
|
|
70
|
-
|
|
71
|
-
self._pwakes = None
|
|
72
|
-
|
|
73
|
-
def initialize(self, algo, verbosity=0):
|
|
74
|
-
"""
|
|
75
|
-
Initializes the model.
|
|
76
|
-
|
|
77
|
-
Parameters
|
|
78
|
-
----------
|
|
79
|
-
algo: foxes.core.Algorithm
|
|
80
|
-
The calculation algorithm
|
|
81
|
-
verbosity: int
|
|
82
|
-
The verbosity level, 0 = silent
|
|
83
|
-
|
|
84
|
-
"""
|
|
85
|
-
self.wake_models = algo.wake_models if self._wmodels is None else self._wmodels
|
|
86
|
-
self.wake_frame = algo.wake_frame if self._wframe is None else self._wframe
|
|
87
|
-
|
|
88
|
-
pws = {}
|
|
89
|
-
for w in self.wake_models:
|
|
90
|
-
pdat = None
|
|
91
|
-
if w.name in self.wname2pwake:
|
|
92
|
-
pdat = deepcopy(self.wname2pwake[w.name])
|
|
93
|
-
|
|
94
|
-
if pdat is None:
|
|
95
|
-
for pwcls, tdat in self.wtype2pwake.items():
|
|
96
|
-
if isinstance(w, pwcls):
|
|
97
|
-
pdat = deepcopy(tdat)
|
|
98
|
-
break
|
|
99
|
-
|
|
100
|
-
if pdat is None:
|
|
101
|
-
pdat = (RotorPoints.__name__, {})
|
|
102
|
-
|
|
103
|
-
pname = pdat[0]
|
|
104
|
-
if pname not in pws:
|
|
105
|
-
pws[pname] = pdat[1]
|
|
106
|
-
pws[pname]["wake_models"] = []
|
|
107
|
-
pws[pname]["wake_frame"] = self.wake_frame
|
|
108
|
-
pws[pname]["wake_models"].append(w)
|
|
109
|
-
|
|
110
|
-
self._pwakes = []
|
|
111
|
-
for pname, pars in pws.items():
|
|
112
|
-
if verbosity:
|
|
113
|
-
print(
|
|
114
|
-
f"Partial wakes '{self.name}': Applying {pname} to {[w.name for w in pars['wake_models']]}"
|
|
115
|
-
)
|
|
116
|
-
self._pwakes.append(PartialWakesModel.new(pname, **pars))
|
|
117
|
-
|
|
118
|
-
super().initialize(algo, verbosity)
|
|
119
|
-
|
|
120
|
-
def sub_models(self):
|
|
121
|
-
"""
|
|
122
|
-
List of all sub-models
|
|
123
|
-
|
|
124
|
-
Returns
|
|
125
|
-
-------
|
|
126
|
-
smdls: list of foxes.core.Model
|
|
127
|
-
Names of all sub models
|
|
128
|
-
|
|
129
|
-
"""
|
|
130
|
-
return super().sub_models() + self._pwakes
|
|
131
|
-
|
|
132
|
-
def new_wake_deltas(self, algo, mdata, fdata):
|
|
133
|
-
"""
|
|
134
|
-
Creates new initial wake deltas, filled
|
|
135
|
-
with zeros.
|
|
136
|
-
|
|
137
|
-
Parameters
|
|
138
|
-
----------
|
|
139
|
-
algo: foxes.core.Algorithm
|
|
140
|
-
The calculation algorithm
|
|
141
|
-
mdata: foxes.core.Data
|
|
142
|
-
The model data
|
|
143
|
-
fdata: foxes.core.Data
|
|
144
|
-
The farm data
|
|
145
|
-
|
|
146
|
-
Returns
|
|
147
|
-
-------
|
|
148
|
-
wake_deltas: dict
|
|
149
|
-
Keys: Variable name str, values: any
|
|
150
|
-
pdata: foxes.core.Data
|
|
151
|
-
The evaluation point data
|
|
152
|
-
|
|
153
|
-
"""
|
|
154
|
-
wdeltas = []
|
|
155
|
-
pdatas = []
|
|
156
|
-
for pw in self._pwakes:
|
|
157
|
-
w, p = pw.new_wake_deltas(algo, mdata, fdata)
|
|
158
|
-
wdeltas.append(w)
|
|
159
|
-
pdatas.append(p)
|
|
160
|
-
|
|
161
|
-
return wdeltas, pdatas
|
|
162
|
-
|
|
163
|
-
def contribute_to_wake_deltas(
|
|
164
|
-
self,
|
|
165
|
-
algo,
|
|
166
|
-
mdata,
|
|
167
|
-
fdata,
|
|
168
|
-
pdata,
|
|
169
|
-
states_source_turbine,
|
|
170
|
-
wake_deltas,
|
|
171
|
-
):
|
|
172
|
-
"""
|
|
173
|
-
Modifies wake deltas by contributions from the
|
|
174
|
-
specified wake source turbines.
|
|
175
|
-
|
|
176
|
-
Parameters
|
|
177
|
-
----------
|
|
178
|
-
algo: foxes.core.Algorithm
|
|
179
|
-
The calculation algorithm
|
|
180
|
-
mdata: foxes.core.Data
|
|
181
|
-
The model data
|
|
182
|
-
fdata: foxes.core.Data
|
|
183
|
-
The farm data
|
|
184
|
-
pdata: foxes.core.Data
|
|
185
|
-
The evaluation point data
|
|
186
|
-
states_source_turbine: numpy.ndarray of int
|
|
187
|
-
For each state, one turbine index corresponding
|
|
188
|
-
to the wake causing turbine. Shape: (n_states,)
|
|
189
|
-
wake_deltas: Any
|
|
190
|
-
The wake deltas object created by the
|
|
191
|
-
`new_wake_deltas` function
|
|
192
|
-
|
|
193
|
-
"""
|
|
194
|
-
for pwi, pw in enumerate(self._pwakes):
|
|
195
|
-
pw.contribute_to_wake_deltas(
|
|
196
|
-
algo, mdata, fdata, pdata[pwi], states_source_turbine, wake_deltas[pwi]
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
def evaluate_results(
|
|
200
|
-
self,
|
|
201
|
-
algo,
|
|
202
|
-
mdata,
|
|
203
|
-
fdata,
|
|
204
|
-
pdata,
|
|
205
|
-
wake_deltas,
|
|
206
|
-
states_turbine,
|
|
207
|
-
amb_res=None,
|
|
208
|
-
):
|
|
209
|
-
"""
|
|
210
|
-
Updates the farm data according to the wake
|
|
211
|
-
deltas.
|
|
212
|
-
|
|
213
|
-
Parameters
|
|
214
|
-
----------
|
|
215
|
-
algo: foxes.core.Algorithm
|
|
216
|
-
The calculation algorithm
|
|
217
|
-
mdata: foxes.core.Data
|
|
218
|
-
The model data
|
|
219
|
-
fdata: foxes.core.Data
|
|
220
|
-
The farm data
|
|
221
|
-
Modified in-place by this function
|
|
222
|
-
pdata: foxes.core.Data
|
|
223
|
-
The evaluation point data
|
|
224
|
-
wake_deltas: Any
|
|
225
|
-
The wake deltas object, created by the
|
|
226
|
-
`new_wake_deltas` function and filled
|
|
227
|
-
by `contribute_to_wake_deltas`
|
|
228
|
-
states_turbine: numpy.ndarray of int
|
|
229
|
-
For each state, the index of one turbine
|
|
230
|
-
for which to evaluate the wake deltas.
|
|
231
|
-
Shape: (n_states,)
|
|
232
|
-
amb_res: dict, optional
|
|
233
|
-
Ambient states results. Keys: var str, values:
|
|
234
|
-
numpy.ndarray of shape (n_states, n_points)
|
|
235
|
-
|
|
236
|
-
"""
|
|
237
|
-
if amb_res is None:
|
|
238
|
-
ares = algo.rotor_model.from_data_or_store(
|
|
239
|
-
FC.AMB_RPOINT_RESULTS, algo, mdata
|
|
240
|
-
).copy()
|
|
241
|
-
amb_res = {v: d.copy() for v, d in ares.items()}
|
|
242
|
-
|
|
243
|
-
for pwi, pw in enumerate(self._pwakes):
|
|
244
|
-
pw.evaluate_results(
|
|
245
|
-
algo,
|
|
246
|
-
mdata,
|
|
247
|
-
fdata,
|
|
248
|
-
pdata[pwi],
|
|
249
|
-
wake_deltas[pwi],
|
|
250
|
-
states_turbine,
|
|
251
|
-
amb_res=amb_res,
|
|
252
|
-
)
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
from foxes.core import TurbineModel
|
|
4
|
-
import foxes.variables as FV
|
|
5
|
-
import foxes.constants as FC
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class SetXYHD(TurbineModel):
|
|
9
|
-
"""
|
|
10
|
-
Sets basic turbine data, from
|
|
11
|
-
turbine object to farm data.
|
|
12
|
-
|
|
13
|
-
Attributes
|
|
14
|
-
----------
|
|
15
|
-
set_XY: bool
|
|
16
|
-
Flag for (x,y) data
|
|
17
|
-
set_H: bool
|
|
18
|
-
Flag for height data
|
|
19
|
-
set_D: bool
|
|
20
|
-
Flag for rotor diameter data
|
|
21
|
-
|
|
22
|
-
:group: models.turbine_models
|
|
23
|
-
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
def __init__(self, set_XY=True, set_H=True, set_D=True):
|
|
27
|
-
"""
|
|
28
|
-
Constructor.
|
|
29
|
-
|
|
30
|
-
Parameters
|
|
31
|
-
----------
|
|
32
|
-
set_XY: bool
|
|
33
|
-
Flag for (x,y) data
|
|
34
|
-
set_H: bool
|
|
35
|
-
Flag for height data
|
|
36
|
-
set_D: bool
|
|
37
|
-
Flag for rotor diameter data
|
|
38
|
-
|
|
39
|
-
"""
|
|
40
|
-
super().__init__()
|
|
41
|
-
|
|
42
|
-
self.set_XY = set_XY
|
|
43
|
-
self.set_H = set_H
|
|
44
|
-
self.set_D = set_D
|
|
45
|
-
|
|
46
|
-
def output_farm_vars(self, algo):
|
|
47
|
-
"""
|
|
48
|
-
The variables which are being modified by the model.
|
|
49
|
-
|
|
50
|
-
Parameters
|
|
51
|
-
----------
|
|
52
|
-
algo: foxes.core.Algorithm
|
|
53
|
-
The calculation algorithm
|
|
54
|
-
|
|
55
|
-
Returns
|
|
56
|
-
-------
|
|
57
|
-
output_vars: list of str
|
|
58
|
-
The output variable names
|
|
59
|
-
|
|
60
|
-
"""
|
|
61
|
-
ovars = []
|
|
62
|
-
if self.set_XY:
|
|
63
|
-
ovars.append(FV.X)
|
|
64
|
-
ovars.append(FV.Y)
|
|
65
|
-
if self.set_H:
|
|
66
|
-
ovars.append(FV.H)
|
|
67
|
-
if self.set_D:
|
|
68
|
-
ovars.append(FV.D)
|
|
69
|
-
return ovars
|
|
70
|
-
|
|
71
|
-
def calculate(self, algo, mdata, fdata, st_sel):
|
|
72
|
-
""" "
|
|
73
|
-
The main model calculation.
|
|
74
|
-
|
|
75
|
-
This function is executed on a single chunk of data,
|
|
76
|
-
all computations should be based on numpy arrays.
|
|
77
|
-
|
|
78
|
-
Parameters
|
|
79
|
-
----------
|
|
80
|
-
algo: foxes.core.Algorithm
|
|
81
|
-
The calculation algorithm
|
|
82
|
-
mdata: foxes.core.Data
|
|
83
|
-
The model data
|
|
84
|
-
fdata: foxes.core.Data
|
|
85
|
-
The farm data
|
|
86
|
-
st_sel: numpy.ndarray of bool
|
|
87
|
-
The state-turbine selection,
|
|
88
|
-
shape: (n_states, n_turbines)
|
|
89
|
-
|
|
90
|
-
Returns
|
|
91
|
-
-------
|
|
92
|
-
results: dict
|
|
93
|
-
The resulting data, keys: output variable str.
|
|
94
|
-
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
95
|
-
|
|
96
|
-
"""
|
|
97
|
-
n_states = mdata.n_states
|
|
98
|
-
n_turbines = algo.n_turbines
|
|
99
|
-
|
|
100
|
-
if self.set_XY or self.set_H:
|
|
101
|
-
fdata[FV.TXYH] = np.full((n_states, n_turbines, 3), np.nan, dtype=FC.DTYPE)
|
|
102
|
-
if self.set_XY:
|
|
103
|
-
fdata[FV.X] = fdata[FV.TXYH][..., 0]
|
|
104
|
-
fdata[FV.Y] = fdata[FV.TXYH][..., 1]
|
|
105
|
-
if self.set_H:
|
|
106
|
-
fdata[FV.H] = fdata[FV.TXYH][..., 2]
|
|
107
|
-
|
|
108
|
-
for ti in range(n_turbines):
|
|
109
|
-
ssel = st_sel[:, ti]
|
|
110
|
-
if np.any(ssel):
|
|
111
|
-
if np.all(ssel):
|
|
112
|
-
ssel = np.s_[:]
|
|
113
|
-
|
|
114
|
-
if self.set_XY:
|
|
115
|
-
fdata[FV.X][ssel, ti] = algo.farm.turbines[ti].xy[0]
|
|
116
|
-
fdata[FV.Y][ssel, ti] = algo.farm.turbines[ti].xy[1]
|
|
117
|
-
|
|
118
|
-
if self.set_H:
|
|
119
|
-
H = algo.farm.turbines[ti].H
|
|
120
|
-
if H is None:
|
|
121
|
-
H = algo.farm_controller.turbine_types[ti].H
|
|
122
|
-
fdata[FV.H][ssel, ti] = H
|
|
123
|
-
|
|
124
|
-
if self.set_D:
|
|
125
|
-
D = algo.farm.turbines[ti].D
|
|
126
|
-
if D is None:
|
|
127
|
-
D = algo.farm_controller.turbine_types[ti].D
|
|
128
|
-
fdata[FV.D][ssel, ti] = D
|
|
129
|
-
|
|
130
|
-
return {v: fdata[v] for v in self.output_farm_vars(algo)}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|