foxes 1.2.5__py3-none-any.whl → 1.3__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 (52) hide show
  1. examples/quickstart/run.py +17 -0
  2. foxes/__init__.py +1 -1
  3. foxes/algorithms/downwind/downwind.py +9 -15
  4. foxes/algorithms/downwind/models/farm_wakes_calc.py +13 -7
  5. foxes/algorithms/downwind/models/init_farm_data.py +4 -4
  6. foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
  7. foxes/algorithms/downwind/models/set_amb_point_results.py +1 -1
  8. foxes/algorithms/iterative/models/farm_wakes_calc.py +6 -3
  9. foxes/algorithms/sequential/models/seq_state.py +0 -18
  10. foxes/algorithms/sequential/sequential.py +5 -18
  11. foxes/constants.py +6 -0
  12. foxes/core/data.py +44 -18
  13. foxes/core/engine.py +19 -1
  14. foxes/core/farm_data_model.py +1 -0
  15. foxes/core/rotor_model.py +42 -38
  16. foxes/core/states.py +2 -47
  17. foxes/input/states/__init__.py +1 -0
  18. foxes/input/states/field_data_nc.py +39 -61
  19. foxes/input/states/multi_height.py +31 -54
  20. foxes/input/states/one_point_flow.py +22 -21
  21. foxes/input/states/scan.py +6 -19
  22. foxes/input/states/single.py +5 -17
  23. foxes/input/states/states_table.py +15 -37
  24. foxes/input/states/wrg_states.py +148 -36
  25. foxes/models/partial_wakes/rotor_points.py +8 -2
  26. foxes/models/partial_wakes/segregated.py +9 -4
  27. foxes/models/rotor_models/centre.py +6 -4
  28. foxes/models/wake_frames/seq_dynamic_wakes.py +5 -2
  29. foxes/models/wake_frames/timelines.py +10 -0
  30. foxes/output/farm_layout.py +12 -4
  31. foxes/output/farm_results_eval.py +36 -12
  32. foxes/output/rose_plot.py +20 -2
  33. foxes/output/slice_data.py +16 -19
  34. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/METADATA +10 -8
  35. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/RECORD +52 -51
  36. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/WHEEL +1 -1
  37. tests/0_consistency/iterative/test_iterative.py +2 -3
  38. tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
  39. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
  40. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
  41. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -2
  42. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -3
  43. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -3
  44. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -3
  45. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -3
  46. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
  47. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -2
  48. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -3
  49. tests/3_examples/test_examples.py +3 -2
  50. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/LICENSE +0 -0
  51. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/entry_points.txt +0 -0
  52. {foxes-1.2.5.dist-info → foxes-1.3.dist-info}/top_level.txt +0 -0
@@ -91,7 +91,7 @@ class MultiHeightStates(States):
91
91
  """
92
92
  super().__init__()
93
93
 
94
- self.ovars = output_vars
94
+ self.ovars = list(output_vars)
95
95
  self.heights = np.array(heights, dtype=config.dtype_double)
96
96
  self.rpars = pd_read_pars
97
97
  self.var2col = var2col
@@ -102,7 +102,6 @@ class MultiHeightStates(States):
102
102
 
103
103
  self._data_source = data_source
104
104
  self._solo = None
105
- self._weights = None
106
105
  self._inds = None
107
106
  self._N = None
108
107
 
@@ -213,9 +212,7 @@ class MultiHeightStates(States):
213
212
  print(f"States '{self.name}': Reading file {self.data_source}")
214
213
  rpars = dict(self.RDICT, **self.rpars)
215
214
  data = PandasFileHelper().read_file(self.data_source, **rpars)
216
- isorg = False
217
215
  else:
218
- isorg = True
219
216
  data = self.data_source
220
217
 
221
218
  if self.states_sel is not None:
@@ -227,34 +224,31 @@ class MultiHeightStates(States):
227
224
  self._inds = data.index.to_numpy()
228
225
 
229
226
  col_w = self.var2col.get(FV.WEIGHT, FV.WEIGHT)
230
- self._weights = np.zeros((self._N, algo.n_turbines), dtype=config.dtype_double)
227
+ weights = None
231
228
  if col_w in data:
232
- self._weights[:] = data[col_w].to_numpy()[:, None]
229
+ weights = data[col_w].to_numpy()
233
230
  elif FV.WEIGHT in self.var2col:
234
231
  raise KeyError(
235
232
  f"Weight variable '{col_w}' defined in var2col, but not found in states table columns {data.columns}"
236
233
  )
237
- else:
238
- self._weights[:] = 1.0 / self._N
239
- if isorg:
240
- data = data.copy()
241
- data[col_w] = self._weights[:, 0]
242
234
 
243
235
  cols = []
244
236
  cmap = {}
245
237
  self._solo = {}
246
238
  for v in self.ovars:
247
- vcols = self._find_cols(v, data.columns)
248
- if len(vcols) == 1:
249
- self._solo[v] = data[vcols[0]].to_numpy()
250
- elif len(vcols) > 1:
251
- cmap[v] = (len(cols), len(cols) + len(vcols))
252
- cols += vcols
239
+ if v != FV.WEIGHT:
240
+ vcols = self._find_cols(v, data.columns)
241
+ if len(vcols) == 1:
242
+ self._solo[v] = data[vcols[0]].to_numpy()
243
+ elif len(vcols) > 1:
244
+ cmap[v] = (len(cols), len(cols) + len(vcols))
245
+ cols += vcols
253
246
  data = data[cols]
254
247
 
255
248
  self.H = self.var(FV.H)
256
249
  self.VARS = self.var("vars")
257
250
  self.DATA = self.var("data")
251
+ self.WEIGHT = self.var(FV.WEIGHT)
258
252
 
259
253
  idata = super().load_data(algo, verbosity)
260
254
 
@@ -268,7 +262,8 @@ class MultiHeightStates(States):
268
262
  dims,
269
263
  data.to_numpy().reshape(self._N, n_vrs, n_hts),
270
264
  )
271
-
265
+ if weights is not None:
266
+ idata["data_vars"][self.WEIGHT] = ((FC.STATE,), weights)
272
267
  for v, d in self._solo.items():
273
268
  idata["data_vars"][self.var(v)] = ((FC.STATE,), d)
274
269
  self._solo = list(self._solo.keys())
@@ -309,10 +304,9 @@ class MultiHeightStates(States):
309
304
 
310
305
  data_stash[self.name] = dict(
311
306
  data_source=self._data_source,
312
- weights=self._weights,
313
307
  inds=self._inds,
314
308
  )
315
- del self._data_source, self._weights, self._inds
309
+ del self._data_source, self._inds
316
310
 
317
311
  def unset_running(
318
312
  self,
@@ -345,7 +339,6 @@ class MultiHeightStates(States):
345
339
 
346
340
  data = data_stash[self.name]
347
341
  self._data_source = data.pop("data_source")
348
- self._weights = data.pop("weights")
349
342
  self._inds = data.pop("inds")
350
343
 
351
344
  def size(self):
@@ -391,27 +384,6 @@ class MultiHeightStates(States):
391
384
  """
392
385
  return self.ovars
393
386
 
394
- def weights(self, algo):
395
- """
396
- The statistical weights of all states.
397
-
398
- Parameters
399
- ----------
400
- algo: foxes.core.Algorithm
401
- The calculation algorithm
402
-
403
- Returns
404
- -------
405
- weights: numpy.ndarray
406
- The weights, shape: (n_states, n_turbines)
407
-
408
- """
409
- if self.running:
410
- raise ValueError(
411
- f"States '{self.name}': Cannot access weights while running"
412
- )
413
- return self._weights
414
-
415
387
  def calculate(self, algo, mdata, fdata, tdata):
416
388
  """
417
389
  The main model calculation.
@@ -512,6 +484,15 @@ class MultiHeightStates(States):
512
484
  else:
513
485
  results[v] = ires[vrs.index(v)]
514
486
 
487
+ # add weights:
488
+ if self.WEIGHT in mdata:
489
+ tdata[FV.WEIGHT] = mdata[self.WEIGHT][:, None, None]
490
+ else:
491
+ tdata[FV.WEIGHT] = np.full(
492
+ (mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
493
+ )
494
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
495
+
515
496
  return results
516
497
 
517
498
  def finalize(self, algo, verbosity=0):
@@ -528,7 +509,6 @@ class MultiHeightStates(States):
528
509
  """
529
510
  super().finalize(algo, verbosity)
530
511
  self._solo = None
531
- self._weights = None
532
512
  self._N = None
533
513
 
534
514
 
@@ -658,30 +638,25 @@ class MultiHeightNCStates(MultiHeightStates):
658
638
  self._inds = format_times_func(self._inds)
659
639
 
660
640
  w_name = self.var2col.get(FV.WEIGHT, FV.WEIGHT)
661
- self._weights = np.zeros((self._N, algo.n_turbines), dtype=config.dtype_double)
641
+ weights = None
662
642
  if w_name in data.data_vars:
663
643
  if data[w_name].dims != (self.state_coord,):
664
644
  raise ValueError(
665
645
  f"Weights data '{w_name}': Expecting dims ({self.state_coord},), got {data[w_name]}"
666
646
  )
667
- self._weights[:] = data.data_vars[w_name].to_numpy()[:, None]
647
+ weights = data.data_vars[w_name].to_numpy()
668
648
  elif FV.WEIGHT in self.var2col:
669
649
  raise KeyError(
670
650
  f"Weight variable '{w_name}' defined in var2col, but not found in data_vars {list(data.data_vars.keys())}"
671
651
  )
672
- else:
673
- self._weights = np.zeros(
674
- (self._N, algo.n_turbines), dtype=config.dtype_double
675
- )
676
- self._weights[:] = 1.0 / self._N
677
652
 
678
653
  cols = {}
679
654
  self._solo = {}
680
655
  for v in self.ovars:
656
+ if v in self.fixed_vars or v == FV.WEIGHT:
657
+ continue
681
658
  c = self.var2col.get(v, v)
682
- if c in self.fixed_vars:
683
- pass
684
- elif c in data.attrs:
659
+ if c in data.attrs:
685
660
  self._solo[v] = np.full(self._N, data.attrs)
686
661
  elif c in data.data_vars:
687
662
  if data[c].dims == (self.state_coord,):
@@ -705,6 +680,7 @@ class MultiHeightNCStates(MultiHeightStates):
705
680
  self.H = self.var(FV.H)
706
681
  self.VARS = self.var("vars")
707
682
  self.DATA = self.var("data")
683
+ self.WEIGHT = self.var(FV.WEIGHT)
708
684
 
709
685
  idata = States.load_data(self, algo, verbosity)
710
686
  idata["coords"][self.H] = self.heights
@@ -717,7 +693,8 @@ class MultiHeightNCStates(MultiHeightStates):
717
693
  [data.data_vars[c].to_numpy() for c in cols.values()], axis=1
718
694
  ).astype(config.dtype_double),
719
695
  )
720
-
696
+ if weights is not None:
697
+ idata["data_vars"][self.WEIGHT] = ((FC.STATE,), weights)
721
698
  for v, d in self._solo.items():
722
699
  idata["data_vars"][self.var(v)] = (
723
700
  (FC.STATE,),
@@ -101,9 +101,13 @@ class OnePointFlowStates(States):
101
101
  """
102
102
  return [self.base_states]
103
103
 
104
- def initialize(self, algo, verbosity=0):
104
+ def load_data(self, algo, verbosity=0):
105
105
  """
106
- Initializes the model.
106
+ Load and/or create all model data that is subject to chunking.
107
+
108
+ Such data should not be stored under self, for memory reasons. The
109
+ data returned here will automatically be chunked and then provided
110
+ as part of the mdata object during calculations.
107
111
 
108
112
  Parameters
109
113
  ----------
@@ -112,8 +116,14 @@ class OnePointFlowStates(States):
112
116
  verbosity: int
113
117
  The verbosity level, 0 = silent
114
118
 
119
+ Returns
120
+ -------
121
+ idata: dict
122
+ The dict has exactly two entries: `data_vars`,
123
+ a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
124
+ and `coords`, a dict with entries `dim_name_str -> dim_array`
125
+
115
126
  """
116
- super().initialize(algo, verbosity)
117
127
 
118
128
  # find heights:
119
129
  if self.heights is None:
@@ -127,10 +137,14 @@ class OnePointFlowStates(States):
127
137
  )
128
138
 
129
139
  # pre-calc data:
130
- Timelines._precalc_data(
140
+ self.WEIGHT = self.var(FV.WEIGHT)
141
+ idata = super().load_data(algo, verbosity)
142
+ idata["data_vars"][self.WEIGHT] = Timelines._precalc_data(
131
143
  self, algo, self.base_states, self.heights, verbosity, needs_res=True
132
144
  )
133
145
 
146
+ return idata
147
+
134
148
  def size(self):
135
149
  """
136
150
  The total number of states.
@@ -172,23 +186,6 @@ class OnePointFlowStates(States):
172
186
  """
173
187
  return self.base_states.output_point_vars(algo)
174
188
 
175
- def weights(self, algo):
176
- """
177
- The statistical weights of all states.
178
-
179
- Parameters
180
- ----------
181
- algo: foxes.core.Algorithm
182
- The calculation algorithm
183
-
184
- Returns
185
- -------
186
- weights: numpy.ndarray
187
- The weights, shape: (n_states, n_turbines)
188
-
189
- """
190
- return self.base_states.weights(algo)
191
-
192
189
  def set_running(
193
190
  self,
194
191
  algo,
@@ -488,6 +485,10 @@ class OnePointFlowStates(States):
488
485
  results = {FV.WD: uv2wd(uv), FV.WS: np.linalg.norm(uv, axis=-1)}
489
486
  del uv
490
487
 
488
+ # set weights:
489
+ tdata[FV.WEIGHT] = mdata[self.WEIGHT][:, None, None]
490
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
491
+
491
492
  return {
492
493
  v: d.reshape(n_states, n_targets, n_tpoints) for v, d in results.items()
493
494
  }
@@ -176,25 +176,6 @@ class ScanStates(States):
176
176
  """
177
177
  return self._vars
178
178
 
179
- def weights(self, algo):
180
- """
181
- The statistical weights of all states.
182
-
183
- Parameters
184
- ----------
185
- algo: foxes.core.Algorithm
186
- The calculation algorithm
187
-
188
- Returns
189
- -------
190
- weights: numpy.ndarray
191
- The weights, shape: (n_states, n_turbines)
192
-
193
- """
194
- return np.full(
195
- (self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
196
- )
197
-
198
179
  def calculate(self, algo, mdata, fdata, tdata):
199
180
  """
200
181
  The main model calculation.
@@ -226,4 +207,10 @@ class ScanStates(States):
226
207
  tdata[v] = np.zeros_like(tdata[FC.TARGETS][..., 0])
227
208
  tdata[v][:] = mdata[self.DATA][:, None, None, i]
228
209
 
210
+ # add weights:
211
+ tdata[FV.WEIGHT] = np.full(
212
+ (mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
213
+ )
214
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
215
+
229
216
  return {v: tdata[v] for v in self.output_point_vars(algo)}
@@ -157,23 +157,6 @@ class SingleStateStates(States):
157
157
 
158
158
  return list(out)
159
159
 
160
- def weights(self, algo):
161
- """
162
- The statistical weights of all states.
163
-
164
- Parameters
165
- ----------
166
- algo: foxes.core.Algorithm
167
- The calculation algorithm
168
-
169
- Returns
170
- -------
171
- weights: numpy.ndarray
172
- The weights, shape: (n_states, n_turbines)
173
-
174
- """
175
- return np.ones((1, algo.n_turbines), dtype=config.dtype_double)
176
-
177
160
  def calculate(self, algo, mdata, fdata, tdata):
178
161
  """
179
162
  The main model calculation.
@@ -233,4 +216,9 @@ class SingleStateStates(States):
233
216
  pres = p.calculate(tdata, z)
234
217
  tdata[v] = pres
235
218
 
219
+ tdata[FV.WEIGHT] = np.full(
220
+ (mdata.n_states, 1, 1), 1.0, dtype=config.dtype_double
221
+ )
222
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
223
+
236
224
  return {v: tdata[v] for v in self.output_point_vars(algo)}
@@ -82,7 +82,7 @@ class StatesTable(States):
82
82
  """
83
83
  super().__init__()
84
84
 
85
- self.ovars = output_vars
85
+ self.ovars = list(output_vars)
86
86
  self.rpars = pd_read_pars
87
87
  self.var2col = var2col
88
88
  self.fixed_vars = fixed_vars
@@ -98,9 +98,7 @@ class StatesTable(States):
98
98
  self._N = None
99
99
  self._tvars = None
100
100
  self._profiles = None
101
-
102
101
  self._data_source = data_source
103
- self.__weights = None
104
102
 
105
103
  @property
106
104
  def data_source(self):
@@ -210,10 +208,10 @@ class StatesTable(States):
210
208
  """
211
209
  self.VARS = self.var("vars")
212
210
  self.DATA = self.var("data")
211
+ self.WEIGHT = self.var(FV.WEIGHT)
213
212
 
214
213
  if isinstance(self.data_source, pd.DataFrame):
215
214
  data = self.data_source
216
- isorg = True
217
215
  else:
218
216
  self._data_source = get_input_path(self.data_source)
219
217
  if not self.data_source.is_file():
@@ -230,7 +228,6 @@ class StatesTable(States):
230
228
  print(f"States '{self.name}': Reading file {self.data_source}")
231
229
  rpars = dict(self.RDICT, **self.rpars)
232
230
  data = PandasFileHelper().read_file(self.data_source, **rpars)
233
- isorg = False
234
231
 
235
232
  if self.states_sel is not None:
236
233
  data = data.iloc[self.states_sel]
@@ -240,18 +237,13 @@ class StatesTable(States):
240
237
  self.__inds = data.index.to_numpy()
241
238
 
242
239
  col_w = self.var2col.get(FV.WEIGHT, FV.WEIGHT)
243
- self.__weights = np.zeros((self._N, algo.n_turbines), dtype=config.dtype_double)
240
+ weights = None
244
241
  if col_w in data:
245
- self.__weights[:] = data[col_w].to_numpy()[:, None]
242
+ weights = data[col_w].to_numpy()
246
243
  elif FV.WEIGHT in self.var2col:
247
244
  raise KeyError(
248
245
  f"Weight variable '{col_w}' defined in var2col, but not found in states table columns {data.columns}"
249
246
  )
250
- else:
251
- self.__weights[:] = 1.0 / self._N
252
- if isorg:
253
- data = data.copy()
254
- data[col_w] = self.__weights[:, 0]
255
247
 
256
248
  tcols = []
257
249
  for v in self._tvars:
@@ -267,6 +259,8 @@ class StatesTable(States):
267
259
  idata = super().load_data(algo, verbosity)
268
260
  idata["coords"][self.VARS] = self._tvars
269
261
  idata["data_vars"][self.DATA] = ((FC.STATE, self.VARS), data.to_numpy())
262
+ if weights is not None:
263
+ idata["data_vars"][self.WEIGHT] = (FC.STATE, weights)
270
264
 
271
265
  return idata
272
266
 
@@ -313,27 +307,6 @@ class StatesTable(States):
313
307
  """
314
308
  return self.ovars
315
309
 
316
- def weights(self, algo):
317
- """
318
- The statistical weights of all states.
319
-
320
- Parameters
321
- ----------
322
- algo: foxes.core.Algorithm
323
- The calculation algorithm
324
-
325
- Returns
326
- -------
327
- weights: numpy.ndarray
328
- The weights, shape: (n_states, n_turbines)
329
-
330
- """
331
- if self.running:
332
- raise ValueError(
333
- f"States '{self.name}': Cannot access weights while running"
334
- )
335
- return self.__weights
336
-
337
310
  def set_running(
338
311
  self,
339
312
  algo,
@@ -368,10 +341,9 @@ class StatesTable(States):
368
341
 
369
342
  data_stash[self.name] = dict(
370
343
  data_source=self._data_source,
371
- weights=self.__weights,
372
344
  inds=self.__inds,
373
345
  )
374
- del self._data_source, self.__weights, self.__inds
346
+ del self._data_source, self.__inds
375
347
 
376
348
  def unset_running(
377
349
  self,
@@ -404,7 +376,6 @@ class StatesTable(States):
404
376
 
405
377
  data = data_stash[self.name]
406
378
  self._data_source = data.pop("data_source")
407
- self.__weights = data.pop("weights")
408
379
  self.__inds = data.pop("inds")
409
380
 
410
381
  def calculate(self, algo, mdata, fdata, tdata):
@@ -455,6 +426,14 @@ class StatesTable(States):
455
426
  for v, p in self._profiles.items():
456
427
  tdata[v] = p.calculate(tdata, z)
457
428
 
429
+ if self.WEIGHT in mdata:
430
+ tdata[FV.WEIGHT] = mdata[self.WEIGHT][:, None, None]
431
+ else:
432
+ tdata[FV.WEIGHT] = np.full(
433
+ (mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
434
+ )
435
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
436
+
458
437
  return {v: tdata[v] for v in self.output_point_vars(algo)}
459
438
 
460
439
  def finalize(self, algo, verbosity=0):
@@ -469,7 +448,6 @@ class StatesTable(States):
469
448
  The verbosity level
470
449
 
471
450
  """
472
- self.__weights = None
473
451
  self._N = None
474
452
  self._tvars = None
475
453