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,28 +5,39 @@ from foxes.utils import Dict
5
5
  import foxes.variables as FV
6
6
  import foxes.constants as FC
7
7
 
8
+ from .read_fields import foxes2wio
9
+
10
+
8
11
  def _read_turbine_outputs(wio_outs, odir, out_dicts, verbosity):
9
- """ Reads the turbine outputs request """
10
- if "turbine_outputs" in wio_outs and wio_outs["turbine_outputs"].get("report", True):
12
+ """Reads the turbine outputs request"""
13
+ if "turbine_outputs" in wio_outs and wio_outs["turbine_outputs"].get(
14
+ "report", True
15
+ ):
11
16
  turbine_outputs = Dict(wio_outs["turbine_outputs"], name="turbine_outputs")
12
- turbine_nc_filename = turbine_outputs.pop("turbine_nc_filename", "turbine_outputs.nc")
17
+ turbine_nc_filename = turbine_outputs.pop(
18
+ "turbine_nc_filename", "turbine_outputs.nc"
19
+ )
13
20
  output_variables = turbine_outputs["output_variables"]
14
21
  if verbosity > 2:
15
22
  print(" Reading turbine_outputs")
16
23
  print(" File name:", turbine_nc_filename)
17
24
  print(" output_variables:", output_variables)
18
-
25
+
19
26
  vmap = Dict(
20
27
  power=FV.P,
21
28
  rotor_effective_velocity=FV.REWS,
22
29
  )
23
30
  ivmap = {d: k for k, d in vmap.items()}
24
- ivmap.update({
25
- FC.STATE: "time",
26
- FC.TURBINE: "turbine",
27
- })
28
-
29
- out_dicts.append(Dict({
31
+ ivmap.update(
32
+ {
33
+ FC.STATE: "time",
34
+ FC.TURBINE: "turbine",
35
+ }
36
+ )
37
+
38
+ out_dicts.append(
39
+ Dict(
40
+ {
30
41
  "output_type": "StateTurbineTable",
31
42
  "farm_results": True,
32
43
  "algo": False,
@@ -34,16 +45,23 @@ def _read_turbine_outputs(wio_outs, odir, out_dicts, verbosity):
34
45
  "run_kwargs": dict(
35
46
  variables=[vmap[v] for v in output_variables],
36
47
  name_map=ivmap,
37
- to_file=odir/turbine_nc_filename,
48
+ to_file=odir / turbine_nc_filename,
49
+ round={
50
+ vw: FV.get_default_digits(vf) for vw, vf in vmap.items()
51
+ },
38
52
  verbosity=verbosity,
39
53
  ),
40
54
  "output_yaml_update": {
41
55
  "power_table": f"include {turbine_nc_filename}",
42
56
  },
43
- }, name = "turbine_outputs"))
57
+ },
58
+ name="turbine_outputs",
59
+ )
60
+ )
61
+
44
62
 
45
63
  def _read_flow_field(wio_outs, odir, out_dicts, verbosity):
46
- """ Reads the flow field request """
64
+ """Reads the flow field request"""
47
65
  if "flow_field" in wio_outs and wio_outs["flow_field"].get("report", True):
48
66
  flow_field = Dict(wio_outs["flow_field"], name="flow_field")
49
67
  flow_nc_filename = flow_field.pop("flow_nc_filename", "flow_field.nc")
@@ -51,10 +69,15 @@ def _read_flow_field(wio_outs, odir, out_dicts, verbosity):
51
69
  z_planes = Dict(flow_field.pop("z_planes"), name="z_planes")
52
70
  z_sampling = z_planes["z_sampling"]
53
71
  xy_sampling = z_planes["xy_sampling"]
72
+ cases_run = Dict(flow_field.pop("cases_run", {}), name="cases_run")
73
+ states_isel = cases_run.get("subset", None)
74
+ if "all_occurences" in cases_run and cases_run.pop("all_occurences"):
75
+ states_isel = None
54
76
  if verbosity > 2:
55
77
  print(" Reading flow_field")
56
78
  print(" File name :", flow_nc_filename)
57
79
  print(" output_variables:", output_variables)
80
+ print(" states subset :", states_isel)
58
81
  print(" z_sampling :", z_sampling)
59
82
  print(" xy_sampling :", xy_sampling)
60
83
 
@@ -62,30 +85,48 @@ def _read_flow_field(wio_outs, odir, out_dicts, verbosity):
62
85
  wind_speed=FV.WS,
63
86
  wind_direction=FV.WD,
64
87
  )
65
-
88
+
89
+ if z_sampling in ["hub_height", "default"]:
90
+ z = None
91
+ elif isinstance(z_sampling, (int, float)):
92
+ z = z_sampling
93
+ else:
94
+ raise NotImplementedError(
95
+ f"z_sampling '{z_sampling}' of type '{type(z_sampling).__name__}' is not supported (yet). Please give 'hub_height', 'default' or a float."
96
+ )
97
+
66
98
  if xy_sampling == "default":
67
- out_dicts.append(Dict({
99
+ out_dicts.append(
100
+ Dict(
101
+ {
68
102
  "output_type": "SliceData",
69
103
  "farm_results": True,
70
104
  "algo": True,
71
105
  "verbosity_delta": 3,
72
106
  "run_func": "get_states_data_xy",
73
107
  "run_kwargs": dict(
74
- resolution=30.,
108
+ states_isel=states_isel,
109
+ n_img_points=(100, 100),
75
110
  variables=[vmap[v] for v in output_variables],
76
- z=None if z_sampling == "hub_height" else z_sampling,
77
- to_file=odir/flow_nc_filename,
111
+ z=z,
112
+ to_file=odir / flow_nc_filename,
113
+ label_map=foxes2wio,
78
114
  verbosity=verbosity,
79
115
  ),
80
116
  "output_yaml_update": {
81
117
  "flow_field": f"include {flow_nc_filename}",
82
118
  },
83
- }, name = "flow_field"))
119
+ },
120
+ name="flow_field",
121
+ )
122
+ )
84
123
  else:
85
- raise NotImplementedError(f"xy_sampling '{xy_sampling}' is not supported (yet)")
86
-
87
-
88
- def read_outputs(wio_outs, algo_dict, verbosity):
124
+ raise NotImplementedError(
125
+ f"xy_sampling '{xy_sampling}' is not supported (yet)"
126
+ )
127
+
128
+
129
+ def read_outputs(wio_outs, algo_dict, output_dir=None, verbosity=1):
89
130
  """
90
131
  Reads the windio outputs
91
132
 
@@ -95,6 +136,8 @@ def read_outputs(wio_outs, algo_dict, verbosity):
95
136
  The windio output data
96
137
  algo_dict: dict
97
138
  The algorithm dictionary
139
+ output_dir: pathlib.Path, optional
140
+ Path to the output folder
98
141
  verbosity: int
99
142
  The verbosity level, 0=silent
100
143
 
@@ -109,7 +152,11 @@ def read_outputs(wio_outs, algo_dict, verbosity):
109
152
 
110
153
  """
111
154
  out_dicts = []
112
- odir = Path(wio_outs.pop("output_folder", "results"))
155
+ odir = (
156
+ Path(output_dir)
157
+ if output_dir is not None
158
+ else Path(wio_outs.pop("output_folder", "results"))
159
+ )
113
160
  odir.mkdir(exist_ok=True, parents=True)
114
161
  if verbosity > 2:
115
162
  print(" Reading outputs")
@@ -5,7 +5,7 @@ from foxes.output import Output
5
5
 
6
6
 
7
7
  def _write_yaml(data, fpath):
8
- """ Write the data to yaml """
8
+ """Write the data to yaml"""
9
9
  rmap = {
10
10
  "include": "!include",
11
11
  }
@@ -13,11 +13,12 @@ def _write_yaml(data, fpath):
13
13
  yaml.dump(data, file)
14
14
  with open(fpath, "r") as f:
15
15
  s = f.read()
16
- with open(fpath, 'w') as f:
16
+ with open(fpath, "w") as f:
17
17
  for k1, k2 in rmap.items():
18
18
  s = s.replace(k1, k2)
19
19
  f.write(s)
20
-
20
+
21
+
21
22
  class WindioRunner:
22
23
  """
23
24
  Runner for windio input
@@ -40,6 +41,10 @@ class WindioRunner:
40
41
  Name of the written input data file
41
42
  file_name_output_yaml: str
42
43
  Name of the written output data file
44
+ write_input_yaml: bool
45
+ Flag for writing file_name_input_yaml
46
+ write_output_yaml: bool
47
+ Flag for writing file_name_output_yaml
43
48
  verbosity: int
44
49
  The verbosity level, 0 = silent
45
50
 
@@ -48,15 +53,17 @@ class WindioRunner:
48
53
  """
49
54
 
50
55
  def __init__(
51
- self,
52
- algo_dict,
56
+ self,
57
+ algo_dict,
53
58
  output_dir=".",
54
- output_dicts=[],
55
- wio_input_data=None,
59
+ output_dicts=[],
60
+ wio_input_data=None,
56
61
  file_name_input_yaml="recorded_input.yaml",
57
62
  file_name_output_yaml="recorded_output.yaml",
63
+ write_input_yaml=False,
64
+ write_output_yaml=False,
58
65
  verbosity=1,
59
- ):
66
+ ):
60
67
  """
61
68
  Conbstructor
62
69
 
@@ -74,6 +81,10 @@ class WindioRunner:
74
81
  Name of the written input data file
75
82
  file_name_output_yaml: str
76
83
  Name of the written output data file
84
+ write_input_yaml: bool
85
+ Flag for writing file_name_input_yaml
86
+ write_output_yaml: bool
87
+ Flag for writing file_name_output_yaml
77
88
  verbosity: int
78
89
  The verbosity level, 0 = silent
79
90
 
@@ -84,15 +95,17 @@ class WindioRunner:
84
95
  self.wio_input_data = wio_input_data
85
96
  self.file_name_input_yaml = file_name_input_yaml
86
97
  self.file_name_output_yaml = file_name_output_yaml
98
+ self.write_input_yaml = write_input_yaml
99
+ self.write_output_yaml = write_output_yaml
87
100
  self.verbosity = verbosity
88
101
  self.farm_results = None
89
102
  self.output_results = None
90
103
 
91
104
  self.__initialized = False
92
-
105
+
93
106
  self._output_yaml = {}
94
- if wio_input_data is not None and len(wio_input_data):
95
- fpath = output_dir/file_name_input_yaml
107
+ if self.write_input_yaml and len(wio_input_data):
108
+ fpath = output_dir / file_name_input_yaml
96
109
  self.print(f"Writing file", fpath)
97
110
  _write_yaml(wio_input_data, fpath)
98
111
  self._output_yaml["wind_energy_system"] = f"include {file_name_input_yaml}"
@@ -131,7 +144,7 @@ class WindioRunner:
131
144
  run_fname = odict.pop("run_func")
132
145
  run_args = odict.pop("run_args", ())
133
146
  run_kwargs = odict.pop("run_kwargs", {})
134
-
147
+
135
148
  _odict = odict.copy()
136
149
  if "output_yaml_update" in _odict:
137
150
  self._output_yaml.update(_odict.pop("output_yaml_update"))
@@ -142,11 +155,12 @@ class WindioRunner:
142
155
  o = Output.new(**_odict)
143
156
  f = getattr(o, run_fname)
144
157
  self.output_results.append(f(*run_args, **run_kwargs))
145
-
146
- fpath = self.output_dir/self.file_name_output_yaml
147
- self.print(f"Writing file", fpath)
148
- _write_yaml(self._output_yaml, fpath)
149
-
158
+
159
+ if self.write_output_yaml:
160
+ fpath = self.output_dir / self.file_name_output_yaml
161
+ self.print(f"Writing file", fpath)
162
+ _write_yaml(self._output_yaml, fpath)
163
+
150
164
  def run(self):
151
165
  """Runs all calculations"""
152
166
  self.run_farm_calc()
@@ -1,5 +1,3 @@
1
- import numpy as np
2
- import pandas as pd
3
1
  from pathlib import Path
4
2
 
5
3
  from foxes.core import WindFarm
@@ -9,7 +7,7 @@ from foxes.data import StaticData, WINDIO
9
7
 
10
8
  from .read_fields import read_wind_resource_field
11
9
  from .get_states import get_states
12
- from .read_farm import read_layout, read_turbine_type
10
+ from .read_farm import read_layout, read_turbine_types
13
11
  from .read_attributes import read_attributes
14
12
  from .runner import WindioRunner
15
13
 
@@ -78,19 +76,28 @@ def _read_farm(wio, algo_dict, verbosity):
78
76
  ws_exp_ct = 1
79
77
 
80
78
  # read turbine type:
81
- turbines = Dict(wio_farm["turbines"], name="turbines")
82
- ttype = read_turbine_type(turbines, algo_dict, ws_exp_P, ws_exp_ct, verbosity)
79
+ ttypes = read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity)
83
80
 
84
81
  # read layouts:
85
- layouts = Dict(wio_farm["layouts"], name="layouts")
82
+ wfarm = wio_farm["layouts"]
83
+ if isinstance(wfarm, dict):
84
+ layouts = Dict(wfarm, name="layouts")
85
+ else:
86
+ layouts = Dict({i: l for i, l in enumerate(wfarm)}, name="layouts")
86
87
  if verbosity > 2:
87
88
  print(" Reading layouts")
88
89
  print(" Contents:", [k for k in layouts.keys()])
89
90
  for lname, ldict in layouts.items():
90
- read_layout(lname, ldict, algo_dict, ttype, verbosity)
91
+ read_layout(lname, ldict, algo_dict, ttypes, verbosity)
91
92
 
92
93
 
93
- def read_windio(windio_yaml, verbosity=1):
94
+ def read_windio(
95
+ windio_yaml,
96
+ verbosity=1,
97
+ algo_pars=None,
98
+ output_dir=None,
99
+ **runner_pars,
100
+ ):
94
101
  """
95
102
  Reads a complete WindIO case.
96
103
 
@@ -103,6 +110,12 @@ def read_windio(windio_yaml, verbosity=1):
103
110
  Path to the windio yaml file
104
111
  verbosity: int
105
112
  The verbosity level, 0 = silent
113
+ algo_pars: dict, optional
114
+ Additional algorithm parameters
115
+ output_dir: str, optional
116
+ Path to the output folder
117
+ runner_pars: dict, optional
118
+ Additional parameters for the WindioRunner
106
119
 
107
120
  Returns
108
121
  -------
@@ -113,7 +126,6 @@ def read_windio(windio_yaml, verbosity=1):
113
126
  :group: input.windio
114
127
 
115
128
  """
116
-
117
129
  wio_file = Path(windio_yaml)
118
130
  if not wio_file.is_file():
119
131
  wio_file = StaticData().get_file_path(WINDIO, wio_file, check_raw=False)
@@ -128,32 +140,38 @@ def read_windio(windio_yaml, verbosity=1):
128
140
  print(" Name:", wio.pop("name", None))
129
141
  print(" Contents:", [k for k in wio.keys()])
130
142
 
131
- algo_dict = Dict(
132
- algo_type="Downwind",
133
- mbook=ModelBook(),
134
- farm=WindFarm(),
135
- wake_models=[],
136
- verbosity=verbosity-3,
143
+ algo_dict = Dict(algo_type="Downwind", name="algo_dict")
144
+ if algo_pars is not None:
145
+ algo_dict.update(algo_pars)
146
+ algo_dict.update(
147
+ dict(
148
+ mbook=ModelBook(),
149
+ farm=WindFarm(),
150
+ wake_models=[],
151
+ verbosity=verbosity - 3,
152
+ )
137
153
  )
138
154
 
139
155
  _read_site(wio, algo_dict, verbosity)
140
156
  _read_farm(wio, algo_dict, verbosity)
141
-
157
+
142
158
  out_dicts, odir = read_attributes(
143
159
  wio,
144
160
  algo_dict,
145
- verbosity,
161
+ output_dir=output_dir,
162
+ verbosity=verbosity,
146
163
  )
147
164
 
148
165
  if verbosity > 1:
149
166
  print("Creating windio runner")
150
167
  runner = WindioRunner(
151
- algo_dict,
152
- output_dir=odir,
153
- output_dicts=out_dicts,
154
- wio_input_data=wio,
155
- verbosity=verbosity
156
- )
168
+ algo_dict,
169
+ output_dir=odir,
170
+ output_dicts=out_dicts,
171
+ wio_input_data=wio,
172
+ verbosity=verbosity,
173
+ **runner_pars,
174
+ )
157
175
 
158
176
  return runner
159
177
 
@@ -65,7 +65,7 @@ class Turbine2FarmModel(FarmModel):
65
65
  return self.turbine_model.output_farm_vars(algo)
66
66
 
67
67
  def calculate(self, algo, mdata, fdata, **parameters):
68
- """ "
68
+ """
69
69
  The main model calculation.
70
70
 
71
71
  This function is executed on a single chunk of data,
@@ -56,7 +56,7 @@ class WakeMirror(GroundModel):
56
56
  The target point data
57
57
  downwind_index: int
58
58
  The index of the wake causing turbine
59
- in the downwnd order
59
+ in the downwind order
60
60
  wake_deltas: dict
61
61
  The wake deltas. Key: variable name,
62
62
  value: numpy.ndarray with shape
@@ -70,6 +70,10 @@ class WakeMirror(GroundModel):
70
70
  # prepare:
71
71
  hh = fdata[FV.H][:, downwind_index].copy()
72
72
 
73
+ # DEBUG CHECK:
74
+ # import numpy as np
75
+ # assert(np.all(fdata[FV.H]==fdata[FV.TXYH[..., 2]]))
76
+
73
77
  # contribution from main wake:
74
78
  wcoos = algo.wake_frame.get_wake_coos(algo, mdata, fdata, tdata, downwind_index)
75
79
  wmodel.contribute(algo, mdata, fdata, tdata, downwind_index, wcoos, wake_deltas)
@@ -78,14 +82,14 @@ class WakeMirror(GroundModel):
78
82
  tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
79
83
  for h in self.heights:
80
84
 
81
- fdata[FV.H][:, downwind_index] = hh + 2 * (h - hh)
85
+ fdata[FV.TXYH][:, downwind_index, 2] = hh + 2 * (h - hh)
82
86
 
83
87
  pwake.contribute(
84
88
  algo, mdata, fdata, tdata, downwind_index, wake_deltas, wmodel
85
89
  )
86
90
 
87
91
  # reset heights:
88
- fdata[FV.H][:, downwind_index] = hh
92
+ fdata[FV.TXYH][:, downwind_index, 2] = hh
89
93
 
90
94
  def contribute_to_point_wakes(
91
95
  self,
@@ -113,7 +117,7 @@ class WakeMirror(GroundModel):
113
117
  The target point data
114
118
  downwind_index: int
115
119
  The index of the wake causing turbine
116
- in the downwnd order
120
+ in the downwind order
117
121
  wake_deltas: dict
118
122
  The wake deltas. Key: variable name,
119
123
  value: numpy.ndarray with shape
@@ -133,7 +137,7 @@ class WakeMirror(GroundModel):
133
137
  tdata[FC.TARGETS] = tdata[FC.TARGETS].copy() # making sure this is no ref
134
138
  for h in self.heights:
135
139
 
136
- fdata[FV.H][:, downwind_index] = hh + 2 * (h - hh)
140
+ fdata[FV.TXYH][:, downwind_index, 2] = hh + 2 * (h - hh)
137
141
 
138
142
  wcoos = algo.wake_frame.get_wake_coos(
139
143
  algo, mdata, fdata, tdata, downwind_index
@@ -143,7 +147,7 @@ class WakeMirror(GroundModel):
143
147
  )
144
148
 
145
149
  # reset heights:
146
- fdata[FV.H][:, downwind_index] = hh
150
+ fdata[FV.TXYH][:, downwind_index, 2] = hh
147
151
 
148
152
 
149
153
  class GroundMirror(WakeMirror):
@@ -85,8 +85,7 @@ class ModelBook:
85
85
  self.point_models["tke2ti"] = fm.point_models.TKE2TI()
86
86
 
87
87
  self.rotor_models = FDict(name="rotor_models")
88
- rvars = [FV.REWS, FV.REWS2, FV.REWS3, FV.TI, FV.RHO]
89
- self.rotor_models["centre"] = fm.rotor_models.CentreRotor(calc_vars=rvars)
88
+ self.rotor_models["centre"] = fm.rotor_models.CentreRotor()
90
89
 
91
90
  def _n2n(n2):
92
91
  n2 = float(n2)
@@ -100,7 +99,7 @@ class ModelBook:
100
99
  self.rotor_models.add_factory(
101
100
  fm.rotor_models.GridRotor,
102
101
  "grid<n2>",
103
- kwargs=dict(calc_vars=rvars, reduce=True),
102
+ kwargs=dict(reduce=True),
104
103
  var2arg={"n2": "n"},
105
104
  n2=_n2n,
106
105
  hints={"n2": "(Number of points in square grid)"},
@@ -108,7 +107,7 @@ class ModelBook:
108
107
  self.rotor_models.add_factory(
109
108
  fm.rotor_models.GridRotor,
110
109
  "grid<n2>_raw",
111
- kwargs=dict(calc_vars=rvars, reduce=False),
110
+ kwargs=dict(reduce=False),
112
111
  var2arg={"n2": "n"},
113
112
  n2=_n2n,
114
113
  hints={"n2": "(Number of points in square grid)"},
@@ -116,14 +115,14 @@ class ModelBook:
116
115
  self.rotor_models.add_factory(
117
116
  fm.rotor_models.LevelRotor,
118
117
  "level<n>",
119
- kwargs=dict(calc_vars=rvars, reduce=True),
118
+ kwargs=dict(reduce=True),
120
119
  n=lambda x: int(x),
121
120
  hints={"n": "(Number of vertical levels)"},
122
121
  )
123
122
  self.rotor_models.add_factory(
124
123
  fm.rotor_models.LevelRotor,
125
124
  "level<n>_raw",
126
- kwargs=dict(calc_vars=rvars, reduce=False),
125
+ kwargs=dict(reduce=False),
127
126
  n=lambda x: int(x),
128
127
  hints={"n": "(Number of vertical levels)"},
129
128
  )
@@ -158,14 +157,14 @@ class ModelBook:
158
157
  fm.turbine_models.kTI,
159
158
  "kTI_<kTI>",
160
159
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
161
- hints={"kTI": "(Value, e.g. 004 for 0.04)"},
160
+ hints={"kTI": "(Value, e.g. 02 for 0.2)"},
162
161
  )
163
162
  self.turbine_models.add_factory(
164
163
  fm.turbine_models.kTI,
165
164
  "kTI_amb_<kTI>",
166
165
  kwargs=dict(ti_var=FV.AMB_TI),
167
166
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
168
- hints={"kTI": "(Value, e.g. 004 for 0.04)"},
167
+ hints={"kTI": "(Value, e.g. 04 for 0.4)"},
169
168
  )
170
169
  self.turbine_models.add_factory(
171
170
  fm.turbine_models.kTI,
@@ -173,7 +172,7 @@ class ModelBook:
173
172
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
174
173
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
175
174
  hints={
176
- "kTI": "(Value, e.g. 004 for 0.04)",
175
+ "kTI": "(Value, e.g. 04 for 0.4)",
177
176
  "kb": "(Value, e.g. 004 for 0.04)",
178
177
  },
179
178
  )
@@ -184,7 +183,7 @@ class ModelBook:
184
183
  kTI=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
185
184
  kb=lambda x: float(f"0.{x[1:]}" if x[0] == "0" else float(x)),
186
185
  hints={
187
- "kTI": "(Value, e.g. 004 for 0.04)",
186
+ "kTI": "(Value, e.g. 04 for 0.4)",
188
187
  "kb": "(Value, e.g. 004 for 0.04)",
189
188
  },
190
189
  )
@@ -254,12 +253,24 @@ class ModelBook:
254
253
  )
255
254
 
256
255
  self.wake_frames["timelines"] = fm.wake_frames.Timelines()
256
+ self.wake_frames["dyn_wakes"] = fm.wake_frames.DynamicWakes()
257
+ self.wake_frames["seq_dyn_wakes"] = fm.wake_frames.SeqDynamicWakes()
257
258
 
258
259
  def _todt(x):
259
260
  if x[-1] == "s":
260
261
  return float(x[:-1]) / 60
261
262
  elif x[-3:] == "min":
262
263
  return float(x[:-3])
264
+ else:
265
+ raise NotImplementedError(f"Cannot translate '{x}' into minutes")
266
+
267
+ def _tokm(x):
268
+ if x[-2:] == "km":
269
+ return float(x[:-2])
270
+ elif x[-1] == "m":
271
+ return float(x[:-1]) / 1e3
272
+ else:
273
+ raise NotImplementedError(f"Cannot translate '{x}' into km")
263
274
 
264
275
  self.wake_frames.add_factory(
265
276
  fm.wake_frames.Timelines,
@@ -268,6 +279,13 @@ class ModelBook:
268
279
  var2arg={"dt": "dt_min"},
269
280
  hints={"dt": "(Time step, e.g '10s', '1min' etc.)"},
270
281
  )
282
+ self.wake_frames.add_factory(
283
+ fm.wake_frames.DynamicWakes,
284
+ "dyn_wakes_<length>",
285
+ length=_tokm,
286
+ var2arg={"length": "max_length_km"},
287
+ hints={"length": "(Maximal wake length, e.g. '5km' or '5000m')"},
288
+ )
271
289
  self.wake_frames.add_factory(
272
290
  fm.wake_frames.SeqDynamicWakes,
273
291
  "seq_dyn_wakes_<dt>",
@@ -411,14 +429,6 @@ class ModelBook:
411
429
  hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
412
430
  )
413
431
 
414
- self.wake_models.add_factory(
415
- fm.wake_models.ti.IECTIWake,
416
- "IECTI2005_<superposition>",
417
- kwargs=dict(iec_type="2005"),
418
- superposition=lambda s: f"ti_{s}",
419
- hints={"superposition": "(Superposition, e.g. linear for ti_linear)"},
420
- )
421
-
422
432
  self.wake_models.add_factory(
423
433
  fm.wake_models.ti.IECTIWake,
424
434
  "IECTI2019_<superposition>",
@@ -450,12 +460,39 @@ class ModelBook:
450
460
  )
451
461
 
452
462
  self.wake_models[f"RHB"] = fm.wake_models.induction.RankineHalfBody()
463
+
464
+ self.wake_models[f"VortexSheet"] = fm.wake_models.induction.VortexSheet()
465
+ self.wake_models.add_factory(
466
+ fm.wake_models.induction.VortexSheet,
467
+ "VortexSheet_<superposition>",
468
+ superposition=lambda s: f"ws_{s}",
469
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
470
+ )
471
+
453
472
  self.wake_models[f"Rathmann"] = fm.wake_models.induction.Rathmann()
473
+ self.wake_models.add_factory(
474
+ fm.wake_models.induction.Rathmann,
475
+ "Rathmann_<superposition>",
476
+ superposition=lambda s: f"ws_{s}",
477
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
478
+ )
479
+
454
480
  self.wake_models[f"SelfSimilar"] = fm.wake_models.induction.SelfSimilar()
455
481
  self.wake_models[f"SelfSimilar2020"] = (
456
482
  fm.wake_models.induction.SelfSimilar2020()
457
483
  )
458
- self.wake_models[f"VortexSheet"] = fm.wake_models.induction.VortexSheet()
484
+ self.wake_models.add_factory(
485
+ fm.wake_models.induction.SelfSimilar,
486
+ "SelfSimilar_<superposition>",
487
+ superposition=lambda s: f"ws_{s}",
488
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
489
+ )
490
+ self.wake_models.add_factory(
491
+ fm.wake_models.induction.SelfSimilar2020,
492
+ "SelfSimilar2020_<superposition>",
493
+ superposition=lambda s: f"ws_{s}",
494
+ hints={"superposition": "(Superposition, e.g. linear for ws_linear)"},
495
+ )
459
496
 
460
497
  self.ground_models = FDict(name="ground_models")
461
498
  self.ground_models["no_ground"] = fm.ground_models.NoGround()
@@ -466,6 +503,7 @@ class ModelBook:
466
503
  var2arg={"height": "heights"},
467
504
  height=lambda h: [0.0, float(h)],
468
505
  hints={"height": "(Boundary layer wake reflection height)"},
506
+ example_vars={"height": 500},
469
507
  )
470
508
 
471
509
  self.sources = FDict(
@@ -504,7 +542,7 @@ class ModelBook:
504
542
  m.name = k
505
543
 
506
544
  def __getitem__(self, key):
507
- return self.sources.__getitem__(key)
545
+ return self.sources.get_item(key)
508
546
 
509
547
  def print_toc(self, subset=None, search=None):
510
548
  """