foxes 1.2.5__py3-none-any.whl → 1.4__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 (201) hide show
  1. docs/source/conf.py +3 -3
  2. examples/abl_states/run.py +2 -2
  3. examples/compare_rotors_pwakes/run.py +1 -1
  4. examples/compare_wakes/run.py +1 -2
  5. examples/dyn_wakes/run.py +29 -6
  6. examples/induction/run.py +3 -3
  7. examples/multi_height/run.py +1 -1
  8. examples/power_mask/run.py +2 -2
  9. examples/quickstart/run.py +16 -0
  10. examples/random_timeseries/run.py +3 -4
  11. examples/scan_row/run.py +3 -3
  12. examples/sequential/run.py +33 -10
  13. examples/single_state/run.py +3 -4
  14. examples/states_lookup_table/run.py +3 -3
  15. examples/streamline_wakes/run.py +27 -4
  16. examples/tab_file/run.py +3 -3
  17. examples/timelines/run.py +29 -5
  18. examples/timeseries/run.py +3 -3
  19. examples/timeseries_slurm/run.py +3 -3
  20. examples/wind_rose/run.py +3 -3
  21. examples/yawed_wake/run.py +16 -8
  22. foxes/__init__.py +22 -18
  23. foxes/algorithms/__init__.py +6 -6
  24. foxes/algorithms/downwind/__init__.py +2 -2
  25. foxes/algorithms/downwind/downwind.py +53 -27
  26. foxes/algorithms/downwind/models/__init__.py +6 -6
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +22 -14
  28. foxes/algorithms/downwind/models/init_farm_data.py +4 -5
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
  31. foxes/algorithms/downwind/models/set_amb_point_results.py +7 -7
  32. foxes/algorithms/iterative/__init__.py +7 -3
  33. foxes/algorithms/iterative/iterative.py +1 -2
  34. foxes/algorithms/iterative/models/__init__.py +7 -3
  35. foxes/algorithms/iterative/models/farm_wakes_calc.py +15 -8
  36. foxes/algorithms/sequential/__init__.py +3 -3
  37. foxes/algorithms/sequential/models/__init__.py +2 -2
  38. foxes/algorithms/sequential/models/seq_state.py +0 -18
  39. foxes/algorithms/sequential/sequential.py +8 -22
  40. foxes/config/__init__.py +5 -1
  41. foxes/constants.py +22 -0
  42. foxes/core/__init__.py +45 -22
  43. foxes/core/algorithm.py +0 -1
  44. foxes/core/data.py +56 -29
  45. foxes/core/engine.py +28 -14
  46. foxes/core/farm_controller.py +2 -2
  47. foxes/core/farm_data_model.py +1 -0
  48. foxes/core/ground_model.py +4 -13
  49. foxes/core/model.py +5 -5
  50. foxes/core/partial_wakes_model.py +147 -10
  51. foxes/core/point_data_model.py +2 -3
  52. foxes/core/rotor_model.py +42 -38
  53. foxes/core/states.py +4 -50
  54. foxes/core/turbine.py +2 -1
  55. foxes/core/wake_deflection.py +130 -0
  56. foxes/core/wake_model.py +222 -9
  57. foxes/core/wake_superposition.py +122 -4
  58. foxes/core/wind_farm.py +6 -6
  59. foxes/data/__init__.py +7 -2
  60. foxes/data/states/weibull_sectors_12.csv +13 -0
  61. foxes/data/states/weibull_sectors_12.nc +0 -0
  62. foxes/engines/__init__.py +14 -15
  63. foxes/engines/dask.py +39 -14
  64. foxes/engines/numpy.py +0 -3
  65. foxes/input/__init__.py +3 -3
  66. foxes/input/farm_layout/__init__.py +8 -8
  67. foxes/input/farm_layout/from_csv.py +1 -1
  68. foxes/input/farm_layout/ring.py +0 -1
  69. foxes/input/states/__init__.py +22 -11
  70. foxes/input/states/create/__init__.py +3 -2
  71. foxes/input/states/field_data_nc.py +48 -84
  72. foxes/input/states/multi_height.py +40 -60
  73. foxes/input/states/one_point_flow.py +22 -25
  74. foxes/input/states/scan.py +6 -19
  75. foxes/input/states/single.py +6 -18
  76. foxes/input/states/states_table.py +25 -44
  77. foxes/input/states/weibull_sectors.py +225 -0
  78. foxes/input/states/wrg_states.py +151 -37
  79. foxes/input/yaml/__init__.py +9 -3
  80. foxes/input/yaml/dict.py +19 -19
  81. foxes/input/yaml/windio/__init__.py +10 -5
  82. foxes/input/yaml/windio/read_attributes.py +2 -2
  83. foxes/input/yaml/windio/read_farm.py +5 -5
  84. foxes/input/yaml/windio/read_fields.py +4 -2
  85. foxes/input/yaml/windio/read_site.py +52 -0
  86. foxes/input/yaml/windio/windio.py +1 -1
  87. foxes/models/__init__.py +15 -14
  88. foxes/models/axial_induction/__init__.py +2 -2
  89. foxes/models/farm_controllers/__init__.py +1 -1
  90. foxes/models/farm_models/__init__.py +1 -1
  91. foxes/models/ground_models/__init__.py +3 -2
  92. foxes/models/ground_models/wake_mirror.py +3 -3
  93. foxes/models/model_book.py +175 -49
  94. foxes/models/partial_wakes/__init__.py +6 -6
  95. foxes/models/partial_wakes/axiwake.py +30 -5
  96. foxes/models/partial_wakes/centre.py +47 -0
  97. foxes/models/partial_wakes/rotor_points.py +45 -9
  98. foxes/models/partial_wakes/segregated.py +2 -20
  99. foxes/models/partial_wakes/top_hat.py +27 -2
  100. foxes/models/point_models/__init__.py +4 -4
  101. foxes/models/rotor_models/__init__.py +3 -3
  102. foxes/models/rotor_models/centre.py +6 -4
  103. foxes/models/turbine_models/__init__.py +11 -11
  104. foxes/models/turbine_models/set_farm_vars.py +0 -1
  105. foxes/models/turbine_types/PCt_file.py +0 -2
  106. foxes/models/turbine_types/PCt_from_two.py +0 -2
  107. foxes/models/turbine_types/__init__.py +9 -9
  108. foxes/models/vertical_profiles/__init__.py +7 -7
  109. foxes/models/wake_deflections/__init__.py +3 -0
  110. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  111. foxes/models/wake_deflections/jimenez.py +277 -0
  112. foxes/models/wake_deflections/no_deflection.py +94 -0
  113. foxes/models/wake_frames/__init__.py +6 -7
  114. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  115. foxes/models/wake_frames/rotor_wd.py +3 -1
  116. foxes/models/wake_frames/seq_dynamic_wakes.py +45 -8
  117. foxes/models/wake_frames/streamlines.py +8 -6
  118. foxes/models/wake_frames/timelines.py +19 -3
  119. foxes/models/wake_models/__init__.py +7 -7
  120. foxes/models/wake_models/dist_sliced.py +50 -84
  121. foxes/models/wake_models/gaussian.py +20 -0
  122. foxes/models/wake_models/induction/__init__.py +5 -5
  123. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  124. foxes/models/wake_models/induction/rathmann.py +65 -64
  125. foxes/models/wake_models/induction/self_similar.py +65 -68
  126. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  127. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  128. foxes/models/wake_models/ti/__init__.py +2 -2
  129. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  130. foxes/models/wake_models/ti/iec_ti.py +6 -4
  131. foxes/models/wake_models/top_hat.py +58 -7
  132. foxes/models/wake_models/wind/__init__.py +6 -4
  133. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  134. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  135. foxes/models/wake_models/wind/jensen.py +15 -2
  136. foxes/models/wake_models/wind/turbopark.py +28 -2
  137. foxes/models/wake_superpositions/__init__.py +18 -9
  138. foxes/models/wake_superpositions/ti_linear.py +4 -4
  139. foxes/models/wake_superpositions/ti_max.py +4 -4
  140. foxes/models/wake_superpositions/ti_pow.py +4 -4
  141. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  142. foxes/models/wake_superpositions/wind_vector.py +257 -0
  143. foxes/models/wake_superpositions/ws_linear.py +9 -10
  144. foxes/models/wake_superpositions/ws_max.py +8 -8
  145. foxes/models/wake_superpositions/ws_pow.py +8 -8
  146. foxes/models/wake_superpositions/ws_product.py +4 -4
  147. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  148. foxes/output/__init__.py +21 -19
  149. foxes/output/farm_layout.py +14 -6
  150. foxes/output/farm_results_eval.py +51 -27
  151. foxes/output/flow_plots_2d/__init__.py +2 -2
  152. foxes/output/flow_plots_2d/get_fig.py +4 -2
  153. foxes/output/rose_plot.py +23 -5
  154. foxes/output/seq_plugins/__init__.py +2 -2
  155. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  156. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  157. foxes/output/slice_data.py +16 -19
  158. foxes/output/turbine_type_curves.py +7 -8
  159. foxes/utils/__init__.py +37 -19
  160. foxes/utils/abl/__init__.py +4 -4
  161. foxes/utils/cubic_roots.py +1 -1
  162. foxes/utils/data_book.py +4 -3
  163. foxes/utils/dict.py +3 -3
  164. foxes/utils/exec_python.py +5 -5
  165. foxes/utils/factory.py +1 -3
  166. foxes/utils/geom2d/__init__.py +7 -5
  167. foxes/utils/geopandas_utils.py +2 -2
  168. foxes/utils/pandas_utils.py +4 -3
  169. foxes/utils/tab_files.py +0 -1
  170. foxes/utils/weibull.py +28 -0
  171. foxes/utils/wrg_utils.py +3 -1
  172. foxes/utils/xarray_utils.py +9 -2
  173. foxes/variables.py +67 -9
  174. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/METADATA +14 -21
  175. foxes-1.4.dist-info/RECORD +320 -0
  176. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
  177. tests/0_consistency/iterative/test_iterative.py +2 -3
  178. tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
  179. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  180. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
  181. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  182. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
  183. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  184. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  185. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -3
  186. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -4
  187. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -4
  188. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -4
  189. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -4
  190. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  191. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
  192. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -3
  193. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  194. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -4
  195. tests/3_examples/test_examples.py +3 -2
  196. foxes/output/round.py +0 -10
  197. foxes/utils/pandas_helpers.py +0 -178
  198. foxes-1.2.5.dist-info/RECORD +0 -312
  199. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
  200. {foxes-1.2.5.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
  201. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
@@ -30,7 +30,6 @@ class SeqState(States):
30
30
 
31
31
  # updated by SequentialIter:
32
32
  self._size = states.size()
33
- self._weight = None
34
33
  self._indx = None
35
34
  self._counter = None
36
35
 
@@ -100,23 +99,6 @@ class SeqState(States):
100
99
  """
101
100
  return self._counter
102
101
 
103
- def weights(self, algo):
104
- """
105
- The statistical weights of all states.
106
-
107
- Parameters
108
- ----------
109
- algo: foxes.core.Algorithm
110
- The calculation algorithm
111
-
112
- Returns
113
- -------
114
- weights: numpy.ndarray
115
- The weights, shape: (n_states, n_turbines)
116
-
117
- """
118
- return self._weight[None, :] if self._size == 1 else self.states.weights(algo)
119
-
120
102
  def output_point_vars(self, algo):
121
103
  """
122
104
  The variables which are being modified by the model.
@@ -139,7 +139,6 @@ class Sequential(Iterative):
139
139
  self.print_deco("calc_farm")
140
140
 
141
141
  self._inds = self.states0.index()
142
- self._weights = self.states0.weights(self)
143
142
  self._i = 0
144
143
  self._counter = 0
145
144
 
@@ -155,15 +154,18 @@ class Sequential(Iterative):
155
154
  if self._verbo0 > 0:
156
155
  print("\nInput data:\n")
157
156
  print(self._model_data)
158
- print(f"\nOutput farm variables:", ", ".join(self.farm_vars))
157
+ print("\nOutput farm variables:", ", ".join(self.farm_vars))
159
158
  print()
160
159
 
160
+ sts = self._model_data[FC.STATE].to_numpy()
161
161
  self._farm_results = Dataset(
162
- coords={FC.STATE: self._model_data[FC.STATE].to_numpy()},
162
+ coords={FC.STATE: sts},
163
163
  data_vars={
164
164
  v: (
165
165
  (FC.STATE, FC.TURBINE),
166
- np.zeros_like(self._model_data[FV.WEIGHT].to_numpy()),
166
+ np.zeros(
167
+ (len(sts), self.n_turbines), dtype=config.dtype_double
168
+ ),
167
169
  )
168
170
  for v in self.farm_vars
169
171
  },
@@ -186,12 +188,10 @@ class Sequential(Iterative):
186
188
  """Run calculation for current step, then iterate to next"""
187
189
 
188
190
  if self._i < len(self._inds):
189
-
190
191
  self._counter = self._i
191
192
  self.states._counter = self._i
192
193
  self.states._size = 1
193
194
  self.states._indx = self._inds[self._i]
194
- self.states._weight = self._weights[self._i]
195
195
 
196
196
  if self._verbo0 > 0:
197
197
  print(f"{self.name}: Running state {self.states.index()[0]}")
@@ -257,7 +257,6 @@ class Sequential(Iterative):
257
257
  self.states._counter = None
258
258
  self.states._size = len(self._inds)
259
259
  self.states._indx = self._inds
260
- self.states._weight = self._weights
261
260
 
262
261
  for p in self.plugins:
263
262
  p.finalize(self)
@@ -323,19 +322,6 @@ class Sequential(Iterative):
323
322
  """
324
323
  return self.counter if counter else self.index
325
324
 
326
- @property
327
- def weight(self):
328
- """
329
- The current weight array
330
-
331
- Returns
332
- -------
333
- w: numpy.ndarray
334
- The current weight array, shape: (n_turbines,)
335
-
336
- """
337
- return self.states._weight if self.iterating else None
338
-
339
325
  @property
340
326
  def farm_results(self):
341
327
  """
@@ -414,7 +400,7 @@ class Sequential(Iterative):
414
400
 
415
401
  """
416
402
  if not self.iterating:
417
- raise ValueError(f"calc_farm call is only allowed during iterations")
403
+ raise ValueError("calc_farm call is only allowed during iterations")
418
404
  return self.cur_farm_results
419
405
 
420
406
  def calc_points(
@@ -446,6 +432,6 @@ class Sequential(Iterative):
446
432
 
447
433
  """
448
434
  if not self.iterating:
449
- raise ValueError(f"calc_points call is only allowed during iterations")
435
+ raise ValueError("calc_points call is only allowed during iterations")
450
436
 
451
437
  return super().calc_points(farm_results, points, finalize=False, **kwargs)
foxes/config/__init__.py CHANGED
@@ -1 +1,5 @@
1
- from .config import Config, config, get_path, get_input_path, get_output_path
1
+ from .config import Config as Config
2
+ from .config import config as config
3
+ from .config import get_path as get_path
4
+ from .config import get_input_path as get_input_path
5
+ from .config import get_output_path as get_output_path
foxes/constants.py CHANGED
@@ -1,3 +1,8 @@
1
+ XY = "xy"
2
+ """ The vector (x, y)
3
+ :group: foxes.variables
4
+ """
5
+
1
6
  XYH = "xyh"
2
7
  """ The vector (x, y, height)
3
8
  :group: foxes.variables
@@ -73,11 +78,17 @@ ROTOR_WEIGHTS = "rotor_weights"
73
78
  """ Identifier for rotor point weights
74
79
  :group: foxes.constants
75
80
  """
81
+
76
82
  AMB_ROTOR_RES = "amb_rotor_res"
77
83
  """ Identifier for ambient rotor point results
78
84
  :group: foxes.constants
79
85
  """
80
86
 
87
+ WEIGHT_RES = "weight_res"
88
+ """ Identifier for weights results at rotor points
89
+ :group: foxes.constants
90
+ """
91
+
81
92
 
82
93
  VARS = "vars"
83
94
  """ Variables identifier
@@ -140,6 +151,17 @@ BLOCK_CONVERGENCE = "block_convergence"
140
151
  """
141
152
 
142
153
 
154
+ WDEFL_ROT_ANGLE = "wake_deflection_rotation_angle"
155
+ """Identifier for the wake deflection rotation angle data
156
+ :group: foxes.constants
157
+ """
158
+
159
+ WDEFL_DWS_FACTOR = "wake_deflection_deltaws_factor"
160
+ """Identifier for the wake deflection delta wind speed factor data
161
+ :group: foxes.constants
162
+ """
163
+
164
+
143
165
  KAPPA = 0.41
144
166
  """ The Von Karman constant
145
167
  :group: foxes.constants
foxes/core/__init__.py CHANGED
@@ -2,25 +2,48 @@
2
2
  Abstract classes and core functionality.
3
3
  """
4
4
 
5
- from .data import Data, MData, FData, TData
6
- from .model import Model
7
- from .data_calc_model import DataCalcModel
8
- from .engine import Engine, get_engine, has_engine, reset_engine
9
- from .states import States, ExtendedStates
10
- from .wind_farm import WindFarm
11
- from .algorithm import Algorithm
12
- from .farm_data_model import FarmDataModel, FarmDataModelList
13
- from .point_data_model import PointDataModel, PointDataModelList
14
- from .rotor_model import RotorModel
15
- from .farm_model import FarmModel
16
- from .turbine_model import TurbineModel
17
- from .turbine_type import TurbineType
18
- from .farm_controller import FarmController
19
- from .turbine import Turbine
20
- from .partial_wakes_model import PartialWakesModel
21
- from .wake_frame import WakeFrame
22
- from .wake_model import WakeModel, TurbineInductionModel, WakeK
23
- from .wake_superposition import WakeSuperposition
24
- from .vertical_profile import VerticalProfile
25
- from .axial_induction_model import AxialInductionModel
26
- from .ground_model import GroundModel
5
+ from .model import Model as Model
6
+ from .data_calc_model import DataCalcModel as DataCalcModel
7
+ from .wind_farm import WindFarm as WindFarm
8
+ from .algorithm import Algorithm as Algorithm
9
+ from .rotor_model import RotorModel as RotorModel
10
+ from .farm_model import FarmModel as FarmModel
11
+ from .turbine_model import TurbineModel as TurbineModel
12
+ from .turbine_type import TurbineType as TurbineType
13
+ from .farm_controller import FarmController as FarmController
14
+ from .turbine import Turbine as Turbine
15
+ from .partial_wakes_model import PartialWakesModel as PartialWakesModel
16
+ from .wake_frame import WakeFrame as WakeFrame
17
+ from .wake_deflection import WakeDeflection as WakeDeflection
18
+ from .vertical_profile import VerticalProfile as VerticalProfile
19
+ from .axial_induction_model import AxialInductionModel as AxialInductionModel
20
+ from .ground_model import GroundModel as GroundModel
21
+
22
+ from .data import Data as Data
23
+ from .data import MData as MData
24
+ from .data import FData as FData
25
+ from .data import TData as TData
26
+
27
+ from .engine import Engine as Engine
28
+ from .engine import get_engine as get_engine
29
+ from .engine import has_engine as has_engine
30
+ from .engine import reset_engine as reset_engine
31
+
32
+ from .states import States as States
33
+ from .states import ExtendedStates as ExtendedStates
34
+
35
+ from .farm_data_model import FarmDataModel as FarmDataModel
36
+ from .farm_data_model import FarmDataModelList as FarmDataModelList
37
+
38
+ from .point_data_model import PointDataModel as PointDataModel
39
+ from .point_data_model import PointDataModelList as PointDataModelList
40
+
41
+ from .wake_model import WakeModel as WakeModel
42
+ from .wake_model import SingleTurbineWakeModel as SingleTurbineWakeModel
43
+ from .wake_model import TurbineInductionModel as TurbineInductionModel
44
+ from .wake_model import WakeK as WakeK
45
+
46
+ from .wake_superposition import WakeSuperposition as WakeSuperposition
47
+ from .wake_superposition import (
48
+ WindVectorWakeSuperposition as WindVectorWakeSuperposition,
49
+ )
foxes/core/algorithm.py CHANGED
@@ -472,7 +472,6 @@ class Algorithm(Model):
472
472
  n_targets = int(tdata.n_targets if tdata is not None else 0)
473
473
 
474
474
  if prev_s > 0 or prev_t > 0:
475
-
476
475
  inds = np.array(
477
476
  [
478
477
  [
foxes/core/data.py CHANGED
@@ -28,9 +28,9 @@ class Data(Dict):
28
28
 
29
29
  def __init__(
30
30
  self,
31
- data,
32
- dims,
33
- loop_dims,
31
+ data={},
32
+ dims={},
33
+ loop_dims=[FC.STATE],
34
34
  states_i0=None,
35
35
  name="data",
36
36
  ):
@@ -153,13 +153,14 @@ class Data(Dict):
153
153
  # remove axes of size 1, added by dask for extra loop dimensions:
154
154
  if dims is not None:
155
155
  if len(dims) != len(data.shape):
156
- for li, l in enumerate(self.loop_dims):
157
- if data.shape[li] == 1 and (len(dims) < li + 1 or dims[li] != l):
156
+ for li, ld in enumerate(self.loop_dims):
157
+ if data.shape[li] == 1 and (len(dims) < li + 1 or dims[li] != ld):
158
158
  self[name] = np.squeeze(data, axis=li)
159
-
160
159
  for ci, c in enumerate(dims):
161
- if c not in self.sizes:
160
+ if c not in self.sizes or self.sizes[c] == 1:
162
161
  self.sizes[c] = self[name].shape[ci]
162
+ elif c != FC.TARGET and self[name].shape[ci] == 1:
163
+ pass
163
164
  elif self.sizes[c] != self[name].shape[ci]:
164
165
  raise ValueError(
165
166
  f"Inconsistent size for data entry '{name}', dimension '{c}': Expecting {self.sizes[c]}, found {self[name].shape[ci]} in shape {self[name].shape}"
@@ -239,9 +240,14 @@ class Data(Dict):
239
240
  )
240
241
  else:
241
242
  states_i0 = None
242
- return type(self)(
243
- data, dims, loop_dims=self.loop_dims, name=name, states_i0=states_i0
244
- )
243
+
244
+ cls = type(self)
245
+ if issubclass(cls, Data):
246
+ return cls(data, dims, name=name, states_i0=states_i0)
247
+ else:
248
+ return cls(
249
+ data, dims, loop_dims=self.loop_dims, name=name, states_i0=states_i0
250
+ )
245
251
 
246
252
  @classmethod
247
253
  def from_dataset(cls, ds, *args, callback=None, s_states=None, copy=True, **kwargs):
@@ -288,12 +294,16 @@ class Data(Dict):
288
294
  raise ValueError(
289
295
  f"Expecting coordinate '{FC.STATE}' at position 0 for data variable '{v}', got {d.dims}"
290
296
  )
291
- n_states = len(d.to_numpy())
297
+ n_states = d.shape[0]
292
298
  s = np.s_[:] if s_states is None else s_states
293
299
  data[v] = d.to_numpy()[s].copy() if copy else d.to_numpy()[s]
300
+ dims[v] = d.dims
301
+ if v == FV.WEIGHT and d.dims == (FC.STATE,):
302
+ data[v] = data[v][:, None]
303
+ dims[v] = (FC.STATE, FC.TURBINE)
294
304
  else:
295
305
  data[v] = d.to_numpy().copy() if copy else d.to_numpy()
296
- dims[v] = d.dims
306
+ dims[v] = d.dims
297
307
 
298
308
  if callback is not None:
299
309
  callback(data, dims)
@@ -355,15 +365,14 @@ class FData(Data):
355
365
  Arguments for the base class
356
366
 
357
367
  """
358
- super().__init__(*args, name=name, **kwargs)
368
+ super().__init__(*args, loop_dims=[FC.STATE], name=name, **kwargs)
359
369
 
360
370
  def _run_entry_checks(self, name, data, dims):
361
371
  """Run entry checks on new data"""
362
372
  super()._run_entry_checks(name, data, dims)
363
373
  data = self[name]
364
374
  dims = self.dims[name]
365
-
366
- if name not in self.sizes and name not in FC.TNAME:
375
+ if name not in self.sizes and name not in [FC.TNAME, FV.WEIGHT]:
367
376
  dms = (FC.STATE, FC.TURBINE)
368
377
  shp = (self.n_states, self.n_turbines)
369
378
  if len(data.shape) < 2:
@@ -418,8 +427,6 @@ class FData(Data):
418
427
  if FC.STATE not in data:
419
428
  data[FC.STATE] = mdata[FC.STATE]
420
429
  dims[FC.STATE] = mdata.dims[FC.STATE]
421
- data[FV.WEIGHT] = mdata[FV.WEIGHT]
422
- dims[FV.WEIGHT] = mdata.dims[FV.WEIGHT]
423
430
  if callback is not None:
424
431
  callback(data, dims)
425
432
 
@@ -451,7 +458,7 @@ class TData(Data):
451
458
  Arguments for the base class
452
459
 
453
460
  """
454
- super().__init__(*args, name=name, **kwargs)
461
+ super().__init__(*args, loop_dims=[FC.STATE, FC.TARGET], name=name, **kwargs)
455
462
 
456
463
  def _run_entry_checks(self, name, data, dims):
457
464
  """Run entry checks on new data"""
@@ -587,8 +594,9 @@ class TData(Data):
587
594
  def from_points(
588
595
  cls,
589
596
  points,
590
- data={},
591
- dims={},
597
+ data=None,
598
+ dims=None,
599
+ variables=None,
592
600
  name="tdata",
593
601
  **kwargs,
594
602
  ):
@@ -599,11 +607,14 @@ class TData(Data):
599
607
  ----------
600
608
  points: np.ndarray
601
609
  The points, shape: (n_states, n_points, 3)
602
- data: dict
610
+ data: dict, optional
603
611
  The initial data to be stored
604
- dims: dict
612
+ dims: dict, optional
605
613
  The dimensions tuples, same or subset
606
614
  of data keys
615
+ variables: list of str
616
+ Add default empty variables with NaN values
617
+ and shape (n_states, n_targets, n_tpoints)
607
618
  name: str
608
619
  The data container name
609
620
  kwargs: dict, optional
@@ -619,19 +630,26 @@ class TData(Data):
619
630
  raise ValueError(
620
631
  f"Expecting points shape (n_states, n_points, 3), got {points.shape}"
621
632
  )
633
+ data = {} if data is None else data
634
+ dims = {} if dims is None else dims
622
635
  data[FC.TARGETS] = points[:, :, None, :]
623
636
  dims[FC.TARGETS] = (FC.STATE, FC.TARGET, FC.TPOINT, FC.XYH)
624
637
  data[FC.TWEIGHTS] = np.array([1], dtype=config.dtype_double)
625
638
  dims[FC.TWEIGHTS] = (FC.TPOINT,)
626
- return cls(data, dims, [FC.STATE, FC.TARGET], name=name, **kwargs)
639
+ if variables is not None:
640
+ for v in variables:
641
+ data[v] = np.full_like(points[:, :, None, 0], np.nan)
642
+ dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
643
+ return cls(data=data, dims=dims, name=name, **kwargs)
627
644
 
628
645
  @classmethod
629
646
  def from_tpoints(
630
647
  cls,
631
648
  tpoints,
632
649
  tweights,
633
- data={},
634
- dims={},
650
+ data=None,
651
+ dims=None,
652
+ variables=None,
635
653
  name="tdata",
636
654
  **kwargs,
637
655
  ):
@@ -646,11 +664,14 @@ class TData(Data):
646
664
  tweights: np.ndarray, optional
647
665
  The target point weights, shape:
648
666
  (n_tpoints,)
649
- data: dict
667
+ data: dict, optional
650
668
  The initial data to be stored
651
- dims: dict
669
+ dims: dict, optional
652
670
  The dimensions tuples, same or subset
653
671
  of data keys
672
+ variables: list of str
673
+ Add default empty variables with NaN values
674
+ and shape (n_states, n_targets, n_tpoints)
654
675
  name: str
655
676
  The data container name
656
677
  kwargs: dict, optional
@@ -666,11 +687,17 @@ class TData(Data):
666
687
  raise ValueError(
667
688
  f"Expecting tpoints shape (n_states, n_targets, n_tpoints, 3), got {tpoints.shape}"
668
689
  )
690
+ data = {} if data is None else data
691
+ dims = {} if dims is None else dims
669
692
  data[FC.TARGETS] = tpoints
670
693
  dims[FC.TARGETS] = (FC.STATE, FC.TARGET, FC.TPOINT, FC.XYH)
671
694
  data[FC.TWEIGHTS] = tweights
672
695
  dims[FC.TWEIGHTS] = (FC.TPOINT,)
673
- return cls(data, dims, [FC.STATE], name=name, **kwargs)
696
+ if variables is not None:
697
+ for v in variables:
698
+ data[v] = np.full_like(tpoints[..., 0], np.nan)
699
+ dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
700
+ return cls(data=data, dims=dims, name=name, **kwargs)
674
701
 
675
702
  @classmethod
676
703
  def from_dataset(
@@ -738,7 +765,7 @@ class TData(Data):
738
765
  FC.TPOINT,
739
766
  ):
740
767
  raise ValueError(
741
- f"Expecting coordinates '{ (FC.STATE, FC.TARGET, FC.TPOINT)}' at positions 0-2 for data variable '{v}', got {dims[v]}"
768
+ f"Expecting coordinates '{(FC.STATE, FC.TARGET, FC.TPOINT)}' at positions 0-2 for data variable '{v}', got {dims[v]}"
742
769
  )
743
770
  else:
744
771
  data[v] = d[:, s_targets]
foxes/core/engine.py CHANGED
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
4
4
  from tqdm import tqdm
5
5
  from xarray import Dataset
6
6
 
7
- from foxes.core import MData, FData, TData
7
+ from .data import MData, FData, TData
8
8
  from foxes.utils import new_instance
9
9
  from foxes.config import config
10
10
  import foxes.constants as FC
@@ -73,7 +73,7 @@ class Engine(ABC):
73
73
 
74
74
  def __enter__(self):
75
75
  if self.__entered:
76
- raise ValueError(f"Enter called for already entered engine")
76
+ raise ValueError("Enter called for already entered engine")
77
77
  self.__entered = True
78
78
  if not self.initialized:
79
79
  self.initialize()
@@ -81,7 +81,7 @@ class Engine(ABC):
81
81
 
82
82
  def __exit__(self, *exit_args):
83
83
  if not self.__entered:
84
- raise ValueError(f"Exit called for not entered engine")
84
+ raise ValueError("Exit called for not entered engine")
85
85
  self.__entered = False
86
86
  if self.initialized:
87
87
  self.finalize(*exit_args)
@@ -127,7 +127,6 @@ class Engine(ABC):
127
127
  raise ValueError(
128
128
  f"Cannot initialize engine '{type(self).__name__}', since engine already set to '{type(get_engine()).__name__}'"
129
129
  )
130
- global __global_engine_data__
131
130
  __global_engine_data__["engine"] = self
132
131
  self.__initialized = True
133
132
 
@@ -148,7 +147,6 @@ class Engine(ABC):
148
147
  if self.entered:
149
148
  self.__exit__(type, value, traceback)
150
149
  elif self.initialized:
151
- global __global_engine_data__
152
150
  __global_engine_data__["engine"] = None
153
151
  self.__initialized = False
154
152
 
@@ -304,9 +302,9 @@ class Engine(ABC):
304
302
  chunk_sizes_targets[-extra:] += 1
305
303
 
306
304
  s = np.sum(chunk_sizes_targets)
307
- assert (
308
- s == n_targets
309
- ), f"Targets count mismatch: Expecting {n_targets}, chunks sum is {s}. Chunks: {[int(c) for c in chunk_sizes_targets]}"
305
+ assert s == n_targets, (
306
+ f"Targets count mismatch: Expecting {n_targets}, chunks sum is {s}. Chunks: {[int(c) for c in chunk_sizes_targets]}"
307
+ )
310
308
 
311
309
  chunk_sizes_states = np.full(n_chunks_states, chunk_size_states)
312
310
  extra = n_states - n_chunks_states * chunk_size_states
@@ -314,9 +312,9 @@ class Engine(ABC):
314
312
  chunk_sizes_states[-extra:] += 1
315
313
 
316
314
  s = np.sum(chunk_sizes_states)
317
- assert (
318
- s == n_states
319
- ), f"States count mismatch: Expecting {n_states}, chunks sum is {s}. Chunks: {[int(c) for c in chunk_sizes_states]}"
315
+ assert s == n_states, (
316
+ f"States count mismatch: Expecting {n_states}, chunks sum is {s}. Chunks: {[int(c) for c in chunk_sizes_states]}"
317
+ )
320
318
 
321
319
  return chunk_sizes_states, chunk_sizes_targets
322
320
 
@@ -389,7 +387,6 @@ class Engine(ABC):
389
387
  mdata=mdata,
390
388
  s_states=s_states,
391
389
  callback=cb,
392
- loop_dims=[FC.STATE],
393
390
  states_i0=i0_states,
394
391
  copy=True,
395
392
  )
@@ -413,7 +410,6 @@ class Engine(ABC):
413
410
  s_states=s_states,
414
411
  s_targets=s_targets,
415
412
  callback=cb,
416
- loop_dims=[FC.STATE, FC.TARGET],
417
413
  states_i0=i0_states,
418
414
  copy=True,
419
415
  )
@@ -515,9 +511,27 @@ class Engine(ABC):
515
511
  if FC.STATE in out_coords and FC.STATE in model_data.coords:
516
512
  coords[FC.STATE] = model_data[FC.STATE].to_numpy()
517
513
 
514
+ # reducing weights dimensions:
515
+ dvars = {}
516
+ for v, (dims, d) in data_vars.items():
517
+ if (
518
+ dims == (FC.STATE, FC.TURBINE)
519
+ and d.shape[1] == 1
520
+ and algo.n_turbines > 1
521
+ ):
522
+ dvars[v] = ((FC.STATE,), d[:, 0])
523
+ elif (
524
+ dims == (FC.STATE, FC.TARGET, FC.TPOINT)
525
+ and goal_data.sizes[FC.TARGET] > n_chunks_targets
526
+ and d.shape[1:] == (n_chunks_targets, 1)
527
+ ):
528
+ dvars[v] = ((FC.STATE,), d[:, 0, 0])
529
+ else:
530
+ dvars[v] = (dims, d)
531
+
518
532
  return Dataset(
519
533
  coords=coords,
520
- data_vars={v: tuple(d) for v, d in data_vars.items()},
534
+ data_vars=dvars,
521
535
  )
522
536
 
523
537
  @abstractmethod
@@ -171,7 +171,7 @@ class FarmController(FarmDataModel):
171
171
  for ti, t in enumerate(algo.farm.turbines):
172
172
  if tmis[ti] != len(models[ti]):
173
173
  raise ValueError(
174
- f"Turbine {ti}, {t.name}: Could not find turbine model order that includes all {mtype} turbine models, missing {t.models[tmis[ti]:]}"
174
+ f"Turbine {ti}, {t.name}: Could not find turbine model order that includes all {mtype} turbine models, missing {t.models[tmis[ti] :]}"
175
175
  )
176
176
 
177
177
  return [m.name for m in tmodels], tmsels
@@ -253,7 +253,7 @@ class FarmController(FarmDataModel):
253
253
  prer = m.pre_rotor
254
254
  elif not prer and m.pre_rotor:
255
255
  raise ValueError(
256
- f"Turbine {ti}, {t.name}: Model is classified as pre-rotor, but following the post-rotor model '{t.models[mi-1]}'"
256
+ f"Turbine {ti}, {t.name}: Model is classified as pre-rotor, but following the post-rotor model '{t.models[mi - 1]}'"
257
257
  )
258
258
  if m.pre_rotor:
259
259
  prer_models[ti].append(m)
@@ -246,6 +246,7 @@ class FarmDataModelList(FarmDataModel):
246
246
  ovars = []
247
247
  for m in self.models:
248
248
  ovars += m.output_farm_vars(algo)
249
+
249
250
  return list(dict.fromkeys(ovars))
250
251
 
251
252
  def calculate(self, algo, mdata, fdata, parameters=[]):
@@ -91,7 +91,6 @@ class GroundModel(Model):
91
91
  mdata,
92
92
  fdata,
93
93
  tdata,
94
- amb_res,
95
94
  rpoint_weights,
96
95
  wake_deltas,
97
96
  wmodel,
@@ -114,11 +113,6 @@ class GroundModel(Model):
114
113
  The farm data
115
114
  tdata: foxes.core.Data
116
115
  The target point data
117
- amb_res: dict
118
- The ambient results at the target points
119
- of all rotors. Key: variable name, value
120
- np.ndarray of shape:
121
- (n_states, n_turbines, n_rotor_points)
122
116
  rpoint_weights: numpy.ndarray
123
117
  The rotor point weights, shape: (n_rotor_points,)
124
118
  wake_deltas: dict
@@ -143,7 +137,6 @@ class GroundModel(Model):
143
137
  mdata,
144
138
  fdata,
145
139
  tdata,
146
- amb_res,
147
140
  rpoint_weights,
148
141
  wake_deltas,
149
142
  wmodel,
@@ -226,7 +219,7 @@ class GroundModel(Model):
226
219
  algo,
227
220
  mdata,
228
221
  fdata,
229
- amb_results,
222
+ tdata,
230
223
  wake_deltas,
231
224
  wmodel,
232
225
  ):
@@ -243,17 +236,15 @@ class GroundModel(Model):
243
236
  The model data
244
237
  fdata: foxes.core.FData
245
238
  The farm data
246
- amb_results: dict
247
- The ambient results, key: variable name str,
248
- values: numpy.ndarray with shape
249
- (n_states, n_targets, n_tpoints)
239
+ tdata: foxes.core.TData
240
+ The target point data
250
241
  wake_deltas: dict
251
242
  The wake deltas object at the selected target
252
243
  turbines. Key: variable str, value: numpy.ndarray
253
244
  with shape (n_states, n_targets, n_tpoints)
254
245
 
255
246
  """
256
- wmodel.finalize_wake_deltas(algo, mdata, fdata, amb_results, wake_deltas)
247
+ wmodel.finalize_wake_deltas(algo, mdata, fdata, tdata, wake_deltas)
257
248
 
258
249
  @classmethod
259
250
  def new(cls, ground_type, *args, **kwargs):