foxes 0.7.2__py3-none-any.whl → 0.7.3.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 (60) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +57 -45
  3. foxes/algorithms/downwind/models/farm_wakes_calc.py +17 -6
  4. foxes/algorithms/downwind/models/point_wakes_calc.py +13 -45
  5. foxes/algorithms/iterative/iterative.py +1 -1
  6. foxes/algorithms/iterative/models/farm_wakes_calc.py +18 -4
  7. foxes/constants.py +5 -0
  8. foxes/core/__init__.py +2 -1
  9. foxes/core/ground_model.py +254 -0
  10. foxes/core/model.py +3 -2
  11. foxes/core/partial_wakes_model.py +19 -3
  12. foxes/core/states.py +33 -0
  13. foxes/core/wake_model.py +138 -2
  14. foxes/data/__init__.py +1 -1
  15. foxes/data/states/WRF-Timeseries-3000.nc +0 -0
  16. foxes/data/states/windio_timeseries_5000.nc +0 -0
  17. foxes/data/static_data.py +7 -0
  18. foxes/data/windio/DTU_10MW_turbine.yaml +10 -0
  19. foxes/data/windio/__init__.py +0 -0
  20. foxes/data/windio/windio_5turbines_timeseries.yaml +63 -0
  21. foxes/input/states/__init__.py +1 -0
  22. foxes/input/states/multi_height.py +225 -6
  23. foxes/input/windio/__init__.py +6 -1
  24. foxes/input/windio/get_states.py +115 -0
  25. foxes/input/windio/read_attributes.py +321 -0
  26. foxes/input/windio/read_farm.py +163 -0
  27. foxes/input/windio/read_fields.py +164 -0
  28. foxes/input/windio/runner.py +105 -0
  29. foxes/input/windio/windio.py +136 -254
  30. foxes/models/__init__.py +1 -0
  31. foxes/models/ground_models/__init__.py +2 -0
  32. foxes/models/ground_models/no_ground.py +12 -0
  33. foxes/models/ground_models/wake_mirror.py +161 -0
  34. foxes/models/model_book.py +68 -149
  35. foxes/models/partial_wakes/axiwake.py +27 -4
  36. foxes/models/partial_wakes/top_hat.py +26 -4
  37. foxes/models/turbine_types/PCt_file.py +1 -0
  38. foxes/models/turbine_types/PCt_from_two.py +92 -0
  39. foxes/models/wake_frames/yawed_wakes.py +41 -38
  40. foxes/models/wake_models/__init__.py +0 -1
  41. foxes/models/wake_models/induction/__init__.py +1 -0
  42. foxes/models/wake_models/induction/rankine_half_body.py +1 -1
  43. foxes/models/wake_models/induction/vortex_sheet.py +227 -0
  44. foxes/models/wake_models/ti/crespo_hernandez.py +26 -24
  45. foxes/models/wake_models/ti/iec_ti.py +33 -26
  46. foxes/models/wake_models/wind/bastankhah14.py +11 -32
  47. foxes/models/wake_models/wind/bastankhah16.py +30 -34
  48. foxes/models/wake_models/wind/jensen.py +13 -29
  49. foxes/models/wake_models/wind/turbopark.py +31 -61
  50. foxes/output/grids.py +6 -6
  51. foxes/output/output.py +6 -6
  52. foxes/utils/__init__.py +1 -1
  53. foxes/utils/factory.py +203 -11
  54. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/METADATA +8 -6
  55. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/RECORD +59 -45
  56. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/WHEEL +1 -1
  57. foxes/models/wake_models/wake_mirror.py +0 -196
  58. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/LICENSE +0 -0
  59. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/top_level.txt +0 -0
  60. {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/zip-safe +0 -0
@@ -0,0 +1,115 @@
1
+ import pandas as pd
2
+ from numbers import Number
3
+
4
+ from foxes.core import States
5
+ import foxes.constants as FC
6
+ import foxes.variables as FV
7
+
8
+ ovars = [FV.WS, FV.WD, FV.TI, FV.RHO]
9
+ fixval = {FV.TI: 0.05, FV.RHO: 1.225}
10
+
11
+
12
+ def _get_SingleStateStates(coords, fields, dims, states_dict, verbosity):
13
+ """Try to generate single state parameters
14
+ :group: input.windio
15
+ """
16
+ for c in coords:
17
+ if not isinstance(c, Number):
18
+ return False
19
+
20
+ if verbosity > 1:
21
+ print(" selecting class 'SingleStateStates'")
22
+
23
+ smap = {FV.WS: "ws", FV.WD: "wd", FV.TI: "ti", FV.RHO: "rho"}
24
+
25
+ data = {smap[v]: d for v, d in fixval.items()}
26
+ for v, d in coords.items():
27
+ if v in smap:
28
+ data[smap[v]] = d
29
+ elif verbosity > 1:
30
+ print(f" ignoring coord '{v}'")
31
+ for v, d in fields.items():
32
+ if v in smap and len(dims[v]) == 0:
33
+ data[smap[v]] = d
34
+ elif verbosity > 1:
35
+ print(f" ignoring field '{v}' with dims {dims[v]}")
36
+
37
+ sdata = pd.DataFrame(index=coords[FC.TIME], data=data)
38
+ sdata.index.name = FC.TIME
39
+ states_dict.update(
40
+ dict(
41
+ states_type="SingleStateStates",
42
+ **data,
43
+ )
44
+ )
45
+ return True
46
+
47
+
48
+ def _get_Timeseries(coords, fields, dims, states_dict, verbosity):
49
+ """Try to generate time series parameters
50
+ :group: input.windio
51
+ """
52
+ if len(coords) == 1 and FC.TIME in coords:
53
+ if verbosity > 1:
54
+ print(" selecting class 'Timeseries'")
55
+
56
+ data = {}
57
+ fix = {}
58
+ for v, d in fields.items():
59
+ if dims[v] == (FC.TIME,):
60
+ data[v] = d
61
+ elif len(dims[v]) == 0:
62
+ fix[v] = d
63
+ elif verbosity > 1:
64
+ print(f" ignoring field '{v}' with dims {dims[v]}")
65
+ fix.update({v: d for v, d in fixval.items() if v not in data})
66
+
67
+ sdata = pd.DataFrame(index=coords[FC.TIME], data=data)
68
+ sdata.index.name = FC.TIME
69
+ states_dict.update(
70
+ dict(
71
+ states_type="Timeseries",
72
+ data_source=sdata,
73
+ output_vars=ovars,
74
+ fixed_vars=fix,
75
+ )
76
+ )
77
+ return True
78
+ return False
79
+
80
+
81
+ def get_states(coords, fields, dims, verbosity=1):
82
+ """
83
+ Reads states parameters from windio input
84
+
85
+ Parameters
86
+ ----------
87
+ coords: dict
88
+ The coordinates data
89
+ fields: dict
90
+ The fields data
91
+ dims: dict
92
+ The dimensions data
93
+ verbosity: int
94
+ The verbosity level
95
+
96
+ Returns
97
+ -------
98
+ states: foxes.core.States
99
+ The states object
100
+
101
+ :group: input.windio
102
+
103
+ """
104
+ if verbosity > 1:
105
+ print(" Preparing states")
106
+
107
+ states_dict = {}
108
+ if _get_SingleStateStates(
109
+ coords, fields, dims, states_dict, verbosity
110
+ ) or _get_Timeseries(coords, fields, dims, states_dict, verbosity):
111
+ return States.new(**states_dict)
112
+ else:
113
+ raise ValueError(
114
+ f"Failed to create states for coords {list(coords.keys())} and fields {list(fields.keys())} with dims {dims}"
115
+ )
@@ -0,0 +1,321 @@
1
+ from foxes.utils import Dict
2
+ from foxes.core import WakeModel, WakeFrame
3
+ import foxes.variables as FV
4
+
5
+
6
+ def _read_wind_deficit(wind_deficit, superposition, induction, algo_dict, verbosity):
7
+ """Reads the wind deficit wake model"""
8
+
9
+ wind_def_map = Dict(
10
+ {
11
+ "Jensen": "JensenWake",
12
+ "Bastankhah2014": "Bastankhah2014",
13
+ "Bastankhah2016": "Bastankhah2016",
14
+ "TurbOPark": "TurbOPark",
15
+ },
16
+ name="wind_def_map",
17
+ )
18
+
19
+ ws_sup_dict = Dict(
20
+ {
21
+ "Linear": "ws_linear",
22
+ "Quadratic": "ws_quadratic",
23
+ },
24
+ name="ws_sup_dict",
25
+ )
26
+
27
+ wname = wind_deficit.pop("name")
28
+ if verbosity > 1:
29
+ print(" Reading wind_deficit_model")
30
+ print(" Name:", wname)
31
+ print(" Contents:", [k for k in wind_deficit.keys()])
32
+ wind_def_dict = Dict(wmodel_type=wind_def_map[wname], induction=induction)
33
+ kcoef = Dict(wind_deficit["wake_expansion_coefficient"], name="kcoef")
34
+ ka = kcoef["k_a"]
35
+ kb = kcoef.get("k_b", 0.0)
36
+ amb_ti = kcoef.get("free_stream_ti", False)
37
+ if ka is None or ka == 0.0:
38
+ wind_def_dict["k"] = kb
39
+ if verbosity > 1:
40
+ print(" Using k =", kb)
41
+ else:
42
+ ti_var = FV.AMB_TI if amb_ti else FV.TI
43
+ if verbosity > 1:
44
+ print(f" Using k = {ka} * {ti_var} + {kb}")
45
+ wind_def_dict["k"] = None
46
+ wind_def_dict["ka"] = ka
47
+ wind_def_dict["kb"] = kb
48
+ wind_def_dict["ti_var"] = ti_var
49
+ if "ceps" in wind_deficit:
50
+ sbf = wind_deficit["ceps"]
51
+ if verbosity > 1:
52
+ print(f" Using sbeta_factor = {sbf}")
53
+ wind_def_dict["sbeta_factor"] = sbf
54
+ wind_def_dict["superposition"] = ws_sup_dict[superposition["ws_superposition"]]
55
+
56
+ algo_dict["mbook"].wake_models[wname] = WakeModel.new(**wind_def_dict)
57
+ if verbosity > 1:
58
+ print(f" Created wake model '{wname}':")
59
+ print(" ", algo_dict["mbook"].wake_models[wname])
60
+ algo_dict["wake_models"].append(wname)
61
+
62
+ return ka, kb, amb_ti
63
+
64
+
65
+ def _read_turbulence(
66
+ turbulence_model, superposition, induction, algo_dict, ka, kb, amb_ti, verbosity
67
+ ):
68
+ """Reads the ti wake model"""
69
+
70
+ twake_def_map = Dict(
71
+ {
72
+ "CrespoHernandez": "CrespoHernandezTIWake",
73
+ "IEC-TI-2019": "IECTI2019",
74
+ },
75
+ name="twake_def_map",
76
+ )
77
+
78
+ ti_sup_dict = Dict(
79
+ {
80
+ "Linear": "ti_linear",
81
+ "Quadratic": "ti_quadratic",
82
+ },
83
+ name="ti_sup_dict",
84
+ )
85
+
86
+ wname = turbulence_model.pop("name")
87
+ if verbosity > 1:
88
+ print(" Reading turbulence_model")
89
+ print(" Name:", wname)
90
+ print(" Contents:", [k for k in turbulence_model.keys()])
91
+ tiwake_dict = dict(wmodel_type=twake_def_map[wname], induction=induction)
92
+ if "wake_expansion_coefficient" in turbulence_model:
93
+ kcoef = Dict(turbulence_model["wake_expansion_coefficient"], name="kcoef")
94
+ ka = kcoef["k_a"]
95
+ kb = kcoef.get("k_b", 0.0)
96
+ amb_ti = kcoef.get("free_stream_ti", False)
97
+ if ka is None or ka == 0.0:
98
+ tiwake_dict["k"] = kb
99
+ if verbosity > 1:
100
+ print(" Using k =", kb)
101
+ else:
102
+ ti_var = FV.AMB_TI if amb_ti else FV.TI
103
+ if verbosity > 1:
104
+ print(f" Using k = {ka} * {ti_var} + {kb}")
105
+ tiwake_dict["k"] = None
106
+ tiwake_dict["ka"] = ka
107
+ tiwake_dict["kb"] = kb
108
+ tiwake_dict["ti_var"] = ti_var
109
+ tiwake_dict["superposition"] = ti_sup_dict[superposition["ti_superposition"]]
110
+
111
+ algo_dict["mbook"].wake_models[wname] = WakeModel.new(**tiwake_dict)
112
+ if verbosity > 1:
113
+ print(f" Created wake model '{wname}':")
114
+ print(" ", algo_dict["mbook"].wake_models[wname])
115
+ algo_dict["wake_models"].append(wname)
116
+
117
+
118
+ def _read_blockage(blockage_model, superposition, induction, algo_dict, verbosity):
119
+ """Reads the blockage model"""
120
+ indc_def_map = Dict(
121
+ {
122
+ "RankineHalfBody": "RankineHalfBody",
123
+ "Rathmann": "Rathmann",
124
+ "SelfSimilarityDeficit": "SelfSimilar",
125
+ "SelfSimilarityDeficit2020": "SelfSimilar2020",
126
+ },
127
+ name="twake_def_map",
128
+ )
129
+
130
+ wname = blockage_model.pop("name")
131
+ if verbosity > 1:
132
+ print(" Reading blockage_model")
133
+ print(" Name:", wname)
134
+ print(" Contents:", [k for k in blockage_model.keys()])
135
+ if wname != "None":
136
+ indc_dict = Dict(wmodel_type=indc_def_map[wname], induction=induction)
137
+ algo_dict["mbook"].wake_models[wname] = WakeModel.new(**indc_dict)
138
+ if verbosity > 1:
139
+ print(f" Created wake model '{wname}':")
140
+ print(" ", algo_dict["mbook"].wake_models[wname])
141
+ algo_dict["wake_models"].append(wname)
142
+ algo_dict["algo_type"] = "Iterative"
143
+
144
+
145
+ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
146
+ """Reads the rotor averaging"""
147
+ if verbosity > 1:
148
+ print(" Reading rotor_averaging")
149
+ print(" Contents:", [k for k in rotor_averaging.keys()])
150
+ grid = rotor_averaging["grid"]
151
+ nx = rotor_averaging["n_x_grid_points"]
152
+ ny = rotor_averaging["n_y_grid_points"]
153
+ if nx != ny:
154
+ raise NotImplementedError(
155
+ f"Grid '{grid}': Only nx=ny supported, got nx={nx}, ny={ny}"
156
+ )
157
+ background_averaging = rotor_averaging["background_averaging"]
158
+ wake_averaging = rotor_averaging["wake_averaging"]
159
+ wse_P = rotor_averaging["wind_speed_exponent_for_power"]
160
+ wse_ct = rotor_averaging["wind_speed_exponent_for_ct"]
161
+ if verbosity > 1:
162
+ print(" grid :", grid)
163
+ print(" background_averaging:", background_averaging)
164
+ print(" wake_averaging :", wake_averaging)
165
+ print(" ws exponent power :", wse_P)
166
+ print(" ws exponent ct :", wse_ct)
167
+ if background_averaging == "center":
168
+ algo_dict["rotor_model"] = "centre"
169
+ elif background_averaging == "grid":
170
+ algo_dict["rotor_model"] = f"grid{nx*ny}"
171
+ else:
172
+ raise KeyError(
173
+ f"Expecting background_averaging 'center' or 'grid', got '{background_averaging}'"
174
+ )
175
+ if wake_averaging == "centre":
176
+ algo_dict["partial_wakes"] = "centre"
177
+ elif wake_averaging == "grid":
178
+ if background_averaging == "grid":
179
+ algo_dict["partial_wakes"] = "rotor_points"
180
+ else:
181
+ if grid == "grid":
182
+ algo_dict["partial_wakes"] = f"grid{nx*ny}"
183
+ else:
184
+ algo_dict["partial_wakes"] = grid
185
+ else:
186
+ algo_dict["partial_wakes"] = wake_averaging
187
+ if verbosity > 1:
188
+ print(" --> rotor_model :", algo_dict["rotor_model"])
189
+ print(" --> partial_wakes :", algo_dict["partial_wakes"])
190
+
191
+
192
+ def _read_deflection(deflection, induction, algo_dict, verbosity):
193
+ """Reads deflection model"""
194
+ defl_def_map = Dict(
195
+ {
196
+ "None": "RotorWD",
197
+ "Batankhah2016": "YawedWakes",
198
+ },
199
+ name="defl_def_map",
200
+ )
201
+
202
+ wname = deflection.pop("name")
203
+ if verbosity > 1:
204
+ print(" Reading deflection_model")
205
+ print(" Name:", wname)
206
+ print(" Contents:", [k for k in deflection.keys()])
207
+ indc_dict = Dict(wframe_type=defl_def_map[wname])
208
+ try:
209
+ algo_dict["mbook"].wake_frames[wname] = WakeFrame.new(
210
+ **indc_dict, induction=induction
211
+ )
212
+ except TypeError:
213
+ algo_dict["mbook"].wake_frames[wname] = WakeFrame.new(**indc_dict)
214
+ if verbosity > 1:
215
+ print(f" Created wake frame '{wname}':")
216
+ print(" ", algo_dict["mbook"].wake_frames[wname])
217
+ algo_dict["wake_frame"] = wname
218
+
219
+
220
+ def _read_analysis(wio_ana, algo_dict, verbosity):
221
+ """Reads the windio analyses"""
222
+ if verbosity > 1:
223
+ print(" Reading analysis")
224
+ print(" Contents:", [k for k in wio_ana.keys()])
225
+
226
+ # superposition:
227
+ superposition = Dict(wio_ana["superposition_model"], name="superposition_model")
228
+ if verbosity > 1:
229
+ print(" Reading superposition_model")
230
+ print(" Contents:", [k for k in superposition.keys()])
231
+
232
+ # axial induction model:
233
+ imap = Dict(
234
+ {
235
+ "1D": "Betz",
236
+ "Madsen": "Madsen",
237
+ },
238
+ name="induction mapping",
239
+ )
240
+ induction = imap[wio_ana["axial_induction_model"]]
241
+ if verbosity > 1:
242
+ print(" axial induction model:", induction)
243
+
244
+ # wind deficit model:
245
+ wind_deficit = Dict(wio_ana["wind_deficit_model"], name="wind_deficit_model")
246
+ ka, kb, amb_ti = _read_wind_deficit(
247
+ wind_deficit, superposition, induction, algo_dict, verbosity
248
+ )
249
+
250
+ # turbulence model:
251
+ turbulence_model = Dict(wio_ana["turbulence_model"], name="turbulence_model")
252
+ _read_turbulence(
253
+ turbulence_model, superposition, induction, algo_dict, ka, kb, amb_ti, verbosity
254
+ )
255
+
256
+ # blockage model:
257
+ blockage_model = Dict(wio_ana["blockage_model"], name="blockage_model")
258
+ _read_blockage(blockage_model, superposition, induction, algo_dict, verbosity)
259
+
260
+ # rotor_averaging:
261
+ rotor_averaging = Dict(wio_ana["rotor_averaging"], name="rotor_averaging")
262
+ _read_rotor_averaging(rotor_averaging, algo_dict, verbosity)
263
+
264
+ # deflection:
265
+ deflection = Dict(wio_ana["deflection_model"], name="deflection_model")
266
+ _read_deflection(deflection, induction, algo_dict, verbosity)
267
+
268
+
269
+ def _read_outputs(wio_outs, algo_dict, verbosity):
270
+ """Reads the outputs"""
271
+ if verbosity > 1:
272
+ print(" Reading outputs")
273
+ print(" Contents:", [k for k in wio_outs.keys()])
274
+ quit()
275
+ return []
276
+
277
+
278
+ def read_attributes(wio, algo_dict, verbosity):
279
+ """
280
+ Reads the attributes part of windio
281
+
282
+ Parameters
283
+ ----------
284
+ wio: dict
285
+ The windio data
286
+ algo_dict: dict
287
+ The algorithm dictionary
288
+ verbosity: int
289
+ The verbosity level, 0=silent
290
+
291
+ Returns
292
+ -------
293
+ out_dicts: list of dict
294
+ The output dictionaries
295
+
296
+ :group: input.windio
297
+
298
+ """
299
+ wio_attrs = Dict(wio["attributes"], name="attributes")
300
+ if verbosity > 0:
301
+ print("Reading attributes")
302
+ print(" Contents:", [k for k in wio_attrs.keys()])
303
+
304
+ # read flow model:
305
+ if "flow_model" in wio_attrs:
306
+ flow_model = Dict(wio_attrs["flow_model"], name="flow_model")
307
+ fmname = flow_model.pop("name")
308
+ if verbosity > 1:
309
+ print(" Reading flow_model")
310
+ print(" Name:", fmname)
311
+ print(" Contents:", [k for k in flow_model.keys()])
312
+ if fmname != "foxes":
313
+ raise ValueError(f"Can only run flow_model 'foxes', got '{fmname}'")
314
+
315
+ # read analysis:
316
+ wio_ana = Dict(wio_attrs["analysis"], name="analyses")
317
+ _read_analysis(wio_ana, algo_dict, verbosity)
318
+
319
+ # outputs:
320
+ outputs = Dict(wio_attrs["outputs"], name="outputs")
321
+ return _read_outputs(outputs, algo_dict, verbosity)
@@ -0,0 +1,163 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+
4
+ from foxes.utils import Dict
5
+ from foxes.core import Turbine, TurbineType
6
+ import foxes.variables as FV
7
+
8
+
9
+ def read_turbine_type(wio_trbns, algo_dict, ws_exp_P, ws_exp_ct, verbosity):
10
+ """
11
+ Reads the turbine type from windio
12
+
13
+ Parameters
14
+ ----------
15
+ wio_trbns: dict
16
+ The windio turbines data
17
+ algo_dict: dict
18
+ The algorithm dictionary
19
+ ws_exp_P: int
20
+ The REWS exponent for power
21
+ ws_exp_ct: int
22
+ The REWS exponent for ct
23
+ verbosity: int
24
+ The verbosity level, 0=silent
25
+
26
+ Returns
27
+ -------
28
+ ttype: str
29
+ The turbine type model name
30
+
31
+ :group: input.windio
32
+
33
+ """
34
+ tname = wio_trbns.pop("name")
35
+ if verbosity > 1:
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 > 1:
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 > 1:
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 > 1:
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 > 1:
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 > 1:
87
+ print(" ", algo_dict["mbook"].turbine_types[tname])
88
+
89
+ # P, ct data:
90
+ elif "Cp_curve" in performance:
91
+ cp_curve = Dict(performance["Cp_curve"], name="Cp_curve")
92
+ if verbosity > 1:
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")
98
+ if verbosity > 1:
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})
106
+
107
+ if verbosity > 1:
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):
129
+ """
130
+ Read wind farm layout from windio input
131
+
132
+ Parameters
133
+ ----------
134
+ lname: str
135
+ The layout name
136
+ ldict: dict
137
+ The layout data
138
+ algo_dict: dict
139
+ The algorithm dictionary
140
+ ttype: str
141
+ Name of the turbine type model
142
+ verbosity: int
143
+ The verbosity level, 0=silent
144
+
145
+ Returns
146
+ -------
147
+ states: foxes.core.States
148
+ The states object
149
+
150
+ :group: input.windio
151
+
152
+ """
153
+ if verbosity > 1:
154
+ print(f" Reading '{lname}'")
155
+ cdict = Dict(ldict["coordinates"], name="coordinates")
156
+ farm = algo_dict["farm"]
157
+ for xy in zip(cdict["x"], cdict["y"]):
158
+ farm.add_turbine(
159
+ Turbine(xy=np.array(xy), turbine_models=[ttype]),
160
+ verbosity=0,
161
+ )
162
+ if verbosity > 1:
163
+ print(f" Added {farm.n_turbines} wio_trbns of type '{ttype}'")