foxes 0.8.2__py3-none-any.whl → 1.1.0.2__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 (215) hide show
  1. docs/source/conf.py +353 -0
  2. examples/abl_states/run.py +160 -0
  3. examples/compare_rotors_pwakes/run.py +217 -0
  4. examples/compare_wakes/run.py +241 -0
  5. examples/dyn_wakes/run.py +311 -0
  6. examples/field_data_nc/run.py +121 -0
  7. examples/induction/run.py +201 -0
  8. examples/multi_height/run.py +113 -0
  9. examples/power_mask/run.py +249 -0
  10. examples/random_timeseries/run.py +210 -0
  11. examples/scan_row/run.py +193 -0
  12. examples/sector_management/run.py +162 -0
  13. examples/sequential/run.py +209 -0
  14. examples/single_state/run.py +201 -0
  15. examples/states_lookup_table/run.py +137 -0
  16. examples/streamline_wakes/run.py +138 -0
  17. examples/tab_file/run.py +142 -0
  18. examples/timelines/run.py +267 -0
  19. examples/timeseries/run.py +190 -0
  20. examples/timeseries_slurm/run.py +185 -0
  21. examples/wind_rose/run.py +141 -0
  22. examples/windio/run.py +29 -0
  23. examples/yawed_wake/run.py +196 -0
  24. foxes/__init__.py +4 -8
  25. foxes/algorithms/__init__.py +1 -1
  26. foxes/algorithms/downwind/downwind.py +247 -111
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
  28. foxes/algorithms/downwind/models/init_farm_data.py +2 -2
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
  33. foxes/algorithms/iterative/iterative.py +74 -34
  34. foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
  35. foxes/algorithms/iterative/models/urelax.py +3 -3
  36. foxes/algorithms/sequential/models/plugin.py +5 -5
  37. foxes/algorithms/sequential/models/seq_state.py +1 -1
  38. foxes/algorithms/sequential/sequential.py +126 -255
  39. foxes/constants.py +22 -7
  40. foxes/core/__init__.py +1 -0
  41. foxes/core/algorithm.py +632 -147
  42. foxes/core/data.py +252 -20
  43. foxes/core/data_calc_model.py +15 -291
  44. foxes/core/engine.py +640 -0
  45. foxes/core/farm_controller.py +38 -10
  46. foxes/core/farm_data_model.py +16 -1
  47. foxes/core/ground_model.py +2 -2
  48. foxes/core/model.py +249 -182
  49. foxes/core/partial_wakes_model.py +1 -1
  50. foxes/core/point_data_model.py +17 -2
  51. foxes/core/rotor_model.py +27 -21
  52. foxes/core/states.py +17 -1
  53. foxes/core/turbine_type.py +28 -0
  54. foxes/core/wake_frame.py +30 -34
  55. foxes/core/wake_model.py +5 -5
  56. foxes/core/wake_superposition.py +1 -1
  57. foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
  58. foxes/engines/__init__.py +17 -0
  59. foxes/engines/dask.py +982 -0
  60. foxes/engines/default.py +75 -0
  61. foxes/engines/futures.py +72 -0
  62. foxes/engines/mpi.py +38 -0
  63. foxes/engines/multiprocess.py +71 -0
  64. foxes/engines/numpy.py +167 -0
  65. foxes/engines/pool.py +249 -0
  66. foxes/engines/ray.py +79 -0
  67. foxes/engines/single.py +141 -0
  68. foxes/input/farm_layout/__init__.py +1 -0
  69. foxes/input/farm_layout/from_csv.py +4 -0
  70. foxes/input/farm_layout/from_json.py +2 -2
  71. foxes/input/farm_layout/grid.py +2 -2
  72. foxes/input/farm_layout/ring.py +65 -0
  73. foxes/input/farm_layout/row.py +2 -2
  74. foxes/input/states/__init__.py +7 -0
  75. foxes/input/states/create/random_abl_states.py +1 -1
  76. foxes/input/states/field_data_nc.py +158 -33
  77. foxes/input/states/multi_height.py +128 -14
  78. foxes/input/states/one_point_flow.py +577 -0
  79. foxes/input/states/scan_ws.py +74 -3
  80. foxes/input/states/single.py +1 -1
  81. foxes/input/states/slice_data_nc.py +681 -0
  82. foxes/input/states/states_table.py +204 -35
  83. foxes/input/windio/__init__.py +2 -2
  84. foxes/input/windio/get_states.py +44 -23
  85. foxes/input/windio/read_attributes.py +48 -17
  86. foxes/input/windio/read_farm.py +116 -102
  87. foxes/input/windio/read_fields.py +16 -6
  88. foxes/input/windio/read_outputs.py +71 -24
  89. foxes/input/windio/runner.py +31 -17
  90. foxes/input/windio/windio.py +41 -23
  91. foxes/models/farm_models/turbine2farm.py +1 -1
  92. foxes/models/ground_models/wake_mirror.py +10 -6
  93. foxes/models/model_book.py +58 -20
  94. foxes/models/partial_wakes/axiwake.py +3 -3
  95. foxes/models/partial_wakes/rotor_points.py +3 -3
  96. foxes/models/partial_wakes/top_hat.py +2 -2
  97. foxes/models/point_models/set_uniform_data.py +1 -1
  98. foxes/models/point_models/tke2ti.py +1 -1
  99. foxes/models/point_models/wake_deltas.py +1 -1
  100. foxes/models/rotor_models/centre.py +4 -0
  101. foxes/models/rotor_models/grid.py +24 -25
  102. foxes/models/rotor_models/levels.py +4 -5
  103. foxes/models/turbine_models/calculator.py +4 -6
  104. foxes/models/turbine_models/kTI_model.py +22 -6
  105. foxes/models/turbine_models/lookup_table.py +30 -4
  106. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  107. foxes/models/turbine_models/set_farm_vars.py +103 -34
  108. foxes/models/turbine_types/PCt_file.py +27 -3
  109. foxes/models/turbine_types/PCt_from_two.py +27 -3
  110. foxes/models/turbine_types/TBL_file.py +80 -0
  111. foxes/models/turbine_types/__init__.py +2 -0
  112. foxes/models/turbine_types/lookup.py +316 -0
  113. foxes/models/turbine_types/null_type.py +51 -1
  114. foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
  115. foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
  116. foxes/models/vertical_profiles/__init__.py +1 -1
  117. foxes/models/vertical_profiles/data_profile.py +1 -1
  118. foxes/models/wake_frames/__init__.py +1 -0
  119. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  120. foxes/models/wake_frames/farm_order.py +25 -5
  121. foxes/models/wake_frames/rotor_wd.py +6 -4
  122. foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
  123. foxes/models/wake_frames/streamlines.py +21 -22
  124. foxes/models/wake_frames/timelines.py +330 -129
  125. foxes/models/wake_frames/yawed_wakes.py +7 -4
  126. foxes/models/wake_models/dist_sliced.py +2 -4
  127. foxes/models/wake_models/induction/rankine_half_body.py +5 -5
  128. foxes/models/wake_models/induction/rathmann.py +78 -24
  129. foxes/models/wake_models/induction/self_similar.py +78 -28
  130. foxes/models/wake_models/induction/vortex_sheet.py +86 -48
  131. foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
  132. foxes/models/wake_models/ti/iec_ti.py +40 -21
  133. foxes/models/wake_models/top_hat.py +1 -1
  134. foxes/models/wake_models/wind/bastankhah14.py +8 -6
  135. foxes/models/wake_models/wind/bastankhah16.py +17 -16
  136. foxes/models/wake_models/wind/jensen.py +4 -3
  137. foxes/models/wake_models/wind/turbopark.py +16 -13
  138. foxes/models/wake_superpositions/ti_linear.py +1 -1
  139. foxes/models/wake_superpositions/ti_max.py +1 -1
  140. foxes/models/wake_superpositions/ti_pow.py +1 -1
  141. foxes/models/wake_superpositions/ti_quadratic.py +1 -1
  142. foxes/models/wake_superpositions/ws_linear.py +8 -7
  143. foxes/models/wake_superpositions/ws_max.py +8 -7
  144. foxes/models/wake_superpositions/ws_pow.py +8 -7
  145. foxes/models/wake_superpositions/ws_product.py +5 -5
  146. foxes/models/wake_superpositions/ws_quadratic.py +8 -7
  147. foxes/output/__init__.py +4 -1
  148. foxes/output/farm_layout.py +16 -12
  149. foxes/output/farm_results_eval.py +1 -1
  150. foxes/output/flow_plots_2d/__init__.py +0 -1
  151. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  152. foxes/output/grids.py +92 -22
  153. foxes/output/results_writer.py +2 -2
  154. foxes/output/rose_plot.py +3 -3
  155. foxes/output/seq_plugins/__init__.py +2 -0
  156. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
  157. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  158. foxes/output/slice_data.py +131 -111
  159. foxes/output/state_turbine_map.py +19 -14
  160. foxes/output/state_turbine_table.py +19 -19
  161. foxes/utils/__init__.py +1 -1
  162. foxes/utils/abl/neutral.py +2 -2
  163. foxes/utils/abl/stable.py +2 -2
  164. foxes/utils/abl/unstable.py +2 -2
  165. foxes/utils/data_book.py +1 -1
  166. foxes/utils/dev_utils.py +42 -0
  167. foxes/utils/dict.py +24 -1
  168. foxes/utils/exec_python.py +1 -1
  169. foxes/utils/factory.py +176 -53
  170. foxes/utils/geom2d/circle.py +1 -1
  171. foxes/utils/geom2d/polygon.py +1 -1
  172. foxes/utils/geopandas_utils.py +2 -2
  173. foxes/utils/load.py +2 -2
  174. foxes/utils/pandas_helpers.py +3 -2
  175. foxes/utils/wind_dir.py +0 -2
  176. foxes/utils/xarray_utils.py +24 -14
  177. foxes/variables.py +39 -2
  178. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
  179. foxes-1.1.0.2.dist-info/RECORD +309 -0
  180. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
  181. foxes-1.1.0.2.dist-info/top_level.txt +4 -0
  182. tests/0_consistency/iterative/test_iterative.py +92 -0
  183. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  184. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  185. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  186. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  187. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  188. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  189. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  190. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  191. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  192. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  193. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  194. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  195. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  196. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  197. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  198. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  199. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  200. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  201. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  202. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  203. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  204. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  205. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  206. tests/3_examples/test_examples.py +34 -0
  207. foxes/VERSION +0 -1
  208. foxes/output/flow_plots_2d.py +0 -0
  209. foxes/utils/geopandas_helpers.py +0 -294
  210. foxes/utils/runners/__init__.py +0 -1
  211. foxes/utils/runners/runners.py +0 -280
  212. foxes-0.8.2.dist-info/RECORD +0 -247
  213. foxes-0.8.2.dist-info/top_level.txt +0 -1
  214. foxes-0.8.2.dist-info/zip-safe +0 -1
  215. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/LICENSE +0 -0
@@ -1,15 +1,16 @@
1
1
  import numpy as np
2
2
  from scipy.spatial.distance import cdist
3
3
 
4
- from foxes.core import WakeFrame
5
4
  from foxes.utils import wd2uv
6
5
  from foxes.core.data import TData
7
6
  import foxes.variables as FV
8
7
  import foxes.constants as FC
9
- from foxes.algorithms import Sequential
8
+ from foxes.algorithms.sequential import Sequential
10
9
 
10
+ from .farm_order import FarmOrder
11
11
 
12
- class SeqDynamicWakes(WakeFrame):
12
+
13
+ class SeqDynamicWakes(FarmOrder):
13
14
  """
14
15
  Dynamic wakes for the sequential algorithm.
15
16
 
@@ -26,7 +27,7 @@ class SeqDynamicWakes(WakeFrame):
26
27
 
27
28
  """
28
29
 
29
- def __init__(self, cl_ipars={}, dt_min=None):
30
+ def __init__(self, cl_ipars={}, dt_min=None, **kwargs):
30
31
  """
31
32
  Constructor.
32
33
 
@@ -38,9 +39,11 @@ class SeqDynamicWakes(WakeFrame):
38
39
  dt_min: float, optional
39
40
  The delta t value in minutes,
40
41
  if not from timeseries data
42
+ kwargs: dict, optional
43
+ Additional parameters for the base class
41
44
 
42
45
  """
43
- super().__init__()
46
+ super().__init__(**kwargs)
44
47
  self.cl_ipars = cl_ipars
45
48
  self.dt_min = dt_min
46
49
 
@@ -88,10 +91,12 @@ class SeqDynamicWakes(WakeFrame):
88
91
  # init wake traces data:
89
92
  self._traces_p = np.zeros((algo.n_states, algo.n_turbines, 3), dtype=FC.DTYPE)
90
93
  self._traces_v = np.zeros((algo.n_states, algo.n_turbines, 3), dtype=FC.DTYPE)
91
- self._traces_l = np.zeros((algo.n_states, algo.n_turbines), dtype=FC.DTYPE)
94
+ self._traces_l = np.full(
95
+ (algo.n_states, algo.n_turbines), np.nan, dtype=FC.DTYPE
96
+ )
92
97
 
93
98
  def calc_order(self, algo, mdata, fdata):
94
- """ "
99
+ """
95
100
  Calculates the order of turbine evaluation.
96
101
 
97
102
  This function is executed on a single chunk of data,
@@ -112,26 +117,7 @@ class SeqDynamicWakes(WakeFrame):
112
117
  The turbine order, shape: (n_states, n_turbines)
113
118
 
114
119
  """
115
- # prepare:
116
- n_states = fdata.n_states
117
- n_turbines = algo.n_turbines
118
- tdata = TData.from_points(points=fdata[FV.TXYH])
119
-
120
- # calculate streamline x coordinates for turbines rotor centre points:
121
- # n_states, n_turbines_source, n_turbines_target
122
- coosx = np.zeros((n_states, n_turbines, n_turbines), dtype=FC.DTYPE)
123
- for ti in range(n_turbines):
124
- coosx[:, ti, :] = self.get_wake_coos(algo, mdata, fdata, tdata, ti)[
125
- :, :, 0, 0
126
- ]
127
-
128
- # derive turbine order:
129
- # TODO: Remove loop over states
130
- order = np.zeros((n_states, n_turbines), dtype=FC.ITYPE)
131
- for si in range(n_states):
132
- order[si] = np.lexsort(keys=coosx[si])
133
-
134
- return order
120
+ return super().calc_order(algo, mdata, fdata)
135
121
 
136
122
  def get_wake_coos(
137
123
  self,
@@ -156,7 +142,7 @@ class SeqDynamicWakes(WakeFrame):
156
142
  The target point data
157
143
  downwind_index: int
158
144
  The index of the wake causing turbine
159
- in the downwnd order
145
+ in the downwind order
160
146
 
161
147
  Returns
162
148
  -------
@@ -174,48 +160,54 @@ class SeqDynamicWakes(WakeFrame):
174
160
  counter = algo.states.counter
175
161
  N = counter + 1
176
162
 
177
- # new wake starts at turbine:
178
- self._traces_p[counter, downwind_index] = fdata[FV.TXYH][0, downwind_index]
179
- self._traces_l[counter, downwind_index] = 0
180
-
181
- # transport wakes that originate from previous time steps:
182
- if counter > 0:
183
- dxyz = self._traces_v[:counter, downwind_index] * self._dt[:counter, None]
184
- self._traces_p[:counter, downwind_index] += dxyz
185
- self._traces_l[:counter, downwind_index] += np.linalg.norm(dxyz, axis=-1)
186
-
187
- # compute wind vectors at wake traces:
188
- # TODO: dz from U_z is missing here
189
- hpdata = {
190
- v: np.zeros((1, N, 1), dtype=FC.DTYPE)
191
- for v in algo.states.output_point_vars(algo)
192
- }
193
- hpdims = {v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in hpdata.keys()}
194
- hpdata = TData.from_points(
195
- points=self._traces_p[None, :N, downwind_index],
196
- data=hpdata,
197
- dims=hpdims,
198
- )
199
- res = algo.states.calculate(algo, mdata, fdata, hpdata)
200
- self._traces_v[:N, downwind_index, :2] = wd2uv(
201
- res[FV.WD][0, :, 0], res[FV.WS][0, :, 0]
202
- )
203
- del hpdata, hpdims, res
163
+ if np.isnan(self._traces_l[counter, downwind_index]):
204
164
 
205
- # project:
165
+ # new wake starts at turbine:
166
+ self._traces_p[counter, downwind_index][:] = fdata[FV.TXYH][
167
+ 0, downwind_index
168
+ ]
169
+ self._traces_l[counter, downwind_index] = 0
170
+
171
+ # transport wakes that originate from previous time steps:
172
+ if counter > 0:
173
+ dxyz = self._traces_v[:counter, downwind_index] * self._dt[counter - 1]
174
+ self._traces_p[:counter, downwind_index] += dxyz
175
+ self._traces_l[:counter, downwind_index] += np.linalg.norm(
176
+ dxyz, axis=-1
177
+ )
178
+ del dxyz
179
+
180
+ # compute wind vectors at wake traces:
181
+ # TODO: dz from U_z is missing here
182
+ hpdata = TData.from_points(points=self._traces_p[None, :N, downwind_index])
183
+ res = algo.states.calculate(algo, mdata, fdata, hpdata)
184
+ self._traces_v[:N, downwind_index, :2] = wd2uv(
185
+ res[FV.WD][0, :, 0], res[FV.WS][0, :, 0]
186
+ )
187
+ del hpdata, res
188
+
189
+ # find nearest wake point:
206
190
  dists = cdist(points[0], self._traces_p[:N, downwind_index])
207
191
  tri = np.argmin(dists, axis=1)
208
192
  del dists
193
+
194
+ # project:
209
195
  wcoos = np.full((n_states, n_points, 3), 1e20, dtype=FC.DTYPE)
210
- wcoos[0, :, 2] = points[0, :, 2] - fdata[FV.TXYH][:, downwind_index][0, None, 2]
211
- delp = points[0, :, :2] - self._traces_p[tri, downwind_index, :2]
196
+ wcoos[0, :, 2] = points[0, :, 2] - fdata[FV.TXYH][0, downwind_index, None, 2]
212
197
  nx = self._traces_v[tri, downwind_index, :2]
213
- nx /= np.linalg.norm(nx, axis=1)[:, None]
214
- ny = np.concatenate([-nx[:, 1, None], nx[:, 0, None]], axis=1)
215
- wcoos[0, :, 0] = (
216
- np.einsum("pd,pd->p", delp, nx) + self._traces_l[tri, downwind_index]
217
- )
218
- wcoos[0, :, 1] = np.einsum("pd,pd->p", delp, ny)
198
+ mv = np.linalg.norm(nx, axis=-1)
199
+ nx /= mv[:, None]
200
+ delp = points[0, :, :2] - self._traces_p[tri, downwind_index, :2]
201
+ projx = np.einsum("pd,pd->p", delp, nx)
202
+ dt = self._dt[counter] if counter < len(self._dt) else self._dt[-1]
203
+ dx = mv * dt
204
+ sel = (projx > -dx) & (projx < dx)
205
+ if np.any(sel):
206
+ ny = np.concatenate([-nx[:, 1, None], nx[:, 0, None]], axis=1)
207
+ wcoos[0, sel, 0] = projx[sel] + self._traces_l[tri[sel], downwind_index]
208
+ wcoos[0, sel, 1] = np.einsum("pd,pd->p", delp, ny)[sel]
209
+ del ny
210
+ del delp, projx, mv, dx, nx, sel
219
211
 
220
212
  # turbines that cause wake:
221
213
  tdata[FC.STATE_SOURCE_ORDERI] = downwind_index
@@ -238,7 +230,6 @@ class SeqDynamicWakes(WakeFrame):
238
230
  tdata,
239
231
  target,
240
232
  states0=None,
241
- upcast=False,
242
233
  ):
243
234
  """
244
235
  Return data that is required for computing the
@@ -261,17 +252,12 @@ class SeqDynamicWakes(WakeFrame):
261
252
  FC.STATE_TARGET, FC.STATE_TARGET_TPOINT
262
253
  states0: numpy.ndarray, optional
263
254
  The states of wake creation
264
- upcast: bool
265
- Flag for ensuring targets dimension,
266
- otherwise dimension 1 is entered
267
255
 
268
256
  Returns
269
257
  -------
270
258
  data: numpy.ndarray
271
259
  Data for wake modelling, shape:
272
260
  (n_states, n_turbines) or (n_states, n_target)
273
- dims: tuple
274
- The data dimensions
275
261
 
276
262
  """
277
263
  if states0 is None and FC.STATE_SOURCE_ORDERI in tdata:
@@ -287,7 +273,8 @@ class SeqDynamicWakes(WakeFrame):
287
273
  n_points = n_targets * n_tpoints
288
274
 
289
275
  s = tdata[FC.STATES_SEL][0].reshape(n_points)
290
- data = algo.farm_results[variable].to_numpy()
276
+ data = algo.farm_results_downwind[variable].to_numpy()
277
+ data[algo.counter] = fdata[variable][0]
291
278
  data = data[s, downwind_index].reshape(n_states, n_targets, n_tpoints)
292
279
 
293
280
  if target == FC.STATE_TARGET:
@@ -295,9 +282,9 @@ class SeqDynamicWakes(WakeFrame):
295
282
  data = data[:, :, 0]
296
283
  else:
297
284
  data = np.einsum("stp,p->st", data, tdata[FC.TWEIGHTS])
298
- return data, (FC.STATE, FC.TARGET)
285
+ return data
299
286
  elif target == FC.STATE_TARGET_TPOINT:
300
- return data, (FC.STATE, FC.TARGET, FC.TPOINT)
287
+ return data
301
288
  else:
302
289
  raise ValueError(
303
290
  f"Cannot handle target '{target}', choices are {FC.STATE_TARGET}, {FC.STATE_TARGET_TPOINT}"
@@ -305,7 +292,7 @@ class SeqDynamicWakes(WakeFrame):
305
292
 
306
293
  else:
307
294
  return super().get_wake_modelling_data(
308
- algo, variable, downwind_index, fdata, tdata, target, states0, upcast
295
+ algo, variable, downwind_index, fdata, tdata, target, states0
309
296
  )
310
297
 
311
298
  def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
@@ -16,8 +16,6 @@ class Streamlines2D(WakeFrame):
16
16
  ----------
17
17
  step: float
18
18
  The streamline step size in m
19
- max_length: float
20
- The maximal streamline length
21
19
  cl_ipars: dict
22
20
  Interpolation parameters for centre line
23
21
  point interpolation
@@ -26,7 +24,7 @@ class Streamlines2D(WakeFrame):
26
24
 
27
25
  """
28
26
 
29
- def __init__(self, step, max_length=1e4, cl_ipars={}):
27
+ def __init__(self, step, max_length_km=20, cl_ipars={}, **kwargs):
30
28
  """
31
29
  Constructor.
32
30
 
@@ -34,16 +32,17 @@ class Streamlines2D(WakeFrame):
34
32
  ----------
35
33
  step: float
36
34
  The streamline step size in m
37
- max_length: float
38
- The maximal streamline length
35
+ max_length_km: float
36
+ The maximal streamline length in km
39
37
  cl_ipars: dict
40
38
  Interpolation parameters for centre line
41
39
  point interpolation
40
+ kwargs: dict, optional
41
+ Additional parameters for the base class
42
42
 
43
43
  """
44
- super().__init__()
44
+ super().__init__(max_length_km=max_length_km, **kwargs)
45
45
  self.step = step
46
- self.max_length = max_length
47
46
  self.cl_ipars = cl_ipars
48
47
 
49
48
  self.DATA = self.var("DATA")
@@ -51,7 +50,9 @@ class Streamlines2D(WakeFrame):
51
50
  self.SDAT = self.var("SDAT")
52
51
 
53
52
  def __repr__(self):
54
- return f"{type(self).__name__}(step={self.step})"
53
+ return (
54
+ f"{type(self).__name__}(step={self.step}, max_length={self.max_length_km})"
55
+ )
55
56
 
56
57
  def _calc_streamlines(self, algo, mdata, fdata):
57
58
  """
@@ -60,7 +61,7 @@ class Streamlines2D(WakeFrame):
60
61
  # prepare:
61
62
  n_states = mdata.n_states
62
63
  n_turbines = mdata.n_turbines
63
- N = int(self.max_length / self.step)
64
+ N = int(self.max_length_km * 1e3 / self.step)
64
65
 
65
66
  # calc data: x, y, z, wd
66
67
  data = np.zeros((n_states, n_turbines, N, 4), dtype=FC.DTYPE)
@@ -134,7 +135,6 @@ class Streamlines2D(WakeFrame):
134
135
  Helper function, calculates streamline coordinates
135
136
  for given points and given turbine
136
137
  """
137
-
138
138
  # prepare:
139
139
  n_states, n_targets, n_tpoints = targets.shape[:3]
140
140
  n_points = n_targets * n_tpoints
@@ -151,18 +151,21 @@ class Streamlines2D(WakeFrame):
151
151
  del dists, selp
152
152
 
153
153
  # calculate coordinates:
154
- coos = np.zeros((n_states, n_points, 3), dtype=FC.DTYPE)
155
- nx = wd2uv(data[:, :, 3])
156
- ny = np.stack([-nx[:, :, 1], nx[:, :, 0]], axis=2)
157
- delta = points[:, :, :2] - data[:, :, :2]
158
- coos[:, :, 0] = slen + np.einsum("spd,spd->sp", delta, nx)
159
- coos[:, :, 1] = np.einsum("spd,spd->sp", delta, ny)
154
+ coos = np.full((n_states, n_points, 3), np.nan, dtype=FC.DTYPE)
160
155
  coos[:, :, 2] = points[:, :, 2] - data[:, :, 2]
156
+ delta = points[:, :, :2] - data[:, :, :2]
157
+ nx = wd2uv(data[:, :, 3])
158
+ projx = np.einsum("spd,spd->sp", delta, nx)
159
+ sel = (projx > -self.step) & (projx < self.step)
160
+ if np.any(sel):
161
+ ny = np.stack([-nx[:, :, 1], nx[:, :, 0]], axis=2)
162
+ coos[sel, 0] = slen[sel] + projx[sel]
163
+ coos[sel, 1] = np.einsum("spd,spd->sp", delta, ny)[sel]
161
164
 
162
165
  return coos.reshape(n_states, n_targets, n_tpoints, 3)
163
166
 
164
167
  def calc_order(self, algo, mdata, fdata):
165
- """ "
168
+ """
166
169
  Calculates the order of turbine evaluation.
167
170
 
168
171
  This function is executed on a single chunk of data,
@@ -227,7 +230,7 @@ class Streamlines2D(WakeFrame):
227
230
  The target point data
228
231
  downwind_index: int
229
232
  The index of the wake causing turbine
230
- in the downwnd order
233
+ in the downwind order
231
234
 
232
235
  Returns
233
236
  -------
@@ -262,10 +265,6 @@ class Streamlines2D(WakeFrame):
262
265
  The centreline points, shape: (n_states, n_points, 3)
263
266
 
264
267
  """
265
- # calculate long enough streamlines:
266
- xmax = np.max(x)
267
- self._ensure_min_length(algo, mdata, fdata, xmax)
268
-
269
268
  # get streamline points:
270
269
  n_states, n_points = x.shape
271
270
  data = self.get_streamline_data(algo, mdata, fdata)[:, downwind_index]