foxes 1.3__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 (190) 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 +0 -1
  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 +21 -17
  23. foxes/algorithms/__init__.py +6 -6
  24. foxes/algorithms/downwind/__init__.py +2 -2
  25. foxes/algorithms/downwind/downwind.py +44 -12
  26. foxes/algorithms/downwind/models/__init__.py +6 -6
  27. foxes/algorithms/downwind/models/farm_wakes_calc.py +11 -9
  28. foxes/algorithms/downwind/models/init_farm_data.py +0 -1
  29. foxes/algorithms/downwind/models/point_wakes_calc.py +7 -13
  30. foxes/algorithms/downwind/models/set_amb_point_results.py +6 -6
  31. foxes/algorithms/iterative/__init__.py +7 -3
  32. foxes/algorithms/iterative/iterative.py +1 -2
  33. foxes/algorithms/iterative/models/__init__.py +7 -3
  34. foxes/algorithms/iterative/models/farm_wakes_calc.py +9 -5
  35. foxes/algorithms/sequential/__init__.py +3 -3
  36. foxes/algorithms/sequential/models/__init__.py +2 -2
  37. foxes/algorithms/sequential/sequential.py +3 -4
  38. foxes/config/__init__.py +5 -1
  39. foxes/constants.py +16 -0
  40. foxes/core/__init__.py +45 -22
  41. foxes/core/algorithm.py +0 -1
  42. foxes/core/data.py +19 -18
  43. foxes/core/engine.py +9 -13
  44. foxes/core/farm_controller.py +2 -2
  45. foxes/core/ground_model.py +4 -13
  46. foxes/core/model.py +5 -5
  47. foxes/core/partial_wakes_model.py +147 -10
  48. foxes/core/point_data_model.py +2 -3
  49. foxes/core/rotor_model.py +3 -3
  50. foxes/core/states.py +2 -3
  51. foxes/core/turbine.py +2 -1
  52. foxes/core/wake_deflection.py +130 -0
  53. foxes/core/wake_model.py +222 -9
  54. foxes/core/wake_superposition.py +122 -4
  55. foxes/core/wind_farm.py +6 -6
  56. foxes/data/__init__.py +7 -2
  57. foxes/data/states/weibull_sectors_12.csv +13 -0
  58. foxes/data/states/weibull_sectors_12.nc +0 -0
  59. foxes/engines/__init__.py +14 -15
  60. foxes/engines/dask.py +39 -14
  61. foxes/engines/numpy.py +0 -3
  62. foxes/input/__init__.py +3 -3
  63. foxes/input/farm_layout/__init__.py +8 -8
  64. foxes/input/farm_layout/from_csv.py +1 -1
  65. foxes/input/farm_layout/ring.py +0 -1
  66. foxes/input/states/__init__.py +22 -12
  67. foxes/input/states/create/__init__.py +3 -2
  68. foxes/input/states/field_data_nc.py +10 -24
  69. foxes/input/states/multi_height.py +9 -6
  70. foxes/input/states/one_point_flow.py +0 -4
  71. foxes/input/states/single.py +1 -1
  72. foxes/input/states/states_table.py +10 -7
  73. foxes/input/states/weibull_sectors.py +225 -0
  74. foxes/input/states/wrg_states.py +7 -5
  75. foxes/input/yaml/__init__.py +9 -3
  76. foxes/input/yaml/dict.py +19 -19
  77. foxes/input/yaml/windio/__init__.py +10 -5
  78. foxes/input/yaml/windio/read_attributes.py +2 -2
  79. foxes/input/yaml/windio/read_farm.py +5 -5
  80. foxes/input/yaml/windio/read_fields.py +4 -2
  81. foxes/input/yaml/windio/read_site.py +52 -0
  82. foxes/input/yaml/windio/windio.py +1 -1
  83. foxes/models/__init__.py +15 -14
  84. foxes/models/axial_induction/__init__.py +2 -2
  85. foxes/models/farm_controllers/__init__.py +1 -1
  86. foxes/models/farm_models/__init__.py +1 -1
  87. foxes/models/ground_models/__init__.py +3 -2
  88. foxes/models/ground_models/wake_mirror.py +3 -3
  89. foxes/models/model_book.py +175 -49
  90. foxes/models/partial_wakes/__init__.py +6 -6
  91. foxes/models/partial_wakes/axiwake.py +30 -5
  92. foxes/models/partial_wakes/centre.py +47 -0
  93. foxes/models/partial_wakes/rotor_points.py +41 -11
  94. foxes/models/partial_wakes/segregated.py +2 -25
  95. foxes/models/partial_wakes/top_hat.py +27 -2
  96. foxes/models/point_models/__init__.py +4 -4
  97. foxes/models/rotor_models/__init__.py +3 -3
  98. foxes/models/turbine_models/__init__.py +11 -11
  99. foxes/models/turbine_models/set_farm_vars.py +0 -1
  100. foxes/models/turbine_types/PCt_file.py +0 -2
  101. foxes/models/turbine_types/PCt_from_two.py +0 -2
  102. foxes/models/turbine_types/__init__.py +9 -9
  103. foxes/models/vertical_profiles/__init__.py +7 -7
  104. foxes/models/wake_deflections/__init__.py +3 -0
  105. foxes/models/{wake_frames/yawed_wakes.py → wake_deflections/bastankhah2016.py} +32 -111
  106. foxes/models/wake_deflections/jimenez.py +277 -0
  107. foxes/models/wake_deflections/no_deflection.py +94 -0
  108. foxes/models/wake_frames/__init__.py +6 -7
  109. foxes/models/wake_frames/dynamic_wakes.py +12 -3
  110. foxes/models/wake_frames/rotor_wd.py +3 -1
  111. foxes/models/wake_frames/seq_dynamic_wakes.py +41 -7
  112. foxes/models/wake_frames/streamlines.py +8 -6
  113. foxes/models/wake_frames/timelines.py +9 -3
  114. foxes/models/wake_models/__init__.py +7 -7
  115. foxes/models/wake_models/dist_sliced.py +50 -84
  116. foxes/models/wake_models/gaussian.py +20 -0
  117. foxes/models/wake_models/induction/__init__.py +5 -5
  118. foxes/models/wake_models/induction/rankine_half_body.py +30 -71
  119. foxes/models/wake_models/induction/rathmann.py +65 -64
  120. foxes/models/wake_models/induction/self_similar.py +65 -68
  121. foxes/models/wake_models/induction/self_similar2020.py +0 -3
  122. foxes/models/wake_models/induction/vortex_sheet.py +71 -75
  123. foxes/models/wake_models/ti/__init__.py +2 -2
  124. foxes/models/wake_models/ti/crespo_hernandez.py +5 -3
  125. foxes/models/wake_models/ti/iec_ti.py +6 -4
  126. foxes/models/wake_models/top_hat.py +58 -7
  127. foxes/models/wake_models/wind/__init__.py +6 -4
  128. foxes/models/wake_models/wind/bastankhah14.py +25 -7
  129. foxes/models/wake_models/wind/bastankhah16.py +35 -3
  130. foxes/models/wake_models/wind/jensen.py +15 -2
  131. foxes/models/wake_models/wind/turbopark.py +28 -2
  132. foxes/models/wake_superpositions/__init__.py +18 -9
  133. foxes/models/wake_superpositions/ti_linear.py +4 -4
  134. foxes/models/wake_superpositions/ti_max.py +4 -4
  135. foxes/models/wake_superpositions/ti_pow.py +4 -4
  136. foxes/models/wake_superpositions/ti_quadratic.py +4 -4
  137. foxes/models/wake_superpositions/wind_vector.py +257 -0
  138. foxes/models/wake_superpositions/ws_linear.py +9 -10
  139. foxes/models/wake_superpositions/ws_max.py +8 -8
  140. foxes/models/wake_superpositions/ws_pow.py +8 -8
  141. foxes/models/wake_superpositions/ws_product.py +4 -4
  142. foxes/models/wake_superpositions/ws_quadratic.py +8 -8
  143. foxes/output/__init__.py +21 -19
  144. foxes/output/farm_layout.py +2 -2
  145. foxes/output/farm_results_eval.py +15 -15
  146. foxes/output/flow_plots_2d/__init__.py +2 -2
  147. foxes/output/flow_plots_2d/get_fig.py +4 -2
  148. foxes/output/rose_plot.py +3 -3
  149. foxes/output/seq_plugins/__init__.py +2 -2
  150. foxes/output/seq_plugins/seq_flow_ani_plugin.py +0 -3
  151. foxes/output/seq_plugins/seq_wake_debug_plugin.py +0 -1
  152. foxes/output/turbine_type_curves.py +7 -8
  153. foxes/utils/__init__.py +37 -19
  154. foxes/utils/abl/__init__.py +4 -4
  155. foxes/utils/cubic_roots.py +1 -1
  156. foxes/utils/data_book.py +4 -3
  157. foxes/utils/dict.py +3 -3
  158. foxes/utils/exec_python.py +5 -5
  159. foxes/utils/factory.py +1 -3
  160. foxes/utils/geom2d/__init__.py +7 -5
  161. foxes/utils/geopandas_utils.py +2 -2
  162. foxes/utils/pandas_utils.py +4 -3
  163. foxes/utils/tab_files.py +0 -1
  164. foxes/utils/weibull.py +28 -0
  165. foxes/utils/wrg_utils.py +3 -1
  166. foxes/utils/xarray_utils.py +9 -2
  167. foxes/variables.py +67 -9
  168. {foxes-1.3.dist-info → foxes-1.4.dist-info}/METADATA +6 -15
  169. foxes-1.4.dist-info/RECORD +320 -0
  170. {foxes-1.3.dist-info → foxes-1.4.dist-info}/WHEEL +1 -1
  171. tests/1_verification/flappy_0_6/PCt_files/flappy/run.py +2 -3
  172. tests/1_verification/flappy_0_6/PCt_files/test_PCt_files.py +1 -1
  173. tests/1_verification/flappy_0_6/abl_states/flappy/run.py +0 -1
  174. tests/1_verification/flappy_0_6/partial_top_hat/flappy/run.py +0 -1
  175. tests/1_verification/flappy_0_6/partial_top_hat/test_partial_top_hat.py +0 -2
  176. tests/1_verification/flappy_0_6/row_Jensen_linear_centre/test_row_Jensen_linear_centre.py +0 -1
  177. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat/test_row_Jensen_linear_tophat.py +0 -1
  178. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2005/test_row_Jensen_linear_tophat_IECTI_2005.py +0 -1
  179. tests/1_verification/flappy_0_6/row_Jensen_linear_tophat_IECTI2019/test_row_Jensen_linear_tophat_IECTI_2019.py +0 -1
  180. tests/1_verification/flappy_0_6/row_Jensen_quadratic_centre/test_row_Jensen_quadratic_centre.py +0 -1
  181. tests/1_verification/flappy_0_6_2/grid_rotors/flappy/run.py +0 -2
  182. tests/1_verification/flappy_0_6_2/row_Bastankhah_Crespo/test_row_Bastankhah_Crespo.py +0 -1
  183. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/flappy/run.py +0 -1
  184. tests/1_verification/flappy_0_6_2/row_Bastankhah_linear_centre/test_row_Bastankhah_linear_centre.py +0 -1
  185. foxes/output/round.py +0 -10
  186. foxes/utils/pandas_helpers.py +0 -178
  187. foxes-1.3.dist-info/RECORD +0 -313
  188. {foxes-1.3.dist-info → foxes-1.4.dist-info}/entry_points.txt +0 -0
  189. {foxes-1.3.dist-info → foxes-1.4.dist-info/licenses}/LICENSE +0 -0
  190. {foxes-1.3.dist-info → foxes-1.4.dist-info}/top_level.txt +0 -0
@@ -2,18 +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
- from .wrg_states import WRGStates
18
28
 
19
- 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
@@ -303,7 +303,7 @@ class FieldDataNC(States):
303
303
  d = data[..., i]
304
304
  nn = np.sum(np.isnan(d))
305
305
  print(
306
- 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}%)"
307
307
  )
308
308
 
309
309
  return sts, h, y, x, data, weights
@@ -352,7 +352,6 @@ class FieldDataNC(States):
352
352
  # pre-load file reading:
353
353
  coords = [self.states_coord, self.h_coord, self.y_coord, self.x_coord]
354
354
  if not isinstance(self.data_source, xr.Dataset):
355
-
356
355
  # check variables:
357
356
  for v in self.ovars:
358
357
  if v == FV.WEIGHT and self.weight_ncvar is None:
@@ -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]
@@ -460,6 +458,11 @@ class FieldDataNC(States):
460
458
  self.__inds, format=self.time_format
461
459
  ).to_numpy()
462
460
 
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)
465
+
463
466
  # ensure WD and WS get the first two slots of data:
464
467
  self._dkys = {}
465
468
  if FV.WS in self.ovars:
@@ -601,23 +604,6 @@ class FieldDataNC(States):
601
604
  raise ValueError(f"States '{self.name}': Cannot access index while running")
602
605
  return self.__inds
603
606
 
604
- def output_point_vars(self, algo):
605
- """
606
- The variables which are being modified by the model.
607
-
608
- Parameters
609
- ----------
610
- algo: foxes.core.Algorithm
611
- The calculation algorithm
612
-
613
- Returns
614
- -------
615
- output_vars: list of str
616
- The output variable names
617
-
618
- """
619
- return self.ovars
620
-
621
607
  def calculate(self, algo, mdata, fdata, tdata):
622
608
  """
623
609
  The main model calculation.
@@ -706,9 +692,9 @@ class FieldDataNC(States):
706
692
  i0 += b - a
707
693
  j0 = j1
708
694
 
709
- assert (
710
- i0 == i1
711
- ), 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
+ )
712
698
 
713
699
  data = xr.concat(data, dim=self.states_coord)
714
700
  __, h, y, x, data, weights = self._get_data(data, coords, verbosity=0)
@@ -830,7 +816,7 @@ class FieldDataNC(States):
830
816
  if v != FV.WEIGHT and v not in out:
831
817
  if v in self._dkys:
832
818
  out[v] = data[..., self._dkys[v]]
833
- else:
819
+ elif v in self.fixed_vars:
834
820
  out[v] = np.full(
835
821
  (n_states, n_pts), self.fixed_vars[v], dtype=config.dtype_double
836
822
  )
@@ -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
@@ -93,7 +93,7 @@ class MultiHeightStates(States):
93
93
 
94
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
@@ -572,7 +572,7 @@ class MultiHeightNCStates(MultiHeightStates):
572
572
  data_source,
573
573
  *args,
574
574
  heights=[],
575
- pd_read_pars=None,
575
+ read_pars=None,
576
576
  **kwargs,
577
577
  )
578
578
  self.state_coord = state_coord
@@ -631,7 +631,10 @@ class MultiHeightNCStates(MultiHeightStates):
631
631
  self._inds = data.coords[self.state_coord].to_numpy()
632
632
 
633
633
  if self._format_times_func == "default":
634
- 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]")
635
638
  else:
636
639
  format_times_func = self._format_times_func
637
640
  if format_times_func is not None:
@@ -260,7 +260,6 @@ class OnePointFlowStates(States):
260
260
  self.timelines_data = data.pop("data")
261
261
 
262
262
  def calc_states_indices(self, algo, mdata, points, hi, ref_xy):
263
-
264
263
  n_states, n_points = points.shape[:2]
265
264
  dxy = self.timelines_data["dxy"].to_numpy()[hi]
266
265
 
@@ -301,7 +300,6 @@ class OnePointFlowStates(States):
301
300
  sel = np.isnan(coeffs)
302
301
  tshift = 0
303
302
  while np.any(sel):
304
-
305
303
  trs = trace_si[sel]
306
304
  hdxy = -dxy[trs]
307
305
  trace_p[sel] += hdxy
@@ -326,7 +324,6 @@ class OnePointFlowStates(States):
326
324
  sel &= trace_si < algo.n_states
327
325
  tshift = 1
328
326
  while np.any(sel):
329
-
330
327
  trs = trace_si[sel]
331
328
  hdxy = dxy[trs]
332
329
  trace_p[sel] += hdxy
@@ -420,7 +417,6 @@ class OnePointFlowStates(States):
420
417
 
421
418
  # interpolate to heights:
422
419
  if n_heights > 1:
423
-
424
420
  ar_states = np.arange(n_states)
425
421
  ar_points = np.arange(n_points)
426
422
 
@@ -75,7 +75,7 @@ class SingleStateStates(States):
75
75
  and not len(profiles)
76
76
  ):
77
77
  raise KeyError(
78
- f"Expecting at least one parameter: ws, wd, ti, rho, profiles"
78
+ "Expecting at least one parameter: ws, wd, ti, rho, profiles"
79
79
  )
80
80
 
81
81
  def sub_models(self):
@@ -51,7 +51,7 @@ class StatesTable(States):
51
51
  var2col={},
52
52
  fixed_vars={},
53
53
  profiles={},
54
- pd_read_pars={},
54
+ read_pars={},
55
55
  states_sel=None,
56
56
  states_loc=None,
57
57
  ):
@@ -72,7 +72,7 @@ class StatesTable(States):
72
72
  profiles: dict
73
73
  Key: output variable name str, Value: str or dict
74
74
  or `foxes.core.VerticalProfile`
75
- pd_read_pars: dict
75
+ read_pars: dict
76
76
  pandas file reading parameters
77
77
  states_sel: slice or range or list of int, optional
78
78
  States subset selection
@@ -83,7 +83,7 @@ class StatesTable(States):
83
83
  super().__init__()
84
84
 
85
85
  self.ovars = list(output_vars)
86
- self.rpars = pd_read_pars
86
+ self.rpars = read_pars
87
87
  self.var2col = var2col
88
88
  self.fixed_vars = fixed_vars
89
89
  self.profdicts = profiles
@@ -153,7 +153,6 @@ class StatesTable(States):
153
153
 
154
154
  """
155
155
  self._profiles = {}
156
- self._tvars = set(self.ovars)
157
156
  for v, d in self.profdicts.items():
158
157
  if isinstance(d, str):
159
158
  self._profiles[v] = VerticalProfile.new(d)
@@ -166,9 +165,7 @@ class StatesTable(States):
166
165
  raise TypeError(
167
166
  f"States '{self.name}': Wrong profile type '{type(d).__name__}' for variable '{v}'. Expecting VerticalProfile, str or dict"
168
167
  )
169
- self._tvars.update(self._profiles[v].input_vars())
170
- self._tvars -= set(self.fixed_vars.keys())
171
- self._tvars = list(self._tvars)
168
+
172
169
  super().initialize(algo, verbosity)
173
170
 
174
171
  def sub_models(self):
@@ -245,6 +242,12 @@ class StatesTable(States):
245
242
  f"Weight variable '{col_w}' defined in var2col, but not found in states table columns {data.columns}"
246
243
  )
247
244
 
245
+ self._tvars = set(self.ovars)
246
+ for v in self.profdicts.keys():
247
+ self._tvars.update(self._profiles[v].input_vars())
248
+ self._tvars -= set(self.fixed_vars.keys())
249
+ self._tvars = list(self._tvars)
250
+
248
251
  tcols = []
249
252
  for v in self._tvars:
250
253
  c = self.var2col.get(v, v)
@@ -0,0 +1,225 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ from os import PathLike
4
+ from xarray import Dataset, open_dataset
5
+
6
+ from foxes.data import STATES
7
+ from foxes.utils import PandasFileHelper, weibull_weights
8
+ from foxes.config import config, get_input_path
9
+ import foxes.variables as FV
10
+ import foxes.constants as FC
11
+
12
+ from .states_table import StatesTable
13
+
14
+
15
+ class WeibullSectors(StatesTable):
16
+ """
17
+ States with wind speed from Weibull parameters
18
+ from a NetCDF file
19
+
20
+ Attributes
21
+ ----------
22
+ ws_bins: numpy.ndarray
23
+ The wind speed bins, including
24
+ lower and upper bounds, shape: (n_ws_bins+1,)
25
+ var2ncvar: dict
26
+ Mapping from variable names to variable names
27
+ in the nc file
28
+ sel: dict
29
+ Subset selection via xr.Dataset.sel()
30
+ isel: dict
31
+ Subset selection via xr.Dataset.isel()
32
+ RDICT: dict
33
+ Default xarray file reading parameters
34
+
35
+ :group: input.states
36
+
37
+ """
38
+
39
+ RDICT = {}
40
+
41
+ def __init__(
42
+ self,
43
+ data_source,
44
+ output_vars,
45
+ ws_bins=None,
46
+ var2ncvar={},
47
+ sel=None,
48
+ isel=None,
49
+ **kwargs,
50
+ ):
51
+ """
52
+ Constructor.
53
+
54
+ Parameters
55
+ ----------
56
+ data_source: str or xarray.Dataset or pandas.DataFrame
57
+ Either path to NetCDF or csv file or data
58
+ output_vars: list of str
59
+ The output variables
60
+ ws_bins: list of float, optional
61
+ The wind speed bins, including
62
+ lower and upper bounds
63
+ var2ncvar: dict
64
+ Mapping from variable names to variable names
65
+ in the nc file
66
+ sel: dict, optional
67
+ Subset selection via xr.Dataset.sel()
68
+ isel: dict, optional
69
+ Subset selection via xr.Dataset.isel()
70
+ kwargs: dict, optional
71
+ Additional arguments for the base class
72
+
73
+ """
74
+ super().__init__(data_source, output_vars, var2col={}, **kwargs)
75
+ self.ws_bins = None if ws_bins is None else np.asarray(ws_bins)
76
+ self.var2ncvar = var2ncvar
77
+ self.sel = sel if sel is not None else {}
78
+ self.isel = isel if isel is not None else {}
79
+
80
+ if FV.WS not in self.ovars:
81
+ raise ValueError(
82
+ f"States '{self.name}': Expecting output variable '{FV.WS}', got {self.ovars}"
83
+ )
84
+ for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT]:
85
+ if v in self.ovars:
86
+ raise ValueError(
87
+ f"States '{self.name}': Cannot have '{v}' as output variable"
88
+ )
89
+
90
+ self._original_data_source = None
91
+
92
+ def __repr__(self):
93
+ return f"{type(self).__name__}(ws_bins={self._n_ws})"
94
+
95
+ def load_data(self, algo, verbosity=0):
96
+ """
97
+ Load and/or create all model data that is subject to chunking.
98
+
99
+ Such data should not be stored under self, for memory reasons. The
100
+ data returned here will automatically be chunked and then provided
101
+ as part of the mdata object during calculations.
102
+
103
+ Parameters
104
+ ----------
105
+ algo: foxes.core.Algorithm
106
+ The calculation algorithm
107
+ verbosity: int
108
+ The verbosity level, 0 = silent
109
+
110
+ Returns
111
+ -------
112
+ idata: dict
113
+ The dict has exactly two entries: `data_vars`,
114
+ a dict with entries `name_str -> (dim_tuple, data_ndarray)`;
115
+ and `coords`, a dict with entries `dim_name_str -> dim_array`
116
+
117
+ """
118
+
119
+ if self._original_data_source is not None:
120
+ self._data_source = self._original_data_source
121
+ self._original_data_source = None
122
+
123
+ if isinstance(self.data_source, (str, PathLike)):
124
+ fpath = get_input_path(self.data_source)
125
+ if not fpath.is_file():
126
+ if verbosity > 0:
127
+ print(
128
+ f"States '{self.name}': Reading static data '{fpath}' from context '{STATES}'"
129
+ )
130
+ fpath = algo.dbook.get_file_path(STATES, fpath.name, check_raw=False)
131
+ if verbosity > 0:
132
+ print(f"Path: {fpath}")
133
+ elif verbosity:
134
+ print(f"States '{self.name}': Reading file {fpath}")
135
+ rpars = dict(self.RDICT, **self.rpars)
136
+ if fpath.suffix == ".nc":
137
+ data = open_dataset(fpath, engine=config.nc_engine, **rpars)
138
+ else:
139
+ data = PandasFileHelper().read_file(fpath, **rpars).to_xarray()
140
+ self._original_data_source = data
141
+
142
+ elif isinstance(self.data_source, Dataset):
143
+ data = self.data_source
144
+
145
+ elif isinstance(self.data_source, pd.DataFrame):
146
+ data = self.data_source.to_xarray()
147
+
148
+ if self.isel is not None and len(self.isel):
149
+ data = data.isel(**self.isel)
150
+ if self.sel is not None and len(self.sel):
151
+ data = data.sel(**self.sel)
152
+
153
+ wsn = self.var2ncvar.get(FV.WS, FV.WS)
154
+ if self.ws_bins is not None:
155
+ wsb = self.ws_bins
156
+ elif wsn in data:
157
+ wsb = data[wsn].to_numpy()
158
+ else:
159
+ raise ValueError(
160
+ f"States '{self.name}': Expecting ws_bins argument, since '{wsn}' not found in data"
161
+ )
162
+ wss = 0.5 * (wsb[:-1] + wsb[1:])
163
+ wsd = wsb[1:] - wsb[:-1]
164
+ n_ws = len(wss)
165
+ self._n_ws = n_ws
166
+ del wsb
167
+
168
+ secn = None
169
+ n_secs = None
170
+ if self._original_data_source is None:
171
+ self._original_data_source = self.data_source
172
+ self._data_source = {}
173
+ for v in [FV.WEIBULL_A, FV.WEIBULL_k, FV.WEIGHT] + self.ovars:
174
+ if v != FV.WS and v not in self.fixed_vars:
175
+ c = self.var2ncvar.get(v, v)
176
+ if c not in data:
177
+ raise KeyError(
178
+ f"States '{self.name}': Missing variable '{c}' in data, found {list(data.data_vars.keys())}"
179
+ )
180
+ d = data[c]
181
+ if len(d.dims) == 0:
182
+ self.fixed_vars[v] = float(d.to_numpy())
183
+ continue
184
+ elif len(d.dims) != 1:
185
+ raise ValueError(
186
+ f"States '{self.name}': Expecting single dimension for variable '{c}', got {d.dims}"
187
+ )
188
+ elif secn is None:
189
+ secn = d.dims[0]
190
+ n_secs = data.sizes[secn]
191
+ elif d.dims[0] != secn:
192
+ raise ValueError(
193
+ f"States '{self.name}': Expecting dimension '{secn}' for variable '{c}', got {d.dims}"
194
+ )
195
+ self._data_source[v] = np.zeros(
196
+ (n_secs, n_ws), dtype=config.dtype_double
197
+ )
198
+ self._data_source[v][:] = d.to_numpy()[:, None]
199
+ self._data_source[FV.WS] = np.zeros((n_secs, n_ws), dtype=config.dtype_double)
200
+ self._data_source[FV.WS][:] = wss[None, :]
201
+ del wss
202
+
203
+ self._data_source[FV.WEIGHT] *= weibull_weights(
204
+ ws=self._data_source[FV.WS],
205
+ ws_deltas=wsd[None, :],
206
+ A=self._data_source.pop(FV.WEIBULL_A),
207
+ k=self._data_source.pop(FV.WEIBULL_k),
208
+ )
209
+
210
+ # remove wd 360 from the end, if wd 0 is given:
211
+ if FV.WD in self._data_source:
212
+ if np.all(self._data_source[FV.WD][0] == 0.0) and np.all(
213
+ self._data_source[FV.WD][-1] == 360.0
214
+ ):
215
+ for v in self._data_source.keys():
216
+ self._data_source[v] = self._data_source[v][:-1]
217
+ n_secs -= 1
218
+
219
+ N = n_secs * n_ws
220
+ for v in self._data_source.keys():
221
+ self._data_source[v] = self._data_source[v].reshape(N)
222
+ self._data_source = pd.DataFrame(data=self._data_source, index=np.arange(N))
223
+ self._data_source.index.name = FC.STATE
224
+
225
+ return super().load_data(algo, verbosity)
@@ -3,7 +3,7 @@ from scipy.interpolate import interpn
3
3
 
4
4
  from foxes.core.states import States
5
5
  from foxes.config import config, get_input_path
6
- from foxes.utils.wrg_utils import ReaderWRG
6
+ from foxes.utils import ReaderWRG, weibull_weights
7
7
  from foxes.data import STATES
8
8
  import foxes.variables as FV
9
9
  import foxes.constants as FC
@@ -132,7 +132,7 @@ class WRGStates(States):
132
132
  self._y = p0[1] + np.arange(ny) * res
133
133
  self._y = self._y[sy]
134
134
  if len(self._x) < 2 or len(self._y) < 2:
135
- raise ValueError(f"No overlap between data bounds and farm bounds")
135
+ raise ValueError("No overlap between data bounds and farm bounds")
136
136
  p0[0] = np.min(self._x)
137
137
  p0[1] = np.min(self._y)
138
138
  p1[0] = np.max(self._x)
@@ -293,9 +293,11 @@ class WRGStates(States):
293
293
  dims=(FC.STATE, FC.TARGET, FC.TPOINT),
294
294
  )
295
295
 
296
- wsA = out[FV.WS] / A
297
- tdata[FV.WEIGHT] *= wsd[:, None, None] * (
298
- k / A * wsA ** (k - 1) * np.exp(-(wsA**k))
296
+ tdata[FV.WEIGHT] *= weibull_weights(
297
+ ws=out[FV.WS],
298
+ ws_deltas=wsd[:, None, None],
299
+ A=A,
300
+ k=k,
299
301
  )
300
302
 
301
303
  return out
@@ -1,3 +1,9 @@
1
- from .dict import read_dict, run_dict, run_outputs, run_obj_function, get_output_obj
2
- from .yaml import foxes_yaml
3
- from .windio.windio import read_windio, foxes_windio
1
+ from .dict import read_dict as read_dict
2
+ from .dict import run_dict as run_dict
3
+ from .dict import run_outputs as run_outputs
4
+ from .dict import run_obj_function as run_obj_function
5
+ from .dict import get_output_obj as get_output_obj
6
+
7
+ from .yaml import foxes_yaml as foxes_yaml
8
+ from .windio.windio import read_windio as read_windio
9
+ from .windio.windio import foxes_windio as foxes_windio
foxes/input/yaml/dict.py CHANGED
@@ -75,13 +75,13 @@ def read_dict(
75
75
  print(*args, **kwargs)
76
76
 
77
77
  # set working directory:
78
- l = 0
78
+ ld = 0
79
79
  for c, d in zip(
80
80
  [FC.WORK_DIR, FC.INPUT_DIR, FC.OUTPUT_DIR], [work_dir, input_dir, output_dir]
81
81
  ):
82
82
  if d is not None:
83
83
  config[c] = d
84
- l = max(l, len(str(d)))
84
+ ld = max(ld, len(str(d)))
85
85
  _print("\n--------------------- Reading foxes parameter dict ---------------------")
86
86
  _print("Working directory :", config.work_dir)
87
87
  _print("Input directory :", config.input_dir)
@@ -95,9 +95,9 @@ def read_dict(
95
95
  else:
96
96
  states = algo.states
97
97
  else:
98
- assert (
99
- algo is None
100
- ), f"Cannot handle both the algo and the states argument, please drop one"
98
+ assert algo is None, (
99
+ "Cannot handle both the algo and the states argument, please drop one"
100
+ )
101
101
 
102
102
  # create model book:
103
103
  if mbook is None:
@@ -119,9 +119,9 @@ def read_dict(
119
119
  else:
120
120
  mbook = algo.mbook
121
121
  else:
122
- assert (
123
- algo is None
124
- ), f"Cannot handle both the algo and the mbook argument, please drop one"
122
+ assert algo is None, (
123
+ "Cannot handle both the algo and the mbook argument, please drop one"
124
+ )
125
125
 
126
126
  # create farm:
127
127
  if farm is None:
@@ -129,8 +129,8 @@ def read_dict(
129
129
  _print("Creating wind farm")
130
130
  fdict = idict.get_item("wind_farm")
131
131
  lyts = [
132
- Dict(l, name=f"{fdict.name}.layout{i}")
133
- for i, l in enumerate(fdict.pop_item("layouts"))
132
+ Dict(lo, name=f"{fdict.name}.layout{i}")
133
+ for i, lo in enumerate(fdict.pop_item("layouts"))
134
134
  ]
135
135
  farm = WindFarm(**fdict)
136
136
  for lyt in lyts:
@@ -141,9 +141,9 @@ def read_dict(
141
141
  else:
142
142
  farm = algo.farm
143
143
  else:
144
- assert (
145
- algo is None
146
- ), f"Cannot handle both the algo and the farm argument, please drop one"
144
+ assert algo is None, (
145
+ "Cannot handle both the algo and the farm argument, please drop one"
146
+ )
147
147
 
148
148
  # create engine:
149
149
  engine = None
@@ -321,12 +321,12 @@ def run_obj_function(
321
321
 
322
322
  def _set_label(rlabels, k, r):
323
323
  if k not in ["", "none", "None", "_", "__"]:
324
- assert (
325
- k[0] == "$"
326
- ), f"Output {i} of type '{ocls}', function '{fname}': result labels must start with '$', got '{k}'"
327
- assert (
328
- "[" not in k and "]" not in k and "," not in k
329
- ), f"Output {i} of type '{ocls}', function '{fname}': result labels cannot contain '[' or ']' or comma, got '{k}'"
324
+ assert k[0] == "$", (
325
+ f"Output {i} of type '{ocls}', function '{fname}': result labels must start with '$', got '{k}'"
326
+ )
327
+ assert "[" not in k and "]" not in k and "," not in k, (
328
+ f"Output {i} of type '{ocls}', function '{fname}': result labels cannot contain '[' or ']' or comma, got '{k}'"
329
+ )
330
330
  _print(f" result label {k}: {type(r).__name__}")
331
331
  rlabels[k] = r
332
332
 
@@ -1,5 +1,10 @@
1
- from .windio import foxes_windio, read_windio
2
- from .read_site import read_site
3
- from .read_fields import read_wind_resource_field
4
- from .read_farm import read_layout, read_turbine_types, read_farm
5
- from .read_attributes import read_attributes
1
+ from .windio import foxes_windio as foxes_windio
2
+ from .windio import read_windio as read_windio
3
+
4
+ from .read_farm import read_layout as read_layout
5
+ from .read_farm import read_turbine_types as read_turbine_types
6
+ from .read_farm import read_farm as read_farm
7
+
8
+ from .read_site import read_site as read_site
9
+ from .read_fields import read_wind_resource_field as read_wind_resource_field
10
+ from .read_attributes import read_attributes as read_attributes
@@ -202,7 +202,7 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
202
202
  elif background_averaging in ["none", "None", None]:
203
203
  algo_dict["rotor_model"] = None
204
204
  elif background_averaging == "grid":
205
- algo_dict["rotor_model"] = f"grid{nx*ny}"
205
+ algo_dict["rotor_model"] = f"grid{nx * ny}"
206
206
  else:
207
207
  algo_dict["rotor_model"] = background_averaging
208
208
 
@@ -215,7 +215,7 @@ def _read_rotor_averaging(rotor_averaging, algo_dict, verbosity):
215
215
  algo_dict["partial_wakes"] = "rotor_points"
216
216
  else:
217
217
  if grid == "grid":
218
- algo_dict["partial_wakes"] = f"grid{nx*ny}"
218
+ algo_dict["partial_wakes"] = f"grid{nx * ny}"
219
219
  else:
220
220
  algo_dict["partial_wakes"] = grid
221
221
  else: