foxes 1.0__py3-none-any.whl → 1.1.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 +0 -1
- examples/states_lookup_table/run.py +1 -1
- examples/timeseries/run.py +11 -4
- foxes/algorithms/downwind/downwind.py +18 -13
- foxes/algorithms/downwind/models/farm_wakes_calc.py +1 -1
- foxes/algorithms/downwind/models/init_farm_data.py +1 -1
- foxes/algorithms/downwind/models/point_wakes_calc.py +1 -1
- foxes/algorithms/downwind/models/reorder_farm_output.py +1 -1
- foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
- foxes/algorithms/downwind/models/set_amb_point_results.py +1 -1
- foxes/algorithms/iterative/iterative.py +1 -1
- foxes/algorithms/iterative/models/farm_wakes_calc.py +1 -1
- foxes/algorithms/iterative/models/urelax.py +3 -3
- foxes/algorithms/sequential/models/plugin.py +4 -4
- foxes/algorithms/sequential/models/seq_state.py +1 -1
- foxes/constants.py +5 -5
- foxes/core/algorithm.py +2 -2
- foxes/core/data_calc_model.py +2 -2
- foxes/core/engine.py +20 -10
- foxes/core/farm_controller.py +3 -3
- foxes/core/farm_data_model.py +1 -1
- foxes/core/ground_model.py +2 -2
- foxes/core/model.py +122 -108
- foxes/core/partial_wakes_model.py +1 -1
- foxes/core/point_data_model.py +2 -2
- foxes/core/states.py +1 -1
- foxes/core/turbine_type.py +2 -2
- foxes/core/wake_frame.py +8 -30
- foxes/core/wake_model.py +3 -2
- foxes/core/wake_superposition.py +1 -1
- foxes/data/windio/windio_5turbines_timeseries.yaml +9 -15
- foxes/engines/__init__.py +1 -0
- foxes/engines/dask.py +13 -6
- foxes/engines/multiprocess.py +5 -8
- foxes/engines/numpy.py +8 -26
- foxes/engines/pool.py +10 -24
- foxes/engines/ray.py +79 -0
- foxes/engines/single.py +3 -1
- foxes/input/farm_layout/from_json.py +1 -1
- foxes/input/states/__init__.py +1 -0
- foxes/input/states/field_data_nc.py +4 -4
- foxes/input/states/multi_height.py +4 -4
- foxes/input/states/scan_ws.py +1 -1
- foxes/input/states/single.py +1 -1
- foxes/input/states/slice_data_nc.py +681 -0
- foxes/input/states/states_table.py +3 -3
- foxes/input/windio/__init__.py +1 -1
- foxes/input/windio/read_attributes.py +8 -2
- foxes/input/windio/read_fields.py +3 -0
- foxes/input/windio/read_outputs.py +8 -2
- foxes/input/windio/windio.py +6 -2
- foxes/models/farm_models/turbine2farm.py +1 -1
- foxes/models/ground_models/wake_mirror.py +2 -2
- foxes/models/model_book.py +29 -2
- foxes/models/partial_wakes/axiwake.py +3 -3
- foxes/models/partial_wakes/top_hat.py +2 -2
- foxes/models/point_models/set_uniform_data.py +1 -1
- foxes/models/point_models/tke2ti.py +1 -1
- foxes/models/point_models/wake_deltas.py +1 -1
- foxes/models/rotor_models/grid.py +2 -2
- foxes/models/turbine_models/calculator.py +4 -4
- foxes/models/turbine_models/kTI_model.py +22 -6
- foxes/models/turbine_models/lookup_table.py +3 -2
- foxes/models/turbine_types/PCt_file.py +5 -5
- foxes/models/turbine_types/PCt_from_two.py +5 -5
- foxes/models/turbine_types/TBL_file.py +80 -0
- foxes/models/turbine_types/__init__.py +1 -0
- foxes/models/turbine_types/lookup.py +5 -5
- foxes/models/turbine_types/null_type.py +3 -3
- foxes/models/turbine_types/wsrho2PCt_from_two.py +7 -7
- foxes/models/turbine_types/wsti2PCt_from_two.py +9 -9
- foxes/models/vertical_profiles/__init__.py +1 -1
- foxes/models/wake_frames/dynamic_wakes.py +2 -2
- foxes/models/wake_frames/farm_order.py +2 -2
- foxes/models/wake_frames/rotor_wd.py +2 -2
- foxes/models/wake_frames/seq_dynamic_wakes.py +5 -11
- foxes/models/wake_frames/streamlines.py +2 -2
- foxes/models/wake_frames/timelines.py +2 -2
- foxes/models/wake_frames/yawed_wakes.py +3 -3
- foxes/models/wake_models/dist_sliced.py +1 -1
- foxes/models/wake_models/induction/rankine_half_body.py +1 -1
- foxes/models/wake_models/induction/rathmann.py +76 -22
- foxes/models/wake_models/induction/self_similar.py +76 -26
- foxes/models/wake_models/induction/vortex_sheet.py +84 -46
- foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
- foxes/models/wake_models/ti/iec_ti.py +7 -5
- foxes/models/wake_models/wind/bastankhah14.py +6 -4
- foxes/models/wake_models/wind/bastankhah16.py +9 -9
- foxes/models/wake_models/wind/jensen.py +3 -2
- foxes/models/wake_models/wind/turbopark.py +14 -11
- foxes/models/wake_superpositions/ti_linear.py +1 -1
- foxes/models/wake_superpositions/ti_max.py +1 -1
- foxes/models/wake_superpositions/ti_pow.py +1 -1
- foxes/models/wake_superpositions/ti_quadratic.py +1 -1
- foxes/models/wake_superpositions/ws_linear.py +8 -7
- foxes/models/wake_superpositions/ws_max.py +8 -7
- foxes/models/wake_superpositions/ws_pow.py +8 -7
- foxes/models/wake_superpositions/ws_product.py +5 -5
- foxes/models/wake_superpositions/ws_quadratic.py +8 -7
- foxes/output/farm_layout.py +14 -10
- foxes/output/farm_results_eval.py +1 -1
- foxes/output/grids.py +1 -1
- foxes/output/results_writer.py +2 -2
- foxes/output/rose_plot.py +3 -3
- foxes/output/seq_plugins/seq_flow_ani_plugin.py +2 -2
- foxes/output/seq_plugins/seq_wake_debug_plugin.py +2 -2
- foxes/output/state_turbine_map.py +1 -1
- foxes/utils/abl/neutral.py +2 -2
- foxes/utils/abl/stable.py +2 -2
- foxes/utils/abl/unstable.py +2 -2
- foxes/utils/data_book.py +1 -1
- foxes/utils/dict.py +23 -0
- foxes/utils/exec_python.py +1 -1
- foxes/utils/factory.py +29 -1
- foxes/utils/geom2d/circle.py +1 -1
- foxes/utils/geom2d/polygon.py +1 -1
- foxes/utils/geopandas_utils.py +2 -2
- foxes/utils/load.py +2 -2
- foxes/utils/pandas_helpers.py +1 -1
- foxes/utils/xarray_utils.py +1 -1
- foxes/variables.py +3 -3
- {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/METADATA +8 -6
- {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/RECORD +127 -125
- {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/WHEEL +1 -1
- foxes/utils/geopandas_helpers.py +0 -294
- /examples/{induction_RHB → induction}/run.py +0 -0
- {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/LICENSE +0 -0
- {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/top_level.txt +0 -0
foxes/core/model.py
CHANGED
|
@@ -296,6 +296,7 @@ class Model(ABC):
|
|
|
296
296
|
accept_nan=True,
|
|
297
297
|
algo=None,
|
|
298
298
|
upcast=False,
|
|
299
|
+
selection=None,
|
|
299
300
|
):
|
|
300
301
|
"""
|
|
301
302
|
Getter for a data entry in the model object
|
|
@@ -335,6 +336,9 @@ class Model(ABC):
|
|
|
335
336
|
upcast: bool
|
|
336
337
|
Flag for ensuring targets dimension,
|
|
337
338
|
otherwise dimension 1 is entered
|
|
339
|
+
selection: numpy.ndarray, optional
|
|
340
|
+
Apply this selection to the result,
|
|
341
|
+
state-turbine, state-target, or state-target-tpoint
|
|
338
342
|
|
|
339
343
|
"""
|
|
340
344
|
|
|
@@ -358,6 +362,10 @@ class Model(ABC):
|
|
|
358
362
|
|
|
359
363
|
n_states = _geta("n_states")
|
|
360
364
|
if target == FC.STATE_TURBINE:
|
|
365
|
+
if downwind_index is not None:
|
|
366
|
+
raise ValueError(
|
|
367
|
+
f"Target '{target}' is incompatible with downwind_index (here {downwind_index})"
|
|
368
|
+
)
|
|
361
369
|
n_turbines = _geta("n_turbines")
|
|
362
370
|
dims = (FC.STATE, FC.TURBINE)
|
|
363
371
|
shp = (n_states, n_turbines)
|
|
@@ -375,42 +383,49 @@ class Model(ABC):
|
|
|
375
383
|
f"Model '{self.name}': Wrong parameter 'target = {target}'. Choices: {FC.STATE_TURBINE}, {FC.STATE_TARGET}, {FC.STATE_TARGET_TPOINT}"
|
|
376
384
|
)
|
|
377
385
|
|
|
386
|
+
def _match_shape(a):
|
|
387
|
+
out = np.asarray(a)
|
|
388
|
+
if len(out.shape) < len(shp):
|
|
389
|
+
for i, s in enumerate(shp):
|
|
390
|
+
if i >= len(out.shape):
|
|
391
|
+
out = out[..., None]
|
|
392
|
+
elif a.shape[i] not in (1, s):
|
|
393
|
+
raise ValueError(
|
|
394
|
+
f"Shape mismatch for '{variable}': Got {out.shape}, expecting {shp}"
|
|
395
|
+
)
|
|
396
|
+
elif len(out.shape) > len(shp):
|
|
397
|
+
raise ValueError(
|
|
398
|
+
f"Shape mismatch for '{variable}': Got {out.shape}, expecting {shp}"
|
|
399
|
+
)
|
|
400
|
+
return out
|
|
401
|
+
|
|
402
|
+
def _filter_dims(source):
|
|
403
|
+
a = source[variable]
|
|
404
|
+
a_dims = tuple(source.dims[variable])
|
|
405
|
+
if downwind_index is None or FC.TURBINE not in a_dims:
|
|
406
|
+
d = a_dims
|
|
407
|
+
else:
|
|
408
|
+
slc = tuple(
|
|
409
|
+
[downwind_index if dd == FC.TURBINE else np.s_[:] for dd in a_dims]
|
|
410
|
+
)
|
|
411
|
+
a = a[slc]
|
|
412
|
+
d = tuple([dd for dd in a_dims if dd != FC.TURBINE])
|
|
413
|
+
return a, d
|
|
414
|
+
|
|
378
415
|
out = None
|
|
379
|
-
out_dims = None
|
|
380
416
|
for s in lookup:
|
|
381
417
|
# lookup self:
|
|
382
418
|
if s == "s" and hasattr(self, variable):
|
|
383
419
|
a = getattr(self, variable)
|
|
384
420
|
if a is not None:
|
|
385
|
-
|
|
386
|
-
out = a
|
|
387
|
-
out_dims = None
|
|
388
|
-
elif target == FC.STATE_TURBINE:
|
|
389
|
-
out = np.full((n_states, n_turbines), np.nan, dtype=FC.DTYPE)
|
|
390
|
-
out[:] = a
|
|
391
|
-
out_dims = (FC.STATE, FC.TURBINE)
|
|
392
|
-
elif target == FC.STATE_TARGET:
|
|
393
|
-
out = np.full((n_states, n_targets), np.nan, dtype=FC.DTYPE)
|
|
394
|
-
out[:] = a
|
|
395
|
-
out_dims = (FC.STATE, FC.TARGET)
|
|
396
|
-
elif target == FC.STATE_TARGET_TPOINT:
|
|
397
|
-
out = np.full(
|
|
398
|
-
(n_states, n_targets, n_tpoints), np.nan, dtype=FC.DTYPE
|
|
399
|
-
)
|
|
400
|
-
out[:] = a
|
|
401
|
-
out_dims = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
402
|
-
else:
|
|
403
|
-
raise NotImplementedError
|
|
421
|
+
out = _match_shape(a)
|
|
404
422
|
|
|
405
423
|
# lookup mdata:
|
|
406
|
-
elif
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
and
|
|
410
|
-
|
|
411
|
-
):
|
|
412
|
-
out = mdata[variable]
|
|
413
|
-
out_dims = dims
|
|
424
|
+
elif s == "m" and mdata is not None and variable in mdata:
|
|
425
|
+
a, d = _filter_dims(mdata)
|
|
426
|
+
l = len(d)
|
|
427
|
+
if l <= len(dims) and d == dims[:l]:
|
|
428
|
+
out = _match_shape(mdata[variable])
|
|
414
429
|
|
|
415
430
|
# lookup fdata:
|
|
416
431
|
elif (
|
|
@@ -419,18 +434,22 @@ class Model(ABC):
|
|
|
419
434
|
and variable in fdata
|
|
420
435
|
and tuple(fdata.dims[variable]) == (FC.STATE, FC.TURBINE)
|
|
421
436
|
):
|
|
422
|
-
|
|
423
|
-
|
|
437
|
+
if target == FC.STATE_TURBINE:
|
|
438
|
+
out = fdata[variable]
|
|
439
|
+
elif downwind_index is not None:
|
|
440
|
+
out = _match_shape(fdata[variable][:, downwind_index])
|
|
424
441
|
|
|
425
442
|
# lookup pdata:
|
|
426
443
|
elif (
|
|
427
444
|
s == "t"
|
|
445
|
+
and target != FC.STATE_TURBINE
|
|
428
446
|
and tdata is not None
|
|
429
447
|
and variable in tdata
|
|
430
|
-
and tuple(tdata.dims[variable]) == (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
431
448
|
):
|
|
432
|
-
|
|
433
|
-
|
|
449
|
+
a, d = _filter_dims(tdata)
|
|
450
|
+
l = len(d)
|
|
451
|
+
if l <= len(dims) and d == dims[:l]:
|
|
452
|
+
out = _match_shape(tdata[variable])
|
|
434
453
|
|
|
435
454
|
# lookup wake modelling data:
|
|
436
455
|
elif (
|
|
@@ -442,84 +461,27 @@ class Model(ABC):
|
|
|
442
461
|
and downwind_index is not None
|
|
443
462
|
and algo is not None
|
|
444
463
|
):
|
|
445
|
-
out
|
|
446
|
-
algo
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
464
|
+
out = _match_shape(
|
|
465
|
+
algo.wake_frame.get_wake_modelling_data(
|
|
466
|
+
algo,
|
|
467
|
+
variable,
|
|
468
|
+
downwind_index,
|
|
469
|
+
fdata,
|
|
470
|
+
tdata=tdata,
|
|
471
|
+
target=target,
|
|
472
|
+
)
|
|
453
473
|
)
|
|
454
474
|
|
|
455
475
|
if out is not None:
|
|
456
476
|
break
|
|
457
477
|
|
|
458
478
|
# check for None:
|
|
459
|
-
if
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
# cast dimensions:
|
|
465
|
-
if out_dims != dims:
|
|
466
|
-
if out_dims is None:
|
|
467
|
-
if upcast:
|
|
468
|
-
out0 = out
|
|
469
|
-
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
470
|
-
out[:] = out0
|
|
471
|
-
out_dims = dims
|
|
472
|
-
del out0
|
|
473
|
-
else:
|
|
474
|
-
out_dims = tuple([1 for _ in dims])
|
|
475
|
-
|
|
476
|
-
elif out_dims == (FC.STATE, FC.TURBINE):
|
|
477
|
-
if downwind_index is None:
|
|
478
|
-
raise KeyError(
|
|
479
|
-
f"Require downwind_index for target {target} and out dims {out_dims}"
|
|
480
|
-
)
|
|
481
|
-
out0 = out[:, downwind_index, None]
|
|
482
|
-
if len(dims) == 3:
|
|
483
|
-
out0 = out0[:, :, None]
|
|
484
|
-
if upcast:
|
|
485
|
-
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
486
|
-
out[:] = out0
|
|
487
|
-
out_dims = dims
|
|
488
|
-
else:
|
|
489
|
-
out = out0
|
|
490
|
-
out_dims = (FC.STATE, 1) if len(dims) == 2 else (FC.STATE, 1, 1)
|
|
491
|
-
del out0
|
|
492
|
-
|
|
493
|
-
elif out_dims == (FC.STATE, 1):
|
|
494
|
-
out0 = out
|
|
495
|
-
if len(dims) == 3:
|
|
496
|
-
out0 = out0[:, :, None]
|
|
497
|
-
out_dims = (FC.STATE, 1, 1)
|
|
498
|
-
if upcast:
|
|
499
|
-
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
500
|
-
out[:] = out0
|
|
501
|
-
out_dims = dims
|
|
502
|
-
else:
|
|
503
|
-
out = out0
|
|
504
|
-
del out0
|
|
505
|
-
|
|
506
|
-
elif out_dims == (FC.STATE, 1, 1):
|
|
507
|
-
out0 = out
|
|
508
|
-
if len(dims) == 2:
|
|
509
|
-
out0 = out0[:, :, 0]
|
|
510
|
-
out_dims = (FC.STATE, 1)
|
|
511
|
-
if upcast:
|
|
512
|
-
out = np.zeros(shp, dtype=FC.DTYPE)
|
|
513
|
-
out[:] = out0
|
|
514
|
-
out_dims = dims
|
|
515
|
-
else:
|
|
516
|
-
out = out0
|
|
517
|
-
del out0
|
|
518
|
-
|
|
519
|
-
else:
|
|
520
|
-
raise NotImplementedError(
|
|
521
|
-
f"No casting implemented for target {target} and out dims {out_dims} fo upcast {upcast}"
|
|
479
|
+
if out is None:
|
|
480
|
+
if not accept_none:
|
|
481
|
+
raise ValueError(
|
|
482
|
+
f"Model '{self.name}': Variable '{variable}' is requested but not found."
|
|
522
483
|
)
|
|
484
|
+
return out
|
|
523
485
|
|
|
524
486
|
# data from other chunks, only with iterations:
|
|
525
487
|
if (
|
|
@@ -529,10 +491,14 @@ class Model(ABC):
|
|
|
529
491
|
and tdata is not None
|
|
530
492
|
and FC.STATES_SEL in tdata
|
|
531
493
|
):
|
|
532
|
-
if
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
494
|
+
if out.shape != shp:
|
|
495
|
+
# upcast to dims:
|
|
496
|
+
tmp = np.zeros(shp, dtype=out.dtype)
|
|
497
|
+
tmp[:] = out
|
|
498
|
+
out = tmp
|
|
499
|
+
del tmp
|
|
500
|
+
else:
|
|
501
|
+
out = out.copy()
|
|
536
502
|
if downwind_index is None:
|
|
537
503
|
raise KeyError(
|
|
538
504
|
f"Model '{self.name}': Require downwind_index for obtaining results from previous iteration"
|
|
@@ -592,4 +558,52 @@ class Model(ABC):
|
|
|
592
558
|
except TypeError:
|
|
593
559
|
pass
|
|
594
560
|
|
|
561
|
+
# apply selection:
|
|
562
|
+
if selection is not None:
|
|
563
|
+
|
|
564
|
+
def _upcast_sel(sel_shape):
|
|
565
|
+
chp = []
|
|
566
|
+
for i, s in enumerate(out.shape):
|
|
567
|
+
if i < len(sel_shape) and sel_shape[i] > 1:
|
|
568
|
+
if sel_shape[i] != shp[i]:
|
|
569
|
+
raise ValueError(
|
|
570
|
+
f"Incompatible selection shape {sel_shape} for output shape {shp[i]}"
|
|
571
|
+
)
|
|
572
|
+
chp.append(shp[i])
|
|
573
|
+
else:
|
|
574
|
+
chp.append(s)
|
|
575
|
+
chp = tuple(chp)
|
|
576
|
+
eshp = list(shp[len(sel_shape) :])
|
|
577
|
+
if chp != out.shape:
|
|
578
|
+
nout = np.zeros(chp, dtype=out.dtype)
|
|
579
|
+
nout[:] = out
|
|
580
|
+
return nout, eshp
|
|
581
|
+
return out, eshp
|
|
582
|
+
|
|
583
|
+
if isinstance(selection, np.ndarray) and selection.dtype == bool:
|
|
584
|
+
if len(selection.shape) > len(out.shape):
|
|
585
|
+
raise ValueError(
|
|
586
|
+
f"Expecting selection of shape {out.shape}, got {selection.shape}"
|
|
587
|
+
)
|
|
588
|
+
out, eshp = _upcast_sel(selection.shape)
|
|
589
|
+
elif isinstance(selection, (tuple, list)):
|
|
590
|
+
if len(selection) > len(out.shape):
|
|
591
|
+
raise ValueError(
|
|
592
|
+
f"Selection is tuple/list of length {len(selection)}, expecting <= {len(out.shape)} "
|
|
593
|
+
)
|
|
594
|
+
out, eshp = _upcast_sel(shp[: len(selection)])
|
|
595
|
+
else:
|
|
596
|
+
raise TypeError(
|
|
597
|
+
f"Expecting selection of type np.ndarray (bool), or tuple, or list. Got {type(selection).__name__}"
|
|
598
|
+
)
|
|
599
|
+
out = out[selection]
|
|
600
|
+
shp = tuple([len(out)] + list(eshp))
|
|
601
|
+
|
|
602
|
+
# apply upcast:
|
|
603
|
+
if upcast and out.shape != shp:
|
|
604
|
+
tmp = np.zeros(shp, dtype=out.dtype)
|
|
605
|
+
tmp[:] = out
|
|
606
|
+
out = tmp
|
|
607
|
+
del tmp
|
|
608
|
+
|
|
595
609
|
return out
|
|
@@ -121,7 +121,7 @@ class PartialWakesModel(Model):
|
|
|
121
121
|
The target point data
|
|
122
122
|
downwind_index: int
|
|
123
123
|
The index of the wake causing turbine
|
|
124
|
-
in the
|
|
124
|
+
in the downwind order
|
|
125
125
|
wake_deltas: dict
|
|
126
126
|
The wake deltas. Key: variable name,
|
|
127
127
|
value: numpy.ndarray with shape
|
foxes/core/point_data_model.py
CHANGED
|
@@ -66,7 +66,7 @@ class PointDataModel(DataCalcModel):
|
|
|
66
66
|
|
|
67
67
|
@abstractmethod
|
|
68
68
|
def calculate(self, algo, mdata, fdata, tdata):
|
|
69
|
-
"""
|
|
69
|
+
"""
|
|
70
70
|
The main model calculation.
|
|
71
71
|
|
|
72
72
|
This function is executed on a single chunk of data,
|
|
@@ -218,7 +218,7 @@ class PointDataModelList(PointDataModel):
|
|
|
218
218
|
return list(dict.fromkeys(ovars))
|
|
219
219
|
|
|
220
220
|
def calculate(self, algo, mdata, fdata, tdata, parameters=None):
|
|
221
|
-
"""
|
|
221
|
+
"""
|
|
222
222
|
The main model calculation.
|
|
223
223
|
|
|
224
224
|
This function is executed on a single chunk of data,
|
foxes/core/states.py
CHANGED
foxes/core/turbine_type.py
CHANGED
|
@@ -69,7 +69,7 @@ class TurbineType(TurbineModel):
|
|
|
69
69
|
@abstractmethod
|
|
70
70
|
def needs_rews2(self):
|
|
71
71
|
"""
|
|
72
|
-
Returns flag for
|
|
72
|
+
Returns flag for requiring REWS2 variable
|
|
73
73
|
|
|
74
74
|
Returns
|
|
75
75
|
-------
|
|
@@ -82,7 +82,7 @@ class TurbineType(TurbineModel):
|
|
|
82
82
|
@abstractmethod
|
|
83
83
|
def needs_rews3(self):
|
|
84
84
|
"""
|
|
85
|
-
Returns flag for
|
|
85
|
+
Returns flag for requiring REWS3 variable
|
|
86
86
|
|
|
87
87
|
Returns
|
|
88
88
|
-------
|
foxes/core/wake_frame.py
CHANGED
|
@@ -45,7 +45,7 @@ class WakeFrame(Model):
|
|
|
45
45
|
|
|
46
46
|
@abstractmethod
|
|
47
47
|
def calc_order(self, algo, mdata, fdata):
|
|
48
|
-
"""
|
|
48
|
+
"""
|
|
49
49
|
Calculates the order of turbine evaluation.
|
|
50
50
|
|
|
51
51
|
This function is executed on a single chunk of data,
|
|
@@ -92,7 +92,7 @@ class WakeFrame(Model):
|
|
|
92
92
|
The target point data
|
|
93
93
|
downwind_index: int
|
|
94
94
|
The index of the wake causing turbine
|
|
95
|
-
in the
|
|
95
|
+
in the downwind order
|
|
96
96
|
|
|
97
97
|
Returns
|
|
98
98
|
-------
|
|
@@ -112,7 +112,6 @@ class WakeFrame(Model):
|
|
|
112
112
|
tdata,
|
|
113
113
|
target,
|
|
114
114
|
states0=None,
|
|
115
|
-
upcast=False,
|
|
116
115
|
):
|
|
117
116
|
"""
|
|
118
117
|
Return data that is required for computing the
|
|
@@ -136,47 +135,26 @@ class WakeFrame(Model):
|
|
|
136
135
|
FC.STATE_TARGET_TPOINT
|
|
137
136
|
states0: numpy.ndarray, optional
|
|
138
137
|
The states of wake creation
|
|
139
|
-
upcast: bool
|
|
140
|
-
Flag for ensuring targets dimension,
|
|
141
|
-
otherwise dimension 1 is entered
|
|
142
138
|
|
|
143
139
|
Returns
|
|
144
140
|
-------
|
|
145
141
|
data: numpy.ndarray
|
|
146
142
|
Data for wake modelling, shape:
|
|
147
143
|
(n_states, n_turbines) or (n_states, n_target)
|
|
148
|
-
dims: tuple
|
|
149
|
-
The data dimensions
|
|
150
144
|
|
|
151
145
|
"""
|
|
152
|
-
n_states = fdata.n_states
|
|
153
146
|
s = np.s_[:] if states0 is None else states0
|
|
154
147
|
|
|
155
|
-
if
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
else:
|
|
160
|
-
out = fdata[variable][s, downwind_index, None]
|
|
161
|
-
dims = (FC.STATE, 1)
|
|
162
|
-
elif target == FC.STATE_TURBINE:
|
|
163
|
-
out = np.zeros((n_states, fdata.n_turbines), dtype=FC.DTYPE)
|
|
164
|
-
out[:] = fdata[variable][s, downwind_index, None]
|
|
165
|
-
dims = (FC.STATE, FC.TURBINE)
|
|
166
|
-
elif target == FC.STATE_TARGET:
|
|
167
|
-
out = np.zeros((n_states, tdata.n_targets), dtype=FC.DTYPE)
|
|
168
|
-
out[:] = fdata[variable][s, downwind_index, None]
|
|
169
|
-
dims = (FC.STATE, FC.TARGET)
|
|
170
|
-
elif target == FC.STATE_TARGET_TPOINT:
|
|
171
|
-
out = np.zeros((n_states, tdata.n_targets, tdata.n_tpoints), dtype=FC.DTYPE)
|
|
172
|
-
out[:] = fdata[variable][s, downwind_index, None, None]
|
|
173
|
-
dims = (FC.STATE, FC.TARGET, FC.TPOINT)
|
|
148
|
+
if target == FC.STATE_TARGET_TPOINT:
|
|
149
|
+
out = fdata[variable][s, downwind_index, None, None]
|
|
150
|
+
elif target in [FC.STATE_TURBINE, FC.STATE_TARGET]:
|
|
151
|
+
out = fdata[variable][s, downwind_index, None]
|
|
174
152
|
else:
|
|
175
153
|
raise ValueError(
|
|
176
|
-
f"
|
|
154
|
+
f"Unkown target '{target}', choices are {FC.STATE_TURBINE}, {FC.STATE_TARGET}, {FC.STATE_TARGET_TPOINT}"
|
|
177
155
|
)
|
|
178
156
|
|
|
179
|
-
return out
|
|
157
|
+
return out
|
|
180
158
|
|
|
181
159
|
def get_centreline_points(self, algo, mdata, fdata, downwind_index, x):
|
|
182
160
|
"""
|
foxes/core/wake_model.py
CHANGED
|
@@ -81,7 +81,7 @@ class WakeModel(Model):
|
|
|
81
81
|
The target point data
|
|
82
82
|
downwind_index: int
|
|
83
83
|
The index of the wake causing turbine
|
|
84
|
-
in the
|
|
84
|
+
in the downwind order
|
|
85
85
|
wake_coos: numpy.ndarray
|
|
86
86
|
The wake frame coordinates of the evaluation
|
|
87
87
|
points, shape: (n_states, n_targets, n_tpoints, 3)
|
|
@@ -304,6 +304,7 @@ class WakeK(Model):
|
|
|
304
304
|
The k array as returned by get_data
|
|
305
305
|
|
|
306
306
|
"""
|
|
307
|
+
sel = kwargs.pop("selection", None)
|
|
307
308
|
setattr(self, self.k_var, self._k)
|
|
308
309
|
if self._ka is not None or self._kb is not None:
|
|
309
310
|
if self.ti_var == FV.TI and ti is not None:
|
|
@@ -315,6 +316,6 @@ class WakeK(Model):
|
|
|
315
316
|
kb = 0 if self._kb is None else self._kb
|
|
316
317
|
setattr(self, self.k_var, self._ka * ti + kb)
|
|
317
318
|
|
|
318
|
-
k = self.get_data(self.k_var, *args, lookup=lookup_k, **kwargs)
|
|
319
|
+
k = self.get_data(self.k_var, *args, lookup=lookup_k, selection=sel, **kwargs)
|
|
319
320
|
setattr(self, self.k_var, None)
|
|
320
321
|
return k
|
foxes/core/wake_superposition.py
CHANGED
|
@@ -45,7 +45,7 @@ class WakeSuperposition(Model):
|
|
|
45
45
|
The target point data
|
|
46
46
|
downwind_index: int
|
|
47
47
|
The index of the wake causing turbine
|
|
48
|
-
in the
|
|
48
|
+
in the downwind order
|
|
49
49
|
st_sel: numpy.ndarray of bool
|
|
50
50
|
The selection of targets, shape: (n_states, n_targets)
|
|
51
51
|
variable: str
|
|
@@ -14,10 +14,9 @@ site:
|
|
|
14
14
|
wind_farm:
|
|
15
15
|
name: One row with 5 turbines
|
|
16
16
|
layouts:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
y: [0, 600, 1150, 1730, 2400]
|
|
17
|
+
- coordinates:
|
|
18
|
+
x: [0, 0, 0, 0, 0]
|
|
19
|
+
y: [0, 600, 1150, 1730, 2400]
|
|
21
20
|
turbines: !include DTU_10MW_turbine.yaml
|
|
22
21
|
|
|
23
22
|
attributes:
|
|
@@ -26,36 +25,31 @@ attributes:
|
|
|
26
25
|
|
|
27
26
|
analysis:
|
|
28
27
|
|
|
28
|
+
#pywake and foxes
|
|
29
29
|
wind_deficit_model:
|
|
30
30
|
name: Bastankhah2014
|
|
31
31
|
wake_expansion_coefficient: # k = ka*ti + kb
|
|
32
|
-
k_a: 0.
|
|
33
|
-
k_b: 0.
|
|
32
|
+
k_a: 0.0
|
|
33
|
+
k_b: 0.04
|
|
34
34
|
free_stream_ti: false
|
|
35
35
|
ceps: 0.2
|
|
36
36
|
use_effective_ws: true
|
|
37
|
-
|
|
38
37
|
axial_induction_model: Madsen
|
|
39
|
-
|
|
40
38
|
deflection_model:
|
|
41
39
|
name: None
|
|
42
|
-
|
|
43
40
|
turbulence_model:
|
|
44
41
|
name: CrespoHernandez
|
|
45
|
-
|
|
46
42
|
superposition_model:
|
|
47
43
|
ws_superposition: Linear
|
|
48
44
|
ti_superposition: Quadratic
|
|
49
|
-
|
|
50
45
|
rotor_averaging:
|
|
51
46
|
grid: grid
|
|
52
47
|
n_x_grid_points: 4
|
|
53
48
|
n_y_grid_points: 4
|
|
54
|
-
background_averaging:
|
|
55
|
-
wake_averaging:
|
|
49
|
+
background_averaging: center
|
|
50
|
+
wake_averaging: centre
|
|
56
51
|
wind_speed_exponent_for_power: 3
|
|
57
52
|
wind_speed_exponent_for_ct: 2
|
|
58
|
-
|
|
59
53
|
blockage_model:
|
|
60
54
|
name: None
|
|
61
55
|
|
|
@@ -66,7 +60,7 @@ attributes:
|
|
|
66
60
|
output_variables: ['power', 'rotor_effective_velocity'] #'frequency'
|
|
67
61
|
#
|
|
68
62
|
flow_field:
|
|
69
|
-
report:
|
|
63
|
+
report: False
|
|
70
64
|
flow_nc_filename: flow_field.nc
|
|
71
65
|
cases_run:
|
|
72
66
|
all_occurences: True
|
foxes/engines/__init__.py
CHANGED
foxes/engines/dask.py
CHANGED
|
@@ -8,6 +8,9 @@ from foxes.utils import import_module
|
|
|
8
8
|
import foxes.variables as FV
|
|
9
9
|
import foxes.constants as FC
|
|
10
10
|
|
|
11
|
+
dask = None
|
|
12
|
+
distributed = None
|
|
13
|
+
|
|
11
14
|
|
|
12
15
|
def delayed(func):
|
|
13
16
|
"""A dummy decorator"""
|
|
@@ -17,15 +20,19 @@ def delayed(func):
|
|
|
17
20
|
def load_dask():
|
|
18
21
|
"""On-demand loading of the dask package"""
|
|
19
22
|
global dask, ProgressBar, delayed
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
if dask is None:
|
|
24
|
+
dask = import_module("dask", hint="pip install dask")
|
|
25
|
+
ProgressBar = import_module(
|
|
26
|
+
"dask.diagnostics", hint="pip install dask"
|
|
27
|
+
).ProgressBar
|
|
28
|
+
delayed = dask.delayed
|
|
23
29
|
|
|
24
30
|
|
|
25
31
|
def load_distributed():
|
|
26
32
|
"""On-demand loading of the distributed package"""
|
|
27
33
|
global distributed
|
|
28
|
-
|
|
34
|
+
if distributed is None:
|
|
35
|
+
distributed = import_module("distributed", hint="pip install distributed")
|
|
29
36
|
|
|
30
37
|
|
|
31
38
|
class DaskBaseEngine(Engine):
|
|
@@ -337,13 +344,13 @@ class XArrayEngine(DaskBaseEngine):
|
|
|
337
344
|
chunk_size_points0 = self.chunk_size_points
|
|
338
345
|
n_states = model_data.sizes[FC.STATE]
|
|
339
346
|
n_targets = point_data.sizes[FC.TARGET] if point_data is not None else 0
|
|
340
|
-
|
|
347
|
+
chunk_sizes_states, chunk_sizes_targets = self.calc_chunk_sizes(
|
|
341
348
|
n_states, n_targets
|
|
342
349
|
)
|
|
343
350
|
self.chunk_size_states = np.min(chunk_sizes_states)
|
|
344
351
|
self.chunk_size_points = np.min(chunk_sizes_targets)
|
|
345
352
|
self.print(
|
|
346
|
-
f"Selecting chunk_size_states = {self.chunk_size_states}, chunk_size_points = {self.chunk_size_points}"
|
|
353
|
+
f"{type(self).__name__}: Selecting chunk_size_states = {self.chunk_size_states}, chunk_size_points = {self.chunk_size_points}"
|
|
347
354
|
) # , level=2)
|
|
348
355
|
|
|
349
356
|
# prepare:
|
foxes/engines/multiprocess.py
CHANGED
|
@@ -2,11 +2,14 @@ from foxes.utils import import_module
|
|
|
2
2
|
|
|
3
3
|
from .pool import PoolEngine
|
|
4
4
|
|
|
5
|
+
Pool = None
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def load_multiprocess():
|
|
7
9
|
"""On-demand loading of the multiprocess package"""
|
|
8
10
|
global Pool
|
|
9
|
-
Pool
|
|
11
|
+
if Pool is None:
|
|
12
|
+
Pool = import_module("multiprocess", hint="pip install multiprocess").Pool
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
class MultiprocessEngine(PoolEngine):
|
|
@@ -17,15 +20,9 @@ class MultiprocessEngine(PoolEngine):
|
|
|
17
20
|
|
|
18
21
|
"""
|
|
19
22
|
|
|
20
|
-
def initialize(self):
|
|
21
|
-
"""
|
|
22
|
-
Initializes the engine.
|
|
23
|
-
"""
|
|
24
|
-
load_multiprocess()
|
|
25
|
-
super().initialize()
|
|
26
|
-
|
|
27
23
|
def _create_pool(self):
|
|
28
24
|
"""Creates the pool"""
|
|
25
|
+
load_multiprocess()
|
|
29
26
|
self._pool = Pool(processes=self.n_procs)
|
|
30
27
|
|
|
31
28
|
def _submit(self, f, *args, **kwargs):
|