foxes 0.8.2__py3-none-any.whl → 1.1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of foxes might be problematic. Click here for more details.

Files changed (215) hide show
  1. docs/source/conf.py +353 -0
  2. examples/abl_states/run.py +160 -0
  3. examples/compare_rotors_pwakes/run.py +217 -0
  4. examples/compare_wakes/run.py +241 -0
  5. examples/dyn_wakes/run.py +311 -0
  6. examples/field_data_nc/run.py +121 -0
  7. examples/induction/run.py +201 -0
  8. examples/multi_height/run.py +113 -0
  9. examples/power_mask/run.py +249 -0
  10. examples/random_timeseries/run.py +210 -0
  11. examples/scan_row/run.py +193 -0
  12. examples/sector_management/run.py +162 -0
  13. examples/sequential/run.py +209 -0
  14. examples/single_state/run.py +201 -0
  15. examples/states_lookup_table/run.py +137 -0
  16. examples/streamline_wakes/run.py +138 -0
  17. examples/tab_file/run.py +142 -0
  18. examples/timelines/run.py +267 -0
  19. examples/timeseries/run.py +190 -0
  20. examples/timeseries_slurm/run.py +185 -0
  21. examples/wind_rose/run.py +141 -0
  22. examples/windio/run.py +29 -0
  23. examples/yawed_wake/run.py +196 -0
  24. foxes/__init__.py +4 -8
  25. foxes/algorithms/__init__.py +1 -1
  26. foxes/algorithms/downwind/downwind.py +247 -111
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +12 -7
  28. foxes/algorithms/downwind/models/init_farm_data.py +2 -2
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +6 -7
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +1 -2
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +5 -3
  33. foxes/algorithms/iterative/iterative.py +74 -34
  34. foxes/algorithms/iterative/models/farm_wakes_calc.py +12 -7
  35. foxes/algorithms/iterative/models/urelax.py +3 -3
  36. foxes/algorithms/sequential/models/plugin.py +5 -5
  37. foxes/algorithms/sequential/models/seq_state.py +1 -1
  38. foxes/algorithms/sequential/sequential.py +126 -255
  39. foxes/constants.py +22 -7
  40. foxes/core/__init__.py +1 -0
  41. foxes/core/algorithm.py +632 -147
  42. foxes/core/data.py +252 -20
  43. foxes/core/data_calc_model.py +15 -291
  44. foxes/core/engine.py +640 -0
  45. foxes/core/farm_controller.py +38 -10
  46. foxes/core/farm_data_model.py +16 -1
  47. foxes/core/ground_model.py +2 -2
  48. foxes/core/model.py +249 -182
  49. foxes/core/partial_wakes_model.py +1 -1
  50. foxes/core/point_data_model.py +17 -2
  51. foxes/core/rotor_model.py +27 -21
  52. foxes/core/states.py +17 -1
  53. foxes/core/turbine_type.py +28 -0
  54. foxes/core/wake_frame.py +30 -34
  55. foxes/core/wake_model.py +5 -5
  56. foxes/core/wake_superposition.py +1 -1
  57. foxes/data/windio/windio_5turbines_timeseries.yaml +31 -15
  58. foxes/engines/__init__.py +17 -0
  59. foxes/engines/dask.py +982 -0
  60. foxes/engines/default.py +75 -0
  61. foxes/engines/futures.py +72 -0
  62. foxes/engines/mpi.py +38 -0
  63. foxes/engines/multiprocess.py +71 -0
  64. foxes/engines/numpy.py +167 -0
  65. foxes/engines/pool.py +249 -0
  66. foxes/engines/ray.py +79 -0
  67. foxes/engines/single.py +141 -0
  68. foxes/input/farm_layout/__init__.py +1 -0
  69. foxes/input/farm_layout/from_csv.py +4 -0
  70. foxes/input/farm_layout/from_json.py +2 -2
  71. foxes/input/farm_layout/grid.py +2 -2
  72. foxes/input/farm_layout/ring.py +65 -0
  73. foxes/input/farm_layout/row.py +2 -2
  74. foxes/input/states/__init__.py +7 -0
  75. foxes/input/states/create/random_abl_states.py +1 -1
  76. foxes/input/states/field_data_nc.py +158 -33
  77. foxes/input/states/multi_height.py +128 -14
  78. foxes/input/states/one_point_flow.py +577 -0
  79. foxes/input/states/scan_ws.py +74 -3
  80. foxes/input/states/single.py +1 -1
  81. foxes/input/states/slice_data_nc.py +681 -0
  82. foxes/input/states/states_table.py +204 -35
  83. foxes/input/windio/__init__.py +2 -2
  84. foxes/input/windio/get_states.py +44 -23
  85. foxes/input/windio/read_attributes.py +48 -17
  86. foxes/input/windio/read_farm.py +116 -102
  87. foxes/input/windio/read_fields.py +16 -6
  88. foxes/input/windio/read_outputs.py +71 -24
  89. foxes/input/windio/runner.py +31 -17
  90. foxes/input/windio/windio.py +41 -23
  91. foxes/models/farm_models/turbine2farm.py +1 -1
  92. foxes/models/ground_models/wake_mirror.py +10 -6
  93. foxes/models/model_book.py +58 -20
  94. foxes/models/partial_wakes/axiwake.py +3 -3
  95. foxes/models/partial_wakes/rotor_points.py +3 -3
  96. foxes/models/partial_wakes/top_hat.py +2 -2
  97. foxes/models/point_models/set_uniform_data.py +1 -1
  98. foxes/models/point_models/tke2ti.py +1 -1
  99. foxes/models/point_models/wake_deltas.py +1 -1
  100. foxes/models/rotor_models/centre.py +4 -0
  101. foxes/models/rotor_models/grid.py +24 -25
  102. foxes/models/rotor_models/levels.py +4 -5
  103. foxes/models/turbine_models/calculator.py +4 -6
  104. foxes/models/turbine_models/kTI_model.py +22 -6
  105. foxes/models/turbine_models/lookup_table.py +30 -4
  106. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  107. foxes/models/turbine_models/set_farm_vars.py +103 -34
  108. foxes/models/turbine_types/PCt_file.py +27 -3
  109. foxes/models/turbine_types/PCt_from_two.py +27 -3
  110. foxes/models/turbine_types/TBL_file.py +80 -0
  111. foxes/models/turbine_types/__init__.py +2 -0
  112. foxes/models/turbine_types/lookup.py +316 -0
  113. foxes/models/turbine_types/null_type.py +51 -1
  114. foxes/models/turbine_types/wsrho2PCt_from_two.py +29 -5
  115. foxes/models/turbine_types/wsti2PCt_from_two.py +31 -7
  116. foxes/models/vertical_profiles/__init__.py +1 -1
  117. foxes/models/vertical_profiles/data_profile.py +1 -1
  118. foxes/models/wake_frames/__init__.py +1 -0
  119. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  120. foxes/models/wake_frames/farm_order.py +25 -5
  121. foxes/models/wake_frames/rotor_wd.py +6 -4
  122. foxes/models/wake_frames/seq_dynamic_wakes.py +61 -74
  123. foxes/models/wake_frames/streamlines.py +21 -22
  124. foxes/models/wake_frames/timelines.py +330 -129
  125. foxes/models/wake_frames/yawed_wakes.py +7 -4
  126. foxes/models/wake_models/dist_sliced.py +2 -4
  127. foxes/models/wake_models/induction/rankine_half_body.py +5 -5
  128. foxes/models/wake_models/induction/rathmann.py +78 -24
  129. foxes/models/wake_models/induction/self_similar.py +78 -28
  130. foxes/models/wake_models/induction/vortex_sheet.py +86 -48
  131. foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
  132. foxes/models/wake_models/ti/iec_ti.py +40 -21
  133. foxes/models/wake_models/top_hat.py +1 -1
  134. foxes/models/wake_models/wind/bastankhah14.py +8 -6
  135. foxes/models/wake_models/wind/bastankhah16.py +17 -16
  136. foxes/models/wake_models/wind/jensen.py +4 -3
  137. foxes/models/wake_models/wind/turbopark.py +16 -13
  138. foxes/models/wake_superpositions/ti_linear.py +1 -1
  139. foxes/models/wake_superpositions/ti_max.py +1 -1
  140. foxes/models/wake_superpositions/ti_pow.py +1 -1
  141. foxes/models/wake_superpositions/ti_quadratic.py +1 -1
  142. foxes/models/wake_superpositions/ws_linear.py +8 -7
  143. foxes/models/wake_superpositions/ws_max.py +8 -7
  144. foxes/models/wake_superpositions/ws_pow.py +8 -7
  145. foxes/models/wake_superpositions/ws_product.py +5 -5
  146. foxes/models/wake_superpositions/ws_quadratic.py +8 -7
  147. foxes/output/__init__.py +4 -1
  148. foxes/output/farm_layout.py +16 -12
  149. foxes/output/farm_results_eval.py +1 -1
  150. foxes/output/flow_plots_2d/__init__.py +0 -1
  151. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  152. foxes/output/grids.py +92 -22
  153. foxes/output/results_writer.py +2 -2
  154. foxes/output/rose_plot.py +3 -3
  155. foxes/output/seq_plugins/__init__.py +2 -0
  156. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +64 -22
  157. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  158. foxes/output/slice_data.py +131 -111
  159. foxes/output/state_turbine_map.py +19 -14
  160. foxes/output/state_turbine_table.py +19 -19
  161. foxes/utils/__init__.py +1 -1
  162. foxes/utils/abl/neutral.py +2 -2
  163. foxes/utils/abl/stable.py +2 -2
  164. foxes/utils/abl/unstable.py +2 -2
  165. foxes/utils/data_book.py +1 -1
  166. foxes/utils/dev_utils.py +42 -0
  167. foxes/utils/dict.py +24 -1
  168. foxes/utils/exec_python.py +1 -1
  169. foxes/utils/factory.py +176 -53
  170. foxes/utils/geom2d/circle.py +1 -1
  171. foxes/utils/geom2d/polygon.py +1 -1
  172. foxes/utils/geopandas_utils.py +2 -2
  173. foxes/utils/load.py +2 -2
  174. foxes/utils/pandas_helpers.py +3 -2
  175. foxes/utils/wind_dir.py +0 -2
  176. foxes/utils/xarray_utils.py +24 -14
  177. foxes/variables.py +39 -2
  178. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/METADATA +75 -33
  179. foxes-1.1.0.2.dist-info/RECORD +309 -0
  180. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/WHEEL +1 -1
  181. foxes-1.1.0.2.dist-info/top_level.txt +4 -0
  182. tests/0_consistency/iterative/test_iterative.py +92 -0
  183. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  184. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  185. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  186. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  187. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  188. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  189. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  190. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  191. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  192. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  193. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  194. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  195. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  196. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  197. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  198. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  199. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  200. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  201. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  202. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  203. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  204. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  205. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  206. tests/3_examples/test_examples.py +34 -0
  207. foxes/VERSION +0 -1
  208. foxes/output/flow_plots_2d.py +0 -0
  209. foxes/utils/geopandas_helpers.py +0 -294
  210. foxes/utils/runners/__init__.py +0 -1
  211. foxes/utils/runners/runners.py +0 -280
  212. foxes-0.8.2.dist-info/RECORD +0 -247
  213. foxes-0.8.2.dist-info/top_level.txt +0 -1
  214. foxes-0.8.2.dist-info/zip-safe +0 -1
  215. {foxes-0.8.2.dist-info → foxes-1.1.0.2.dist-info}/LICENSE +0 -0
@@ -5,7 +5,9 @@ import foxes.variables as FV
5
5
  from .read_outputs import read_outputs
6
6
 
7
7
 
8
- def _read_wind_deficit(wind_deficit, superposition, induction, algo_dict, verbosity):
8
+ def _read_wind_deficit(
9
+ wake_model_key, wind_deficit, superposition, induction, algo_dict, verbosity
10
+ ):
9
11
  """Reads the wind deficit wake model"""
10
12
 
11
13
  wind_def_map = Dict(
@@ -22,6 +24,7 @@ def _read_wind_deficit(wind_deficit, superposition, induction, algo_dict, verbos
22
24
  {
23
25
  "Linear": "ws_linear",
24
26
  "Quadratic": "ws_quadratic",
27
+ "Product": "ws_product",
25
28
  },
26
29
  name="ws_sup_dict",
27
30
  )
@@ -29,14 +32,15 @@ def _read_wind_deficit(wind_deficit, superposition, induction, algo_dict, verbos
29
32
  {
30
33
  "Linear": "ws_linear_amb",
31
34
  "Quadratic": "ws_quadratic_amb",
35
+ "Product": "ws_product",
32
36
  },
33
37
  name="ws_sup_dict",
34
38
  )
35
-
39
+
36
40
  wname = wind_deficit.pop("name")
37
41
  eff_ws = wind_deficit.pop("use_effective_ws", True)
38
42
  if verbosity > 2:
39
- print(" Reading wind_deficit_model")
43
+ print(" Reading", wake_model_key)
40
44
  print(" Name :", wname)
41
45
  print(" Eff ws :", eff_ws)
42
46
  print(" Contents:", [k for k in wind_deficit.keys()])
@@ -73,6 +77,7 @@ def _read_wind_deficit(wind_deficit, superposition, induction, algo_dict, verbos
73
77
 
74
78
  return ka, kb, amb_ti
75
79
 
80
+
76
81
  def _read_turbulence(
77
82
  turbulence_model, superposition, induction, algo_dict, ka, kb, amb_ti, verbosity
78
83
  ):
@@ -99,7 +104,7 @@ def _read_turbulence(
99
104
  print(" Reading turbulence_model")
100
105
  print(" Name:", wname)
101
106
  print(" Contents:", [k for k in turbulence_model.keys()])
102
- if wname != "None":
107
+ if wname not in ["None", "none"]:
103
108
  tiwake_dict = dict(wmodel_type=twake_def_map[wname], induction=induction)
104
109
  if wname == "IEC-TI-2019":
105
110
  tiwake_dict["opening_angle"] = None
@@ -129,6 +134,7 @@ def _read_turbulence(
129
134
  print(" ", algo_dict["mbook"].wake_models[wname])
130
135
  algo_dict["wake_models"].append(wname)
131
136
 
137
+
132
138
  def _read_blockage(blockage_model, induction, algo_dict, verbosity):
133
139
  """Reads the blockage model"""
134
140
  indc_def_map = Dict(
@@ -146,7 +152,7 @@ def _read_blockage(blockage_model, induction, algo_dict, verbosity):
146
152
  print(" Reading blockage_model")
147
153
  print(" Name:", wname)
148
154
  print(" Contents:", [k for k in blockage_model.keys()])
149
- if wname != "None":
155
+ if wname not in ["None", "none"]:
150
156
  indc_dict = Dict(wmodel_type=indc_def_map[wname], induction=induction)
151
157
  algo_dict["mbook"].wake_models[wname] = WakeModel.new(**indc_dict)
152
158
  if verbosity > 2:
@@ -155,6 +161,7 @@ def _read_blockage(blockage_model, induction, algo_dict, verbosity):
155
161
  algo_dict["wake_models"].append(wname)
156
162
  algo_dict["algo_type"] = "Iterative"
157
163
 
164
+
158
165
  def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
159
166
  """Reads the rotor averaging"""
160
167
  if verbosity > 2:
@@ -177,16 +184,20 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
177
184
  print(" wake_averaging :", wake_averaging)
178
185
  print(" ws exponent power :", wse_P)
179
186
  print(" ws exponent ct :", wse_ct)
187
+
180
188
  if background_averaging in ["center", "centre"]:
181
189
  algo_dict["rotor_model"] = "centre"
190
+ elif background_averaging in ["none", "None", None]:
191
+ algo_dict["rotor_model"] = None
182
192
  elif background_averaging == "grid":
183
193
  algo_dict["rotor_model"] = f"grid{nx*ny}"
184
194
  else:
185
- raise KeyError(
186
- f"Expecting background_averaging 'center' or 'grid', got '{background_averaging}'"
187
- )
195
+ algo_dict["rotor_model"] = background_averaging
196
+
188
197
  if wake_averaging in ["centre", "center"]:
189
198
  algo_dict["partial_wakes"] = "centre"
199
+ elif wake_averaging in ["none", "None", "auto", None]:
200
+ algo_dict["partial_wakes"] = None
190
201
  elif wake_averaging == "grid":
191
202
  if background_averaging == "grid":
192
203
  algo_dict["partial_wakes"] = "rotor_points"
@@ -197,10 +208,12 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
197
208
  algo_dict["partial_wakes"] = grid
198
209
  else:
199
210
  algo_dict["partial_wakes"] = wake_averaging
211
+
200
212
  if verbosity > 2:
201
213
  print(" --> rotor_model :", algo_dict["rotor_model"])
202
214
  print(" --> partial_wakes :", algo_dict["partial_wakes"])
203
215
 
216
+
204
217
  def _read_deflection(deflection, induction, algo_dict, verbosity):
205
218
  """Reads deflection model"""
206
219
  defl_def_map = Dict(
@@ -228,6 +241,7 @@ def _read_deflection(deflection, induction, algo_dict, verbosity):
228
241
  print(" ", algo_dict["mbook"].wake_frames[wname])
229
242
  algo_dict["wake_frame"] = wname
230
243
 
244
+
231
245
  def _read_analysis(wio_ana, algo_dict, verbosity):
232
246
  """Reads the windio analyses"""
233
247
  if verbosity > 2:
@@ -253,16 +267,26 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
253
267
  print(" axial induction model:", induction)
254
268
 
255
269
  # wind deficit model:
256
- wind_deficit = Dict(wio_ana["wind_deficit_model"], name="wind_deficit_model")
270
+ wake_model_key = (
271
+ "wind_deficit_model" if "wind_deficit_model" in wio_ana else "wake_model"
272
+ )
273
+ wind_deficit = Dict(wio_ana[wake_model_key], name=wake_model_key)
257
274
  ka, kb, amb_ti = _read_wind_deficit(
258
- wind_deficit, superposition, induction, algo_dict, verbosity
275
+ wake_model_key, wind_deficit, superposition, induction, algo_dict, verbosity
259
276
  )
260
277
 
261
278
  # turbulence model:
262
279
  if "turbulence_model" in wio_ana:
263
280
  turbulence_model = Dict(wio_ana["turbulence_model"], name="turbulence_model")
264
281
  _read_turbulence(
265
- turbulence_model, superposition, induction, algo_dict, ka, kb, amb_ti, verbosity
282
+ turbulence_model,
283
+ superposition,
284
+ induction,
285
+ algo_dict,
286
+ ka,
287
+ kb,
288
+ amb_ti,
289
+ verbosity,
266
290
  )
267
291
  elif verbosity > 0:
268
292
  print("turbulence_model not found, not using a TI wake model")
@@ -273,22 +297,23 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
273
297
  _read_blockage(blockage_model, induction, algo_dict, verbosity)
274
298
  elif verbosity > 0:
275
299
  print("blockage_model not found, not using a turbine induction model")
276
-
300
+
277
301
  # rotor_averaging:
278
302
  if "rotor_averaging" in wio_ana:
279
303
  rotor_averaging = Dict(wio_ana["rotor_averaging"], name="rotor_averaging")
280
304
  _read_rotor_averaging(rotor_averaging, algo_dict, verbosity)
281
305
  elif verbosity > 0:
282
306
  print("rotor_averaging not found, using default settings")
283
-
307
+
284
308
  # deflection:
285
309
  if "deflection_model" in wio_ana:
286
310
  deflection = Dict(wio_ana["deflection_model"], name="deflection_model")
287
311
  _read_deflection(deflection, induction, algo_dict, verbosity)
288
312
  elif verbosity > 0:
289
313
  print("deflection_model not found, using default settings")
290
-
291
- def read_attributes(wio, algo_dict, verbosity):
314
+
315
+
316
+ def read_attributes(wio, algo_dict, verbosity=1, **output_pars):
292
317
  """
293
318
  Reads the attributes part of windio
294
319
 
@@ -300,11 +325,15 @@ def read_attributes(wio, algo_dict, verbosity):
300
325
  The algorithm dictionary
301
326
  verbosity: int
302
327
  The verbosity level, 0=silent
328
+ **output_pars: dict, optional
329
+ Additional parameters for output reading
303
330
 
304
331
  Returns
305
332
  -------
306
333
  out_dicts: list of dict
307
334
  The output dictionaries
335
+ odir: pathlib.Path
336
+ Path to the output folder
308
337
 
309
338
  :group: input.windio
310
339
 
@@ -333,6 +362,8 @@ def read_attributes(wio, algo_dict, verbosity):
333
362
  out_dicts = []
334
363
  if "outputs" in wio_attrs:
335
364
  outputs = Dict(wio_attrs["outputs"], name="outputs")
336
- out_dicts = read_outputs(outputs, algo_dict, verbosity)
365
+ out_dicts, odir = read_outputs(
366
+ outputs, algo_dict, verbosity=verbosity, **output_pars
367
+ )
337
368
 
338
- return out_dicts
369
+ return out_dicts, odir
@@ -6,14 +6,14 @@ from foxes.core import Turbine, TurbineType
6
6
  import foxes.variables as FV
7
7
 
8
8
 
9
- def read_turbine_type(wio_trbns, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
9
+ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
10
10
  """
11
11
  Reads the turbine type from windio
12
12
 
13
13
  Parameters
14
14
  ----------
15
- wio_trbns: dict
16
- The windio turbines data
15
+ wio_farm: dict
16
+ The windio farm data
17
17
  algo_dict: dict
18
18
  The algorithm dictionary
19
19
  ws_exp_P: int
@@ -25,107 +25,116 @@ def read_turbine_type(wio_trbns, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
25
25
 
26
26
  Returns
27
27
  -------
28
- ttype: str
29
- The turbine type model name
28
+ ttypes: dict
29
+ Mapping from turbine type key to turbine
30
+ type name in the model book
30
31
 
31
32
  :group: input.windio
32
33
 
33
34
  """
34
- tname = wio_trbns.pop("name")
35
- if verbosity > 2:
36
- print(" Reading wio_trbns")
37
- print(" Name:", tname)
38
- print(" Contents:", [k for k in wio_trbns.keys()])
39
-
40
- # read performance:
41
- performance = Dict(wio_trbns["performance"], name="performance")
42
- if verbosity > 2:
43
- print(" Reading performance")
44
- print(" Contents:", [k for k in performance.keys()])
45
-
46
- # P, ct data:
47
- if "power_curve" in performance:
48
- power_curve = Dict(performance["power_curve"], name="power_curve")
49
- if verbosity > 2:
50
- print(" Reading power_curve")
51
- print(" Contents:", [k for k in power_curve.keys()])
52
- P = power_curve["power_values"]
53
- ws_P = power_curve["power_wind_speeds"]
54
- ct_curve = Dict(performance["Ct_curve"], name="Ct_values")
55
- if verbosity > 2:
56
- print(" Reading Ct_curve")
57
- print(" Contents:", [k for k in ct_curve.keys()])
58
- ct = ct_curve["Ct_values"]
59
- ws_ct = ct_curve["Ct_wind_speeds"]
60
-
61
- data_P = pd.DataFrame(data={"ws": ws_P, "P": P})
62
- data_ct = pd.DataFrame(data={"ws": ws_ct, "ct": ct})
63
-
64
- def _get_wse_var(wse):
65
- if wse not in [1, 2, 3]:
66
- raise ValueError(f"Expecting wind speed exponent 1, 2 or 3, got {wse}")
67
- return FV.REWS if wse == 1 else (FV.REWS2 if wse == 2 else FV.REWS3)
68
-
69
- if verbosity > 2:
70
- print(f" Creating model '{tname}'")
71
- print(f" Turbine type class: PCtFromTwo")
72
- algo_dict["mbook"].turbine_types[tname] = TurbineType.new(
73
- ttype_type="PCtFromTwo",
74
- data_source_P=data_P,
75
- data_source_ct=data_ct,
76
- col_ws_P_file="ws",
77
- col_ws_ct_file="ws",
78
- col_P="P",
79
- col_ct="ct",
80
- H=wio_trbns["hub_height"],
81
- D=wio_trbns["rotor_diameter"],
82
- var_ws_ct=_get_wse_var(ws_exp_ct),
83
- var_ws_P=_get_wse_var(ws_exp_P),
84
- rho=1.225,
85
- )
86
- if verbosity > 2:
87
- print(" ", algo_dict["mbook"].turbine_types[tname])
35
+ if "turbine_types" not in wio_farm:
36
+ wio_farm["turbine_types"] = {0: wio_farm["turbines"]}
88
37
 
89
- # P, ct data:
90
- elif "Cp_curve" in performance:
91
- cp_curve = Dict(performance["Cp_curve"], name="Cp_curve")
92
- if verbosity > 2:
93
- print(" Reading Cp_curve")
94
- print(" Contents:", [k for k in cp_curve.keys()])
95
- cp = cp_curve["Cp_values"]
96
- ws_cp = cp_curve["Cp_wind_speeds"]
97
- ct_curve = Dict(performance["Ct_curve"], name="Ct_values")
38
+ ttypes = {}
39
+ for k, wio_trbns in wio_farm["turbine_types"].items():
40
+ tname = wio_trbns.pop("name")
41
+ ttypes[k] = tname
98
42
  if verbosity > 2:
99
- print(" Reading Ct_curve")
100
- print(" Contents:", [k for k in ct_curve.keys()])
101
- ct = ct_curve["Ct_values"]
102
- ws_ct = ct_curve["Ct_wind_speeds"]
103
-
104
- data_cp = pd.DataFrame(data={"ws": ws_cp, "cp": cp})
105
- data_ct = pd.DataFrame(data={"ws": ws_ct, "ct": ct})
43
+ print(" Reading turbine type", k)
44
+ print(" Name:", tname)
45
+ print(" Contents:", [k for k in wio_trbns.keys()])
106
46
 
47
+ # read performance:
48
+ performance = Dict(wio_trbns["performance"], name="performance")
107
49
  if verbosity > 2:
108
- print(f" Creating model '{tname}'")
109
- print(f" Turbine type class: CpCtFromTwo")
110
- algo_dict["mbook"].turbine_types[tname] = TurbineType.new(
111
- ttype_type="CpCtFromTwo",
112
- data_source_cp=data_cp,
113
- data_source_ct=data_ct,
114
- col_ws_cp_file="ws",
115
- col_ws_ct_file="ws",
116
- col_cp="cp",
117
- col_ct="ct",
118
- H=wio_trbns["hub_height"],
119
- D=wio_trbns["rotor_diameter"],
120
- )
121
-
122
- else:
123
- raise KeyError(f"Expecting either 'power_curve' or 'Cp_curve'")
124
-
125
- return tname
126
-
127
-
128
- def read_layout(lname, ldict, algo_dict, ttype, verbosity=1):
50
+ print(" Reading performance")
51
+ print(" Contents:", [k for k in performance.keys()])
52
+
53
+ # P, ct data:
54
+ if "power_curve" in performance:
55
+ power_curve = Dict(performance["power_curve"], name="power_curve")
56
+ if verbosity > 2:
57
+ print(" Reading power_curve")
58
+ print(" Contents:", [k for k in power_curve.keys()])
59
+ P = power_curve["power_values"]
60
+ ws_P = power_curve["power_wind_speeds"]
61
+ ct_curve = Dict(performance["Ct_curve"], name="Ct_values")
62
+ if verbosity > 2:
63
+ print(" Reading Ct_curve")
64
+ print(" Contents:", [k for k in ct_curve.keys()])
65
+ ct = ct_curve["Ct_values"]
66
+ ws_ct = ct_curve["Ct_wind_speeds"]
67
+
68
+ data_P = pd.DataFrame(data={"ws": ws_P, "P": P})
69
+ data_ct = pd.DataFrame(data={"ws": ws_ct, "ct": ct})
70
+
71
+ def _get_wse_var(wse):
72
+ if wse not in [1, 2, 3]:
73
+ raise ValueError(
74
+ f"Expecting wind speed exponent 1, 2 or 3, got {wse}"
75
+ )
76
+ return FV.REWS if wse == 1 else (FV.REWS2 if wse == 2 else FV.REWS3)
77
+
78
+ if verbosity > 2:
79
+ print(f" Creating model '{tname}'")
80
+ print(f" Turbine type class: PCtFromTwo")
81
+ algo_dict["mbook"].turbine_types[tname] = TurbineType.new(
82
+ ttype_type="PCtFromTwo",
83
+ data_source_P=data_P,
84
+ data_source_ct=data_ct,
85
+ col_ws_P_file="ws",
86
+ col_ws_ct_file="ws",
87
+ col_P="P",
88
+ col_ct="ct",
89
+ H=wio_trbns["hub_height"],
90
+ D=wio_trbns["rotor_diameter"],
91
+ var_ws_ct=_get_wse_var(ws_exp_ct),
92
+ var_ws_P=_get_wse_var(ws_exp_P),
93
+ rho=1.225,
94
+ )
95
+ if verbosity > 2:
96
+ print(" ", algo_dict["mbook"].turbine_types[tname])
97
+
98
+ # P, ct data:
99
+ elif "Cp_curve" in performance:
100
+ cp_curve = Dict(performance["Cp_curve"], name="Cp_curve")
101
+ if verbosity > 2:
102
+ print(" Reading Cp_curve")
103
+ print(" Contents:", [k for k in cp_curve.keys()])
104
+ cp = cp_curve["Cp_values"]
105
+ ws_cp = cp_curve["Cp_wind_speeds"]
106
+ ct_curve = Dict(performance["Ct_curve"], name="Ct_values")
107
+ if verbosity > 2:
108
+ print(" Reading Ct_curve")
109
+ print(" Contents:", [k for k in ct_curve.keys()])
110
+ ct = ct_curve["Ct_values"]
111
+ ws_ct = ct_curve["Ct_wind_speeds"]
112
+
113
+ data_cp = pd.DataFrame(data={"ws": ws_cp, "cp": cp})
114
+ data_ct = pd.DataFrame(data={"ws": ws_ct, "ct": ct})
115
+
116
+ if verbosity > 2:
117
+ print(f" Creating model '{tname}'")
118
+ print(f" Turbine type class: CpCtFromTwo")
119
+ algo_dict["mbook"].turbine_types[tname] = TurbineType.new(
120
+ ttype_type="CpCtFromTwo",
121
+ data_source_cp=data_cp,
122
+ data_source_ct=data_ct,
123
+ col_ws_cp_file="ws",
124
+ col_ws_ct_file="ws",
125
+ col_cp="cp",
126
+ col_ct="ct",
127
+ H=wio_trbns["hub_height"],
128
+ D=wio_trbns["rotor_diameter"],
129
+ )
130
+
131
+ else:
132
+ raise KeyError(f"Expecting either 'power_curve' or 'Cp_curve'")
133
+
134
+ return ttypes
135
+
136
+
137
+ def read_layout(lname, ldict, algo_dict, ttypes, verbosity=1):
129
138
  """
130
139
  Read wind farm layout from windio input
131
140
 
@@ -137,8 +146,9 @@ def read_layout(lname, ldict, algo_dict, ttype, verbosity=1):
137
146
  The layout data
138
147
  algo_dict: dict
139
148
  The algorithm dictionary
140
- ttype: str
141
- Name of the turbine type model
149
+ ttypes: dict
150
+ Mapping from turbine type key to turbine
151
+ type name in the model book
142
152
  verbosity: int
143
153
  The verbosity level, 0=silent
144
154
 
@@ -154,10 +164,14 @@ def read_layout(lname, ldict, algo_dict, ttype, verbosity=1):
154
164
  print(f" Reading '{lname}'")
155
165
  cdict = Dict(ldict["coordinates"], name="coordinates")
156
166
  farm = algo_dict["farm"]
157
- for xy in zip(cdict["x"], cdict["y"]):
167
+ tmap = ldict.get("turbine_types", None)
168
+ if verbosity > 2:
169
+ print(f" Turbine type map:", tmap)
170
+ for i, xy in enumerate(zip(cdict["x"], cdict["y"])):
171
+ tt = ttypes[tmap[i] if tmap is not None else 0]
158
172
  farm.add_turbine(
159
- Turbine(xy=np.array(xy), turbine_models=[ttype]),
160
- verbosity=verbosity-3,
173
+ Turbine(xy=np.array(xy), turbine_models=[tt]),
174
+ verbosity=verbosity - 3,
161
175
  )
162
176
  if verbosity > 2:
163
- print(f" Added {farm.n_turbines} wio_trbns of type '{ttype}'")
177
+ print(f" Added {farm.n_turbines} turbines")
@@ -28,6 +28,7 @@ wio2foxes = {
28
28
  """
29
29
  foxes2wio = {d: k for k, d in wio2foxes.items()}
30
30
 
31
+
31
32
  def _read_nondimensional_coordinate(name, wio_data, coords):
32
33
  """read nondimensional coordinate
33
34
  :group: input.windio
@@ -37,6 +38,7 @@ def _read_nondimensional_coordinate(name, wio_data, coords):
37
38
  return True
38
39
  return False
39
40
 
41
+
40
42
  def _read_dimensional_coordinate(name, wio_data, coords):
41
43
  """read dimensional coordinate
42
44
  :group: input.windio
@@ -48,6 +50,7 @@ def _read_dimensional_coordinate(name, wio_data, coords):
48
50
  return True
49
51
  return False
50
52
 
53
+
51
54
  def _read_multi_dimensional_coordinate(name, wio_data, coords):
52
55
  """Read multi dimensional coordinate
53
56
  :group: input.windio
@@ -56,6 +59,7 @@ def _read_multi_dimensional_coordinate(name, wio_data, coords):
56
59
  name, wio_data, coords
57
60
  ) or _read_dimensional_coordinate(name, wio_data, coords)
58
61
 
62
+
59
63
  def _read_nondimensional_data(name, wio_data, fields, dims):
60
64
  """read nondimensional data
61
65
  :group: input.windio
@@ -67,6 +71,7 @@ def _read_nondimensional_data(name, wio_data, fields, dims):
67
71
  return True
68
72
  return False
69
73
 
74
+
70
75
  def _read_dimensional_data(name, wio_data, fields, dims):
71
76
  """read dimensional data
72
77
  :group: input.windio
@@ -83,6 +88,7 @@ def _read_dimensional_data(name, wio_data, fields, dims):
83
88
  return True
84
89
  return False
85
90
 
91
+
86
92
  def _read_multi_dimensional_data(name, wio_data, fields, dims):
87
93
  """Read multi dimensional data
88
94
  :group: input.windio
@@ -91,14 +97,15 @@ def _read_multi_dimensional_data(name, wio_data, fields, dims):
91
97
  name, wio_data, fields, dims
92
98
  ) or _read_dimensional_data(name, wio_data, fields, dims)
93
99
 
100
+
94
101
  def read_wind_resource_field(
95
- name,
96
- wio_data,
97
- coords,
98
- fields,
99
- dims,
102
+ name,
103
+ wio_data,
104
+ coords,
105
+ fields,
106
+ dims,
100
107
  verbosity,
101
- ):
108
+ ):
102
109
  """
103
110
  Reads wind resource data into fields and dims
104
111
 
@@ -136,6 +143,9 @@ def read_wind_resource_field(
136
143
  "lapse_rate",
137
144
  "capping_inversion_thickness",
138
145
  "capping_inversion_strength",
146
+ "tau_x",
147
+ "tau_y",
148
+ "fc",
139
149
  ]:
140
150
  if verbosity > 2:
141
151
  print(f" Ignoring variable '{name}'")