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.

Files changed (228) hide show
  1. docs/source/conf.py +3 -3
  2. examples/abl_states/run.py +2 -2
  3. examples/compare_rotors_pwakes/run.py +1 -1
  4. examples/compare_wakes/run.py +1 -2
  5. examples/dyn_wakes/run.py +29 -6
  6. examples/field_data_nc/run.py +1 -1
  7. examples/induction/run.py +3 -3
  8. examples/multi_height/run.py +1 -1
  9. examples/power_mask/run.py +2 -2
  10. examples/quickstart/run.py +0 -1
  11. examples/random_timeseries/run.py +3 -4
  12. examples/scan_row/run.py +3 -3
  13. examples/sequential/run.py +33 -10
  14. examples/single_state/run.py +3 -4
  15. examples/states_lookup_table/run.py +3 -3
  16. examples/streamline_wakes/run.py +29 -6
  17. examples/tab_file/run.py +3 -3
  18. examples/timelines/run.py +29 -5
  19. examples/timeseries/run.py +3 -3
  20. examples/timeseries_slurm/run.py +3 -3
  21. examples/wind_rose/run.py +3 -3
  22. examples/yawed_wake/run.py +19 -9
  23. foxes/__init__.py +21 -17
  24. foxes/algorithms/__init__.py +6 -6
  25. foxes/algorithms/downwind/__init__.py +2 -2
  26. foxes/algorithms/downwind/downwind.py +49 -17
  27. foxes/algorithms/downwind/models/__init__.py +6 -6
  28. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
  29. foxes/algorithms/downwind/models/init_farm_data.py +58 -29
  30. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
  33. foxes/algorithms/iterative/__init__.py +7 -3
  34. foxes/algorithms/iterative/iterative.py +1 -2
  35. foxes/algorithms/iterative/models/__init__.py +7 -3
  36. foxes/algorithms/iterative/models/farm_wakes_calc.py +9 -5
  37. foxes/algorithms/sequential/__init__.py +3 -3
  38. foxes/algorithms/sequential/models/__init__.py +2 -2
  39. foxes/algorithms/sequential/sequential.py +3 -4
  40. foxes/config/__init__.py +5 -1
  41. foxes/constants.py +16 -0
  42. foxes/core/__init__.py +45 -22
  43. foxes/core/algorithm.py +5 -6
  44. foxes/core/data.py +94 -22
  45. foxes/core/data_calc_model.py +4 -2
  46. foxes/core/engine.py +42 -53
  47. foxes/core/farm_controller.py +2 -2
  48. foxes/core/farm_data_model.py +16 -13
  49. foxes/core/ground_model.py +4 -13
  50. foxes/core/model.py +24 -6
  51. foxes/core/partial_wakes_model.py +147 -10
  52. foxes/core/point_data_model.py +21 -17
  53. foxes/core/rotor_model.py +4 -3
  54. foxes/core/states.py +2 -3
  55. foxes/core/turbine.py +2 -1
  56. foxes/core/wake_deflection.py +130 -0
  57. foxes/core/wake_model.py +222 -9
  58. foxes/core/wake_superposition.py +122 -4
  59. foxes/core/wind_farm.py +6 -6
  60. foxes/data/__init__.py +7 -2
  61. foxes/data/states/point_cloud_100.nc +0 -0
  62. foxes/data/states/weibull_cloud_4.nc +0 -0
  63. foxes/data/states/weibull_grid.nc +0 -0
  64. foxes/data/states/weibull_sectors_12.csv +13 -0
  65. foxes/data/states/weibull_sectors_12.nc +0 -0
  66. foxes/engines/__init__.py +14 -15
  67. foxes/engines/dask.py +42 -20
  68. foxes/engines/default.py +2 -2
  69. foxes/engines/numpy.py +11 -13
  70. foxes/engines/pool.py +20 -11
  71. foxes/engines/single.py +8 -6
  72. foxes/input/__init__.py +3 -3
  73. foxes/input/farm_layout/__init__.py +9 -8
  74. foxes/input/farm_layout/from_arrays.py +68 -0
  75. foxes/input/farm_layout/from_csv.py +1 -1
  76. foxes/input/farm_layout/ring.py +0 -1
  77. foxes/input/states/__init__.py +28 -12
  78. foxes/input/states/create/__init__.py +3 -2
  79. foxes/input/states/dataset_states.py +710 -0
  80. foxes/input/states/field_data.py +531 -0
  81. foxes/input/states/multi_height.py +11 -6
  82. foxes/input/states/one_point_flow.py +1 -4
  83. foxes/input/states/point_cloud_data.py +618 -0
  84. foxes/input/states/scan.py +2 -0
  85. foxes/input/states/single.py +3 -1
  86. foxes/input/states/states_table.py +23 -30
  87. foxes/input/states/weibull_sectors.py +330 -0
  88. foxes/input/states/wrg_states.py +8 -6
  89. foxes/input/yaml/__init__.py +9 -3
  90. foxes/input/yaml/dict.py +42 -41
  91. foxes/input/yaml/windio/__init__.py +10 -5
  92. foxes/input/yaml/windio/read_attributes.py +42 -29
  93. foxes/input/yaml/windio/read_farm.py +17 -15
  94. foxes/input/yaml/windio/read_fields.py +4 -2
  95. foxes/input/yaml/windio/read_outputs.py +25 -15
  96. foxes/input/yaml/windio/read_site.py +172 -11
  97. foxes/input/yaml/windio/windio.py +23 -11
  98. foxes/input/yaml/yaml.py +1 -0
  99. foxes/models/__init__.py +15 -14
  100. foxes/models/axial_induction/__init__.py +2 -2
  101. foxes/models/farm_controllers/__init__.py +1 -1
  102. foxes/models/farm_models/__init__.py +1 -1
  103. foxes/models/ground_models/__init__.py +3 -2
  104. foxes/models/ground_models/wake_mirror.py +3 -3
  105. foxes/models/model_book.py +190 -63
  106. foxes/models/partial_wakes/__init__.py +6 -6
  107. foxes/models/partial_wakes/axiwake.py +30 -5
  108. foxes/models/partial_wakes/centre.py +47 -0
  109. foxes/models/partial_wakes/rotor_points.py +41 -11
  110. foxes/models/partial_wakes/segregated.py +2 -25
  111. foxes/models/partial_wakes/top_hat.py +27 -2
  112. foxes/models/point_models/__init__.py +4 -4
  113. foxes/models/rotor_models/__init__.py +4 -3
  114. foxes/models/rotor_models/centre.py +1 -1
  115. foxes/models/rotor_models/direct_infusion.py +241 -0
  116. foxes/models/turbine_models/__init__.py +11 -11
  117. foxes/models/turbine_models/calculator.py +16 -3
  118. foxes/models/turbine_models/kTI_model.py +1 -0
  119. foxes/models/turbine_models/lookup_table.py +2 -0
  120. foxes/models/turbine_models/power_mask.py +1 -0
  121. foxes/models/turbine_models/rotor_centre_calc.py +2 -0
  122. foxes/models/turbine_models/sector_management.py +1 -0
  123. foxes/models/turbine_models/set_farm_vars.py +3 -9
  124. foxes/models/turbine_models/table_factors.py +2 -0
  125. foxes/models/turbine_models/thrust2ct.py +1 -0
  126. foxes/models/turbine_models/yaw2yawm.py +2 -0
  127. foxes/models/turbine_models/yawm2yaw.py +2 -0
  128. foxes/models/turbine_types/PCt_file.py +2 -6
  129. foxes/models/turbine_types/PCt_from_two.py +1 -2
  130. foxes/models/turbine_types/__init__.py +10 -9
  131. foxes/models/turbine_types/calculator_type.py +123 -0
  132. foxes/models/turbine_types/null_type.py +1 -0
  133. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
  134. foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
  135. foxes/models/vertical_profiles/__init__.py +7 -7
  136. foxes/models/wake_deflections/__init__.py +3 -0
  137. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  138. foxes/models/wake_deflections/jimenez.py +277 -0
  139. foxes/models/wake_deflections/no_deflection.py +94 -0
  140. foxes/models/wake_frames/__init__.py +6 -7
  141. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  142. foxes/models/wake_frames/rotor_wd.py +3 -1
  143. foxes/models/wake_frames/seq_dynamic_wakes.py +41 -7
  144. foxes/models/wake_frames/streamlines.py +8 -6
  145. foxes/models/wake_frames/timelines.py +9 -3
  146. foxes/models/wake_models/__init__.py +7 -7
  147. foxes/models/wake_models/dist_sliced.py +50 -84
  148. foxes/models/wake_models/gaussian.py +20 -0
  149. foxes/models/wake_models/induction/__init__.py +5 -5
  150. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  151. foxes/models/wake_models/induction/rathmann.py +65 -64
  152. foxes/models/wake_models/induction/self_similar.py +65 -68
  153. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  154. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  155. foxes/models/wake_models/ti/__init__.py +2 -2
  156. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  157. foxes/models/wake_models/ti/iec_ti.py +6 -4
  158. foxes/models/wake_models/top_hat.py +58 -7
  159. foxes/models/wake_models/wind/__init__.py +6 -4
  160. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  161. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  162. foxes/models/wake_models/wind/jensen.py +15 -2
  163. foxes/models/wake_models/wind/turbopark.py +28 -2
  164. foxes/models/wake_superpositions/__init__.py +18 -9
  165. foxes/models/wake_superpositions/ti_linear.py +4 -4
  166. foxes/models/wake_superpositions/ti_max.py +4 -4
  167. foxes/models/wake_superpositions/ti_pow.py +4 -4
  168. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  169. foxes/models/wake_superpositions/wind_vector.py +257 -0
  170. foxes/models/wake_superpositions/ws_linear.py +9 -10
  171. foxes/models/wake_superpositions/ws_max.py +8 -8
  172. foxes/models/wake_superpositions/ws_pow.py +8 -8
  173. foxes/models/wake_superpositions/ws_product.py +4 -4
  174. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  175. foxes/output/__init__.py +21 -19
  176. foxes/output/farm_layout.py +4 -2
  177. foxes/output/farm_results_eval.py +19 -16
  178. foxes/output/flow_plots_2d/__init__.py +2 -2
  179. foxes/output/flow_plots_2d/flow_plots.py +18 -0
  180. foxes/output/flow_plots_2d/get_fig.py +5 -2
  181. foxes/output/output.py +6 -1
  182. foxes/output/results_writer.py +1 -1
  183. foxes/output/rose_plot.py +13 -3
  184. foxes/output/rotor_point_plots.py +3 -0
  185. foxes/output/seq_plugins/__init__.py +2 -2
  186. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  187. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  188. foxes/output/state_turbine_map.py +3 -0
  189. foxes/output/turbine_type_curves.py +10 -8
  190. foxes/utils/__init__.py +37 -19
  191. foxes/utils/abl/__init__.py +4 -4
  192. foxes/utils/cubic_roots.py +1 -1
  193. foxes/utils/data_book.py +4 -3
  194. foxes/utils/dict.py +49 -37
  195. foxes/utils/exec_python.py +5 -5
  196. foxes/utils/factory.py +3 -5
  197. foxes/utils/geom2d/__init__.py +7 -5
  198. foxes/utils/geopandas_utils.py +2 -2
  199. foxes/utils/pandas_utils.py +4 -3
  200. foxes/utils/tab_files.py +0 -1
  201. foxes/utils/weibull.py +28 -0
  202. foxes/utils/wrg_utils.py +3 -1
  203. foxes/utils/xarray_utils.py +9 -2
  204. foxes/variables.py +67 -9
  205. {foxes-1.3.dist-info → foxes-1.5.dist-info}/METADATA +34 -63
  206. foxes-1.5.dist-info/RECORD +328 -0
  207. {foxes-1.3.dist-info → foxes-1.5.dist-info}/WHEEL +1 -1
  208. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  209. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +1 -1
  210. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  211. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  212. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  213. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +0 -1
  214. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
  215. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
  216. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
  217. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
  218. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  219. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
  220. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  221. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +0 -1
  222. foxes/input/states/field_data_nc.py +0 -847
  223. foxes/output/round.py +0 -10
  224. foxes/utils/pandas_helpers.py +0 -178
  225. foxes-1.3.dist-info/RECORD +0 -313
  226. {foxes-1.3.dist-info → foxes-1.5.dist-info}/entry_points.txt +0 -0
  227. {foxes-1.3.dist-info → foxes-1.5.dist-info/licenses}/LICENSE +0 -0
  228. {foxes-1.3.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,123 @@
1
+ from foxes.core import TurbineType
2
+
3
+
4
+ class CalculatorType(TurbineType):
5
+ """
6
+ Direct data infusion by a user function.
7
+
8
+ :group: models.turbine_types
9
+
10
+ """
11
+
12
+ def __init__(
13
+ self,
14
+ func,
15
+ out_vars,
16
+ *args,
17
+ needs_rews2=False,
18
+ needs_rews3=False,
19
+ **kwargs,
20
+ ):
21
+ """
22
+ Constructor.
23
+
24
+ Parameters
25
+ ----------
26
+ func: callable
27
+ The function to calculate farm variables, should have the signature:
28
+ f(algo, mdata, fdata, st_sel) -> dict, where the keys are
29
+ output variable names and the values are numpy.ndarrays
30
+ with shape (n_states, n_turbines).
31
+
32
+ Beware that the turbine ordering in fdata is in downwind order,
33
+ hence external data X of shape (n_states, n_turbines) in farm order
34
+ needs to be reordered by X[ssel, order] with
35
+ ssel = fdata[FV.ORDER_SSEL], order = fdata[FV.ORDER]
36
+ before using it in combination with fdata variables.
37
+ out_vars: list of str
38
+ The output variables of the function
39
+ args: tuple, optional
40
+ Additional parameters for TurbineType class
41
+ needs_rews2: bool
42
+ Flag for runs that require the REWS2 variable
43
+ needs_rews3: bool
44
+ Flag for runs that require the REWS3 variable
45
+ kwargs: dict, optional
46
+ Additional parameters for TurbineType class
47
+
48
+ """
49
+ super().__init__(*args, **kwargs)
50
+ self._func = func
51
+ self._ovars = out_vars
52
+ self._rews2 = needs_rews2
53
+ self._rews3 = needs_rews3
54
+
55
+ def needs_rews2(self):
56
+ """
57
+ Returns flag for requiring REWS2 variable
58
+
59
+ Returns
60
+ -------
61
+ flag: bool
62
+ True if REWS2 is required
63
+
64
+ """
65
+ return self._rews2
66
+
67
+ def needs_rews3(self):
68
+ """
69
+ Returns flag for requiring REWS3 variable
70
+
71
+ Returns
72
+ -------
73
+ flag: bool
74
+ True if REWS3 is required
75
+
76
+ """
77
+ return self._rews3
78
+
79
+ def output_farm_vars(self, algo):
80
+ """
81
+ The variables which are being modified by the model.
82
+
83
+ Parameters
84
+ ----------
85
+ algo: foxes.core.Algorithm
86
+ The calculation algorithm
87
+
88
+ Returns
89
+ -------
90
+ output_vars: list of str
91
+ The output variable names
92
+
93
+ """
94
+ return self._ovars
95
+
96
+ def calculate(self, algo, mdata, fdata, st_sel):
97
+ """
98
+ The main model calculation.
99
+
100
+ This function is executed on a single chunk of data,
101
+ all computations should be based on numpy arrays.
102
+
103
+ Parameters
104
+ ----------
105
+ algo: foxes.core.Algorithm
106
+ The calculation algorithm
107
+ mdata: foxes.core.MData
108
+ The model data
109
+ fdata: foxes.core.FData
110
+ The farm data
111
+ st_sel: numpy.ndarray of bool
112
+ The state-turbine selection,
113
+ shape: (n_states, n_turbines)
114
+
115
+ Returns
116
+ -------
117
+ results: dict
118
+ The resulting data, keys: output variable str.
119
+ Values: numpy.ndarray with shape (n_states, n_turbines)
120
+
121
+ """
122
+ self.ensure_output_vars(algo, fdata)
123
+ return self._func(algo, mdata, fdata, st_sel)
@@ -102,4 +102,5 @@ class NullType(TurbineType):
102
102
  Values: numpy.ndarray with shape (n_states, n_turbines)
103
103
 
104
104
  """
105
+ self.ensure_output_vars(algo, fdata)
105
106
  return {}
@@ -262,6 +262,8 @@ class WsRho2PCtFromTwo(TurbineType):
262
262
  Values: numpy.ndarray with shape (n_states, n_turbines)
263
263
 
264
264
  """
265
+ # prepare:
266
+ self.ensure_output_vars(algo, fdata)
265
267
 
266
268
  # calculate P:
267
269
  st_sel_P = (
@@ -5,8 +5,8 @@ from scipy.interpolate import interpn
5
5
  from foxes.core import TurbineType
6
6
  from foxes.utils import PandasFileHelper
7
7
  from foxes.data import PCTCURVE, parse_Pct_two_files
8
- import foxes.variables as FV
9
8
  from foxes.config import config, get_input_path
9
+ import foxes.variables as FV
10
10
 
11
11
 
12
12
  class WsTI2PCtFromTwo(TurbineType):
@@ -274,6 +274,8 @@ class WsTI2PCtFromTwo(TurbineType):
274
274
  Values: numpy.ndarray with shape (n_states, n_turbines)
275
275
 
276
276
  """
277
+ # prepare:
278
+ self.ensure_output_vars(algo, fdata)
277
279
 
278
280
  # calculate P:
279
281
  st_sel_P = (
@@ -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
@@ -0,0 +1,3 @@
1
+ from .no_deflection import NoDeflection as NoDeflection
2
+ from .bastankhah2016 import Bastankhah2016Deflection as Bastankhah2016Deflection
3
+ from .jimenez import JimenezDeflection as JimenezDeflection
@@ -1,18 +1,17 @@
1
1
  import numpy as np
2
2
 
3
- from foxes.core import WakeFrame, WakeK, TData
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 YawedWakes(WakeFrame):
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
- model_pars: dict
32
- Model parameters
33
- YAWM: float
34
- The yaw misalignment YAWM. If not given here
35
- it will be searched in the farm data.
36
- base_frame: foxes.core.WakeFrame
37
- The wake frame from which to start
38
-
39
- :group: models.wake_frames
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__(max_length_km=max_length_km)
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.base_frame, self.model]
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 get_wake_coos(
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
- Calculate wake coordinates of rotor points.
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
- wake_coos: numpy.ndarray
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", xyz[..., :2], tdata[FC.TWEIGHTS])
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
- xyz[..., 1] = y[:, :, None]
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 points
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