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.

Files changed (201) 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/induction/run.py +3 -3
  7. examples/multi_height/run.py +1 -1
  8. examples/power_mask/run.py +2 -2
  9. examples/quickstart/run.py +16 -0
  10. examples/random_timeseries/run.py +3 -4
  11. examples/scan_row/run.py +3 -3
  12. examples/sequential/run.py +33 -10
  13. examples/single_state/run.py +3 -4
  14. examples/states_lookup_table/run.py +3 -3
  15. examples/streamline_wakes/run.py +27 -4
  16. examples/tab_file/run.py +3 -3
  17. examples/timelines/run.py +29 -5
  18. examples/timeseries/run.py +3 -3
  19. examples/timeseries_slurm/run.py +3 -3
  20. examples/wind_rose/run.py +3 -3
  21. examples/yawed_wake/run.py +16 -8
  22. foxes/__init__.py +22 -18
  23. foxes/algorithms/__init__.py +6 -6
  24. foxes/algorithms/downwind/__init__.py +2 -2
  25. foxes/algorithms/downwind/downwind.py +53 -27
  26. foxes/algorithms/downwind/models/__init__.py +6 -6
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +22 -14
  28. foxes/algorithms/downwind/models/init_farm_data.py +4 -5
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
  31. foxes/algorithms/downwind/models/set_amb_point_results.py +7 -7
  32. foxes/algorithms/iterative/__init__.py +7 -3
  33. foxes/algorithms/iterative/iterative.py +1 -2
  34. foxes/algorithms/iterative/models/__init__.py +7 -3
  35. foxes/algorithms/iterative/models/farm_wakes_calc.py +15 -8
  36. foxes/algorithms/sequential/__init__.py +3 -3
  37. foxes/algorithms/sequential/models/__init__.py +2 -2
  38. foxes/algorithms/sequential/models/seq_state.py +0 -18
  39. foxes/algorithms/sequential/sequential.py +8 -22
  40. foxes/config/__init__.py +5 -1
  41. foxes/constants.py +22 -0
  42. foxes/core/__init__.py +45 -22
  43. foxes/core/algorithm.py +0 -1
  44. foxes/core/data.py +56 -29
  45. foxes/core/engine.py +28 -14
  46. foxes/core/farm_controller.py +2 -2
  47. foxes/core/farm_data_model.py +1 -0
  48. foxes/core/ground_model.py +4 -13
  49. foxes/core/model.py +5 -5
  50. foxes/core/partial_wakes_model.py +147 -10
  51. foxes/core/point_data_model.py +2 -3
  52. foxes/core/rotor_model.py +42 -38
  53. foxes/core/states.py +4 -50
  54. foxes/core/turbine.py +2 -1
  55. foxes/core/wake_deflection.py +130 -0
  56. foxes/core/wake_model.py +222 -9
  57. foxes/core/wake_superposition.py +122 -4
  58. foxes/core/wind_farm.py +6 -6
  59. foxes/data/__init__.py +7 -2
  60. foxes/data/states/weibull_sectors_12.csv +13 -0
  61. foxes/data/states/weibull_sectors_12.nc +0 -0
  62. foxes/engines/__init__.py +14 -15
  63. foxes/engines/dask.py +39 -14
  64. foxes/engines/numpy.py +0 -3
  65. foxes/input/__init__.py +3 -3
  66. foxes/input/farm_layout/__init__.py +8 -8
  67. foxes/input/farm_layout/from_csv.py +1 -1
  68. foxes/input/farm_layout/ring.py +0 -1
  69. foxes/input/states/__init__.py +22 -11
  70. foxes/input/states/create/__init__.py +3 -2
  71. foxes/input/states/field_data_nc.py +48 -84
  72. foxes/input/states/multi_height.py +40 -60
  73. foxes/input/states/one_point_flow.py +22 -25
  74. foxes/input/states/scan.py +6 -19
  75. foxes/input/states/single.py +6 -18
  76. foxes/input/states/states_table.py +25 -44
  77. foxes/input/states/weibull_sectors.py +225 -0
  78. foxes/input/states/wrg_states.py +151 -37
  79. foxes/input/yaml/__init__.py +9 -3
  80. foxes/input/yaml/dict.py +19 -19
  81. foxes/input/yaml/windio/__init__.py +10 -5
  82. foxes/input/yaml/windio/read_attributes.py +2 -2
  83. foxes/input/yaml/windio/read_farm.py +5 -5
  84. foxes/input/yaml/windio/read_fields.py +4 -2
  85. foxes/input/yaml/windio/read_site.py +52 -0
  86. foxes/input/yaml/windio/windio.py +1 -1
  87. foxes/models/__init__.py +15 -14
  88. foxes/models/axial_induction/__init__.py +2 -2
  89. foxes/models/farm_controllers/__init__.py +1 -1
  90. foxes/models/farm_models/__init__.py +1 -1
  91. foxes/models/ground_models/__init__.py +3 -2
  92. foxes/models/ground_models/wake_mirror.py +3 -3
  93. foxes/models/model_book.py +175 -49
  94. foxes/models/partial_wakes/__init__.py +6 -6
  95. foxes/models/partial_wakes/axiwake.py +30 -5
  96. foxes/models/partial_wakes/centre.py +47 -0
  97. foxes/models/partial_wakes/rotor_points.py +45 -9
  98. foxes/models/partial_wakes/segregated.py +2 -20
  99. foxes/models/partial_wakes/top_hat.py +27 -2
  100. foxes/models/point_models/__init__.py +4 -4
  101. foxes/models/rotor_models/__init__.py +3 -3
  102. foxes/models/rotor_models/centre.py +6 -4
  103. foxes/models/turbine_models/__init__.py +11 -11
  104. foxes/models/turbine_models/set_farm_vars.py +0 -1
  105. foxes/models/turbine_types/PCt_file.py +0 -2
  106. foxes/models/turbine_types/PCt_from_two.py +0 -2
  107. foxes/models/turbine_types/__init__.py +9 -9
  108. foxes/models/vertical_profiles/__init__.py +7 -7
  109. foxes/models/wake_deflections/__init__.py +3 -0
  110. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  111. foxes/models/wake_deflections/jimenez.py +277 -0
  112. foxes/models/wake_deflections/no_deflection.py +94 -0
  113. foxes/models/wake_frames/__init__.py +6 -7
  114. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  115. foxes/models/wake_frames/rotor_wd.py +3 -1
  116. foxes/models/wake_frames/seq_dynamic_wakes.py +45 -8
  117. foxes/models/wake_frames/streamlines.py +8 -6
  118. foxes/models/wake_frames/timelines.py +19 -3
  119. foxes/models/wake_models/__init__.py +7 -7
  120. foxes/models/wake_models/dist_sliced.py +50 -84
  121. foxes/models/wake_models/gaussian.py +20 -0
  122. foxes/models/wake_models/induction/__init__.py +5 -5
  123. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  124. foxes/models/wake_models/induction/rathmann.py +65 -64
  125. foxes/models/wake_models/induction/self_similar.py +65 -68
  126. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  127. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  128. foxes/models/wake_models/ti/__init__.py +2 -2
  129. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  130. foxes/models/wake_models/ti/iec_ti.py +6 -4
  131. foxes/models/wake_models/top_hat.py +58 -7
  132. foxes/models/wake_models/wind/__init__.py +6 -4
  133. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  134. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  135. foxes/models/wake_models/wind/jensen.py +15 -2
  136. foxes/models/wake_models/wind/turbopark.py +28 -2
  137. foxes/models/wake_superpositions/__init__.py +18 -9
  138. foxes/models/wake_superpositions/ti_linear.py +4 -4
  139. foxes/models/wake_superpositions/ti_max.py +4 -4
  140. foxes/models/wake_superpositions/ti_pow.py +4 -4
  141. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  142. foxes/models/wake_superpositions/wind_vector.py +257 -0
  143. foxes/models/wake_superpositions/ws_linear.py +9 -10
  144. foxes/models/wake_superpositions/ws_max.py +8 -8
  145. foxes/models/wake_superpositions/ws_pow.py +8 -8
  146. foxes/models/wake_superpositions/ws_product.py +4 -4
  147. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  148. foxes/output/__init__.py +21 -19
  149. foxes/output/farm_layout.py +14 -6
  150. foxes/output/farm_results_eval.py +51 -27
  151. foxes/output/flow_plots_2d/__init__.py +2 -2
  152. foxes/output/flow_plots_2d/get_fig.py +4 -2
  153. foxes/output/rose_plot.py +23 -5
  154. foxes/output/seq_plugins/__init__.py +2 -2
  155. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  156. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  157. foxes/output/slice_data.py +16 -19
  158. foxes/output/turbine_type_curves.py +7 -8
  159. foxes/utils/__init__.py +37 -19
  160. foxes/utils/abl/__init__.py +4 -4
  161. foxes/utils/cubic_roots.py +1 -1
  162. foxes/utils/data_book.py +4 -3
  163. foxes/utils/dict.py +3 -3
  164. foxes/utils/exec_python.py +5 -5
  165. foxes/utils/factory.py +1 -3
  166. foxes/utils/geom2d/__init__.py +7 -5
  167. foxes/utils/geopandas_utils.py +2 -2
  168. foxes/utils/pandas_utils.py +4 -3
  169. foxes/utils/tab_files.py +0 -1
  170. foxes/utils/weibull.py +28 -0
  171. foxes/utils/wrg_utils.py +3 -1
  172. foxes/utils/xarray_utils.py +9 -2
  173. foxes/variables.py +67 -9
  174. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/METADATA +14 -21
  175. foxes-1.4.dist-info/RECORD +320 -0
  176. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
  177. tests/0_consistency/iterative/test_iterative.py +2 -3
  178. tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
  179. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  180. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
  181. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  182. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
  183. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  184. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  185. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -3
  186. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -4
  187. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -4
  188. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -4
  189. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -4
  190. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  191. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
  192. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -3
  193. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  194. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -4
  195. tests/3_examples/test_examples.py +3 -2
  196. foxes/output/round.py +0 -10
  197. foxes/utils/pandas_helpers.py +0 -178
  198. foxes-1.2.5.dist-info/RECORD +0 -312
  199. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
  200. {foxes-1.2.5.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
  201. {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
- weights,
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(weights) > 1:
127
+ if len(rpoint_weights) > 1:
128
128
  return super().eval_rpoint_results(
129
- algo, mdata, fdata, rpoint_results, weights, downwind_index
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
@@ -270,7 +270,6 @@ class SetFarmVars(TurbineModel):
270
270
  """
271
271
  i0 = mdata.states_i0(counter=True)
272
272
  if not self.once or i0 not in self.__once_done:
273
-
274
273
  if self.pre_rotor:
275
274
  order = np.s_[:]
276
275
  ssel = np.s_[:]
@@ -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
@@ -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