foxes 1.3__py3-none-any.whl → 1.5__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 (228) 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/field_data_nc/run.py +1 -1
  7. examples/induction/run.py +3 -3
  8. examples/multi_height/run.py +1 -1
  9. examples/power_mask/run.py +2 -2
  10. examples/quickstart/run.py +0 -1
  11. examples/random_timeseries/run.py +3 -4
  12. examples/scan_row/run.py +3 -3
  13. examples/sequential/run.py +33 -10
  14. examples/single_state/run.py +3 -4
  15. examples/states_lookup_table/run.py +3 -3
  16. examples/streamline_wakes/run.py +29 -6
  17. examples/tab_file/run.py +3 -3
  18. examples/timelines/run.py +29 -5
  19. examples/timeseries/run.py +3 -3
  20. examples/timeseries_slurm/run.py +3 -3
  21. examples/wind_rose/run.py +3 -3
  22. examples/yawed_wake/run.py +19 -9
  23. foxes/__init__.py +21 -17
  24. foxes/algorithms/__init__.py +6 -6
  25. foxes/algorithms/downwind/__init__.py +2 -2
  26. foxes/algorithms/downwind/downwind.py +49 -17
  27. foxes/algorithms/downwind/models/__init__.py +6 -6
  28. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
  29. foxes/algorithms/downwind/models/init_farm_data.py +58 -29
  30. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  31. foxes/algorithms/downwind/models/set_amb_farm_results.py +1 -1
  32. foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
  33. foxes/algorithms/iterative/__init__.py +7 -3
  34. foxes/algorithms/iterative/iterative.py +1 -2
  35. foxes/algorithms/iterative/models/__init__.py +7 -3
  36. foxes/algorithms/iterative/models/farm_wakes_calc.py +9 -5
  37. foxes/algorithms/sequential/__init__.py +3 -3
  38. foxes/algorithms/sequential/models/__init__.py +2 -2
  39. foxes/algorithms/sequential/sequential.py +3 -4
  40. foxes/config/__init__.py +5 -1
  41. foxes/constants.py +16 -0
  42. foxes/core/__init__.py +45 -22
  43. foxes/core/algorithm.py +5 -6
  44. foxes/core/data.py +94 -22
  45. foxes/core/data_calc_model.py +4 -2
  46. foxes/core/engine.py +42 -53
  47. foxes/core/farm_controller.py +2 -2
  48. foxes/core/farm_data_model.py +16 -13
  49. foxes/core/ground_model.py +4 -13
  50. foxes/core/model.py +24 -6
  51. foxes/core/partial_wakes_model.py +147 -10
  52. foxes/core/point_data_model.py +21 -17
  53. foxes/core/rotor_model.py +4 -3
  54. foxes/core/states.py +2 -3
  55. foxes/core/turbine.py +2 -1
  56. foxes/core/wake_deflection.py +130 -0
  57. foxes/core/wake_model.py +222 -9
  58. foxes/core/wake_superposition.py +122 -4
  59. foxes/core/wind_farm.py +6 -6
  60. foxes/data/__init__.py +7 -2
  61. foxes/data/states/point_cloud_100.nc +0 -0
  62. foxes/data/states/weibull_cloud_4.nc +0 -0
  63. foxes/data/states/weibull_grid.nc +0 -0
  64. foxes/data/states/weibull_sectors_12.csv +13 -0
  65. foxes/data/states/weibull_sectors_12.nc +0 -0
  66. foxes/engines/__init__.py +14 -15
  67. foxes/engines/dask.py +42 -20
  68. foxes/engines/default.py +2 -2
  69. foxes/engines/numpy.py +11 -13
  70. foxes/engines/pool.py +20 -11
  71. foxes/engines/single.py +8 -6
  72. foxes/input/__init__.py +3 -3
  73. foxes/input/farm_layout/__init__.py +9 -8
  74. foxes/input/farm_layout/from_arrays.py +68 -0
  75. foxes/input/farm_layout/from_csv.py +1 -1
  76. foxes/input/farm_layout/ring.py +0 -1
  77. foxes/input/states/__init__.py +28 -12
  78. foxes/input/states/create/__init__.py +3 -2
  79. foxes/input/states/dataset_states.py +710 -0
  80. foxes/input/states/field_data.py +531 -0
  81. foxes/input/states/multi_height.py +11 -6
  82. foxes/input/states/one_point_flow.py +1 -4
  83. foxes/input/states/point_cloud_data.py +618 -0
  84. foxes/input/states/scan.py +2 -0
  85. foxes/input/states/single.py +3 -1
  86. foxes/input/states/states_table.py +23 -30
  87. foxes/input/states/weibull_sectors.py +330 -0
  88. foxes/input/states/wrg_states.py +8 -6
  89. foxes/input/yaml/__init__.py +9 -3
  90. foxes/input/yaml/dict.py +42 -41
  91. foxes/input/yaml/windio/__init__.py +10 -5
  92. foxes/input/yaml/windio/read_attributes.py +42 -29
  93. foxes/input/yaml/windio/read_farm.py +17 -15
  94. foxes/input/yaml/windio/read_fields.py +4 -2
  95. foxes/input/yaml/windio/read_outputs.py +25 -15
  96. foxes/input/yaml/windio/read_site.py +172 -11
  97. foxes/input/yaml/windio/windio.py +23 -11
  98. foxes/input/yaml/yaml.py +1 -0
  99. foxes/models/__init__.py +15 -14
  100. foxes/models/axial_induction/__init__.py +2 -2
  101. foxes/models/farm_controllers/__init__.py +1 -1
  102. foxes/models/farm_models/__init__.py +1 -1
  103. foxes/models/ground_models/__init__.py +3 -2
  104. foxes/models/ground_models/wake_mirror.py +3 -3
  105. foxes/models/model_book.py +190 -63
  106. foxes/models/partial_wakes/__init__.py +6 -6
  107. foxes/models/partial_wakes/axiwake.py +30 -5
  108. foxes/models/partial_wakes/centre.py +47 -0
  109. foxes/models/partial_wakes/rotor_points.py +41 -11
  110. foxes/models/partial_wakes/segregated.py +2 -25
  111. foxes/models/partial_wakes/top_hat.py +27 -2
  112. foxes/models/point_models/__init__.py +4 -4
  113. foxes/models/rotor_models/__init__.py +4 -3
  114. foxes/models/rotor_models/centre.py +1 -1
  115. foxes/models/rotor_models/direct_infusion.py +241 -0
  116. foxes/models/turbine_models/__init__.py +11 -11
  117. foxes/models/turbine_models/calculator.py +16 -3
  118. foxes/models/turbine_models/kTI_model.py +1 -0
  119. foxes/models/turbine_models/lookup_table.py +2 -0
  120. foxes/models/turbine_models/power_mask.py +1 -0
  121. foxes/models/turbine_models/rotor_centre_calc.py +2 -0
  122. foxes/models/turbine_models/sector_management.py +1 -0
  123. foxes/models/turbine_models/set_farm_vars.py +3 -9
  124. foxes/models/turbine_models/table_factors.py +2 -0
  125. foxes/models/turbine_models/thrust2ct.py +1 -0
  126. foxes/models/turbine_models/yaw2yawm.py +2 -0
  127. foxes/models/turbine_models/yawm2yaw.py +2 -0
  128. foxes/models/turbine_types/PCt_file.py +2 -6
  129. foxes/models/turbine_types/PCt_from_two.py +1 -2
  130. foxes/models/turbine_types/__init__.py +10 -9
  131. foxes/models/turbine_types/calculator_type.py +123 -0
  132. foxes/models/turbine_types/null_type.py +1 -0
  133. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -0
  134. foxes/models/turbine_types/wsti2PCt_from_two.py +3 -1
  135. foxes/models/vertical_profiles/__init__.py +7 -7
  136. foxes/models/wake_deflections/__init__.py +3 -0
  137. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  138. foxes/models/wake_deflections/jimenez.py +277 -0
  139. foxes/models/wake_deflections/no_deflection.py +94 -0
  140. foxes/models/wake_frames/__init__.py +6 -7
  141. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  142. foxes/models/wake_frames/rotor_wd.py +3 -1
  143. foxes/models/wake_frames/seq_dynamic_wakes.py +41 -7
  144. foxes/models/wake_frames/streamlines.py +8 -6
  145. foxes/models/wake_frames/timelines.py +9 -3
  146. foxes/models/wake_models/__init__.py +7 -7
  147. foxes/models/wake_models/dist_sliced.py +50 -84
  148. foxes/models/wake_models/gaussian.py +20 -0
  149. foxes/models/wake_models/induction/__init__.py +5 -5
  150. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  151. foxes/models/wake_models/induction/rathmann.py +65 -64
  152. foxes/models/wake_models/induction/self_similar.py +65 -68
  153. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  154. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  155. foxes/models/wake_models/ti/__init__.py +2 -2
  156. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  157. foxes/models/wake_models/ti/iec_ti.py +6 -4
  158. foxes/models/wake_models/top_hat.py +58 -7
  159. foxes/models/wake_models/wind/__init__.py +6 -4
  160. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  161. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  162. foxes/models/wake_models/wind/jensen.py +15 -2
  163. foxes/models/wake_models/wind/turbopark.py +28 -2
  164. foxes/models/wake_superpositions/__init__.py +18 -9
  165. foxes/models/wake_superpositions/ti_linear.py +4 -4
  166. foxes/models/wake_superpositions/ti_max.py +4 -4
  167. foxes/models/wake_superpositions/ti_pow.py +4 -4
  168. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  169. foxes/models/wake_superpositions/wind_vector.py +257 -0
  170. foxes/models/wake_superpositions/ws_linear.py +9 -10
  171. foxes/models/wake_superpositions/ws_max.py +8 -8
  172. foxes/models/wake_superpositions/ws_pow.py +8 -8
  173. foxes/models/wake_superpositions/ws_product.py +4 -4
  174. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  175. foxes/output/__init__.py +21 -19
  176. foxes/output/farm_layout.py +4 -2
  177. foxes/output/farm_results_eval.py +19 -16
  178. foxes/output/flow_plots_2d/__init__.py +2 -2
  179. foxes/output/flow_plots_2d/flow_plots.py +18 -0
  180. foxes/output/flow_plots_2d/get_fig.py +5 -2
  181. foxes/output/output.py +6 -1
  182. foxes/output/results_writer.py +1 -1
  183. foxes/output/rose_plot.py +13 -3
  184. foxes/output/rotor_point_plots.py +3 -0
  185. foxes/output/seq_plugins/__init__.py +2 -2
  186. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  187. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  188. foxes/output/state_turbine_map.py +3 -0
  189. foxes/output/turbine_type_curves.py +10 -8
  190. foxes/utils/__init__.py +37 -19
  191. foxes/utils/abl/__init__.py +4 -4
  192. foxes/utils/cubic_roots.py +1 -1
  193. foxes/utils/data_book.py +4 -3
  194. foxes/utils/dict.py +49 -37
  195. foxes/utils/exec_python.py +5 -5
  196. foxes/utils/factory.py +3 -5
  197. foxes/utils/geom2d/__init__.py +7 -5
  198. foxes/utils/geopandas_utils.py +2 -2
  199. foxes/utils/pandas_utils.py +4 -3
  200. foxes/utils/tab_files.py +0 -1
  201. foxes/utils/weibull.py +28 -0
  202. foxes/utils/wrg_utils.py +3 -1
  203. foxes/utils/xarray_utils.py +9 -2
  204. foxes/variables.py +67 -9
  205. {foxes-1.3.dist-info → foxes-1.5.dist-info}/METADATA +34 -63
  206. foxes-1.5.dist-info/RECORD +328 -0
  207. {foxes-1.3.dist-info → foxes-1.5.dist-info}/WHEEL +1 -1
  208. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  209. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +1 -1
  210. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  211. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  212. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  213. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +0 -1
  214. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
  215. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
  216. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
  217. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
  218. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  219. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
  220. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  221. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +0 -1
  222. foxes/input/states/field_data_nc.py +0 -847
  223. foxes/output/round.py +0 -10
  224. foxes/utils/pandas_helpers.py +0 -178
  225. foxes-1.3.dist-info/RECORD +0 -313
  226. {foxes-1.3.dist-info → foxes-1.5.dist-info}/entry_points.txt +0 -0
  227. {foxes-1.3.dist-info → foxes-1.5.dist-info/licenses}/LICENSE +0 -0
  228. {foxes-1.3.dist-info → foxes-1.5.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  from copy import deepcopy
3
3
 
4
- from foxes.core import FarmDataModel, TData
4
+ from foxes.core import FarmDataModel
5
5
  import foxes.constants as FC
6
6
  import foxes.variables as FV
7
7
 
@@ -99,8 +99,14 @@ class FarmWakesCalculation(FarmDataModel):
99
99
  for wname, wmodel in algo.wake_models.items():
100
100
  pwake = algo.partial_wakes[wname]
101
101
  if pwake.name not in pwake2tdata:
102
- tpoints, tweights = pwake.get_wake_points(algo, mdata, fdata)
103
- pwake2tdata[pwake.name] = TData.from_tpoints(tpoints, tweights)
102
+ wmodels = [
103
+ wm
104
+ for wn, wm in algo.wake_models.items()
105
+ if algo.partial_wakes[wn] is pwake
106
+ ]
107
+ pwake2tdata[pwake.name] = pwake.get_initial_tdata(
108
+ algo, mdata, fdata, amb_res, rwghts, wmodels
109
+ )
104
110
 
105
111
  def _get_wdata(tdatap, wdeltas, variables, s):
106
112
  """Helper function for wake data extraction"""
@@ -117,7 +123,6 @@ class FarmWakesCalculation(FarmDataModel):
117
123
  wdeltas = pwake.new_wake_deltas(algo, mdata, fdata, tdatap, wmodel)
118
124
 
119
125
  for oi in range(n_turbines):
120
-
121
126
  if oi > 0:
122
127
  tdata, wdelta = _get_wdata(
123
128
  tdatap, wdeltas, [FC.STATE, FC.TARGET], np.s_[:, :oi]
@@ -140,7 +145,6 @@ class FarmWakesCalculation(FarmDataModel):
140
145
  mdata,
141
146
  fdata,
142
147
  tdatap,
143
- amb_res,
144
148
  rwghts,
145
149
  wdeltas,
146
150
  wmodel,
@@ -1,4 +1,4 @@
1
- from .sequential import Sequential
2
- from .models import SequentialPlugin
1
+ from .sequential import Sequential as Sequential
2
+ from .models import SequentialPlugin as SequentialPlugin
3
3
 
4
- from . import models
4
+ from . import models as models
@@ -1,2 +1,2 @@
1
- from .plugin import SequentialPlugin
2
- from .seq_state import SeqState
1
+ from .plugin import SequentialPlugin as SequentialPlugin
2
+ from .seq_state import SeqState as SeqState
@@ -154,7 +154,7 @@ class Sequential(Iterative):
154
154
  if self._verbo0 > 0:
155
155
  print("\nInput data:\n")
156
156
  print(self._model_data)
157
- print(f"\nOutput farm variables:", ", ".join(self.farm_vars))
157
+ print("\nOutput farm variables:", ", ".join(self.farm_vars))
158
158
  print()
159
159
 
160
160
  sts = self._model_data[FC.STATE].to_numpy()
@@ -188,7 +188,6 @@ class Sequential(Iterative):
188
188
  """Run calculation for current step, then iterate to next"""
189
189
 
190
190
  if self._i < len(self._inds):
191
-
192
191
  self._counter = self._i
193
192
  self.states._counter = self._i
194
193
  self.states._size = 1
@@ -401,7 +400,7 @@ class Sequential(Iterative):
401
400
 
402
401
  """
403
402
  if not self.iterating:
404
- raise ValueError(f"calc_farm call is only allowed during iterations")
403
+ raise ValueError("calc_farm call is only allowed during iterations")
405
404
  return self.cur_farm_results
406
405
 
407
406
  def calc_points(
@@ -433,6 +432,6 @@ class Sequential(Iterative):
433
432
 
434
433
  """
435
434
  if not self.iterating:
436
- raise ValueError(f"calc_points call is only allowed during iterations")
435
+ raise ValueError("calc_points call is only allowed during iterations")
437
436
 
438
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
@@ -146,6 +151,17 @@ BLOCK_CONVERGENCE = "block_convergence"
146
151
  """
147
152
 
148
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
+
149
165
  KAPPA = 0.41
150
166
  """ The Von Karman constant
151
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
@@ -63,8 +63,8 @@ class Algorithm(Model):
63
63
  self.__farm = farm
64
64
  self.__mbook = mbook
65
65
  self.__dbook = StaticData() if dbook is None else dbook
66
- self.__idata_mem = Dict(name="idata_mem")
67
- self.__chunk_store = Dict(name="chunk_store")
66
+ self.__idata_mem = Dict(_name="idata_mem")
67
+ self.__chunk_store = Dict(_name="chunk_store")
68
68
 
69
69
  if len(engine_pars):
70
70
  if "engine_type" in engine_pars:
@@ -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
  [
@@ -559,7 +558,7 @@ class Algorithm(Model):
559
558
  "n_states": n_states,
560
559
  "n_targets": n_targets,
561
560
  },
562
- name=f"chunk_store_{i0}_{t0}",
561
+ _name=f"chunk_store_{i0}_{t0}",
563
562
  )
564
563
 
565
564
  self.chunk_store[key][name] = data.copy() if copy else data
@@ -639,11 +638,11 @@ class Algorithm(Model):
639
638
  """
640
639
  chunk_store = self.chunk_store
641
640
  if new_chunk_store is None:
642
- self.__chunk_store = Dict(name="chunk_store")
641
+ self.__chunk_store = Dict(_name="chunk_store")
643
642
  elif isinstance(new_chunk_store, Dict):
644
643
  self.__chunk_store = new_chunk_store
645
644
  else:
646
- self.__chunk_store = Dict(name="chunk_store")
645
+ self.__chunk_store = Dict(_name="chunk_store")
647
646
  self.__chunk_store.update(new_chunk_store)
648
647
  return chunk_store
649
648
 
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
  ):
@@ -53,7 +53,7 @@ class Data(Dict):
53
53
  The data container name
54
54
 
55
55
  """
56
- super().__init__(name=name)
56
+ super().__init__(_name=name)
57
57
 
58
58
  self.update(data)
59
59
  self.dims = dims
@@ -109,12 +109,12 @@ class Data(Dict):
109
109
  or the corresponding index
110
110
 
111
111
  """
112
- if FC.STATE not in self:
113
- return None
114
- elif counter:
112
+ if counter:
115
113
  if self.__states_i0 is None:
116
114
  raise KeyError(f"Data '{self.name}': states_i0 requested but not set")
117
115
  return self.__states_i0
116
+ elif FC.STATE not in self:
117
+ return None
118
118
  else:
119
119
  return self[FC.STATE][0]
120
120
 
@@ -153,13 +153,13 @@ 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
159
  for ci, c in enumerate(dims):
160
160
  if c not in self.sizes or self.sizes[c] == 1:
161
161
  self.sizes[c] = self[name].shape[ci]
162
- elif self[name].shape[ci] == 1:
162
+ elif c != FC.TARGET and self[name].shape[ci] == 1:
163
163
  pass
164
164
  elif self.sizes[c] != self[name].shape[ci]:
165
165
  raise ValueError(
@@ -240,9 +240,14 @@ class Data(Dict):
240
240
  )
241
241
  else:
242
242
  states_i0 = None
243
- return type(self)(
244
- data, dims, loop_dims=self.loop_dims, name=name, states_i0=states_i0
245
- )
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
+ )
246
251
 
247
252
  @classmethod
248
253
  def from_dataset(cls, ds, *args, callback=None, s_states=None, copy=True, **kwargs):
@@ -360,7 +365,7 @@ class FData(Data):
360
365
  Arguments for the base class
361
366
 
362
367
  """
363
- super().__init__(*args, name=name, **kwargs)
368
+ super().__init__(*args, loop_dims=[FC.STATE], name=name, **kwargs)
364
369
 
365
370
  def _run_entry_checks(self, name, data, dims):
366
371
  """Run entry checks on new data"""
@@ -389,6 +394,74 @@ class FData(Data):
389
394
  f"FData '{self.name}': Missing '{x}' in sizes, got {sorted(list(self.sizes.keys()))}"
390
395
  )
391
396
 
397
+ @classmethod
398
+ def from_sizes(cls, n_states, n_turbines, *args, callback=None, **kwargs):
399
+ """
400
+ Create Data object from model data
401
+
402
+ Parameters
403
+ ----------
404
+ n_states: int
405
+ The number of states
406
+ n_turbines: int
407
+ The number of turbines
408
+ args: tuple, optional
409
+ Additional parameters for the constructor
410
+ callback: Function, optional
411
+ Function f(data, dims) that manipulates
412
+ the data and dims dicts before construction
413
+ kwargs: dict, optional
414
+ Additional parameters for the constructor
415
+
416
+ Returns
417
+ -------
418
+ data: Data
419
+ The data object
420
+
421
+ """
422
+ data = cls(*args, **kwargs)
423
+ data.sizes[FC.STATE] = n_states
424
+ data.sizes[FC.TURBINE] = n_turbines
425
+
426
+ if callback is not None:
427
+ callback(data, data.dims)
428
+
429
+ return data
430
+
431
+ @classmethod
432
+ def from_mdata(cls, mdata, *args, callback=None, **kwargs):
433
+ """
434
+ Create Data object from model data
435
+
436
+ Parameters
437
+ ----------
438
+ mdata: MData
439
+ The model data
440
+ args: tuple, optional
441
+ Additional parameters for the constructor
442
+ callback: Function, optional
443
+ Function f(data, dims) that manipulates
444
+ the data and dims dicts before construction
445
+ kwargs: dict, optional
446
+ Additional parameters for the constructor
447
+
448
+ Returns
449
+ -------
450
+ data: Data
451
+ The data object
452
+
453
+ """
454
+ data = cls(*args, **kwargs)
455
+ for v in [FC.STATE, FC.TURBINE]:
456
+ data[v] = mdata[v]
457
+ data.dims[v] = mdata.dims[v]
458
+ data.sizes[v] = mdata.sizes[v]
459
+
460
+ if callback is not None:
461
+ callback(data, data.dims)
462
+
463
+ return data
464
+
392
465
  @classmethod
393
466
  def from_dataset(cls, ds, *args, mdata=None, callback=None, **kwargs):
394
467
  """
@@ -422,6 +495,9 @@ class FData(Data):
422
495
  if FC.STATE not in data:
423
496
  data[FC.STATE] = mdata[FC.STATE]
424
497
  dims[FC.STATE] = mdata.dims[FC.STATE]
498
+ if FC.TURBINE not in data:
499
+ data[FC.TURBINE] = mdata[FC.TURBINE]
500
+ dims[FC.TURBINE] = mdata.dims[FC.TURBINE]
425
501
  if callback is not None:
426
502
  callback(data, dims)
427
503
 
@@ -453,7 +529,7 @@ class TData(Data):
453
529
  Arguments for the base class
454
530
 
455
531
  """
456
- super().__init__(*args, name=name, **kwargs)
532
+ super().__init__(*args, loop_dims=[FC.STATE, FC.TARGET], name=name, **kwargs)
457
533
 
458
534
  def _run_entry_checks(self, name, data, dims):
459
535
  """Run entry checks on new data"""
@@ -635,9 +711,7 @@ class TData(Data):
635
711
  for v in variables:
636
712
  data[v] = np.full_like(points[:, :, None, 0], np.nan)
637
713
  dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
638
- return cls(
639
- data=data, dims=dims, loop_dims=[FC.STATE, FC.TARGET], name=name, **kwargs
640
- )
714
+ return cls(data=data, dims=dims, name=name, **kwargs)
641
715
 
642
716
  @classmethod
643
717
  def from_tpoints(
@@ -694,9 +768,7 @@ class TData(Data):
694
768
  for v in variables:
695
769
  data[v] = np.full_like(tpoints[..., 0], np.nan)
696
770
  dims[v] = (FC.STATE, FC.TARGET, FC.TPOINT)
697
- return cls(
698
- data=data, dims=dims, loop_dims=[FC.STATE, FC.TARGET], name=name, **kwargs
699
- )
771
+ return cls(data=data, dims=dims, name=name, **kwargs)
700
772
 
701
773
  @classmethod
702
774
  def from_dataset(
@@ -764,7 +836,7 @@ class TData(Data):
764
836
  FC.TPOINT,
765
837
  ):
766
838
  raise ValueError(
767
- f"Expecting coordinates '{ (FC.STATE, FC.TARGET, FC.TPOINT)}' at positions 0-2 for data variable '{v}', got {dims[v]}"
839
+ f"Expecting coordinates '{(FC.STATE, FC.TARGET, FC.TPOINT)}' at positions 0-2 for data variable '{v}', got {dims[v]}"
768
840
  )
769
841
  else:
770
842
  data[v] = d[:, s_targets]
@@ -45,8 +45,10 @@ class DataCalcModel(Model):
45
45
  ----------
46
46
  algo: foxes.core.Algorithm
47
47
  The calculation algorithm
48
- data: tuple of foxes.core.Data
49
- The input data
48
+ data: tuple of foxes.core.Data, optional
49
+ The input data, typically either (mdata, fdata) in
50
+ the case of farm calculations, or (mdata, fdata, tdata)
51
+ for point data calculations
50
52
  parameters: dict, optional
51
53
  The calculation parameters
52
54
 
foxes/core/engine.py CHANGED
@@ -4,9 +4,8 @@ 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
- from foxes.config import config
10
9
  import foxes.constants as FC
11
10
 
12
11
  __global_engine_data__ = dict(
@@ -73,7 +72,7 @@ class Engine(ABC):
73
72
 
74
73
  def __enter__(self):
75
74
  if self.__entered:
76
- raise ValueError(f"Enter called for already entered engine")
75
+ raise ValueError("Enter called for already entered engine")
77
76
  self.__entered = True
78
77
  if not self.initialized:
79
78
  self.initialize()
@@ -81,7 +80,7 @@ class Engine(ABC):
81
80
 
82
81
  def __exit__(self, *exit_args):
83
82
  if not self.__entered:
84
- raise ValueError(f"Exit called for not entered engine")
83
+ raise ValueError("Exit called for not entered engine")
85
84
  self.__entered = False
86
85
  if self.initialized:
87
86
  self.finalize(*exit_args)
@@ -127,7 +126,6 @@ class Engine(ABC):
127
126
  raise ValueError(
128
127
  f"Cannot initialize engine '{type(self).__name__}', since engine already set to '{type(get_engine()).__name__}'"
129
128
  )
130
- global __global_engine_data__
131
129
  __global_engine_data__["engine"] = self
132
130
  self.__initialized = True
133
131
 
@@ -148,7 +146,6 @@ class Engine(ABC):
148
146
  if self.entered:
149
147
  self.__exit__(type, value, traceback)
150
148
  elif self.initialized:
151
- global __global_engine_data__
152
149
  __global_engine_data__["engine"] = None
153
150
  self.__initialized = False
154
151
 
@@ -304,9 +301,9 @@ class Engine(ABC):
304
301
  chunk_sizes_targets[-extra:] += 1
305
302
 
306
303
  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]}"
304
+ assert s == n_targets, (
305
+ f"Targets count mismatch: Expecting {n_targets}, chunks sum is {s}. Chunks: {[int(c) for c in chunk_sizes_targets]}"
306
+ )
310
307
 
311
308
  chunk_sizes_states = np.full(n_chunks_states, chunk_size_states)
312
309
  extra = n_states - n_chunks_states * chunk_size_states
@@ -314,9 +311,9 @@ class Engine(ABC):
314
311
  chunk_sizes_states[-extra:] += 1
315
312
 
316
313
  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]}"
314
+ assert s == n_states, (
315
+ f"States count mismatch: Expecting {n_states}, chunks sum is {s}. Chunks: {[int(c) for c in chunk_sizes_states]}"
316
+ )
320
317
 
321
318
  return chunk_sizes_states, chunk_sizes_targets
322
319
 
@@ -352,8 +349,9 @@ class Engine(ABC):
352
349
 
353
350
  Returns
354
351
  -------
355
- data: list of foxes.core.Data
356
- Either [mdata, fdata] or [mdata, fdata, tdata]
352
+ data: tuple of foxes.core.Data
353
+ The input data for the chunk calculation,
354
+ either (mdata, fdata) or (mdata, fdata, tdata)
357
355
 
358
356
  """
359
357
  # prepare:
@@ -372,53 +370,37 @@ class Engine(ABC):
372
370
  )
373
371
 
374
372
  # create fdata:
375
- if point_data is None:
376
-
377
- def cb(data, dims):
378
- n_states = i1_states - i0_states
379
- for o in set(out_vars).difference(data.keys()):
380
- data[o] = np.full(
381
- (n_states, algo.n_turbines), np.nan, dtype=config.dtype_double
382
- )
383
- dims[o] = (FC.STATE, FC.TURBINE)
384
-
373
+ if farm_data is not None:
374
+ fdata = FData.from_dataset(
375
+ farm_data,
376
+ mdata=mdata,
377
+ s_states=s_states,
378
+ callback=None,
379
+ states_i0=i0_states,
380
+ copy=True,
381
+ )
385
382
  else:
386
- cb = None
387
- fdata = FData.from_dataset(
388
- farm_data,
389
- mdata=mdata,
390
- s_states=s_states,
391
- callback=cb,
392
- loop_dims=[FC.STATE],
393
- states_i0=i0_states,
394
- copy=True,
395
- )
383
+ fdata = FData.from_mdata(
384
+ mdata=mdata,
385
+ states_i0=i0_states,
386
+ )
396
387
 
397
388
  # create tdata:
398
- tdata = None
399
- if point_data is not None:
400
-
401
- def cb(data, dims):
402
- n_states = i1_states - i0_states
403
- n_targets = i1_targets - i0_targets
404
- for o in set(out_vars).difference(data.keys()):
405
- data[o] = np.full(
406
- (n_states, n_targets, 1), np.nan, dtype=config.dtype_double
407
- )
408
- dims[o] = (FC.STATE, FC.TARGET, FC.TPOINT)
409
-
410
- tdata = TData.from_dataset(
389
+ tdata = (
390
+ TData.from_dataset(
411
391
  point_data,
412
392
  mdata=mdata,
413
393
  s_states=s_states,
414
394
  s_targets=s_targets,
415
- callback=cb,
416
- loop_dims=[FC.STATE, FC.TARGET],
395
+ callback=None,
417
396
  states_i0=i0_states,
418
397
  copy=True,
419
398
  )
399
+ if point_data is not None
400
+ else None
401
+ )
420
402
 
421
- return [d for d in [mdata, fdata, tdata] if d is not None]
403
+ return (mdata, fdata) if tdata is None else (mdata, fdata, tdata)
422
404
 
423
405
  def combine_results(
424
406
  self,
@@ -539,7 +521,14 @@ class Engine(ABC):
539
521
  )
540
522
 
541
523
  @abstractmethod
542
- def run_calculation(self, algo, model, model_data, farm_data, point_data=None):
524
+ def run_calculation(
525
+ self,
526
+ algo,
527
+ model,
528
+ model_data=None,
529
+ farm_data=None,
530
+ point_data=None,
531
+ ):
543
532
  """
544
533
  Runs the model calculation
545
534
 
@@ -547,12 +536,12 @@ class Engine(ABC):
547
536
  ----------
548
537
  algo: foxes.core.Algorithm
549
538
  The algorithm object
550
- model: foxes.core.DataCalcModel
539
+ model: foxes.core.DataCalcModel, optional
551
540
  The model that whose calculate function
552
541
  should be run
553
542
  model_data: xarray.Dataset
554
543
  The initial model data
555
- farm_data: xarray.Dataset
544
+ farm_data: xarray.Dataset, optional
556
545
  The initial farm data
557
546
  point_data: xarray.Dataset, optional
558
547
  The initial point data
@@ -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)