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.
- foxes/VERSION +1 -1
- foxes/algorithms/downwind/downwind.py +57 -45
- foxes/algorithms/downwind/models/farm_wakes_calc.py +17 -6
- foxes/algorithms/downwind/models/point_wakes_calc.py +13 -45
- foxes/algorithms/iterative/iterative.py +1 -1
- foxes/algorithms/iterative/models/farm_wakes_calc.py +18 -4
- foxes/constants.py +5 -0
- foxes/core/__init__.py +2 -1
- foxes/core/ground_model.py +254 -0
- foxes/core/model.py +3 -2
- foxes/core/partial_wakes_model.py +19 -3
- foxes/core/states.py +33 -0
- foxes/core/wake_model.py +138 -2
- foxes/data/__init__.py +1 -1
- foxes/data/states/WRF-Timeseries-3000.nc +0 -0
- foxes/data/states/windio_timeseries_5000.nc +0 -0
- foxes/data/static_data.py +7 -0
- foxes/data/windio/DTU_10MW_turbine.yaml +10 -0
- foxes/data/windio/__init__.py +0 -0
- foxes/data/windio/windio_5turbines_timeseries.yaml +63 -0
- foxes/input/states/__init__.py +1 -0
- foxes/input/states/multi_height.py +225 -6
- foxes/input/windio/__init__.py +6 -1
- foxes/input/windio/get_states.py +115 -0
- foxes/input/windio/read_attributes.py +321 -0
- foxes/input/windio/read_farm.py +163 -0
- foxes/input/windio/read_fields.py +164 -0
- foxes/input/windio/runner.py +105 -0
- foxes/input/windio/windio.py +136 -254
- foxes/models/__init__.py +1 -0
- foxes/models/ground_models/__init__.py +2 -0
- foxes/models/ground_models/no_ground.py +12 -0
- foxes/models/ground_models/wake_mirror.py +161 -0
- foxes/models/model_book.py +68 -149
- foxes/models/partial_wakes/axiwake.py +27 -4
- foxes/models/partial_wakes/top_hat.py +26 -4
- foxes/models/turbine_types/PCt_file.py +1 -0
- foxes/models/turbine_types/PCt_from_two.py +92 -0
- foxes/models/wake_frames/yawed_wakes.py +41 -38
- foxes/models/wake_models/__init__.py +0 -1
- foxes/models/wake_models/induction/__init__.py +1 -0
- foxes/models/wake_models/induction/rankine_half_body.py +1 -1
- foxes/models/wake_models/induction/vortex_sheet.py +227 -0
- foxes/models/wake_models/ti/crespo_hernandez.py +26 -24
- foxes/models/wake_models/ti/iec_ti.py +33 -26
- foxes/models/wake_models/wind/bastankhah14.py +11 -32
- foxes/models/wake_models/wind/bastankhah16.py +30 -34
- foxes/models/wake_models/wind/jensen.py +13 -29
- foxes/models/wake_models/wind/turbopark.py +31 -61
- foxes/output/grids.py +6 -6
- foxes/output/output.py +6 -6
- foxes/utils/__init__.py +1 -1
- foxes/utils/factory.py +203 -11
- {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/METADATA +8 -6
- {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/RECORD +59 -45
- {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/WHEEL +1 -1
- foxes/models/wake_models/wake_mirror.py +0 -196
- {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/LICENSE +0 -0
- {foxes-0.7.2.dist-info → foxes-0.7.3.1.dist-info}/top_level.txt +0 -0
- {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}'")
|