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
foxes/core/farm_data_model.py
CHANGED
|
@@ -66,28 +66,29 @@ class FarmDataModel(DataCalcModel):
|
|
|
66
66
|
"""
|
|
67
67
|
return (FC.STATE, FC.TURBINE)
|
|
68
68
|
|
|
69
|
-
def
|
|
69
|
+
def ensure_output_vars(self, algo, fdata):
|
|
70
70
|
"""
|
|
71
|
-
|
|
71
|
+
Ensures that the output variables are present in the farm data.
|
|
72
72
|
|
|
73
73
|
Parameters
|
|
74
74
|
----------
|
|
75
75
|
algo: foxes.core.Algorithm
|
|
76
76
|
The calculation algorithm
|
|
77
|
-
|
|
78
|
-
The model data
|
|
79
|
-
fdata: foxes.core.Data
|
|
77
|
+
fdata: foxes.core.FData
|
|
80
78
|
The farm data
|
|
81
79
|
|
|
82
80
|
"""
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
for var in self.output_farm_vars(algo):
|
|
82
|
+
if var not in fdata:
|
|
83
|
+
fdata.add(
|
|
84
|
+
var,
|
|
85
|
+
np.full(
|
|
86
|
+
(fdata.n_states, fdata.n_turbines),
|
|
87
|
+
np.nan,
|
|
88
|
+
dtype=config.dtype_double,
|
|
89
|
+
),
|
|
90
|
+
(FC.STATE, FC.TURBINE),
|
|
89
91
|
)
|
|
90
|
-
fdata.dims[v] = (FC.STATE, FC.TURBINE)
|
|
91
92
|
|
|
92
93
|
@abstractmethod
|
|
93
94
|
def calculate(self, algo, mdata, fdata):
|
|
@@ -264,7 +265,7 @@ class FarmDataModelList(FarmDataModel):
|
|
|
264
265
|
The model data
|
|
265
266
|
fdata: foxes.core.FData
|
|
266
267
|
The farm data
|
|
267
|
-
parameters: list of dict
|
|
268
|
+
parameters: list of dict
|
|
268
269
|
A list of parameter dicts, one for each model
|
|
269
270
|
|
|
270
271
|
Returns
|
|
@@ -274,6 +275,8 @@ class FarmDataModelList(FarmDataModel):
|
|
|
274
275
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
275
276
|
|
|
276
277
|
"""
|
|
278
|
+
self.ensure_output_vars(algo, fdata)
|
|
279
|
+
|
|
277
280
|
if parameters is None:
|
|
278
281
|
parameters = [{}] * len(self.models)
|
|
279
282
|
elif not isinstance(parameters, list):
|
foxes/core/ground_model.py
CHANGED
|
@@ -91,7 +91,6 @@ class GroundModel(Model):
|
|
|
91
91
|
mdata,
|
|
92
92
|
fdata,
|
|
93
93
|
tdata,
|
|
94
|
-
amb_res,
|
|
95
94
|
rpoint_weights,
|
|
96
95
|
wake_deltas,
|
|
97
96
|
wmodel,
|
|
@@ -114,11 +113,6 @@ class GroundModel(Model):
|
|
|
114
113
|
The farm data
|
|
115
114
|
tdata: foxes.core.Data
|
|
116
115
|
The target point data
|
|
117
|
-
amb_res: dict
|
|
118
|
-
The ambient results at the target points
|
|
119
|
-
of all rotors. Key: variable name, value
|
|
120
|
-
np.ndarray of shape:
|
|
121
|
-
(n_states, n_turbines, n_rotor_points)
|
|
122
116
|
rpoint_weights: numpy.ndarray
|
|
123
117
|
The rotor point weights, shape: (n_rotor_points,)
|
|
124
118
|
wake_deltas: dict
|
|
@@ -143,7 +137,6 @@ class GroundModel(Model):
|
|
|
143
137
|
mdata,
|
|
144
138
|
fdata,
|
|
145
139
|
tdata,
|
|
146
|
-
amb_res,
|
|
147
140
|
rpoint_weights,
|
|
148
141
|
wake_deltas,
|
|
149
142
|
wmodel,
|
|
@@ -226,7 +219,7 @@ class GroundModel(Model):
|
|
|
226
219
|
algo,
|
|
227
220
|
mdata,
|
|
228
221
|
fdata,
|
|
229
|
-
|
|
222
|
+
tdata,
|
|
230
223
|
wake_deltas,
|
|
231
224
|
wmodel,
|
|
232
225
|
):
|
|
@@ -243,17 +236,15 @@ class GroundModel(Model):
|
|
|
243
236
|
The model data
|
|
244
237
|
fdata: foxes.core.FData
|
|
245
238
|
The farm data
|
|
246
|
-
|
|
247
|
-
The
|
|
248
|
-
values: numpy.ndarray with shape
|
|
249
|
-
(n_states, n_targets, n_tpoints)
|
|
239
|
+
tdata: foxes.core.TData
|
|
240
|
+
The target point data
|
|
250
241
|
wake_deltas: dict
|
|
251
242
|
The wake deltas object at the selected target
|
|
252
243
|
turbines. Key: variable str, value: numpy.ndarray
|
|
253
244
|
with shape (n_states, n_targets, n_tpoints)
|
|
254
245
|
|
|
255
246
|
"""
|
|
256
|
-
wmodel.finalize_wake_deltas(algo, mdata, fdata,
|
|
247
|
+
wmodel.finalize_wake_deltas(algo, mdata, fdata, tdata, wake_deltas)
|
|
257
248
|
|
|
258
249
|
@classmethod
|
|
259
250
|
def new(cls, ground_type, *args, **kwargs):
|
foxes/core/model.py
CHANGED
|
@@ -64,12 +64,30 @@ class Model(ABC):
|
|
|
64
64
|
|
|
65
65
|
Returns
|
|
66
66
|
-------
|
|
67
|
-
str
|
|
67
|
+
vnm: str
|
|
68
68
|
Model specific variable name
|
|
69
69
|
|
|
70
70
|
"""
|
|
71
71
|
return f"{self.name}_{v}"
|
|
72
72
|
|
|
73
|
+
def unvar(self, vnm):
|
|
74
|
+
"""
|
|
75
|
+
Translates model specific variable name to origninal variable name.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
vnm: str
|
|
80
|
+
The vamodel specific variable name
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
v: str
|
|
85
|
+
Original variable name
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
lng = len(f"{self.name}_")
|
|
89
|
+
return vnm[lng:] if vnm.startswith(f"{self.name}_") else None
|
|
90
|
+
|
|
73
91
|
@property
|
|
74
92
|
def initialized(self):
|
|
75
93
|
"""
|
|
@@ -77,7 +95,7 @@ class Model(ABC):
|
|
|
77
95
|
|
|
78
96
|
Returns
|
|
79
97
|
-------
|
|
80
|
-
bool
|
|
98
|
+
bool:
|
|
81
99
|
True if the model has been initialized.
|
|
82
100
|
|
|
83
101
|
"""
|
|
@@ -424,8 +442,8 @@ class Model(ABC):
|
|
|
424
442
|
# lookup mdata:
|
|
425
443
|
elif s == "m" and mdata is not None and variable in mdata:
|
|
426
444
|
a, d = _filter_dims(mdata)
|
|
427
|
-
|
|
428
|
-
if
|
|
445
|
+
ld = len(d)
|
|
446
|
+
if ld <= len(dims) and d == dims[:ld]:
|
|
429
447
|
out = _match_shape(mdata[variable])
|
|
430
448
|
|
|
431
449
|
# lookup fdata:
|
|
@@ -448,8 +466,8 @@ class Model(ABC):
|
|
|
448
466
|
and variable in tdata
|
|
449
467
|
):
|
|
450
468
|
a, d = _filter_dims(tdata)
|
|
451
|
-
|
|
452
|
-
if
|
|
469
|
+
ld = len(ld)
|
|
470
|
+
if ld <= len(dims) and d == dims[:ld]:
|
|
453
471
|
out = _match_shape(tdata[variable])
|
|
454
472
|
|
|
455
473
|
# lookup wake modelling data:
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
+
import numpy as np
|
|
2
3
|
|
|
3
|
-
from foxes.utils import new_instance
|
|
4
|
+
from foxes.utils import new_instance, wd2uv, uv2wd
|
|
5
|
+
from foxes.config import config
|
|
6
|
+
import foxes.variables as FV
|
|
7
|
+
import foxes.constants as FC
|
|
4
8
|
|
|
5
9
|
from .model import Model
|
|
10
|
+
from .data import TData
|
|
6
11
|
|
|
7
12
|
|
|
8
13
|
class PartialWakesModel(Model):
|
|
@@ -68,6 +73,144 @@ class PartialWakesModel(Model):
|
|
|
68
73
|
"""
|
|
69
74
|
pass
|
|
70
75
|
|
|
76
|
+
def get_initial_tdata(
|
|
77
|
+
self,
|
|
78
|
+
algo,
|
|
79
|
+
mdata,
|
|
80
|
+
fdata,
|
|
81
|
+
amb_rotor_res,
|
|
82
|
+
rotor_weights,
|
|
83
|
+
wmodels,
|
|
84
|
+
):
|
|
85
|
+
"""
|
|
86
|
+
Creates the initial target data object
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
algo: foxes.core.Algorithm
|
|
91
|
+
The calculation algorithm
|
|
92
|
+
mdata: foxes.core.MData
|
|
93
|
+
The model data
|
|
94
|
+
fdata: foxes.core.FData
|
|
95
|
+
The farm data
|
|
96
|
+
amb_rotor_res: dict
|
|
97
|
+
The ambient results at rotor points,
|
|
98
|
+
key: variable name, value: numpy.ndarray
|
|
99
|
+
of shape: (n_states, n_turbines, n_rotor_points)
|
|
100
|
+
rotor_weights: numpy.ndarray
|
|
101
|
+
The rotor point weights, shape: (n_rotor_points,)
|
|
102
|
+
wmodels: list of foxes.core.WakeModel
|
|
103
|
+
The wake models for this partial wake model
|
|
104
|
+
|
|
105
|
+
Returns
|
|
106
|
+
-------
|
|
107
|
+
tdata: foxes.core.TData
|
|
108
|
+
The target point data for the wake points
|
|
109
|
+
|
|
110
|
+
"""
|
|
111
|
+
tpoints, tweights = self.get_wake_points(algo, mdata, fdata)
|
|
112
|
+
tdata = TData.from_tpoints(tpoints, tweights)
|
|
113
|
+
|
|
114
|
+
# map wind data:
|
|
115
|
+
if FV.WD in amb_rotor_res or FV.WS in amb_rotor_res:
|
|
116
|
+
assert FV.WD in amb_rotor_res and FV.WS in amb_rotor_res, (
|
|
117
|
+
"Require both wind direction and speed in ambient rotor results."
|
|
118
|
+
)
|
|
119
|
+
uv = wd2uv(amb_rotor_res[FV.WD], amb_rotor_res[FV.WS])
|
|
120
|
+
uv = np.stack(
|
|
121
|
+
[
|
|
122
|
+
self.map_rotor_results(
|
|
123
|
+
algo, mdata, fdata, tdata, FV.U, uv[..., 0], rotor_weights
|
|
124
|
+
),
|
|
125
|
+
self.map_rotor_results(
|
|
126
|
+
algo, mdata, fdata, tdata, FV.V, uv[..., 1], rotor_weights
|
|
127
|
+
),
|
|
128
|
+
],
|
|
129
|
+
axis=-1,
|
|
130
|
+
)
|
|
131
|
+
tdata.add(FV.AMB_WD, uv2wd(uv), dims=(FC.STATE, FC.TARGET, FC.TPOINT))
|
|
132
|
+
tdata.add(
|
|
133
|
+
FV.AMB_WS,
|
|
134
|
+
np.linalg.norm(uv, axis=-1),
|
|
135
|
+
dims=(FC.STATE, FC.TARGET, FC.TPOINT),
|
|
136
|
+
)
|
|
137
|
+
for wmodel in wmodels:
|
|
138
|
+
if wmodel.has_uv:
|
|
139
|
+
tdata.add(
|
|
140
|
+
FV.AMB_UV, uv, dims=(FC.STATE, FC.TARGET, FC.TPOINT, FC.XY)
|
|
141
|
+
)
|
|
142
|
+
break
|
|
143
|
+
|
|
144
|
+
# map rotor point results onto target points:
|
|
145
|
+
for v, d in amb_rotor_res.items():
|
|
146
|
+
if v not in [FV.WS, FV.WD, FV.U, FV.V, FV.UV]:
|
|
147
|
+
w = FV.var2amb.get(v, v)
|
|
148
|
+
tdata.add(
|
|
149
|
+
w,
|
|
150
|
+
self.map_rotor_results(
|
|
151
|
+
algo, mdata, fdata, tdata, v, d, rotor_weights
|
|
152
|
+
),
|
|
153
|
+
dims=(FC.STATE, FC.TARGET, FC.TPOINT),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return tdata
|
|
157
|
+
|
|
158
|
+
def map_rotor_results(
|
|
159
|
+
self,
|
|
160
|
+
algo,
|
|
161
|
+
mdata,
|
|
162
|
+
fdata,
|
|
163
|
+
tdata,
|
|
164
|
+
variable,
|
|
165
|
+
rotor_res,
|
|
166
|
+
rotor_weights,
|
|
167
|
+
):
|
|
168
|
+
"""
|
|
169
|
+
Map ambient rotor point results onto target points.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
algo: foxes.core.Algorithm
|
|
174
|
+
The calculation algorithm
|
|
175
|
+
mdata: foxes.core.MData
|
|
176
|
+
The model data
|
|
177
|
+
fdata: foxes.core.FData
|
|
178
|
+
The farm data
|
|
179
|
+
tdata: foxes.core.TData
|
|
180
|
+
The target point data
|
|
181
|
+
variable: str
|
|
182
|
+
The variable name to map
|
|
183
|
+
rotor_res: numpy.ndarray
|
|
184
|
+
The results at rotor points, shape:
|
|
185
|
+
(n_states, n_turbines, n_rotor_points)
|
|
186
|
+
rotor_weights: numpy.ndarray
|
|
187
|
+
The rotor point weights, shape: (n_rotor_points,)
|
|
188
|
+
|
|
189
|
+
Returns
|
|
190
|
+
-------
|
|
191
|
+
res: numpy.ndarray
|
|
192
|
+
The mapped results at target points, shape:
|
|
193
|
+
(n_states, n_targets, n_tpoints)
|
|
194
|
+
|
|
195
|
+
"""
|
|
196
|
+
if len(rotor_res.shape) > 2 and rotor_res.shape[:2] == (
|
|
197
|
+
tdata.n_states,
|
|
198
|
+
tdata.n_targets,
|
|
199
|
+
):
|
|
200
|
+
q = np.zeros(
|
|
201
|
+
(tdata.n_states, tdata.n_targets, tdata.n_tpoints),
|
|
202
|
+
dtype=config.dtype_double,
|
|
203
|
+
)
|
|
204
|
+
if rotor_res.shape[2] == 1:
|
|
205
|
+
q[:] = rotor_res
|
|
206
|
+
else:
|
|
207
|
+
q[:] = np.einsum("str,r->st", rotor_res, rotor_weights)[:, :, None]
|
|
208
|
+
return q
|
|
209
|
+
else:
|
|
210
|
+
raise ValueError(
|
|
211
|
+
f"Partial wakes '{self.name}': Incompatible shape '{rotor_res.shape}' for variable '{variable}' in rotor results."
|
|
212
|
+
)
|
|
213
|
+
|
|
71
214
|
def new_wake_deltas(self, algo, mdata, fdata, tdata, wmodel):
|
|
72
215
|
"""
|
|
73
216
|
Creates new initial wake deltas, filled
|
|
@@ -77,11 +220,11 @@ class PartialWakesModel(Model):
|
|
|
77
220
|
----------
|
|
78
221
|
algo: foxes.core.Algorithm
|
|
79
222
|
The calculation algorithm
|
|
80
|
-
mdata: foxes.core.
|
|
223
|
+
mdata: foxes.core.MData
|
|
81
224
|
The model data
|
|
82
|
-
fdata: foxes.core.
|
|
225
|
+
fdata: foxes.core.FData
|
|
83
226
|
The farm data
|
|
84
|
-
tdata: foxes.core.
|
|
227
|
+
tdata: foxes.core.TData
|
|
85
228
|
The target point data
|
|
86
229
|
wmodel: foxes.core.WakeModel
|
|
87
230
|
The wake model
|
|
@@ -140,7 +283,6 @@ class PartialWakesModel(Model):
|
|
|
140
283
|
mdata,
|
|
141
284
|
fdata,
|
|
142
285
|
tdata,
|
|
143
|
-
amb_res,
|
|
144
286
|
rpoint_weights,
|
|
145
287
|
wake_deltas,
|
|
146
288
|
wmodel,
|
|
@@ -162,11 +304,6 @@ class PartialWakesModel(Model):
|
|
|
162
304
|
The farm data
|
|
163
305
|
tdata: foxes.core.Data
|
|
164
306
|
The target point data
|
|
165
|
-
amb_res: dict
|
|
166
|
-
The ambient results at the target points
|
|
167
|
-
of all rotors. Key: variable name, value
|
|
168
|
-
np.ndarray of shape:
|
|
169
|
-
(n_states, n_turbines, n_rotor_points)
|
|
170
307
|
rpoint_weights: numpy.ndarray
|
|
171
308
|
The rotor point weights, shape: (n_rotor_points,)
|
|
172
309
|
wake_deltas: dict
|
foxes/core/point_data_model.py
CHANGED
|
@@ -42,30 +42,33 @@ class PointDataModel(DataCalcModel):
|
|
|
42
42
|
"""
|
|
43
43
|
return (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
44
44
|
|
|
45
|
-
def
|
|
45
|
+
def ensure_output_vars(self, algo, tdata):
|
|
46
46
|
"""
|
|
47
|
-
|
|
47
|
+
Ensures that the output variables are present in the target data.
|
|
48
48
|
|
|
49
49
|
Parameters
|
|
50
50
|
----------
|
|
51
51
|
algo: foxes.core.Algorithm
|
|
52
52
|
The calculation algorithm
|
|
53
|
-
|
|
54
|
-
The model data
|
|
55
|
-
fdata: foxes.core.Data
|
|
56
|
-
The farm data
|
|
57
|
-
tdata: foxes.core.Data
|
|
53
|
+
tdata: foxes.core.TData
|
|
58
54
|
The target point data
|
|
59
55
|
|
|
60
56
|
"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
vrs = set(self.output_point_vars(algo))
|
|
58
|
+
if hasattr(self, "fixed_vars"):
|
|
59
|
+
vrs.update(self.fixed_vars.keys())
|
|
60
|
+
|
|
61
|
+
for var in vrs:
|
|
62
|
+
if var not in tdata:
|
|
63
|
+
tdata.add(
|
|
64
|
+
var,
|
|
65
|
+
np.full(
|
|
66
|
+
(tdata.n_states, tdata.n_targets, tdata.n_tpoints),
|
|
67
|
+
np.nan,
|
|
68
|
+
dtype=config.dtype_double,
|
|
69
|
+
),
|
|
70
|
+
(FC.STATE, FC.TARGET, FC.TPOINT),
|
|
67
71
|
)
|
|
68
|
-
tdata.dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
69
72
|
|
|
70
73
|
@abstractmethod
|
|
71
74
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
@@ -98,8 +101,7 @@ class PointDataModel(DataCalcModel):
|
|
|
98
101
|
|
|
99
102
|
def run_calculation(self, algo, *data, out_vars, **calc_pars):
|
|
100
103
|
"""
|
|
101
|
-
Starts the model calculation in parallel
|
|
102
|
-
xarray's `apply_ufunc`.
|
|
104
|
+
Starts the model calculation in parallel.
|
|
103
105
|
|
|
104
106
|
Typically this function is called by algorithms.
|
|
105
107
|
|
|
@@ -149,7 +151,7 @@ class PointDataModelList(PointDataModel):
|
|
|
149
151
|
|
|
150
152
|
By using the PointDataModelList the models'
|
|
151
153
|
`calculate` functions are called together
|
|
152
|
-
under one common call
|
|
154
|
+
under one common call by the engine.
|
|
153
155
|
|
|
154
156
|
Attributes
|
|
155
157
|
----------
|
|
@@ -248,6 +250,8 @@ class PointDataModelList(PointDataModel):
|
|
|
248
250
|
(n_states, n_targets, n_tpoints)
|
|
249
251
|
|
|
250
252
|
"""
|
|
253
|
+
self.ensure_output_vars(algo, tdata)
|
|
254
|
+
|
|
251
255
|
if parameters is None:
|
|
252
256
|
parameters = [{}] * len(self.models)
|
|
253
257
|
elif not isinstance(parameters, list):
|
foxes/core/rotor_model.py
CHANGED
|
@@ -60,9 +60,9 @@ class RotorModel(FarmDataModel):
|
|
|
60
60
|
"""
|
|
61
61
|
if self.calc_vars is None:
|
|
62
62
|
vrs = algo.states.output_point_vars(algo)
|
|
63
|
-
assert (
|
|
64
|
-
FV.WEIGHT
|
|
65
|
-
)
|
|
63
|
+
assert FV.WEIGHT not in vrs, (
|
|
64
|
+
f"Rotor '{self.name}': States '{algo.states.name}' output_point_vars contain '{FV.WEIGHT}', please remove"
|
|
65
|
+
)
|
|
66
66
|
|
|
67
67
|
if FV.WS in vrs:
|
|
68
68
|
self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
|
|
@@ -362,6 +362,7 @@ class RotorModel(FarmDataModel):
|
|
|
362
362
|
numpy.ndarray with results, shape: (n_states, n_turbines)
|
|
363
363
|
|
|
364
364
|
"""
|
|
365
|
+
self.ensure_output_vars(algo, fdata)
|
|
365
366
|
|
|
366
367
|
if rpoints is None:
|
|
367
368
|
rpoints = mdata.get(
|
foxes/core/states.py
CHANGED
|
@@ -2,7 +2,6 @@ from abc import abstractmethod
|
|
|
2
2
|
|
|
3
3
|
from .point_data_model import PointDataModel, PointDataModelList
|
|
4
4
|
from foxes.utils import new_instance
|
|
5
|
-
import foxes.variables as FV
|
|
6
5
|
import foxes.constants as FC
|
|
7
6
|
|
|
8
7
|
|
|
@@ -114,7 +113,7 @@ class States(PointDataModel):
|
|
|
114
113
|
elif isinstance(s, ExtendedStates):
|
|
115
114
|
if s.states is not self:
|
|
116
115
|
raise ValueError(
|
|
117
|
-
|
|
116
|
+
"Cannot add extended states, since not based on same states"
|
|
118
117
|
)
|
|
119
118
|
return ExtendedStates(self, s.pmodels.models[1:])
|
|
120
119
|
else:
|
|
@@ -268,7 +267,7 @@ class ExtendedStates(States):
|
|
|
268
267
|
elif isinstance(m, ExtendedStates):
|
|
269
268
|
if m.states is not self.states:
|
|
270
269
|
raise ValueError(
|
|
271
|
-
|
|
270
|
+
"Cannot add extended states, since not based on same states"
|
|
272
271
|
)
|
|
273
272
|
return ExtendedStates(self.states, models + m.pmodels.models[1:])
|
|
274
273
|
else:
|
foxes/core/turbine.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
from copy import deepcopy
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class Turbine:
|
|
@@ -71,7 +72,7 @@ class Turbine:
|
|
|
71
72
|
self.index = index
|
|
72
73
|
self.name = name
|
|
73
74
|
self.xy = np.array(xy)
|
|
74
|
-
self.models = turbine_models
|
|
75
|
+
self.models = deepcopy(turbine_models)
|
|
75
76
|
self.D = D
|
|
76
77
|
self.H = H
|
|
77
78
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from foxes.utils import new_instance
|
|
4
|
+
from .model import Model
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class WakeDeflection(Model):
|
|
8
|
+
"""
|
|
9
|
+
Abstract base class for wake deflection models.
|
|
10
|
+
|
|
11
|
+
:group: core
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def has_uv(self):
|
|
17
|
+
"""
|
|
18
|
+
This model uses wind vector data
|
|
19
|
+
|
|
20
|
+
Returns
|
|
21
|
+
-------
|
|
22
|
+
hasuv: bool
|
|
23
|
+
Flag for wind vector data
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
return False
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def calc_deflection(
|
|
30
|
+
self,
|
|
31
|
+
algo,
|
|
32
|
+
mdata,
|
|
33
|
+
fdata,
|
|
34
|
+
tdata,
|
|
35
|
+
downwind_index,
|
|
36
|
+
coos,
|
|
37
|
+
):
|
|
38
|
+
"""
|
|
39
|
+
Calculates the wake deflection.
|
|
40
|
+
|
|
41
|
+
This function optionally adds FC.WDEFL_ROT_ANGLE or
|
|
42
|
+
FC.WDEFL_DWS_FACTOR to the tdata.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
algo: foxes.core.Algorithm
|
|
47
|
+
The calculation algorithm
|
|
48
|
+
mdata: foxes.core.MData
|
|
49
|
+
The model data
|
|
50
|
+
fdata: foxes.core.FData
|
|
51
|
+
The farm data
|
|
52
|
+
tdata: foxes.core.TData
|
|
53
|
+
The target point data
|
|
54
|
+
downwind_index: int
|
|
55
|
+
The index of the wake causing turbine
|
|
56
|
+
in the downwind order
|
|
57
|
+
coos: numpy.ndarray
|
|
58
|
+
The wake frame coordinates of the evaluation
|
|
59
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
60
|
+
|
|
61
|
+
Returns
|
|
62
|
+
-------
|
|
63
|
+
coos: numpy.ndarray
|
|
64
|
+
The wake frame coordinates of the evaluation
|
|
65
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
66
|
+
|
|
67
|
+
"""
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def get_yaw_alpha_seq(
|
|
71
|
+
self,
|
|
72
|
+
algo,
|
|
73
|
+
mdata,
|
|
74
|
+
fdata,
|
|
75
|
+
tdata,
|
|
76
|
+
downwind_index,
|
|
77
|
+
x,
|
|
78
|
+
):
|
|
79
|
+
"""
|
|
80
|
+
Computes sequential wind vector rotation angles.
|
|
81
|
+
|
|
82
|
+
Wind vector rotation angles are computed at the
|
|
83
|
+
current trace points due to a yawed rotor
|
|
84
|
+
for sequential runs.
|
|
85
|
+
|
|
86
|
+
Parameters
|
|
87
|
+
----------
|
|
88
|
+
algo: foxes.core.Algorithm
|
|
89
|
+
The calculation algorithm
|
|
90
|
+
mdata: foxes.core.MData
|
|
91
|
+
The model data
|
|
92
|
+
fdata: foxes.core.FData
|
|
93
|
+
The farm data
|
|
94
|
+
tdata: foxes.core.TData
|
|
95
|
+
The target point data
|
|
96
|
+
downwind_index: int
|
|
97
|
+
The index of the wake causing turbine
|
|
98
|
+
in the downwind order
|
|
99
|
+
x: numpy.ndarray
|
|
100
|
+
The distance from the wake causing rotor
|
|
101
|
+
for the first n_times subsequent time steps,
|
|
102
|
+
shape: (n_times,)
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
alpha: numpy.ndarray
|
|
107
|
+
The delta WD result at the x locations,
|
|
108
|
+
shape: (n_times,)
|
|
109
|
+
|
|
110
|
+
"""
|
|
111
|
+
raise NotImplementedError(
|
|
112
|
+
f"Wake deflection '{self.name}' not implemented for sequential runs"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
@classmethod
|
|
116
|
+
def new(cls, wdefl_type, *args, **kwargs):
|
|
117
|
+
"""
|
|
118
|
+
Run-time wake deflection model factory.
|
|
119
|
+
|
|
120
|
+
Parameters
|
|
121
|
+
----------
|
|
122
|
+
wdefl_type: str
|
|
123
|
+
The selected derived class name
|
|
124
|
+
args: tuple, optional
|
|
125
|
+
Additional parameters for constructor
|
|
126
|
+
kwargs: dict, optional
|
|
127
|
+
Additional parameters for constructor
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
return new_instance(cls, wdefl_type, *args, **kwargs)
|