foxes 1.1.1__py3-none-any.whl → 1.2.1__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 (155) hide show
  1. docs/source/conf.py +3 -1
  2. examples/abl_states/run.py +5 -5
  3. examples/dyn_wakes/run.py +2 -2
  4. examples/induction/run.py +5 -5
  5. examples/random_timeseries/run.py +13 -13
  6. examples/scan_row/run.py +12 -7
  7. examples/sector_management/run.py +11 -7
  8. examples/single_state/run.py +5 -5
  9. examples/tab_file/run.py +1 -1
  10. examples/timelines/run.py +1 -1
  11. examples/timeseries/run.py +5 -5
  12. examples/timeseries_slurm/run.py +5 -5
  13. examples/wind_rose/run.py +1 -1
  14. examples/yawed_wake/run.py +5 -5
  15. foxes/__init__.py +13 -2
  16. foxes/algorithms/downwind/downwind.py +21 -6
  17. foxes/algorithms/downwind/models/init_farm_data.py +5 -2
  18. foxes/algorithms/downwind/models/point_wakes_calc.py +0 -1
  19. foxes/algorithms/iterative/iterative.py +1 -1
  20. foxes/algorithms/sequential/sequential.py +5 -4
  21. foxes/config/__init__.py +1 -0
  22. foxes/config/config.py +134 -0
  23. foxes/constants.py +15 -6
  24. foxes/core/algorithm.py +46 -30
  25. foxes/core/axial_induction_model.py +18 -0
  26. foxes/core/data.py +2 -1
  27. foxes/core/engine.py +43 -49
  28. foxes/core/farm_controller.py +22 -3
  29. foxes/core/farm_data_model.py +6 -2
  30. foxes/core/ground_model.py +19 -0
  31. foxes/core/model.py +2 -1
  32. foxes/core/partial_wakes_model.py +9 -21
  33. foxes/core/point_data_model.py +22 -2
  34. foxes/core/rotor_model.py +9 -21
  35. foxes/core/states.py +2 -17
  36. foxes/core/turbine_model.py +2 -18
  37. foxes/core/turbine_type.py +2 -18
  38. foxes/core/vertical_profile.py +8 -20
  39. foxes/core/wake_frame.py +9 -25
  40. foxes/core/wake_model.py +24 -20
  41. foxes/core/wake_superposition.py +19 -0
  42. foxes/data/__init__.py +1 -1
  43. foxes/data/static_data.py +0 -7
  44. foxes/engines/dask.py +4 -3
  45. foxes/engines/single.py +1 -1
  46. foxes/input/__init__.py +1 -1
  47. foxes/input/farm_layout/from_csv.py +3 -1
  48. foxes/input/farm_layout/from_file.py +10 -10
  49. foxes/input/farm_layout/from_json.py +4 -3
  50. foxes/input/farm_layout/grid.py +3 -3
  51. foxes/input/states/__init__.py +1 -1
  52. foxes/input/states/create/random_abl_states.py +5 -3
  53. foxes/input/states/field_data_nc.py +36 -15
  54. foxes/input/states/multi_height.py +26 -15
  55. foxes/input/states/one_point_flow.py +6 -5
  56. foxes/input/states/{scan_ws.py → scan.py} +42 -52
  57. foxes/input/states/single.py +15 -6
  58. foxes/input/states/slice_data_nc.py +18 -12
  59. foxes/input/states/states_table.py +17 -10
  60. foxes/input/yaml/__init__.py +3 -0
  61. foxes/input/yaml/dict.py +381 -0
  62. foxes/input/yaml/windio/__init__.py +4 -0
  63. foxes/input/{windio → yaml/windio}/get_states.py +7 -7
  64. foxes/input/{windio → yaml/windio}/read_attributes.py +61 -40
  65. foxes/input/{windio → yaml/windio}/read_farm.py +34 -43
  66. foxes/input/{windio → yaml/windio}/read_fields.py +11 -10
  67. foxes/input/yaml/windio/read_outputs.py +147 -0
  68. foxes/input/yaml/windio/windio.py +269 -0
  69. foxes/input/yaml/yaml.py +103 -0
  70. foxes/models/partial_wakes/axiwake.py +7 -6
  71. foxes/models/partial_wakes/centre.py +3 -2
  72. foxes/models/partial_wakes/segregated.py +5 -2
  73. foxes/models/point_models/set_uniform_data.py +5 -3
  74. foxes/models/rotor_models/centre.py +2 -2
  75. foxes/models/rotor_models/grid.py +5 -5
  76. foxes/models/rotor_models/levels.py +6 -6
  77. foxes/models/turbine_models/kTI_model.py +3 -1
  78. foxes/models/turbine_models/lookup_table.py +7 -4
  79. foxes/models/turbine_models/power_mask.py +14 -8
  80. foxes/models/turbine_models/sector_management.py +4 -2
  81. foxes/models/turbine_models/set_farm_vars.py +53 -23
  82. foxes/models/turbine_models/table_factors.py +8 -7
  83. foxes/models/turbine_models/yaw2yawm.py +0 -1
  84. foxes/models/turbine_models/yawm2yaw.py +0 -1
  85. foxes/models/turbine_types/CpCt_file.py +6 -3
  86. foxes/models/turbine_types/CpCt_from_two.py +6 -3
  87. foxes/models/turbine_types/PCt_file.py +7 -6
  88. foxes/models/turbine_types/PCt_from_two.py +11 -2
  89. foxes/models/turbine_types/TBL_file.py +3 -4
  90. foxes/models/turbine_types/wsrho2PCt_from_two.py +19 -11
  91. foxes/models/turbine_types/wsti2PCt_from_two.py +19 -11
  92. foxes/models/vertical_profiles/abl_log_neutral_ws.py +1 -1
  93. foxes/models/vertical_profiles/abl_log_stable_ws.py +1 -1
  94. foxes/models/vertical_profiles/abl_log_unstable_ws.py +1 -1
  95. foxes/models/vertical_profiles/abl_log_ws.py +1 -1
  96. foxes/models/wake_frames/dynamic_wakes.py +17 -9
  97. foxes/models/wake_frames/farm_order.py +4 -3
  98. foxes/models/wake_frames/rotor_wd.py +3 -1
  99. foxes/models/wake_frames/seq_dynamic_wakes.py +14 -7
  100. foxes/models/wake_frames/streamlines.py +9 -6
  101. foxes/models/wake_frames/timelines.py +21 -14
  102. foxes/models/wake_frames/yawed_wakes.py +3 -1
  103. foxes/models/wake_models/induction/vortex_sheet.py +0 -1
  104. foxes/models/wake_models/ti/crespo_hernandez.py +2 -1
  105. foxes/models/wake_models/wind/bastankhah14.py +3 -2
  106. foxes/models/wake_models/wind/bastankhah16.py +2 -1
  107. foxes/models/wake_models/wind/turbopark.py +9 -7
  108. foxes/models/wake_superpositions/ws_product.py +0 -1
  109. foxes/output/__init__.py +2 -1
  110. foxes/output/calc_points.py +7 -4
  111. foxes/output/farm_layout.py +30 -18
  112. foxes/output/farm_results_eval.py +61 -38
  113. foxes/output/grids.py +8 -7
  114. foxes/output/output.py +9 -20
  115. foxes/output/plt.py +19 -0
  116. foxes/output/results_writer.py +10 -11
  117. foxes/output/rose_plot.py +448 -224
  118. foxes/output/rotor_point_plots.py +7 -3
  119. foxes/output/slice_data.py +1 -1
  120. foxes/output/state_turbine_map.py +5 -1
  121. foxes/output/state_turbine_table.py +7 -3
  122. foxes/output/turbine_type_curves.py +7 -2
  123. foxes/utils/__init__.py +1 -2
  124. foxes/utils/dict.py +107 -3
  125. foxes/utils/geopandas_utils.py +3 -2
  126. foxes/utils/subclasses.py +69 -0
  127. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/METADATA +18 -18
  128. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/RECORD +145 -145
  129. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/WHEEL +1 -1
  130. foxes-1.2.1.dist-info/entry_points.txt +3 -0
  131. tests/0_consistency/iterative/test_iterative.py +65 -67
  132. tests/0_consistency/partial_wakes/test_partial_wakes.py +58 -61
  133. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +56 -53
  134. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +41 -41
  135. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +34 -34
  136. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +57 -52
  137. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +58 -54
  138. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +80 -76
  139. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +80 -76
  140. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +58 -51
  141. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +101 -103
  142. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +67 -64
  143. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +58 -54
  144. examples/windio/run.py +0 -29
  145. foxes/data/states/windio_timeseries_5000.nc +0 -0
  146. foxes/data/windio/DTU_10MW_turbine.yaml +0 -10
  147. foxes/data/windio/__init__.py +0 -0
  148. foxes/data/windio/windio_5turbines_timeseries.yaml +0 -79
  149. foxes/input/windio/__init__.py +0 -11
  150. foxes/input/windio/read_outputs.py +0 -172
  151. foxes/input/windio/runner.py +0 -183
  152. foxes/input/windio/windio.py +0 -193
  153. foxes/utils/windrose_plot.py +0 -152
  154. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/LICENSE +0 -0
  155. {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,7 @@ from foxes.core import Turbine, TurbineType
6
6
  import foxes.variables as FV
7
7
 
8
8
 
9
- def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
9
+ def read_turbine_types(wio_farm, mbook, ws_exp_P, ws_exp_ct, verbosity):
10
10
  """
11
11
  Reads the turbine type from windio
12
12
 
@@ -14,8 +14,8 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
14
14
  ----------
15
15
  wio_farm: dict
16
16
  The windio farm data
17
- algo_dict: dict
18
- The algorithm dictionary
17
+ mbook: foxes.models.ModelBook
18
+ The model book
19
19
  ws_exp_P: int
20
20
  The REWS exponent for power
21
21
  ws_exp_ct: int
@@ -29,9 +29,14 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
29
29
  Mapping from turbine type key to turbine
30
30
  type name in the model book
31
31
 
32
- :group: input.windio
32
+ :group: input.yaml.windio
33
33
 
34
34
  """
35
+
36
+ def _print(*args, level=1, **kwargs):
37
+ if verbosity >= level:
38
+ print(*args, **kwargs)
39
+
35
40
  if "turbine_types" not in wio_farm:
36
41
  wio_farm["turbine_types"] = {0: wio_farm["turbines"]}
37
42
 
@@ -39,29 +44,25 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
39
44
  for k, wio_trbns in wio_farm["turbine_types"].items():
40
45
  tname = wio_trbns.pop("name")
41
46
  ttypes[k] = tname
42
- if verbosity > 2:
43
- print(" Reading turbine type", k)
44
- print(" Name:", tname)
45
- print(" Contents:", [k for k in wio_trbns.keys()])
47
+ _print(" Reading turbine type", k, level=3)
48
+ _print(" Name:", tname, level=3)
49
+ _print(" Contents:", [k for k in wio_trbns.keys()], level=3)
46
50
 
47
51
  # read performance:
48
52
  performance = Dict(wio_trbns["performance"], name="performance")
49
- if verbosity > 2:
50
- print(" Reading performance")
51
- print(" Contents:", [k for k in performance.keys()])
53
+ _print(" Reading performance", level=3)
54
+ _print(" Contents:", [k for k in performance.keys()], level=3)
52
55
 
53
56
  # P, ct data:
54
57
  if "power_curve" in performance:
55
58
  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
+ _print(" Reading power_curve", level=3)
60
+ _print(" Contents:", [k for k in power_curve.keys()], level=3)
59
61
  P = power_curve["power_values"]
60
62
  ws_P = power_curve["power_wind_speeds"]
61
63
  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()])
64
+ _print(" Reading Ct_curve", level=3)
65
+ _print(" Contents:", [k for k in ct_curve.keys()], level=3)
65
66
  ct = ct_curve["Ct_values"]
66
67
  ws_ct = ct_curve["Ct_wind_speeds"]
67
68
 
@@ -75,10 +76,9 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
75
76
  )
76
77
  return FV.REWS if wse == 1 else (FV.REWS2 if wse == 2 else FV.REWS3)
77
78
 
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(
79
+ _print(f" Creating model '{tname}'", level=3)
80
+ _print(f" Turbine type class: PCtFomTwo", level=3)
81
+ mbook.turbine_types[tname] = TurbineType.new(
82
82
  ttype_type="PCtFromTwo",
83
83
  data_source_P=data_P,
84
84
  data_source_ct=data_ct,
@@ -92,31 +92,27 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
92
92
  var_ws_P=_get_wse_var(ws_exp_P),
93
93
  rho=1.225,
94
94
  )
95
- if verbosity > 2:
96
- print(" ", algo_dict["mbook"].turbine_types[tname])
95
+ _print(" ", mbook.turbine_types[tname], level=3)
97
96
 
98
97
  # P, ct data:
99
98
  elif "Cp_curve" in performance:
100
99
  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()])
100
+ _print(" Reading Cp_curve", level=3)
101
+ _print(" Contents:", [k for k in cp_curve.keys()], level=3)
104
102
  cp = cp_curve["Cp_values"]
105
103
  ws_cp = cp_curve["Cp_wind_speeds"]
106
104
  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()])
105
+ _print(" Reading Ct_curve", level=3)
106
+ _print(" Contents:", [k for k in ct_curve.keys()], level=3)
110
107
  ct = ct_curve["Ct_values"]
111
108
  ws_ct = ct_curve["Ct_wind_speeds"]
112
109
 
113
110
  data_cp = pd.DataFrame(data={"ws": ws_cp, "cp": cp})
114
111
  data_ct = pd.DataFrame(data={"ws": ws_ct, "ct": ct})
115
112
 
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(
113
+ _print(f" Creating model '{tname}'", level=3)
114
+ _print(f" Turbine type class: CpCtFromTwo", level=3)
115
+ mbook.turbine_types[tname] = TurbineType.new(
120
116
  ttype_type="CpCtFromTwo",
121
117
  data_source_cp=data_cp,
122
118
  data_source_ct=data_ct,
@@ -127,6 +123,7 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
127
123
  H=wio_trbns["hub_height"],
128
124
  D=wio_trbns["rotor_diameter"],
129
125
  )
126
+ _print(" ", mbook.turbine_types[tname], level=3)
130
127
 
131
128
  else:
132
129
  raise KeyError(f"Expecting either 'power_curve' or 'Cp_curve'")
@@ -134,7 +131,7 @@ def read_turbine_types(wio_farm, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
134
131
  return ttypes
135
132
 
136
133
 
137
- def read_layout(lname, ldict, algo_dict, ttypes, verbosity=1):
134
+ def read_layout(lname, ldict, farm, ttypes, verbosity=1):
138
135
  """
139
136
  Read wind farm layout from windio input
140
137
 
@@ -144,26 +141,20 @@ def read_layout(lname, ldict, algo_dict, ttypes, verbosity=1):
144
141
  The layout name
145
142
  ldict: dict
146
143
  The layout data
147
- algo_dict: dict
148
- The algorithm dictionary
144
+ farm: foxes.core.WindFarm
145
+ The wind farm
149
146
  ttypes: dict
150
147
  Mapping from turbine type key to turbine
151
148
  type name in the model book
152
149
  verbosity: int
153
150
  The verbosity level, 0=silent
154
151
 
155
- Returns
156
- -------
157
- states: foxes.core.States
158
- The states object
159
-
160
- :group: input.windio
152
+ :group: input.yaml.windio
161
153
 
162
154
  """
163
155
  if verbosity > 2:
164
156
  print(f" Reading '{lname}'")
165
157
  cdict = Dict(ldict["coordinates"], name="coordinates")
166
- farm = algo_dict["farm"]
167
158
  tmap = ldict.get("turbine_types", None)
168
159
  if verbosity > 2:
169
160
  print(f" Turbine type map:", tmap)
@@ -1,11 +1,12 @@
1
1
  import numpy as np
2
2
  from numbers import Number
3
3
 
4
- import foxes.constants as FC
5
4
  import foxes.variables as FV
5
+ import foxes.constants as FC
6
+
6
7
 
7
8
  """ Mapping from windio to foxes variables
8
- :group: input.windio
9
+ :group: input.yaml.windio
9
10
  """
10
11
  wio2foxes = {
11
12
  "time": FC.TIME,
@@ -24,14 +25,14 @@ wio2foxes = {
24
25
  }
25
26
 
26
27
  """ Mapping from foxes to windio variables
27
- :group: input.windio
28
+ :group: input.yaml.windio
28
29
  """
29
30
  foxes2wio = {d: k for k, d in wio2foxes.items()}
30
31
 
31
32
 
32
33
  def _read_nondimensional_coordinate(name, wio_data, coords):
33
34
  """read nondimensional coordinate
34
- :group: input.windio
35
+ :group: input.yaml.windio
35
36
  """
36
37
  if isinstance(wio_data, Number):
37
38
  coords[wio2foxes[name]] = wio_data
@@ -41,7 +42,7 @@ def _read_nondimensional_coordinate(name, wio_data, coords):
41
42
 
42
43
  def _read_dimensional_coordinate(name, wio_data, coords):
43
44
  """read dimensional coordinate
44
- :group: input.windio
45
+ :group: input.yaml.windio
45
46
  """
46
47
  if isinstance(wio_data, list):
47
48
  wio_data = np.array(wio_data)
@@ -53,7 +54,7 @@ def _read_dimensional_coordinate(name, wio_data, coords):
53
54
 
54
55
  def _read_multi_dimensional_coordinate(name, wio_data, coords):
55
56
  """Read multi dimensional coordinate
56
- :group: input.windio
57
+ :group: input.yaml.windio
57
58
  """
58
59
  return _read_nondimensional_coordinate(
59
60
  name, wio_data, coords
@@ -62,7 +63,7 @@ def _read_multi_dimensional_coordinate(name, wio_data, coords):
62
63
 
63
64
  def _read_nondimensional_data(name, wio_data, fields, dims):
64
65
  """read nondimensional data
65
- :group: input.windio
66
+ :group: input.yaml.windio
66
67
  """
67
68
  if isinstance(wio_data, Number):
68
69
  v = wio2foxes[name]
@@ -74,7 +75,7 @@ def _read_nondimensional_data(name, wio_data, fields, dims):
74
75
 
75
76
  def _read_dimensional_data(name, wio_data, fields, dims):
76
77
  """read dimensional data
77
- :group: input.windio
78
+ :group: input.yaml.windio
78
79
  """
79
80
  if isinstance(wio_data, dict) and "data" in wio_data and "dims" in wio_data:
80
81
  d = wio_data["data"]
@@ -91,7 +92,7 @@ def _read_dimensional_data(name, wio_data, fields, dims):
91
92
 
92
93
  def _read_multi_dimensional_data(name, wio_data, fields, dims):
93
94
  """Read multi dimensional data
94
- :group: input.windio
95
+ :group: input.yaml.windio
95
96
  """
96
97
  return _read_nondimensional_data(
97
98
  name, wio_data, fields, dims
@@ -129,7 +130,7 @@ def read_wind_resource_field(
129
130
  success: bool
130
131
  Flag for successful data extraction
131
132
 
132
- :group: input.windio
133
+ :group: input.yaml.windio
133
134
 
134
135
  """
135
136
  if name in [
@@ -0,0 +1,147 @@
1
+ from pathlib import Path
2
+
3
+ from foxes.utils import Dict
4
+ import foxes.variables as FV
5
+ import foxes.constants as FC
6
+
7
+ from .read_fields import foxes2wio
8
+
9
+
10
+ def _read_turbine_outputs(wio_outs, odict, verbosity):
11
+ """Reads the turbine outputs request"""
12
+ if "turbine_outputs" in wio_outs and wio_outs["turbine_outputs"].get(
13
+ "report", True
14
+ ):
15
+ turbine_outputs = Dict(
16
+ wio_outs["turbine_outputs"], name=wio_outs.name + ".turbine_outputs"
17
+ )
18
+ turbine_nc_filename = turbine_outputs.pop(
19
+ "turbine_nc_filename", "turbine_outputs.nc"
20
+ )
21
+ output_variables = turbine_outputs["output_variables"]
22
+ if verbosity > 2:
23
+ print(" Reading turbine_outputs")
24
+ print(" File name:", turbine_nc_filename)
25
+ print(" output_variables:", output_variables)
26
+
27
+ vmap = Dict(
28
+ power=FV.P,
29
+ rotor_effective_velocity=FV.REWS,
30
+ )
31
+ ivmap = {d: k for k, d in vmap.items()}
32
+ ivmap.update(
33
+ {
34
+ FC.STATE: "time",
35
+ FC.TURBINE: "turbine",
36
+ }
37
+ )
38
+
39
+ odict["StateTurbineTable"] = Dict(
40
+ functions=[
41
+ dict(
42
+ name="get_dataset",
43
+ variables=[vmap[v] for v in output_variables],
44
+ name_map=ivmap,
45
+ to_file=turbine_nc_filename,
46
+ round={vw: FV.get_default_digits(vf) for vw, vf in vmap.items()},
47
+ verbosity=verbosity,
48
+ )
49
+ ],
50
+ name=odict.name + ".StateTurbineTable",
51
+ )
52
+
53
+
54
+ def _read_flow_field(wio_outs, odict, verbosity):
55
+ """Reads the flow field request"""
56
+ if "flow_field" in wio_outs and wio_outs["flow_field"].get("report", True):
57
+ flow_field = Dict(wio_outs["flow_field"], name=wio_outs.name + ".flow_field")
58
+ flow_nc_filename = flow_field.pop("flow_nc_filename", "flow_field.nc")
59
+ output_variables = flow_field.pop("output_variables")
60
+ z_planes = Dict(flow_field.pop("z_planes"), name=flow_field.name + ".z_planes")
61
+ z_sampling = z_planes["z_sampling"]
62
+ xy_sampling = z_planes["xy_sampling"]
63
+ cases_run = Dict(
64
+ flow_field.pop("cases_run", {}), name=flow_field.name + ".cases_run"
65
+ )
66
+ states_isel = cases_run.get("subset", None)
67
+ if "all_occurences" in cases_run and cases_run.pop("all_occurences"):
68
+ states_isel = None
69
+ if verbosity > 2:
70
+ print(" Reading flow_field")
71
+ print(" File name :", flow_nc_filename)
72
+ print(" output_variables:", output_variables)
73
+ print(" states subset :", states_isel)
74
+ print(" z_sampling :", z_sampling)
75
+ print(" xy_sampling :", xy_sampling)
76
+
77
+ vmap = Dict(
78
+ wind_speed=FV.WS,
79
+ wind_direction=FV.WD,
80
+ )
81
+
82
+ if z_sampling in ["hub_height", "default"]:
83
+ z = None
84
+ elif isinstance(z_sampling, (int, float)):
85
+ z = z_sampling
86
+ else:
87
+ raise NotImplementedError(
88
+ f"z_sampling '{z_sampling}' of type '{type(z_sampling).__name__}' is not supported (yet). Please give 'hub_height', 'default' or a float."
89
+ )
90
+
91
+ if xy_sampling == "default":
92
+ odict["SliceData"] = Dict(
93
+ verbosity_delta=3,
94
+ functions=[
95
+ dict(
96
+ name="get_states_data_xy",
97
+ states_isel=states_isel,
98
+ n_img_points=(100, 100),
99
+ variables=[vmap[v] for v in output_variables],
100
+ z=z,
101
+ to_file=flow_nc_filename,
102
+ label_map=foxes2wio,
103
+ verbosity=verbosity,
104
+ )
105
+ ],
106
+ name=odict.name + ".SliceData",
107
+ )
108
+ else:
109
+ raise NotImplementedError(
110
+ f"xy_sampling '{xy_sampling}' is not supported (yet)"
111
+ )
112
+
113
+
114
+ def read_outputs(wio_outs, odict, verbosity=1):
115
+ """
116
+ Reads the windio outputs
117
+
118
+ Parameters
119
+ ----------
120
+ wio_outs: foxes.utils.Dict
121
+ The windio output data dict
122
+ odict: foxes.utils.Dict
123
+ The foxes output dictionary
124
+ verbosity: int
125
+ The verbosity level, 0=silent
126
+
127
+ Returns
128
+ -------
129
+ odir: pathlib.Path
130
+ The output directory
131
+
132
+ :group: input.yaml.windio
133
+
134
+ """
135
+ odir = wio_outs.pop("output_folder", ".")
136
+ if verbosity > 2:
137
+ print(" Reading outputs")
138
+ print(" Output dir:", odir)
139
+ print(" Contents :", [k for k in wio_outs.keys()])
140
+
141
+ # read turbine_outputs:
142
+ _read_turbine_outputs(wio_outs, odict, verbosity)
143
+
144
+ # read flow field:
145
+ _read_flow_field(wio_outs, odict, verbosity)
146
+
147
+ return odir
@@ -0,0 +1,269 @@
1
+ import argparse
2
+ from pathlib import Path
3
+
4
+ from foxes.core import WindFarm
5
+ from foxes.models import ModelBook
6
+ from foxes.utils import import_module, Dict
7
+
8
+ from .read_fields import read_wind_resource_field
9
+ from .get_states import get_states
10
+ from .read_farm import read_layout, read_turbine_types
11
+ from .read_attributes import read_attributes
12
+ from ..dict import run_dict
13
+
14
+
15
+ def _read_site(wio_dict, verbosity):
16
+ """Reads the site information"""
17
+
18
+ def _print(*args, level=1, **kwargs):
19
+ if verbosity >= level:
20
+ print(*args, **kwargs)
21
+
22
+ wio_site = Dict(wio_dict["site"], name=wio_dict.name + ".site")
23
+ _print("Reading site")
24
+ _print(" Name:", wio_site.pop("name", None))
25
+ _print(" Contents:", [k for k in wio_site.keys()])
26
+ _print(" Ignoring boundaries", level=2)
27
+
28
+ # read energy_resource:
29
+ energy_resource = Dict(
30
+ wio_site["energy_resource"], name=wio_site.name + ".energy_resource"
31
+ )
32
+ _print(" Reading energy_resource", level=2)
33
+ _print(" Name:", energy_resource.pop("name", None), level=2)
34
+ _print(" Contents:", [k for k in energy_resource.keys()], level=2)
35
+
36
+ # read wind_resource:
37
+ wind_resource = Dict(
38
+ energy_resource["wind_resource"], name=energy_resource.name + ".wind_resource"
39
+ )
40
+ _print(" Reading wind_resource", level=3)
41
+ _print(" Name:", wind_resource.pop("name", None), level=3)
42
+ _print(" Contents:", [k for k in wind_resource.keys()], level=3)
43
+
44
+ # read fields
45
+ coords = Dict(name="coords")
46
+ fields = Dict(name="fields")
47
+ dims = Dict(name="dims")
48
+ for n, d in wind_resource.items():
49
+ read_wind_resource_field(n, d, coords, fields, dims, verbosity)
50
+ if verbosity > 2:
51
+ print(" Coords:")
52
+ for c, d in coords.items():
53
+ print(f" {c}: Shape {d.shape}")
54
+ print(" Fields:")
55
+ for f, d in dims.items():
56
+ if len(d):
57
+ print(f" {f}: Dims {d}, shape {fields[f].shape}")
58
+ else:
59
+ print(f" {f} = {fields[f]}")
60
+
61
+ return get_states(coords, fields, dims, verbosity)
62
+
63
+
64
+ def _read_farm(wio_dict, mbook, verbosity):
65
+ """Reads the wind farm information"""
66
+ wio_farm = Dict(wio_dict["wind_farm"], name=wio_dict.name + ".wind_farm")
67
+ if verbosity > 1:
68
+ print("Reading wind farm")
69
+ print(" Name:", wio_farm.pop("name", None))
70
+ print(" Contents:", [k for k in wio_farm.keys()])
71
+
72
+ # find REWS exponents:
73
+ try:
74
+ rotor_averaging = wio_dict["attributes"]["analysis"]["rotor_averaging"]
75
+ ws_exp_P = rotor_averaging["wind_speed_exponent_for_power"]
76
+ ws_exp_ct = rotor_averaging["wind_speed_exponent_for_ct"]
77
+ except KeyError:
78
+ ws_exp_P = 1
79
+ ws_exp_ct = 1
80
+
81
+ # read turbine type:
82
+ ttypes = read_turbine_types(wio_farm, mbook, ws_exp_P, ws_exp_ct, verbosity)
83
+
84
+ # read layouts and create wind farm:
85
+ farm = WindFarm()
86
+ wfarm = wio_farm["layouts"]
87
+ if isinstance(wfarm, dict):
88
+ layouts = Dict(wfarm, name=wio_farm.name + ".layouts")
89
+ else:
90
+ layouts = {str(i): l for i, l in enumerate(wfarm)}
91
+ layouts = Dict(layouts, name=wio_farm.name + ".layouts")
92
+ if verbosity > 2:
93
+ print(" Reading layouts")
94
+ print(" Contents:", [k for k in layouts.keys()])
95
+ for lname, ldict in layouts.items():
96
+ read_layout(lname, ldict, farm, ttypes, verbosity)
97
+
98
+ return farm
99
+
100
+
101
+ def read_windio(wio_dict, verbosity=1):
102
+ """
103
+ Translate windio data to foxes input data
104
+
105
+ Parameters
106
+ ----------
107
+ wio_dict: foxes.utils.Dict
108
+ The windio data
109
+ verbosity: int
110
+ The verbosity level, 0 = silent
111
+
112
+ Returns
113
+ -------
114
+ idict: foxes.utils.Dict
115
+ The foxes input data dictionary
116
+ states: foxes.core.States
117
+ The states object
118
+ farm: foxes.core.WindFarm
119
+ The wind farm
120
+ mbook: foxes.models.ModelBook
121
+ The model book
122
+
123
+ :group: input.yaml.windio
124
+
125
+ """
126
+
127
+ def _print(*args, level=1, **kwargs):
128
+ if verbosity >= level:
129
+ print(*args, **kwargs)
130
+
131
+ _print(f"Reading windio data")
132
+ _print(" Name:", wio_dict.pop("name", None))
133
+ _print(" Contents:", [k for k in wio_dict.keys()])
134
+
135
+ idict = Dict(
136
+ wind_farm=Dict(name="wio2fxs.farm"),
137
+ algorithm=Dict(
138
+ algo_type="Downwind",
139
+ wake_models=[],
140
+ name="wio2fxs.algorithm",
141
+ verbosity=verbosity - 3,
142
+ ),
143
+ calc_farm=Dict(run=True, name="wio2fxs.calc_farm"),
144
+ outputs=Dict(name="wio2fxs.outputs"),
145
+ name="wio2fxs",
146
+ )
147
+
148
+ mbook = ModelBook()
149
+ states = _read_site(wio_dict, verbosity)
150
+ farm = _read_farm(wio_dict, mbook, verbosity)
151
+
152
+ odir = read_attributes(wio_dict, idict, mbook, verbosity=verbosity)
153
+
154
+ return idict, states, farm, mbook, odir
155
+
156
+
157
+ def foxes_windio():
158
+ """
159
+ Command line tool for running foxes from windio yaml file input.
160
+
161
+ Examples
162
+ --------
163
+ >>> foxes_windio input.yaml
164
+
165
+ :group: input.yaml.windio
166
+
167
+ """
168
+
169
+ parser = argparse.ArgumentParser()
170
+ parser.add_argument(
171
+ "yml_file",
172
+ help="The windio yaml file",
173
+ )
174
+ parser.add_argument("-o", "--out_dir", help="The output directory", default=None)
175
+ parser.add_argument("-r", "--rotor", help="The rotor model", default="centre")
176
+ parser.add_argument(
177
+ "-p", "--pwakes", help="The partial wakes models", default="centre", nargs="+"
178
+ )
179
+ parser.add_argument(
180
+ "-w",
181
+ "--wakes",
182
+ help="The wake models",
183
+ default=["Jensen_linear_k007"],
184
+ nargs="+",
185
+ )
186
+ parser.add_argument("-f", "--frame", help="The wake frame", default="rotor_wd")
187
+ parser.add_argument("-e", "--engine", help="The engine", default=None)
188
+ parser.add_argument(
189
+ "-n", "--n_procs", help="The number of processes", default=None, type=int
190
+ )
191
+ parser.add_argument(
192
+ "-c",
193
+ "--chunksize_states",
194
+ help="The chunk size for states",
195
+ default=None,
196
+ type=int,
197
+ )
198
+ parser.add_argument(
199
+ "-C",
200
+ "--chunksize_points",
201
+ help="The chunk size for points",
202
+ default=5000,
203
+ type=int,
204
+ )
205
+ parser.add_argument(
206
+ "-it", "--iterative", help="Use iterative algorithm", action="store_true"
207
+ )
208
+ parser.add_argument(
209
+ "-nf", "--nofig", help="Do not show figures", action="store_true"
210
+ )
211
+ parser.add_argument(
212
+ "-v",
213
+ "--verbosity",
214
+ help="The verbosity level, 0 = silent",
215
+ type=int,
216
+ default=None,
217
+ )
218
+ args = parser.parse_args()
219
+
220
+ v = 1 if args.verbosity is None else args.verbosity
221
+
222
+ def _print(*args, level=1, **kwargs):
223
+ if v >= level:
224
+ print(*args, **kwargs)
225
+
226
+ if (
227
+ args.engine is not None
228
+ or args.n_procs is not None
229
+ or args.chunksize_states is not None
230
+ or args.chunksize_points is not None
231
+ ):
232
+ epars = dict(
233
+ engine_type=args.engine,
234
+ n_procs=args.n_procs,
235
+ chunk_size_states=args.chunksize_states,
236
+ chunk_size_points=args.chunksize_points,
237
+ verbosity=v,
238
+ )
239
+ else:
240
+ epars = None
241
+
242
+ wio_file = Path(args.yml_file)
243
+ _print(f"Reading windio file {wio_file}")
244
+ yml_utils = import_module(
245
+ "windIO.utils.yml_utils",
246
+ hint="pip install git+https://github.com/kilojoules/windIO@master#egg=windIO",
247
+ )
248
+
249
+ wio = Dict(yml_utils.load_yaml(wio_file), name="windio")
250
+ idict, states, farm, mbook, odir = read_windio(wio, verbosity=v)
251
+
252
+ if args.out_dir is not None:
253
+ odir = args.odir
254
+
255
+ run_dict(
256
+ idict,
257
+ farm=farm,
258
+ states=states,
259
+ mbook=mbook,
260
+ rotor_model=args.rotor,
261
+ partial_wakes=args.pwakes,
262
+ wake_models=args.wakes,
263
+ wake_frame=args.frame,
264
+ engine_pars=epars,
265
+ iterative=args.iterative,
266
+ work_dir=wio_file.parent,
267
+ out_dir=odir,
268
+ verbosity=args.verbosity,
269
+ )