foxes 1.3__py3-none-any.whl → 1.5__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 (228) 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/field_data_nc/run.py +1 -1
  7. examples/induction/run.py +3 -3
  8. examples/multi_height/run.py +1 -1
  9. examples/power_mask/run.py +2 -2
  10. examples/quickstart/run.py +0 -1
  11. examples/random_timeseries/run.py +3 -4
  12. examples/scan_row/run.py +3 -3
  13. examples/sequential/run.py +33 -10
  14. examples/single_state/run.py +3 -4
  15. examples/states_lookup_table/run.py +3 -3
  16. examples/streamline_wakes/run.py +29 -6
  17. examples/tab_file/run.py +3 -3
  18. examples/timelines/run.py +29 -5
  19. examples/timeseries/run.py +3 -3
  20. examples/timeseries_slurm/run.py +3 -3
  21. examples/wind_rose/run.py +3 -3
  22. examples/yawed_wake/run.py +19 -9
  23. foxes/__init__.py +21 -17
  24. foxes/algorithms/__init__.py +6 -6
  25. foxes/algorithms/downwind/__init__.py +2 -2
  26. foxes/algorithms/downwind/downwind.py +49 -17
  27. foxes/algorithms/downwind/models/__init__.py +6 -6
  28. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
  29. foxes/algorithms/downwind/models/init_farm_data.py +58 -29
  30. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
  33. foxes/algorithms/iterative/__init__.py +7 -3
  34. foxes/algorithms/iterative/iterative.py +1 -2
  35. foxes/algorithms/iterative/models/__init__.py +7 -3
  36. foxes/algorithms/iterative/models/farm_wakes_calc.py +9 -5
  37. foxes/algorithms/sequential/__init__.py +3 -3
  38. foxes/algorithms/sequential/models/__init__.py +2 -2
  39. foxes/algorithms/sequential/sequential.py +3 -4
  40. foxes/config/__init__.py +5 -1
  41. foxes/constants.py +16 -0
  42. foxes/core/__init__.py +45 -22
  43. foxes/core/algorithm.py +5 -6
  44. foxes/core/data.py +94 -22
  45. foxes/core/data_calc_model.py +4 -2
  46. foxes/core/engine.py +42 -53
  47. foxes/core/farm_controller.py +2 -2
  48. foxes/core/farm_data_model.py +16 -13
  49. foxes/core/ground_model.py +4 -13
  50. foxes/core/model.py +24 -6
  51. foxes/core/partial_wakes_model.py +147 -10
  52. foxes/core/point_data_model.py +21 -17
  53. foxes/core/rotor_model.py +4 -3
  54. foxes/core/states.py +2 -3
  55. foxes/core/turbine.py +2 -1
  56. foxes/core/wake_deflection.py +130 -0
  57. foxes/core/wake_model.py +222 -9
  58. foxes/core/wake_superposition.py +122 -4
  59. foxes/core/wind_farm.py +6 -6
  60. foxes/data/__init__.py +7 -2
  61. foxes/data/states/point_cloud_100.nc +0 -0
  62. foxes/data/states/weibull_cloud_4.nc +0 -0
  63. foxes/data/states/weibull_grid.nc +0 -0
  64. foxes/data/states/weibull_sectors_12.csv +13 -0
  65. foxes/data/states/weibull_sectors_12.nc +0 -0
  66. foxes/engines/__init__.py +14 -15
  67. foxes/engines/dask.py +42 -20
  68. foxes/engines/default.py +2 -2
  69. foxes/engines/numpy.py +11 -13
  70. foxes/engines/pool.py +20 -11
  71. foxes/engines/single.py +8 -6
  72. foxes/input/__init__.py +3 -3
  73. foxes/input/farm_layout/__init__.py +9 -8
  74. foxes/input/farm_layout/from_arrays.py +68 -0
  75. foxes/input/farm_layout/from_csv.py +1 -1
  76. foxes/input/farm_layout/ring.py +0 -1
  77. foxes/input/states/__init__.py +28 -12
  78. foxes/input/states/create/__init__.py +3 -2
  79. foxes/input/states/dataset_states.py +710 -0
  80. foxes/input/states/field_data.py +531 -0
  81. foxes/input/states/multi_height.py +11 -6
  82. foxes/input/states/one_point_flow.py +1 -4
  83. foxes/input/states/point_cloud_data.py +618 -0
  84. foxes/input/states/scan.py +2 -0
  85. foxes/input/states/single.py +3 -1
  86. foxes/input/states/states_table.py +23 -30
  87. foxes/input/states/weibull_sectors.py +330 -0
  88. foxes/input/states/wrg_states.py +8 -6
  89. foxes/input/yaml/__init__.py +9 -3
  90. foxes/input/yaml/dict.py +42 -41
  91. foxes/input/yaml/windio/__init__.py +10 -5
  92. foxes/input/yaml/windio/read_attributes.py +42 -29
  93. foxes/input/yaml/windio/read_farm.py +17 -15
  94. foxes/input/yaml/windio/read_fields.py +4 -2
  95. foxes/input/yaml/windio/read_outputs.py +25 -15
  96. foxes/input/yaml/windio/read_site.py +172 -11
  97. foxes/input/yaml/windio/windio.py +23 -11
  98. foxes/input/yaml/yaml.py +1 -0
  99. foxes/models/__init__.py +15 -14
  100. foxes/models/axial_induction/__init__.py +2 -2
  101. foxes/models/farm_controllers/__init__.py +1 -1
  102. foxes/models/farm_models/__init__.py +1 -1
  103. foxes/models/ground_models/__init__.py +3 -2
  104. foxes/models/ground_models/wake_mirror.py +3 -3
  105. foxes/models/model_book.py +190 -63
  106. foxes/models/partial_wakes/__init__.py +6 -6
  107. foxes/models/partial_wakes/axiwake.py +30 -5
  108. foxes/models/partial_wakes/centre.py +47 -0
  109. foxes/models/partial_wakes/rotor_points.py +41 -11
  110. foxes/models/partial_wakes/segregated.py +2 -25
  111. foxes/models/partial_wakes/top_hat.py +27 -2
  112. foxes/models/point_models/__init__.py +4 -4
  113. foxes/models/rotor_models/__init__.py +4 -3
  114. foxes/models/rotor_models/centre.py +1 -1
  115. foxes/models/rotor_models/direct_infusion.py +241 -0
  116. foxes/models/turbine_models/__init__.py +11 -11
  117. foxes/models/turbine_models/calculator.py +16 -3
  118. foxes/models/turbine_models/kTI_model.py +1 -0
  119. foxes/models/turbine_models/lookup_table.py +2 -0
  120. foxes/models/turbine_models/power_mask.py +1 -0
  121. foxes/models/turbine_models/rotor_centre_calc.py +2 -0
  122. foxes/models/turbine_models/sector_management.py +1 -0
  123. foxes/models/turbine_models/set_farm_vars.py +3 -9
  124. foxes/models/turbine_models/table_factors.py +2 -0
  125. foxes/models/turbine_models/thrust2ct.py +1 -0
  126. foxes/models/turbine_models/yaw2yawm.py +2 -0
  127. foxes/models/turbine_models/yawm2yaw.py +2 -0
  128. foxes/models/turbine_types/PCt_file.py +2 -6
  129. foxes/models/turbine_types/PCt_from_two.py +1 -2
  130. foxes/models/turbine_types/__init__.py +10 -9
  131. foxes/models/turbine_types/calculator_type.py +123 -0
  132. foxes/models/turbine_types/null_type.py +1 -0
  133. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
  134. foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
  135. foxes/models/vertical_profiles/__init__.py +7 -7
  136. foxes/models/wake_deflections/__init__.py +3 -0
  137. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  138. foxes/models/wake_deflections/jimenez.py +277 -0
  139. foxes/models/wake_deflections/no_deflection.py +94 -0
  140. foxes/models/wake_frames/__init__.py +6 -7
  141. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  142. foxes/models/wake_frames/rotor_wd.py +3 -1
  143. foxes/models/wake_frames/seq_dynamic_wakes.py +41 -7
  144. foxes/models/wake_frames/streamlines.py +8 -6
  145. foxes/models/wake_frames/timelines.py +9 -3
  146. foxes/models/wake_models/__init__.py +7 -7
  147. foxes/models/wake_models/dist_sliced.py +50 -84
  148. foxes/models/wake_models/gaussian.py +20 -0
  149. foxes/models/wake_models/induction/__init__.py +5 -5
  150. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  151. foxes/models/wake_models/induction/rathmann.py +65 -64
  152. foxes/models/wake_models/induction/self_similar.py +65 -68
  153. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  154. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  155. foxes/models/wake_models/ti/__init__.py +2 -2
  156. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  157. foxes/models/wake_models/ti/iec_ti.py +6 -4
  158. foxes/models/wake_models/top_hat.py +58 -7
  159. foxes/models/wake_models/wind/__init__.py +6 -4
  160. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  161. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  162. foxes/models/wake_models/wind/jensen.py +15 -2
  163. foxes/models/wake_models/wind/turbopark.py +28 -2
  164. foxes/models/wake_superpositions/__init__.py +18 -9
  165. foxes/models/wake_superpositions/ti_linear.py +4 -4
  166. foxes/models/wake_superpositions/ti_max.py +4 -4
  167. foxes/models/wake_superpositions/ti_pow.py +4 -4
  168. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  169. foxes/models/wake_superpositions/wind_vector.py +257 -0
  170. foxes/models/wake_superpositions/ws_linear.py +9 -10
  171. foxes/models/wake_superpositions/ws_max.py +8 -8
  172. foxes/models/wake_superpositions/ws_pow.py +8 -8
  173. foxes/models/wake_superpositions/ws_product.py +4 -4
  174. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  175. foxes/output/__init__.py +21 -19
  176. foxes/output/farm_layout.py +4 -2
  177. foxes/output/farm_results_eval.py +19 -16
  178. foxes/output/flow_plots_2d/__init__.py +2 -2
  179. foxes/output/flow_plots_2d/flow_plots.py +18 -0
  180. foxes/output/flow_plots_2d/get_fig.py +5 -2
  181. foxes/output/output.py +6 -1
  182. foxes/output/results_writer.py +1 -1
  183. foxes/output/rose_plot.py +13 -3
  184. foxes/output/rotor_point_plots.py +3 -0
  185. foxes/output/seq_plugins/__init__.py +2 -2
  186. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  187. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  188. foxes/output/state_turbine_map.py +3 -0
  189. foxes/output/turbine_type_curves.py +10 -8
  190. foxes/utils/__init__.py +37 -19
  191. foxes/utils/abl/__init__.py +4 -4
  192. foxes/utils/cubic_roots.py +1 -1
  193. foxes/utils/data_book.py +4 -3
  194. foxes/utils/dict.py +49 -37
  195. foxes/utils/exec_python.py +5 -5
  196. foxes/utils/factory.py +3 -5
  197. foxes/utils/geom2d/__init__.py +7 -5
  198. foxes/utils/geopandas_utils.py +2 -2
  199. foxes/utils/pandas_utils.py +4 -3
  200. foxes/utils/tab_files.py +0 -1
  201. foxes/utils/weibull.py +28 -0
  202. foxes/utils/wrg_utils.py +3 -1
  203. foxes/utils/xarray_utils.py +9 -2
  204. foxes/variables.py +67 -9
  205. {foxes-1.3.dist-info → foxes-1.5.dist-info}/METADATA +34 -63
  206. foxes-1.5.dist-info/RECORD +328 -0
  207. {foxes-1.3.dist-info → foxes-1.5.dist-info}/WHEEL +1 -1
  208. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  209. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +1 -1
  210. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  211. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  212. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  213. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +0 -1
  214. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
  215. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
  216. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
  217. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
  218. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  219. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
  220. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  221. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +0 -1
  222. foxes/input/states/field_data_nc.py +0 -847
  223. foxes/output/round.py +0 -10
  224. foxes/utils/pandas_helpers.py +0 -178
  225. foxes-1.3.dist-info/RECORD +0 -313
  226. {foxes-1.3.dist-info → foxes-1.5.dist-info}/entry_points.txt +0 -0
  227. {foxes-1.3.dist-info → foxes-1.5.dist-info/licenses}/LICENSE +0 -0
  228. {foxes-1.3.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
@@ -34,18 +34,24 @@ if __name__ == "__main__":
34
34
  "-w",
35
35
  "--wakes",
36
36
  help="The wake models",
37
- default=["Bastankhah2016_linear_ka02", "CrespoHernandez_quadratic_ka04"],
37
+ default=["TurbOPark_vector_ambka004", "CrespoHernandez_quadratic_ambka04"],
38
38
  nargs="+",
39
39
  )
40
+ parser.add_argument(
41
+ "-d", "--deflection", help="The wake deflection", default="Jimenez"
42
+ )
40
43
  parser.add_argument("-r", "--rotor", help="The rotor model", default="centre")
41
44
  parser.add_argument(
42
45
  "-p", "--pwakes", help="The partial wakes models", default=None, nargs="+"
43
46
  )
44
- parser.add_argument("-f", "--frame", help="The wake frame", default="yawed")
47
+ parser.add_argument("-f", "--frame", help="The wake frame", default="rotor_wd")
45
48
  parser.add_argument(
46
49
  "-m", "--tmodels", help="The turbine models", default=[], nargs="+"
47
50
  )
48
51
  parser.add_argument("-v", "--var", help="The plot variable", default=FV.WS)
52
+ parser.add_argument(
53
+ "-it", "--iterative", help="Use iterative algorithm", action="store_true"
54
+ )
49
55
  parser.add_argument("-e", "--engine", help="The engine", default="process")
50
56
  parser.add_argument(
51
57
  "-n", "--n_cpus", help="The number of cpus", default=None, type=int
@@ -76,7 +82,9 @@ if __name__ == "__main__":
76
82
 
77
83
  # set turbines in yaw
78
84
  yawm = np.array([[args.yawm, args.yawm2]])
79
- mbook.turbine_models["set_yawm"] = foxes.models.turbine_models.SetFarmVars()
85
+ mbook.turbine_models["set_yawm"] = foxes.models.turbine_models.SetFarmVars(
86
+ pre_rotor=True
87
+ )
80
88
  mbook.turbine_models["set_yawm"].add_var(FV.YAWM, yawm)
81
89
 
82
90
  # create states
@@ -96,12 +104,14 @@ if __name__ == "__main__":
96
104
  )
97
105
 
98
106
  # create algorithm
99
- algo = foxes.algorithms.Downwind(
107
+ Algo = foxes.algorithms.Iterative if args.iterative else foxes.algorithms.Downwind
108
+ algo = Algo(
100
109
  farm,
101
110
  states=states,
102
111
  rotor_model=args.rotor,
103
112
  wake_models=args.wakes,
104
113
  wake_frame=args.frame,
114
+ wake_deflection=args.deflection,
105
115
  partial_wakes=args.pwakes,
106
116
  mbook=mbook,
107
117
  engine=args.engine,
@@ -119,7 +129,7 @@ if __name__ == "__main__":
119
129
  print("\nHorizontal flow figure output:")
120
130
  o = foxes.output.FlowPlots2D(algo, farm_results)
121
131
  g = o.gen_states_fig_xy(
122
- args.var, resolution=10, xmin=-100, xmax=3000, rotor_color="red"
132
+ args.var, resolution=10, xmin=-500, xmax=3000, rotor_color="red"
123
133
  )
124
134
  fig = next(g)
125
135
  plt.show()
@@ -130,7 +140,7 @@ if __name__ == "__main__":
130
140
  o = foxes.output.FlowPlots2D(algo, farm_results)
131
141
  g = o.gen_states_fig_yz(
132
142
  args.var,
133
- resolution=10,
143
+ resolution=5,
134
144
  x=750,
135
145
  ymin=-200,
136
146
  ymax=200,
@@ -190,7 +200,7 @@ if __name__ == "__main__":
190
200
  # power results
191
201
  P0 = o.calc_mean_farm_power(ambient=True)
192
202
  P = o.calc_mean_farm_power()
193
- print(f"\nFarm power : {P/1000:.1f} MW")
194
- print(f"Farm ambient power: {P0/1000:.1f} MW")
195
- print(f"Farm efficiency : {o.calc_farm_efficiency()*100:.2f} %")
203
+ print(f"\nFarm power : {P / 1000:.1f} MW")
204
+ print(f"Farm ambient power: {P0 / 1000:.1f} MW")
205
+ print(f"Farm efficiency : {o.calc_farm_efficiency() * 100:.2f} %")
196
206
  print(f"Annual farm yield : {turbine_results[FV.YLD].sum():.2f} GWh.")
foxes/__init__.py CHANGED
@@ -3,24 +3,28 @@ 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
17
14
 
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
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
21
+
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
@@ -70,6 +72,7 @@ class Downwind(Algorithm):
70
72
  wake_models,
71
73
  rotor_model="centre",
72
74
  wake_frame="rotor_wd",
75
+ wake_deflection="no_deflection",
73
76
  partial_wakes=None,
74
77
  ground_models=None,
75
78
  farm_controller="basic_ctrl",
@@ -94,6 +97,8 @@ class Downwind(Algorithm):
94
97
  wake_frame: str
95
98
  The wake frame. Will be looked up in the
96
99
  model book
100
+ deflection: foxes.core.WakeDeflection, optional
101
+ The wake deflection model
97
102
  partial_wakes: dict, list or str, optional
98
103
  The partial wakes mapping. Key: wake model name,
99
104
  value: partial wake model name
@@ -123,6 +128,9 @@ class Downwind(Algorithm):
123
128
  self.__wake_frame = self.mbook.wake_frames.get_item(wake_frame)
124
129
  self.wake_frame.name = wake_frame
125
130
 
131
+ self.__wake_deflection = self.mbook.wake_deflections.get_item(wake_deflection)
132
+ self.wake_deflection.name = wake_deflection
133
+
126
134
  self.__wake_models = {}
127
135
  for w in wake_models:
128
136
  m = self.mbook.wake_models.get_item(w)
@@ -251,6 +259,19 @@ class Downwind(Algorithm):
251
259
  """
252
260
  return self.__wake_frame
253
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
+
254
275
  @property
255
276
  def partial_wakes(self):
256
277
  """
@@ -310,6 +331,15 @@ class Downwind(Algorithm):
310
331
  """
311
332
  return getattr(mdls, name)
312
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
+
313
343
  def print_deco(self, func_name=None, n_points=None):
314
344
  """
315
345
  Helper function for printing model names
@@ -334,25 +364,26 @@ class Downwind(Algorithm):
334
364
  if n_points is not None:
335
365
  print(f" n_points : {n_points}")
336
366
  print(deco)
337
- print(f" states : {self.states}")
338
- print(f" rotor : {self.rotor_model}")
367
+ print(f" states : {self.states}")
368
+ print(f" rotor : {self.rotor_model}")
339
369
  print(f" controller: {self.farm_controller}")
340
370
  print(f" wake frame: {self.wake_frame}")
371
+ print(f" deflection: {self.wake_deflection}")
341
372
  print(deco)
342
- print(f" wakes:")
373
+ print(" wakes:")
343
374
  for i, w in enumerate(self.wake_models.values()):
344
375
  print(f" {i}) {w.name}: {w}")
345
376
  print(deco)
346
- print(f" partial wakes:")
377
+ print(" partial wakes:")
347
378
  for i, (w, p) in enumerate(self.partial_wakes.items()):
348
379
  print(f" {i}) {w}: {p.name}, {p}")
349
380
  print(deco)
350
- print(f" turbine models:")
381
+ print(" turbine models:")
351
382
  for i, m in enumerate(self.farm_controller.pre_rotor_models.models):
352
383
  print(f" {i}) {m.name}: {m} [pre-rotor]")
353
384
  for i, m in enumerate(self.farm_controller.post_rotor_models.models):
354
385
  print(
355
- 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}"
356
387
  )
357
388
  print(deco)
358
389
  print()
@@ -364,7 +395,7 @@ class Downwind(Algorithm):
364
395
  if self.verbosity > 0:
365
396
  deco = "-" * 50
366
397
  print(f"\n{deco}")
367
- print(f" Model oder")
398
+ print(" Model oder")
368
399
  print(f"{deco}")
369
400
 
370
401
  for i, m in enumerate(mlist.models):
@@ -402,6 +433,7 @@ class Downwind(Algorithm):
402
433
  self.states,
403
434
  self.farm_controller,
404
435
  self.rotor_model,
436
+ self.wake_deflection,
405
437
  self.wake_frame,
406
438
  ]
407
439
  mdls += list(self.wake_models.values())
@@ -445,7 +477,7 @@ class Downwind(Algorithm):
445
477
  # 2) calculate ambient rotor results:
446
478
  mlist.models.append(self.rotor_model)
447
479
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
448
- calc_pars[-1].update({"store": True})
480
+ calc_pars[-1]["store"] = True
449
481
 
450
482
  # 3) run post-rotor turbine models via farm controller:
451
483
  mlist.models.append(self.farm_controller)
@@ -463,7 +495,7 @@ class Downwind(Algorithm):
463
495
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
464
496
 
465
497
  # 6) reorder back to state-turbine dimensions:
466
- if outputs != False:
498
+ if not isinstance(outputs, bool) or outputs:
467
499
  mlist.models.append(self.get_model("ReorderFarmOutput")(outputs))
468
500
  calc_pars.append(calc_parameters.get(mlist.models[-1].name, {}))
469
501
 
@@ -476,7 +508,7 @@ class Downwind(Algorithm):
476
508
  def _launch_parallel_farm_calc(
477
509
  self,
478
510
  mlist,
479
- *data,
511
+ model_data,
480
512
  outputs=None,
481
513
  normalize=False,
482
514
  **kwargs,
@@ -488,8 +520,8 @@ class Downwind(Algorithm):
488
520
  ----------
489
521
  mlist: foxes.models.FarmDataModelList
490
522
  The model list
491
- data: tuple of xarray.Dataset
492
- The (mdata, fdata) inputs
523
+ model_data: xarray.Dataset
524
+ The initial model data
493
525
  outputs: list of str, optional
494
526
  The output variables, or None for defaults
495
527
  normalize: bool
@@ -506,7 +538,7 @@ class Downwind(Algorithm):
506
538
  """
507
539
  out_vars = self.farm_vars if outputs is None else outputs
508
540
  farm_results = get_engine().run_calculation(
509
- self, mlist, *data, out_vars=out_vars, **kwargs
541
+ self, mlist, model_data, out_vars=out_vars, **kwargs
510
542
  )
511
543
 
512
544
  if normalize:
@@ -573,8 +605,8 @@ class Downwind(Algorithm):
573
605
  # get input model data:
574
606
  model_data = self.get_models_data()
575
607
  self.print("\nInput data:\n\n", model_data, "\n")
576
- self.print(f"\nFarm variables:", ", ".join(self.farm_vars))
577
- self.print(f"\nOutput variables:", ", ".join(outputs))
608
+ self.print("\nFarm variables:", ", ".join(self.farm_vars))
609
+ self.print("\nOutput variables:", ", ".join(outputs))
578
610
 
579
611
  # run main calculation:
580
612
  farm_results = super().calc_farm(
@@ -779,7 +811,7 @@ class Downwind(Algorithm):
779
811
  if persist_mdata:
780
812
  model_data = model_data.persist()
781
813
  self.print("\nInput data:\n\n", model_data, "\n")
782
- self.print(f"\nOutput farm variables:", ", ".join(self.farm_vars))
814
+ self.print("\nOutput farm variables:", ", ".join(self.farm_vars))
783
815
 
784
816
  # chunk farm results:
785
817
  self.print("\nInput farm data:\n\n", farm_results, "\n")
@@ -798,7 +830,7 @@ class Downwind(Algorithm):
798
830
 
799
831
  # check vars:
800
832
  ovars = mlist.output_point_vars(self) if outputs is None else outputs
801
- self.print(f"\nOutput point variables:", ", ".join(ovars))
833
+ self.print("\nOutput point variables:", ", ".join(ovars))
802
834
 
803
835
  # calculate:
804
836
  point_results = super().calc_points(
@@ -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,7 +1,7 @@
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
6
  import foxes.variables as FV
7
7
 
@@ -69,8 +69,14 @@ class FarmWakesCalculation(FarmDataModel):
69
69
  for wname, wmodel in algo.wake_models.items():
70
70
  pwake = algo.partial_wakes[wname]
71
71
  if pwake.name not in pwake2tdata:
72
- tpoints, tweights = pwake.get_wake_points(algo, mdata, fdata)
73
- 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
+ )
74
80
 
75
81
  def _get_wdata(tdatap, wdeltas, variables, s):
76
82
  """Helper function for wake data extraction"""
@@ -78,12 +84,10 @@ class FarmWakesCalculation(FarmDataModel):
78
84
  wdelta = {v: d[s] for v, d in wdeltas.items()}
79
85
  return tdata, wdelta
80
86
 
81
- def _evaluate(
82
- gmodel, tdata, amb_res, rwghts, wake_res, wdeltas, oi, wmodel, pwake
83
- ):
87
+ def _evaluate(gmodel, tdata, rwghts, wake_res, wdeltas, oi, wmodel, pwake):
84
88
  """Helper function for data evaluation at turbines"""
85
89
  wres = gmodel.finalize_farm_wakes(
86
- algo, mdata, fdata, tdata, amb_res, rwghts, wdeltas, wmodel, oi, pwake
90
+ algo, mdata, fdata, tdata, rwghts, wdeltas, wmodel, oi, pwake
87
91
  )
88
92
 
89
93
  hres = {
@@ -124,7 +128,6 @@ class FarmWakesCalculation(FarmDataModel):
124
128
  _evaluate(
125
129
  gmodel,
126
130
  tdatap,
127
- amb_res,
128
131
  rwghts,
129
132
  wake_res,
130
133
  wdeltas,
@@ -149,7 +152,6 @@ class FarmWakesCalculation(FarmDataModel):
149
152
  _evaluate(
150
153
  gmodel,
151
154
  tdatap,
152
- amb_res,
153
155
  rwghts,
154
156
  wake_res,
155
157
  wdeltas,
@@ -74,19 +74,18 @@ class InitFarmData(FarmDataModel):
74
74
  n_states = fdata.n_states
75
75
  n_turbines = algo.n_turbines
76
76
 
77
- # define FV.TXYH as vector [X, Y, H]:
78
- fdata[FV.TXYH] = np.full(
79
- (n_states, n_turbines, 3), np.nan, dtype=config.dtype_double
77
+ # add and set X, Y, H, D:
78
+ fdata.add(
79
+ FV.TXYH,
80
+ np.zeros((n_states, n_turbines, 3), dtype=config.dtype_double),
81
+ (FC.STATE, FC.TURBINE, FC.XYH),
82
+ )
83
+ fdata.add(
84
+ FV.D,
85
+ np.zeros((n_states, n_turbines), dtype=config.dtype_double),
86
+ (FC.STATE, FC.TURBINE),
80
87
  )
81
- fdata.dims[FV.TXYH] = (FC.STATE, FC.TURBINE, FC.XYH)
82
- for i, v in enumerate([FV.X, FV.Y, FV.H]):
83
- fdata[v] = fdata[FV.TXYH][..., i]
84
- fdata.dims[v] = (FC.STATE, FC.TURBINE)
85
-
86
- # set X, Y, H, D:
87
- fdata[FV.D] = np.zeros((n_states, n_turbines), dtype=config.dtype_double)
88
88
  for ti, t in enumerate(algo.farm.turbines):
89
-
90
89
  if len(t.xy.shape) == 1:
91
90
  fdata[FV.TXYH][:, ti, :2] = t.xy[None, :]
92
91
  else:
@@ -104,34 +103,64 @@ class InitFarmData(FarmDataModel):
104
103
  D = algo.farm_controller.turbine_types[ti].D
105
104
  fdata[FV.D][:, ti] = D
106
105
 
107
- # calc WD and YAW at rotor centres:
106
+ # calc WD at rotor centres:
108
107
  svrs = algo.states.output_point_vars(algo)
109
108
  tdata = TData.from_points(points=fdata[FV.TXYH], variables=svrs)
110
109
  sres = algo.states.calculate(algo, mdata, fdata, tdata)
111
- fdata[FV.WD] = sres[FV.WD][:, :, 0]
110
+ fdata.add(
111
+ FV.WD,
112
+ sres[FV.WD][:, :, 0],
113
+ (FC.STATE, FC.TURBINE),
114
+ )
115
+ fdata.add(
116
+ FV.AMB_WD,
117
+ fdata[FV.WD].copy(),
118
+ (FC.STATE, FC.TURBINE),
119
+ )
112
120
  del tdata, sres, svrs
113
121
 
114
- # calculate and inverse:
122
+ # calculate downwind order:
115
123
  order = algo.wake_frame.calc_order(algo, mdata, fdata)
116
124
  ssel = np.zeros_like(order)
117
125
  ssel[:] = np.arange(n_states)[:, None]
118
- fdata[FV.ORDER] = order
119
- fdata[FV.ORDER_SSEL] = ssel
120
- fdata[FV.ORDER_INV] = np.zeros_like(order)
121
- fdata[FV.ORDER_INV][ssel, order] = np.arange(n_turbines)[None, :]
122
126
 
123
127
  # apply downwind order to all data:
124
- fdata[FV.TXYH] = fdata[FV.TXYH][ssel, order]
128
+ for data in [fdata, mdata]:
129
+ for k in data.keys():
130
+ if (
131
+ k not in [FV.X, FV.Y, FV.H]
132
+ and tuple(data.dims[k][:2]) == (FC.STATE, FC.TURBINE)
133
+ and np.any(data[k] != data[k][0, 0, None, None])
134
+ ):
135
+ data[k][:] = data[k][ssel, order]
136
+
137
+ # add derived data:
125
138
  for i, v in enumerate([FV.X, FV.Y, FV.H]):
126
- fdata[v] = fdata[FV.TXYH][..., i]
127
- for v in [FV.D, FV.WD]:
128
- if np.any(fdata[v] != fdata[v][0, 0, None, None]):
129
- fdata[v] = fdata[v][ssel, order]
130
- fdata[FV.YAW] = fdata[FV.WD].copy()
131
- for k in mdata.keys():
132
- if tuple(mdata.dims[k][:2]) == (FC.STATE, FC.TURBINE) and np.any(
133
- mdata[k] != mdata[k][0, 0, None, None]
134
- ):
135
- mdata[k] = mdata[k][ssel, order]
139
+ fdata.add(
140
+ v,
141
+ fdata[FV.TXYH][:, :, i],
142
+ (FC.STATE, FC.TURBINE),
143
+ )
144
+ fdata.add(
145
+ FV.YAW,
146
+ fdata[FV.WD].copy(),
147
+ (FC.STATE, FC.TURBINE),
148
+ )
149
+ fdata.add(
150
+ FV.ORDER,
151
+ order,
152
+ (FC.STATE, FC.TURBINE),
153
+ )
154
+ fdata.add(
155
+ FV.ORDER_SSEL,
156
+ ssel,
157
+ (FC.STATE, FC.TURBINE),
158
+ )
159
+ fdata.add(
160
+ FV.ORDER_INV,
161
+ np.zeros_like(order),
162
+ (FC.STATE, FC.TURBINE),
163
+ )
164
+ fdata[FV.ORDER_INV][ssel, order] = np.arange(n_turbines)[None, :]
136
165
 
137
166
  return {v: fdata[v] for v in self.output_farm_vars(algo)}
@@ -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)
@@ -65,5 +65,5 @@ class SetAmbFarmResults(FarmDataModel):
65
65
 
66
66
  """
67
67
  for v in self.vars:
68
- fdata[FV.var2amb[v]] = fdata[v].copy()
68
+ fdata.add(FV.var2amb[v], fdata[v].copy(), fdata.dims[v])
69
69
  return {v: fdata[v] for v in self.output_farm_vars(algo)}
@@ -60,7 +60,7 @@ class SetAmbPointResults(PointDataModel):
60
60
  """
61
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