foxes 1.2.5__py3-none-any.whl → 1.4__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/induction/run.py +3 -3
- examples/multi_height/run.py +1 -1
- examples/power_mask/run.py +2 -2
- examples/quickstart/run.py +16 -0
- 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 +27 -4
- 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 +16 -8
- foxes/__init__.py +22 -18
- foxes/algorithms/__init__.py +6 -6
- foxes/algorithms/downwind/__init__.py +2 -2
- foxes/algorithms/downwind/downwind.py +53 -27
- foxes/algorithms/downwind/models/__init__.py +6 -6
- foxes/algorithms/downwind/models/farm_wakes_calc.py +22 -14
- foxes/algorithms/downwind/models/init_farm_data.py +4 -5
- foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
- foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +7 -7
- 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 +15 -8
- foxes/algorithms/sequential/__init__.py +3 -3
- foxes/algorithms/sequential/models/__init__.py +2 -2
- foxes/algorithms/sequential/models/seq_state.py +0 -18
- foxes/algorithms/sequential/sequential.py +8 -22
- foxes/config/__init__.py +5 -1
- foxes/constants.py +22 -0
- foxes/core/__init__.py +45 -22
- foxes/core/algorithm.py +0 -1
- foxes/core/data.py +56 -29
- foxes/core/engine.py +28 -14
- foxes/core/farm_controller.py +2 -2
- foxes/core/farm_data_model.py +1 -0
- foxes/core/ground_model.py +4 -13
- foxes/core/model.py +5 -5
- foxes/core/partial_wakes_model.py +147 -10
- foxes/core/point_data_model.py +2 -3
- foxes/core/rotor_model.py +42 -38
- foxes/core/states.py +4 -50
- 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/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 +39 -14
- foxes/engines/numpy.py +0 -3
- foxes/input/__init__.py +3 -3
- foxes/input/farm_layout/__init__.py +8 -8
- foxes/input/farm_layout/from_csv.py +1 -1
- foxes/input/farm_layout/ring.py +0 -1
- foxes/input/states/__init__.py +22 -11
- foxes/input/states/create/__init__.py +3 -2
- foxes/input/states/field_data_nc.py +48 -84
- foxes/input/states/multi_height.py +40 -60
- foxes/input/states/one_point_flow.py +22 -25
- foxes/input/states/scan.py +6 -19
- foxes/input/states/single.py +6 -18
- foxes/input/states/states_table.py +25 -44
- foxes/input/states/weibull_sectors.py +225 -0
- foxes/input/states/wrg_states.py +151 -37
- foxes/input/yaml/__init__.py +9 -3
- foxes/input/yaml/dict.py +19 -19
- foxes/input/yaml/windio/__init__.py +10 -5
- foxes/input/yaml/windio/read_attributes.py +2 -2
- foxes/input/yaml/windio/read_farm.py +5 -5
- foxes/input/yaml/windio/read_fields.py +4 -2
- foxes/input/yaml/windio/read_site.py +52 -0
- foxes/input/yaml/windio/windio.py +1 -1
- 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 +175 -49
- 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 +45 -9
- foxes/models/partial_wakes/segregated.py +2 -20
- foxes/models/partial_wakes/top_hat.py +27 -2
- foxes/models/point_models/__init__.py +4 -4
- foxes/models/rotor_models/__init__.py +3 -3
- foxes/models/rotor_models/centre.py +6 -4
- foxes/models/turbine_models/__init__.py +11 -11
- foxes/models/turbine_models/set_farm_vars.py +0 -1
- foxes/models/turbine_types/PCt_file.py +0 -2
- foxes/models/turbine_types/PCt_from_two.py +0 -2
- foxes/models/turbine_types/__init__.py +9 -9
- 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 +45 -8
- foxes/models/wake_frames/streamlines.py +8 -6
- foxes/models/wake_frames/timelines.py +19 -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 +14 -6
- foxes/output/farm_results_eval.py +51 -27
- foxes/output/flow_plots_2d/__init__.py +2 -2
- foxes/output/flow_plots_2d/get_fig.py +4 -2
- foxes/output/rose_plot.py +23 -5
- 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/slice_data.py +16 -19
- foxes/output/turbine_type_curves.py +7 -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 +3 -3
- foxes/utils/exec_python.py +5 -5
- foxes/utils/factory.py +1 -3
- 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.2.5.dist-info → foxes-1.4.dist-info}/METADATA +14 -21
- foxes-1.4.dist-info/RECORD +320 -0
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
- tests/0_consistency/iterative/test_iterative.py +2 -3
- tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
- 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 +48 -56
- tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
- 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 +3 -3
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -4
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -4
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -4
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -4
- tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -3
- 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 +3 -4
- tests/3_examples/test_examples.py +3 -2
- foxes/output/round.py +0 -10
- foxes/utils/pandas_helpers.py +0 -178
- foxes-1.2.5.dist-info/RECORD +0 -312
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
- {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
|
@@ -89,7 +89,7 @@ class CentreRotor(RotorModel):
|
|
|
89
89
|
mdata,
|
|
90
90
|
fdata,
|
|
91
91
|
rpoint_results,
|
|
92
|
-
|
|
92
|
+
rpoint_weights,
|
|
93
93
|
downwind_index=None,
|
|
94
94
|
copy_to_ambient=False,
|
|
95
95
|
):
|
|
@@ -124,9 +124,9 @@ class CentreRotor(RotorModel):
|
|
|
124
124
|
variables after calculation
|
|
125
125
|
|
|
126
126
|
"""
|
|
127
|
-
if len(
|
|
127
|
+
if len(rpoint_weights) > 1:
|
|
128
128
|
return super().eval_rpoint_results(
|
|
129
|
-
algo, mdata, fdata, rpoint_results,
|
|
129
|
+
algo, mdata, fdata, rpoint_results, rpoint_weights, downwind_index
|
|
130
130
|
)
|
|
131
131
|
|
|
132
132
|
n_states = mdata.n_states
|
|
@@ -192,7 +192,9 @@ class CentreRotor(RotorModel):
|
|
|
192
192
|
del uvp
|
|
193
193
|
|
|
194
194
|
for v in self.calc_vars:
|
|
195
|
-
if v not in vdone
|
|
195
|
+
if v not in vdone and (
|
|
196
|
+
fdata[v].shape[1] > 1 or downwind_index is None or downwind_index == 0
|
|
197
|
+
):
|
|
196
198
|
res = rpoint_results[v][:, :, 0]
|
|
197
199
|
self._set_res(fdata, v, res, downwind_index)
|
|
198
200
|
del res
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -2,12 +2,12 @@
|
|
|
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
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
Vertical profile models.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .uniform import UniformProfile
|
|
6
|
-
from .abl_log_neutral_ws import ABLLogNeutralWsProfile
|
|
7
|
-
from .abl_log_stable_ws import ABLLogStableWsProfile
|
|
8
|
-
from .abl_log_unstable_ws import ABLLogUnstableWsProfile
|
|
9
|
-
from .abl_log_ws import ABLLogWsProfile
|
|
10
|
-
from .sheared_ws import ShearedProfile
|
|
11
|
-
from .data_profile import DataProfile
|
|
5
|
+
from .uniform import UniformProfile as UniformProfile
|
|
6
|
+
from .abl_log_neutral_ws import ABLLogNeutralWsProfile as ABLLogNeutralWsProfile
|
|
7
|
+
from .abl_log_stable_ws import ABLLogStableWsProfile as ABLLogStableWsProfile
|
|
8
|
+
from .abl_log_unstable_ws import ABLLogUnstableWsProfile as ABLLogUnstableWsProfile
|
|
9
|
+
from .abl_log_ws import ABLLogWsProfile as ABLLogWsProfile
|
|
10
|
+
from .sheared_ws import ShearedProfile as ShearedProfile
|
|
11
|
+
from .data_profile import DataProfile as DataProfile
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
|
-
from foxes.
|
|
3
|
+
from foxes.config import config
|
|
4
|
+
from foxes.core.wake_deflection import WakeDeflection
|
|
5
|
+
from foxes.core.wake_model import WakeK
|
|
4
6
|
from foxes.models.wake_models.wind.bastankhah16 import (
|
|
5
7
|
Bastankhah2016Model,
|
|
6
8
|
Bastankhah2016,
|
|
7
9
|
)
|
|
8
|
-
from foxes.config import config
|
|
9
|
-
import foxes.variables as FV
|
|
10
10
|
import foxes.constants as FC
|
|
11
|
-
|
|
12
|
-
from .rotor_wd import RotorWD
|
|
11
|
+
import foxes.variables as FV
|
|
13
12
|
|
|
14
13
|
|
|
15
|
-
class
|
|
14
|
+
class Bastankhah2016Deflection(WakeDeflection):
|
|
16
15
|
"""
|
|
17
16
|
Bend the wakes for yawed turbines, based on the
|
|
18
17
|
Bastankhah 2016 wake model
|
|
@@ -28,25 +27,26 @@ class YawedWakes(WakeFrame):
|
|
|
28
27
|
----------
|
|
29
28
|
model: Bastankhah2016Model
|
|
30
29
|
The model for computing common data
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
:
|
|
30
|
+
alpha: float
|
|
31
|
+
model parameter used to determine onset of far wake region,
|
|
32
|
+
if not found in wake model
|
|
33
|
+
beta: float
|
|
34
|
+
model parameter used to determine onset of far wake region,
|
|
35
|
+
if not found in wake model
|
|
36
|
+
wake_k: dict
|
|
37
|
+
Parameters for the WakeK class, if not found in wake model
|
|
38
|
+
induction: foxes.core.AxialInductionModel
|
|
39
|
+
The induction model, if not found in wake model
|
|
40
|
+
|
|
41
|
+
:group: models.wake_deflections
|
|
40
42
|
|
|
41
43
|
"""
|
|
42
44
|
|
|
43
45
|
def __init__(
|
|
44
46
|
self,
|
|
45
|
-
base_frame=RotorWD(),
|
|
46
47
|
alpha=0.58,
|
|
47
48
|
beta=0.07,
|
|
48
49
|
induction="Madsen",
|
|
49
|
-
max_length_km=30,
|
|
50
50
|
**wake_k,
|
|
51
51
|
):
|
|
52
52
|
"""
|
|
@@ -54,8 +54,6 @@ class YawedWakes(WakeFrame):
|
|
|
54
54
|
|
|
55
55
|
Parameters
|
|
56
56
|
----------
|
|
57
|
-
base_frame: foxes.core.WakeFrame
|
|
58
|
-
The wake frame from which to start
|
|
59
57
|
alpha: float
|
|
60
58
|
model parameter used to determine onset of far wake region,
|
|
61
59
|
if not found in wake model
|
|
@@ -66,13 +64,10 @@ class YawedWakes(WakeFrame):
|
|
|
66
64
|
The induction model, if not found in wake model
|
|
67
65
|
wake_k: dict, optional
|
|
68
66
|
Parameters for the WakeK class, if not found in wake model
|
|
69
|
-
max_length_km: float
|
|
70
|
-
The maximal wake length in km
|
|
71
67
|
|
|
72
68
|
"""
|
|
73
|
-
super().__init__(
|
|
69
|
+
super().__init__()
|
|
74
70
|
|
|
75
|
-
self.base_frame = base_frame
|
|
76
71
|
self.model = None
|
|
77
72
|
self.alpha = alpha
|
|
78
73
|
self.beta = beta
|
|
@@ -98,7 +93,7 @@ class YawedWakes(WakeFrame):
|
|
|
98
93
|
Names of all sub models
|
|
99
94
|
|
|
100
95
|
"""
|
|
101
|
-
return [self.wake_k, self.
|
|
96
|
+
return [self.wake_k, self.model]
|
|
102
97
|
|
|
103
98
|
def initialize(self, algo, verbosity=0, force=False):
|
|
104
99
|
"""
|
|
@@ -138,30 +133,6 @@ class YawedWakes(WakeFrame):
|
|
|
138
133
|
|
|
139
134
|
super().initialize(algo, verbosity, force)
|
|
140
135
|
|
|
141
|
-
def calc_order(self, algo, mdata, fdata):
|
|
142
|
-
"""
|
|
143
|
-
Calculates the order of turbine evaluation.
|
|
144
|
-
|
|
145
|
-
This function is executed on a single chunk of data,
|
|
146
|
-
all computations should be based on numpy arrays.
|
|
147
|
-
|
|
148
|
-
Parameters
|
|
149
|
-
----------
|
|
150
|
-
algo: foxes.core.Algorithm
|
|
151
|
-
The calculation algorithm
|
|
152
|
-
mdata: foxes.core.MData
|
|
153
|
-
The model data
|
|
154
|
-
fdata: foxes.core.FData
|
|
155
|
-
The farm data
|
|
156
|
-
|
|
157
|
-
Returns
|
|
158
|
-
-------
|
|
159
|
-
order: numpy.ndarray
|
|
160
|
-
The turbine order, shape: (n_states, n_turbines)
|
|
161
|
-
|
|
162
|
-
"""
|
|
163
|
-
return self.base_frame.calc_order(algo, mdata, fdata)
|
|
164
|
-
|
|
165
136
|
def _update_y(self, algo, mdata, fdata, tdata, downwind_index, x, y):
|
|
166
137
|
"""
|
|
167
138
|
Helper function for y deflection
|
|
@@ -227,16 +198,20 @@ class YawedWakes(WakeFrame):
|
|
|
227
198
|
# apply deflection:
|
|
228
199
|
y[st_sel] -= ydef
|
|
229
200
|
|
|
230
|
-
def
|
|
201
|
+
def calc_deflection(
|
|
231
202
|
self,
|
|
232
203
|
algo,
|
|
233
204
|
mdata,
|
|
234
205
|
fdata,
|
|
235
206
|
tdata,
|
|
236
207
|
downwind_index,
|
|
208
|
+
coos,
|
|
237
209
|
):
|
|
238
210
|
"""
|
|
239
|
-
|
|
211
|
+
Calculates the wake deflection.
|
|
212
|
+
|
|
213
|
+
This function optionally adds FC.WDEFL_ROT_ANGLE or
|
|
214
|
+
FC.WDEFL_DWS_FACTOR to the tdata.
|
|
240
215
|
|
|
241
216
|
Parameters
|
|
242
217
|
----------
|
|
@@ -251,79 +226,25 @@ class YawedWakes(WakeFrame):
|
|
|
251
226
|
downwind_index: int
|
|
252
227
|
The index of the wake causing turbine
|
|
253
228
|
in the downwind order
|
|
229
|
+
coos: numpy.ndarray
|
|
230
|
+
The wake frame coordinates of the evaluation
|
|
231
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
254
232
|
|
|
255
233
|
Returns
|
|
256
234
|
-------
|
|
257
|
-
|
|
235
|
+
coos: numpy.ndarray
|
|
258
236
|
The wake frame coordinates of the evaluation
|
|
259
237
|
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
260
238
|
|
|
261
239
|
"""
|
|
262
|
-
# get unyawed results:
|
|
263
|
-
xyz = self.base_frame.get_wake_coos(
|
|
264
|
-
algo,
|
|
265
|
-
mdata,
|
|
266
|
-
fdata,
|
|
267
|
-
tdata,
|
|
268
|
-
downwind_index,
|
|
269
|
-
)
|
|
270
240
|
|
|
271
241
|
# take rotor average:
|
|
272
|
-
xy = np.einsum("stpd,p->std",
|
|
242
|
+
xy = np.einsum("stpd,p->std", coos[..., :2], tdata[FC.TWEIGHTS])
|
|
273
243
|
x = xy[:, :, 0]
|
|
274
244
|
y = xy[:, :, 1]
|
|
275
245
|
|
|
276
246
|
# apply deflection:
|
|
277
247
|
self._update_y(algo, mdata, fdata, tdata, downwind_index, x, y)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return xyz
|
|
281
|
-
|
|
282
|
-
def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
|
|
283
|
-
"""
|
|
284
|
-
Gets the points along the centreline for given
|
|
285
|
-
values of x.
|
|
286
|
-
|
|
287
|
-
Parameters
|
|
288
|
-
----------
|
|
289
|
-
algo: foxes.core.Algorithm
|
|
290
|
-
The calculation algorithm
|
|
291
|
-
mdata: foxes.core.MData
|
|
292
|
-
The model data
|
|
293
|
-
fdata: foxes.core.FData
|
|
294
|
-
The farm data
|
|
295
|
-
downwind_index: int
|
|
296
|
-
The index in the downwind order
|
|
297
|
-
x: numpy.ndarray
|
|
298
|
-
The wake frame x coordinates, shape: (n_states, n_points)
|
|
299
|
-
|
|
300
|
-
Returns
|
|
301
|
-
-------
|
|
302
|
-
points: numpy.ndarray
|
|
303
|
-
The centreline points, shape: (n_states, n_points, 3)
|
|
304
|
-
|
|
305
|
-
"""
|
|
306
|
-
points = self.base_frame.get_centreline_points(
|
|
307
|
-
algo, mdata, fdata, downwind_index, x
|
|
308
|
-
)
|
|
309
|
-
tdata = TData.from_points(points)
|
|
310
|
-
|
|
311
|
-
nx = np.zeros_like(points)
|
|
312
|
-
nx[:, 0] = points[:, 1] - points[:, 0]
|
|
313
|
-
nx[:, -1] = points[:, -1] - points[:, -2]
|
|
314
|
-
nx[:, 1:-1] = 0.5 * (points[:, 1:-1] - points[:, :-2]) + 0.5 * (
|
|
315
|
-
points[:, 2:] - points[:, 1:-1]
|
|
316
|
-
)
|
|
317
|
-
nx /= np.linalg.norm(nx, axis=-1)[:, :, None]
|
|
318
|
-
|
|
319
|
-
nz = np.zeros_like(nx)
|
|
320
|
-
nz[:, :, 2] = 1
|
|
321
|
-
ny = np.cross(nz, nx, axis=-1)
|
|
322
|
-
del nx, nz
|
|
323
|
-
|
|
324
|
-
y = np.zeros_like(x)
|
|
325
|
-
self._update_y(algo, mdata, fdata, tdata, downwind_index, x, y)
|
|
326
|
-
|
|
327
|
-
points += y[:, :, None] * ny
|
|
248
|
+
coos[..., 1] = y[:, :, None]
|
|
328
249
|
|
|
329
|
-
return
|
|
250
|
+
return coos
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from foxes.core.wake_deflection import WakeDeflection
|
|
4
|
+
from foxes.algorithms import Sequential
|
|
5
|
+
import foxes.constants as FC
|
|
6
|
+
import foxes.variables as FV
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class JimenezDeflection(WakeDeflection):
|
|
10
|
+
"""
|
|
11
|
+
Yawed rotor wake defection according to the Jimenez model
|
|
12
|
+
|
|
13
|
+
Notes
|
|
14
|
+
-----
|
|
15
|
+
Reference:
|
|
16
|
+
Jiménez, Á., Crespo, A. and Migoya, E. (2010), Application of a LES technique to characterize
|
|
17
|
+
the wake deflection of a wind turbine in yaw. Wind Energ., 13: 559-572. doi:10.1002/we.380
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
rotate: bool
|
|
23
|
+
If True, rotate local wind vector at evaluation points.
|
|
24
|
+
If False, multiply wind speed with cos(angle) instead.
|
|
25
|
+
If None, do not modify the wind vector, only the path.
|
|
26
|
+
beta: float
|
|
27
|
+
The beta coefficient of the Jimenez model
|
|
28
|
+
step_x: float
|
|
29
|
+
The x step in m for integration
|
|
30
|
+
|
|
31
|
+
:group: models.wake_deflections
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, rotate=True, beta=0.1, step_x=10.0):
|
|
36
|
+
"""
|
|
37
|
+
Constructor.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
rotate: bool, optional
|
|
42
|
+
If True, rotate local wind vector at evaluation points.
|
|
43
|
+
If False, multiply wind speed with cos(angle) instead.
|
|
44
|
+
If None, do not modify the wind vector, only the path.
|
|
45
|
+
beta: float
|
|
46
|
+
The beta coefficient of the Jimenez model
|
|
47
|
+
step_x: float
|
|
48
|
+
The x step in m for integration
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
super().__init__()
|
|
52
|
+
self.rotate = rotate
|
|
53
|
+
self.beta = beta
|
|
54
|
+
self.step_x = step_x
|
|
55
|
+
|
|
56
|
+
def __repr__(self):
|
|
57
|
+
s = f"{type(self).__name__}("
|
|
58
|
+
s += f"rotate={self.rotate}, beta={self.beta}, step_x={self.step_x}"
|
|
59
|
+
s += ")"
|
|
60
|
+
return s
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def has_uv(self):
|
|
64
|
+
"""
|
|
65
|
+
This model uses wind vector data
|
|
66
|
+
|
|
67
|
+
Returns
|
|
68
|
+
-------
|
|
69
|
+
hasuv: bool
|
|
70
|
+
Flag for wind vector data
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
return self.rotate is not None and self.rotate
|
|
74
|
+
|
|
75
|
+
def calc_deflection(
|
|
76
|
+
self,
|
|
77
|
+
algo,
|
|
78
|
+
mdata,
|
|
79
|
+
fdata,
|
|
80
|
+
tdata,
|
|
81
|
+
downwind_index,
|
|
82
|
+
coos,
|
|
83
|
+
):
|
|
84
|
+
"""
|
|
85
|
+
Calculates the wake deflection.
|
|
86
|
+
|
|
87
|
+
This function optionally adds FC.WDEFL_ROT_ANGLE or
|
|
88
|
+
FC.WDEFL_DWS_FACTOR to the tdata.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
algo: foxes.core.Algorithm
|
|
93
|
+
The calculation algorithm
|
|
94
|
+
mdata: foxes.core.MData
|
|
95
|
+
The model data
|
|
96
|
+
fdata: foxes.core.FData
|
|
97
|
+
The farm data
|
|
98
|
+
tdata: foxes.core.TData
|
|
99
|
+
The target point data
|
|
100
|
+
downwind_index: int
|
|
101
|
+
The index of the wake causing turbine
|
|
102
|
+
in the downwind order
|
|
103
|
+
coos: numpy.ndarray
|
|
104
|
+
The wake frame coordinates of the evaluation
|
|
105
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
coos: numpy.ndarray
|
|
110
|
+
The wake frame coordinates of the evaluation
|
|
111
|
+
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
if FV.YAWM not in fdata:
|
|
116
|
+
return coos
|
|
117
|
+
|
|
118
|
+
# take rotor average:
|
|
119
|
+
xyz = np.einsum("stpd,p->std", coos, tdata[FC.TWEIGHTS])
|
|
120
|
+
x = xyz[:, :, 0]
|
|
121
|
+
y = xyz[:, :, 1]
|
|
122
|
+
z = xyz[:, :, 2]
|
|
123
|
+
|
|
124
|
+
# get ct:
|
|
125
|
+
ct = self.get_data(
|
|
126
|
+
FV.CT,
|
|
127
|
+
FC.STATE_TARGET,
|
|
128
|
+
lookup="w",
|
|
129
|
+
algo=algo,
|
|
130
|
+
fdata=fdata,
|
|
131
|
+
tdata=tdata,
|
|
132
|
+
downwind_index=downwind_index,
|
|
133
|
+
upcast=True,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# get gamma:
|
|
137
|
+
gamma = self.get_data(
|
|
138
|
+
FV.YAWM,
|
|
139
|
+
FC.STATE_TARGET,
|
|
140
|
+
lookup="w",
|
|
141
|
+
algo=algo,
|
|
142
|
+
fdata=fdata,
|
|
143
|
+
tdata=tdata,
|
|
144
|
+
downwind_index=downwind_index,
|
|
145
|
+
upcast=True,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
sel = (x > 1e-8) & (x < 1e10) & (ct > 1e-8) & (np.abs(gamma) > 1e-8)
|
|
149
|
+
delwd = np.zeros_like(coos[..., 0])
|
|
150
|
+
n_sel = np.sum(sel)
|
|
151
|
+
if n_sel > 0:
|
|
152
|
+
# apply selection:
|
|
153
|
+
gamma = np.deg2rad(gamma[sel])
|
|
154
|
+
ct = ct[sel]
|
|
155
|
+
x = x[sel]
|
|
156
|
+
|
|
157
|
+
# get rotor diameter:
|
|
158
|
+
D = self.get_data(
|
|
159
|
+
FV.D,
|
|
160
|
+
FC.STATE_TARGET,
|
|
161
|
+
lookup="w",
|
|
162
|
+
algo=algo,
|
|
163
|
+
fdata=fdata,
|
|
164
|
+
tdata=tdata,
|
|
165
|
+
downwind_index=downwind_index,
|
|
166
|
+
upcast=True,
|
|
167
|
+
selection=sel,
|
|
168
|
+
)[:, None]
|
|
169
|
+
|
|
170
|
+
# define x path:
|
|
171
|
+
xmax = np.max(x)
|
|
172
|
+
n_x = int(xmax / self.step_x)
|
|
173
|
+
if xmax > n_x * self.step_x:
|
|
174
|
+
n_x += 1
|
|
175
|
+
delx = np.arange(n_x + 1) * self.step_x
|
|
176
|
+
delx = np.minimum(delx[None, :], x[:, None])
|
|
177
|
+
dx = delx[:, 1:] - delx[:, :-1]
|
|
178
|
+
delx = delx[:, :-1]
|
|
179
|
+
|
|
180
|
+
# integrate deflection of y along the x path:
|
|
181
|
+
alpha0 = (
|
|
182
|
+
-(np.cos(gamma[:, None]) ** 2)
|
|
183
|
+
* np.sin(gamma[:, None])
|
|
184
|
+
* ct[:, None]
|
|
185
|
+
/ 2
|
|
186
|
+
)
|
|
187
|
+
y[sel] += np.sum(
|
|
188
|
+
np.tan(alpha0 / (1 + self.beta * delx / D) ** 2) * dx, axis=-1
|
|
189
|
+
)
|
|
190
|
+
del delx, dx
|
|
191
|
+
coos[..., 1] = y[:, :, None]
|
|
192
|
+
|
|
193
|
+
# calculate wind vector modification at evaluation points:
|
|
194
|
+
if self.rotate is not None:
|
|
195
|
+
# delta wd at evaluation points, if within wake radius:
|
|
196
|
+
r2 = (y[sel, None] ** 2 + z[sel, None] ** 2) / D**2
|
|
197
|
+
WD2 = (1 + self.beta * x[:, None] / D) ** 2
|
|
198
|
+
delwd[sel] = np.where(r2 <= WD2 / 4, alpha0 / WD2, 0)
|
|
199
|
+
|
|
200
|
+
if self.rotate:
|
|
201
|
+
tdata[FC.WDEFL_ROT_ANGLE] = np.rad2deg(delwd)
|
|
202
|
+
else:
|
|
203
|
+
tdata[FC.WDEFL_DWS_FACTOR] = np.cos(delwd)
|
|
204
|
+
|
|
205
|
+
return coos
|
|
206
|
+
|
|
207
|
+
def get_yaw_alpha_seq(
|
|
208
|
+
self,
|
|
209
|
+
algo,
|
|
210
|
+
mdata,
|
|
211
|
+
fdata,
|
|
212
|
+
tdata,
|
|
213
|
+
downwind_index,
|
|
214
|
+
x,
|
|
215
|
+
):
|
|
216
|
+
"""
|
|
217
|
+
Computes sequential wind vector rotation angles.
|
|
218
|
+
|
|
219
|
+
Wind vector rotation angles are computed at the
|
|
220
|
+
current trace points due to a yawed rotor
|
|
221
|
+
for sequential runs.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
algo: foxes.core.Algorithm
|
|
226
|
+
The calculation algorithm
|
|
227
|
+
mdata: foxes.core.MData
|
|
228
|
+
The model data
|
|
229
|
+
fdata: foxes.core.FData
|
|
230
|
+
The farm data
|
|
231
|
+
tdata: foxes.core.TData
|
|
232
|
+
The target point data
|
|
233
|
+
downwind_index: int
|
|
234
|
+
The index of the wake causing turbine
|
|
235
|
+
in the downwind order
|
|
236
|
+
x: numpy.ndarray
|
|
237
|
+
The distance from the wake causing rotor
|
|
238
|
+
for the first n_times subsequent time steps,
|
|
239
|
+
shape: (n_times,)
|
|
240
|
+
|
|
241
|
+
Returns
|
|
242
|
+
-------
|
|
243
|
+
alpha: numpy.ndarray
|
|
244
|
+
The delta WD result at the x locations,
|
|
245
|
+
shape: (n_times,)
|
|
246
|
+
|
|
247
|
+
"""
|
|
248
|
+
assert isinstance(algo, Sequential), (
|
|
249
|
+
f"Wake deflection '{self.name}' requires Sequential algorithm, got '{type(algo).__name__}'"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
n_times = len(x)
|
|
253
|
+
|
|
254
|
+
def _get_data(var):
|
|
255
|
+
data = algo.farm_results_downwind[var].to_numpy()[:n_times, downwind_index]
|
|
256
|
+
data[-1] = fdata[var][0, downwind_index]
|
|
257
|
+
return data
|
|
258
|
+
|
|
259
|
+
gamma = _get_data(FV.YAWM)
|
|
260
|
+
ct = _get_data(FV.CT)
|
|
261
|
+
alpha = np.zeros_like(gamma)
|
|
262
|
+
|
|
263
|
+
sel = (ct > 1e-8) & (np.abs(gamma) > 1e-8)
|
|
264
|
+
if np.any(sel):
|
|
265
|
+
D = _get_data(FV.D)[sel]
|
|
266
|
+
gamma = np.deg2rad(gamma[sel])
|
|
267
|
+
ct = ct[sel]
|
|
268
|
+
|
|
269
|
+
alpha[sel] = np.rad2deg(
|
|
270
|
+
-(np.cos(gamma) ** 2)
|
|
271
|
+
* np.sin(gamma)
|
|
272
|
+
* ct
|
|
273
|
+
/ 2
|
|
274
|
+
/ (1 + self.beta * x / D) ** 2
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return alpha
|