foxes 0.8.1__py3-none-any.whl → 1.0__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 (175) hide show
  1. docs/source/conf.py +353 -0
  2. examples/abl_states/run.py +160 -0
  3. examples/compare_rotors_pwakes/run.py +217 -0
  4. examples/compare_wakes/run.py +241 -0
  5. examples/dyn_wakes/run.py +311 -0
  6. examples/field_data_nc/run.py +121 -0
  7. examples/induction_RHB/run.py +201 -0
  8. examples/multi_height/run.py +113 -0
  9. examples/power_mask/run.py +249 -0
  10. examples/random_timeseries/run.py +210 -0
  11. examples/scan_row/run.py +193 -0
  12. examples/sector_management/run.py +162 -0
  13. examples/sequential/run.py +209 -0
  14. examples/single_state/run.py +201 -0
  15. examples/states_lookup_table/run.py +137 -0
  16. examples/streamline_wakes/run.py +138 -0
  17. examples/tab_file/run.py +142 -0
  18. examples/timelines/run.py +267 -0
  19. examples/timeseries/run.py +183 -0
  20. examples/timeseries_slurm/run.py +185 -0
  21. examples/wind_rose/run.py +141 -0
  22. examples/windio/run.py +29 -0
  23. examples/yawed_wake/run.py +196 -0
  24. foxes/__init__.py +4 -8
  25. foxes/algorithms/__init__.py +1 -1
  26. foxes/algorithms/downwind/downwind.py +232 -101
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -6
  28. foxes/algorithms/downwind/models/init_farm_data.py +1 -1
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +5 -6
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +0 -1
  31. foxes/algorithms/downwind/models/set_amb_point_results.py +4 -2
  32. foxes/algorithms/iterative/iterative.py +73 -33
  33. foxes/algorithms/iterative/models/farm_wakes_calc.py +11 -6
  34. foxes/algorithms/sequential/models/plugin.py +1 -1
  35. foxes/algorithms/sequential/sequential.py +126 -255
  36. foxes/constants.py +17 -2
  37. foxes/core/__init__.py +1 -0
  38. foxes/core/algorithm.py +631 -146
  39. foxes/core/data.py +252 -20
  40. foxes/core/data_calc_model.py +13 -289
  41. foxes/core/engine.py +630 -0
  42. foxes/core/farm_controller.py +37 -9
  43. foxes/core/farm_data_model.py +15 -0
  44. foxes/core/model.py +133 -80
  45. foxes/core/point_data_model.py +15 -0
  46. foxes/core/rotor_model.py +27 -21
  47. foxes/core/states.py +16 -0
  48. foxes/core/turbine_type.py +28 -0
  49. foxes/core/wake_frame.py +22 -4
  50. foxes/core/wake_model.py +2 -3
  51. foxes/data/windio/windio_5turbines_timeseries.yaml +23 -1
  52. foxes/engines/__init__.py +16 -0
  53. foxes/engines/dask.py +975 -0
  54. foxes/engines/default.py +75 -0
  55. foxes/engines/futures.py +72 -0
  56. foxes/engines/mpi.py +38 -0
  57. foxes/engines/multiprocess.py +74 -0
  58. foxes/engines/numpy.py +185 -0
  59. foxes/engines/pool.py +263 -0
  60. foxes/engines/single.py +139 -0
  61. foxes/input/farm_layout/__init__.py +1 -0
  62. foxes/input/farm_layout/from_csv.py +4 -0
  63. foxes/input/farm_layout/from_json.py +1 -1
  64. foxes/input/farm_layout/grid.py +2 -2
  65. foxes/input/farm_layout/ring.py +65 -0
  66. foxes/input/farm_layout/row.py +2 -2
  67. foxes/input/states/__init__.py +6 -0
  68. foxes/input/states/create/random_abl_states.py +1 -1
  69. foxes/input/states/field_data_nc.py +157 -32
  70. foxes/input/states/multi_height.py +127 -13
  71. foxes/input/states/one_point_flow.py +577 -0
  72. foxes/input/states/scan_ws.py +73 -2
  73. foxes/input/states/states_table.py +204 -35
  74. foxes/input/windio/__init__.py +1 -1
  75. foxes/input/windio/get_states.py +44 -23
  76. foxes/input/windio/read_attributes.py +41 -16
  77. foxes/input/windio/read_farm.py +116 -102
  78. foxes/input/windio/read_fields.py +13 -6
  79. foxes/input/windio/read_outputs.py +63 -22
  80. foxes/input/windio/runner.py +31 -17
  81. foxes/input/windio/windio.py +36 -22
  82. foxes/models/ground_models/wake_mirror.py +8 -4
  83. foxes/models/model_book.py +29 -18
  84. foxes/models/partial_wakes/rotor_points.py +3 -3
  85. foxes/models/rotor_models/centre.py +4 -0
  86. foxes/models/rotor_models/grid.py +22 -23
  87. foxes/models/rotor_models/levels.py +4 -5
  88. foxes/models/turbine_models/calculator.py +0 -2
  89. foxes/models/turbine_models/lookup_table.py +27 -2
  90. foxes/models/turbine_models/rotor_centre_calc.py +4 -3
  91. foxes/models/turbine_models/set_farm_vars.py +103 -34
  92. foxes/models/turbine_types/PCt_file.py +24 -0
  93. foxes/models/turbine_types/PCt_from_two.py +24 -0
  94. foxes/models/turbine_types/__init__.py +1 -0
  95. foxes/models/turbine_types/lookup.py +316 -0
  96. foxes/models/turbine_types/null_type.py +50 -0
  97. foxes/models/turbine_types/wsrho2PCt_from_two.py +24 -0
  98. foxes/models/turbine_types/wsti2PCt_from_two.py +24 -0
  99. foxes/models/vertical_profiles/data_profile.py +1 -1
  100. foxes/models/wake_frames/__init__.py +1 -0
  101. foxes/models/wake_frames/dynamic_wakes.py +424 -0
  102. foxes/models/wake_frames/farm_order.py +23 -3
  103. foxes/models/wake_frames/rotor_wd.py +4 -2
  104. foxes/models/wake_frames/seq_dynamic_wakes.py +56 -63
  105. foxes/models/wake_frames/streamlines.py +19 -20
  106. foxes/models/wake_frames/timelines.py +328 -127
  107. foxes/models/wake_frames/yawed_wakes.py +4 -1
  108. foxes/models/wake_models/dist_sliced.py +1 -3
  109. foxes/models/wake_models/induction/rankine_half_body.py +4 -4
  110. foxes/models/wake_models/induction/rathmann.py +2 -2
  111. foxes/models/wake_models/induction/self_similar.py +2 -2
  112. foxes/models/wake_models/induction/vortex_sheet.py +2 -2
  113. foxes/models/wake_models/ti/iec_ti.py +34 -17
  114. foxes/models/wake_models/top_hat.py +1 -1
  115. foxes/models/wake_models/wind/bastankhah14.py +2 -2
  116. foxes/models/wake_models/wind/bastankhah16.py +8 -7
  117. foxes/models/wake_models/wind/jensen.py +1 -1
  118. foxes/models/wake_models/wind/turbopark.py +2 -2
  119. foxes/output/__init__.py +4 -1
  120. foxes/output/farm_layout.py +2 -2
  121. foxes/output/flow_plots_2d/__init__.py +0 -1
  122. foxes/output/flow_plots_2d/flow_plots.py +70 -30
  123. foxes/output/grids.py +91 -21
  124. foxes/output/seq_plugins/__init__.py +2 -0
  125. foxes/output/{flow_plots_2d → seq_plugins}/seq_flow_ani_plugin.py +62 -20
  126. foxes/output/seq_plugins/seq_wake_debug_plugin.py +145 -0
  127. foxes/output/slice_data.py +131 -111
  128. foxes/output/state_turbine_map.py +18 -13
  129. foxes/output/state_turbine_table.py +19 -19
  130. foxes/utils/__init__.py +1 -1
  131. foxes/utils/dev_utils.py +42 -0
  132. foxes/utils/dict.py +1 -1
  133. foxes/utils/factory.py +147 -52
  134. foxes/utils/pandas_helpers.py +4 -3
  135. foxes/utils/wind_dir.py +0 -2
  136. foxes/utils/xarray_utils.py +25 -13
  137. foxes/variables.py +37 -0
  138. {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/METADATA +72 -34
  139. foxes-1.0.dist-info/RECORD +307 -0
  140. {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/WHEEL +1 -1
  141. foxes-1.0.dist-info/top_level.txt +4 -0
  142. tests/0_consistency/iterative/test_iterative.py +92 -0
  143. tests/0_consistency/partial_wakes/test_partial_wakes.py +90 -0
  144. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +85 -0
  145. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +103 -0
  146. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +85 -0
  147. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +87 -0
  148. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +82 -0
  149. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +82 -0
  150. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/flappy/run.py +92 -0
  151. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +93 -0
  152. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/flappy/run.py +92 -0
  153. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +96 -0
  154. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/flappy/run.py +94 -0
  155. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +122 -0
  156. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/flappy/run.py +94 -0
  157. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +122 -0
  158. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/flappy/run.py +92 -0
  159. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +93 -0
  160. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +85 -0
  161. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +130 -0
  162. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/flappy/run.py +96 -0
  163. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +116 -0
  164. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +93 -0
  165. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +99 -0
  166. tests/3_examples/test_examples.py +34 -0
  167. foxes/VERSION +0 -1
  168. foxes/output/flow_plots_2d.py +0 -0
  169. foxes/utils/plotly_helpers.py +0 -19
  170. foxes/utils/runners/__init__.py +0 -1
  171. foxes/utils/runners/runners.py +0 -280
  172. foxes-0.8.1.dist-info/RECORD +0 -248
  173. foxes-0.8.1.dist-info/top_level.txt +0 -1
  174. foxes-0.8.1.dist-info/zip-safe +0 -1
  175. {foxes-0.8.1.dist-info → foxes-1.0.dist-info}/LICENSE +0 -0
@@ -1,15 +1,15 @@
1
1
  import numpy as np
2
2
  from xarray import Dataset
3
3
 
4
- from foxes.algorithms.downwind.downwind import Downwind
4
+ from foxes.algorithms import Iterative
5
5
  import foxes.constants as FC
6
6
  import foxes.variables as FV
7
- from foxes.core.data import MData, FData, TData
7
+ from foxes.core import get_engine
8
8
 
9
9
  from . import models as mdls
10
10
 
11
11
 
12
- class Sequential(Downwind):
12
+ class Sequential(Iterative):
13
13
  """
14
14
  A sequential calculation of states without chunking.
15
15
 
@@ -65,7 +65,6 @@ class Sequential(Downwind):
65
65
  points=None,
66
66
  ambient=False,
67
67
  calc_pars={},
68
- chunks={FC.STATE: None, FC.POINT: 4000},
69
68
  plugins=[],
70
69
  outputs=None,
71
70
  **kwargs,
@@ -88,8 +87,6 @@ class Sequential(Downwind):
88
87
  calc_pars: dict
89
88
  Parameters for model calculation.
90
89
  Key: model name str, value: parameter dict
91
- chunks: dict
92
- The xarray.Dataset chunk parameters
93
90
  plugins: list of foxes.algorithm.sequential.SequentialIterPlugin
94
91
  The plugins, updated with every iteration
95
92
  outputs: list of str, optional
@@ -98,7 +95,7 @@ class Sequential(Downwind):
98
95
  Additional arguments for Downwind
99
96
 
100
97
  """
101
- super().__init__(farm, mdls.SeqState(states), *args, chunks=chunks, **kwargs)
98
+ super().__init__(farm, mdls.SeqState(states), *args, **kwargs)
102
99
  self.ambient = ambient
103
100
  self.calc_pars = calc_pars
104
101
  self.states0 = self.states.states
@@ -106,6 +103,10 @@ class Sequential(Downwind):
106
103
  self.plugins = plugins
107
104
  self.outputs = outputs if outputs is not None else self.DEFAULT_FARM_OUTPUTS
108
105
 
106
+ self._verbo0 = self.verbosity + 1
107
+ self.verbosity -= 1
108
+ get_engine().verbosity -= 2
109
+
109
110
  self._i = None
110
111
 
111
112
  @property
@@ -121,6 +122,13 @@ class Sequential(Downwind):
121
122
  """
122
123
  return self._i is not None
123
124
 
125
+ def get_models_data(self, sel=None, isel=None):
126
+ if sel is not None and len(sel):
127
+ raise ValueError(f"calc_points does not support sel, got sel={sel}")
128
+ if isel is not None and len(isel):
129
+ raise ValueError(f"calc_points does not support isel, got isel={isel}")
130
+ return self._model_data.isel({FC.STATE: [self.counter]})
131
+
124
132
  def __iter__(self):
125
133
  """Initialize the iterator"""
126
134
 
@@ -134,62 +142,39 @@ class Sequential(Downwind):
134
142
  self._i = 0
135
143
  self._counter = 0
136
144
 
137
- self._mlist, self._calc_pars = self._collect_farm_models(
138
- self.outputs, self.calc_pars, self.ambient
145
+ self._it = 0
146
+ mlist, __ = self._collect_farm_models(
147
+ None, self.calc_pars, ambient=self.ambient
139
148
  )
140
- if not self._mlist.initialized:
141
- self._mlist.initialize(self, self.verbosity)
142
- self._calc_farm_vars(self._mlist)
143
- self._print_model_oder(self._mlist, self._calc_pars)
144
-
145
- self._mdata = self.get_models_idata()
146
- if self.verbosity > 0:
147
- s = "\n".join(
148
- [
149
- f" {v}: {d[0]} {d[1].dtype}, shape {d[1].shape}"
150
- for v, d in self._mdata["data_vars"].items()
151
- ]
152
- )
149
+ self._calc_farm_vars(mlist)
150
+ self._it = None
151
+
152
+ self._model_data = Dataset(**super().get_models_idata())
153
+
154
+ if self._verbo0 > 0:
153
155
  print("\nInput data:\n")
154
- print(s, "\n")
155
- print(f"Output farm variables:", ", ".join(self.farm_vars))
156
+ print(self._model_data)
157
+ print(f"\nOutput farm variables:", ", ".join(self.farm_vars))
156
158
  print()
157
159
 
158
- self._mdata = MData(
159
- data={v: d[1] for v, d in self._mdata["data_vars"].items()},
160
- dims={v: d[0] for v, d in self._mdata["data_vars"].items()},
161
- loop_dims=[FC.STATE],
162
- name="mdata",
163
- )
164
-
165
- self._fdata = FData(
166
- data={
167
- v: np.zeros((self.n_states, self.n_turbines), dtype=FC.DTYPE)
160
+ self._farm_results = Dataset(
161
+ coords={FC.STATE: self._model_data[FC.STATE].to_numpy()},
162
+ data_vars={
163
+ v: (
164
+ (FC.STATE, FC.TURBINE),
165
+ np.zeros_like(self._model_data[FV.WEIGHT].to_numpy()),
166
+ )
168
167
  for v in self.farm_vars
169
168
  },
170
- dims={v: (FC.STATE, FC.TURBINE) for v in self.farm_vars},
171
- loop_dims=[FC.STATE],
172
- name="fdata",
173
169
  )
174
-
175
- if self.points is not None:
176
- self._plist, self._calc_pars_p = self._collect_point_models(
177
- ambient=self.ambient
178
- )
179
- if not self._plist.initialized:
180
- self._plist.initialize(self, self.verbosity)
181
- self._pvars = self._plist.output_point_vars(self)
182
- self.print(f"\nOutput point variables:", ", ".join(self._pvars), "\n")
183
-
184
- n_points = self.points.shape[1]
185
- self._tdata = TData.from_points(
186
- self.points,
187
- data={
188
- v: np.zeros((self.n_states, n_points, 1), dtype=FC.DTYPE)
189
- for v in self._pvars
190
- },
191
- dims={v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in self._pvars},
170
+ self._farm_results[FC.TNAME] = ((FC.TURBINE,), self.farm.turbine_names)
171
+ if FV.ORDER in self._farm_results:
172
+ self._farm_results[FV.ORDER] = self._farm_results[FV.ORDER].astype(
173
+ FC.ITYPE
192
174
  )
175
+ self._farm_results_dwnd = self._farm_results.copy(deep=True)
176
+
177
+ self._point_results = None
193
178
 
194
179
  for p in self.plugins:
195
180
  p.initialize(self)
@@ -200,45 +185,29 @@ class Sequential(Downwind):
200
185
  """Run calculation for current step, then iterate to next"""
201
186
 
202
187
  if self._i < len(self._inds):
188
+
203
189
  self._counter = self._i
204
190
  self.states._counter = self._i
205
191
  self.states._size = 1
206
192
  self.states._indx = self._inds[self._i]
207
193
  self.states._weight = self._weights[self._i]
208
194
 
209
- mdata = MData(
210
- data={
211
- v: d[self._i, None] if self._mdata.dims[v][0] == FC.STATE else d
212
- for v, d in self._mdata.items()
213
- },
214
- dims={v: d for v, d in self._mdata.dims.items()},
215
- loop_dims=[FC.STATE],
216
- name="mdata",
217
- )
195
+ if self._verbo0 > 0:
196
+ print(f"{self.name}: Running state {self.states.index()[0]}")
218
197
 
219
- fdata = FData(
220
- data={
221
- v: np.zeros((1, self.n_turbines), dtype=FC.DTYPE)
222
- for v in self.farm_vars
223
- },
224
- dims={v: (FC.STATE, FC.TURBINE) for v in self.farm_vars},
225
- loop_dims=[FC.STATE],
226
- name="fdata",
198
+ fres, fres_dnwnd = super().calc_farm(
199
+ outputs=self.farm_vars,
200
+ finalize=False,
201
+ ret_dwnd_order=True,
202
+ **self.calc_pars,
227
203
  )
228
204
 
229
- fres = self._mlist.calculate(self, mdata, fdata, parameters=self._calc_pars)
230
- fres[FV.WEIGHT] = self.weight[None, :]
231
-
232
- for v, d in fres.items():
233
- self._fdata[v][self._i] = d[0]
234
-
235
- fres = Dataset(
236
- coords={FC.STATE: [self.index]},
237
- data_vars={v: ((FC.STATE, FC.TURBINE), d) for v, d in fres.items()},
238
- )
239
- fres[FC.TNAME] = ((FC.TURBINE,), self.farm.turbine_names)
240
- if FV.ORDER in fres:
241
- fres[FV.ORDER] = fres[FV.ORDER].astype(FC.ITYPE)
205
+ for v in self._farm_results.data_vars.keys():
206
+ if FC.STATE in self._farm_results[v].dims:
207
+ self._farm_results[v].loc[{FC.STATE: [self.index]}] = fres[v]
208
+ self._farm_results_dwnd[v].loc[{FC.STATE: [self.index]}] = (
209
+ fres_dnwnd[v]
210
+ )
242
211
 
243
212
  if self.points is None:
244
213
  for p in self.plugins:
@@ -248,30 +217,31 @@ class Sequential(Downwind):
248
217
  return fres
249
218
 
250
219
  else:
251
- n_points = self.points.shape[1]
252
- tdata = TData.from_points(
253
- self.points[self.counter, None],
254
- data={
255
- v: np.zeros((1, n_points, 1), dtype=FC.DTYPE)
256
- for v in self._pvars
257
- },
258
- dims={v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in self._pvars},
259
- )
260
-
261
- pres = self._plist.calculate(
262
- self, mdata, fdata, tdata, parameters=self._calc_pars_p
263
- )
264
-
265
- for v, d in pres.items():
266
- self._tdata[v][self._i] = d[0]
267
-
268
- pres = Dataset(
269
- coords={FC.STATE: [self.index]},
270
- data_vars={
271
- v: ((FC.STATE, FC.TARGET, FC.TPOINT), d)
272
- for v, d in pres.items()
273
- },
274
- )
220
+ pres = super().calc_points(fres, points=self.points, finalize=False)
221
+
222
+ if self._point_results is None:
223
+ n_states = self._model_data.sizes[FC.STATE]
224
+ self._point_results = Dataset(
225
+ coords={
226
+ FC.STATE: self._model_data[FC.STATE].to_numpy(),
227
+ **{c: d for c, d in pres.coords.items() if c != FC.STATE},
228
+ },
229
+ data_vars={
230
+ v: (
231
+ d.dims,
232
+ np.zeros([n_states] + list(d.shape[1:]), dtype=d.dtype),
233
+ )
234
+ for v, d in pres.data_vars.items()
235
+ if d.dims[0] == FC.STATE
236
+ },
237
+ )
238
+ for v, d in pres.data_vars.items():
239
+ if FC.STATE not in d.dims:
240
+ self._point_results[v] = d
241
+
242
+ for v in self._point_results.data_vars.keys():
243
+ if FC.STATE in self._point_results[v].dims:
244
+ self._point_results[v].loc[{FC.STATE: [self.index]}] = pres[v]
275
245
 
276
246
  for p in self.plugins:
277
247
  p.update(self, fres, pres)
@@ -280,7 +250,7 @@ class Sequential(Downwind):
280
250
  return fres, pres
281
251
 
282
252
  else:
283
- del self._mdata
253
+ del self._model_data
284
254
 
285
255
  self._i = None
286
256
  self.states._counter = None
@@ -365,45 +335,6 @@ class Sequential(Downwind):
365
335
  """
366
336
  return self.states._weight if self.iterating else None
367
337
 
368
- @property
369
- def mdata(self):
370
- """
371
- Get the current model data
372
-
373
- Returns
374
- -------
375
- d: foxes.core.MData
376
- The current model data
377
-
378
- """
379
- return self._mdata if self.iterating else None
380
-
381
- @property
382
- def fdata(self):
383
- """
384
- Get the current farm data
385
-
386
- Returns
387
- -------
388
- d: foxes.core.FData
389
- The current farm data
390
-
391
- """
392
- return self._fdata
393
-
394
- @property
395
- def tdata(self):
396
- """
397
- Get the current point data
398
-
399
- Returns
400
- -------
401
- d: foxes.core.TData
402
- The current point data
403
-
404
- """
405
- return self._tdata if self.points is not None and self.iterating else None
406
-
407
338
  @property
408
339
  def farm_results(self):
409
340
  """
@@ -415,21 +346,13 @@ class Sequential(Downwind):
415
346
  The overall farm results
416
347
 
417
348
  """
418
- results = Dataset(
419
- coords={FC.STATE: self._inds, FC.TURBINE: np.arange(self.n_turbines)},
420
- data_vars={v: (self._fdata.dims[v], d) for v, d in self._fdata.items()},
421
- )
422
-
423
- results[FC.TNAME] = ((FC.TURBINE,), self.farm.turbine_names)
424
- if FV.ORDER in results:
425
- results[FV.ORDER] = results[FV.ORDER].astype(FC.ITYPE)
426
-
427
- return results
349
+ return self._farm_results
428
350
 
429
351
  @property
430
- def prev_farm_results(self):
352
+ def farm_results_downwind(self):
431
353
  """
432
- Alias for farm_results
354
+ The overall farm results, with turbine
355
+ dimension in downwind order
433
356
 
434
357
  Returns
435
358
  -------
@@ -437,7 +360,7 @@ class Sequential(Downwind):
437
360
  The overall farm results
438
361
 
439
362
  """
440
- return self.farm_results
363
+ return self._farm_results_dwnd
441
364
 
442
365
  @property
443
366
  def cur_farm_results(self):
@@ -450,20 +373,7 @@ class Sequential(Downwind):
450
373
  The current farm results
451
374
 
452
375
  """
453
-
454
- i = self.counter
455
- results = Dataset(
456
- coords={FC.STATE: [self.index], FC.TURBINE: np.arange(self.n_turbines)},
457
- data_vars={
458
- v: (self._fdata.dims[v], d[i, None]) for v, d in self._fdata.items()
459
- },
460
- )
461
-
462
- results[FC.TNAME] = ((FC.TURBINE,), self.farm.turbine_names)
463
- if FV.ORDER in results:
464
- results[FV.ORDER] = results[FV.ORDER].astype(FC.ITYPE)
465
-
466
- return results
376
+ return self._farm_results.isel({FC.STATE: [self.counter]})
467
377
 
468
378
  @property
469
379
  def point_results(self):
@@ -476,18 +386,7 @@ class Sequential(Downwind):
476
386
  The overall point results
477
387
 
478
388
  """
479
- n_points = self.points.shape[1]
480
- results = Dataset(
481
- coords={
482
- FC.STATE: self._inds,
483
- FC.TURBINE: np.arange(self.n_turbines),
484
- FC.POINT: np.arange(n_points),
485
- FC.XYH: np.arange(3),
486
- },
487
- data_vars={v: (self._tdata.dims[v], d) for v, d in self._tdata.items()},
488
- )
489
-
490
- return results
389
+ return self._point_results
491
390
 
492
391
  @property
493
392
  def cur_point_results(self):
@@ -500,80 +399,52 @@ class Sequential(Downwind):
500
399
  The current point results
501
400
 
502
401
  """
402
+ return self._point_results.isel({FC.STATE: [self.counter]})
503
403
 
504
- n_points = self.points.shape[1]
505
- i = self.counter
506
-
507
- results = Dataset(
508
- coords={
509
- FC.STATE: [self.index],
510
- FC.TURBINE: np.arange(self.n_turbines),
511
- FC.POINT: np.arange(n_points),
512
- FC.XYH: np.arange(3),
513
- },
514
- data_vars={
515
- v: (self._tdata.dims[v], d[i, None]) for v, d in self._tdata.items()
516
- },
517
- )
404
+ def calc_farm(self):
405
+ """
406
+ Calculate farm data.
518
407
 
519
- return results
408
+ Returns
409
+ -------
410
+ farm_results: xarray.Dataset
411
+ The farm results. The calculated variables have
412
+ dimensions (state, turbine)
520
413
 
521
- def calc_farm(self, *args, **kwargs):
414
+ """
522
415
  if not self.iterating:
523
416
  raise ValueError(f"calc_farm call is only allowed during iterations")
524
-
525
417
  return self.cur_farm_results
526
418
 
527
- def calc_points(self, farm_results, points):
419
+ def calc_points(
420
+ self,
421
+ farm_results,
422
+ points,
423
+ **kwargs,
424
+ ):
425
+ """
426
+ Calculate data at a given set of points.
427
+
428
+ Parameters
429
+ ----------
430
+ farm_results: xarray.Dataset
431
+ The farm results. The calculated variables have
432
+ dimensions (state, turbine)
433
+ points: numpy.ndarray
434
+ The points of interest, shape: (n_states, n_points, 3)
435
+ states_sel: list, optional
436
+ Reduce to selected states
437
+ states_isel: list, optional
438
+ Reduce to the selected states indices
439
+
440
+ Returns
441
+ -------
442
+ point_results: xarray.Dataset
443
+ The point results. The calculated variables have
444
+ dimensions (state, point)
445
+
446
+ """
528
447
  if not self.iterating:
529
448
  raise ValueError(f"calc_points call is only allowed during iterations")
530
449
 
531
- n_points = points.shape[1]
532
-
533
- plist, calc_pars = self._collect_point_models(ambient=self.ambient)
534
- if not plist.initialized:
535
- plist.initialize(self, self.verbosity)
536
- pvars = plist.output_point_vars(self)
537
-
538
- mdata = self.get_models_idata()
539
- mdata = MData(
540
- data={v: d[1] for v, d in mdata["data_vars"].items()},
541
- dims={v: d[0] for v, d in mdata["data_vars"].items()},
542
- loop_dims=[FC.STATE],
543
- name="mdata",
544
- )
545
- mdata = MData(
546
- data={
547
- v: d[self.states.counter, None] if mdata.dims[v][0] == FC.STATE else d
548
- for v, d in mdata.items()
549
- },
550
- dims={v: d for v, d in mdata.dims.items()},
551
- loop_dims=[FC.STATE],
552
- name="mdata",
553
- )
554
-
555
- fdata = FData(
556
- data={v: farm_results[v].to_numpy() for v in self.farm_vars},
557
- dims={v: (FC.STATE, FC.TURBINE) for v in self.farm_vars},
558
- loop_dims=[FC.STATE],
559
- name="fdata",
560
- )
561
-
562
- tdata = TData.from_points(
563
- points[0, None],
564
- data={v: np.zeros((1, n_points, 1), dtype=FC.DTYPE) for v in pvars},
565
- dims={v: (FC.STATE, FC.TARGET, FC.TPOINT) for v in pvars},
566
- name="tdata",
567
- )
568
-
569
- pres = plist.calculate(self, mdata, fdata, tdata, parameters=calc_pars)
570
- pres = Dataset(
571
- coords={FC.STATE: self.states.index()},
572
- data_vars={
573
- v: ((FC.STATE, FC.TARGET, FC.TPOINT), d) for v, d in pres.items()
574
- },
575
- )
576
-
577
- # plist.finalize(self, self.verbosity)
578
-
579
- return pres
450
+ return super().calc_points(farm_results, points, finalize=False, **kwargs)
foxes/constants.py CHANGED
@@ -65,8 +65,18 @@ POINTS = "points"
65
65
  :group: foxes.constants
66
66
  """
67
67
 
68
- AMB_TARGET_RESULTS = "amb_target_res"
69
- """ Identifier for ambient target results
68
+
69
+ ROTOR_POINTS = "rotor_points"
70
+ """ Identifier for rotor points
71
+ :group: foxes.constants
72
+ """
73
+
74
+ ROTOR_WEIGHTS = "rotor_weights"
75
+ """ Identifier for rotor point weights
76
+ :group: foxes.constants
77
+ """
78
+ AMB_ROTOR_RES = "amb_rotor_res"
79
+ """ Identifier for ambient rotor point results
70
80
  :group: foxes.constants
71
81
  """
72
82
 
@@ -126,6 +136,11 @@ ITYPE = np.int64
126
136
  :group: foxes.constants
127
137
  """
128
138
 
139
+ BLOCK_CONVERGENCE = "block_convergence"
140
+ """Identifier for convergence blocking signal
141
+ :group: foxes.constants
142
+ """
143
+
129
144
 
130
145
  KAPPA = 0.41
131
146
  """ The Van-Karman constant
foxes/core/__init__.py CHANGED
@@ -5,6 +5,7 @@ Abstract classes and core functionality.
5
5
  from .data import Data, MData, FData, TData
6
6
  from .model import Model
7
7
  from .data_calc_model import DataCalcModel
8
+ from .engine import Engine, get_engine, has_engine, reset_engine
8
9
  from .states import States, ExtendedStates
9
10
  from .wind_farm import WindFarm
10
11
  from .algorithm import Algorithm