foxes 1.2.5__py3-none-any.whl → 1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of foxes might be problematic. Click here for more details.

Files changed (201) hide show
  1. docs/source/conf.py +3 -3
  2. examples/abl_states/run.py +2 -2
  3. examples/compare_rotors_pwakes/run.py +1 -1
  4. examples/compare_wakes/run.py +1 -2
  5. examples/dyn_wakes/run.py +29 -6
  6. examples/induction/run.py +3 -3
  7. examples/multi_height/run.py +1 -1
  8. examples/power_mask/run.py +2 -2
  9. examples/quickstart/run.py +16 -0
  10. examples/random_timeseries/run.py +3 -4
  11. examples/scan_row/run.py +3 -3
  12. examples/sequential/run.py +33 -10
  13. examples/single_state/run.py +3 -4
  14. examples/states_lookup_table/run.py +3 -3
  15. examples/streamline_wakes/run.py +27 -4
  16. examples/tab_file/run.py +3 -3
  17. examples/timelines/run.py +29 -5
  18. examples/timeseries/run.py +3 -3
  19. examples/timeseries_slurm/run.py +3 -3
  20. examples/wind_rose/run.py +3 -3
  21. examples/yawed_wake/run.py +16 -8
  22. foxes/__init__.py +22 -18
  23. foxes/algorithms/__init__.py +6 -6
  24. foxes/algorithms/downwind/__init__.py +2 -2
  25. foxes/algorithms/downwind/downwind.py +53 -27
  26. foxes/algorithms/downwind/models/__init__.py +6 -6
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +22 -14
  28. foxes/algorithms/downwind/models/init_farm_data.py +4 -5
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  30. foxes/algorithms/downwind/models/reorder_farm_output.py +5 -1
  31. foxes/algorithms/downwind/models/set_amb_point_results.py +7 -7
  32. foxes/algorithms/iterative/__init__.py +7 -3
  33. foxes/algorithms/iterative/iterative.py +1 -2
  34. foxes/algorithms/iterative/models/__init__.py +7 -3
  35. foxes/algorithms/iterative/models/farm_wakes_calc.py +15 -8
  36. foxes/algorithms/sequential/__init__.py +3 -3
  37. foxes/algorithms/sequential/models/__init__.py +2 -2
  38. foxes/algorithms/sequential/models/seq_state.py +0 -18
  39. foxes/algorithms/sequential/sequential.py +8 -22
  40. foxes/config/__init__.py +5 -1
  41. foxes/constants.py +22 -0
  42. foxes/core/__init__.py +45 -22
  43. foxes/core/algorithm.py +0 -1
  44. foxes/core/data.py +56 -29
  45. foxes/core/engine.py +28 -14
  46. foxes/core/farm_controller.py +2 -2
  47. foxes/core/farm_data_model.py +1 -0
  48. foxes/core/ground_model.py +4 -13
  49. foxes/core/model.py +5 -5
  50. foxes/core/partial_wakes_model.py +147 -10
  51. foxes/core/point_data_model.py +2 -3
  52. foxes/core/rotor_model.py +42 -38
  53. foxes/core/states.py +4 -50
  54. foxes/core/turbine.py +2 -1
  55. foxes/core/wake_deflection.py +130 -0
  56. foxes/core/wake_model.py +222 -9
  57. foxes/core/wake_superposition.py +122 -4
  58. foxes/core/wind_farm.py +6 -6
  59. foxes/data/__init__.py +7 -2
  60. foxes/data/states/weibull_sectors_12.csv +13 -0
  61. foxes/data/states/weibull_sectors_12.nc +0 -0
  62. foxes/engines/__init__.py +14 -15
  63. foxes/engines/dask.py +39 -14
  64. foxes/engines/numpy.py +0 -3
  65. foxes/input/__init__.py +3 -3
  66. foxes/input/farm_layout/__init__.py +8 -8
  67. foxes/input/farm_layout/from_csv.py +1 -1
  68. foxes/input/farm_layout/ring.py +0 -1
  69. foxes/input/states/__init__.py +22 -11
  70. foxes/input/states/create/__init__.py +3 -2
  71. foxes/input/states/field_data_nc.py +48 -84
  72. foxes/input/states/multi_height.py +40 -60
  73. foxes/input/states/one_point_flow.py +22 -25
  74. foxes/input/states/scan.py +6 -19
  75. foxes/input/states/single.py +6 -18
  76. foxes/input/states/states_table.py +25 -44
  77. foxes/input/states/weibull_sectors.py +225 -0
  78. foxes/input/states/wrg_states.py +151 -37
  79. foxes/input/yaml/__init__.py +9 -3
  80. foxes/input/yaml/dict.py +19 -19
  81. foxes/input/yaml/windio/__init__.py +10 -5
  82. foxes/input/yaml/windio/read_attributes.py +2 -2
  83. foxes/input/yaml/windio/read_farm.py +5 -5
  84. foxes/input/yaml/windio/read_fields.py +4 -2
  85. foxes/input/yaml/windio/read_site.py +52 -0
  86. foxes/input/yaml/windio/windio.py +1 -1
  87. foxes/models/__init__.py +15 -14
  88. foxes/models/axial_induction/__init__.py +2 -2
  89. foxes/models/farm_controllers/__init__.py +1 -1
  90. foxes/models/farm_models/__init__.py +1 -1
  91. foxes/models/ground_models/__init__.py +3 -2
  92. foxes/models/ground_models/wake_mirror.py +3 -3
  93. foxes/models/model_book.py +175 -49
  94. foxes/models/partial_wakes/__init__.py +6 -6
  95. foxes/models/partial_wakes/axiwake.py +30 -5
  96. foxes/models/partial_wakes/centre.py +47 -0
  97. foxes/models/partial_wakes/rotor_points.py +45 -9
  98. foxes/models/partial_wakes/segregated.py +2 -20
  99. foxes/models/partial_wakes/top_hat.py +27 -2
  100. foxes/models/point_models/__init__.py +4 -4
  101. foxes/models/rotor_models/__init__.py +3 -3
  102. foxes/models/rotor_models/centre.py +6 -4
  103. foxes/models/turbine_models/__init__.py +11 -11
  104. foxes/models/turbine_models/set_farm_vars.py +0 -1
  105. foxes/models/turbine_types/PCt_file.py +0 -2
  106. foxes/models/turbine_types/PCt_from_two.py +0 -2
  107. foxes/models/turbine_types/__init__.py +9 -9
  108. foxes/models/vertical_profiles/__init__.py +7 -7
  109. foxes/models/wake_deflections/__init__.py +3 -0
  110. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  111. foxes/models/wake_deflections/jimenez.py +277 -0
  112. foxes/models/wake_deflections/no_deflection.py +94 -0
  113. foxes/models/wake_frames/__init__.py +6 -7
  114. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  115. foxes/models/wake_frames/rotor_wd.py +3 -1
  116. foxes/models/wake_frames/seq_dynamic_wakes.py +45 -8
  117. foxes/models/wake_frames/streamlines.py +8 -6
  118. foxes/models/wake_frames/timelines.py +19 -3
  119. foxes/models/wake_models/__init__.py +7 -7
  120. foxes/models/wake_models/dist_sliced.py +50 -84
  121. foxes/models/wake_models/gaussian.py +20 -0
  122. foxes/models/wake_models/induction/__init__.py +5 -5
  123. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  124. foxes/models/wake_models/induction/rathmann.py +65 -64
  125. foxes/models/wake_models/induction/self_similar.py +65 -68
  126. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  127. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  128. foxes/models/wake_models/ti/__init__.py +2 -2
  129. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  130. foxes/models/wake_models/ti/iec_ti.py +6 -4
  131. foxes/models/wake_models/top_hat.py +58 -7
  132. foxes/models/wake_models/wind/__init__.py +6 -4
  133. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  134. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  135. foxes/models/wake_models/wind/jensen.py +15 -2
  136. foxes/models/wake_models/wind/turbopark.py +28 -2
  137. foxes/models/wake_superpositions/__init__.py +18 -9
  138. foxes/models/wake_superpositions/ti_linear.py +4 -4
  139. foxes/models/wake_superpositions/ti_max.py +4 -4
  140. foxes/models/wake_superpositions/ti_pow.py +4 -4
  141. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  142. foxes/models/wake_superpositions/wind_vector.py +257 -0
  143. foxes/models/wake_superpositions/ws_linear.py +9 -10
  144. foxes/models/wake_superpositions/ws_max.py +8 -8
  145. foxes/models/wake_superpositions/ws_pow.py +8 -8
  146. foxes/models/wake_superpositions/ws_product.py +4 -4
  147. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  148. foxes/output/__init__.py +21 -19
  149. foxes/output/farm_layout.py +14 -6
  150. foxes/output/farm_results_eval.py +51 -27
  151. foxes/output/flow_plots_2d/__init__.py +2 -2
  152. foxes/output/flow_plots_2d/get_fig.py +4 -2
  153. foxes/output/rose_plot.py +23 -5
  154. foxes/output/seq_plugins/__init__.py +2 -2
  155. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  156. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  157. foxes/output/slice_data.py +16 -19
  158. foxes/output/turbine_type_curves.py +7 -8
  159. foxes/utils/__init__.py +37 -19
  160. foxes/utils/abl/__init__.py +4 -4
  161. foxes/utils/cubic_roots.py +1 -1
  162. foxes/utils/data_book.py +4 -3
  163. foxes/utils/dict.py +3 -3
  164. foxes/utils/exec_python.py +5 -5
  165. foxes/utils/factory.py +1 -3
  166. foxes/utils/geom2d/__init__.py +7 -5
  167. foxes/utils/geopandas_utils.py +2 -2
  168. foxes/utils/pandas_utils.py +4 -3
  169. foxes/utils/tab_files.py +0 -1
  170. foxes/utils/weibull.py +28 -0
  171. foxes/utils/wrg_utils.py +3 -1
  172. foxes/utils/xarray_utils.py +9 -2
  173. foxes/variables.py +67 -9
  174. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/METADATA +14 -21
  175. foxes-1.4.dist-info/RECORD +320 -0
  176. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
  177. tests/0_consistency/iterative/test_iterative.py +2 -3
  178. tests/0_consistency/partial_wakes/test_partial_wakes.py +2 -2
  179. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  180. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +48 -56
  181. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  182. tests/1_verification/flappy_0_6/abl_states/test_abl_states.py +33 -36
  183. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  184. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  185. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +3 -3
  186. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +3 -4
  187. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +3 -4
  188. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +3 -4
  189. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +3 -4
  190. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  191. tests/1_verification/flappy_0_6_2/grid_rotors/test_grid_rotors.py +3 -3
  192. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +3 -3
  193. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  194. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +3 -4
  195. tests/3_examples/test_examples.py +3 -2
  196. foxes/output/round.py +0 -10
  197. foxes/utils/pandas_helpers.py +0 -178
  198. foxes-1.2.5.dist-info/RECORD +0 -312
  199. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
  200. {foxes-1.2.5.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
  201. {foxes-1.2.5.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
@@ -2,17 +2,28 @@
2
2
  Atmospheric input states.
3
3
  """
4
4
 
5
- from .single import SingleStateStates
6
- from .scan import ScanStates
7
- from .states_table import StatesTable, Timeseries, TabStates
8
- from .field_data_nc import FieldDataNC
9
- from .multi_height import MultiHeightStates, MultiHeightTimeseries
10
- from .multi_height import MultiHeightNCStates, MultiHeightNCTimeseries
5
+ from .single import SingleStateStates as SingleStateStates
6
+ from .scan import ScanStates as ScanStates
7
+ from .field_data_nc import FieldDataNC as FieldDataNC
8
+ from .wrg_states import WRGStates as WRGStates
9
+ from .weibull_sectors import WeibullSectors as WeibullSectors
10
+
11
+ from .states_table import StatesTable as StatesTable
12
+ from .states_table import Timeseries as Timeseries
13
+ from .states_table import TabStates as TabStates
14
+
15
+ from .multi_height import MultiHeightStates as MultiHeightStates
16
+ from .multi_height import MultiHeightTimeseries as MultiHeightTimeseries
17
+ from .multi_height import MultiHeightNCStates as MultiHeightNCStates
18
+ from .multi_height import MultiHeightNCTimeseries as MultiHeightNCTimeseries
19
+
20
+ from .one_point_flow import OnePointFlowStates as OnePointFlowStates
21
+ from .one_point_flow import OnePointFlowTimeseries as OnePointFlowTimeseries
22
+ from .one_point_flow import (
23
+ OnePointFlowMultiHeightTimeseries as OnePointFlowMultiHeightTimeseries,
24
+ )
11
25
  from .one_point_flow import (
12
- OnePointFlowStates,
13
- OnePointFlowTimeseries,
14
- OnePointFlowMultiHeightTimeseries,
15
- OnePointFlowMultiHeightNCTimeseries,
26
+ OnePointFlowMultiHeightNCTimeseries as OnePointFlowMultiHeightNCTimeseries,
16
27
  )
17
28
 
18
- from . import create
29
+ from . import create as create
@@ -1,2 +1,3 @@
1
- from .random_abl_states import create_random_abl_states, write_random_abl_states
2
- from .random_timeseries import random_timseries_data
1
+ from .random_abl_states import create_random_abl_states as create_random_abl_states
2
+ from .random_abl_states import write_random_abl_states as write_random_abl_states
3
+ from .random_timeseries import random_timseries_data as random_timseries_data
@@ -16,7 +16,6 @@ def _read_nc_file(
16
16
  fpath,
17
17
  coords,
18
18
  vars,
19
- weight_var,
20
19
  nc_engine,
21
20
  sel,
22
21
  isel,
@@ -30,18 +29,7 @@ def _read_nc_file(
30
29
  f"Missing coordinate '{c}' in file {fpath}, got: {list(data.coords.keys())}"
31
30
  )
32
31
  if minimal:
33
- weights = None
34
- if weight_var is not None:
35
- if weight_var not in data.data_vars:
36
- raise KeyError(
37
- f"Missing weight var '{weight_var}' in file {fpath}, found: {list(data.data_vars.keys())}"
38
- )
39
- if data[weight_var].dims != (coords[0],):
40
- raise ValueError(
41
- f"Wrong dimensions for variable '{weight_var}' in file {fpath}. Expecting {(coords[0],)}, got {data[weight_var].dims}"
42
- )
43
- weights = data[weight_var].to_numpy()
44
- return data[coords[0]].to_numpy(), weights
32
+ return data[coords[0]].to_numpy()
45
33
  else:
46
34
  data = data[vars]
47
35
  data.attrs = {}
@@ -175,7 +163,7 @@ class FieldDataNC(States):
175
163
  super().__init__()
176
164
 
177
165
  self.states_coord = states_coord
178
- self.ovars = output_vars
166
+ self.ovars = list(output_vars)
179
167
  self.fixed_vars = fixed_vars
180
168
  self.x_coord = x_coord
181
169
  self.y_coord = y_coord
@@ -196,7 +184,6 @@ class FieldDataNC(States):
196
184
  self._N = None
197
185
 
198
186
  self.__data_source = data_source
199
- self.__weights = None
200
187
  self.__inds = None
201
188
 
202
189
  @property
@@ -298,16 +285,28 @@ class FieldDataNC(States):
298
285
  dtype=config.dtype_double,
299
286
  )
300
287
 
288
+ weights = None
289
+ if self.weight_ncvar is not None:
290
+ if self.weight_ncvar not in ds.data_vars:
291
+ raise KeyError(
292
+ f"States '{self.name}': Missing weights variable '{self.weight_ncvar}' in data, found {sorted(list(ds.data_vars.keys()))}"
293
+ )
294
+ if ds[self.weight_ncvar].dims != (self.states_coord,):
295
+ raise ValueError(
296
+ f"States '{self.name}': Weights variable '{self.weight_ncvar}' has wrong dimensions. Expecting {(self.states_coord,)}, got {ds[self.weight_ncvar].dims}"
297
+ )
298
+ weights = ds[self.weight_ncvar].to_numpy()
299
+
301
300
  if verbosity > 1:
302
301
  print(f"\n{self.name}: Data ranges")
303
302
  for v, i in self._dkys.items():
304
303
  d = data[..., i]
305
304
  nn = np.sum(np.isnan(d))
306
305
  print(
307
- f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100*nn/len(d.flat):.2f}%)"
306
+ f" {v}: {np.nanmin(d)} --> {np.nanmax(d)}, nans: {nn} ({100 * nn / len(d.flat):.2f}%)"
308
307
  )
309
308
 
310
- return sts, h, y, x, data
309
+ return sts, h, y, x, data, weights
311
310
 
312
311
  def output_point_vars(self, algo):
313
312
  """
@@ -353,10 +352,11 @@ class FieldDataNC(States):
353
352
  # pre-load file reading:
354
353
  coords = [self.states_coord, self.h_coord, self.y_coord, self.x_coord]
355
354
  if not isinstance(self.data_source, xr.Dataset):
356
-
357
355
  # check variables:
358
356
  for v in self.ovars:
359
- if v not in self.var2ncvar and v not in self.fixed_vars:
357
+ if v == FV.WEIGHT and self.weight_ncvar is None:
358
+ pass
359
+ elif v not in self.var2ncvar and v not in self.fixed_vars:
360
360
  raise ValueError(
361
361
  f"States '{self.name}': Variable '{v}' neither found in var2ncvar not in fixed_vars"
362
362
  )
@@ -413,7 +413,6 @@ class FieldDataNC(States):
413
413
  _read_nc_file,
414
414
  files,
415
415
  coords=coords,
416
- weight_var=self.weight_ncvar,
417
416
  vars=vars,
418
417
  nc_engine=config.nc_engine,
419
418
  isel=self.isel,
@@ -422,7 +421,6 @@ class FieldDataNC(States):
422
421
  )
423
422
 
424
423
  if self.load_mode in ["preload", "lazy"]:
425
-
426
424
  if self.load_mode == "lazy":
427
425
  try:
428
426
  self.__data_source = [ds.chunk() for ds in self.__data_source]
@@ -440,23 +438,15 @@ class FieldDataNC(States):
440
438
  )
441
439
  if self.load_mode == "preload":
442
440
  self.__data_source.load()
443
- if self.weight_ncvar is not None:
444
- self.__weights = self.__data_source[self.weight_ncvar].to_numpy()
445
441
  self.__inds = self.__data_source[self.states_coord].to_numpy()
446
442
  self._N = len(self.__inds)
447
443
 
448
444
  elif self.load_mode == "fly":
449
- self.__inds, weights = zip(*self.__data_source)
445
+ self.__inds = self.__data_source
450
446
  self.__data_source = fpath
451
447
  self._files_maxi = {f: len(inds) for f, inds in zip(files, self.__inds)}
452
448
  self.__inds = np.concatenate(self.__inds, axis=0)
453
449
  self._N = len(self.__inds)
454
- if weights[0] is not None:
455
- self.__weights = np.zeros(
456
- (self._N, algo.n_turbines), dtype=config.dtype_double
457
- )
458
- self.__weights[:] = np.concatenate(weights, axis=0)[:, None]
459
- del weights
460
450
 
461
451
  else:
462
452
  raise KeyError(
@@ -468,10 +458,10 @@ class FieldDataNC(States):
468
458
  self.__inds, format=self.time_format
469
459
  ).to_numpy()
470
460
 
471
- if self.__weights is None:
472
- self.__weights = np.full(
473
- (self._N, algo.n_turbines), 1.0 / self._N, dtype=config.dtype_double
474
- )
461
+ # given data is already Dataset:
462
+ else:
463
+ self.__inds = self.data_source[self.states_coord].to_numpy()
464
+ self._N = len(self.__inds)
475
465
 
476
466
  # ensure WD and WS get the first two slots of data:
477
467
  self._dkys = {}
@@ -492,8 +482,11 @@ class FieldDataNC(States):
492
482
  self.H = self.var(FV.H)
493
483
  self.VARS = self.var("vars")
494
484
  self.DATA = self.var("data")
485
+ self.WEIGHT = self.var(FV.WEIGHT)
495
486
 
496
- __, h, y, x, data = self._get_data(self.data_source, coords, verbosity)
487
+ __, h, y, x, data, weights = self._get_data(
488
+ self.data_source, coords, verbosity
489
+ )
497
490
  self._prl_coords = coords
498
491
 
499
492
  coos = (FC.STATE, self.H, self.Y, self.X, self.VARS)
@@ -504,6 +497,8 @@ class FieldDataNC(States):
504
497
  idata["coords"][self.X] = x
505
498
  idata["coords"][self.VARS] = list(self._dkys.keys())
506
499
  idata["data_vars"][self.DATA] = data
500
+ if weights is not None:
501
+ idata["data_vars"][self.WEIGHT] = ((FC.STATE,), weights)
507
502
 
508
503
  return idata
509
504
 
@@ -540,10 +535,9 @@ class FieldDataNC(States):
540
535
  super().set_running(algo, data_stash, sel, isel, verbosity)
541
536
 
542
537
  data_stash[self.name] = dict(
543
- weights=self.__weights,
544
538
  inds=self.__inds,
545
539
  )
546
- del self.__weights, self.__inds
540
+ del self.__inds
547
541
 
548
542
  if self.load_mode == "preload":
549
543
  data_stash[self.name]["data_source"] = self.__data_source
@@ -579,7 +573,6 @@ class FieldDataNC(States):
579
573
  super().unset_running(algo, data_stash, sel, isel, verbosity)
580
574
 
581
575
  data = data_stash[self.name]
582
- self.__weights = data.pop("weights")
583
576
  self.__inds = data.pop("inds")
584
577
 
585
578
  if self.load_mode == "preload":
@@ -611,44 +604,6 @@ class FieldDataNC(States):
611
604
  raise ValueError(f"States '{self.name}': Cannot access index while running")
612
605
  return self.__inds
613
606
 
614
- def output_point_vars(self, algo):
615
- """
616
- The variables which are being modified by the model.
617
-
618
- Parameters
619
- ----------
620
- algo: foxes.core.Algorithm
621
- The calculation algorithm
622
-
623
- Returns
624
- -------
625
- output_vars: list of str
626
- The output variable names
627
-
628
- """
629
- return self.ovars
630
-
631
- def weights(self, algo):
632
- """
633
- The statistical weights of all states.
634
-
635
- Parameters
636
- ----------
637
- algo: foxes.core.Algorithm
638
- The calculation algorithm
639
-
640
- Returns
641
- -------
642
- weights: numpy.ndarray
643
- The weights, shape: (n_states, n_turbines)
644
-
645
- """
646
- if self.running:
647
- raise ValueError(
648
- f"States '{self.name}': Cannot access weights while running"
649
- )
650
- return self.__weights
651
-
652
607
  def calculate(self, algo, mdata, fdata, tdata):
653
608
  """
654
609
  The main model calculation.
@@ -690,6 +645,7 @@ class FieldDataNC(States):
690
645
  y = mdata[self.Y]
691
646
  h = mdata[self.H]
692
647
  data = mdata[self.DATA].copy()
648
+ weights = mdata.get(self.WEIGHT, None)
693
649
  coords = self._prl_coords
694
650
 
695
651
  # case lazy:
@@ -697,7 +653,7 @@ class FieldDataNC(States):
697
653
  i0 = mdata.states_i0(counter=True)
698
654
  s = slice(i0, i0 + n_states)
699
655
  ds = self.data_source.isel({self.states_coord: s}).load()
700
- __, h, y, x, data = self._get_data(ds, coords, verbosity=0)
656
+ __, h, y, x, data, weights = self._get_data(ds, coords, verbosity=0)
701
657
  del ds
702
658
 
703
659
  # case fly:
@@ -725,7 +681,6 @@ class FieldDataNC(States):
725
681
  _read_nc_file(
726
682
  fpath,
727
683
  coords=coords,
728
- weight_var=self.weight_ncvar,
729
684
  vars=vars,
730
685
  nc_engine=config.nc_engine,
731
686
  isel=isel,
@@ -737,12 +692,12 @@ class FieldDataNC(States):
737
692
  i0 += b - a
738
693
  j0 = j1
739
694
 
740
- assert (
741
- i0 == i1
742
- ), f"States '{self.name}': Missing states for load_mode '{self.load_mode}': (i0, i1) = {(i0, i1)}"
695
+ assert i0 == i1, (
696
+ f"States '{self.name}': Missing states for load_mode '{self.load_mode}': (i0, i1) = {(i0, i1)}"
697
+ )
743
698
 
744
699
  data = xr.concat(data, dim=self.states_coord)
745
- __, h, y, x, data = self._get_data(data, coords, verbosity=0)
700
+ __, h, y, x, data, weights = self._get_data(data, coords, verbosity=0)
746
701
 
747
702
  else:
748
703
  raise KeyError(
@@ -858,12 +813,21 @@ class FieldDataNC(States):
858
813
  out[FV.WD] = uv2wd(uv, axis=-1)
859
814
  del uv
860
815
  for v in self.ovars:
861
- if v not in out:
816
+ if v != FV.WEIGHT and v not in out:
862
817
  if v in self._dkys:
863
818
  out[v] = data[..., self._dkys[v]]
864
- else:
819
+ elif v in self.fixed_vars:
865
820
  out[v] = np.full(
866
821
  (n_states, n_pts), self.fixed_vars[v], dtype=config.dtype_double
867
822
  )
868
823
 
824
+ # add weights:
825
+ if weights is not None:
826
+ tdata[FV.WEIGHT] = weights[:, None, None]
827
+ else:
828
+ tdata[FV.WEIGHT] = np.full(
829
+ (mdata.n_states, 1, 1), 1 / self._N, dtype=config.dtype_double
830
+ )
831
+ tdata.dims[FV.WEIGHT] = (FC.STATE, FC.TARGET, FC.TPOINT)
832
+
869
833
  return {v: d.reshape(n_states, n_targets, n_tpoints) for v, d in out.items()}
@@ -36,7 +36,7 @@ class MultiHeightStates(States):
36
36
  fixed_vars: dict, optional
37
37
  Fixed uniform variable values, instead of
38
38
  reading from data
39
- pd_read_pars: dict, optional
39
+ read_pars: dict, optional
40
40
  pandas file reading parameters
41
41
  states_sel: slice or range or list of int
42
42
  States subset selection
@@ -58,7 +58,7 @@ class MultiHeightStates(States):
58
58
  heights,
59
59
  var2col={},
60
60
  fixed_vars={},
61
- pd_read_pars={},
61
+ read_pars={},
62
62
  states_sel=None,
63
63
  states_loc=None,
64
64
  **ipars,
@@ -79,7 +79,7 @@ class MultiHeightStates(States):
79
79
  fixed_vars: dict, optional
80
80
  Fixed uniform variable values, instead of
81
81
  reading from data
82
- pd_read_pars: dict, optional
82
+ read_pars: dict, optional
83
83
  pandas file reading parameters
84
84
  states_sel: slice or range or list of int, optional
85
85
  States subset selection
@@ -91,9 +91,9 @@ 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
- self.rpars = pd_read_pars
96
+ self.rpars = read_pars
97
97
  self.var2col = var2col
98
98
  self.fixed_vars = fixed_vars
99
99
  self.ipars = ipars
@@ -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
 
@@ -592,7 +572,7 @@ class MultiHeightNCStates(MultiHeightStates):
592
572
  data_source,
593
573
  *args,
594
574
  heights=[],
595
- pd_read_pars=None,
575
+ read_pars=None,
596
576
  **kwargs,
597
577
  )
598
578
  self.state_coord = state_coord
@@ -651,37 +631,35 @@ class MultiHeightNCStates(MultiHeightStates):
651
631
  self._inds = data.coords[self.state_coord].to_numpy()
652
632
 
653
633
  if self._format_times_func == "default":
654
- format_times_func = lambda t: t.astype("datetime64[ns]")
634
+
635
+ def format_times_func(t):
636
+ """little helper function to convert times to datetime64"""
637
+ return t.astype("datetime64[ns]")
655
638
  else:
656
639
  format_times_func = self._format_times_func
657
640
  if format_times_func is not None:
658
641
  self._inds = format_times_func(self._inds)
659
642
 
660
643
  w_name = self.var2col.get(FV.WEIGHT, FV.WEIGHT)
661
- self._weights = np.zeros((self._N, algo.n_turbines), dtype=config.dtype_double)
644
+ weights = None
662
645
  if w_name in data.data_vars:
663
646
  if data[w_name].dims != (self.state_coord,):
664
647
  raise ValueError(
665
648
  f"Weights data '{w_name}': Expecting dims ({self.state_coord},), got {data[w_name]}"
666
649
  )
667
- self._weights[:] = data.data_vars[w_name].to_numpy()[:, None]
650
+ weights = data.data_vars[w_name].to_numpy()
668
651
  elif FV.WEIGHT in self.var2col:
669
652
  raise KeyError(
670
653
  f"Weight variable '{w_name}' defined in var2col, but not found in data_vars {list(data.data_vars.keys())}"
671
654
  )
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
655
 
678
656
  cols = {}
679
657
  self._solo = {}
680
658
  for v in self.ovars:
659
+ if v in self.fixed_vars or v == FV.WEIGHT:
660
+ continue
681
661
  c = self.var2col.get(v, v)
682
- if c in self.fixed_vars:
683
- pass
684
- elif c in data.attrs:
662
+ if c in data.attrs:
685
663
  self._solo[v] = np.full(self._N, data.attrs)
686
664
  elif c in data.data_vars:
687
665
  if data[c].dims == (self.state_coord,):
@@ -705,6 +683,7 @@ class MultiHeightNCStates(MultiHeightStates):
705
683
  self.H = self.var(FV.H)
706
684
  self.VARS = self.var("vars")
707
685
  self.DATA = self.var("data")
686
+ self.WEIGHT = self.var(FV.WEIGHT)
708
687
 
709
688
  idata = States.load_data(self, algo, verbosity)
710
689
  idata["coords"][self.H] = self.heights
@@ -717,7 +696,8 @@ class MultiHeightNCStates(MultiHeightStates):
717
696
  [data.data_vars[c].to_numpy() for c in cols.values()], axis=1
718
697
  ).astype(config.dtype_double),
719
698
  )
720
-
699
+ if weights is not None:
700
+ idata["data_vars"][self.WEIGHT] = ((FC.STATE,), weights)
721
701
  for v, d in self._solo.items():
722
702
  idata["data_vars"][self.var(v)] = (
723
703
  (FC.STATE,),