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.
- docs/source/conf.py +3 -1
- examples/abl_states/run.py +5 -5
- examples/dyn_wakes/run.py +2 -2
- examples/induction/run.py +5 -5
- examples/random_timeseries/run.py +13 -13
- examples/scan_row/run.py +12 -7
- examples/sector_management/run.py +11 -7
- examples/single_state/run.py +5 -5
- examples/tab_file/run.py +1 -1
- examples/timelines/run.py +1 -1
- examples/timeseries/run.py +5 -5
- examples/timeseries_slurm/run.py +5 -5
- examples/wind_rose/run.py +1 -1
- examples/yawed_wake/run.py +5 -5
- foxes/__init__.py +13 -2
- foxes/algorithms/downwind/downwind.py +21 -6
- foxes/algorithms/downwind/models/init_farm_data.py +5 -2
- foxes/algorithms/downwind/models/point_wakes_calc.py +0 -1
- foxes/algorithms/iterative/iterative.py +1 -1
- foxes/algorithms/sequential/sequential.py +5 -4
- foxes/config/__init__.py +1 -0
- foxes/config/config.py +134 -0
- foxes/constants.py +15 -6
- foxes/core/algorithm.py +46 -30
- foxes/core/axial_induction_model.py +18 -0
- foxes/core/data.py +2 -1
- foxes/core/engine.py +43 -49
- foxes/core/farm_controller.py +22 -3
- foxes/core/farm_data_model.py +6 -2
- foxes/core/ground_model.py +19 -0
- foxes/core/model.py +2 -1
- foxes/core/partial_wakes_model.py +9 -21
- foxes/core/point_data_model.py +22 -2
- foxes/core/rotor_model.py +9 -21
- foxes/core/states.py +2 -17
- foxes/core/turbine_model.py +2 -18
- foxes/core/turbine_type.py +2 -18
- foxes/core/vertical_profile.py +8 -20
- foxes/core/wake_frame.py +9 -25
- foxes/core/wake_model.py +24 -20
- foxes/core/wake_superposition.py +19 -0
- foxes/data/__init__.py +1 -1
- foxes/data/static_data.py +0 -7
- foxes/engines/dask.py +4 -3
- foxes/engines/single.py +1 -1
- foxes/input/__init__.py +1 -1
- foxes/input/farm_layout/from_csv.py +3 -1
- foxes/input/farm_layout/from_file.py +10 -10
- foxes/input/farm_layout/from_json.py +4 -3
- foxes/input/farm_layout/grid.py +3 -3
- foxes/input/states/__init__.py +1 -1
- foxes/input/states/create/random_abl_states.py +5 -3
- foxes/input/states/field_data_nc.py +36 -15
- foxes/input/states/multi_height.py +26 -15
- foxes/input/states/one_point_flow.py +6 -5
- foxes/input/states/{scan_ws.py → scan.py} +42 -52
- foxes/input/states/single.py +15 -6
- foxes/input/states/slice_data_nc.py +18 -12
- foxes/input/states/states_table.py +17 -10
- foxes/input/yaml/__init__.py +3 -0
- foxes/input/yaml/dict.py +381 -0
- foxes/input/yaml/windio/__init__.py +4 -0
- foxes/input/{windio → yaml/windio}/get_states.py +7 -7
- foxes/input/{windio → yaml/windio}/read_attributes.py +61 -40
- foxes/input/{windio → yaml/windio}/read_farm.py +34 -43
- foxes/input/{windio → yaml/windio}/read_fields.py +11 -10
- foxes/input/yaml/windio/read_outputs.py +147 -0
- foxes/input/yaml/windio/windio.py +269 -0
- foxes/input/yaml/yaml.py +103 -0
- foxes/models/partial_wakes/axiwake.py +7 -6
- foxes/models/partial_wakes/centre.py +3 -2
- foxes/models/partial_wakes/segregated.py +5 -2
- foxes/models/point_models/set_uniform_data.py +5 -3
- foxes/models/rotor_models/centre.py +2 -2
- foxes/models/rotor_models/grid.py +5 -5
- foxes/models/rotor_models/levels.py +6 -6
- foxes/models/turbine_models/kTI_model.py +3 -1
- foxes/models/turbine_models/lookup_table.py +7 -4
- foxes/models/turbine_models/power_mask.py +14 -8
- foxes/models/turbine_models/sector_management.py +4 -2
- foxes/models/turbine_models/set_farm_vars.py +53 -23
- foxes/models/turbine_models/table_factors.py +8 -7
- foxes/models/turbine_models/yaw2yawm.py +0 -1
- foxes/models/turbine_models/yawm2yaw.py +0 -1
- foxes/models/turbine_types/CpCt_file.py +6 -3
- foxes/models/turbine_types/CpCt_from_two.py +6 -3
- foxes/models/turbine_types/PCt_file.py +7 -6
- foxes/models/turbine_types/PCt_from_two.py +11 -2
- foxes/models/turbine_types/TBL_file.py +3 -4
- foxes/models/turbine_types/wsrho2PCt_from_two.py +19 -11
- foxes/models/turbine_types/wsti2PCt_from_two.py +19 -11
- foxes/models/vertical_profiles/abl_log_neutral_ws.py +1 -1
- foxes/models/vertical_profiles/abl_log_stable_ws.py +1 -1
- foxes/models/vertical_profiles/abl_log_unstable_ws.py +1 -1
- foxes/models/vertical_profiles/abl_log_ws.py +1 -1
- foxes/models/wake_frames/dynamic_wakes.py +17 -9
- foxes/models/wake_frames/farm_order.py +4 -3
- foxes/models/wake_frames/rotor_wd.py +3 -1
- foxes/models/wake_frames/seq_dynamic_wakes.py +14 -7
- foxes/models/wake_frames/streamlines.py +9 -6
- foxes/models/wake_frames/timelines.py +21 -14
- foxes/models/wake_frames/yawed_wakes.py +3 -1
- foxes/models/wake_models/induction/vortex_sheet.py +0 -1
- foxes/models/wake_models/ti/crespo_hernandez.py +2 -1
- foxes/models/wake_models/wind/bastankhah14.py +3 -2
- foxes/models/wake_models/wind/bastankhah16.py +2 -1
- foxes/models/wake_models/wind/turbopark.py +9 -7
- foxes/models/wake_superpositions/ws_product.py +0 -1
- foxes/output/__init__.py +2 -1
- foxes/output/calc_points.py +7 -4
- foxes/output/farm_layout.py +30 -18
- foxes/output/farm_results_eval.py +61 -38
- foxes/output/grids.py +8 -7
- foxes/output/output.py +9 -20
- foxes/output/plt.py +19 -0
- foxes/output/results_writer.py +10 -11
- foxes/output/rose_plot.py +448 -224
- foxes/output/rotor_point_plots.py +7 -3
- foxes/output/slice_data.py +1 -1
- foxes/output/state_turbine_map.py +5 -1
- foxes/output/state_turbine_table.py +7 -3
- foxes/output/turbine_type_curves.py +7 -2
- foxes/utils/__init__.py +1 -2
- foxes/utils/dict.py +107 -3
- foxes/utils/geopandas_utils.py +3 -2
- foxes/utils/subclasses.py +69 -0
- {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/METADATA +18 -18
- {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/RECORD +145 -145
- {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/WHEEL +1 -1
- foxes-1.2.1.dist-info/entry_points.txt +3 -0
- tests/0_consistency/iterative/test_iterative.py +65 -67
- tests/0_consistency/partial_wakes/test_partial_wakes.py +58 -61
- tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +56 -53
- tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +41 -41
- tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +34 -34
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +57 -52
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +58 -54
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +80 -76
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +80 -76
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +58 -51
- tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +101 -103
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +67 -64
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +58 -54
- examples/windio/run.py +0 -29
- foxes/data/states/windio_timeseries_5000.nc +0 -0
- foxes/data/windio/DTU_10MW_turbine.yaml +0 -10
- foxes/data/windio/__init__.py +0 -0
- foxes/data/windio/windio_5turbines_timeseries.yaml +0 -79
- foxes/input/windio/__init__.py +0 -11
- foxes/input/windio/read_outputs.py +0 -172
- foxes/input/windio/runner.py +0 -183
- foxes/input/windio/windio.py +0 -193
- foxes/utils/windrose_plot.py +0 -152
- {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/LICENSE +0 -0
- {foxes-1.1.1.dist-info → foxes-1.2.1.dist-info}/top_level.txt +0 -0
foxes/input/yaml/dict.py
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import matplotlib.pyplot as plt
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from inspect import signature
|
|
4
|
+
|
|
5
|
+
import foxes.input.farm_layout as farm_layout
|
|
6
|
+
from foxes.core import States, Engine, WindFarm, Algorithm
|
|
7
|
+
from foxes.models import ModelBook
|
|
8
|
+
from foxes.output import Output
|
|
9
|
+
from foxes.utils import Dict, new_cls
|
|
10
|
+
from foxes.config import config
|
|
11
|
+
import foxes.constants as FC
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def read_dict(
|
|
15
|
+
idict,
|
|
16
|
+
farm=None,
|
|
17
|
+
states=None,
|
|
18
|
+
mbook=None,
|
|
19
|
+
algo=None,
|
|
20
|
+
engine_pars=None,
|
|
21
|
+
iterative=None,
|
|
22
|
+
verbosity=None,
|
|
23
|
+
work_dir=".",
|
|
24
|
+
out_dir=".",
|
|
25
|
+
**algo_pars,
|
|
26
|
+
):
|
|
27
|
+
"""
|
|
28
|
+
Read dictionary input into foxes objects
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
idict: foxes.utils.Dict
|
|
33
|
+
The input parameter dictionary
|
|
34
|
+
farm: foxes.core.WindFarm, optional
|
|
35
|
+
The wind farm, overrules settings from idict
|
|
36
|
+
states: foxes.core.States, optional
|
|
37
|
+
The ambient states, overrules settings from idict
|
|
38
|
+
mbook: foxes.models.ModelBook, optional
|
|
39
|
+
The model book, overrules settings from idict
|
|
40
|
+
algo: foxes.core.Algorithm, optional
|
|
41
|
+
The algorithm, overrules settings from idict
|
|
42
|
+
engine_pars: dict, optional
|
|
43
|
+
Parameters for engine creation, overrules
|
|
44
|
+
settings from idict
|
|
45
|
+
iterative: bool, optional
|
|
46
|
+
Force iterative calculations, overrules
|
|
47
|
+
settings from idict
|
|
48
|
+
verbosity: int, optional
|
|
49
|
+
Force a verbosity level, 0 = silent, overrules
|
|
50
|
+
settings from idict
|
|
51
|
+
work_dir: str or pathlib.Path
|
|
52
|
+
Path to the working directory
|
|
53
|
+
out_dir: str or pathlib.Path
|
|
54
|
+
The default output directory
|
|
55
|
+
algo_pars: dict, optional
|
|
56
|
+
Additional parameters for the algorithm, overrules
|
|
57
|
+
settings from idict
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
algo: foxes.core.Algorithm
|
|
62
|
+
The algorithm
|
|
63
|
+
engine: foxes.core.Engine
|
|
64
|
+
The engine, or None if not set
|
|
65
|
+
|
|
66
|
+
:group: input.yaml
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def _print(*args, level=1, **kwargs):
|
|
71
|
+
if verbosity is None or verbosity >= level:
|
|
72
|
+
print(*args, **kwargs)
|
|
73
|
+
|
|
74
|
+
# set working directory:
|
|
75
|
+
config[FC.WORK_DIR] = work_dir
|
|
76
|
+
config[FC.OUT_DIR] = out_dir
|
|
77
|
+
_print("Working directory:", config.work_dir)
|
|
78
|
+
_print("Output directory :", config.out_dir)
|
|
79
|
+
|
|
80
|
+
# create states:
|
|
81
|
+
if states is None:
|
|
82
|
+
_print("Creating states")
|
|
83
|
+
states = States.new(**idict["states"])
|
|
84
|
+
|
|
85
|
+
# create model book:
|
|
86
|
+
if mbook is None:
|
|
87
|
+
mbook = ModelBook()
|
|
88
|
+
if "model_book" in idict:
|
|
89
|
+
_print("Creating model book")
|
|
90
|
+
mdict = idict.get_item("model_book")
|
|
91
|
+
for s, mlst in mdict.items():
|
|
92
|
+
t = mbook.sources.get_item(s)
|
|
93
|
+
c = mbook.base_classes.get_item(s)
|
|
94
|
+
ms = [Dict(m, name=f"{mdict.name}.s{i}") for i, m in enumerate(mlst)]
|
|
95
|
+
for m in ms:
|
|
96
|
+
mname = m.pop_item("name")
|
|
97
|
+
_print(f" Adding {s}.{mname}")
|
|
98
|
+
t[mname] = c.new(**m)
|
|
99
|
+
|
|
100
|
+
# create farm:
|
|
101
|
+
if farm is None:
|
|
102
|
+
_print("Creating wind farm")
|
|
103
|
+
fdict = idict.get_item("wind_farm")
|
|
104
|
+
lyts = [
|
|
105
|
+
Dict(l, name=f"{fdict.name}.layout{i}")
|
|
106
|
+
for i, l in enumerate(fdict.pop_item("layouts"))
|
|
107
|
+
]
|
|
108
|
+
farm = WindFarm(**fdict)
|
|
109
|
+
for lyt in lyts:
|
|
110
|
+
add_fun = getattr(farm_layout, lyt.pop_item("function"))
|
|
111
|
+
if verbosity is not None:
|
|
112
|
+
lyt["verbosity"] = verbosity - 1
|
|
113
|
+
add_fun(farm, **lyt)
|
|
114
|
+
|
|
115
|
+
# create engine:
|
|
116
|
+
engine = None
|
|
117
|
+
if engine_pars is not None:
|
|
118
|
+
engine = Engine.new(**engine_pars)
|
|
119
|
+
_print(f"Initializing engine: {engine}")
|
|
120
|
+
engine.initialize()
|
|
121
|
+
elif "engine" in idict:
|
|
122
|
+
if verbosity is not None:
|
|
123
|
+
idict["verbosity"] = verbosity - 1
|
|
124
|
+
engine = Engine.new(**idict["engine"])
|
|
125
|
+
engine.initialize()
|
|
126
|
+
_print(f"Initializing engine: {engine}")
|
|
127
|
+
|
|
128
|
+
# create algorithm:
|
|
129
|
+
if algo is None:
|
|
130
|
+
_print("Creating algorithm")
|
|
131
|
+
adict = idict.get_item("algorithm")
|
|
132
|
+
if iterative is not None and iterative:
|
|
133
|
+
adict["algo_type"] = "Iterative"
|
|
134
|
+
adict.update(dict(farm=farm, states=states, mbook=mbook))
|
|
135
|
+
if verbosity is not None:
|
|
136
|
+
adict["verbosity"] = verbosity - 1
|
|
137
|
+
if algo_pars is not None:
|
|
138
|
+
adict.update({v: d for v, d in algo_pars.items() if d is not None})
|
|
139
|
+
algo = Algorithm.new(**adict)
|
|
140
|
+
|
|
141
|
+
return algo, engine
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def run_outputs(
|
|
145
|
+
idict,
|
|
146
|
+
algo=None,
|
|
147
|
+
farm_results=None,
|
|
148
|
+
point_results=None,
|
|
149
|
+
verbosity=None,
|
|
150
|
+
):
|
|
151
|
+
"""
|
|
152
|
+
Run outputs from dict.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
idict: foxes.utils.Dict
|
|
157
|
+
The input parameter dictionary
|
|
158
|
+
algo: foxes.core.Algorithm, optional
|
|
159
|
+
The algorithm
|
|
160
|
+
farm_results: xarray.Dataset, optional
|
|
161
|
+
The farm results
|
|
162
|
+
point_results: xarray.Dataset, optional
|
|
163
|
+
The point results
|
|
164
|
+
verbosity: int, optional
|
|
165
|
+
Force a verbosity level, 0 = silent, overrules
|
|
166
|
+
settings from idict
|
|
167
|
+
|
|
168
|
+
Returns
|
|
169
|
+
-------
|
|
170
|
+
outputs: list of tuple
|
|
171
|
+
For each output enty, a tuple (dict, results),
|
|
172
|
+
where results is a tuple that represents one
|
|
173
|
+
entry per function call
|
|
174
|
+
|
|
175
|
+
:group: input.yaml
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
def _print(*args, level=1, **kwargs):
|
|
180
|
+
if verbosity is None or verbosity >= level:
|
|
181
|
+
print(*args, **kwargs)
|
|
182
|
+
|
|
183
|
+
out = []
|
|
184
|
+
if "outputs" in idict:
|
|
185
|
+
_print("Running outputs")
|
|
186
|
+
odicts = [
|
|
187
|
+
Dict(odict, name=f"{idict.name}.output{i}")
|
|
188
|
+
for i, odict in enumerate(idict["outputs"])
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
rlabels = Dict(name="result_labels")
|
|
192
|
+
|
|
193
|
+
def _get_object(rlabels, d):
|
|
194
|
+
d = d.replace("]", "")
|
|
195
|
+
i0 = d.find("[")
|
|
196
|
+
if i0 > 0:
|
|
197
|
+
inds = tuple([int(x) for x in d[i0 + 1 :].split(",")])
|
|
198
|
+
return rlabels[d[:i0]][inds]
|
|
199
|
+
else:
|
|
200
|
+
return rlabels[d]
|
|
201
|
+
|
|
202
|
+
for i, d in enumerate(odicts):
|
|
203
|
+
|
|
204
|
+
if "output_type" in d:
|
|
205
|
+
ocls = d.pop_item("output_type")
|
|
206
|
+
_print(f" Output {i}: {ocls}")
|
|
207
|
+
d0 = dict(output_type=ocls)
|
|
208
|
+
d0.update(d)
|
|
209
|
+
flist = [
|
|
210
|
+
Dict(f, name=f"{d.name}.function{i}")
|
|
211
|
+
for i, f in enumerate(d.pop_item("functions"))
|
|
212
|
+
]
|
|
213
|
+
cls = new_cls(Output, ocls)
|
|
214
|
+
prs = list(signature(cls.__init__).parameters.keys())
|
|
215
|
+
if "algo" in prs:
|
|
216
|
+
assert (
|
|
217
|
+
algo is not None
|
|
218
|
+
), f"Output {i} of type '{ocls}' requires algo"
|
|
219
|
+
d["algo"] = algo
|
|
220
|
+
if "farm" in prs:
|
|
221
|
+
d["farm"] = algo.farm
|
|
222
|
+
if "farm_results" in prs:
|
|
223
|
+
if farm_results is None:
|
|
224
|
+
print(f"No farm results; skipping output {ocls}")
|
|
225
|
+
for fdict in flist:
|
|
226
|
+
out += (d0, None)
|
|
227
|
+
continue
|
|
228
|
+
d["farm_results"] = farm_results
|
|
229
|
+
if "point_results" in prs:
|
|
230
|
+
d["point_results"] = point_results
|
|
231
|
+
o = cls(**d)
|
|
232
|
+
|
|
233
|
+
elif "object" in d:
|
|
234
|
+
ocls = d.pop("object")
|
|
235
|
+
o = _get_object(rlabels, ocls)
|
|
236
|
+
d0 = dict(object=ocls)
|
|
237
|
+
d0.update(d)
|
|
238
|
+
flist = [
|
|
239
|
+
Dict(f, name=f"{d.name}.function{i}")
|
|
240
|
+
for i, f in enumerate(d.pop_item("functions"))
|
|
241
|
+
]
|
|
242
|
+
|
|
243
|
+
else:
|
|
244
|
+
raise KeyError(
|
|
245
|
+
f"Output {i} of type '{ocls}': Please specify either 'output_type' or 'object'"
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
fres = []
|
|
249
|
+
for fdict in flist:
|
|
250
|
+
fname = fdict.pop_item("function")
|
|
251
|
+
_print(f" - {fname}")
|
|
252
|
+
plt_show = fdict.pop("plt_show", False)
|
|
253
|
+
plt_close = fdict.pop("plt_close", False)
|
|
254
|
+
rlbs = fdict.pop("result_labels", None)
|
|
255
|
+
|
|
256
|
+
# grab function:
|
|
257
|
+
assert hasattr(
|
|
258
|
+
o, fname
|
|
259
|
+
), f"Output {i} of type '{ocls}': Function '{fname}' not found"
|
|
260
|
+
f = getattr(o, fname)
|
|
261
|
+
|
|
262
|
+
# add required input data objects:
|
|
263
|
+
prs = list(signature(f).parameters.keys())
|
|
264
|
+
if "algo" in prs:
|
|
265
|
+
fdict["algo"] = algo
|
|
266
|
+
if "farm" in prs:
|
|
267
|
+
fdict["farm"] = algo.farm
|
|
268
|
+
|
|
269
|
+
# replace result labels by objects:
|
|
270
|
+
for k, d in fdict.items():
|
|
271
|
+
if isinstance(d, str) and d[0] == "$":
|
|
272
|
+
fdict[k] = _get_object(rlabels, d)
|
|
273
|
+
|
|
274
|
+
# run function:
|
|
275
|
+
args = fdict.pop("args", tuple())
|
|
276
|
+
results = f(*args, **fdict)
|
|
277
|
+
|
|
278
|
+
# pyplot shortcuts:
|
|
279
|
+
if plt_show:
|
|
280
|
+
plt.show()
|
|
281
|
+
if plt_close:
|
|
282
|
+
results = None
|
|
283
|
+
plt.close()
|
|
284
|
+
|
|
285
|
+
# store results under result labels:
|
|
286
|
+
if rlbs is not None:
|
|
287
|
+
|
|
288
|
+
def _set_label(rlabels, k, r):
|
|
289
|
+
if k not in ["", "none", "None", "_", "__"]:
|
|
290
|
+
assert (
|
|
291
|
+
k[0] == "$"
|
|
292
|
+
), f"Output {i} of type '{ocls}', function '{fname}': result labels must start with '$', got '{k}'"
|
|
293
|
+
assert (
|
|
294
|
+
"[" not in k and "]" not in k and "," not in k
|
|
295
|
+
), f"Output {i} of type '{ocls}', function '{fname}': result labels cannot contain '[' or ']' or comma, got '{k}'"
|
|
296
|
+
_print(f" result label {k}: {type(r).__name__}")
|
|
297
|
+
rlabels[k] = r
|
|
298
|
+
|
|
299
|
+
if isinstance(rlbs, (list, tuple)):
|
|
300
|
+
for i, k in enumerate(rlbs):
|
|
301
|
+
_set_label(rlabels, k, results[i])
|
|
302
|
+
else:
|
|
303
|
+
_set_label(rlabels, rlbs, results)
|
|
304
|
+
|
|
305
|
+
fres.append(results)
|
|
306
|
+
out.append((d0, fres))
|
|
307
|
+
|
|
308
|
+
return out
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def run_dict(idict, *args, verbosity=None, **kwargs):
|
|
312
|
+
"""
|
|
313
|
+
Runs foxes from dictionary input
|
|
314
|
+
|
|
315
|
+
Parameters
|
|
316
|
+
----------
|
|
317
|
+
idict: foxes.utils.Dict
|
|
318
|
+
The input parameter dictionary
|
|
319
|
+
args: tuple, optional
|
|
320
|
+
Additional parameters for read_dict
|
|
321
|
+
verbosity: int, optional
|
|
322
|
+
Force a verbosity level, 0 = silent, overrules
|
|
323
|
+
settings from idict
|
|
324
|
+
kwargs: dict, optional
|
|
325
|
+
Additional parameters for read_dict
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
farm_results: xarray.Dataset, optional
|
|
330
|
+
The farm results
|
|
331
|
+
point_results: xarray.Dataset, optional
|
|
332
|
+
The point results
|
|
333
|
+
outputs: list of tuple
|
|
334
|
+
For each output enty, a tuple (dict, results),
|
|
335
|
+
where results is a tuple that represents one
|
|
336
|
+
entry per function call
|
|
337
|
+
|
|
338
|
+
:group: input.yaml
|
|
339
|
+
|
|
340
|
+
"""
|
|
341
|
+
|
|
342
|
+
def _print(*args, level=1, **kwargs):
|
|
343
|
+
if verbosity is None or verbosity >= level:
|
|
344
|
+
print(*args, **kwargs)
|
|
345
|
+
|
|
346
|
+
# read components:
|
|
347
|
+
algo, engine = read_dict(idict, *args, verbosity=verbosity, **kwargs)
|
|
348
|
+
|
|
349
|
+
# run farm calculation:
|
|
350
|
+
rdict = idict.get_item("calc_farm", Dict(name=idict.name + ".calc_farm"))
|
|
351
|
+
if rdict.pop_item("run", True):
|
|
352
|
+
_print("Running calc_farm")
|
|
353
|
+
farm_results = algo.calc_farm(**rdict)
|
|
354
|
+
else:
|
|
355
|
+
farm_results = None
|
|
356
|
+
out = (farm_results,)
|
|
357
|
+
|
|
358
|
+
# run points calculation:
|
|
359
|
+
point_results = None
|
|
360
|
+
if "calc_points" in idict:
|
|
361
|
+
rdict = idict.get_item("calc_points")
|
|
362
|
+
if rdict.pop_item("run"):
|
|
363
|
+
_print("Running calc_points")
|
|
364
|
+
points = rdict.pop_item("points")
|
|
365
|
+
if isinstance(points, str):
|
|
366
|
+
_print("Reading file", points)
|
|
367
|
+
points = pd.read_csv(points).to_numpy()
|
|
368
|
+
point_results = algo.calc_points(farm_results, points=points, **rdict)
|
|
369
|
+
else:
|
|
370
|
+
point_results = None
|
|
371
|
+
out += (point_results,)
|
|
372
|
+
|
|
373
|
+
# run outputs:
|
|
374
|
+
out += (run_outputs(idict, algo, farm_results, point_results, verbosity),)
|
|
375
|
+
|
|
376
|
+
# shutdown engine, if created above:
|
|
377
|
+
if engine is not None:
|
|
378
|
+
_print(f"Finalizing engine: {engine}")
|
|
379
|
+
engine.finalize()
|
|
380
|
+
|
|
381
|
+
return out
|
|
@@ -4,13 +4,13 @@ from xarray import Dataset
|
|
|
4
4
|
from numbers import Number
|
|
5
5
|
|
|
6
6
|
from foxes.core import States
|
|
7
|
-
import foxes.constants as FC
|
|
8
7
|
import foxes.variables as FV
|
|
8
|
+
import foxes.constants as FC
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _get_profiles(coords, fields, dims, ovars, fixval, verbosity):
|
|
12
12
|
"""Read ABL profiles information
|
|
13
|
-
:group: input.windio
|
|
13
|
+
:group: input.yaml.windio
|
|
14
14
|
"""
|
|
15
15
|
profiles = {}
|
|
16
16
|
if FV.Z0 in fields:
|
|
@@ -42,7 +42,7 @@ def _get_SingleStateStates(
|
|
|
42
42
|
coords, fields, dims, states_dict, ovars, fixval, profiles, verbosity
|
|
43
43
|
):
|
|
44
44
|
"""Try to generate single state parameters
|
|
45
|
-
:group: input.windio
|
|
45
|
+
:group: input.yaml.windio
|
|
46
46
|
"""
|
|
47
47
|
for c in coords:
|
|
48
48
|
if not isinstance(c, Number):
|
|
@@ -81,7 +81,7 @@ def _get_Timeseries(
|
|
|
81
81
|
coords, fields, dims, states_dict, ovars, fixval, profiles, verbosity
|
|
82
82
|
):
|
|
83
83
|
"""Try to generate time series parameters
|
|
84
|
-
:group: input.windio
|
|
84
|
+
:group: input.yaml.windio
|
|
85
85
|
"""
|
|
86
86
|
if len(coords) == 1 and FC.TIME in coords:
|
|
87
87
|
if verbosity > 2:
|
|
@@ -117,7 +117,7 @@ def _get_MultiHeightNCTimeseries(
|
|
|
117
117
|
coords, fields, dims, states_dict, ovars, fixval, profiles, verbosity
|
|
118
118
|
):
|
|
119
119
|
"""Try to generate time series parameters
|
|
120
|
-
:group: input.windio
|
|
120
|
+
:group: input.yaml.windio
|
|
121
121
|
"""
|
|
122
122
|
if len(coords) == 2 and FC.TIME in coords and FV.H in coords:
|
|
123
123
|
if verbosity > 2:
|
|
@@ -176,11 +176,11 @@ def get_states(coords, fields, dims, verbosity=1):
|
|
|
176
176
|
states: foxes.core.States
|
|
177
177
|
The states object
|
|
178
178
|
|
|
179
|
-
:group: input.windio
|
|
179
|
+
:group: input.yaml.windio
|
|
180
180
|
|
|
181
181
|
"""
|
|
182
182
|
if verbosity > 2:
|
|
183
|
-
print("
|
|
183
|
+
print(" Creating states")
|
|
184
184
|
|
|
185
185
|
ovars = [FV.WS, FV.WD, FV.TI, FV.RHO]
|
|
186
186
|
fixval = {FV.TI: 0.05, FV.RHO: 1.225}
|
|
@@ -6,7 +6,13 @@ from .read_outputs import read_outputs
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def _read_wind_deficit(
|
|
9
|
-
wake_model_key,
|
|
9
|
+
wake_model_key,
|
|
10
|
+
wind_deficit,
|
|
11
|
+
superposition,
|
|
12
|
+
induction,
|
|
13
|
+
algo_dict,
|
|
14
|
+
mbook,
|
|
15
|
+
verbosity,
|
|
10
16
|
):
|
|
11
17
|
"""Reads the wind deficit wake model"""
|
|
12
18
|
|
|
@@ -69,17 +75,25 @@ def _read_wind_deficit(
|
|
|
69
75
|
supd = ws_sup_dict if eff_ws else ws_sup_amb_dict
|
|
70
76
|
wind_def_dict["superposition"] = supd[superposition["ws_superposition"]]
|
|
71
77
|
|
|
72
|
-
|
|
78
|
+
mbook.wake_models[wname] = WakeModel.new(**wind_def_dict)
|
|
73
79
|
if verbosity > 2:
|
|
74
80
|
print(f" Created wake model '{wname}':")
|
|
75
|
-
print(" ",
|
|
81
|
+
print(" ", mbook.wake_models[wname])
|
|
76
82
|
algo_dict["wake_models"].append(wname)
|
|
77
83
|
|
|
78
84
|
return ka, kb, amb_ti
|
|
79
85
|
|
|
80
86
|
|
|
81
87
|
def _read_turbulence(
|
|
82
|
-
turbulence_model,
|
|
88
|
+
turbulence_model,
|
|
89
|
+
superposition,
|
|
90
|
+
induction,
|
|
91
|
+
algo_dict,
|
|
92
|
+
mbook,
|
|
93
|
+
ka,
|
|
94
|
+
kb,
|
|
95
|
+
amb_ti,
|
|
96
|
+
verbosity,
|
|
83
97
|
):
|
|
84
98
|
"""Reads the ti wake model"""
|
|
85
99
|
|
|
@@ -128,14 +142,14 @@ def _read_turbulence(
|
|
|
128
142
|
tiwake_dict["ti_var"] = ti_var
|
|
129
143
|
tiwake_dict["superposition"] = ti_sup_dict[superposition["ti_superposition"]]
|
|
130
144
|
|
|
131
|
-
|
|
145
|
+
mbook.wake_models[wname] = WakeModel.new(**tiwake_dict)
|
|
132
146
|
if verbosity > 2:
|
|
133
147
|
print(f" Created wake model '{wname}':")
|
|
134
|
-
print(" ",
|
|
148
|
+
print(" ", mbook.wake_models[wname])
|
|
135
149
|
algo_dict["wake_models"].append(wname)
|
|
136
150
|
|
|
137
151
|
|
|
138
|
-
def _read_blockage(blockage_model, induction, algo_dict, verbosity):
|
|
152
|
+
def _read_blockage(blockage_model, induction, algo_dict, mbook, verbosity):
|
|
139
153
|
"""Reads the blockage model"""
|
|
140
154
|
indc_def_map = Dict(
|
|
141
155
|
{
|
|
@@ -154,10 +168,10 @@ def _read_blockage(blockage_model, induction, algo_dict, verbosity):
|
|
|
154
168
|
print(" Contents:", [k for k in blockage_model.keys()])
|
|
155
169
|
if wname not in ["None", "none"]:
|
|
156
170
|
indc_dict = Dict(wmodel_type=indc_def_map[wname], induction=induction)
|
|
157
|
-
|
|
171
|
+
mbook.wake_models[wname] = WakeModel.new(**indc_dict)
|
|
158
172
|
if verbosity > 2:
|
|
159
173
|
print(f" Created wake model '{wname}':")
|
|
160
|
-
print(" ",
|
|
174
|
+
print(" ", mbook.wake_models[wname])
|
|
161
175
|
algo_dict["wake_models"].append(wname)
|
|
162
176
|
algo_dict["algo_type"] = "Iterative"
|
|
163
177
|
|
|
@@ -214,7 +228,7 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
|
|
|
214
228
|
print(" --> partial_wakes :", algo_dict["partial_wakes"])
|
|
215
229
|
|
|
216
230
|
|
|
217
|
-
def _read_deflection(deflection, induction, algo_dict, verbosity):
|
|
231
|
+
def _read_deflection(deflection, induction, algo_dict, mbook, verbosity):
|
|
218
232
|
"""Reads deflection model"""
|
|
219
233
|
defl_def_map = Dict(
|
|
220
234
|
{
|
|
@@ -231,25 +245,25 @@ def _read_deflection(deflection, induction, algo_dict, verbosity):
|
|
|
231
245
|
print(" Contents:", [k for k in deflection.keys()])
|
|
232
246
|
indc_dict = Dict(wframe_type=defl_def_map[wname])
|
|
233
247
|
try:
|
|
234
|
-
|
|
235
|
-
**indc_dict, induction=induction
|
|
236
|
-
)
|
|
248
|
+
mbook.wake_frames[wname] = WakeFrame.new(**indc_dict, induction=induction)
|
|
237
249
|
except TypeError:
|
|
238
|
-
|
|
250
|
+
mbook.wake_frames[wname] = WakeFrame.new(**indc_dict)
|
|
239
251
|
if verbosity > 2:
|
|
240
252
|
print(f" Created wake frame '{wname}':")
|
|
241
|
-
print(" ",
|
|
253
|
+
print(" ", mbook.wake_frames[wname])
|
|
242
254
|
algo_dict["wake_frame"] = wname
|
|
243
255
|
|
|
244
256
|
|
|
245
|
-
def _read_analysis(wio_ana,
|
|
257
|
+
def _read_analysis(wio_ana, idict, mbook, verbosity):
|
|
246
258
|
"""Reads the windio analyses"""
|
|
247
259
|
if verbosity > 2:
|
|
248
260
|
print(" Reading analysis")
|
|
249
261
|
print(" Contents:", [k for k in wio_ana.keys()])
|
|
250
262
|
|
|
251
263
|
# superposition:
|
|
252
|
-
superposition = Dict(
|
|
264
|
+
superposition = Dict(
|
|
265
|
+
wio_ana["superposition_model"], name=wio_ana.name + ".superposition_model"
|
|
266
|
+
)
|
|
253
267
|
if verbosity > 2:
|
|
254
268
|
print(" Reading superposition_model")
|
|
255
269
|
print(" Contents:", [k for k in superposition.keys()])
|
|
@@ -270,9 +284,18 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
|
|
|
270
284
|
wake_model_key = (
|
|
271
285
|
"wind_deficit_model" if "wind_deficit_model" in wio_ana else "wake_model"
|
|
272
286
|
)
|
|
273
|
-
|
|
287
|
+
algo_dict = idict["algorithm"]
|
|
288
|
+
wind_deficit = Dict(
|
|
289
|
+
wio_ana[wake_model_key], name=wio_ana.name + "." + wake_model_key
|
|
290
|
+
)
|
|
274
291
|
ka, kb, amb_ti = _read_wind_deficit(
|
|
275
|
-
wake_model_key,
|
|
292
|
+
wake_model_key,
|
|
293
|
+
wind_deficit,
|
|
294
|
+
superposition,
|
|
295
|
+
induction,
|
|
296
|
+
algo_dict,
|
|
297
|
+
mbook,
|
|
298
|
+
verbosity,
|
|
276
299
|
)
|
|
277
300
|
|
|
278
301
|
# turbulence model:
|
|
@@ -283,6 +306,7 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
|
|
|
283
306
|
superposition,
|
|
284
307
|
induction,
|
|
285
308
|
algo_dict,
|
|
309
|
+
mbook,
|
|
286
310
|
ka,
|
|
287
311
|
kb,
|
|
288
312
|
amb_ti,
|
|
@@ -294,7 +318,7 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
|
|
|
294
318
|
# blockage model:
|
|
295
319
|
if "blockage_model" in wio_ana:
|
|
296
320
|
blockage_model = Dict(wio_ana["blockage_model"], name="blockage_model")
|
|
297
|
-
_read_blockage(blockage_model, induction, algo_dict, verbosity)
|
|
321
|
+
_read_blockage(blockage_model, induction, algo_dict, mbook, verbosity)
|
|
298
322
|
elif verbosity > 0:
|
|
299
323
|
print("blockage_model not found, not using a turbine induction model")
|
|
300
324
|
|
|
@@ -308,37 +332,35 @@ def _read_analysis(wio_ana, algo_dict, verbosity):
|
|
|
308
332
|
# deflection:
|
|
309
333
|
if "deflection_model" in wio_ana:
|
|
310
334
|
deflection = Dict(wio_ana["deflection_model"], name="deflection_model")
|
|
311
|
-
_read_deflection(deflection, induction, algo_dict, verbosity)
|
|
335
|
+
_read_deflection(deflection, induction, algo_dict, mbook, verbosity)
|
|
312
336
|
elif verbosity > 0:
|
|
313
337
|
print("deflection_model not found, using default settings")
|
|
314
338
|
|
|
315
339
|
|
|
316
|
-
def read_attributes(wio,
|
|
340
|
+
def read_attributes(wio, idict, mbook, verbosity=1):
|
|
317
341
|
"""
|
|
318
342
|
Reads the attributes part of windio
|
|
319
343
|
|
|
320
344
|
Parameters
|
|
321
345
|
----------
|
|
322
|
-
wio:
|
|
346
|
+
wio: foxes.utils.Dict
|
|
323
347
|
The windio data
|
|
324
|
-
|
|
325
|
-
The
|
|
348
|
+
idict: foxes.utils.Dict
|
|
349
|
+
The foxes input data dictionary
|
|
350
|
+
mbook: foxes.models.ModelBook
|
|
351
|
+
The model book
|
|
326
352
|
verbosity: int
|
|
327
353
|
The verbosity level, 0=silent
|
|
328
|
-
**output_pars: dict, optional
|
|
329
|
-
Additional parameters for output reading
|
|
330
354
|
|
|
331
355
|
Returns
|
|
332
356
|
-------
|
|
333
|
-
out_dicts: list of dict
|
|
334
|
-
The output dictionaries
|
|
335
357
|
odir: pathlib.Path
|
|
336
|
-
|
|
358
|
+
The output directory
|
|
337
359
|
|
|
338
|
-
:group: input.windio
|
|
360
|
+
:group: input.yaml.windio
|
|
339
361
|
|
|
340
362
|
"""
|
|
341
|
-
wio_attrs = Dict(wio["attributes"], name="attributes")
|
|
363
|
+
wio_attrs = Dict(wio["attributes"], name=wio.name + ".attributes")
|
|
342
364
|
if verbosity > 1:
|
|
343
365
|
print("Reading attributes")
|
|
344
366
|
print(" Contents:", [k for k in wio_attrs.keys()])
|
|
@@ -355,15 +377,14 @@ def read_attributes(wio, algo_dict, verbosity=1, **output_pars):
|
|
|
355
377
|
print(f"Running flow model 'foxes', overruling original choice '{fmname}'")
|
|
356
378
|
|
|
357
379
|
# read analysis:
|
|
358
|
-
wio_ana = Dict(wio_attrs["analysis"], name="
|
|
359
|
-
_read_analysis(wio_ana,
|
|
380
|
+
wio_ana = Dict(wio_attrs["analysis"], name=wio_attrs.name + ".analysis")
|
|
381
|
+
_read_analysis(wio_ana, idict, mbook, verbosity)
|
|
360
382
|
|
|
361
383
|
# outputs:
|
|
362
|
-
|
|
384
|
+
odict = idict["outputs"]
|
|
385
|
+
odir = "."
|
|
363
386
|
if "outputs" in wio_attrs:
|
|
364
|
-
outputs = Dict(wio_attrs["outputs"], name="outputs")
|
|
365
|
-
|
|
366
|
-
outputs, algo_dict, verbosity=verbosity, **output_pars
|
|
367
|
-
)
|
|
387
|
+
outputs = Dict(wio_attrs["outputs"], name=wio_attrs.name + ".outputs")
|
|
388
|
+
odir = read_outputs(outputs, odict, verbosity=verbosity)
|
|
368
389
|
|
|
369
|
-
return
|
|
390
|
+
return odir
|