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
foxes/__init__.py CHANGED
@@ -1,26 +1,30 @@
1
1
  """
2
2
  Farm Optimization and eXtended yield Evaluation Software
3
-
3
+
4
4
  """
5
5
 
6
- from .config import config, get_path # noqa: F401
7
- from .core import Engine, WindFarm, Turbine, get_engine, reset_engine # noqa: F401
8
- from .models import ModelBook # noqa: F401
9
- from .data import (
10
- parse_Pct_file_name,
11
- parse_Pct_two_files,
12
- FARM,
13
- STATES,
14
- PCTCURVE,
15
- StaticData,
16
- ) # noqa: F401
6
+ from .config import config as config
7
+ from .config import get_path as get_path
8
+ from .core import Engine as Engine
9
+ from .core import WindFarm as WindFarm
10
+ from .core import Turbine as Turbine
11
+ from .core import get_engine as get_engine
12
+ from .core import reset_engine as reset_engine
13
+ from .models import ModelBook as ModelBook
14
+
15
+ from .data import parse_Pct_file_name as parse_Pct_file_name
16
+ from .data import parse_Pct_two_files as parse_Pct_two_files
17
+ from .data import FARM as FARM
18
+ from .data import STATES as STATES
19
+ from .data import PCTCURVE as PCTCURVE
20
+ from .data import StaticData as StaticData
17
21
 
18
- from . import algorithms # noqa: F401
19
- from . import engines # noqa: F401
20
- from . import models # noqa: F401
21
- from . import input # noqa: F401
22
- from . import output # noqa: F401
23
- from . import utils # noqa: F401
22
+ from . import algorithms as algorithms
23
+ from . import engines as engines
24
+ from . import models as models
25
+ from . import input as input
26
+ from . import output as output
27
+ from . import utils as utils
24
28
 
25
29
  import importlib
26
30
  from pathlib import Path
@@ -2,10 +2,10 @@
2
2
  Algorithms define the main calculation routines.
3
3
  """
4
4
 
5
- from .downwind.downwind import Downwind
6
- from .iterative.iterative import Iterative
7
- from .sequential import Sequential
5
+ from .downwind.downwind import Downwind as Downwind
6
+ from .iterative.iterative import Iterative as Iterative
7
+ from .sequential import Sequential as Sequential
8
8
 
9
- from . import downwind
10
- from . import iterative
11
- from . import sequential
9
+ from . import downwind as downwind
10
+ from . import iterative as iterative
11
+ from . import sequential as sequential
@@ -1,3 +1,3 @@
1
- from .downwind import Downwind
1
+ from .downwind import Downwind as Downwind
2
2
 
3
- from . import models
3
+ from . import models as models
@@ -32,6 +32,8 @@ class Downwind(Algorithm):
32
32
  partial_wakes: dict
33
33
  The partial wakes mapping. Key: wake model name,
34
34
  value: foxes.core.PartialWakesModel
35
+ deflection: foxes.core.WakeDeflection
36
+ The wake deflection model
35
37
  ground_models: dict
36
38
  The ground models mapping. Key: wake model name,
37
39
  value: foxes.core.GroundModel
@@ -61,8 +63,6 @@ class Downwind(Algorithm):
61
63
  FV.TI,
62
64
  FV.CT,
63
65
  FV.P,
64
- FV.ORDER,
65
- FV.WEIGHT,
66
66
  ]
67
67
 
68
68
  def __init__(
@@ -72,6 +72,7 @@ class Downwind(Algorithm):
72
72
  wake_models,
73
73
  rotor_model="centre",
74
74
  wake_frame="rotor_wd",
75
+ wake_deflection="no_deflection",
75
76
  partial_wakes=None,
76
77
  ground_models=None,
77
78
  farm_controller="basic_ctrl",
@@ -96,6 +97,8 @@ class Downwind(Algorithm):
96
97
  wake_frame: str
97
98
  The wake frame. Will be looked up in the
98
99
  model book
100
+ deflection: foxes.core.WakeDeflection, optional
101
+ The wake deflection model
99
102
  partial_wakes: dict, list or str, optional
100
103
  The partial wakes mapping. Key: wake model name,
101
104
  value: partial wake model name
@@ -125,6 +128,9 @@ class Downwind(Algorithm):
125
128
  self.__wake_frame = self.mbook.wake_frames.get_item(wake_frame)
126
129
  self.wake_frame.name = wake_frame
127
130
 
131
+ self.__wake_deflection = self.mbook.wake_deflections.get_item(wake_deflection)
132
+ self.wake_deflection.name = wake_deflection
133
+
128
134
  self.__wake_models = {}
129
135
  for w in wake_models:
130
136
  m = self.mbook.wake_models.get_item(w)
@@ -253,6 +259,19 @@ class Downwind(Algorithm):
253
259
  """
254
260
  return self.__wake_frame
255
261
 
262
+ @property
263
+ def wake_deflection(self):
264
+ """
265
+ The wake deflection
266
+
267
+ Returns
268
+ -------
269
+ m: foxes.core.WakeDeflection
270
+ The wake deflection model
271
+
272
+ """
273
+ return self.__wake_deflection
274
+
256
275
  @property
257
276
  def partial_wakes(self):
258
277
  """
@@ -312,6 +331,15 @@ class Downwind(Algorithm):
312
331
  """
313
332
  return getattr(mdls, name)
314
333
 
334
+ def update_n_turbines(self):
335
+ """
336
+ Reset the number of turbines,
337
+ according to self.farm
338
+ """
339
+ if self.n_turbines != self.farm.n_turbines:
340
+ super().update_n_turbines()
341
+ self.farm_controller.find_turbine_types(self)
342
+
315
343
  def print_deco(self, func_name=None, n_points=None):
316
344
  """
317
345
  Helper function for printing model names
@@ -336,25 +364,26 @@ class Downwind(Algorithm):
336
364
  if n_points is not None:
337
365
  print(f" n_points : {n_points}")
338
366
  print(deco)
339
- print(f" states : {self.states}")
340
- print(f" rotor : {self.rotor_model}")
367
+ print(f" states : {self.states}")
368
+ print(f" rotor : {self.rotor_model}")
341
369
  print(f" controller: {self.farm_controller}")
342
370
  print(f" wake frame: {self.wake_frame}")
371
+ print(f" deflection: {self.wake_deflection}")
343
372
  print(deco)
344
- print(f" wakes:")
373
+ print(" wakes:")
345
374
  for i, w in enumerate(self.wake_models.values()):
346
375
  print(f" {i}) {w.name}: {w}")
347
376
  print(deco)
348
- print(f" partial wakes:")
377
+ print(" partial wakes:")
349
378
  for i, (w, p) in enumerate(self.partial_wakes.items()):
350
379
  print(f" {i}) {w}: {p.name}, {p}")
351
380
  print(deco)
352
- print(f" turbine models:")
381
+ print(" turbine models:")
353
382
  for i, m in enumerate(self.farm_controller.pre_rotor_models.models):
354
383
  print(f" {i}) {m.name}: {m} [pre-rotor]")
355
384
  for i, m in enumerate(self.farm_controller.post_rotor_models.models):
356
385
  print(
357
- f" {i+len(self.farm_controller.pre_rotor_models.models)}) {m.name}: {m}"
386
+ f" {i + len(self.farm_controller.pre_rotor_models.models)}) {m.name}: {m}"
358
387
  )
359
388
  print(deco)
360
389
  print()
@@ -366,7 +395,7 @@ class Downwind(Algorithm):
366
395
  if self.verbosity > 0:
367
396
  deco = "-" * 50
368
397
  print(f"\n{deco}")
369
- print(f" Model oder")
398
+ print(" Model oder")
370
399
  print(f"{deco}")
371
400
 
372
401
  for i, m in enumerate(mlist.models):
@@ -404,6 +433,7 @@ class Downwind(Algorithm):
404
433
  self.states,
405
434
  self.farm_controller,
406
435
  self.rotor_model,
436
+ self.wake_deflection,
407
437
  self.wake_frame,
408
438
  ]
409
439
  mdls += list(self.wake_models.values())
@@ -447,9 +477,7 @@ class Downwind(Algorithm):
447
477
  # 2) calculate ambient rotor results:
448
478
  mlist.models.append(self.rotor_model)
449
479
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
450
- calc_pars[-1].update(
451
- {"store_rpoints": True, "store_rweights": True, "store_amb_res": True}
452
- )
480
+ calc_pars[-1].update({"store": True})
453
481
 
454
482
  # 3) run post-rotor turbine models via farm controller:
455
483
  mlist.models.append(self.farm_controller)
@@ -467,7 +495,7 @@ class Downwind(Algorithm):
467
495
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
468
496
 
469
497
  # 6) reorder back to state-turbine dimensions:
470
- if outputs != False:
498
+ if not isinstance(outputs, bool) or outputs:
471
499
  mlist.models.append(self.get_model("ReorderFarmOutput")(outputs))
472
500
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
473
501
 
@@ -475,13 +503,14 @@ class Downwind(Algorithm):
475
503
 
476
504
  def _calc_farm_vars(self, mlist):
477
505
  """Helper function that gathers the farm variables"""
478
- self.farm_vars = sorted(list(set([FV.WEIGHT] + mlist.output_farm_vars(self))))
506
+ self.farm_vars = sorted(list(mlist.output_farm_vars(self)))
479
507
 
480
508
  def _launch_parallel_farm_calc(
481
509
  self,
482
510
  mlist,
483
511
  *data,
484
512
  outputs=None,
513
+ normalize=False,
485
514
  **kwargs,
486
515
  ):
487
516
  """
@@ -495,6 +524,8 @@ class Downwind(Algorithm):
495
524
  The (mdata, fdata) inputs
496
525
  outputs: list of str, optional
497
526
  The output variables, or None for defaults
527
+ normalize: bool
528
+ Normalize the weights to 1 wrt sum over states
498
529
  kwargs: dict, optional
499
530
  Additional parameters for running
500
531
 
@@ -510,6 +541,9 @@ class Downwind(Algorithm):
510
541
  self, mlist, *data, out_vars=out_vars, **kwargs
511
542
  )
512
543
 
544
+ if normalize:
545
+ farm_results[FV.WEIGHT] /= farm_results[FV.WEIGHT].sum(dim=FC.STATE)
546
+
513
547
  return farm_results
514
548
 
515
549
  def calc_farm(
@@ -571,8 +605,8 @@ class Downwind(Algorithm):
571
605
  # get input model data:
572
606
  model_data = self.get_models_data()
573
607
  self.print("\nInput data:\n\n", model_data, "\n")
574
- self.print(f"\nFarm variables:", ", ".join(self.farm_vars))
575
- self.print(f"\nOutput variables:", ", ".join(outputs))
608
+ self.print("\nFarm variables:", ", ".join(self.farm_vars))
609
+ self.print("\nOutput variables:", ", ".join(outputs))
576
610
 
577
611
  # run main calculation:
578
612
  farm_results = super().calc_farm(
@@ -679,13 +713,7 @@ class Downwind(Algorithm):
679
713
  """
680
714
  return (
681
715
  get_engine()
682
- .run_calculation(
683
- self,
684
- mlist,
685
- *data,
686
- out_vars=outputs,
687
- **kwargs,
688
- )
716
+ .run_calculation(self, mlist, *data, out_vars=outputs, **kwargs)
689
717
  .sel({FC.TPOINT: 0})
690
718
  .rename({FC.TARGET: FC.POINT})
691
719
  )
@@ -783,7 +811,7 @@ class Downwind(Algorithm):
783
811
  if persist_mdata:
784
812
  model_data = model_data.persist()
785
813
  self.print("\nInput data:\n\n", model_data, "\n")
786
- self.print(f"\nOutput farm variables:", ", ".join(self.farm_vars))
814
+ self.print("\nOutput farm variables:", ", ".join(self.farm_vars))
787
815
 
788
816
  # chunk farm results:
789
817
  self.print("\nInput farm data:\n\n", farm_results, "\n")
@@ -802,7 +830,7 @@ class Downwind(Algorithm):
802
830
 
803
831
  # check vars:
804
832
  ovars = mlist.output_point_vars(self) if outputs is None else outputs
805
- self.print(f"\nOutput point variables:", ", ".join(ovars))
833
+ self.print("\nOutput point variables:", ", ".join(ovars))
806
834
 
807
835
  # calculate:
808
836
  point_results = super().calc_points(
@@ -812,8 +840,6 @@ class Downwind(Algorithm):
812
840
  point_data,
813
841
  outputs=ovars,
814
842
  parameters=calc_pars,
815
- # sel=sel,
816
- # isel=isel,
817
843
  **kwargs,
818
844
  )
819
845
  del model_data, farm_results, point_data
@@ -1,6 +1,6 @@
1
- from .set_amb_farm_results import SetAmbFarmResults
2
- from .set_amb_point_results import SetAmbPointResults
3
- from .farm_wakes_calc import FarmWakesCalculation
4
- from .point_wakes_calc import PointWakesCalculation
5
- from .init_farm_data import InitFarmData
6
- from .reorder_farm_output import ReorderFarmOutput
1
+ from .set_amb_farm_results import SetAmbFarmResults as SetAmbFarmResults
2
+ from .set_amb_point_results import SetAmbPointResults as SetAmbPointResults
3
+ from .farm_wakes_calc import FarmWakesCalculation as FarmWakesCalculation
4
+ from .point_wakes_calc import PointWakesCalculation as PointWakesCalculation
5
+ from .init_farm_data import InitFarmData as InitFarmData
6
+ from .reorder_farm_output import ReorderFarmOutput as ReorderFarmOutput
@@ -1,8 +1,9 @@
1
1
  import numpy as np
2
2
  from copy import deepcopy
3
3
 
4
- from foxes.core import FarmDataModel, TData
4
+ from foxes.core import FarmDataModel
5
5
  import foxes.constants as FC
6
+ import foxes.variables as FV
6
7
 
7
8
 
8
9
  class FarmWakesCalculation(FarmDataModel):
@@ -58,8 +59,9 @@ class FarmWakesCalculation(FarmDataModel):
58
59
  """
59
60
  # collect ambient rotor results and weights:
60
61
  rotor = algo.rotor_model
61
- weights = algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata)
62
+ rwghts = algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata)
62
63
  amb_res = algo.get_from_chunk_store(FC.AMB_ROTOR_RES, mdata=mdata)
64
+ weights = algo.get_from_chunk_store(FC.WEIGHT_RES, mdata=mdata)
63
65
 
64
66
  # generate all wake evaluation points
65
67
  # (n_states, n_order, n_rpoints)
@@ -67,8 +69,14 @@ class FarmWakesCalculation(FarmDataModel):
67
69
  for wname, wmodel in algo.wake_models.items():
68
70
  pwake = algo.partial_wakes[wname]
69
71
  if pwake.name not in pwake2tdata:
70
- tpoints, tweights = pwake.get_wake_points(algo, mdata, fdata)
71
- pwake2tdata[pwake.name] = TData.from_tpoints(tpoints, tweights)
72
+ wmodels = [
73
+ wm
74
+ for wn, wm in algo.wake_models.items()
75
+ if algo.partial_wakes[wn] is pwake
76
+ ]
77
+ pwake2tdata[pwake.name] = pwake.get_initial_tdata(
78
+ algo, mdata, fdata, amb_res, rwghts, wmodels
79
+ )
72
80
 
73
81
  def _get_wdata(tdatap, wdeltas, variables, s):
74
82
  """Helper function for wake data extraction"""
@@ -76,21 +84,23 @@ class FarmWakesCalculation(FarmDataModel):
76
84
  wdelta = {v: d[s] for v, d in wdeltas.items()}
77
85
  return tdata, wdelta
78
86
 
79
- def _evaluate(
80
- gmodel, tdata, amb_res, weights, wake_res, wdeltas, oi, wmodel, pwake
81
- ):
87
+ def _evaluate(gmodel, tdata, rwghts, wake_res, wdeltas, oi, wmodel, pwake):
82
88
  """Helper function for data evaluation at turbines"""
83
89
  wres = gmodel.finalize_farm_wakes(
84
- algo, mdata, fdata, tdata, amb_res, weights, wdeltas, wmodel, oi, pwake
90
+ algo, mdata, fdata, tdata, rwghts, wdeltas, wmodel, oi, pwake
85
91
  )
86
92
 
87
- hres = {v: d[:, oi, None] for v, d in wake_res.items()}
93
+ hres = {
94
+ v: d[:, oi, None] if d.shape[1] > 1 else d[:, 0, None]
95
+ for v, d in wake_res.items()
96
+ }
88
97
  for v, d in wres.items():
89
98
  if v in wake_res:
90
99
  hres[v] += d[:, None]
100
+ hres[FV.WEIGHT] = weights
91
101
 
92
102
  rotor.eval_rpoint_results(
93
- algo, mdata, fdata, hres, weights, downwind_index=oi
103
+ algo, mdata, fdata, hres, rwghts, downwind_index=oi
94
104
  )
95
105
 
96
106
  res = algo.farm_controller.calculate(
@@ -118,8 +128,7 @@ class FarmWakesCalculation(FarmDataModel):
118
128
  _evaluate(
119
129
  gmodel,
120
130
  tdatap,
121
- amb_res,
122
- weights,
131
+ rwghts,
123
132
  wake_res,
124
133
  wdeltas,
125
134
  oi,
@@ -143,8 +152,7 @@ class FarmWakesCalculation(FarmDataModel):
143
152
  _evaluate(
144
153
  gmodel,
145
154
  tdatap,
146
- amb_res,
147
- weights,
155
+ rwghts,
148
156
  wake_res,
149
157
  wdeltas,
150
158
  oi,
@@ -43,7 +43,6 @@ class InitFarmData(FarmDataModel):
43
43
  FV.WD,
44
44
  FV.YAW,
45
45
  FV.ORDER,
46
- FV.WEIGHT,
47
46
  FV.ORDER_SSEL,
48
47
  FV.ORDER_INV,
49
48
  ]
@@ -87,7 +86,6 @@ class InitFarmData(FarmDataModel):
87
86
  # set X, Y, H, D:
88
87
  fdata[FV.D] = np.zeros((n_states, n_turbines), dtype=config.dtype_double)
89
88
  for ti, t in enumerate(algo.farm.turbines):
90
-
91
89
  if len(t.xy.shape) == 1:
92
90
  fdata[FV.TXYH][:, ti, :2] = t.xy[None, :]
93
91
  else:
@@ -106,10 +104,11 @@ class InitFarmData(FarmDataModel):
106
104
  fdata[FV.D][:, ti] = D
107
105
 
108
106
  # calc WD and YAW at rotor centres:
109
- tdata = TData.from_points(points=fdata[FV.TXYH])
107
+ svrs = algo.states.output_point_vars(algo)
108
+ tdata = TData.from_points(points=fdata[FV.TXYH], variables=svrs)
110
109
  sres = algo.states.calculate(algo, mdata, fdata, tdata)
111
110
  fdata[FV.WD] = sres[FV.WD][:, :, 0]
112
- del tdata, sres
111
+ del tdata, sres, svrs
113
112
 
114
113
  # calculate and inverse:
115
114
  order = algo.wake_frame.calc_order(algo, mdata, fdata)
@@ -124,7 +123,7 @@ class InitFarmData(FarmDataModel):
124
123
  fdata[FV.TXYH] = fdata[FV.TXYH][ssel, order]
125
124
  for i, v in enumerate([FV.X, FV.Y, FV.H]):
126
125
  fdata[v] = fdata[FV.TXYH][..., i]
127
- for v in [FV.D, FV.WD, FV.WEIGHT]:
126
+ for v in [FV.D, FV.WD]:
128
127
  if np.any(fdata[v] != fdata[v][0, 0, None, None]):
129
128
  fdata[v] = fdata[v][ssel, order]
130
129
  fdata[FV.YAW] = fdata[FV.WD].copy()
@@ -1,4 +1,5 @@
1
1
  from foxes.core import PointDataModel
2
+ import foxes.variables as FV
2
3
 
3
4
 
4
5
  class PointWakesCalculation(PointDataModel):
@@ -114,17 +115,17 @@ class PointWakesCalculation(PointDataModel):
114
115
  (n_states, n_targets, n_tpoints)
115
116
 
116
117
  """
117
- res = {}
118
+
118
119
  wmodels = (
119
120
  algo.wake_models.values() if self.wake_models is None else self.wake_models
120
121
  )
122
+ pvrs = self.pvars + [FV.UV]
121
123
  for wmodel in wmodels:
122
124
  gmodel = algo.ground_models[wmodel.name]
123
125
 
124
126
  wdeltas = gmodel.new_point_wake_deltas(algo, mdata, fdata, tdata, wmodel)
125
127
 
126
- if len(set(self.pvars).intersection(wdeltas.keys())):
127
-
128
+ if len(set(pvrs).intersection(wdeltas.keys())):
128
129
  if downwind_index is None:
129
130
  for oi in range(fdata.n_turbines):
130
131
  gmodel.contribute_to_point_wakes(
@@ -135,18 +136,11 @@ class PointWakesCalculation(PointDataModel):
135
136
  algo, mdata, fdata, tdata, downwind_index, wdeltas, wmodel
136
137
  )
137
138
 
138
- for v in self.pvars:
139
- if v not in res and v in tdata:
140
- res[v] = tdata[v].copy()
139
+ gmodel.finalize_point_wakes(algo, mdata, fdata, tdata, wdeltas, wmodel)
141
140
 
142
- gmodel.finalize_point_wakes(algo, mdata, fdata, res, wdeltas, wmodel)
143
-
144
- for v in res.keys():
141
+ for v in tdata.keys():
145
142
  if v in wdeltas:
146
- res[v] += wdeltas[v]
147
-
148
- for v in res.keys():
149
- tdata[v] = res[v]
143
+ tdata[v] += wdeltas[v]
150
144
 
151
145
  if self.emodels is not None:
152
146
  self.emodels.calculate(algo, mdata, fdata, tdata, self.emodels_cpars)
@@ -75,7 +75,11 @@ class ReorderFarmOutput(FarmDataModel):
75
75
 
76
76
  out = {}
77
77
  for v in self.output_farm_vars(algo):
78
- if v != FV.ORDER and np.any(fdata[v] != fdata[v][0, 0, None, None]):
78
+ if (
79
+ v != FV.ORDER
80
+ and fdata[v].shape[1] > 1
81
+ and np.any(fdata[v] != fdata[v][0, 0, None, None])
82
+ ):
79
83
  out[v] = fdata[v][ssel, order_inv]
80
84
  else:
81
85
  out[v] = fdata[v]
@@ -58,9 +58,9 @@ class SetAmbPointResults(PointDataModel):
58
58
  The output variable names
59
59
 
60
60
  """
61
- return [FV.var2amb[v] for v in self.vars]
61
+ return [FV.var2amb[v] for v in self.vars] + [FV.WEIGHT]
62
62
 
63
- def calculate(self, algo, mdata, fdata, pdata):
63
+ def calculate(self, algo, mdata, fdata, tdata):
64
64
  """
65
65
  The main model calculation.
66
66
 
@@ -71,11 +71,11 @@ class SetAmbPointResults(PointDataModel):
71
71
  ----------
72
72
  algo: foxes.core.Algorithm
73
73
  The calculation algorithm
74
- mdata: foxes.core.Data
74
+ mdata: foxes.core.MData
75
75
  The model data
76
- fdata: foxes.core.Data
76
+ fdata: foxes.core.FData
77
77
  The farm data
78
- pdata: foxes.core.Data
78
+ tdata: foxes.core.TData
79
79
  The point data
80
80
 
81
81
  Returns
@@ -86,5 +86,5 @@ class SetAmbPointResults(PointDataModel):
86
86
 
87
87
  """
88
88
  for v in self.vars:
89
- pdata[FV.var2amb[v]] = pdata[v].copy()
90
- return {v: pdata[v] for v in self.output_point_vars(algo)}
89
+ tdata.add(FV.var2amb[v], tdata[v].copy(), tdata.dims[v])
90
+ return {v: tdata[v] for v in self.output_point_vars(algo)}
@@ -1,4 +1,8 @@
1
- from .iterative import Iterative
2
- from .models.convergence import ConvCrit, ConvCritList, ConvVarDelta, DefaultConv
1
+ from .iterative import Iterative as Iterative
3
2
 
4
- from . import models
3
+ from .models.convergence import ConvCrit as ConvCrit
4
+ from .models.convergence import ConvCritList as ConvCritList
5
+ from .models.convergence import ConvVarDelta as ConvVarDelta
6
+ from .models.convergence import DefaultConv as DefaultConv
7
+
8
+ from . import models as models
@@ -114,7 +114,7 @@ class Iterative(Downwind):
114
114
 
115
115
  """
116
116
  if self.initialized:
117
- raise ValueError(f"Attempt to set_urelax after initialization")
117
+ raise ValueError("Attempt to set_urelax after initialization")
118
118
  if self._urelax is None:
119
119
  self._urelax = Dict(
120
120
  first={},
@@ -219,7 +219,6 @@ class Iterative(Downwind):
219
219
 
220
220
  # do not rotate back from downwind order:
221
221
  if not self._final_run:
222
-
223
222
  # add under-relaxation during wake calculation:
224
223
  urelax = None
225
224
  if self._urelax is not None and len(self._urelax["pre_wake"]):
@@ -1,3 +1,7 @@
1
- from .convergence import ConvCrit, ConvCritList, ConvVarDelta, DefaultConv
2
- from .farm_wakes_calc import FarmWakesCalculation
3
- from .urelax import URelax
1
+ from .convergence import ConvCrit as ConvCrit
2
+ from .convergence import ConvCritList as ConvCritList
3
+ from .convergence import ConvVarDelta as ConvVarDelta
4
+ from .convergence import DefaultConv as DefaultConv
5
+
6
+ from .farm_wakes_calc import FarmWakesCalculation as FarmWakesCalculation
7
+ from .urelax import URelax as URelax
@@ -1,8 +1,9 @@
1
1
  import numpy as np
2
2
  from copy import deepcopy
3
3
 
4
- from foxes.core import FarmDataModel, TData
4
+ from foxes.core import FarmDataModel
5
5
  import foxes.constants as FC
6
+ import foxes.variables as FV
6
7
 
7
8
 
8
9
  class FarmWakesCalculation(FarmDataModel):
@@ -88,8 +89,9 @@ class FarmWakesCalculation(FarmDataModel):
88
89
  """
89
90
  # collect ambient rotor results and weights:
90
91
  rotor = algo.rotor_model
91
- weights = algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata)
92
+ rwghts = algo.get_from_chunk_store(FC.ROTOR_WEIGHTS, mdata=mdata)
92
93
  amb_res = algo.get_from_chunk_store(FC.AMB_ROTOR_RES, mdata=mdata)
94
+ weights = algo.get_from_chunk_store(FC.WEIGHT_RES, mdata=mdata)
93
95
 
94
96
  # generate all wake evaluation points
95
97
  # (n_states, n_order, n_rpoints)
@@ -97,8 +99,14 @@ class FarmWakesCalculation(FarmDataModel):
97
99
  for wname, wmodel in algo.wake_models.items():
98
100
  pwake = algo.partial_wakes[wname]
99
101
  if pwake.name not in pwake2tdata:
100
- tpoints, tweights = pwake.get_wake_points(algo, mdata, fdata)
101
- pwake2tdata[pwake.name] = TData.from_tpoints(tpoints, tweights)
102
+ wmodels = [
103
+ wm
104
+ for wn, wm in algo.wake_models.items()
105
+ if algo.partial_wakes[wn] is pwake
106
+ ]
107
+ pwake2tdata[pwake.name] = pwake.get_initial_tdata(
108
+ algo, mdata, fdata, amb_res, rwghts, wmodels
109
+ )
102
110
 
103
111
  def _get_wdata(tdatap, wdeltas, variables, s):
104
112
  """Helper function for wake data extraction"""
@@ -115,7 +123,6 @@ class FarmWakesCalculation(FarmDataModel):
115
123
  wdeltas = pwake.new_wake_deltas(algo, mdata, fdata, tdatap, wmodel)
116
124
 
117
125
  for oi in range(n_turbines):
118
-
119
126
  if oi > 0:
120
127
  tdata, wdelta = _get_wdata(
121
128
  tdatap, wdeltas, [FC.STATE, FC.TARGET], np.s_[:, :oi]
@@ -138,8 +145,7 @@ class FarmWakesCalculation(FarmDataModel):
138
145
  mdata,
139
146
  fdata,
140
147
  tdatap,
141
- amb_res,
142
- weights,
148
+ rwghts,
143
149
  wdeltas,
144
150
  wmodel,
145
151
  oi,
@@ -151,7 +157,8 @@ class FarmWakesCalculation(FarmDataModel):
151
157
 
152
158
  del pwake, tdatap, wdeltas
153
159
 
154
- rotor.eval_rpoint_results(algo, mdata, fdata, wake_res, weights)
160
+ wake_res[FV.WEIGHT] = weights
161
+ rotor.eval_rpoint_results(algo, mdata, fdata, wake_res, rwghts)
155
162
  res = algo.farm_controller.calculate(algo, mdata, fdata, pre_rotor=False)
156
163
  if self.urelax is not None:
157
164
  res = self.urelax.calculate(algo, mdata, fdata, res)
@@ -1,4 +1,4 @@
1
- from .sequential import Sequential
2
- from .models import SequentialPlugin
1
+ from .sequential import Sequential as Sequential
2
+ from .models import SequentialPlugin as SequentialPlugin
3
3
 
4
- from . import models
4
+ from . import models as models
@@ -1,2 +1,2 @@
1
- from .plugin import SequentialPlugin
2
- from .seq_state import SeqState
1
+ from .plugin import SequentialPlugin as SequentialPlugin
2
+ from .seq_state import SeqState as SeqState