foxes 0.8.2__py3-none-any.whl → 1.0__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 (174) 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_RHB/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 +183 -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 +232 -101
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -6
  28. foxes/algorithms/downwind/models/init_farm_data.py +1 -1
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +5 -6
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +0 -1
  31. foxes/algorithms/downwind/models/set_amb_point_results.py +4 -2
  32. foxes/algorithms/iterative/iterative.py +73 -33
  33. foxes/algorithms/iterative/models/farm_wakes_calc.py +11 -6
  34. foxes/algorithms/sequential/models/plugin.py +1 -1
  35. foxes/algorithms/sequential/sequential.py +126 -255
  36. foxes/constants.py +17 -2
  37. foxes/core/__init__.py +1 -0
  38. foxes/core/algorithm.py +631 -146
  39. foxes/core/data.py +252 -20
  40. foxes/core/data_calc_model.py +13 -289
  41. foxes/core/engine.py +630 -0
  42. foxes/core/farm_controller.py +37 -9
  43. foxes/core/farm_data_model.py +15 -0
  44. foxes/core/model.py +133 -80
  45. foxes/core/point_data_model.py +15 -0
  46. foxes/core/rotor_model.py +27 -21
  47. foxes/core/states.py +16 -0
  48. foxes/core/turbine_type.py +28 -0
  49. foxes/core/wake_frame.py +22 -4
  50. foxes/core/wake_model.py +2 -3
  51. foxes/data/windio/windio_5turbines_timeseries.yaml +23 -1
  52. foxes/engines/__init__.py +16 -0
  53. foxes/engines/dask.py +975 -0
  54. foxes/engines/default.py +75 -0
  55. foxes/engines/futures.py +72 -0
  56. foxes/engines/mpi.py +38 -0
  57. foxes/engines/multiprocess.py +74 -0
  58. foxes/engines/numpy.py +185 -0
  59. foxes/engines/pool.py +263 -0
  60. foxes/engines/single.py +139 -0
  61. foxes/input/farm_layout/__init__.py +1 -0
  62. foxes/input/farm_layout/from_csv.py +4 -0
  63. foxes/input/farm_layout/from_json.py +1 -1
  64. foxes/input/farm_layout/grid.py +2 -2
  65. foxes/input/farm_layout/ring.py +65 -0
  66. foxes/input/farm_layout/row.py +2 -2
  67. foxes/input/states/__init__.py +6 -0
  68. foxes/input/states/create/random_abl_states.py +1 -1
  69. foxes/input/states/field_data_nc.py +157 -32
  70. foxes/input/states/multi_height.py +127 -13
  71. foxes/input/states/one_point_flow.py +577 -0
  72. foxes/input/states/scan_ws.py +73 -2
  73. foxes/input/states/states_table.py +204 -35
  74. foxes/input/windio/__init__.py +1 -1
  75. foxes/input/windio/get_states.py +44 -23
  76. foxes/input/windio/read_attributes.py +41 -16
  77. foxes/input/windio/read_farm.py +116 -102
  78. foxes/input/windio/read_fields.py +13 -6
  79. foxes/input/windio/read_outputs.py +63 -22
  80. foxes/input/windio/runner.py +31 -17
  81. foxes/input/windio/windio.py +36 -22
  82. foxes/models/ground_models/wake_mirror.py +8 -4
  83. foxes/models/model_book.py +29 -18
  84. foxes/models/partial_wakes/rotor_points.py +3 -3
  85. foxes/models/rotor_models/centre.py +4 -0
  86. foxes/models/rotor_models/grid.py +22 -23
  87. foxes/models/rotor_models/levels.py +4 -5
  88. foxes/models/turbine_models/calculator.py +0 -2
  89. foxes/models/turbine_models/lookup_table.py +27 -2
  90. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  91. foxes/models/turbine_models/set_farm_vars.py +103 -34
  92. foxes/models/turbine_types/PCt_file.py +24 -0
  93. foxes/models/turbine_types/PCt_from_two.py +24 -0
  94. foxes/models/turbine_types/__init__.py +1 -0
  95. foxes/models/turbine_types/lookup.py +316 -0
  96. foxes/models/turbine_types/null_type.py +50 -0
  97. foxes/models/turbine_types/wsrho2PCt_from_two.py +24 -0
  98. foxes/models/turbine_types/wsti2PCt_from_two.py +24 -0
  99. foxes/models/vertical_profiles/data_profile.py +1 -1
  100. foxes/models/wake_frames/__init__.py +1 -0
  101. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  102. foxes/models/wake_frames/farm_order.py +23 -3
  103. foxes/models/wake_frames/rotor_wd.py +4 -2
  104. foxes/models/wake_frames/seq_dynamic_wakes.py +56 -63
  105. foxes/models/wake_frames/streamlines.py +19 -20
  106. foxes/models/wake_frames/timelines.py +328 -127
  107. foxes/models/wake_frames/yawed_wakes.py +4 -1
  108. foxes/models/wake_models/dist_sliced.py +1 -3
  109. foxes/models/wake_models/induction/rankine_half_body.py +4 -4
  110. foxes/models/wake_models/induction/rathmann.py +2 -2
  111. foxes/models/wake_models/induction/self_similar.py +2 -2
  112. foxes/models/wake_models/induction/vortex_sheet.py +2 -2
  113. foxes/models/wake_models/ti/iec_ti.py +34 -17
  114. foxes/models/wake_models/top_hat.py +1 -1
  115. foxes/models/wake_models/wind/bastankhah14.py +2 -2
  116. foxes/models/wake_models/wind/bastankhah16.py +8 -7
  117. foxes/models/wake_models/wind/jensen.py +1 -1
  118. foxes/models/wake_models/wind/turbopark.py +2 -2
  119. foxes/output/__init__.py +4 -1
  120. foxes/output/farm_layout.py +2 -2
  121. foxes/output/flow_plots_2d/__init__.py +0 -1
  122. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  123. foxes/output/grids.py +91 -21
  124. foxes/output/seq_plugins/__init__.py +2 -0
  125. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +62 -20
  126. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  127. foxes/output/slice_data.py +131 -111
  128. foxes/output/state_turbine_map.py +18 -13
  129. foxes/output/state_turbine_table.py +19 -19
  130. foxes/utils/__init__.py +1 -1
  131. foxes/utils/dev_utils.py +42 -0
  132. foxes/utils/dict.py +1 -1
  133. foxes/utils/factory.py +147 -52
  134. foxes/utils/pandas_helpers.py +4 -3
  135. foxes/utils/wind_dir.py +0 -2
  136. foxes/utils/xarray_utils.py +23 -13
  137. foxes/variables.py +37 -0
  138. {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/METADATA +71 -33
  139. foxes-1.0.dist-info/RECORD +307 -0
  140. {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/WHEEL +1 -1
  141. foxes-1.0.dist-info/top_level.txt +4 -0
  142. tests/0_consistency/iterative/test_iterative.py +92 -0
  143. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  144. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  145. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  146. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  147. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  148. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  149. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  150. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  151. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  152. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  153. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  154. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  155. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  156. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  157. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  158. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  159. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  160. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  161. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  162. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  163. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  164. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  165. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  166. tests/3_examples/test_examples.py +34 -0
  167. foxes/VERSION +0 -1
  168. foxes/output/flow_plots_2d.py +0 -0
  169. foxes/utils/runners/__init__.py +0 -1
  170. foxes/utils/runners/runners.py +0 -280
  171. foxes-0.8.2.dist-info/RECORD +0 -247
  172. foxes-0.8.2.dist-info/top_level.txt +0 -1
  173. foxes-0.8.2.dist-info/zip-safe +0 -1
  174. {foxes-0.8.2.dist-info → foxes-1.0.dist-info}/LICENSE +0 -0
foxes/output/grids.py CHANGED
@@ -12,7 +12,6 @@ def calc_point_results(
12
12
  g_pts,
13
13
  farm_results=None,
14
14
  seq_iter=None,
15
- runner=None,
16
15
  verbosity=0,
17
16
  **kwargs,
18
17
  ):
@@ -29,8 +28,6 @@ def calc_point_results(
29
28
  The farm results
30
29
  seq_iter: foxes.algorithms.sequential.SequentialIter, optional
31
30
  The sequential itarator
32
- runner: foxes.utils.runners.Runner, optional
33
- The runner
34
31
  verbosity: int
35
32
  The verbosity level, 0 = silent
36
33
  kwargs: dict, optional
@@ -41,11 +38,7 @@ def calc_point_results(
41
38
  if averb is not None:
42
39
  algo.verbosity = verbosity
43
40
  fres = farm_results if seq_iter is None else seq_iter.farm_results
44
- if runner is None:
45
- point_results = algo.calc_points(fres, points=g_pts, **kwargs)
46
- else:
47
- kwargs["points"] = g_pts
48
- point_results = runner.run(algo.calc_points, args=(fres,), kwargs=kwargs)
41
+ point_results = algo.calc_points(fres, points=g_pts, **kwargs)
49
42
  if averb is not None:
50
43
  algo.verbosity = averb
51
44
 
@@ -54,7 +47,8 @@ def calc_point_results(
54
47
 
55
48
  def get_grid_xy(
56
49
  farm_results,
57
- resolution,
50
+ resolution=None,
51
+ n_img_points=None,
58
52
  xmin=None,
59
53
  ymin=None,
60
54
  xmax=None,
@@ -62,6 +56,8 @@ def get_grid_xy(
62
56
  z=None,
63
57
  xspace=500.0,
64
58
  yspace=500.0,
59
+ states_sel=None,
60
+ states_isel=None,
65
61
  verbosity=0,
66
62
  ):
67
63
  """
@@ -74,6 +70,8 @@ def get_grid_xy(
74
70
  dimensions (state, turbine)
75
71
  resolution: float
76
72
  The resolution in m
73
+ n_img_points: tuple of int, optional
74
+ The number of image points (n, m) in the two directions
77
75
  xmin: float
78
76
  The min x coordinate, or None for automatic
79
77
  ymin: float
@@ -88,6 +86,10 @@ def get_grid_xy(
88
86
  The extra space in x direction, before and after wind farm
89
87
  yspace: float
90
88
  The extra space in y direction, before and after wind farm
89
+ states_sel: list, optional
90
+ Reduce to selected states
91
+ states_isel: list, optional
92
+ Reduce to the selected states indices
91
93
  verbosity: int, optional
92
94
  The verbosity level
93
95
 
@@ -103,8 +105,11 @@ def get_grid_xy(
103
105
  The grid points, shape: (n_states, n_pts, 3)
104
106
 
105
107
  """
106
-
107
108
  # prepare:
109
+ if states_isel is not None:
110
+ farm_results = farm_results.isel({FC.STATE: states_isel})
111
+ if states_sel is not None:
112
+ farm_results = farm_results.sel({FC.STATE: states_sel})
108
113
  n_states = farm_results[FV.H].shape[0]
109
114
 
110
115
  # get base rectangle:
@@ -115,10 +120,22 @@ def get_grid_xy(
115
120
  y_max = ymax if ymax is not None else farm_results[FV.Y].max().to_numpy() + yspace
116
121
  z_max = z if z is not None else farm_results[FV.H].max().to_numpy()
117
122
 
123
+ # compute number of points:
124
+ if resolution is not None and n_img_points is None:
125
+ nx = int((x_max - x_min) / resolution + 0.5) + 1
126
+ ny = int((y_max - y_min) / resolution + 0.5) + 1
127
+ elif resolution is None and n_img_points is not None:
128
+ nx, ny = n_img_points
129
+ else:
130
+ raise ValueError(
131
+ f"Expecting either 'resolution' or 'n_img_points', got: resolution = {resolution}, n_img_points = {n_img_points}"
132
+ )
133
+
134
+ # compute points:
118
135
  x_pos, x_res = np.linspace(
119
136
  x_min,
120
137
  x_max,
121
- num=int((x_max - x_min) / resolution) + 1,
138
+ num=nx,
122
139
  endpoint=True,
123
140
  retstep=True,
124
141
  dtype=None,
@@ -126,7 +143,7 @@ def get_grid_xy(
126
143
  y_pos, y_res = np.linspace(
127
144
  y_min,
128
145
  y_max,
129
- num=int((y_max - y_min) / resolution) + 1,
146
+ num=ny,
130
147
  endpoint=True,
131
148
  retstep=True,
132
149
  dtype=None,
@@ -158,7 +175,8 @@ def get_grid_xy(
158
175
 
159
176
  def get_grid_xz(
160
177
  farm_results,
161
- resolution,
178
+ resolution=None,
179
+ n_img_points=None,
162
180
  x_direction=270,
163
181
  xmin=None,
164
182
  zmin=0.0,
@@ -167,6 +185,8 @@ def get_grid_xz(
167
185
  y=None,
168
186
  xspace=500.0,
169
187
  zspace=500.0,
188
+ states_sel=None,
189
+ states_isel=None,
170
190
  verbosity=0,
171
191
  ):
172
192
  """
@@ -177,8 +197,10 @@ def get_grid_xz(
177
197
  farm_results: xarray.Dataset
178
198
  The farm results. The calculated variables have
179
199
  dimensions (state, turbine)
180
- resolution: float
200
+ resolution: float, optional
181
201
  The resolution in m
202
+ n_img_points: tuple of int, optional
203
+ The number of image points (n, m) in the two directions
182
204
  x_direction: float
183
205
  The direction of the x axis, 0 = north
184
206
  xmin: float
@@ -195,6 +217,10 @@ def get_grid_xz(
195
217
  The extra space in x direction, before and after wind farm
196
218
  zspace: float
197
219
  The extra space in z direction, below and above wind farm
220
+ states_sel: list, optional
221
+ Reduce to selected states
222
+ states_isel: list, optional
223
+ Reduce to the selected states indices
198
224
  verbosity: int, optional
199
225
  The verbosity level
200
226
 
@@ -212,6 +238,10 @@ def get_grid_xz(
212
238
  """
213
239
 
214
240
  # prepare:
241
+ if states_isel is not None:
242
+ farm_results = farm_results.isel({FC.STATE: states_isel})
243
+ if states_sel is not None:
244
+ farm_results = farm_results.sel({FC.STATE: states_sel})
215
245
  n_states, n_turbines = farm_results[FV.H].shape
216
246
  n_x = np.append(wd2uv(x_direction), [0.0], axis=0)
217
247
  n_z = np.array([0.0, 0.0, 1.0])
@@ -236,10 +266,22 @@ def get_grid_xz(
236
266
  y_max = y if y is not None else np.max(yy)
237
267
  del xx, yy, zz
238
268
 
269
+ # compute number of points:
270
+ if resolution is not None and n_img_points is None:
271
+ nx = int((x_max - x_min) / resolution + 0.5) + 1
272
+ nz = int((z_max - z_min) / resolution + 0.5) + 1
273
+ elif resolution is None and n_img_points is not None:
274
+ nx, nz = n_img_points
275
+ else:
276
+ raise ValueError(
277
+ f"Expecting either 'resolution' or 'n_img_points', got: resolution = {resolution}, n_img_points = {n_img_points}"
278
+ )
279
+
280
+ # compute points:
239
281
  x_pos, x_res = np.linspace(
240
282
  x_min,
241
283
  x_max,
242
- num=int((x_max - x_min) / resolution) + 1,
284
+ num=nx,
243
285
  endpoint=True,
244
286
  retstep=True,
245
287
  dtype=None,
@@ -247,7 +289,7 @@ def get_grid_xz(
247
289
  z_pos, z_res = np.linspace(
248
290
  z_min,
249
291
  z_max,
250
- num=int((z_max - z_min) / resolution) + 1,
292
+ num=nz,
251
293
  endpoint=True,
252
294
  retstep=True,
253
295
  dtype=None,
@@ -279,7 +321,8 @@ def get_grid_xz(
279
321
 
280
322
  def get_grid_yz(
281
323
  farm_results,
282
- resolution,
324
+ resolution=None,
325
+ n_img_points=None,
283
326
  x_direction=270,
284
327
  ymin=None,
285
328
  zmin=0.0,
@@ -288,6 +331,8 @@ def get_grid_yz(
288
331
  x=None,
289
332
  yspace=500.0,
290
333
  zspace=500.0,
334
+ states_sel=None,
335
+ states_isel=None,
291
336
  verbosity=0,
292
337
  ):
293
338
  """
@@ -298,8 +343,10 @@ def get_grid_yz(
298
343
  farm_results: xarray.Dataset
299
344
  The farm results. The calculated variables have
300
345
  dimensions (state, turbine)
301
- resolution: float
346
+ resolution: float, optional
302
347
  The resolution in m
348
+ n_img_points: tuple of int, optional
349
+ The number of image points (n, m) in the two directions
303
350
  x_direction: float
304
351
  The direction of the x axis, 0 = north
305
352
  ymin: float
@@ -316,6 +363,10 @@ def get_grid_yz(
316
363
  The extra space in y direction, before and after wind farm
317
364
  zspace: float
318
365
  The extra space in z direction, below and above wind farm
366
+ states_sel: list, optional
367
+ Reduce to selected states
368
+ states_isel: list, optional
369
+ Reduce to the selected states indices
319
370
  verbosity: int, optional
320
371
  The verbosity level
321
372
 
@@ -333,6 +384,10 @@ def get_grid_yz(
333
384
  """
334
385
 
335
386
  # prepare:
387
+ if states_isel is not None:
388
+ farm_results = farm_results.isel({FC.STATE: states_isel})
389
+ if states_sel is not None:
390
+ farm_results = farm_results.sel({FC.STATE: states_sel})
336
391
  n_states, n_turbines = farm_results[FV.H].shape
337
392
  n_x = np.append(wd2uv(x_direction), [0.0], axis=0)
338
393
  n_z = np.array([0.0, 0.0, 1.0])
@@ -357,10 +412,22 @@ def get_grid_yz(
357
412
  x_max = x if x is not None else np.max(xx)
358
413
  del xx, yy, zz
359
414
 
415
+ # compute number of points:
416
+ if resolution is not None and n_img_points is None:
417
+ ny = int((y_max - y_min) / resolution + 0.5) + 1
418
+ nz = int((z_max - z_min) / resolution + 0.5) + 1
419
+ elif resolution is None and n_img_points is not None:
420
+ ny, nz = n_img_points
421
+ else:
422
+ raise ValueError(
423
+ f"Expecting either 'resolution' or 'n_img_points', got: resolution = {resolution}, n_img_points = {n_img_points}"
424
+ )
425
+
426
+ # compute points:
360
427
  y_pos, y_res = np.linspace(
361
428
  y_min,
362
429
  y_max,
363
- num=int((y_max - y_min) / resolution) + 1,
430
+ num=ny,
364
431
  endpoint=True,
365
432
  retstep=True,
366
433
  dtype=None,
@@ -368,7 +435,7 @@ def get_grid_yz(
368
435
  z_pos, z_res = np.linspace(
369
436
  z_min,
370
437
  z_max,
371
- num=int((z_max - z_min) / resolution) + 1,
438
+ num=nz,
372
439
  endpoint=True,
373
440
  retstep=True,
374
441
  dtype=None,
@@ -614,7 +681,10 @@ def np2xr_sp(data, states, a_pos, b_pos, c_pos, ori, label_map={}):
614
681
  return Dataset(
615
682
  coords={s: states, b: b_pos, a: a_pos},
616
683
  data_vars={
617
- v: ((s, b, a), np.swapaxes(d.reshape(n_s, n_a, n_b), 1, 2))
684
+ label_map.get(v, v): (
685
+ (s, b, a),
686
+ np.swapaxes(d.reshape(n_s, n_a, n_b), 1, 2),
687
+ )
618
688
  for v, d in data.items()
619
689
  },
620
690
  attrs={c: float(c_pos)},
@@ -0,0 +1,2 @@
1
+ from .seq_flow_ani_plugin import SeqFlowAnimationPlugin
2
+ from .seq_wake_debug_plugin import SeqWakeDebugPlugin
@@ -1,6 +1,8 @@
1
+ from copy import deepcopy
2
+
1
3
  from foxes.algorithms.sequential import SequentialPlugin
2
4
 
3
- from .flow_plots import FlowPlots2D
5
+ from ..flow_plots_2d.flow_plots import FlowPlots2D
4
6
 
5
7
 
6
8
  class SeqFlowAnimationPlugin(SequentialPlugin):
@@ -12,16 +14,14 @@ class SeqFlowAnimationPlugin(SequentialPlugin):
12
14
  ----------
13
15
  orientation: str
14
16
  The orientation, either "yx", "xz" or "yz"
15
- runner: foxes.utils.runners.Runner
16
- The runner
17
17
  pars: dict
18
18
  Additional parameters for plotting
19
19
 
20
- :group: output.flow_plots_2d
20
+ :group: output.seq_plugins
21
21
 
22
22
  """
23
23
 
24
- def __init__(self, orientation, runner=None, **pars):
24
+ def __init__(self, orientation, **pars):
25
25
  """
26
26
  Constructor.
27
27
 
@@ -29,15 +29,12 @@ class SeqFlowAnimationPlugin(SequentialPlugin):
29
29
  ----------
30
30
  orientation: str
31
31
  The orientation, either "yx", "xz" or "yz"
32
- runner: foxes.utils.runners.Runner, optional
33
- The runner
34
32
  pars: dict, optional
35
33
  Additional parameters for plotting
36
34
 
37
35
  """
38
36
  super().__init__()
39
37
  self.orientation = orientation
40
- self.runner = runner
41
38
  self.pars = pars
42
39
 
43
40
  if "title" in self.pars and callable(self.pars["title"]):
@@ -74,28 +71,73 @@ class SeqFlowAnimationPlugin(SequentialPlugin):
74
71
  """
75
72
  super().update(algo, fres, pres)
76
73
 
77
- o = FlowPlots2D(algo, fres, self.runner)
74
+ o = FlowPlots2D(algo, fres)
78
75
 
79
76
  if self._tfun is not None:
80
77
  self.pars["title"] = self._tfun(algo.states.counter, algo.states.index()[0])
81
78
 
82
79
  if self.orientation == "xy":
83
- self._data.append(next(o.gen_states_fig_xy(**self.pars)))
80
+ d = next(o.gen_states_fig_xy(**self.pars, precalc=True))
84
81
  elif self.orientation == "xz":
85
- self._data.append(next(o.gen_states_fig_xz(**self.pars)))
82
+ d = next(o.gen_states_fig_xz(**self.pars, precalc=True))
86
83
  elif self.orientation == "yz":
87
- self._data.append(next(o.gen_states_fig_yz(**self.pars)))
84
+ d = next(o.gen_states_fig_yz(**self.pars, precalc=True))
88
85
  else:
89
86
  raise KeyError(
90
87
  f"Unkown orientation '{self.orientation}', choises: xy, xz, yz"
91
88
  )
92
89
 
93
- if (
94
- self.pars.get("vmin", None) is not None
95
- and self.pars.get("vmax", None) is not None
96
- ):
97
- self.pars["add_bar"] = False
90
+ # minimize stored data:
91
+ od = [d[0], d[1], None]
92
+ if len(self._data) == 0:
93
+ od[2] = d[2]
94
+ of = (
95
+ fres
96
+ if ("rotor_color" in self.pars and self.pars["rotor_color"] is not None)
97
+ else None
98
+ )
99
+
100
+ self._data.append((of, od))
101
+
102
+ def gen_images(self, ax):
103
+ """
104
+
105
+ Parameters
106
+ ----------
107
+ ax: matplotlib.Axis
108
+ The plotting axis
109
+
110
+ Yields
111
+ ------
112
+ imgs: tuple
113
+ The (figure, artists) tuple
114
+
115
+ """
116
+ fig = ax.get_figure()
117
+ gdata = None
118
+ while len(self._data):
119
+
120
+ fres, d = self._data.pop(0)
121
+
122
+ if d[2] is not None:
123
+ gdata = d[2]
124
+
125
+ o = FlowPlots2D(self.algo, fres)
126
+
127
+ yield next(
128
+ o.gen_states_fig_xy(
129
+ **self.pars,
130
+ ax=ax,
131
+ fig=fig,
132
+ ret_im=True,
133
+ precalc=(d[0], d[1], gdata),
134
+ )
135
+ )
136
+
137
+ del o, fres, d
98
138
 
99
- def gen_images(self):
100
- for d in self._data:
101
- yield d
139
+ if (
140
+ self.pars.get("vmin", None) is not None
141
+ and self.pars.get("vmax", None) is not None
142
+ ):
143
+ self.pars["add_bar"] = False
@@ -0,0 +1,145 @@
1
+ from foxes.algorithms.sequential import SequentialPlugin
2
+ from foxes.models.wake_frames.seq_dynamic_wakes import SeqDynamicWakes
3
+
4
+
5
+ class SeqWakeDebugPlugin(SequentialPlugin):
6
+ """
7
+ Plugin for creating wake debug plots in animations
8
+
9
+ Attributes
10
+ ----------
11
+ show_p: bool
12
+ Flag for showing wake points
13
+ show_v: bool
14
+ Flag for showing wake vectors
15
+ vpars: dict
16
+ Additional parameters for vector lines
17
+ ppars: dict
18
+ Additional parameters for point scatter
19
+
20
+ :group: output.seq_plugins
21
+
22
+ """
23
+
24
+ def __init__(self, show_p=True, show_v=True, vpars={}, **ppars):
25
+ """
26
+ Constructor.
27
+
28
+ Parameters
29
+ ----------
30
+ show_p: bool
31
+ Flag for showing wake points
32
+ show_v: bool
33
+ Flag for showing wake vectors
34
+ vpars: dict
35
+ Additional parameters for vector lines
36
+ ppars: dict, optional
37
+ Additional parameters for point scatter
38
+
39
+ """
40
+ super().__init__()
41
+ self.show_p = show_p
42
+ self.show_v = show_v
43
+
44
+ self.vpars = dict(color="blue")
45
+ self.vpars.update(vpars)
46
+
47
+ self.ppars = dict(color="blue")
48
+ self.ppars.update(ppars)
49
+
50
+ def initialize(self, algo):
51
+ """
52
+ Initialize data based on the intial iterator
53
+
54
+ Parameters
55
+ ----------
56
+ algo: foxes.algorithms.sequential.Sequential
57
+ The current sequetial algorithm
58
+
59
+ """
60
+ super().initialize(algo)
61
+ self._data = []
62
+
63
+ def update(self, algo, fres, pres=None):
64
+ """
65
+ Updates data based on current iteration
66
+
67
+ Parameters
68
+ ----------
69
+ algo: foxes.algorithms.sequential.Sequential
70
+ The latest sequetial algorithm
71
+ fres: xarray.Dataset
72
+ The latest farm results
73
+ pres: xarray.Dataset, optional
74
+ The latest point results
75
+
76
+ """
77
+ super().update(algo, fres, pres)
78
+
79
+ wframe = algo.wake_frame
80
+ if not isinstance(wframe, SeqDynamicWakes):
81
+ raise ValueError(
82
+ f"Wake frame not of type SeqDynamicWakes, got {type(algo.wake_frame).__name__}"
83
+ )
84
+
85
+ counter = algo.counter
86
+ N = counter + 1
87
+ dt = wframe._dt[counter] if counter < len(wframe._dt) else wframe._dt[-1]
88
+
89
+ self._data.append(
90
+ (
91
+ dt,
92
+ wframe._traces_p[:N].copy(),
93
+ wframe._traces_v[:N].copy(),
94
+ )
95
+ )
96
+
97
+ def gen_images(self, ax):
98
+ """
99
+
100
+ Parameters
101
+ ----------
102
+ ax: matplotlib.Axis
103
+ The plotting axis
104
+
105
+ Yields
106
+ ------
107
+ imgs: tuple
108
+ The (figure, artists) tuple
109
+
110
+ """
111
+ while len(self._data):
112
+
113
+ dt, pts, v = self._data.pop(0)
114
+
115
+ N = len(pts)
116
+ artists = []
117
+ if self.show_p:
118
+ artists += [
119
+ ax.scatter(
120
+ pts[:, downwind_index, 0],
121
+ pts[:, downwind_index, 1],
122
+ animated=True,
123
+ **self.ppars,
124
+ )
125
+ for downwind_index in range(self.algo.n_turbines)
126
+ ]
127
+
128
+ if self.show_v:
129
+ for downwind_index in range(self.algo.n_turbines):
130
+ for i in range(N):
131
+ p = pts[i, downwind_index]
132
+ dxy = v[i, downwind_index] * dt
133
+ artists.append(
134
+ ax.arrow(
135
+ p[0],
136
+ p[1],
137
+ dxy[0],
138
+ dxy[1],
139
+ length_includes_head=True,
140
+ animated=True,
141
+ **self.vpars,
142
+ )
143
+ )
144
+
145
+ yield ax.get_figure(), artists