foxes 0.8.2__py3-none-any.whl → 1.1.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.
- docs/source/conf.py +353 -0
- examples/abl_states/run.py +160 -0
- examples/compare_rotors_pwakes/run.py +217 -0
- examples/compare_wakes/run.py +241 -0
- examples/dyn_wakes/run.py +311 -0
- examples/field_data_nc/run.py +121 -0
- examples/induction/run.py +201 -0
- examples/multi_height/run.py +113 -0
- examples/power_mask/run.py +249 -0
- examples/random_timeseries/run.py +210 -0
- examples/scan_row/run.py +193 -0
- examples/sector_management/run.py +162 -0
- examples/sequential/run.py +209 -0
- examples/single_state/run.py +201 -0
- examples/states_lookup_table/run.py +137 -0
- examples/streamline_wakes/run.py +138 -0
- examples/tab_file/run.py +142 -0
- examples/timelines/run.py +267 -0
- examples/timeseries/run.py +190 -0
- examples/timeseries_slurm/run.py +185 -0
- examples/wind_rose/run.py +141 -0
- examples/windio/run.py +29 -0
- examples/yawed_wake/run.py +196 -0
- foxes/__init__.py +4 -8
- foxes/algorithms/__init__.py +1 -1
- foxes/algorithms/downwind/downwind.py +247 -111
- foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
- foxes/algorithms/downwind/models/init_farm_data.py +2 -2
- foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
- foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
- foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
- foxes/algorithms/iterative/iterative.py +74 -34
- foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
- foxes/algorithms/iterative/models/urelax.py +3 -3
- foxes/algorithms/sequential/models/plugin.py +5 -5
- foxes/algorithms/sequential/models/seq_state.py +1 -1
- foxes/algorithms/sequential/sequential.py +126 -255
- foxes/constants.py +22 -7
- foxes/core/__init__.py +1 -0
- foxes/core/algorithm.py +632 -147
- foxes/core/data.py +252 -20
- foxes/core/data_calc_model.py +15 -291
- foxes/core/engine.py +640 -0
- foxes/core/farm_controller.py +38 -10
- foxes/core/farm_data_model.py +16 -1
- foxes/core/ground_model.py +2 -2
- foxes/core/model.py +249 -182
- foxes/core/partial_wakes_model.py +1 -1
- foxes/core/point_data_model.py +17 -2
- foxes/core/rotor_model.py +27 -21
- foxes/core/states.py +17 -1
- foxes/core/turbine_type.py +28 -0
- foxes/core/wake_frame.py +30 -34
- foxes/core/wake_model.py +5 -5
- foxes/core/wake_superposition.py +1 -1
- foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
- foxes/engines/__init__.py +17 -0
- foxes/engines/dask.py +982 -0
- foxes/engines/default.py +75 -0
- foxes/engines/futures.py +72 -0
- foxes/engines/mpi.py +38 -0
- foxes/engines/multiprocess.py +71 -0
- foxes/engines/numpy.py +167 -0
- foxes/engines/pool.py +249 -0
- foxes/engines/ray.py +79 -0
- foxes/engines/single.py +141 -0
- foxes/input/farm_layout/__init__.py +1 -0
- foxes/input/farm_layout/from_csv.py +4 -0
- foxes/input/farm_layout/from_json.py +2 -2
- foxes/input/farm_layout/grid.py +2 -2
- foxes/input/farm_layout/ring.py +65 -0
- foxes/input/farm_layout/row.py +2 -2
- foxes/input/states/__init__.py +7 -0
- foxes/input/states/create/random_abl_states.py +1 -1
- foxes/input/states/field_data_nc.py +158 -33
- foxes/input/states/multi_height.py +128 -14
- foxes/input/states/one_point_flow.py +577 -0
- foxes/input/states/scan_ws.py +74 -3
- foxes/input/states/single.py +1 -1
- foxes/input/states/slice_data_nc.py +681 -0
- foxes/input/states/states_table.py +204 -35
- foxes/input/windio/__init__.py +2 -2
- foxes/input/windio/get_states.py +44 -23
- foxes/input/windio/read_attributes.py +48 -17
- foxes/input/windio/read_farm.py +116 -102
- foxes/input/windio/read_fields.py +16 -6
- foxes/input/windio/read_outputs.py +71 -24
- foxes/input/windio/runner.py +31 -17
- foxes/input/windio/windio.py +41 -23
- foxes/models/farm_models/turbine2farm.py +1 -1
- foxes/models/ground_models/wake_mirror.py +10 -6
- foxes/models/model_book.py +58 -20
- foxes/models/partial_wakes/axiwake.py +3 -3
- foxes/models/partial_wakes/rotor_points.py +3 -3
- foxes/models/partial_wakes/top_hat.py +2 -2
- foxes/models/point_models/set_uniform_data.py +1 -1
- foxes/models/point_models/tke2ti.py +1 -1
- foxes/models/point_models/wake_deltas.py +1 -1
- foxes/models/rotor_models/centre.py +4 -0
- foxes/models/rotor_models/grid.py +24 -25
- foxes/models/rotor_models/levels.py +4 -5
- foxes/models/turbine_models/calculator.py +4 -6
- foxes/models/turbine_models/kTI_model.py +22 -6
- foxes/models/turbine_models/lookup_table.py +30 -4
- foxes/models/turbine_models/rotor_centre_calc.py +4 -3
- foxes/models/turbine_models/set_farm_vars.py +103 -34
- foxes/models/turbine_types/PCt_file.py +27 -3
- foxes/models/turbine_types/PCt_from_two.py +27 -3
- foxes/models/turbine_types/TBL_file.py +80 -0
- foxes/models/turbine_types/__init__.py +2 -0
- foxes/models/turbine_types/lookup.py +316 -0
- foxes/models/turbine_types/null_type.py +51 -1
- foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
- foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
- foxes/models/vertical_profiles/__init__.py +1 -1
- foxes/models/vertical_profiles/data_profile.py +1 -1
- foxes/models/wake_frames/__init__.py +1 -0
- foxes/models/wake_frames/dynamic_wakes.py +424 -0
- foxes/models/wake_frames/farm_order.py +25 -5
- foxes/models/wake_frames/rotor_wd.py +6 -4
- foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
- foxes/models/wake_frames/streamlines.py +21 -22
- foxes/models/wake_frames/timelines.py +330 -129
- foxes/models/wake_frames/yawed_wakes.py +7 -4
- foxes/models/wake_models/dist_sliced.py +2 -4
- foxes/models/wake_models/induction/rankine_half_body.py +5 -5
- foxes/models/wake_models/induction/rathmann.py +78 -24
- foxes/models/wake_models/induction/self_similar.py +78 -28
- foxes/models/wake_models/induction/vortex_sheet.py +86 -48
- foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
- foxes/models/wake_models/ti/iec_ti.py +40 -21
- foxes/models/wake_models/top_hat.py +1 -1
- foxes/models/wake_models/wind/bastankhah14.py +8 -6
- foxes/models/wake_models/wind/bastankhah16.py +17 -16
- foxes/models/wake_models/wind/jensen.py +4 -3
- foxes/models/wake_models/wind/turbopark.py +16 -13
- foxes/models/wake_superpositions/ti_linear.py +1 -1
- foxes/models/wake_superpositions/ti_max.py +1 -1
- foxes/models/wake_superpositions/ti_pow.py +1 -1
- foxes/models/wake_superpositions/ti_quadratic.py +1 -1
- foxes/models/wake_superpositions/ws_linear.py +8 -7
- foxes/models/wake_superpositions/ws_max.py +8 -7
- foxes/models/wake_superpositions/ws_pow.py +8 -7
- foxes/models/wake_superpositions/ws_product.py +5 -5
- foxes/models/wake_superpositions/ws_quadratic.py +8 -7
- foxes/output/__init__.py +4 -1
- foxes/output/farm_layout.py +16 -12
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/flow_plots_2d/__init__.py +0 -1
- foxes/output/flow_plots_2d/flow_plots.py +70 -30
- foxes/output/grids.py +92 -22
- foxes/output/results_writer.py +2 -2
- foxes/output/rose_plot.py +3 -3
- foxes/output/seq_plugins/__init__.py +2 -0
- foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
- foxes/output/slice_data.py +131 -111
- foxes/output/state_turbine_map.py +19 -14
- foxes/output/state_turbine_table.py +19 -19
- foxes/utils/__init__.py +1 -1
- foxes/utils/abl/neutral.py +2 -2
- foxes/utils/abl/stable.py +2 -2
- foxes/utils/abl/unstable.py +2 -2
- foxes/utils/data_book.py +1 -1
- foxes/utils/dev_utils.py +42 -0
- foxes/utils/dict.py +24 -1
- foxes/utils/exec_python.py +1 -1
- foxes/utils/factory.py +176 -53
- foxes/utils/geom2d/circle.py +1 -1
- foxes/utils/geom2d/polygon.py +1 -1
- foxes/utils/geopandas_utils.py +2 -2
- foxes/utils/load.py +2 -2
- foxes/utils/pandas_helpers.py +3 -2
- foxes/utils/wind_dir.py +0 -2
- foxes/utils/xarray_utils.py +24 -14
- foxes/variables.py +39 -2
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
- foxes-1.1.0.2.dist-info/RECORD +309 -0
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
- foxes-1.1.0.2.dist-info/top_level.txt +4 -0
- tests/0_consistency/iterative/test_iterative.py +92 -0
- tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
- tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
- tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
- tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
- tests/3_examples/test_examples.py +34 -0
- foxes/VERSION +0 -1
- foxes/output/flow_plots_2d.py +0 -0
- foxes/utils/geopandas_helpers.py +0 -294
- foxes/utils/runners/__init__.py +0 -1
- foxes/utils/runners/runners.py +0 -280
- foxes-0.8.2.dist-info/RECORD +0 -247
- foxes-0.8.2.dist-info/top_level.txt +0 -1
- foxes-0.8.2.dist-info/zip-safe +0 -1
- {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/LICENSE +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
from scipy.spatial.distance import cdist
|
|
3
3
|
|
|
4
|
-
from foxes.core import WakeFrame
|
|
5
4
|
from foxes.utils import wd2uv
|
|
6
5
|
from foxes.core.data import TData
|
|
7
6
|
import foxes.variables as FV
|
|
8
7
|
import foxes.constants as FC
|
|
9
|
-
from foxes.algorithms import Sequential
|
|
8
|
+
from foxes.algorithms.sequential import Sequential
|
|
10
9
|
|
|
10
|
+
from .farm_order import FarmOrder
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
class SeqDynamicWakes(FarmOrder):
|
|
13
14
|
"""
|
|
14
15
|
Dynamic wakes for the sequential algorithm.
|
|
15
16
|
|
|
@@ -26,7 +27,7 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
26
27
|
|
|
27
28
|
"""
|
|
28
29
|
|
|
29
|
-
def __init__(self, cl_ipars={}, dt_min=None):
|
|
30
|
+
def __init__(self, cl_ipars={}, dt_min=None, **kwargs):
|
|
30
31
|
"""
|
|
31
32
|
Constructor.
|
|
32
33
|
|
|
@@ -38,9 +39,11 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
38
39
|
dt_min: float, optional
|
|
39
40
|
The delta t value in minutes,
|
|
40
41
|
if not from timeseries data
|
|
42
|
+
kwargs: dict, optional
|
|
43
|
+
Additional parameters for the base class
|
|
41
44
|
|
|
42
45
|
"""
|
|
43
|
-
super().__init__()
|
|
46
|
+
super().__init__(**kwargs)
|
|
44
47
|
self.cl_ipars = cl_ipars
|
|
45
48
|
self.dt_min = dt_min
|
|
46
49
|
|
|
@@ -88,10 +91,12 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
88
91
|
# init wake traces data:
|
|
89
92
|
self._traces_p = np.zeros((algo.n_states, algo.n_turbines, 3), dtype=FC.DTYPE)
|
|
90
93
|
self._traces_v = np.zeros((algo.n_states, algo.n_turbines, 3), dtype=FC.DTYPE)
|
|
91
|
-
self._traces_l = np.
|
|
94
|
+
self._traces_l = np.full(
|
|
95
|
+
(algo.n_states, algo.n_turbines), np.nan, dtype=FC.DTYPE
|
|
96
|
+
)
|
|
92
97
|
|
|
93
98
|
def calc_order(self, algo, mdata, fdata):
|
|
94
|
-
"""
|
|
99
|
+
"""
|
|
95
100
|
Calculates the order of turbine evaluation.
|
|
96
101
|
|
|
97
102
|
This function is executed on a single chunk of data,
|
|
@@ -112,26 +117,7 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
112
117
|
The turbine order, shape: (n_states, n_turbines)
|
|
113
118
|
|
|
114
119
|
"""
|
|
115
|
-
|
|
116
|
-
n_states = fdata.n_states
|
|
117
|
-
n_turbines = algo.n_turbines
|
|
118
|
-
tdata = TData.from_points(points=fdata[FV.TXYH])
|
|
119
|
-
|
|
120
|
-
# calculate streamline x coordinates for turbines rotor centre points:
|
|
121
|
-
# n_states, n_turbines_source, n_turbines_target
|
|
122
|
-
coosx = np.zeros((n_states, n_turbines, n_turbines), dtype=FC.DTYPE)
|
|
123
|
-
for ti in range(n_turbines):
|
|
124
|
-
coosx[:, ti, :] = self.get_wake_coos(algo, mdata, fdata, tdata, ti)[
|
|
125
|
-
:, :, 0, 0
|
|
126
|
-
]
|
|
127
|
-
|
|
128
|
-
# derive turbine order:
|
|
129
|
-
# TODO: Remove loop over states
|
|
130
|
-
order = np.zeros((n_states, n_turbines), dtype=FC.ITYPE)
|
|
131
|
-
for si in range(n_states):
|
|
132
|
-
order[si] = np.lexsort(keys=coosx[si])
|
|
133
|
-
|
|
134
|
-
return order
|
|
120
|
+
return super().calc_order(algo, mdata, fdata)
|
|
135
121
|
|
|
136
122
|
def get_wake_coos(
|
|
137
123
|
self,
|
|
@@ -156,7 +142,7 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
156
142
|
The target point data
|
|
157
143
|
downwind_index: int
|
|
158
144
|
The index of the wake causing turbine
|
|
159
|
-
in the
|
|
145
|
+
in the downwind order
|
|
160
146
|
|
|
161
147
|
Returns
|
|
162
148
|
-------
|
|
@@ -174,48 +160,54 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
174
160
|
counter = algo.states.counter
|
|
175
161
|
N = counter + 1
|
|
176
162
|
|
|
177
|
-
|
|
178
|
-
self._traces_p[counter, downwind_index] = fdata[FV.TXYH][0, downwind_index]
|
|
179
|
-
self._traces_l[counter, downwind_index] = 0
|
|
180
|
-
|
|
181
|
-
# transport wakes that originate from previous time steps:
|
|
182
|
-
if counter > 0:
|
|
183
|
-
dxyz = self._traces_v[:counter, downwind_index] * self._dt[:counter, None]
|
|
184
|
-
self._traces_p[:counter, downwind_index] += dxyz
|
|
185
|
-
self._traces_l[:counter, downwind_index] += np.linalg.norm(dxyz, axis=-1)
|
|
186
|
-
|
|
187
|
-
# compute wind vectors at wake traces:
|
|
188
|
-
# TODO: dz from U_z is missing here
|
|
189
|
-
hpdata = {
|
|
190
|
-
v: np.zeros((1, N, 1), dtype=FC.DTYPE)
|
|
191
|
-
for v in algo.states.output_point_vars(algo)
|
|
192
|
-
}
|
|
193
|
-
hpdims = {v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in hpdata.keys()}
|
|
194
|
-
hpdata = TData.from_points(
|
|
195
|
-
points=self._traces_p[None, :N, downwind_index],
|
|
196
|
-
data=hpdata,
|
|
197
|
-
dims=hpdims,
|
|
198
|
-
)
|
|
199
|
-
res = algo.states.calculate(algo, mdata, fdata, hpdata)
|
|
200
|
-
self._traces_v[:N, downwind_index, :2] = wd2uv(
|
|
201
|
-
res[FV.WD][0, :, 0], res[FV.WS][0, :, 0]
|
|
202
|
-
)
|
|
203
|
-
del hpdata, hpdims, res
|
|
163
|
+
if np.isnan(self._traces_l[counter, downwind_index]):
|
|
204
164
|
|
|
205
|
-
|
|
165
|
+
# new wake starts at turbine:
|
|
166
|
+
self._traces_p[counter, downwind_index][:] = fdata[FV.TXYH][
|
|
167
|
+
0, downwind_index
|
|
168
|
+
]
|
|
169
|
+
self._traces_l[counter, downwind_index] = 0
|
|
170
|
+
|
|
171
|
+
# transport wakes that originate from previous time steps:
|
|
172
|
+
if counter > 0:
|
|
173
|
+
dxyz = self._traces_v[:counter, downwind_index] * self._dt[counter - 1]
|
|
174
|
+
self._traces_p[:counter, downwind_index] += dxyz
|
|
175
|
+
self._traces_l[:counter, downwind_index] += np.linalg.norm(
|
|
176
|
+
dxyz, axis=-1
|
|
177
|
+
)
|
|
178
|
+
del dxyz
|
|
179
|
+
|
|
180
|
+
# compute wind vectors at wake traces:
|
|
181
|
+
# TODO: dz from U_z is missing here
|
|
182
|
+
hpdata = TData.from_points(points=self._traces_p[None, :N, downwind_index])
|
|
183
|
+
res = algo.states.calculate(algo, mdata, fdata, hpdata)
|
|
184
|
+
self._traces_v[:N, downwind_index, :2] = wd2uv(
|
|
185
|
+
res[FV.WD][0, :, 0], res[FV.WS][0, :, 0]
|
|
186
|
+
)
|
|
187
|
+
del hpdata, res
|
|
188
|
+
|
|
189
|
+
# find nearest wake point:
|
|
206
190
|
dists = cdist(points[0], self._traces_p[:N, downwind_index])
|
|
207
191
|
tri = np.argmin(dists, axis=1)
|
|
208
192
|
del dists
|
|
193
|
+
|
|
194
|
+
# project:
|
|
209
195
|
wcoos = np.full((n_states, n_points, 3), 1e20, dtype=FC.DTYPE)
|
|
210
|
-
wcoos[0, :, 2] = points[0, :, 2] - fdata[FV.TXYH][
|
|
211
|
-
delp = points[0, :, :2] - self._traces_p[tri, downwind_index, :2]
|
|
196
|
+
wcoos[0, :, 2] = points[0, :, 2] - fdata[FV.TXYH][0, downwind_index, None, 2]
|
|
212
197
|
nx = self._traces_v[tri, downwind_index, :2]
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
)
|
|
218
|
-
|
|
198
|
+
mv = np.linalg.norm(nx, axis=-1)
|
|
199
|
+
nx /= mv[:, None]
|
|
200
|
+
delp = points[0, :, :2] - self._traces_p[tri, downwind_index, :2]
|
|
201
|
+
projx = np.einsum("pd,pd->p", delp, nx)
|
|
202
|
+
dt = self._dt[counter] if counter < len(self._dt) else self._dt[-1]
|
|
203
|
+
dx = mv * dt
|
|
204
|
+
sel = (projx > -dx) & (projx < dx)
|
|
205
|
+
if np.any(sel):
|
|
206
|
+
ny = np.concatenate([-nx[:, 1, None], nx[:, 0, None]], axis=1)
|
|
207
|
+
wcoos[0, sel, 0] = projx[sel] + self._traces_l[tri[sel], downwind_index]
|
|
208
|
+
wcoos[0, sel, 1] = np.einsum("pd,pd->p", delp, ny)[sel]
|
|
209
|
+
del ny
|
|
210
|
+
del delp, projx, mv, dx, nx, sel
|
|
219
211
|
|
|
220
212
|
# turbines that cause wake:
|
|
221
213
|
tdata[FC.STATE_SOURCE_ORDERI] = downwind_index
|
|
@@ -238,7 +230,6 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
238
230
|
tdata,
|
|
239
231
|
target,
|
|
240
232
|
states0=None,
|
|
241
|
-
upcast=False,
|
|
242
233
|
):
|
|
243
234
|
"""
|
|
244
235
|
Return data that is required for computing the
|
|
@@ -261,17 +252,12 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
261
252
|
FC.STATE_TARGET, FC.STATE_TARGET_TPOINT
|
|
262
253
|
states0: numpy.ndarray, optional
|
|
263
254
|
The states of wake creation
|
|
264
|
-
upcast: bool
|
|
265
|
-
Flag for ensuring targets dimension,
|
|
266
|
-
otherwise dimension 1 is entered
|
|
267
255
|
|
|
268
256
|
Returns
|
|
269
257
|
-------
|
|
270
258
|
data: numpy.ndarray
|
|
271
259
|
Data for wake modelling, shape:
|
|
272
260
|
(n_states, n_turbines) or (n_states, n_target)
|
|
273
|
-
dims: tuple
|
|
274
|
-
The data dimensions
|
|
275
261
|
|
|
276
262
|
"""
|
|
277
263
|
if states0 is None and FC.STATE_SOURCE_ORDERI in tdata:
|
|
@@ -287,7 +273,8 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
287
273
|
n_points = n_targets * n_tpoints
|
|
288
274
|
|
|
289
275
|
s = tdata[FC.STATES_SEL][0].reshape(n_points)
|
|
290
|
-
data = algo.
|
|
276
|
+
data = algo.farm_results_downwind[variable].to_numpy()
|
|
277
|
+
data[algo.counter] = fdata[variable][0]
|
|
291
278
|
data = data[s, downwind_index].reshape(n_states, n_targets, n_tpoints)
|
|
292
279
|
|
|
293
280
|
if target == FC.STATE_TARGET:
|
|
@@ -295,9 +282,9 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
295
282
|
data = data[:, :, 0]
|
|
296
283
|
else:
|
|
297
284
|
data = np.einsum("stp,p->st", data, tdata[FC.TWEIGHTS])
|
|
298
|
-
return data
|
|
285
|
+
return data
|
|
299
286
|
elif target == FC.STATE_TARGET_TPOINT:
|
|
300
|
-
return data
|
|
287
|
+
return data
|
|
301
288
|
else:
|
|
302
289
|
raise ValueError(
|
|
303
290
|
f"Cannot handle target '{target}', choices are {FC.STATE_TARGET}, {FC.STATE_TARGET_TPOINT}"
|
|
@@ -305,7 +292,7 @@ class SeqDynamicWakes(WakeFrame):
|
|
|
305
292
|
|
|
306
293
|
else:
|
|
307
294
|
return super().get_wake_modelling_data(
|
|
308
|
-
algo, variable, downwind_index, fdata, tdata, target, states0
|
|
295
|
+
algo, variable, downwind_index, fdata, tdata, target, states0
|
|
309
296
|
)
|
|
310
297
|
|
|
311
298
|
def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
|
|
@@ -16,8 +16,6 @@ class Streamlines2D(WakeFrame):
|
|
|
16
16
|
----------
|
|
17
17
|
step: float
|
|
18
18
|
The streamline step size in m
|
|
19
|
-
max_length: float
|
|
20
|
-
The maximal streamline length
|
|
21
19
|
cl_ipars: dict
|
|
22
20
|
Interpolation parameters for centre line
|
|
23
21
|
point interpolation
|
|
@@ -26,7 +24,7 @@ class Streamlines2D(WakeFrame):
|
|
|
26
24
|
|
|
27
25
|
"""
|
|
28
26
|
|
|
29
|
-
def __init__(self, step,
|
|
27
|
+
def __init__(self, step, max_length_km=20, cl_ipars={}, **kwargs):
|
|
30
28
|
"""
|
|
31
29
|
Constructor.
|
|
32
30
|
|
|
@@ -34,16 +32,17 @@ class Streamlines2D(WakeFrame):
|
|
|
34
32
|
----------
|
|
35
33
|
step: float
|
|
36
34
|
The streamline step size in m
|
|
37
|
-
|
|
38
|
-
The maximal streamline length
|
|
35
|
+
max_length_km: float
|
|
36
|
+
The maximal streamline length in km
|
|
39
37
|
cl_ipars: dict
|
|
40
38
|
Interpolation parameters for centre line
|
|
41
39
|
point interpolation
|
|
40
|
+
kwargs: dict, optional
|
|
41
|
+
Additional parameters for the base class
|
|
42
42
|
|
|
43
43
|
"""
|
|
44
|
-
super().__init__()
|
|
44
|
+
super().__init__(max_length_km=max_length_km, **kwargs)
|
|
45
45
|
self.step = step
|
|
46
|
-
self.max_length = max_length
|
|
47
46
|
self.cl_ipars = cl_ipars
|
|
48
47
|
|
|
49
48
|
self.DATA = self.var("DATA")
|
|
@@ -51,7 +50,9 @@ class Streamlines2D(WakeFrame):
|
|
|
51
50
|
self.SDAT = self.var("SDAT")
|
|
52
51
|
|
|
53
52
|
def __repr__(self):
|
|
54
|
-
return
|
|
53
|
+
return (
|
|
54
|
+
f"{type(self).__name__}(step={self.step}, max_length={self.max_length_km})"
|
|
55
|
+
)
|
|
55
56
|
|
|
56
57
|
def _calc_streamlines(self, algo, mdata, fdata):
|
|
57
58
|
"""
|
|
@@ -60,7 +61,7 @@ class Streamlines2D(WakeFrame):
|
|
|
60
61
|
# prepare:
|
|
61
62
|
n_states = mdata.n_states
|
|
62
63
|
n_turbines = mdata.n_turbines
|
|
63
|
-
N = int(self.
|
|
64
|
+
N = int(self.max_length_km * 1e3 / self.step)
|
|
64
65
|
|
|
65
66
|
# calc data: x, y, z, wd
|
|
66
67
|
data = np.zeros((n_states, n_turbines, N, 4), dtype=FC.DTYPE)
|
|
@@ -134,7 +135,6 @@ class Streamlines2D(WakeFrame):
|
|
|
134
135
|
Helper function, calculates streamline coordinates
|
|
135
136
|
for given points and given turbine
|
|
136
137
|
"""
|
|
137
|
-
|
|
138
138
|
# prepare:
|
|
139
139
|
n_states, n_targets, n_tpoints = targets.shape[:3]
|
|
140
140
|
n_points = n_targets * n_tpoints
|
|
@@ -151,18 +151,21 @@ class Streamlines2D(WakeFrame):
|
|
|
151
151
|
del dists, selp
|
|
152
152
|
|
|
153
153
|
# calculate coordinates:
|
|
154
|
-
coos = np.
|
|
155
|
-
nx = wd2uv(data[:, :, 3])
|
|
156
|
-
ny = np.stack([-nx[:, :, 1], nx[:, :, 0]], axis=2)
|
|
157
|
-
delta = points[:, :, :2] - data[:, :, :2]
|
|
158
|
-
coos[:, :, 0] = slen + np.einsum("spd,spd->sp", delta, nx)
|
|
159
|
-
coos[:, :, 1] = np.einsum("spd,spd->sp", delta, ny)
|
|
154
|
+
coos = np.full((n_states, n_points, 3), np.nan, dtype=FC.DTYPE)
|
|
160
155
|
coos[:, :, 2] = points[:, :, 2] - data[:, :, 2]
|
|
156
|
+
delta = points[:, :, :2] - data[:, :, :2]
|
|
157
|
+
nx = wd2uv(data[:, :, 3])
|
|
158
|
+
projx = np.einsum("spd,spd->sp", delta, nx)
|
|
159
|
+
sel = (projx > -self.step) & (projx < self.step)
|
|
160
|
+
if np.any(sel):
|
|
161
|
+
ny = np.stack([-nx[:, :, 1], nx[:, :, 0]], axis=2)
|
|
162
|
+
coos[sel, 0] = slen[sel] + projx[sel]
|
|
163
|
+
coos[sel, 1] = np.einsum("spd,spd->sp", delta, ny)[sel]
|
|
161
164
|
|
|
162
165
|
return coos.reshape(n_states, n_targets, n_tpoints, 3)
|
|
163
166
|
|
|
164
167
|
def calc_order(self, algo, mdata, fdata):
|
|
165
|
-
"""
|
|
168
|
+
"""
|
|
166
169
|
Calculates the order of turbine evaluation.
|
|
167
170
|
|
|
168
171
|
This function is executed on a single chunk of data,
|
|
@@ -227,7 +230,7 @@ class Streamlines2D(WakeFrame):
|
|
|
227
230
|
The target point data
|
|
228
231
|
downwind_index: int
|
|
229
232
|
The index of the wake causing turbine
|
|
230
|
-
in the
|
|
233
|
+
in the downwind order
|
|
231
234
|
|
|
232
235
|
Returns
|
|
233
236
|
-------
|
|
@@ -262,10 +265,6 @@ class Streamlines2D(WakeFrame):
|
|
|
262
265
|
The centreline points, shape: (n_states, n_points, 3)
|
|
263
266
|
|
|
264
267
|
"""
|
|
265
|
-
# calculate long enough streamlines:
|
|
266
|
-
xmax = np.max(x)
|
|
267
|
-
self._ensure_min_length(algo, mdata, fdata, xmax)
|
|
268
|
-
|
|
269
268
|
# get streamline points:
|
|
270
269
|
n_states, n_points = x.shape
|
|
271
270
|
data = self.get_streamline_data(algo, mdata, fdata)[:, downwind_index]
|