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
|
@@ -87,7 +87,6 @@ class PartialSegregated(PartialWakesModel):
|
|
|
87
87
|
mdata,
|
|
88
88
|
fdata,
|
|
89
89
|
tdata,
|
|
90
|
-
amb_res,
|
|
91
90
|
rpoint_weights,
|
|
92
91
|
wake_deltas,
|
|
93
92
|
wmodel,
|
|
@@ -109,11 +108,6 @@ class PartialSegregated(PartialWakesModel):
|
|
|
109
108
|
The farm data
|
|
110
109
|
tdata: foxes.core.Data
|
|
111
110
|
The target point data
|
|
112
|
-
amb_res: dict
|
|
113
|
-
The ambient results at the target points
|
|
114
|
-
of all rotors. Key: variable name, value
|
|
115
|
-
np.ndarray of shape:
|
|
116
|
-
(n_states, n_turbines, n_rotor_points)
|
|
117
111
|
rpoint_weights: numpy.ndarray
|
|
118
112
|
The rotor point weights, shape: (n_rotor_points,)
|
|
119
113
|
wake_deltas: dict
|
|
@@ -138,25 +132,8 @@ class PartialSegregated(PartialWakesModel):
|
|
|
138
132
|
gweights = tdata[FC.TWEIGHTS]
|
|
139
133
|
|
|
140
134
|
wdel = {v: d[:, downwind_index, None].copy() for v, d in wake_deltas.items()}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
ares = {
|
|
144
|
-
v: d[:, downwind_index, None] if d.shape[1] > 1 else d[:, 0, None]
|
|
145
|
-
for v, d in amb_res.items()
|
|
146
|
-
}
|
|
147
|
-
else:
|
|
148
|
-
ares = {}
|
|
149
|
-
for v, d in amb_res.items():
|
|
150
|
-
ares[v] = np.zeros(
|
|
151
|
-
(n_states, 1, tdata.n_tpoints), dtype=config.dtype_double
|
|
152
|
-
)
|
|
153
|
-
ares[v][:] = np.einsum(
|
|
154
|
-
"sp,p->s",
|
|
155
|
-
d[:, downwind_index] if d.shape[1] > 1 else d[:, 0],
|
|
156
|
-
rpoint_weights,
|
|
157
|
-
)[:, None, None]
|
|
158
|
-
|
|
159
|
-
wmodel.finalize_wake_deltas(algo, mdata, fdata, ares, wdel)
|
|
135
|
+
htdata = tdata.get_slice([FC.TURBINE], np.s_[downwind_index])
|
|
136
|
+
wmodel.finalize_wake_deltas(algo, mdata, fdata, htdata, wdel)
|
|
160
137
|
|
|
161
138
|
for v in wdel.keys():
|
|
162
139
|
hdel = np.zeros((n_states, n_rotor_points), dtype=config.dtype_double)
|
|
@@ -126,8 +126,6 @@ class PartialTopHat(PartialCentre):
|
|
|
126
126
|
The wake deltas. Key: variable name,
|
|
127
127
|
value: numpy.ndarray with shape
|
|
128
128
|
(n_states, n_targets, n_tpoints, ...)
|
|
129
|
-
wmodel: foxes.core.WakeModel
|
|
130
|
-
The wake model
|
|
131
129
|
|
|
132
130
|
"""
|
|
133
131
|
self.check_wmodel(wmodel, error=True)
|
|
@@ -182,6 +180,33 @@ class PartialTopHat(PartialCentre):
|
|
|
182
180
|
|
|
183
181
|
weights = calc_area(D / 2, wr, R) / (np.pi * (D / 2) ** 2)
|
|
184
182
|
|
|
183
|
+
# run superposition models:
|
|
184
|
+
if wmodel.affects_ws and wmodel.has_uv:
|
|
185
|
+
assert wmodel.has_vector_wind_superp, (
|
|
186
|
+
f"{self.name}: Expecting vector wind superposition in wake model '{wmodel.name}', got '{wmodel.wind_superposition}'"
|
|
187
|
+
)
|
|
188
|
+
if FV.UV in clw:
|
|
189
|
+
duv = clw.pop(FV.UV)
|
|
190
|
+
else:
|
|
191
|
+
clwe = {v: d[:, None] for v, d in clw.items()}
|
|
192
|
+
wmodel.vec_superp.wdeltas_ws2uv(
|
|
193
|
+
algo, fdata, tdata, downwind_index, clwe, st_sel
|
|
194
|
+
)
|
|
195
|
+
duv = np.einsum("sd,s->sd", clwe.pop(FV.UV)[:, 0], weights)
|
|
196
|
+
del clwe, clw[FV.WS]
|
|
197
|
+
if FV.WD in clw:
|
|
198
|
+
del clw[FV.WD]
|
|
199
|
+
wake_deltas[FV.UV] = wmodel.vec_superp.add_wake_vector(
|
|
200
|
+
algo,
|
|
201
|
+
mdata,
|
|
202
|
+
fdata,
|
|
203
|
+
tdata,
|
|
204
|
+
downwind_index,
|
|
205
|
+
st_sel,
|
|
206
|
+
wake_deltas[FV.UV],
|
|
207
|
+
duv[:, None],
|
|
208
|
+
)
|
|
209
|
+
|
|
185
210
|
for v, d in clw.items():
|
|
186
211
|
try:
|
|
187
212
|
superp = wmodel.superp[v]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Point models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .wake_deltas import WakeDeltas
|
|
6
|
-
from .set_uniform_data import SetUniformData
|
|
7
|
-
from .tke2ti import TKE2TI
|
|
8
|
-
from .ustar2ti import Ustar2TI
|
|
5
|
+
from .wake_deltas import WakeDeltas as WakeDeltas
|
|
6
|
+
from .set_uniform_data import SetUniformData as SetUniformData
|
|
7
|
+
from .tke2ti import TKE2TI as TKE2TI
|
|
8
|
+
from .ustar2ti import Ustar2TI as Ustar2TI
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Rotor models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .centre import CentreRotor
|
|
6
|
-
from .grid import GridRotor
|
|
7
|
-
from .levels import LevelRotor
|
|
5
|
+
from .centre import CentreRotor as CentreRotor
|
|
6
|
+
from .grid import GridRotor as GridRotor
|
|
7
|
+
from .levels import LevelRotor as LevelRotor
|
|
8
|
+
from .direct_infusion import DirectMDataInfusion as DirectMDataInfusion
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from foxes.core import TData
|
|
4
|
+
import foxes.variables as FV
|
|
5
|
+
import foxes.constants as FC
|
|
6
|
+
|
|
7
|
+
from .centre import CentreRotor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DirectMDataInfusion(CentreRotor):
|
|
11
|
+
"""
|
|
12
|
+
Direct data infusion of data stored under mdata.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
svars2mdvars: dict
|
|
17
|
+
A mapping of state variables to mdata variables.
|
|
18
|
+
mdata_vars: list of str
|
|
19
|
+
The mdata variables to be used for infusion. By default,
|
|
20
|
+
all mdata variables are searched.
|
|
21
|
+
turbine_coord: str, optional
|
|
22
|
+
The mdata coordinate that represents turbine names. By default,
|
|
23
|
+
the second coordinate is used as a candidate if the mdata variable
|
|
24
|
+
has three dimensions.
|
|
25
|
+
|
|
26
|
+
:group: models.turbine_types
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
svars2mdvars=None,
|
|
33
|
+
mdata_vars=None,
|
|
34
|
+
turbine_coord=None,
|
|
35
|
+
**kwargs,
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
Constructor.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
svars2mdvars: dict, optional
|
|
43
|
+
A mapping of state variables to mdata variables.
|
|
44
|
+
mdata_vars: list of str, optional
|
|
45
|
+
The mdata variables to be used for infusion. By default,
|
|
46
|
+
all mdata variables are searched.
|
|
47
|
+
turbine_coord: str, optional
|
|
48
|
+
The mdata coordinate that represents turbine names. By default,
|
|
49
|
+
the second coordinate is used as a candidate if the mdata variable
|
|
50
|
+
has three dimensions.
|
|
51
|
+
kwargs: dict, optional
|
|
52
|
+
Additional parameters for RotorModel class
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
super().__init__(**kwargs)
|
|
56
|
+
self.svars2mdvars = svars2mdvars
|
|
57
|
+
self.mdata_vars = mdata_vars
|
|
58
|
+
self.turbine_coord = turbine_coord
|
|
59
|
+
|
|
60
|
+
def output_farm_vars(self, algo):
|
|
61
|
+
"""
|
|
62
|
+
The variables which are being modified by the model.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
algo: foxes.core.Algorithm
|
|
67
|
+
The calculation algorithm
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
output_vars: list of str
|
|
72
|
+
The output variable names
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
if self.svars2mdvars is None:
|
|
76
|
+
self.svars2mdvars = {v: v for v in algo.states.output_point_vars(algo)}
|
|
77
|
+
|
|
78
|
+
if self.calc_vars is None:
|
|
79
|
+
vrs = list(self.svars2mdvars.keys())
|
|
80
|
+
assert FV.WEIGHT not in vrs, (
|
|
81
|
+
f"Rotor '{self.name}': svars2mdvars keys {vrs} contain '{FV.WEIGHT}', please remove"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
if FV.WS in vrs:
|
|
85
|
+
self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
|
|
86
|
+
else:
|
|
87
|
+
self.calc_vars = vrs
|
|
88
|
+
|
|
89
|
+
if algo.farm_controller.needs_rews2() and FV.REWS2 not in self.calc_vars:
|
|
90
|
+
self.calc_vars.append(FV.REWS2)
|
|
91
|
+
if algo.farm_controller.needs_rews3() and FV.REWS3 not in self.calc_vars:
|
|
92
|
+
self.calc_vars.append(FV.REWS3)
|
|
93
|
+
|
|
94
|
+
self.calc_vars = sorted(self.calc_vars)
|
|
95
|
+
|
|
96
|
+
if FV.WEIGHT not in self.calc_vars:
|
|
97
|
+
self.calc_vars.append(FV.WEIGHT)
|
|
98
|
+
if FV.WEIGHT not in self.svars2mdvars:
|
|
99
|
+
self.svars2mdvars[FV.WEIGHT] = FV.WEIGHT
|
|
100
|
+
|
|
101
|
+
return self.calc_vars
|
|
102
|
+
|
|
103
|
+
def calculate(
|
|
104
|
+
self,
|
|
105
|
+
algo,
|
|
106
|
+
mdata,
|
|
107
|
+
fdata,
|
|
108
|
+
rpoints=None,
|
|
109
|
+
rpoint_weights=None,
|
|
110
|
+
store=False,
|
|
111
|
+
downwind_index=None,
|
|
112
|
+
):
|
|
113
|
+
"""
|
|
114
|
+
Calculate ambient rotor effective results.
|
|
115
|
+
|
|
116
|
+
Parameters
|
|
117
|
+
----------
|
|
118
|
+
algo: foxes.core.Algorithm
|
|
119
|
+
The calculation algorithm
|
|
120
|
+
mdata: foxes.core.MData
|
|
121
|
+
The model data
|
|
122
|
+
fdata: foxes.core.FData
|
|
123
|
+
The farm data
|
|
124
|
+
rpoints: numpy.ndarray, optional
|
|
125
|
+
The rotor points, or None for automatic for
|
|
126
|
+
this rotor. Shape: (n_states, n_turbines, n_rpoints, 3)
|
|
127
|
+
rpoint_weights: numpy.ndarray, optional
|
|
128
|
+
The rotor point weights, or None for automatic
|
|
129
|
+
for this rotor. Shape: (n_rpoints,)
|
|
130
|
+
store: bool, optional
|
|
131
|
+
Flag for storing ambient rotor point results
|
|
132
|
+
downwind_index: int, optional
|
|
133
|
+
Only compute for index in the downwind order
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
results: dict
|
|
138
|
+
results dict. Keys: Variable name str. Values:
|
|
139
|
+
numpy.ndarray with results, shape: (n_states, n_turbines)
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
self.ensure_output_vars(algo, fdata)
|
|
143
|
+
|
|
144
|
+
if rpoints is None:
|
|
145
|
+
rpoints = mdata.get(
|
|
146
|
+
FC.ROTOR_POINTS, self.get_rotor_points(algo, mdata, fdata)
|
|
147
|
+
)
|
|
148
|
+
if downwind_index is not None:
|
|
149
|
+
rpoints = rpoints[:, downwind_index, None]
|
|
150
|
+
if rpoint_weights is None:
|
|
151
|
+
rpoint_weights = mdata.get_item(FC.TWEIGHTS, self.rotor_point_weights())
|
|
152
|
+
|
|
153
|
+
tdata = TData.from_tpoints(rpoints, rpoint_weights)
|
|
154
|
+
sres = {}
|
|
155
|
+
mdvs = self.mdata_vars if self.mdata_vars is not None else list(mdata.keys())
|
|
156
|
+
for v, w in self.svars2mdvars.items():
|
|
157
|
+
tdata.add(
|
|
158
|
+
v,
|
|
159
|
+
data=np.full_like(rpoints[..., 0], np.nan),
|
|
160
|
+
dims=(FC.STATE, FC.TARGET, FC.TPOINT),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# check fixed variables
|
|
164
|
+
if hasattr(algo.states, "fixed_vars") and v in algo.states.fixed_vars:
|
|
165
|
+
tdata[v][:] = algo.states.fixed_vars[v]
|
|
166
|
+
sres[v] = tdata[v]
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
# search in mdata variables
|
|
170
|
+
tcoord = self.turbine_coord
|
|
171
|
+
for mdv in mdvs:
|
|
172
|
+
assert mdv in mdata and mdv in mdata.dims, (
|
|
173
|
+
f"Rotor '{self.name}': mdata variable '{mdv}' not found in mdata {list(mdata.keys())} with dims {list(mdata.dims.keys())}"
|
|
174
|
+
)
|
|
175
|
+
mdat = mdata[mdv]
|
|
176
|
+
dims = mdata.dims[mdv]
|
|
177
|
+
|
|
178
|
+
# skip coordinates in the search:
|
|
179
|
+
if dims == (mdv,):
|
|
180
|
+
continue
|
|
181
|
+
|
|
182
|
+
# find variable index in last data array dimension
|
|
183
|
+
vc = dims[-1]
|
|
184
|
+
assert vc in mdata and vc in mdata.dims and mdata.dims[vc] == (vc,), (
|
|
185
|
+
f"Rotor '{self.name}': mdata coordinate '{vc}' not in mdata or wrong dimensions {mdata.dims}, expected '{(vc,)}'"
|
|
186
|
+
)
|
|
187
|
+
vrs = list(mdata[vc])
|
|
188
|
+
if w in vrs:
|
|
189
|
+
i = vrs.index(w)
|
|
190
|
+
mdat = mdat[..., i]
|
|
191
|
+
dims = dims[:-1]
|
|
192
|
+
|
|
193
|
+
# pure state dependent variable
|
|
194
|
+
if dims == (FC.STATE,):
|
|
195
|
+
tdata[v][:] = mdat[:, None, None]
|
|
196
|
+
|
|
197
|
+
# state and turbine dependent variable
|
|
198
|
+
elif len(dims) == 2 and dims[0] == FC.STATE:
|
|
199
|
+
assert mdat.shape[1] == mdata.n_turbines, (
|
|
200
|
+
f"Rotor '{self.name}': mdata variable '{mdv}' has dimensions {dims} and unexpected shape {mdat.shape} for variable '{w}', expected ({mdata.n_states}, {mdata.n_turbines}) for this wind farm with {mdata.n_turbines} turbines"
|
|
201
|
+
)
|
|
202
|
+
if tcoord is None:
|
|
203
|
+
tcoord = dims[1]
|
|
204
|
+
assert dims[1] == tcoord, (
|
|
205
|
+
f"Rotor '{self.name}': mdata variable '{mdv}' has unexpected dimensions {dims} for variable '{w}', expected ({FC.STATE}, {tcoord})"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
tdata[v][:] = mdat[:, :, None]
|
|
209
|
+
|
|
210
|
+
else:
|
|
211
|
+
if tcoord is None:
|
|
212
|
+
tcoord = "<turbine>"
|
|
213
|
+
raise ValueError(
|
|
214
|
+
f"Rotor '{self.name}': mdata variable '{mdv}' has unexpected dimensions {dims} for variable '{w}' at position {i}, expected ({FC.STATE},) or ({FC.STATE}, {tcoord})"
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
sres[v] = tdata[v]
|
|
218
|
+
break
|
|
219
|
+
|
|
220
|
+
if v not in sres:
|
|
221
|
+
raise ValueError(
|
|
222
|
+
f"Rotor '{self.name}': mdata variable '{w}' not found in any of the mdata variables {mdvs}"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
if store:
|
|
226
|
+
algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
|
|
227
|
+
algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, rpoint_weights, mdata=mdata)
|
|
228
|
+
algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres, mdata=mdata)
|
|
229
|
+
algo.add_to_chunk_store(FC.WEIGHT_RES, tdata[FV.WEIGHT], mdata=mdata)
|
|
230
|
+
|
|
231
|
+
self.eval_rpoint_results(
|
|
232
|
+
algo,
|
|
233
|
+
mdata,
|
|
234
|
+
fdata,
|
|
235
|
+
tdata,
|
|
236
|
+
rpoint_weights,
|
|
237
|
+
downwind_index,
|
|
238
|
+
copy_to_ambient=True,
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
return {v: fdata[v] for v in self.output_farm_vars(algo)}
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
Turbine models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .kTI_model import kTI
|
|
6
|
-
from .set_farm_vars import SetFarmVars
|
|
7
|
-
from .thrust2ct import Thrust2Ct
|
|
8
|
-
from .power_mask import PowerMask
|
|
9
|
-
from .sector_management import SectorManagement
|
|
10
|
-
from .table_factors import TableFactors
|
|
11
|
-
from .yaw2yawm import YAW2YAWM
|
|
12
|
-
from .yawm2yaw import YAWM2YAW
|
|
13
|
-
from .calculator import Calculator
|
|
14
|
-
from .rotor_centre_calc import RotorCentreCalc
|
|
15
|
-
from .lookup_table import LookupTable
|
|
5
|
+
from .kTI_model import kTI as kTI
|
|
6
|
+
from .set_farm_vars import SetFarmVars as SetFarmVars
|
|
7
|
+
from .thrust2ct import Thrust2Ct as Thrust2Ct
|
|
8
|
+
from .power_mask import PowerMask as PowerMask
|
|
9
|
+
from .sector_management import SectorManagement as SectorManagement
|
|
10
|
+
from .table_factors import TableFactors as TableFactors
|
|
11
|
+
from .yaw2yawm import YAW2YAWM as YAW2YAWM
|
|
12
|
+
from .yawm2yaw import YAWM2YAW as YAWM2YAW
|
|
13
|
+
from .calculator import Calculator as Calculator
|
|
14
|
+
from .rotor_centre_calc import RotorCentreCalc as RotorCentreCalc
|
|
15
|
+
from .lookup_table import LookupTable as LookupTable
|
|
@@ -12,11 +12,17 @@ class Calculator(TurbineModel):
|
|
|
12
12
|
out_vars: list of str
|
|
13
13
|
The output variables
|
|
14
14
|
func: Function
|
|
15
|
-
The function: f(in0, in1, ...,
|
|
15
|
+
The function: f(in0, in1, ..., algo, mdata, fdata, st_sel) -> (out0, out1, ...)
|
|
16
16
|
where inX and outY are numpy.ndarrays and
|
|
17
17
|
st_sel is the state-turbine selection slice or array.
|
|
18
18
|
All arrays have shape (n_states, n_turbines).
|
|
19
19
|
|
|
20
|
+
Beware that the turbine ordering in fdata is in downwind order,
|
|
21
|
+
hence external data X of shape (n_states, n_turbines) in farm order
|
|
22
|
+
needs to be reordered by X[ssel, order] with
|
|
23
|
+
ssel = fdata[FV.ORDER_SSEL], order = fdata[FV.ORDER]
|
|
24
|
+
before using it in combination with fdata variables.
|
|
25
|
+
|
|
20
26
|
:group: models.turbine_models
|
|
21
27
|
|
|
22
28
|
"""
|
|
@@ -32,10 +38,16 @@ class Calculator(TurbineModel):
|
|
|
32
38
|
out_vars: list of str
|
|
33
39
|
The output variables
|
|
34
40
|
func: Function
|
|
35
|
-
The function: f(in0, in1, ...,
|
|
41
|
+
The function: f(in0, in1, ..., algo, mdata, fdata, st_sel) -> (out0, out1, ...)
|
|
36
42
|
where inX and outY are numpy.ndarrays and
|
|
37
43
|
st_sel is the state-turbine selection slice or array.
|
|
38
44
|
All arrays have shape (n_states, n_turbines).
|
|
45
|
+
|
|
46
|
+
Beware that the turbine ordering in fdata is in downwind order,
|
|
47
|
+
hence external data X of shape (n_states, n_turbines) in farm order
|
|
48
|
+
needs to be reordered by X[ssel, order] with
|
|
49
|
+
ssel = fdata[FV.ORDER_SSEL], order = fdata[FV.ORDER]
|
|
50
|
+
before using it in combination with fdata variables.
|
|
39
51
|
kwargs: dict, optional
|
|
40
52
|
Additional arguments for TurbineModel
|
|
41
53
|
|
|
@@ -92,7 +104,8 @@ class Calculator(TurbineModel):
|
|
|
92
104
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
93
105
|
|
|
94
106
|
"""
|
|
107
|
+
self.ensure_output_vars(algo, fdata)
|
|
95
108
|
ins = [fdata[v] if v in fdata else mdata[v] for v in self.in_vars]
|
|
96
|
-
outs = self.func(*ins, st_sel=st_sel)
|
|
109
|
+
outs = self.func(*ins, algo=algo, mdata=mdata, fdata=fdata, st_sel=st_sel)
|
|
97
110
|
|
|
98
111
|
return {v: outs[vi] for vi, v in enumerate(self.out_vars)}
|
|
@@ -268,21 +268,15 @@ class SetFarmVars(TurbineModel):
|
|
|
268
268
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
269
269
|
|
|
270
270
|
"""
|
|
271
|
+
self.ensure_output_vars(algo, fdata)
|
|
272
|
+
|
|
271
273
|
i0 = mdata.states_i0(counter=True)
|
|
272
274
|
if not self.once or i0 not in self.__once_done:
|
|
273
|
-
|
|
274
|
-
if self.pre_rotor:
|
|
275
|
-
order = np.s_[:]
|
|
276
|
-
ssel = np.s_[:]
|
|
277
|
-
else:
|
|
278
|
-
order = fdata[FV.ORDER]
|
|
279
|
-
ssel = fdata[FV.ORDER_SSEL]
|
|
280
|
-
|
|
281
275
|
bsel = np.zeros((fdata.n_states, fdata.n_turbines), dtype=bool)
|
|
282
276
|
bsel[st_sel] = True
|
|
283
277
|
|
|
284
278
|
for v in self.vars:
|
|
285
|
-
data = mdata[self.var(v)]
|
|
279
|
+
data = mdata[self.var(v)]
|
|
286
280
|
hsel = ~np.isnan(data)
|
|
287
281
|
tsel = bsel & hsel
|
|
288
282
|
|
|
@@ -143,6 +143,8 @@ class TableFactors(TurbineModel):
|
|
|
143
143
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
144
144
|
|
|
145
145
|
"""
|
|
146
|
+
self.ensure_output_vars(algo, fdata)
|
|
147
|
+
|
|
146
148
|
n_sel = np.sum(st_sel)
|
|
147
149
|
qts = np.zeros((n_sel, 2), dtype=config.dtype_double)
|
|
148
150
|
qts[:, 0] = fdata[self.row_var][st_sel]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pandas as pd
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
from foxes.core import TurbineType
|
|
6
5
|
from foxes.utils import PandasFileHelper
|
|
@@ -232,7 +231,6 @@ class PCtFile(TurbineType):
|
|
|
232
231
|
|
|
233
232
|
"""
|
|
234
233
|
if modify_ct or modify_P:
|
|
235
|
-
|
|
236
234
|
ws = self.data_ws
|
|
237
235
|
ct = self.data_ct
|
|
238
236
|
P = self.data_P
|
|
@@ -302,6 +300,7 @@ class PCtFile(TurbineType):
|
|
|
302
300
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
303
301
|
|
|
304
302
|
"""
|
|
303
|
+
self.ensure_output_vars(algo, fdata)
|
|
305
304
|
rews2 = fdata[self.WSCT][st_sel]
|
|
306
305
|
rews3 = fdata[self.WSP][st_sel]
|
|
307
306
|
|
|
@@ -332,10 +331,7 @@ class PCtFile(TurbineType):
|
|
|
332
331
|
rews3 *= (cosm**self.p_P) ** (1.0 / 3.0)
|
|
333
332
|
del yawm, cosm
|
|
334
333
|
|
|
335
|
-
out = {
|
|
336
|
-
FV.P: fdata[FV.P],
|
|
337
|
-
FV.CT: fdata[FV.CT],
|
|
338
|
-
}
|
|
334
|
+
out = {FV.P: fdata[FV.P], FV.CT: fdata[FV.CT]}
|
|
339
335
|
|
|
340
336
|
out[FV.P][st_sel] = np.interp(
|
|
341
337
|
rews3, self.data_ws, self.data_P, left=0.0, right=0.0
|
|
@@ -263,7 +263,6 @@ class PCtFromTwo(TurbineType):
|
|
|
263
263
|
|
|
264
264
|
"""
|
|
265
265
|
if modify_ct:
|
|
266
|
-
|
|
267
266
|
ws = self._data_ws_ct
|
|
268
267
|
ct = self._data_ct
|
|
269
268
|
|
|
@@ -291,7 +290,6 @@ class PCtFromTwo(TurbineType):
|
|
|
291
290
|
self._data_ct = np.concatenate([new_ct[:-1], ct], axis=0)
|
|
292
291
|
|
|
293
292
|
if modify_P:
|
|
294
|
-
|
|
295
293
|
ws = self._data_ws_P
|
|
296
294
|
P = self._data_P
|
|
297
295
|
|
|
@@ -347,6 +345,7 @@ class PCtFromTwo(TurbineType):
|
|
|
347
345
|
Values: numpy.ndarray with shape (n_states, n_turbines)
|
|
348
346
|
|
|
349
347
|
"""
|
|
348
|
+
self.ensure_output_vars(algo, fdata)
|
|
350
349
|
rews2 = fdata[self.WSCT][st_sel]
|
|
351
350
|
rews3 = fdata[self.WSP][st_sel]
|
|
352
351
|
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
Turbine type models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .PCt_file import PCtFile
|
|
6
|
-
from .PCt_from_two import PCtFromTwo
|
|
7
|
-
from .CpCt_file import CpCtFile
|
|
8
|
-
from .CpCt_from_two import CpCtFromTwo
|
|
9
|
-
from .null_type import NullType
|
|
10
|
-
from .wsrho2PCt_from_two import WsRho2PCtFromTwo
|
|
11
|
-
from .wsti2PCt_from_two import WsTI2PCtFromTwo
|
|
12
|
-
from .lookup import FromLookupTable
|
|
13
|
-
from .TBL_file import TBLFile
|
|
5
|
+
from .PCt_file import PCtFile as PCtFile
|
|
6
|
+
from .PCt_from_two import PCtFromTwo as PCtFromTwo
|
|
7
|
+
from .CpCt_file import CpCtFile as CpCtFile
|
|
8
|
+
from .CpCt_from_two import CpCtFromTwo as CpCtFromTwo
|
|
9
|
+
from .null_type import NullType as NullType
|
|
10
|
+
from .wsrho2PCt_from_two import WsRho2PCtFromTwo as WsRho2PCtFromTwo
|
|
11
|
+
from .wsti2PCt_from_two import WsTI2PCtFromTwo as WsTI2PCtFromTwo
|
|
12
|
+
from .lookup import FromLookupTable as FromLookupTable
|
|
13
|
+
from .TBL_file import TBLFile as TBLFile
|
|
14
|
+
from .calculator_type import CalculatorType as CalculatorType
|