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
@@ -52,6 +52,18 @@ class FarmDataModel(DataCalcModel):
52
52
  """
53
53
  return []
54
54
 
55
+ def output_coords(self):
56
+ """
57
+ Gets the coordinates of all output arrays
58
+
59
+ Returns
60
+ -------
61
+ dims: tuple of str
62
+ The coordinates of all output arrays
63
+
64
+ """
65
+ return (FC.STATE, FC.TURBINE)
66
+
55
67
  def ensure_variables(self, algo, mdata, fdata):
56
68
  """
57
69
  Add variables to fdata, initialized with NaN
@@ -171,6 +183,9 @@ class FarmDataModelList(FarmDataModel):
171
183
  super().__init__()
172
184
  self.models = models
173
185
 
186
+ def __repr__(self):
187
+ return f"{type(self).__name__}({[m.name for m in self.models]})"
188
+
174
189
  def append(self, model):
175
190
  """
176
191
  Add a model to the list
foxes/core/model.py CHANGED
@@ -1,10 +1,8 @@
1
1
  import numpy as np
2
2
  from abc import ABC
3
3
  from itertools import count
4
- from copy import deepcopy
5
4
 
6
5
  import foxes.constants as FC
7
- from .data import Data
8
6
 
9
7
 
10
8
  class Model(ABC):
@@ -35,8 +33,8 @@ class Model(ABC):
35
33
  if self._id > 0:
36
34
  self.name += f"_instance{self._id}"
37
35
 
38
- self._store = {}
39
36
  self.__initialized = False
37
+ self.__running = False
40
38
 
41
39
  def __repr__(self):
42
40
  return f"{type(self).__name__}()"
@@ -119,6 +117,10 @@ class Model(ABC):
119
117
  and `coords`, a dict with entries `dim_name_str -> dim_array`
120
118
 
121
119
  """
120
+ if self.initialized:
121
+ raise ValueError(
122
+ f"Model '{self.name}': Cannot call load_data after initialization"
123
+ )
122
124
  return {"coords": {}, "data_vars": {}}
123
125
 
124
126
  def initialize(self, algo, verbosity=0, force=False):
@@ -135,6 +137,8 @@ class Model(ABC):
135
137
  Overwrite existing data
136
138
 
137
139
  """
140
+ if self.running:
141
+ raise ValueError(f"Model '{self.name}': Cannot initialize while running")
138
142
  if not self.initialized:
139
143
  pr = False
140
144
  for m in self.sub_models():
@@ -152,6 +156,103 @@ class Model(ABC):
152
156
 
153
157
  self.__initialized = True
154
158
 
159
+ @property
160
+ def running(self):
161
+ """
162
+ Flag for currently running models
163
+
164
+ Returns
165
+ -------
166
+ flag: bool
167
+ True if currently running
168
+
169
+ """
170
+ return self.__running
171
+
172
+ def set_running(
173
+ self,
174
+ algo,
175
+ data_stash,
176
+ sel=None,
177
+ isel=None,
178
+ verbosity=0,
179
+ ):
180
+ """
181
+ Sets this model status to running, and moves
182
+ all large data to stash.
183
+
184
+ The stashed data will be returned by the
185
+ unset_running() function after running calculations.
186
+
187
+ Parameters
188
+ ----------
189
+ algo: foxes.core.Algorithm
190
+ The calculation algorithm
191
+ data_stash: dict
192
+ Large data stash, this function adds data here.
193
+ Key: model name. Value: dict, large model data
194
+ sel: dict, optional
195
+ The subset selection dictionary
196
+ isel: dict, optional
197
+ The index subset selection dictionary
198
+ verbosity: int
199
+ The verbosity level, 0 = silent
200
+
201
+ """
202
+ if self.running:
203
+ raise ValueError(
204
+ f"Model '{self.name}': Cannot call set_running while running"
205
+ )
206
+ for m in self.sub_models():
207
+ if not m.running:
208
+ m.set_running(algo, data_stash, sel, isel, verbosity=verbosity)
209
+
210
+ if verbosity > 0:
211
+ print(f"Model '{self.name}': running")
212
+ if self.name not in data_stash:
213
+ data_stash[self.name] = {}
214
+
215
+ self.__running = True
216
+
217
+ def unset_running(
218
+ self,
219
+ algo,
220
+ data_stash,
221
+ sel=None,
222
+ isel=None,
223
+ verbosity=0,
224
+ ):
225
+ """
226
+ Sets this model status to not running, recovering large data
227
+ from stash
228
+
229
+ Parameters
230
+ ----------
231
+ algo: foxes.core.Algorithm
232
+ The calculation algorithm
233
+ data_stash: dict
234
+ Large data stash, this function adds data here.
235
+ Key: model name. Value: dict, large model data
236
+ sel: dict, optional
237
+ The subset selection dictionary
238
+ isel: dict, optional
239
+ The index subset selection dictionary
240
+ verbosity: int
241
+ The verbosity level, 0 = silent
242
+
243
+ """
244
+ if not self.running:
245
+ raise ValueError(
246
+ f"Model '{self.name}': Cannot call unset_running when not running"
247
+ )
248
+ for m in self.sub_models():
249
+ if m.running:
250
+ m.unset_running(algo, data_stash, sel, isel, verbosity=verbosity)
251
+
252
+ if verbosity > 0:
253
+ print(f"Model '{self.name}': not running")
254
+ self.__running = False
255
+
155
256
  def finalize(self, algo, verbosity=0):
156
257
  """
157
258
  Finalizes the model.
@@ -164,6 +265,8 @@ class Model(ABC):
164
265
  The verbosity level, 0 = silent
165
266
 
166
267
  """
268
+ if self.running:
269
+ raise ValueError(f"Model '{self.name}': Cannot finalize while running")
167
270
  if self.initialized:
168
271
  pr = False
169
272
  for m in self.sub_models():
@@ -178,7 +281,6 @@ class Model(ABC):
178
281
  print(f"Finalizing model '{self.name}'")
179
282
  algo.del_model_data(self)
180
283
 
181
- self._store = {}
182
284
  self.__initialized = False
183
285
 
184
286
  def get_data(
@@ -241,7 +343,7 @@ class Model(ABC):
241
343
  for s in sources:
242
344
  try:
243
345
  if a == "states_i0":
244
- out = s.states_i0(counter=True, algo=algo)
346
+ out = s.states_i0(counter=True)
245
347
  if out is not None:
246
348
  return out
247
349
  else:
@@ -353,6 +455,12 @@ class Model(ABC):
353
455
  if out is not None:
354
456
  break
355
457
 
458
+ # check for None:
459
+ if not accept_none and out is None:
460
+ raise ValueError(
461
+ f"Model '{self.name}': Variable '{variable}' is requested but not found."
462
+ )
463
+
356
464
  # cast dimensions:
357
465
  if out_dims != dims:
358
466
  if out_dims is None:
@@ -438,7 +546,12 @@ class Model(ABC):
438
546
  f"Model '{self.name}': Iteration data found for variable '{variable}', requiring algo"
439
547
  )
440
548
 
441
- i0 = _geta("states_i0")
549
+ from foxes.algorithms.sequential import Sequential
550
+
551
+ if isinstance(algo, Sequential):
552
+ i0 = algo.states.counter
553
+ else:
554
+ i0 = _geta("states_i0")
442
555
  sts = tdata[FC.STATES_SEL]
443
556
  if target == FC.STATE_TARGET and tdata.n_tpoints != 1:
444
557
  # find the mean index and round it to nearest integer:
@@ -446,27 +559,31 @@ class Model(ABC):
446
559
  sts = (sts + 0.5).astype(FC.ITYPE)
447
560
  sel = sts < i0
448
561
  if np.any(sel):
449
- if not hasattr(algo, "prev_farm_results"):
562
+ if not hasattr(algo, "farm_results_downwind"):
450
563
  raise KeyError(
451
564
  f"Model '{self.name}': Iteration data found for variable '{variable}', requiring iterative algorithm"
452
565
  )
453
- prev_fres = getattr(algo, "prev_farm_results")
566
+ prev_fres = getattr(algo, "farm_results_downwind")
454
567
  if prev_fres is not None:
455
568
  prev_data = prev_fres[variable].to_numpy()[sts[sel], downwind_index]
456
569
  if target == FC.STATE_TARGET:
457
570
  out[sel[:, :, 0]] = prev_data
458
571
  else:
459
572
  out[sel] = prev_data
460
- del prev_fres, prev_data
461
-
462
- # check for None:
463
- if not accept_none and out is None:
464
- raise ValueError(
465
- f"Model '{self.name}': Variable '{variable}' is requested but not found."
466
- )
573
+ del prev_data
574
+ del prev_fres
575
+ if np.any(~sel):
576
+ sts = sts[~sel] - i0
577
+ sel_data = fdata[variable][sts, downwind_index]
578
+ if target == FC.STATE_TARGET:
579
+ out[~sel[:, :, 0]] = sel_data
580
+ else:
581
+ out[~sel] = sel_data
582
+ del sel_data
583
+ del sel, sts
467
584
 
468
585
  # check for nan:
469
- elif not accept_nan:
586
+ if not accept_nan:
470
587
  try:
471
588
  if np.all(np.isnan(np.atleast_1d(out))):
472
589
  raise ValueError(
@@ -476,67 +593,3 @@ class Model(ABC):
476
593
  pass
477
594
 
478
595
  return out
479
-
480
- def data_to_store(self, name, algo, data):
481
- """
482
- Adds data from mdata to the local store, intended
483
- for iterative runs.
484
-
485
- Parameters
486
- ----------
487
- name: str
488
- The data name
489
- algo: foxes.core.Algorithm
490
- The algorithm
491
- data: foxes.utils.Data
492
- The mdata, fdata or pdata object
493
-
494
- """
495
- i0 = data.states_i0(counter=True, algo=algo)
496
- if i0 not in self._store:
497
- self._store[i0] = Data(
498
- data={}, dims={}, loop_dims=data.loop_dims, name=f"{self.name}_{i0}"
499
- )
500
-
501
- self._store[i0][name] = deepcopy(data[name])
502
- self._store[i0].dims[name] = (
503
- deepcopy(data.dims[name]) if name in data.dims else None
504
- )
505
-
506
- def from_data_or_store(self, name, algo, data, ret_dims=False, safe=False):
507
- """
508
- Get data from mdata or local store
509
-
510
- Parameters
511
- ----------
512
- name: str
513
- The data name
514
- algo: foxes.core.Algorithm
515
- The algorithm
516
- data: foxes.utils.Data
517
- The mdata, fdata or pdata object
518
- ret_dims: bool
519
- Return dimensions
520
- safe: bool
521
- Return None instead of error if
522
- not found
523
-
524
- Returns
525
- -------
526
- data: numpy.ndarray
527
- The data
528
- dims: tuple of dims, optional
529
- The data dimensions
530
-
531
- """
532
- if name in data:
533
- return (data[name], data.dims[name]) if ret_dims else data[name]
534
-
535
- i0 = data.states_i0(counter=True, algo=algo)
536
- if not safe or (i0 in self._store and name in self._store[i0]):
537
- if ret_dims:
538
- return self._store[i0][name], self._store[i0].dims[name]
539
- else:
540
- return self._store[i0][name]
541
- else:
542
- return (None, None) if ret_dims else None
@@ -27,6 +27,18 @@ class PointDataModel(DataCalcModel):
27
27
  """
28
28
  return []
29
29
 
30
+ def output_coords(self):
31
+ """
32
+ Gets the coordinates of all output arrays
33
+
34
+ Returns
35
+ -------
36
+ dims: tuple of str
37
+ The coordinates of all output arrays
38
+
39
+ """
40
+ return (FC.STATE, FC.TARGET, FC.TPOINT)
41
+
30
42
  def ensure_variables(self, algo, mdata, fdata, tdata):
31
43
  """
32
44
  Add variables to tdata, initialized with NaN
@@ -158,6 +170,9 @@ class PointDataModelList(PointDataModel):
158
170
  super().__init__()
159
171
  self.models = models
160
172
 
173
+ def __repr__(self):
174
+ return f"{type(self).__name__}({[m.name for m in self.models]})"
175
+
161
176
  def append(self, model):
162
177
  """
163
178
  Add a model to the list
foxes/core/rotor_model.py CHANGED
@@ -27,13 +27,13 @@ class RotorModel(FarmDataModel):
27
27
 
28
28
  """
29
29
 
30
- def __init__(self, calc_vars):
30
+ def __init__(self, calc_vars=None):
31
31
  """
32
32
  Constructor.
33
33
 
34
34
  Parameters
35
35
  ----------
36
- calc_vars: list of str
36
+ calc_vars: list of str, optional
37
37
  The variables that are calculated by the model
38
38
  (Their ambients are added automatically)
39
39
 
@@ -41,10 +41,6 @@ class RotorModel(FarmDataModel):
41
41
  super().__init__()
42
42
  self.calc_vars = calc_vars
43
43
 
44
- self.RPOINTS = self.var("rpoints")
45
- self.RWEIGHTS = self.var("rweights")
46
- self.AMBRES = self.var("amb_res")
47
-
48
44
  def output_farm_vars(self, algo):
49
45
  """
50
46
  The variables which are being modified by the model.
@@ -60,12 +56,21 @@ class RotorModel(FarmDataModel):
60
56
  The output variable names
61
57
 
62
58
  """
63
- return list(
64
- set(
65
- self.calc_vars
66
- + [FV.var2amb[v] for v in self.calc_vars if v in FV.var2amb]
67
- )
68
- )
59
+ if self.calc_vars is None:
60
+ vrs = algo.states.output_point_vars(algo)
61
+ if FV.WS in vrs:
62
+ self.calc_vars = [FV.REWS] + [v for v in vrs if v != FV.WS]
63
+ else:
64
+ self.calc_vars = vrs
65
+
66
+ if algo.farm_controller.needs_rews2() and FV.REWS2 not in self.calc_vars:
67
+ self.calc_vars.append(FV.REWS2)
68
+ if algo.farm_controller.needs_rews3() and FV.REWS3 not in self.calc_vars:
69
+ self.calc_vars.append(FV.REWS3)
70
+
71
+ self.calc_vars = sorted(self.calc_vars)
72
+
73
+ return self.calc_vars
69
74
 
70
75
  @abstractmethod
71
76
  def n_rotor_points(self):
@@ -207,6 +212,10 @@ class RotorModel(FarmDataModel):
207
212
  variables after calculation
208
213
 
209
214
  """
215
+ for v in [FV.REWS2, FV.REWS3]:
216
+ if v in fdata and v not in self.calc_vars:
217
+ self.calc_vars.append(v)
218
+
210
219
  uvp = None
211
220
  uv = None
212
221
  if (
@@ -348,11 +357,11 @@ class RotorModel(FarmDataModel):
348
357
  """
349
358
 
350
359
  if rpoints is None:
351
- rpoints = mdata.get(self.RPOINTS, self.get_rotor_points(algo, mdata, fdata))
360
+ rpoints = mdata.get(
361
+ FC.ROTOR_POINTS, self.get_rotor_points(algo, mdata, fdata)
362
+ )
352
363
  if store_rpoints:
353
- mdata[self.RPOINTS] = rpoints
354
- mdata.dims[self.RPOINTS] = (FC.STATE, FC.TURBINE, FC.TPOINT, FC.XYH)
355
- self.data_to_store(self.RPOINTS, algo, mdata)
364
+ algo.add_to_chunk_store(FC.ROTOR_POINTS, rpoints, mdata=mdata)
356
365
 
357
366
  if downwind_index is not None:
358
367
  rpoints = rpoints[:, downwind_index, None]
@@ -360,9 +369,7 @@ class RotorModel(FarmDataModel):
360
369
  if weights is None:
361
370
  weights = mdata.get(FC.TWEIGHTS, self.rotor_point_weights())
362
371
  if store_rweights:
363
- mdata[self.RWEIGHTS] = weights
364
- mdata.dims[self.RWEIGHTS] = (FC.TPOINT,)
365
- self.data_to_store(self.RWEIGHTS, algo, mdata)
372
+ algo.add_to_chunk_store(FC.ROTOR_WEIGHTS, weights, mdata=mdata)
366
373
 
367
374
  tdata = TData.from_tpoints(rpoints, weights)
368
375
  svars = algo.states.output_point_vars(algo)
@@ -377,8 +384,7 @@ class RotorModel(FarmDataModel):
377
384
  tdata.update(sres)
378
385
 
379
386
  if store_amb_res:
380
- mdata[self.AMBRES] = sres.copy()
381
- self.data_to_store(self.AMBRES, algo, mdata)
387
+ algo.add_to_chunk_store(FC.AMB_ROTOR_RES, sres.copy(), mdata=mdata)
382
388
 
383
389
  self.eval_rpoint_results(
384
390
  algo,
foxes/core/states.py CHANGED
@@ -61,6 +61,22 @@ class States(PointDataModel):
61
61
  """
62
62
  pass
63
63
 
64
+ def reset(self, algo=None, states_sel=None, states_loc=None, verbosity=0):
65
+ """
66
+ Reset the states, optionally select states
67
+
68
+ Parameters
69
+ ----------
70
+ states_sel: slice or range or list of int, optional
71
+ States subset selection
72
+ states_loc: list, optional
73
+ State index selection via pandas loc function
74
+ verbosity: int
75
+ The verbosity level, 0 = silent
76
+
77
+ """
78
+ raise NotImplementedError(f"States '{self.name}': Reset is not implemented")
79
+
64
80
  def load_data(self, algo, verbosity=0):
65
81
  """
66
82
  Load and/or create all model data that is subject to chunking.
@@ -1,3 +1,5 @@
1
+ from abc import abstractmethod
2
+
1
3
  import foxes.constants as FC
2
4
  from foxes.utils import all_subclasses
3
5
 
@@ -64,6 +66,32 @@ class TurbineType(TurbineModel):
64
66
  a = f"D={self.D}, H={self.H}, P_nominal={self.P_nominal}, P_unit={self.P_unit}"
65
67
  return f"{type(self).__name__}({a})"
66
68
 
69
+ @abstractmethod
70
+ def needs_rews2(self):
71
+ """
72
+ Returns flag for requirering REWS2 variable
73
+
74
+ Returns
75
+ -------
76
+ flag: bool
77
+ True if REWS2 is required
78
+
79
+ """
80
+ pass
81
+
82
+ @abstractmethod
83
+ def needs_rews3(self):
84
+ """
85
+ Returns flag for requirering REWS3 variable
86
+
87
+ Returns
88
+ -------
89
+ flag: bool
90
+ True if REWS3 is required
91
+
92
+ """
93
+ pass
94
+
67
95
  def modify_cutin(self, modify_ct, modify_P):
68
96
  """
69
97
  Modify the data such that a discontinuity
foxes/core/wake_frame.py CHANGED
@@ -6,7 +6,7 @@ from foxes.utils import all_subclasses
6
6
  import foxes.constants as FC
7
7
  import foxes.variables as FV
8
8
 
9
- from .data import MData, FData, TData
9
+ from .data import TData
10
10
  from .model import Model
11
11
 
12
12
 
@@ -21,10 +21,28 @@ class WakeFrame(Model):
21
21
  They are also responsible for the calculation of
22
22
  the turbine evaluation order.
23
23
 
24
+ Attributes
25
+ ----------
26
+ max_length_km: float
27
+ The maximal wake length in km
28
+
24
29
  :group: core
25
30
 
26
31
  """
27
32
 
33
+ def __init__(self, max_length_km=3e4):
34
+ """
35
+ Constructor.
36
+
37
+ Parameters
38
+ ----------
39
+ max_length_km: float
40
+ The maximal wake length in km
41
+
42
+ """
43
+ super().__init__()
44
+ self.max_length_km = max_length_km
45
+
28
46
  @abstractmethod
29
47
  def calc_order(self, algo, mdata, fdata):
30
48
  """ "
@@ -241,7 +259,7 @@ class WakeFrame(Model):
241
259
 
242
260
  # calc evaluation points:
243
261
  xmin = 0.0
244
- xmax = np.nanmax(x)
262
+ xmax = min(np.nanmax(x), self.max_length_km * 1e3)
245
263
  n_steps = int((xmax - xmin) / dx)
246
264
  if xmin + n_steps * dx < xmax:
247
265
  n_steps += 1
@@ -262,7 +280,7 @@ class WakeFrame(Model):
262
280
  res = algo.states.calculate(algo, mdata, fdata, tdata)
263
281
  tdata.update(res)
264
282
  amb2var = algo.get_model("SetAmbPointResults")()
265
- amb2var.initialize(algo, verbosity=0)
283
+ amb2var.initialize(algo, verbosity=0, force=True)
266
284
  res = amb2var.calculate(algo, mdata, fdata, tdata)
267
285
  tdata.update(res)
268
286
  del res, amb2var
@@ -277,7 +295,7 @@ class WakeFrame(Model):
277
295
  # calc wakes:
278
296
  if not ambient:
279
297
  wcalc = algo.get_model("PointWakesCalculation")(wake_models=wake_models)
280
- wcalc.initialize(algo, verbosity=0)
298
+ wcalc.initialize(algo, verbosity=0, force=True)
281
299
  wsrc = downwind_index if self_wake else None
282
300
  res = wcalc.calculate(algo, mdata, fdata, tdata, downwind_index=wsrc)
283
301
  tdata.update(res)
foxes/core/wake_model.py CHANGED
@@ -304,9 +304,8 @@ class WakeK(Model):
304
304
  The k array as returned by get_data
305
305
 
306
306
  """
307
- if self._k is not None:
308
- setattr(self, self.k_var, self._k)
309
- elif self._ka is not None or self._kb is not None:
307
+ setattr(self, self.k_var, self._k)
308
+ if self._ka is not None or self._kb is not None:
310
309
  if self.ti_var == FV.TI and ti is not None:
311
310
  pass
312
311
  elif self.ti_var == FV.AMB_TI and amb_ti is not None:
@@ -59,5 +59,27 @@ attributes:
59
59
  blockage_model:
60
60
  name: None
61
61
 
62
-
62
+ outputs:
63
+ output_folder: "results"
64
+ turbine_outputs:
65
+ turbine_nc_filename: 'turbine_data.nc' # dimension = states, turbine
66
+ output_variables: ['power', 'rotor_effective_velocity'] #'frequency'
67
+ #
68
+ flow_field:
69
+ report: True
70
+ flow_nc_filename: flow_field.nc
71
+ cases_run:
72
+ all_occurences: True
73
+ output_variables: ['wind_speed', 'wind_direction']
74
+ z_planes:
75
+ z_sampling: "hub_height"
76
+ xy_sampling: "default"
77
+ #
78
+ statistics:
79
+ stats_filename: None
80
+ AEP: False
81
+ AEP_per_turbine: False
82
+ power_percentiles:
83
+ report: False
84
+ percentiles: None
63
85
 
@@ -0,0 +1,16 @@
1
+ from .pool import PoolEngine
2
+ from .multiprocess import MultiprocessEngine
3
+ from .numpy import NumpyEngine
4
+ from .single import SingleChunkEngine
5
+ from .futures import ThreadsEngine, ProcessEngine
6
+ from .mpi import MPIEngine
7
+
8
+ from .dask import (
9
+ DaskBaseEngine,
10
+ XArrayEngine,
11
+ DaskEngine,
12
+ LocalClusterEngine,
13
+ SlurmClusterEngine,
14
+ )
15
+
16
+ from .default import DefaultEngine