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
@@ -95,8 +95,8 @@ class TILinear(WakeSuperposition):
95
95
  algo,
96
96
  mdata,
97
97
  fdata,
98
+ tdata,
98
99
  variable,
99
- amb_results,
100
100
  wake_delta,
101
101
  ):
102
102
  """
@@ -111,11 +111,10 @@ class TILinear(WakeSuperposition):
111
111
  The model data
112
112
  fdata: foxes.core.FData
113
113
  The farm data
114
+ tdata: foxes.core.TData
115
+ The target point data
114
116
  variable: str
115
117
  The variable name for which the wake deltas applies
116
- amb_results: numpy.ndarray
117
- The ambient results at targets,
118
- shape: (n_states, n_targets, n_tpoints)
119
118
  wake_delta: numpy.ndarray
120
119
  The wake deltas at targets, shape:
121
120
  (n_states, n_targets, n_tpoints)
@@ -134,6 +133,7 @@ class TILinear(WakeSuperposition):
134
133
 
135
134
  # quadratic superposition to ambient:
136
135
  elif self.superp_to_amb == "quadratic":
136
+ amb_results = tdata[FV.var2amb[variable]]
137
137
  return np.sqrt(wake_delta**2 + amb_results**2) - amb_results
138
138
 
139
139
  # unknown ti delta:
@@ -95,8 +95,8 @@ class TIMax(WakeSuperposition):
95
95
  algo,
96
96
  mdata,
97
97
  fdata,
98
+ tdata,
98
99
  variable,
99
- amb_results,
100
100
  wake_delta,
101
101
  ):
102
102
  """
@@ -111,11 +111,10 @@ class TIMax(WakeSuperposition):
111
111
  The model data
112
112
  fdata: foxes.core.FData
113
113
  The farm data
114
+ tdata: foxes.core.TData
115
+ The target point data
114
116
  variable: str
115
117
  The variable name for which the wake deltas applies
116
- amb_results: numpy.ndarray
117
- The ambient results at targets,
118
- shape: (n_states, n_targets, n_tpoints)
119
118
  wake_delta: numpy.ndarray
120
119
  The wake deltas at targets, shape:
121
120
  (n_states, n_targets, n_tpoints)
@@ -134,6 +133,7 @@ class TIMax(WakeSuperposition):
134
133
 
135
134
  # quadratic superposition to ambient:
136
135
  elif self.superp_to_amb == "quadratic":
136
+ amb_results = tdata[FV.var2amb[variable]]
137
137
  return np.sqrt(wake_delta**2 + amb_results**2) - amb_results
138
138
 
139
139
  # unknown ti delta:
@@ -102,8 +102,8 @@ class TIPow(WakeSuperposition):
102
102
  algo,
103
103
  mdata,
104
104
  fdata,
105
+ tdata,
105
106
  variable,
106
- amb_results,
107
107
  wake_delta,
108
108
  ):
109
109
  """
@@ -118,11 +118,10 @@ class TIPow(WakeSuperposition):
118
118
  The model data
119
119
  fdata: foxes.core.FData
120
120
  The farm data
121
+ tdata: foxes.core.TData
122
+ The target point data
121
123
  variable: str
122
124
  The variable name for which the wake deltas applies
123
- amb_results: numpy.ndarray
124
- The ambient results at targets,
125
- shape: (n_states, n_targets, n_tpoints)
126
125
  wake_delta: numpy.ndarray
127
126
  The wake deltas at targets, shape:
128
127
  (n_states, n_targets, n_tpoints)
@@ -141,6 +140,7 @@ class TIPow(WakeSuperposition):
141
140
 
142
141
  # quadratic superposition to ambient:
143
142
  elif self.superp_to_amb == "quadratic":
143
+ amb_results = tdata[FV.var2amb[variable]]
144
144
  return np.sqrt(wake_delta ** (2 / self.pow) + amb_results**2) - amb_results
145
145
 
146
146
  # unknown ti delta:
@@ -95,8 +95,8 @@ class TIQuadratic(WakeSuperposition):
95
95
  algo,
96
96
  mdata,
97
97
  fdata,
98
+ tdata,
98
99
  variable,
99
- amb_results,
100
100
  wake_delta,
101
101
  ):
102
102
  """
@@ -111,11 +111,10 @@ class TIQuadratic(WakeSuperposition):
111
111
  The model data
112
112
  fdata: foxes.core.FData
113
113
  The farm data
114
+ tdata: foxes.core.TData
115
+ The target point data
114
116
  variable: str
115
117
  The variable name for which the wake deltas applies
116
- amb_results: numpy.ndarray
117
- The ambient results at targets,
118
- shape: (n_states, n_targets, n_tpoints)
119
118
  wake_delta: numpy.ndarray
120
119
  The wake deltas at targets, shape:
121
120
  (n_states, n_targets, n_tpoints)
@@ -134,6 +133,7 @@ class TIQuadratic(WakeSuperposition):
134
133
 
135
134
  # quadratic superposition to ambient:
136
135
  elif self.superp_to_amb == "quadratic":
136
+ amb_results = tdata[FV.var2amb[variable]]
137
137
  return np.sqrt(wake_delta + amb_results**2) - amb_results
138
138
 
139
139
  # unknown ti delta:
@@ -0,0 +1,257 @@
1
+ import numpy as np
2
+
3
+ from foxes.core import WindVectorWakeSuperposition
4
+ from foxes.utils import wd2uv, uv2wd, delta_wd
5
+ import foxes.variables as FV
6
+ import foxes.constants as FC
7
+
8
+
9
+ class WindVectorLinear(WindVectorWakeSuperposition):
10
+ """
11
+ Linear superposition of wind deficit vector results
12
+
13
+ Attributes
14
+ ----------
15
+ scale_amb: bool
16
+ Flag for scaling wind deficit with ambient wind speed
17
+ instead of waked wind speed
18
+
19
+ :group: models.wake_superpositions
20
+
21
+ """
22
+
23
+ def __init__(self, scale_amb=False):
24
+ """
25
+ Constructor.
26
+
27
+ Parameters
28
+ ----------
29
+ scale_amb: bool
30
+ Flag for scaling wind deficit with ambient wind speed
31
+ instead of waked wind speed
32
+
33
+ """
34
+ super().__init__()
35
+ self.scale_amb = scale_amb
36
+
37
+ def __repr__(self):
38
+ a = f"scale_amb={self.scale_amb}"
39
+ return f"{type(self).__name__}({a})"
40
+
41
+ def input_farm_vars(self, algo):
42
+ """
43
+ The variables which are needed for running
44
+ the model.
45
+
46
+ Parameters
47
+ ----------
48
+ algo: foxes.core.Algorithm
49
+ The calculation algorithm
50
+
51
+ Returns
52
+ -------
53
+ input_vars: list of str
54
+ The input variable names
55
+
56
+ """
57
+ return [FV.AMB_REWS] if self.scale_amb else [FV.REWS]
58
+
59
+ def wdeltas_ws2uv(self, algo, fdata, tdata, downwind_index, wdeltas, st_sel):
60
+ """
61
+ Transform results from wind speed to wind vector data
62
+
63
+ Parameters
64
+ ----------
65
+ algo: foxes.core.Algorithm
66
+ The calculation algorithm
67
+ fdata: foxes.core.FData
68
+ The farm data
69
+ tdata: foxes.core.TData
70
+ The target point data
71
+ downwind_index: int
72
+ The index of the wake causing turbine
73
+ in the downwind order
74
+ wdeltas: dict
75
+ The wake deltas. Key: variable name str,
76
+ value: numpy.ndarray, shape: (n_st_sel, n_tpoints)
77
+ st_sel: numpy.ndarray of bool
78
+ The state-target selection, for which the wake
79
+ is non-zero, shape: (n_states, n_targets)
80
+
81
+ Returns
82
+ -------
83
+ wdeltas: dict
84
+ The wake deltas. Key: variable name str,
85
+ value: numpy.ndarray, now respecting has_uv flag
86
+
87
+ """
88
+ if FV.AMB_UV not in tdata:
89
+ tdata[FV.AMB_UV] = wd2uv(tdata[FV.AMB_WD], tdata[FV.AMB_WS])
90
+ if FV.UV not in wdeltas:
91
+ assert FV.WS in wdeltas, (
92
+ f"{self.name}: Expecting '{FV.WS}' in wdeltas, got {list(wdeltas.keys())}"
93
+ )
94
+ scale = self.get_data(
95
+ FV.AMB_REWS if self.scale_amb else FV.REWS,
96
+ FC.STATE_TARGET_TPOINT,
97
+ lookup="w",
98
+ algo=algo,
99
+ fdata=fdata,
100
+ tdata=tdata,
101
+ downwind_index=downwind_index,
102
+ upcast=False,
103
+ selection=st_sel,
104
+ )
105
+ ws0 = tdata[FV.AMB_WS][st_sel]
106
+ wd0 = tdata[FV.AMB_WD][st_sel]
107
+ dws = scale * wdeltas.pop(FV.WS)
108
+ dwd = wdeltas.pop(FV.WD, 0)
109
+ wdeltas[FV.UV] = wd2uv(wd0 + dwd, ws0 + dws) - tdata[FV.AMB_UV][st_sel]
110
+
111
+ return wdeltas
112
+
113
+ def wdeltas_uv2ws(self, algo, fdata, tdata, downwind_index, wdeltas, st_sel):
114
+ """
115
+ Transform results from wind vector to wind speed data
116
+
117
+ Parameters
118
+ ----------
119
+ algo: foxes.core.Algorithm
120
+ The calculation algorithm
121
+ fdata: foxes.core.FData
122
+ The farm data
123
+ tdata: foxes.core.TData
124
+ The target point data
125
+ downwind_index: int
126
+ The index of the wake causing turbine
127
+ in the downwind order
128
+ wdeltas: dict
129
+ The wake deltas. Key: variable name str,
130
+ value: numpy.ndarray, shape: (n_st_sel, n_tpoints)
131
+ st_sel: numpy.ndarray of bool
132
+ The state-target selection, for which the wake
133
+ is non-zero, shape: (n_states, n_targets)
134
+
135
+ Returns
136
+ -------
137
+ wdeltas: dict
138
+ The wake deltas. Key: variable name str,
139
+ value: numpy.ndarray, now respecting has_uv flag
140
+
141
+ """
142
+ if FV.UV in wdeltas:
143
+ scale = self.get_data(
144
+ FV.AMB_REWS if self.scale_amb else FV.REWS,
145
+ FC.STATE_TARGET_TPOINT,
146
+ lookup="w",
147
+ algo=algo,
148
+ fdata=fdata,
149
+ tdata=tdata,
150
+ downwind_index=downwind_index,
151
+ upcast=False,
152
+ selection=st_sel,
153
+ )
154
+ ws0 = tdata[FV.AMB_WS][st_sel]
155
+ wd0 = tdata[FV.AMB_WD][st_sel]
156
+ uv = tdata[FV.AMB_UV][st_sel] + wdeltas.pop(FV.UV)
157
+ wdeltas[FV.WD] = delta_wd(wd0, uv2wd(uv))
158
+ wdeltas[FV.WS] = (np.linalg.norm(uv, axis=-1) - ws0) / scale
159
+
160
+ return wdeltas
161
+
162
+ def add_wake_vector(
163
+ self,
164
+ algo,
165
+ mdata,
166
+ fdata,
167
+ tdata,
168
+ downwind_index,
169
+ st_sel,
170
+ wake_delta_uv,
171
+ wake_model_result_uv,
172
+ ):
173
+ """
174
+ Add a wake delta vector to previous wake deltas,
175
+ at rotor points.
176
+
177
+ Parameters
178
+ ----------
179
+ algo: foxes.core.Algorithm
180
+ The calculation algorithm
181
+ mdata: foxes.core.MData
182
+ The model data
183
+ fdata: foxes.core.FData
184
+ The farm data
185
+ tdata: foxes.core.TData
186
+ The target point data
187
+ downwind_index: int
188
+ The index of the wake causing turbine
189
+ in the downwind order
190
+ st_sel: numpy.ndarray of bool
191
+ The selection of targets, shape: (n_states, n_targets)
192
+ wake_delta_uv: numpy.ndarray
193
+ The original wind vector wake deltas, shape:
194
+ (n_states, n_targets, n_tpoints, 2)
195
+ wake_model_result_uv: numpy.ndarray
196
+ The new wind vector wake deltas of the selected rotors,
197
+ shape: (n_st_sel, n_tpoints, 2, ...)
198
+
199
+ Returns
200
+ -------
201
+ wdelta_uv: numpy.ndarray
202
+ The updated wind vector wake deltas, shape:
203
+ (n_states, n_targets, n_tpoints, ...)
204
+
205
+ """
206
+
207
+ if np.any(st_sel):
208
+ wake_delta_uv[st_sel] += wake_model_result_uv
209
+
210
+ return wake_delta_uv
211
+
212
+ def calc_final_wake_delta_uv(
213
+ self,
214
+ algo,
215
+ mdata,
216
+ fdata,
217
+ tdata,
218
+ wake_delta_uv,
219
+ ):
220
+ """
221
+ Calculate the final wind vector wake delta after adding all
222
+ contributions.
223
+
224
+ Parameters
225
+ ----------
226
+ algo: foxes.core.Algorithm
227
+ The calculation algorithm
228
+ mdata: foxes.core.MData
229
+ The model data
230
+ fdata: foxes.core.FData
231
+ The farm data
232
+ tdata: foxes.core.TData
233
+ The target point data
234
+ wake_delta_uv: numpy.ndarray
235
+ The original wind vector wake deltas, shape:
236
+ (n_states, n_targets, n_tpoints, 2)
237
+
238
+ Returns
239
+ -------
240
+ final_wake_delta_ws: numpy.ndarray
241
+ The final wind speed wake delta, which will be added to
242
+ the ambient results by simple plus operation. Shape:
243
+ (n_states, n_targets, n_tpoints)
244
+ final_wake_delta_wd: numpy.ndarray
245
+ The final wind direction wake delta, which will be added to
246
+ the ambient results by simple plus operation. Shape:
247
+ (n_states, n_targets, n_tpoints)
248
+
249
+ """
250
+ if FV.AMB_UV not in tdata:
251
+ tdata[FV.AMB_UV] = wd2uv(tdata[FV.AMB_WD], tdata[FV.AMB_WS])
252
+
253
+ uv = tdata[FV.AMB_UV] + wake_delta_uv
254
+ dwd = delta_wd(tdata[FV.AMB_WD], uv2wd(uv))
255
+ dws = np.linalg.norm(uv, axis=-1) - tdata[FV.AMB_WS]
256
+
257
+ return dws, dwd
@@ -140,8 +140,8 @@ class WSLinear(WakeSuperposition):
140
140
  algo,
141
141
  mdata,
142
142
  fdata,
143
+ tdata,
143
144
  variable,
144
- amb_results,
145
145
  wake_delta,
146
146
  ):
147
147
  """
@@ -156,11 +156,10 @@ class WSLinear(WakeSuperposition):
156
156
  The model data
157
157
  fdata: foxes.core.FData
158
158
  The farm data
159
+ tdata: foxes.core.TData
160
+ The target point data
159
161
  variable: str
160
162
  The variable name for which the wake deltas applies
161
- amb_results: numpy.ndarray
162
- The ambient results at targets,
163
- shape: (n_states, n_targets, n_tpoints)
164
163
  wake_delta: numpy.ndarray
165
164
  The wake deltas at targets, shape:
166
165
  (n_states, n_targets, n_tpoints)
@@ -175,9 +174,9 @@ class WSLinear(WakeSuperposition):
175
174
  """
176
175
  w = wake_delta
177
176
  if self.lim_low is not None:
178
- w = np.maximum(w, self.lim_low - amb_results)
177
+ w = np.maximum(w, self.lim_low - tdata[FV.var2amb[variable]])
179
178
  if self.lim_high is not None:
180
- w = np.minimum(w, self.lim_high - amb_results)
179
+ w = np.minimum(w, self.lim_high - tdata[FV.var2amb[variable]])
181
180
  return w
182
181
 
183
182
 
@@ -296,8 +295,8 @@ class WSLinearLocal(WakeSuperposition):
296
295
  algo,
297
296
  mdata,
298
297
  fdata,
298
+ tdata,
299
299
  variable,
300
- amb_results,
301
300
  wake_delta,
302
301
  ):
303
302
  """
@@ -312,11 +311,10 @@ class WSLinearLocal(WakeSuperposition):
312
311
  The model data
313
312
  fdata: foxes.core.FData
314
313
  The farm data
314
+ tdata: foxes.core.TData
315
+ The target point data
315
316
  variable: str
316
317
  The variable name for which the wake deltas applies
317
- amb_results: numpy.ndarray
318
- The ambient results at targets,
319
- shape: (n_states, n_targets, n_tpoints)
320
318
  wake_delta: numpy.ndarray
321
319
  The wake deltas at targets, shape:
322
320
  (n_states, n_targets, n_tpoints)
@@ -329,6 +327,7 @@ class WSLinearLocal(WakeSuperposition):
329
327
  (n_states, n_targets, n_tpoints)
330
328
 
331
329
  """
330
+ amb_results = tdata[FV.var2amb[variable]]
332
331
  w = wake_delta * amb_results
333
332
  if self.lim_low is not None:
334
333
  w = np.maximum(w, self.lim_low - amb_results)
@@ -143,8 +143,8 @@ class WSMax(WakeSuperposition):
143
143
  algo,
144
144
  mdata,
145
145
  fdata,
146
+ tdata,
146
147
  variable,
147
- amb_results,
148
148
  wake_delta,
149
149
  ):
150
150
  """
@@ -159,11 +159,10 @@ class WSMax(WakeSuperposition):
159
159
  The model data
160
160
  fdata: foxes.core.FData
161
161
  The farm data
162
+ tdata: foxes.core.TData
163
+ The target point data
162
164
  variable: str
163
165
  The variable name for which the wake deltas applies
164
- amb_results: numpy.ndarray
165
- The ambient results at targets,
166
- shape: (n_states, n_targets, n_tpoints)
167
166
  wake_delta: numpy.ndarray
168
167
  The wake deltas at targets, shape:
169
168
  (n_states, n_targets, n_tpoints)
@@ -176,6 +175,7 @@ class WSMax(WakeSuperposition):
176
175
  (n_states, n_targets, n_tpoints)
177
176
 
178
177
  """
178
+ amb_results = tdata[FV.var2amb[variable]]
179
179
  w = -wake_delta
180
180
  if self.lim_low is not None:
181
181
  w = np.maximum(w, self.lim_low - amb_results)
@@ -302,8 +302,8 @@ class WSMaxLocal(WakeSuperposition):
302
302
  algo,
303
303
  mdata,
304
304
  fdata,
305
+ tdata,
305
306
  variable,
306
- amb_results,
307
307
  wake_delta,
308
308
  ):
309
309
  """
@@ -318,11 +318,10 @@ class WSMaxLocal(WakeSuperposition):
318
318
  The model data
319
319
  fdata: foxes.core.FData
320
320
  The farm data
321
+ tdata: foxes.core.TData
322
+ The target point data
321
323
  variable: str
322
324
  The variable name for which the wake deltas applies
323
- amb_results: numpy.ndarray
324
- The ambient results at targets,
325
- shape: (n_states, n_targets, n_tpoints)
326
325
  wake_delta: numpy.ndarray
327
326
  The wake deltas at targets, shape:
328
327
  (n_states, n_targets, n_tpoints)
@@ -335,6 +334,7 @@ class WSMaxLocal(WakeSuperposition):
335
334
  (n_states, n_targets, n_tpoints)
336
335
 
337
336
  """
337
+ amb_results = tdata[FV.var2amb[variable]]
338
338
  w = -wake_delta * amb_results
339
339
  if self.lim_low is not None:
340
340
  w = np.maximum(w, self.lim_low - amb_results)
@@ -145,8 +145,8 @@ class WSPow(WakeSuperposition):
145
145
  algo,
146
146
  mdata,
147
147
  fdata,
148
+ tdata,
148
149
  variable,
149
- amb_results,
150
150
  wake_delta,
151
151
  ):
152
152
  """
@@ -161,11 +161,10 @@ class WSPow(WakeSuperposition):
161
161
  The model data
162
162
  fdata: foxes.core.FData
163
163
  The farm data
164
+ tdata: foxes.core.TData
165
+ The target point data
164
166
  variable: str
165
167
  The variable name for which the wake deltas applies
166
- amb_results: numpy.ndarray
167
- The ambient results at targets,
168
- shape: (n_states, n_targets, n_tpoints)
169
168
  wake_delta: numpy.ndarray
170
169
  The wake deltas at targets, shape:
171
170
  (n_states, n_targets, n_tpoints)
@@ -178,6 +177,7 @@ class WSPow(WakeSuperposition):
178
177
  (n_states, n_targets, n_tpoints)
179
178
 
180
179
  """
180
+ amb_results = tdata[FV.var2amb[variable]]
181
181
  w = -(wake_delta ** (1 / self.pow))
182
182
  if self.lim_low is not None:
183
183
  w = np.maximum(w, self.lim_low - amb_results)
@@ -307,8 +307,8 @@ class WSPowLocal(WakeSuperposition):
307
307
  algo,
308
308
  mdata,
309
309
  fdata,
310
+ tdata,
310
311
  variable,
311
- amb_results,
312
312
  wake_delta,
313
313
  ):
314
314
  """
@@ -323,11 +323,10 @@ class WSPowLocal(WakeSuperposition):
323
323
  The model data
324
324
  fdata: foxes.core.FData
325
325
  The farm data
326
+ tdata: foxes.core.TData
327
+ The target point data
326
328
  variable: str
327
329
  The variable name for which the wake deltas applies
328
- amb_results: numpy.ndarray
329
- The ambient results at targets,
330
- shape: (n_states, n_targets, n_tpoints)
331
330
  wake_delta: numpy.ndarray
332
331
  The wake deltas at targets, shape:
333
332
  (n_states, n_targets, n_tpoints)
@@ -340,6 +339,7 @@ class WSPowLocal(WakeSuperposition):
340
339
  (n_states, n_targets, n_tpoints)
341
340
 
342
341
  """
342
+ amb_results = tdata[FV.var2amb[variable]]
343
343
  w = -(wake_delta ** (1 / self.pow)) * amb_results
344
344
  if self.lim_low is not None:
345
345
  w = np.maximum(w, self.lim_low - amb_results)
@@ -131,8 +131,8 @@ class WSProduct(WakeSuperposition):
131
131
  algo,
132
132
  mdata,
133
133
  fdata,
134
+ tdata,
134
135
  variable,
135
- amb_results,
136
136
  wake_delta,
137
137
  ):
138
138
  """
@@ -147,11 +147,10 @@ class WSProduct(WakeSuperposition):
147
147
  The model data
148
148
  fdata: foxes.core.FData
149
149
  The farm data
150
+ tdata: foxes.core.TData
151
+ The target point data
150
152
  variable: str
151
153
  The variable name for which the wake deltas applies
152
- amb_results: numpy.ndarray
153
- The ambient results at targets,
154
- shape: (n_states, n_targets, n_tpoints)
155
154
  wake_delta: numpy.ndarray
156
155
  The wake deltas at targets, shape:
157
156
  (n_states, n_targets, n_tpoints)
@@ -164,6 +163,7 @@ class WSProduct(WakeSuperposition):
164
163
  (n_states, n_targets, n_tpoints)
165
164
 
166
165
  """
166
+ amb_results = tdata[FV.var2amb[variable]]
167
167
  w = amb_results * (wake_delta - 1)
168
168
  if self.lim_low is not None:
169
169
  w = np.maximum(w, self.lim_low - amb_results)
@@ -140,8 +140,8 @@ class WSQuadratic(WakeSuperposition):
140
140
  algo,
141
141
  mdata,
142
142
  fdata,
143
+ tdata,
143
144
  variable,
144
- amb_results,
145
145
  wake_delta,
146
146
  ):
147
147
  """
@@ -156,11 +156,10 @@ class WSQuadratic(WakeSuperposition):
156
156
  The model data
157
157
  fdata: foxes.core.FData
158
158
  The farm data
159
+ tdata: foxes.core.TData
160
+ The target point data
159
161
  variable: str
160
162
  The variable name for which the wake deltas applies
161
- amb_results: numpy.ndarray
162
- The ambient results at targets,
163
- shape: (n_states, n_targets, n_tpoints)
164
163
  wake_delta: numpy.ndarray
165
164
  The wake deltas at targets, shape:
166
165
  (n_states, n_targets, n_tpoints)
@@ -173,6 +172,7 @@ class WSQuadratic(WakeSuperposition):
173
172
  (n_states, n_targets, n_tpoints)
174
173
 
175
174
  """
175
+ amb_results = tdata[FV.var2amb[variable]]
176
176
  w = -np.sqrt(wake_delta)
177
177
  if self.lim_low is not None:
178
178
  w = np.maximum(w, self.lim_low - amb_results)
@@ -296,8 +296,8 @@ class WSQuadraticLocal(WakeSuperposition):
296
296
  algo,
297
297
  mdata,
298
298
  fdata,
299
+ tdata,
299
300
  variable,
300
- amb_results,
301
301
  wake_delta,
302
302
  ):
303
303
  """
@@ -312,11 +312,10 @@ class WSQuadraticLocal(WakeSuperposition):
312
312
  The model data
313
313
  fdata: foxes.core.FData
314
314
  The farm data
315
+ tdata: foxes.core.TData
316
+ The target point data
315
317
  variable: str
316
318
  The variable name for which the wake deltas applies
317
- amb_results: numpy.ndarray
318
- The ambient results at targets,
319
- shape: (n_states, n_targets, n_tpoints)
320
319
  wake_delta: numpy.ndarray
321
320
  The wake deltas at targets, shape:
322
321
  (n_states, n_targets, n_tpoints)
@@ -329,6 +328,7 @@ class WSQuadraticLocal(WakeSuperposition):
329
328
  (n_states, n_targets, n_tpoints)
330
329
 
331
330
  """
331
+ amb_results = tdata[FV.var2amb[variable]]
332
332
  w = -np.sqrt(wake_delta) * amb_results
333
333
  if self.lim_low is not None:
334
334
  w = np.maximum(w, self.lim_low - amb_results)