foxes 1.2__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.
- examples/abl_states/run.py +5 -5
- 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/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/algorithms/downwind/downwind.py +15 -5
- foxes/algorithms/sequential/sequential.py +1 -1
- foxes/core/algorithm.py +24 -20
- foxes/core/axial_induction_model.py +18 -0
- foxes/core/engine.py +2 -14
- foxes/core/farm_controller.py +18 -0
- foxes/core/ground_model.py +19 -0
- foxes/core/partial_wakes_model.py +9 -21
- foxes/core/point_data_model.py +18 -0
- foxes/core/rotor_model.py +2 -18
- 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 +2 -20
- foxes/core/wake_model.py +19 -20
- foxes/core/wake_superposition.py +19 -0
- foxes/input/states/__init__.py +1 -1
- foxes/input/states/field_data_nc.py +14 -1
- foxes/input/states/{scan_ws.py → scan.py} +39 -52
- foxes/input/yaml/__init__.py +1 -1
- foxes/input/yaml/dict.py +221 -50
- foxes/input/yaml/yaml.py +5 -5
- foxes/output/__init__.py +2 -1
- foxes/output/farm_results_eval.py +57 -35
- foxes/output/output.py +2 -18
- foxes/output/plt.py +19 -0
- foxes/output/rose_plot.py +413 -207
- foxes/utils/__init__.py +1 -2
- foxes/utils/subclasses.py +69 -0
- {foxes-1.2.dist-info → foxes-1.2.1.dist-info}/METADATA +1 -2
- {foxes-1.2.dist-info → foxes-1.2.1.dist-info}/RECORD +56 -56
- tests/0_consistency/iterative/test_iterative.py +1 -1
- tests/0_consistency/partial_wakes/test_partial_wakes.py +1 -1
- tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +7 -2
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +7 -2
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +7 -2
- tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +7 -2
- tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +7 -2
- tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +7 -3
- tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +7 -2
- foxes/utils/windrose_plot.py +0 -152
- {foxes-1.2.dist-info → foxes-1.2.1.dist-info}/LICENSE +0 -0
- {foxes-1.2.dist-info → foxes-1.2.1.dist-info}/WHEEL +0 -0
- {foxes-1.2.dist-info → foxes-1.2.1.dist-info}/entry_points.txt +0 -0
- {foxes-1.2.dist-info → foxes-1.2.1.dist-info}/top_level.txt +0 -0
foxes/input/yaml/dict.py
CHANGED
|
@@ -5,13 +5,13 @@ from inspect import signature
|
|
|
5
5
|
import foxes.input.farm_layout as farm_layout
|
|
6
6
|
from foxes.core import States, Engine, WindFarm, Algorithm
|
|
7
7
|
from foxes.models import ModelBook
|
|
8
|
-
from foxes import
|
|
9
|
-
from foxes.utils import Dict
|
|
8
|
+
from foxes.output import Output
|
|
9
|
+
from foxes.utils import Dict, new_cls
|
|
10
10
|
from foxes.config import config
|
|
11
11
|
import foxes.constants as FC
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def
|
|
14
|
+
def read_dict(
|
|
15
15
|
idict,
|
|
16
16
|
farm=None,
|
|
17
17
|
states=None,
|
|
@@ -25,7 +25,7 @@ def run_dict(
|
|
|
25
25
|
**algo_pars,
|
|
26
26
|
):
|
|
27
27
|
"""
|
|
28
|
-
|
|
28
|
+
Read dictionary input into foxes objects
|
|
29
29
|
|
|
30
30
|
Parameters
|
|
31
31
|
----------
|
|
@@ -58,12 +58,10 @@ def run_dict(
|
|
|
58
58
|
|
|
59
59
|
Returns
|
|
60
60
|
-------
|
|
61
|
-
|
|
62
|
-
The
|
|
63
|
-
|
|
64
|
-
The
|
|
65
|
-
output_i: object
|
|
66
|
-
For each output either None or the output result
|
|
61
|
+
algo: foxes.core.Algorithm
|
|
62
|
+
The algorithm
|
|
63
|
+
engine: foxes.core.Engine
|
|
64
|
+
The engine, or None if not set
|
|
67
65
|
|
|
68
66
|
:group: input.yaml
|
|
69
67
|
|
|
@@ -137,12 +135,220 @@ def run_dict(
|
|
|
137
135
|
if verbosity is not None:
|
|
138
136
|
adict["verbosity"] = verbosity - 1
|
|
139
137
|
if algo_pars is not None:
|
|
140
|
-
adict.update(algo_pars)
|
|
138
|
+
adict.update({v: d for v, d in algo_pars.items() if d is not None})
|
|
141
139
|
algo = Algorithm.new(**adict)
|
|
142
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
|
+
|
|
143
349
|
# run farm calculation:
|
|
144
|
-
rdict = idict.get_item("calc_farm")
|
|
145
|
-
if rdict.pop_item("run"):
|
|
350
|
+
rdict = idict.get_item("calc_farm", Dict(name=idict.name + ".calc_farm"))
|
|
351
|
+
if rdict.pop_item("run", True):
|
|
146
352
|
_print("Running calc_farm")
|
|
147
353
|
farm_results = algo.calc_farm(**rdict)
|
|
148
354
|
else:
|
|
@@ -150,6 +356,7 @@ def run_dict(
|
|
|
150
356
|
out = (farm_results,)
|
|
151
357
|
|
|
152
358
|
# run points calculation:
|
|
359
|
+
point_results = None
|
|
153
360
|
if "calc_points" in idict:
|
|
154
361
|
rdict = idict.get_item("calc_points")
|
|
155
362
|
if rdict.pop_item("run"):
|
|
@@ -164,43 +371,7 @@ def run_dict(
|
|
|
164
371
|
out += (point_results,)
|
|
165
372
|
|
|
166
373
|
# run outputs:
|
|
167
|
-
|
|
168
|
-
_print("Running outputs")
|
|
169
|
-
odict = idict["outputs"]
|
|
170
|
-
for ocls, d in odict.items():
|
|
171
|
-
_print(f" Output {ocls}")
|
|
172
|
-
flist = [
|
|
173
|
-
Dict(f, name=f"{d.name}.function{i}")
|
|
174
|
-
for i, f in enumerate(d.pop_item("functions"))
|
|
175
|
-
]
|
|
176
|
-
try:
|
|
177
|
-
cls = getattr(output, ocls)
|
|
178
|
-
except AttributeError as e:
|
|
179
|
-
print(f"\nClass '{ocls}' not found in outputs. Found:")
|
|
180
|
-
prs = list(signature(cls.__init__).parameters.keys())
|
|
181
|
-
if "algo" in prs:
|
|
182
|
-
d["algo"] = algo
|
|
183
|
-
if "farm_results" in prs:
|
|
184
|
-
if farm_results is None:
|
|
185
|
-
print(f"No farm results; skipping output {ocls}")
|
|
186
|
-
for fdict in flist:
|
|
187
|
-
out += (None,)
|
|
188
|
-
continue
|
|
189
|
-
d["farm_results"] = farm_results
|
|
190
|
-
o = cls(**d)
|
|
191
|
-
for fdict in flist:
|
|
192
|
-
fname = fdict.pop_item("name")
|
|
193
|
-
_print(f" - {fname}")
|
|
194
|
-
plt_show = fdict.pop("plt_show", False)
|
|
195
|
-
f = getattr(o, fname)
|
|
196
|
-
prs = list(signature(f).parameters.keys())
|
|
197
|
-
if "algo" in prs:
|
|
198
|
-
fdict["algo"] = algo
|
|
199
|
-
res = f(**fdict)
|
|
200
|
-
out += (res,) if not isinstance(res, tuple) else res
|
|
201
|
-
if plt_show:
|
|
202
|
-
plt.show()
|
|
203
|
-
plt.close()
|
|
374
|
+
out += (run_outputs(idict, algo, farm_results, point_results, verbosity),)
|
|
204
375
|
|
|
205
376
|
# shutdown engine, if created above:
|
|
206
377
|
if engine is not None:
|
foxes/input/yaml/yaml.py
CHANGED
|
@@ -24,18 +24,18 @@ def foxes_yaml():
|
|
|
24
24
|
help="The input yaml file",
|
|
25
25
|
)
|
|
26
26
|
parser.add_argument("-o", "--out_dir", help="The output directory", default=".")
|
|
27
|
-
parser.add_argument("-r", "--rotor", help="The rotor model", default=
|
|
27
|
+
parser.add_argument("-r", "--rotor", help="The rotor model", default=None)
|
|
28
28
|
parser.add_argument(
|
|
29
|
-
"-p", "--pwakes", help="The partial wakes models", default=
|
|
29
|
+
"-p", "--pwakes", help="The partial wakes models", default=None, nargs="+"
|
|
30
30
|
)
|
|
31
31
|
parser.add_argument(
|
|
32
32
|
"-w",
|
|
33
33
|
"--wakes",
|
|
34
34
|
help="The wake models",
|
|
35
|
-
default=
|
|
35
|
+
default=None,
|
|
36
36
|
nargs="+",
|
|
37
37
|
)
|
|
38
|
-
parser.add_argument("-f", "--frame", help="The wake frame", default=
|
|
38
|
+
parser.add_argument("-f", "--frame", help="The wake frame", default=None)
|
|
39
39
|
parser.add_argument("-e", "--engine", help="The engine", default=None)
|
|
40
40
|
parser.add_argument(
|
|
41
41
|
"-n", "--n_procs", help="The number of processes", default=None, type=int
|
|
@@ -51,7 +51,7 @@ def foxes_yaml():
|
|
|
51
51
|
"-C",
|
|
52
52
|
"--chunksize_points",
|
|
53
53
|
help="The chunk size for points",
|
|
54
|
-
default=
|
|
54
|
+
default=None,
|
|
55
55
|
type=int,
|
|
56
56
|
)
|
|
57
57
|
parser.add_argument(
|
foxes/output/__init__.py
CHANGED
|
@@ -6,7 +6,7 @@ from .round import round_defaults
|
|
|
6
6
|
from .output import Output
|
|
7
7
|
from .farm_layout import FarmLayoutOutput
|
|
8
8
|
from .farm_results_eval import FarmResultsEval
|
|
9
|
-
from .rose_plot import RosePlotOutput, StatesRosePlotOutput
|
|
9
|
+
from .rose_plot import RosePlotOutput, StatesRosePlotOutput, WindRoseBinPlot
|
|
10
10
|
from .results_writer import ResultsWriter
|
|
11
11
|
from .state_turbine_map import StateTurbineMap
|
|
12
12
|
from .turbine_type_curves import TurbineTypeCurves
|
|
@@ -15,6 +15,7 @@ from .calc_points import PointCalculator
|
|
|
15
15
|
from .slice_data import SliceData
|
|
16
16
|
from .rotor_point_plots import RotorPointPlot
|
|
17
17
|
from .state_turbine_table import StateTurbineTable
|
|
18
|
+
from .plt import plt
|
|
18
19
|
|
|
19
20
|
from .flow_plots_2d import FlowPlots2D
|
|
20
21
|
from .seq_plugins import SeqFlowAnimationPlugin, SeqWakeDebugPlugin
|
|
@@ -64,7 +64,12 @@ class FarmResultsEval(Output):
|
|
|
64
64
|
fields = []
|
|
65
65
|
for v in vars:
|
|
66
66
|
if isinstance(v, str):
|
|
67
|
-
|
|
67
|
+
vdata = self.results[v].to_numpy()
|
|
68
|
+
nns = np.sum(np.isnan(vdata))
|
|
69
|
+
assert (
|
|
70
|
+
nns == 0
|
|
71
|
+
), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
|
|
72
|
+
fields.append(vdata)
|
|
68
73
|
else:
|
|
69
74
|
fields.append(v)
|
|
70
75
|
if nas is None:
|
|
@@ -99,7 +104,7 @@ class FarmResultsEval(Output):
|
|
|
99
104
|
vars_op: dict
|
|
100
105
|
The operation per variable. Key: str, the variable
|
|
101
106
|
name. Value: str, the operation, choices
|
|
102
|
-
are:
|
|
107
|
+
are: weights, mean_no_weights, sum, min, max.
|
|
103
108
|
|
|
104
109
|
Returns
|
|
105
110
|
-------
|
|
@@ -111,23 +116,27 @@ class FarmResultsEval(Output):
|
|
|
111
116
|
|
|
112
117
|
rdata = {}
|
|
113
118
|
for v, op in vars_op.items():
|
|
114
|
-
|
|
115
|
-
|
|
119
|
+
vdata = self.results[v].to_numpy()
|
|
120
|
+
nns = np.sum(np.isnan(vdata))
|
|
121
|
+
assert (
|
|
122
|
+
nns == 0
|
|
123
|
+
), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
|
|
124
|
+
|
|
125
|
+
if op == "weights":
|
|
126
|
+
rdata[v] = self.weinsum("t", vdata)
|
|
127
|
+
elif op == "mean_no_weights":
|
|
128
|
+
rdata[v] = np.mean(vdata, axis=0)
|
|
116
129
|
elif op == "sum":
|
|
117
|
-
vdata = self.results[v].to_numpy()
|
|
118
130
|
rdata[v] = np.sum(vdata, axis=0)
|
|
119
131
|
elif op == "min":
|
|
120
|
-
vdata = self.results[v].to_numpy()
|
|
121
132
|
rdata[v] = np.min(vdata, axis=0)
|
|
122
133
|
elif op == "max":
|
|
123
|
-
vdata = self.results[v].to_numpy()
|
|
124
134
|
rdata[v] = np.max(vdata, axis=0)
|
|
125
135
|
elif op == "std":
|
|
126
|
-
vdata = self.results[v].to_numpy()
|
|
127
136
|
rdata[v] = np.std(vdata, axis=0)
|
|
128
137
|
else:
|
|
129
138
|
raise KeyError(
|
|
130
|
-
f"Unknown operation '{op}' for variable '{v}'. Please choose:
|
|
139
|
+
f"Unknown operation '{op}' for variable '{v}'. Please choose: weights, mean_no_weights, sum, min, max"
|
|
131
140
|
)
|
|
132
141
|
|
|
133
142
|
data = pd.DataFrame(index=range(n_turbines), data=rdata)
|
|
@@ -144,7 +153,7 @@ class FarmResultsEval(Output):
|
|
|
144
153
|
vars_op: dict
|
|
145
154
|
The operation per variable. Key: str, the variable
|
|
146
155
|
name. Value: str, the operation, choices
|
|
147
|
-
are:
|
|
156
|
+
are: weights, mean_no_weights, sum, min, max.
|
|
148
157
|
|
|
149
158
|
Returns
|
|
150
159
|
-------
|
|
@@ -156,20 +165,25 @@ class FarmResultsEval(Output):
|
|
|
156
165
|
|
|
157
166
|
rdata = {}
|
|
158
167
|
for v, op in vars_op.items():
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
vdata = self.results[v].to_numpy()
|
|
169
|
+
nns = np.sum(np.isnan(vdata))
|
|
170
|
+
assert (
|
|
171
|
+
nns == 0
|
|
172
|
+
), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
|
|
173
|
+
|
|
174
|
+
if op == "weights":
|
|
175
|
+
rdata[v] = self.weinsum("s", vdata)
|
|
176
|
+
elif op == "mean_no_weights":
|
|
177
|
+
rdata[v] = np.mean(vdata, axis=1)
|
|
161
178
|
elif op == "sum":
|
|
162
|
-
vdata = self.results[v].to_numpy()
|
|
163
179
|
rdata[v] = np.sum(vdata, axis=1)
|
|
164
180
|
elif op == "min":
|
|
165
|
-
vdata = self.results[v].to_numpy()
|
|
166
181
|
rdata[v] = np.min(vdata, axis=1)
|
|
167
182
|
elif op == "max":
|
|
168
|
-
vdata = self.results[v].to_numpy()
|
|
169
183
|
rdata[v] = np.max(vdata, axis=1)
|
|
170
184
|
else:
|
|
171
185
|
raise KeyError(
|
|
172
|
-
f"Unknown operation '{op}' for variable '{v}'. Please choose:
|
|
186
|
+
f"Unknown operation '{op}' for variable '{v}'. Please choose: weights, mean_no_weights, sum, min, max"
|
|
173
187
|
)
|
|
174
188
|
|
|
175
189
|
data = pd.DataFrame(index=states, data=rdata)
|
|
@@ -205,29 +219,32 @@ class FarmResultsEval(Output):
|
|
|
205
219
|
rdata = {}
|
|
206
220
|
for v, op in turbines_op.items():
|
|
207
221
|
vdata = sdata[v].to_numpy()
|
|
208
|
-
|
|
209
|
-
|
|
222
|
+
nns = np.sum(np.isnan(vdata))
|
|
223
|
+
assert (
|
|
224
|
+
nns == 0
|
|
225
|
+
), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
|
|
226
|
+
|
|
227
|
+
if op == "weights":
|
|
228
|
+
if states_op[v] == "weights":
|
|
210
229
|
rdata[v] = self.weinsum("", v)
|
|
211
230
|
else:
|
|
212
|
-
vdata = sdata[v].to_numpy()
|
|
213
231
|
rdata[v] = self.weinsum("", vdata[None, :])
|
|
232
|
+
elif op == "mean_no_weights":
|
|
233
|
+
rdata[v] = np.sum(vdata)
|
|
214
234
|
elif op == "sum":
|
|
215
|
-
vdata = sdata[v].to_numpy()
|
|
216
235
|
rdata[v] = np.sum(vdata)
|
|
217
236
|
elif op == "min":
|
|
218
|
-
vdata = sdata[v].to_numpy()
|
|
219
237
|
rdata[v] = np.min(vdata)
|
|
220
238
|
elif op == "max":
|
|
221
|
-
vdata = sdata[v].to_numpy()
|
|
222
239
|
rdata[v] = np.max(vdata)
|
|
223
240
|
else:
|
|
224
241
|
raise KeyError(
|
|
225
|
-
f"Unknown operation '{op}' for variable '{v}'. Please choose: sum, mean, min, max"
|
|
242
|
+
f"Unknown operation '{op}' for variable '{v}'. Please choose: sum, mean, min, max, weights"
|
|
226
243
|
)
|
|
227
244
|
|
|
228
245
|
return rdata
|
|
229
246
|
|
|
230
|
-
def calc_states_mean(self, vars):
|
|
247
|
+
def calc_states_mean(self, vars, use_weights=True):
|
|
231
248
|
"""
|
|
232
249
|
Calculates the mean wrt states.
|
|
233
250
|
|
|
@@ -235,6 +252,8 @@ class FarmResultsEval(Output):
|
|
|
235
252
|
----------
|
|
236
253
|
vars: list of str
|
|
237
254
|
The variables
|
|
255
|
+
use_weights: bool
|
|
256
|
+
Flag for using states weights for the mean
|
|
238
257
|
|
|
239
258
|
Returns
|
|
240
259
|
-------
|
|
@@ -242,9 +261,10 @@ class FarmResultsEval(Output):
|
|
|
242
261
|
The results per turbine
|
|
243
262
|
|
|
244
263
|
"""
|
|
264
|
+
r = "weights" if use_weights else "mean_no_weights"
|
|
245
265
|
if isinstance(vars, str):
|
|
246
|
-
return self.reduce_states({vars:
|
|
247
|
-
return self.reduce_states({v:
|
|
266
|
+
return self.reduce_states({vars: r})
|
|
267
|
+
return self.reduce_states({v: r for v in vars})
|
|
248
268
|
|
|
249
269
|
def calc_states_sum(self, vars):
|
|
250
270
|
"""
|
|
@@ -291,7 +311,7 @@ class FarmResultsEval(Output):
|
|
|
291
311
|
The results per state
|
|
292
312
|
|
|
293
313
|
"""
|
|
294
|
-
return self.reduce_turbines({v: "
|
|
314
|
+
return self.reduce_turbines({v: "mean_no_weights" for v in vars})
|
|
295
315
|
|
|
296
316
|
def calc_turbine_sum(self, vars):
|
|
297
317
|
"""
|
|
@@ -325,7 +345,7 @@ class FarmResultsEval(Output):
|
|
|
325
345
|
The fully contracted results
|
|
326
346
|
|
|
327
347
|
"""
|
|
328
|
-
op = {v: "
|
|
348
|
+
op = {v: "weights" for v in vars}
|
|
329
349
|
return self.reduce_all(states_op=op, turbines_op=op)
|
|
330
350
|
|
|
331
351
|
def calc_farm_sum(self, vars):
|
|
@@ -362,7 +382,7 @@ class FarmResultsEval(Output):
|
|
|
362
382
|
|
|
363
383
|
"""
|
|
364
384
|
v = FV.P if not ambient else FV.AMB_P
|
|
365
|
-
cdata = self.reduce_all(states_op={v: "
|
|
385
|
+
cdata = self.reduce_all(states_op={v: "weights"}, turbines_op={v: "sum"})
|
|
366
386
|
return cdata[v]
|
|
367
387
|
|
|
368
388
|
def calc_turbine_yield(
|
|
@@ -536,10 +556,12 @@ class FarmResultsEval(Output):
|
|
|
536
556
|
The verbosity level, 0 = silent
|
|
537
557
|
|
|
538
558
|
"""
|
|
539
|
-
P = self.results[FV.P]
|
|
540
|
-
P0 = self.results[FV.AMB_P]
|
|
541
|
-
|
|
542
|
-
|
|
559
|
+
P = self.results[FV.P].to_numpy()
|
|
560
|
+
P0 = np.maximum(self.results[FV.AMB_P].to_numpy(), 1e-12)
|
|
561
|
+
eff = np.minimum(P / P0, 1)
|
|
562
|
+
eff[P < 1e-10] = 0
|
|
563
|
+
self.results[FV.EFF] = (self.results[FV.AMB_P].dims, eff)
|
|
564
|
+
if verbosity > 0:
|
|
543
565
|
print("Efficiency added to farm results")
|
|
544
566
|
|
|
545
567
|
def calc_farm_efficiency(self):
|
|
@@ -553,8 +575,8 @@ class FarmResultsEval(Output):
|
|
|
553
575
|
|
|
554
576
|
"""
|
|
555
577
|
P = self.calc_mean_farm_power()
|
|
556
|
-
P0 = self.calc_mean_farm_power(ambient=True)
|
|
557
|
-
return P / P0
|
|
578
|
+
P0 = np.maximum(self.calc_mean_farm_power(ambient=True), 1e-14)
|
|
579
|
+
return np.minimum(P / P0, 1)
|
|
558
580
|
|
|
559
581
|
def gen_stdata(
|
|
560
582
|
self,
|
foxes/output/output.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
|
|
3
3
|
from foxes.config import config, get_path
|
|
4
|
-
from foxes.utils import PandasFileHelper, all_subclasses
|
|
4
|
+
from foxes.utils import PandasFileHelper, new_instance, all_subclasses
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Output:
|
|
@@ -116,20 +116,4 @@ class Output:
|
|
|
116
116
|
Additional parameters for the constructor
|
|
117
117
|
|
|
118
118
|
"""
|
|
119
|
-
|
|
120
|
-
if output_type is None:
|
|
121
|
-
return None
|
|
122
|
-
|
|
123
|
-
allc = all_subclasses(cls)
|
|
124
|
-
found = output_type in [scls.__name__ for scls in allc]
|
|
125
|
-
|
|
126
|
-
if found:
|
|
127
|
-
for scls in allc:
|
|
128
|
-
if scls.__name__ == output_type:
|
|
129
|
-
return scls(*args, **kwargs)
|
|
130
|
-
|
|
131
|
-
else:
|
|
132
|
-
estr = "Output type '{}' is not defined, available types are \n {}".format(
|
|
133
|
-
output_type, sorted([i.__name__ for i in allc])
|
|
134
|
-
)
|
|
135
|
-
raise KeyError(estr)
|
|
119
|
+
return new_instance(cls, output_type, *args, **kwargs)
|
foxes/output/plt.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from matplotlib import pyplot
|
|
2
|
+
|
|
3
|
+
from .output import Output
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class plt(Output):
|
|
7
|
+
"""
|
|
8
|
+
Class that runs plt commands
|
|
9
|
+
|
|
10
|
+
:group: output
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __getattr__(self, name):
|
|
15
|
+
return getattr(pyplot, name)
|
|
16
|
+
|
|
17
|
+
def savefig(self, fname, *args, **kwargs):
|
|
18
|
+
fpath = super().get_fpath(fname)
|
|
19
|
+
pyplot.savefig(fpath, *args, **kwargs)
|