foxes 1.3__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 (190) 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 +0 -1
  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 +21 -17
  23. foxes/algorithms/__init__.py +6 -6
  24. foxes/algorithms/downwind/__init__.py +2 -2
  25. foxes/algorithms/downwind/downwind.py +44 -12
  26. foxes/algorithms/downwind/models/__init__.py +6 -6
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
  28. foxes/algorithms/downwind/models/init_farm_data.py +0 -1
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  30. foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
  31. foxes/algorithms/iterative/__init__.py +7 -3
  32. foxes/algorithms/iterative/iterative.py +1 -2
  33. foxes/algorithms/iterative/models/__init__.py +7 -3
  34. foxes/algorithms/iterative/models/farm_wakes_calc.py +9 -5
  35. foxes/algorithms/sequential/__init__.py +3 -3
  36. foxes/algorithms/sequential/models/__init__.py +2 -2
  37. foxes/algorithms/sequential/sequential.py +3 -4
  38. foxes/config/__init__.py +5 -1
  39. foxes/constants.py +16 -0
  40. foxes/core/__init__.py +45 -22
  41. foxes/core/algorithm.py +0 -1
  42. foxes/core/data.py +19 -18
  43. foxes/core/engine.py +9 -13
  44. foxes/core/farm_controller.py +2 -2
  45. foxes/core/ground_model.py +4 -13
  46. foxes/core/model.py +5 -5
  47. foxes/core/partial_wakes_model.py +147 -10
  48. foxes/core/point_data_model.py +2 -3
  49. foxes/core/rotor_model.py +3 -3
  50. foxes/core/states.py +2 -3
  51. foxes/core/turbine.py +2 -1
  52. foxes/core/wake_deflection.py +130 -0
  53. foxes/core/wake_model.py +222 -9
  54. foxes/core/wake_superposition.py +122 -4
  55. foxes/core/wind_farm.py +6 -6
  56. foxes/data/__init__.py +7 -2
  57. foxes/data/states/weibull_sectors_12.csv +13 -0
  58. foxes/data/states/weibull_sectors_12.nc +0 -0
  59. foxes/engines/__init__.py +14 -15
  60. foxes/engines/dask.py +39 -14
  61. foxes/engines/numpy.py +0 -3
  62. foxes/input/__init__.py +3 -3
  63. foxes/input/farm_layout/__init__.py +8 -8
  64. foxes/input/farm_layout/from_csv.py +1 -1
  65. foxes/input/farm_layout/ring.py +0 -1
  66. foxes/input/states/__init__.py +22 -12
  67. foxes/input/states/create/__init__.py +3 -2
  68. foxes/input/states/field_data_nc.py +10 -24
  69. foxes/input/states/multi_height.py +9 -6
  70. foxes/input/states/one_point_flow.py +0 -4
  71. foxes/input/states/single.py +1 -1
  72. foxes/input/states/states_table.py +10 -7
  73. foxes/input/states/weibull_sectors.py +225 -0
  74. foxes/input/states/wrg_states.py +7 -5
  75. foxes/input/yaml/__init__.py +9 -3
  76. foxes/input/yaml/dict.py +19 -19
  77. foxes/input/yaml/windio/__init__.py +10 -5
  78. foxes/input/yaml/windio/read_attributes.py +2 -2
  79. foxes/input/yaml/windio/read_farm.py +5 -5
  80. foxes/input/yaml/windio/read_fields.py +4 -2
  81. foxes/input/yaml/windio/read_site.py +52 -0
  82. foxes/input/yaml/windio/windio.py +1 -1
  83. foxes/models/__init__.py +15 -14
  84. foxes/models/axial_induction/__init__.py +2 -2
  85. foxes/models/farm_controllers/__init__.py +1 -1
  86. foxes/models/farm_models/__init__.py +1 -1
  87. foxes/models/ground_models/__init__.py +3 -2
  88. foxes/models/ground_models/wake_mirror.py +3 -3
  89. foxes/models/model_book.py +175 -49
  90. foxes/models/partial_wakes/__init__.py +6 -6
  91. foxes/models/partial_wakes/axiwake.py +30 -5
  92. foxes/models/partial_wakes/centre.py +47 -0
  93. foxes/models/partial_wakes/rotor_points.py +41 -11
  94. foxes/models/partial_wakes/segregated.py +2 -25
  95. foxes/models/partial_wakes/top_hat.py +27 -2
  96. foxes/models/point_models/__init__.py +4 -4
  97. foxes/models/rotor_models/__init__.py +3 -3
  98. foxes/models/turbine_models/__init__.py +11 -11
  99. foxes/models/turbine_models/set_farm_vars.py +0 -1
  100. foxes/models/turbine_types/PCt_file.py +0 -2
  101. foxes/models/turbine_types/PCt_from_two.py +0 -2
  102. foxes/models/turbine_types/__init__.py +9 -9
  103. foxes/models/vertical_profiles/__init__.py +7 -7
  104. foxes/models/wake_deflections/__init__.py +3 -0
  105. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  106. foxes/models/wake_deflections/jimenez.py +277 -0
  107. foxes/models/wake_deflections/no_deflection.py +94 -0
  108. foxes/models/wake_frames/__init__.py +6 -7
  109. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  110. foxes/models/wake_frames/rotor_wd.py +3 -1
  111. foxes/models/wake_frames/seq_dynamic_wakes.py +41 -7
  112. foxes/models/wake_frames/streamlines.py +8 -6
  113. foxes/models/wake_frames/timelines.py +9 -3
  114. foxes/models/wake_models/__init__.py +7 -7
  115. foxes/models/wake_models/dist_sliced.py +50 -84
  116. foxes/models/wake_models/gaussian.py +20 -0
  117. foxes/models/wake_models/induction/__init__.py +5 -5
  118. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  119. foxes/models/wake_models/induction/rathmann.py +65 -64
  120. foxes/models/wake_models/induction/self_similar.py +65 -68
  121. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  122. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  123. foxes/models/wake_models/ti/__init__.py +2 -2
  124. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  125. foxes/models/wake_models/ti/iec_ti.py +6 -4
  126. foxes/models/wake_models/top_hat.py +58 -7
  127. foxes/models/wake_models/wind/__init__.py +6 -4
  128. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  129. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  130. foxes/models/wake_models/wind/jensen.py +15 -2
  131. foxes/models/wake_models/wind/turbopark.py +28 -2
  132. foxes/models/wake_superpositions/__init__.py +18 -9
  133. foxes/models/wake_superpositions/ti_linear.py +4 -4
  134. foxes/models/wake_superpositions/ti_max.py +4 -4
  135. foxes/models/wake_superpositions/ti_pow.py +4 -4
  136. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  137. foxes/models/wake_superpositions/wind_vector.py +257 -0
  138. foxes/models/wake_superpositions/ws_linear.py +9 -10
  139. foxes/models/wake_superpositions/ws_max.py +8 -8
  140. foxes/models/wake_superpositions/ws_pow.py +8 -8
  141. foxes/models/wake_superpositions/ws_product.py +4 -4
  142. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  143. foxes/output/__init__.py +21 -19
  144. foxes/output/farm_layout.py +2 -2
  145. foxes/output/farm_results_eval.py +15 -15
  146. foxes/output/flow_plots_2d/__init__.py +2 -2
  147. foxes/output/flow_plots_2d/get_fig.py +4 -2
  148. foxes/output/rose_plot.py +3 -3
  149. foxes/output/seq_plugins/__init__.py +2 -2
  150. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  151. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  152. foxes/output/turbine_type_curves.py +7 -8
  153. foxes/utils/__init__.py +37 -19
  154. foxes/utils/abl/__init__.py +4 -4
  155. foxes/utils/cubic_roots.py +1 -1
  156. foxes/utils/data_book.py +4 -3
  157. foxes/utils/dict.py +3 -3
  158. foxes/utils/exec_python.py +5 -5
  159. foxes/utils/factory.py +1 -3
  160. foxes/utils/geom2d/__init__.py +7 -5
  161. foxes/utils/geopandas_utils.py +2 -2
  162. foxes/utils/pandas_utils.py +4 -3
  163. foxes/utils/tab_files.py +0 -1
  164. foxes/utils/weibull.py +28 -0
  165. foxes/utils/wrg_utils.py +3 -1
  166. foxes/utils/xarray_utils.py +9 -2
  167. foxes/variables.py +67 -9
  168. {foxes-1.3.dist-info → foxes-1.4.dist-info}/METADATA +6 -15
  169. foxes-1.4.dist-info/RECORD +320 -0
  170. {foxes-1.3.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
  171. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  172. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +1 -1
  173. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  174. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  175. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  176. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +0 -1
  177. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
  178. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
  179. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
  180. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
  181. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  182. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
  183. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  184. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +0 -1
  185. foxes/output/round.py +0 -10
  186. foxes/utils/pandas_helpers.py +0 -178
  187. foxes-1.3.dist-info/RECORD +0 -313
  188. {foxes-1.3.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
  189. {foxes-1.3.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
  190. {foxes-1.3.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
@@ -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
@@ -0,0 +1,94 @@
1
+ from foxes.core.wake_deflection import WakeDeflection
2
+
3
+
4
+ class NoDeflection(WakeDeflection):
5
+ """
6
+ Switch of wake deflection
7
+
8
+ :group: models.wake_deflections
9
+
10
+ """
11
+
12
+ def calc_deflection(
13
+ self,
14
+ algo,
15
+ mdata,
16
+ fdata,
17
+ tdata,
18
+ downwind_index,
19
+ coos,
20
+ ):
21
+ """
22
+ Calculates the wake deflection.
23
+
24
+ This function optionally adds FC.WDEFL_ROT_ANGLE or
25
+ FC.WDEFL_DWS_FACTOR to the tdata.
26
+
27
+ Parameters
28
+ ----------
29
+ algo: foxes.core.Algorithm
30
+ The calculation algorithm
31
+ mdata: foxes.core.MData
32
+ The model data
33
+ fdata: foxes.core.FData
34
+ The farm data
35
+ tdata: foxes.core.TData
36
+ The target point data
37
+ downwind_index: int
38
+ The index of the wake causing turbine
39
+ in the downwind order
40
+ coos: numpy.ndarray
41
+ The wake frame coordinates of the evaluation
42
+ points, shape: (n_states, n_targets, n_tpoints, 3)
43
+
44
+ Returns
45
+ -------
46
+ coos: numpy.ndarray
47
+ The wake frame coordinates of the evaluation
48
+ points, shape: (n_states, n_targets, n_tpoints, 3)
49
+
50
+ """
51
+ return coos
52
+
53
+ def get_yaw_alpha_seq(
54
+ self,
55
+ algo,
56
+ mdata,
57
+ fdata,
58
+ tdata,
59
+ downwind_index,
60
+ x,
61
+ ):
62
+ """
63
+ Computes sequential wind vector rotation angles.
64
+
65
+ Wind vector rotation angles are computed at the
66
+ current trace points due to a yawed rotor
67
+ for sequential runs.
68
+
69
+ Parameters
70
+ ----------
71
+ algo: foxes.core.Algorithm
72
+ The calculation algorithm
73
+ mdata: foxes.core.MData
74
+ The model data
75
+ fdata: foxes.core.FData
76
+ The farm data
77
+ tdata: foxes.core.TData
78
+ The target point data
79
+ downwind_index: int
80
+ The index of the wake causing turbine
81
+ in the downwind order
82
+ x: numpy.ndarray
83
+ The distance from the wake causing rotor
84
+ for the first n_times subsequent time steps,
85
+ shape: (n_times,)
86
+
87
+ Returns
88
+ -------
89
+ alpha: numpy.ndarray
90
+ The delta WD result at the x locations,
91
+ shape: (n_times,)
92
+
93
+ """
94
+ return None
@@ -2,10 +2,9 @@
2
2
  Wake frame models.
3
3
  """
4
4
 
5
- from .rotor_wd import RotorWD
6
- from .streamlines import Streamlines2D
7
- from .timelines import Timelines
8
- from .yawed_wakes import YawedWakes
9
- from .farm_order import FarmOrder
10
- from .seq_dynamic_wakes import SeqDynamicWakes
11
- from .dynamic_wakes import DynamicWakes
5
+ from .rotor_wd import RotorWD as RotorWD
6
+ from .streamlines import Streamlines2D as Streamlines2D
7
+ from .timelines import Timelines as Timelines
8
+ from .farm_order import FarmOrder as FarmOrder
9
+ from .seq_dynamic_wakes import SeqDynamicWakes as SeqDynamicWakes
10
+ from .dynamic_wakes import DynamicWakes as DynamicWakes
@@ -161,7 +161,10 @@ class DynamicWakes(WakeFrame):
161
161
  for v in algo.states.output_point_vars(algo)
162
162
  }
163
163
  key = f"{self.DATA}_{downwind_index}"
164
- ukey_fun = lambda fr, to: f"{self.UPDATE}_dw{downwind_index}_from_{fr}_to_{to}"
164
+
165
+ def ukey_fun(fr, to):
166
+ """helper function to create update key"""
167
+ return f"{self.UPDATE}_dw{downwind_index}_from_{fr}_to_{to}"
165
168
 
166
169
  # compute wakes that start within this chunk: x, y, z, length
167
170
  data = algo.get_from_chunk_store(name=key, mdata=mdata, error=False)
@@ -274,7 +277,6 @@ class DynamicWakes(WakeFrame):
274
277
  # compute single state wake propagation:
275
278
  isnan0 = np.isnan(hdata)
276
279
  for si in range(n_states):
277
-
278
280
  s = slice(si, si + 1, None)
279
281
  hmdata = mdata.get_slice(FC.STATE, s)
280
282
  hfdata = fdata.get_slice(FC.STATE, s)
@@ -429,4 +431,11 @@ class DynamicWakes(WakeFrame):
429
431
  (FC.STATE, FC.TARGET, FC.TPOINT),
430
432
  )
431
433
 
432
- return wcoos.reshape(n_states, n_targets, n_tpoints, 3)
434
+ return algo.wake_deflection.calc_deflection(
435
+ algo,
436
+ mdata,
437
+ fdata,
438
+ tdata,
439
+ downwind_index,
440
+ wcoos.reshape(n_states, n_targets, n_tpoints, 3),
441
+ )
@@ -116,7 +116,9 @@ class RotorWD(WakeFrame):
116
116
 
117
117
  coos = np.einsum("stpd,sad->stpa", delta, nax)
118
118
 
119
- return coos
119
+ return algo.wake_deflection.calc_deflection(
120
+ algo, mdata, fdata, tdata, downwind_index, coos
121
+ )
120
122
 
121
123
  def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
122
124
  """
@@ -23,12 +23,14 @@ class SeqDynamicWakes(FarmOrder):
23
23
  dt_min: float, optional
24
24
  The delta t value in minutes,
25
25
  if not from timeseries data
26
+ induction: foxes.core.AxialInductionModel
27
+ The induction model
26
28
 
27
29
  :group: models.wake_frames.sequential
28
30
 
29
31
  """
30
32
 
31
- def __init__(self, cl_ipars={}, dt_min=None, **kwargs):
33
+ def __init__(self, cl_ipars={}, dt_min=None, induction="Madsen", **kwargs):
32
34
  """
33
35
  Constructor.
34
36
 
@@ -40,6 +42,8 @@ class SeqDynamicWakes(FarmOrder):
40
42
  dt_min: float, optional
41
43
  The delta t value in minutes,
42
44
  if not from timeseries data
45
+ induction: foxes.core.AxialInductionModel or str
46
+ The induction model
43
47
  kwargs: dict, optional
44
48
  Additional parameters for the base class
45
49
 
@@ -47,9 +51,25 @@ class SeqDynamicWakes(FarmOrder):
47
51
  super().__init__(**kwargs)
48
52
  self.cl_ipars = cl_ipars
49
53
  self.dt_min = dt_min
54
+ self.induction = induction
50
55
 
51
56
  def __repr__(self):
52
- return f"{type(self).__name__}(dt_min={self.dt_min})"
57
+ iname = (
58
+ self.induction if isinstance(self.induction, str) else self.induction.name
59
+ )
60
+ return f"{type(self).__name__}(dt_min={self.dt_min}, induction={iname})"
61
+
62
+ def sub_models(self):
63
+ """
64
+ List of all sub-models
65
+
66
+ Returns
67
+ -------
68
+ smdls: list of foxes.core.Model
69
+ All sub models
70
+
71
+ """
72
+ return [self.induction]
53
73
 
54
74
  def initialize(self, algo, verbosity=0):
55
75
  """
@@ -63,7 +83,11 @@ class SeqDynamicWakes(FarmOrder):
63
83
  The verbosity level, 0 = silent
64
84
 
65
85
  """
86
+ if isinstance(self.induction, str):
87
+ self.induction = algo.mbook.axial_induction[self.induction]
88
+
66
89
  super().initialize(algo, verbosity)
90
+
67
91
  if not isinstance(algo, Sequential):
68
92
  raise TypeError(
69
93
  f"Incompatible algorithm type {type(algo).__name__}, expecting {Sequential.__name__}"
@@ -168,7 +192,6 @@ class SeqDynamicWakes(FarmOrder):
168
192
  N = counter + 1
169
193
 
170
194
  if np.isnan(self._traces_l[counter, downwind_index]):
171
-
172
195
  # new wake starts at turbine:
173
196
  self._traces_p[counter, downwind_index][:] = fdata[FV.TXYH][
174
197
  0, downwind_index
@@ -191,10 +214,21 @@ class SeqDynamicWakes(FarmOrder):
191
214
  points=self._traces_p[None, :N, downwind_index], variables=svrs
192
215
  )
193
216
  res = algo.states.calculate(algo, mdata, fdata, hpdata)
194
- self._traces_v[:N, downwind_index, :2] = wd2uv(
195
- res[FV.WD][0, :, 0], res[FV.WS][0, :, 0]
196
- )
197
- del hpdata, res, svrs
217
+ wd = res[FV.WD][0, :, 0]
218
+ if FV.YAWM in fdata:
219
+ wddef = algo.wake_deflection.get_yaw_alpha_seq(
220
+ algo,
221
+ mdata,
222
+ fdata,
223
+ hpdata,
224
+ downwind_index,
225
+ self._traces_l[:N, downwind_index],
226
+ )
227
+ if wddef is not None:
228
+ wd += wddef
229
+ del wddef
230
+ self._traces_v[:N, downwind_index, :2] = wd2uv(wd, res[FV.WS][0, :, 0])
231
+ del hpdata, res, svrs, wd
198
232
 
199
233
  # find nearest wake point:
200
234
  dists = cdist(points[0], self._traces_p[:N, downwind_index])
@@ -67,7 +67,6 @@ class Streamlines2D(WakeFrame):
67
67
  # calc data: x, y, z, wd
68
68
  data = np.zeros((n_states, n_turbines, N, 4), dtype=config.dtype_double)
69
69
  for i in range(N):
70
-
71
70
  # set streamline start point data (rotor centre):
72
71
  if i == 0:
73
72
  data[:, :, i, :3] = fdata[FV.TXYH]
@@ -75,7 +74,6 @@ class Streamlines2D(WakeFrame):
75
74
 
76
75
  # compute next step:
77
76
  else:
78
-
79
77
  # calculate next point:
80
78
  xyz = data[:, :, i - 1, :3]
81
79
  n = wd2uv(data[:, :, i - 1, 3])
@@ -198,9 +196,9 @@ class Streamlines2D(WakeFrame):
198
196
  # n_states, n_turbines_source, n_turbines_target
199
197
  coosx = np.zeros((n_states, n_turbines, n_turbines), dtype=config.dtype_double)
200
198
  for ti in range(n_turbines):
201
- coosx[:, ti, :] = self.get_wake_coos(algo, mdata, fdata, tdata, ti)[
202
- :, :, 0, 0
203
- ]
199
+ coosx[:, ti, :] = self._calc_coos(
200
+ algo, mdata, fdata, tdata[FC.TARGETS], ti
201
+ )[:, :, 0, 0]
204
202
 
205
203
  # derive turbine order:
206
204
  # TODO: Remove loop over states
@@ -242,7 +240,11 @@ class Streamlines2D(WakeFrame):
242
240
  points, shape: (n_states, n_targets, n_tpoints, 3)
243
241
 
244
242
  """
245
- return self._calc_coos(algo, mdata, fdata, tdata[FC.TARGETS], downwind_index)
243
+ coos = self._calc_coos(algo, mdata, fdata, tdata[FC.TARGETS], downwind_index)
244
+
245
+ return algo.wake_deflection.calc_deflection(
246
+ algo, mdata, fdata, tdata, downwind_index, coos
247
+ )
246
248
 
247
249
  def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
248
250
  """
@@ -92,7 +92,7 @@ class Timelines(WakeFrame):
92
92
  del mdict, mdims, data
93
93
 
94
94
  # prepare fdata:
95
- fdata = FData({}, {}, loop_dims=[FC.STATE])
95
+ fdata = FData()
96
96
 
97
97
  # prepare tdata:
98
98
  n_states = states.size()
@@ -107,7 +107,6 @@ class Timelines(WakeFrame):
107
107
  self.timelines_data = {"dxy": (("height", FC.STATE, "dir"), [])}
108
108
  weight_data = None
109
109
  for h in heights:
110
-
111
110
  if verbosity > 0:
112
111
  print(f" Height: {h} m")
113
112
 
@@ -430,7 +429,14 @@ class Timelines(WakeFrame):
430
429
  (FC.STATE, FC.TARGET, FC.TPOINT),
431
430
  )
432
431
 
433
- return wcoos.reshape(n_states, n_targets, n_tpoints, 3)
432
+ return algo.wake_deflection.calc_deflection(
433
+ algo,
434
+ mdata,
435
+ fdata,
436
+ tdata,
437
+ downwind_index,
438
+ wcoos.reshape(n_states, n_targets, n_tpoints, 3),
439
+ )
434
440
 
435
441
  def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
436
442
  """
@@ -2,11 +2,11 @@
2
2
  Wake models.
3
3
  """
4
4
 
5
- from .dist_sliced import DistSlicedWakeModel
6
- from .axisymmetric import AxisymmetricWakeModel
7
- from .top_hat import TopHatWakeModel
8
- from .gaussian import GaussianWakeModel
5
+ from .dist_sliced import DistSlicedWakeModel as DistSlicedWakeModel
6
+ from .axisymmetric import AxisymmetricWakeModel as AxisymmetricWakeModel
7
+ from .top_hat import TopHatWakeModel as TopHatWakeModel
8
+ from .gaussian import GaussianWakeModel as GaussianWakeModel
9
9
 
10
- from . import wind
11
- from . import ti
12
- from . import induction
10
+ from . import wind as wind
11
+ from . import ti as ti
12
+ from . import induction as induction