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.

Files changed (128) hide show
  1. docs/source/conf.py +0 -1
  2. examples/states_lookup_table/run.py +1 -1
  3. examples/timeseries/run.py +11 -4
  4. foxes/algorithms/downwind/downwind.py +18 -13
  5. foxes/algorithms/downwind/models/farm_wakes_calc.py +1 -1
  6. foxes/algorithms/downwind/models/init_farm_data.py +1 -1
  7. foxes/algorithms/downwind/models/point_wakes_calc.py +1 -1
  8. foxes/algorithms/downwind/models/reorder_farm_output.py +1 -1
  9. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  10. foxes/algorithms/downwind/models/set_amb_point_results.py +1 -1
  11. foxes/algorithms/iterative/iterative.py +1 -1
  12. foxes/algorithms/iterative/models/farm_wakes_calc.py +1 -1
  13. foxes/algorithms/iterative/models/urelax.py +3 -3
  14. foxes/algorithms/sequential/models/plugin.py +4 -4
  15. foxes/algorithms/sequential/models/seq_state.py +1 -1
  16. foxes/constants.py +5 -5
  17. foxes/core/algorithm.py +2 -2
  18. foxes/core/data_calc_model.py +2 -2
  19. foxes/core/engine.py +20 -10
  20. foxes/core/farm_controller.py +3 -3
  21. foxes/core/farm_data_model.py +1 -1
  22. foxes/core/ground_model.py +2 -2
  23. foxes/core/model.py +122 -108
  24. foxes/core/partial_wakes_model.py +1 -1
  25. foxes/core/point_data_model.py +2 -2
  26. foxes/core/states.py +1 -1
  27. foxes/core/turbine_type.py +2 -2
  28. foxes/core/wake_frame.py +8 -30
  29. foxes/core/wake_model.py +3 -2
  30. foxes/core/wake_superposition.py +1 -1
  31. foxes/data/windio/windio_5turbines_timeseries.yaml +9 -15
  32. foxes/engines/__init__.py +1 -0
  33. foxes/engines/dask.py +13 -6
  34. foxes/engines/multiprocess.py +5 -8
  35. foxes/engines/numpy.py +8 -26
  36. foxes/engines/pool.py +10 -24
  37. foxes/engines/ray.py +79 -0
  38. foxes/engines/single.py +3 -1
  39. foxes/input/farm_layout/from_json.py +1 -1
  40. foxes/input/states/__init__.py +1 -0
  41. foxes/input/states/field_data_nc.py +4 -4
  42. foxes/input/states/multi_height.py +4 -4
  43. foxes/input/states/scan_ws.py +1 -1
  44. foxes/input/states/single.py +1 -1
  45. foxes/input/states/slice_data_nc.py +681 -0
  46. foxes/input/states/states_table.py +3 -3
  47. foxes/input/windio/__init__.py +1 -1
  48. foxes/input/windio/read_attributes.py +8 -2
  49. foxes/input/windio/read_fields.py +3 -0
  50. foxes/input/windio/read_outputs.py +8 -2
  51. foxes/input/windio/windio.py +6 -2
  52. foxes/models/farm_models/turbine2farm.py +1 -1
  53. foxes/models/ground_models/wake_mirror.py +2 -2
  54. foxes/models/model_book.py +29 -2
  55. foxes/models/partial_wakes/axiwake.py +3 -3
  56. foxes/models/partial_wakes/top_hat.py +2 -2
  57. foxes/models/point_models/set_uniform_data.py +1 -1
  58. foxes/models/point_models/tke2ti.py +1 -1
  59. foxes/models/point_models/wake_deltas.py +1 -1
  60. foxes/models/rotor_models/grid.py +2 -2
  61. foxes/models/turbine_models/calculator.py +4 -4
  62. foxes/models/turbine_models/kTI_model.py +22 -6
  63. foxes/models/turbine_models/lookup_table.py +3 -2
  64. foxes/models/turbine_types/PCt_file.py +5 -5
  65. foxes/models/turbine_types/PCt_from_two.py +5 -5
  66. foxes/models/turbine_types/TBL_file.py +80 -0
  67. foxes/models/turbine_types/__init__.py +1 -0
  68. foxes/models/turbine_types/lookup.py +5 -5
  69. foxes/models/turbine_types/null_type.py +3 -3
  70. foxes/models/turbine_types/wsrho2PCt_from_two.py +7 -7
  71. foxes/models/turbine_types/wsti2PCt_from_two.py +9 -9
  72. foxes/models/vertical_profiles/__init__.py +1 -1
  73. foxes/models/wake_frames/dynamic_wakes.py +2 -2
  74. foxes/models/wake_frames/farm_order.py +2 -2
  75. foxes/models/wake_frames/rotor_wd.py +2 -2
  76. foxes/models/wake_frames/seq_dynamic_wakes.py +5 -11
  77. foxes/models/wake_frames/streamlines.py +2 -2
  78. foxes/models/wake_frames/timelines.py +2 -2
  79. foxes/models/wake_frames/yawed_wakes.py +3 -3
  80. foxes/models/wake_models/dist_sliced.py +1 -1
  81. foxes/models/wake_models/induction/rankine_half_body.py +1 -1
  82. foxes/models/wake_models/induction/rathmann.py +76 -22
  83. foxes/models/wake_models/induction/self_similar.py +76 -26
  84. foxes/models/wake_models/induction/vortex_sheet.py +84 -46
  85. foxes/models/wake_models/ti/crespo_hernandez.py +6 -4
  86. foxes/models/wake_models/ti/iec_ti.py +7 -5
  87. foxes/models/wake_models/wind/bastankhah14.py +6 -4
  88. foxes/models/wake_models/wind/bastankhah16.py +9 -9
  89. foxes/models/wake_models/wind/jensen.py +3 -2
  90. foxes/models/wake_models/wind/turbopark.py +14 -11
  91. foxes/models/wake_superpositions/ti_linear.py +1 -1
  92. foxes/models/wake_superpositions/ti_max.py +1 -1
  93. foxes/models/wake_superpositions/ti_pow.py +1 -1
  94. foxes/models/wake_superpositions/ti_quadratic.py +1 -1
  95. foxes/models/wake_superpositions/ws_linear.py +8 -7
  96. foxes/models/wake_superpositions/ws_max.py +8 -7
  97. foxes/models/wake_superpositions/ws_pow.py +8 -7
  98. foxes/models/wake_superpositions/ws_product.py +5 -5
  99. foxes/models/wake_superpositions/ws_quadratic.py +8 -7
  100. foxes/output/farm_layout.py +14 -10
  101. foxes/output/farm_results_eval.py +1 -1
  102. foxes/output/grids.py +1 -1
  103. foxes/output/results_writer.py +2 -2
  104. foxes/output/rose_plot.py +3 -3
  105. foxes/output/seq_plugins/seq_flow_ani_plugin.py +2 -2
  106. foxes/output/seq_plugins/seq_wake_debug_plugin.py +2 -2
  107. foxes/output/state_turbine_map.py +1 -1
  108. foxes/utils/abl/neutral.py +2 -2
  109. foxes/utils/abl/stable.py +2 -2
  110. foxes/utils/abl/unstable.py +2 -2
  111. foxes/utils/data_book.py +1 -1
  112. foxes/utils/dict.py +23 -0
  113. foxes/utils/exec_python.py +1 -1
  114. foxes/utils/factory.py +29 -1
  115. foxes/utils/geom2d/circle.py +1 -1
  116. foxes/utils/geom2d/polygon.py +1 -1
  117. foxes/utils/geopandas_utils.py +2 -2
  118. foxes/utils/load.py +2 -2
  119. foxes/utils/pandas_helpers.py +1 -1
  120. foxes/utils/xarray_utils.py +1 -1
  121. foxes/variables.py +3 -3
  122. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/METADATA +8 -6
  123. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/RECORD +127 -125
  124. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/WHEEL +1 -1
  125. foxes/utils/geopandas_helpers.py +0 -294
  126. /examples/{induction_RHB → induction}/run.py +0 -0
  127. {foxes-1.0.dist-info → foxes-1.1.1.dist-info}/LICENSE +0 -0
  128. {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
- if not upcast:
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
- s == "m"
408
- and mdata is not None
409
- and variable in mdata
410
- and tuple(mdata.dims[variable]) == dims
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
- out = fdata[variable]
423
- out_dims = (FC.STATE, FC.TURBINE)
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
- out = tdata[variable]
433
- out_dims = (FC.STATE, FC.TARGET, FC.TPOINT)
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, out_dims = algo.wake_frame.get_wake_modelling_data(
446
- algo,
447
- variable,
448
- downwind_index,
449
- fdata,
450
- tdata=tdata,
451
- target=target,
452
- upcast=upcast,
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 not accept_none and out is None:
460
- raise ValueError(
461
- f"Model '{self.name}': Variable '{variable}' is requested but not found."
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 out_dims != dims:
533
- raise ValueError(
534
- f"Model '{self.name}': Iteration data found for variable '{variable}', but missing upcast: out_dims = {out_dims}, expecting {dims}"
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 downwnd order
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
@@ -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
@@ -295,7 +295,7 @@ class ExtendedStates(States):
295
295
  return self.states.output_point_vars(algo)
296
296
 
297
297
  def calculate(self, algo, mdata, fdata, tdata):
298
- """ "
298
+ """
299
299
  The main model calculation.
300
300
 
301
301
  This function is executed on a single chunk of data,
@@ -69,7 +69,7 @@ class TurbineType(TurbineModel):
69
69
  @abstractmethod
70
70
  def needs_rews2(self):
71
71
  """
72
- Returns flag for requirering REWS2 variable
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 requirering REWS3 variable
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 downwnd order
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 not upcast:
156
- if target == FC.STATE_TARGET_TPOINT:
157
- out = fdata[variable][s, downwind_index, None, None]
158
- dims = (FC.STATE, 1, 1)
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"Unsupported target '{target}', expcting '{FC.STATE_TURBINE}', '{FC.STATE_TARGET}', {FC.STATE_TARGET_TPOINT}"
154
+ f"Unkown target '{target}', choices are {FC.STATE_TURBINE}, {FC.STATE_TARGET}, {FC.STATE_TARGET_TPOINT}"
177
155
  )
178
156
 
179
- return out, dims
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 downwnd order
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
@@ -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 downwnd order
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
- initial_layout:
18
- coordinates:
19
- x: [0, 0, 0, 0, 0]
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.04
33
- k_b: 0.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: grid
55
- wake_averaging: axiwake9
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: True
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
@@ -4,6 +4,7 @@ from .numpy import NumpyEngine
4
4
  from .single import SingleChunkEngine
5
5
  from .futures import ThreadsEngine, ProcessEngine
6
6
  from .mpi import MPIEngine
7
+ from .ray import RayEngine
7
8
 
8
9
  from .dask import (
9
10
  DaskBaseEngine,
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
- dask = import_module("dask", hint="pip install dask")
21
- ProgressBar = import_module("dask.diagnostics", hint="pip install dask").ProgressBar
22
- delayed = dask.delayed
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
- distributed = import_module("distributed", hint="pip install distributed")
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
- __, chunk_sizes_states, chunk_sizes_targets = self.calc_chunk_sizes(
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:
@@ -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 = import_module("multiprocess", hint="pip install multiprocess").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):