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
foxes/output/__init__.py CHANGED
@@ -2,24 +2,26 @@
2
2
  Output tools and functions.
3
3
  """
4
4
 
5
- from .round import round_defaults
6
- from .output import Output
7
- from .farm_layout import FarmLayoutOutput
8
- from .farm_results_eval import FarmResultsEval
9
- from .rose_plot import RosePlotOutput, StatesRosePlotOutput, WindRoseBinPlot
10
- from .results_writer import ResultsWriter
11
- from .state_turbine_map import StateTurbineMap
12
- from .turbine_type_curves import TurbineTypeCurves
13
- from .animation import Animator
14
- from .calc_points import PointCalculator
15
- from .slice_data import SliceData
16
- from .slices_data import SlicesData
17
- from .rotor_point_plots import RotorPointPlot
18
- from .state_turbine_table import StateTurbineTable
19
- from .plt import plt
5
+ from .output import Output as Output
6
+ from .farm_layout import FarmLayoutOutput as FarmLayoutOutput
7
+ from .farm_results_eval import FarmResultsEval as FarmResultsEval
8
+ from .rose_plot import RosePlotOutput as RosePlotOutput
9
+ from .rose_plot import StatesRosePlotOutput as StatesRosePlotOutput
10
+ from .rose_plot import WindRoseBinPlot as WindRoseBinPlot
11
+ from .results_writer import ResultsWriter as ResultsWriter
12
+ from .state_turbine_map import StateTurbineMap as StateTurbineMap
13
+ from .turbine_type_curves import TurbineTypeCurves as TurbineTypeCurves
14
+ from .animation import Animator as Animator
15
+ from .calc_points import PointCalculator as PointCalculator
16
+ from .slice_data import SliceData as SliceData
17
+ from .slices_data import SlicesData as SlicesData
18
+ from .rotor_point_plots import RotorPointPlot as RotorPointPlot
19
+ from .state_turbine_table import StateTurbineTable as StateTurbineTable
20
+ from .plt import plt as plt
20
21
 
21
- from .flow_plots_2d import FlowPlots2D
22
- from .seq_plugins import SeqFlowAnimationPlugin, SeqWakeDebugPlugin
22
+ from .flow_plots_2d import FlowPlots2D as FlowPlots2D
23
+ from .seq_plugins import SeqFlowAnimationPlugin as SeqFlowAnimationPlugin
24
+ from .seq_plugins import SeqWakeDebugPlugin as SeqWakeDebugPlugin
23
25
 
24
- from . import grids
25
- from . import seq_plugins
26
+ from . import grids as grids
27
+ from . import seq_plugins as seq_plugins
@@ -5,8 +5,9 @@ import matplotlib.pyplot as plt
5
5
  from mpl_toolkits.axes_grid1 import make_axes_locatable
6
6
 
7
7
  from foxes.config import config
8
- import foxes.variables as FV
9
8
  from foxes.output.output import Output
9
+ import foxes.variables as FV
10
+ import foxes.constants as FC
10
11
 
11
12
 
12
13
  class FarmLayoutOutput(Output):
@@ -66,10 +67,10 @@ class FarmLayoutOutput(Output):
66
67
  self.D = D
67
68
 
68
69
  if from_results and farm_results is None:
69
- raise ValueError(f"Missing farm_results for switch from_results.")
70
+ raise ValueError("Missing farm_results for switch from_results.")
70
71
 
71
72
  if from_results and results_state is None:
72
- raise ValueError(f"Please specify results_state for switch from_results.")
73
+ raise ValueError("Please specify results_state for switch from_results.")
73
74
 
74
75
  def get_layout_data(self):
75
76
  """
@@ -229,9 +230,16 @@ class FarmLayoutOutput(Output):
229
230
  if self.fres is None:
230
231
  raise ValueError(f"Missing farm_results for color_by '{color_by}'")
231
232
  if color_by[:5] == "mean_":
232
- kw["c"] = np.einsum(
233
- "st,st->t", self.fres[color_by[5:]], self.fres[FV.WEIGHT]
234
- )
233
+ weights = self.fres[FV.WEIGHT]
234
+ if weights.dims == (FC.STATE,):
235
+ wx = "s"
236
+ elif weights.dims == (FC.STATE, FC.TURBINE):
237
+ wx = "st"
238
+ else:
239
+ raise ValueError(
240
+ f"Unsupported dimensions for '{FV.WEIGHT}': Expecting '{(FC.STATE,)}' or '{(FC.STATE, FC.TURBINE)}', got '{weights.dims}'"
241
+ )
242
+ kw["c"] = np.einsum(f"st,{wx}->t", self.fres[color_by[5:]], weights)
235
243
  elif color_by[:4] == "sum_":
236
244
  kw["c"] = np.sum(self.fres[color_by[4:]], axis=0)
237
245
  elif color_by[:4] == "min_":
@@ -66,9 +66,9 @@ class FarmResultsEval(Output):
66
66
  if isinstance(v, str):
67
67
  vdata = self.results[v].to_numpy()
68
68
  nns = np.sum(np.isnan(vdata))
69
- assert (
70
- nns == 0
71
- ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
69
+ assert nns == 0, (
70
+ f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
71
+ )
72
72
  fields.append(vdata)
73
73
  else:
74
74
  fields.append(v)
@@ -76,22 +76,46 @@ class FarmResultsEval(Output):
76
76
  nas = np.zeros_like(fields[-1], dtype=bool)
77
77
  nas = nas | np.isnan(fields[-1])
78
78
 
79
- inds = ["st" for v in fields] + ["st"]
80
- expr = ",".join(inds) + "->" + rhs
79
+ inds = ["st" for __ in fields]
80
+ if self.results[FV.WEIGHT].dims == (FC.STATE,):
81
+ inds += ["s"]
82
+
83
+ if np.any(nas):
84
+ sel = ~np.any(nas, axis=1)
85
+ fields = [f[sel] for f in fields]
86
+
87
+ weights0 = self.results[FV.WEIGHT].to_numpy()
88
+ w0 = np.sum(weights0)
89
+ weights = weights0[sel]
90
+ w1 = np.sum(weights)
91
+ weights *= w0 / w1
92
+ fields.append(weights)
81
93
 
82
- if np.any(nas):
83
- sel = ~np.any(nas, axis=1)
84
- fields = [f[sel] for f in fields]
94
+ else:
95
+ fields.append(self.results[FV.WEIGHT].to_numpy())
96
+
97
+ elif self.results[FV.WEIGHT].dims == (FC.STATE, FC.TURBINE):
98
+ inds += ["st"]
85
99
 
86
- weights0 = self.results[FV.WEIGHT].to_numpy()
87
- w0 = np.sum(weights0, axis=0)[None, :]
88
- weights = weights0[sel]
89
- w1 = np.sum(weights, axis=0)[None, :]
90
- weights *= w0 / w1
91
- fields.append(weights)
100
+ if np.any(nas):
101
+ sel = ~np.any(nas, axis=1)
102
+ fields = [f[sel] for f in fields]
103
+
104
+ weights0 = self.results[FV.WEIGHT].to_numpy()
105
+ w0 = np.sum(weights0, axis=0)[None, :]
106
+ weights = weights0[sel]
107
+ w1 = np.sum(weights, axis=0)[None, :]
108
+ weights *= w0 / w1
109
+ fields.append(weights)
110
+
111
+ else:
112
+ fields.append(self.results[FV.WEIGHT].to_numpy())
92
113
 
93
114
  else:
94
- fields.append(self.results[FV.WEIGHT].to_numpy())
115
+ raise ValueError(
116
+ f"Expecting '{FV.WEIGHT}' variable with dimensions {(FC.STATE,)} or {(FC.STATE, FC.TURBINE)}, got {self.results[FV.WEIGHT].dims}"
117
+ )
118
+ expr = ",".join(inds) + "->" + rhs
95
119
 
96
120
  return np.einsum(expr, *fields)
97
121
 
@@ -118,9 +142,9 @@ class FarmResultsEval(Output):
118
142
  for v, op in vars_op.items():
119
143
  vdata = self.results[v].to_numpy()
120
144
  nns = np.sum(np.isnan(vdata))
121
- assert (
122
- nns == 0
123
- ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
145
+ assert nns == 0, (
146
+ f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
147
+ )
124
148
 
125
149
  if op == "weights":
126
150
  rdata[v] = self.weinsum("t", vdata)
@@ -167,9 +191,9 @@ class FarmResultsEval(Output):
167
191
  for v, op in vars_op.items():
168
192
  vdata = self.results[v].to_numpy()
169
193
  nns = np.sum(np.isnan(vdata))
170
- assert (
171
- nns == 0
172
- ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
194
+ assert nns == 0, (
195
+ f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
196
+ )
173
197
 
174
198
  if op == "weights":
175
199
  rdata[v] = self.weinsum("s", vdata)
@@ -220,9 +244,9 @@ class FarmResultsEval(Output):
220
244
  for v, op in turbines_op.items():
221
245
  vdata = sdata[v].to_numpy()
222
246
  nns = np.sum(np.isnan(vdata))
223
- assert (
224
- nns == 0
225
- ), f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
247
+ assert nns == 0, (
248
+ f"Found {nns} nan values for variable '{v}' of shape {vdata.shape}"
249
+ )
226
250
 
227
251
  if op == "weights":
228
252
  if states_op[v] == "weights":
@@ -447,11 +471,11 @@ class FarmResultsEval(Output):
447
471
  duration = times[-1] - times[0] + delta_t
448
472
  duration_seconds = np.int64(duration.astype(np.int64) / 1e9)
449
473
  duration_hours = duration_seconds / 3600
450
- elif hours is None and annual == True:
474
+ elif hours is None and annual:
451
475
  duration_hours = 8760
452
476
  elif hours is None:
453
477
  raise ValueError(
454
- f"Expecting parameter 'hours' for non-timeseries data, or 'annual=True'"
478
+ "Expecting parameter 'hours' for non-timeseries data, or 'annual=True'"
455
479
  )
456
480
  else:
457
481
  duration_hours = hours
@@ -630,7 +654,7 @@ class FarmResultsEval(Output):
630
654
  else:
631
655
  hax = ax
632
656
 
633
- hax.set_xlabel(f"State")
657
+ hax.set_xlabel("State")
634
658
  hax.set_ylabel(variable)
635
659
  cc = cycler(color="bgrcmyk")
636
660
 
@@ -1,2 +1,2 @@
1
- from .flow_plots import FlowPlots2D
2
- from .get_fig import get_fig
1
+ from .flow_plots import FlowPlots2D as FlowPlots2D
2
+ from .get_fig import get_fig as get_fig
@@ -181,6 +181,7 @@ def get_fig(
181
181
  hax.invert_yaxis()
182
182
 
183
183
  # add rotor position:
184
+ imr = []
184
185
  if show_rotor_dict is not None:
185
186
  D = show_rotor_dict["D"]
186
187
  coords = np.zeros(shape=(2, len(D))) # array to hold change to turbine coords
@@ -211,12 +212,13 @@ def get_fig(
211
212
  turb_x2 = x[t] - coords[0, t]
212
213
  turb_y1 = y[t] + coords[1, t]
213
214
  turb_y2 = y[t] - coords[1, t]
214
- hax.plot(
215
+ imr += hax.plot(
215
216
  [turb_x1, turb_x2],
216
217
  [turb_y1, turb_y2],
217
218
  color=c,
218
219
  linestyle="-",
219
220
  linewidth=1,
221
+ animated=animated,
220
222
  )
221
223
 
222
224
  if add_bar:
@@ -233,7 +235,7 @@ def get_fig(
233
235
  if ret_state:
234
236
  out.append(si)
235
237
  if ret_im:
236
- out.append([i for i in [im, qv, ttl] if i is not None])
238
+ out.append([i for i in [im, qv, ttl] if i is not None] + imr)
237
239
  if ret_state or ret_im:
238
240
  out = tuple(out)
239
241
 
foxes/output/rose_plot.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import numpy as np
2
2
  import matplotlib.pyplot as plt
3
3
  from xarray import Dataset
4
- from matplotlib.cm import ScalarMappable
5
4
  from matplotlib.projections.polar import PolarAxes
6
5
  from matplotlib.lines import Line2D
7
6
 
@@ -58,7 +57,7 @@ class RosePlotOutput(Output):
58
57
  self.results = farm_results
59
58
  self._rtype = FC.TURBINE
60
59
  else:
61
- raise KeyError(f"Require either farm_results or point_results")
60
+ raise KeyError("Require either farm_results or point_results")
62
61
 
63
62
  @classmethod
64
63
  def get_data_info(cls, dname):
@@ -151,9 +150,19 @@ class RosePlotOutput(Output):
151
150
  The plot data
152
151
 
153
152
  """
153
+ if self.results[FV.WEIGHT].dims == (FC.STATE,):
154
+ w = self.results[FV.WEIGHT].to_numpy()
155
+ elif self.results[FV.WEIGHT].dims == (FC.STATE, FC.TURBINE):
156
+ w = self.results[FV.WEIGHT].to_numpy()[:, turbine]
157
+ elif self.results[FV.WEIGHT].dims == (FC.STATE, FC.POINT):
158
+ w = self.results[FV.WEIGHT].to_numpy()[:, point]
159
+ else:
160
+ raise ValueError(
161
+ f"Wrong dimensions for '{FV.WEIGHT}'. Expecting {(FC.STATE,)}, {(FC.STATE, FC.TURBINE)} or {(FC.STATE, FC.POINT)}, got {self.results[FV.WEIGHT].dims}"
162
+ )
163
+
154
164
  if add_inf:
155
165
  ws_bins = list(ws_bins) + [np.inf]
156
- w = self.results[FV.WEIGHT].to_numpy()[:, turbine]
157
166
  t = turbine if self._rtype == FC.TURBINE else point
158
167
  ws = self.results[ws_var].to_numpy()[:, t]
159
168
  wd = self.results[wd_var].to_numpy()[:, t].copy()
@@ -286,7 +295,8 @@ class RosePlotOutput(Output):
286
295
 
287
296
  llines = [Line2D([0], [0], color=c, lw=10) for c in np.flip(color_list, axis=0)]
288
297
  lleg = [
289
- f"[{ws_bins[i]:.1f}, {ws_bins[i+1]:.1f})" for i in range(n_wsb - 1, -1, -1)
298
+ f"[{ws_bins[i]:.1f}, {ws_bins[i + 1]:.1f})"
299
+ for i in range(n_wsb - 1, -1, -1)
290
300
  ]
291
301
  lpars = dict(
292
302
  loc="upper left",
@@ -449,8 +459,16 @@ class WindRoseBinPlot(Output):
449
459
  The plot data
450
460
 
451
461
  """
462
+ if self.farm_results[FV.WEIGHT].dims == (FC.STATE,):
463
+ w = self.farm_results[FV.WEIGHT].to_numpy()
464
+ elif self.farm_results[FV.WEIGHT].dims == (FC.STATE, FC.TURBINE):
465
+ w = self.farm_results[FV.WEIGHT].to_numpy()[:, turbine]
466
+ else:
467
+ raise ValueError(
468
+ f"Wrong dimensions for '{FV.WEIGHT}'. Expecting {(FC.STATE,)} or {(FC.STATE, FC.TURBINE)}, got {self.farm_results[FV.WEIGHT].dims}"
469
+ )
470
+
452
471
  var = self.farm_results[variable].to_numpy()[:, turbine]
453
- w = self.farm_results[FV.WEIGHT].to_numpy()[:, turbine]
454
472
  ws = self.farm_results[ws_var].to_numpy()[:, turbine]
455
473
  wd = self.farm_results[wd_var].to_numpy()[:, turbine].copy()
456
474
  wd_delta = 360 / wd_sectors
@@ -1,2 +1,2 @@
1
- from .seq_flow_ani_plugin import SeqFlowAnimationPlugin
2
- from .seq_wake_debug_plugin import SeqWakeDebugPlugin
1
+ from .seq_flow_ani_plugin import SeqFlowAnimationPlugin as SeqFlowAnimationPlugin
2
+ from .seq_wake_debug_plugin import SeqWakeDebugPlugin as SeqWakeDebugPlugin
@@ -1,5 +1,3 @@
1
- from copy import deepcopy
2
-
3
1
  from foxes.algorithms.sequential import SequentialPlugin
4
2
 
5
3
  from ..flow_plots_2d.flow_plots import FlowPlots2D
@@ -116,7 +114,6 @@ class SeqFlowAnimationPlugin(SequentialPlugin):
116
114
  fig = ax.get_figure()
117
115
  gdata = None
118
116
  while len(self._data):
119
-
120
117
  fres, d = self._data.pop(0)
121
118
 
122
119
  if d[2] is not None:
@@ -109,7 +109,6 @@ class SeqWakeDebugPlugin(SequentialPlugin):
109
109
 
110
110
  """
111
111
  while len(self._data):
112
-
113
112
  dt, pts, v = self._data.pop(0)
114
113
 
115
114
  N = len(pts)
@@ -123,7 +123,6 @@ class SliceData(Output):
123
123
  label_map,
124
124
  vmin,
125
125
  vmax,
126
- weight_turbine,
127
126
  to_file,
128
127
  write_pars,
129
128
  ret_states,
@@ -147,12 +146,22 @@ class SliceData(Output):
147
146
  del g_pts
148
147
 
149
148
  # take mean over states:
150
- weights = self.fres[FV.WEIGHT][:, weight_turbine].to_numpy()
151
- data = {
152
- v: np.einsum("s,sp->p", weights, point_results[v].to_numpy())
153
- for v in variables
154
- }
155
- del point_results
149
+ weights = point_results[FV.WEIGHT].to_numpy()
150
+ if point_results[FV.WEIGHT].dims == (FC.STATE,):
151
+ data = {
152
+ v: np.einsum("s,sp->p", weights, point_results[v].to_numpy())
153
+ for v in variables
154
+ }
155
+ elif point_results[FV.WEIGHT].dims == (FC.STATE, FC.POINT):
156
+ data = {
157
+ v: np.einsum("sp,sp->p", weights, point_results[v].to_numpy())
158
+ for v in variables
159
+ }
160
+ else:
161
+ raise ValueError(
162
+ f"Wrong dimensions for '{FV.WEIGHT}': Expecting {(FC.STATE,)} or {(FC.STATE, FC.POINT)}, got {point_results[FV.WEIGHT].dims}"
163
+ )
164
+ del point_results, weights
156
165
 
157
166
  # apply data modification:
158
167
  a_pos, b_pos, c_pos, data = self._data_mod(
@@ -207,7 +216,6 @@ class SliceData(Output):
207
216
  vmax={},
208
217
  states_sel=None,
209
218
  states_isel=None,
210
- weight_turbine=0,
211
219
  to_file=None,
212
220
  write_pars={},
213
221
  ret_states=False,
@@ -260,8 +268,6 @@ class SliceData(Output):
260
268
  Reduce to selected states
261
269
  states_isel: list, optional
262
270
  Reduce to the selected states indices
263
- weight_turbine: int, optional
264
- Index of the turbine from which to take the weight
265
271
  to_file: str, optional
266
272
  Write data to this file name
267
273
  write_pars: dict
@@ -314,7 +320,6 @@ class SliceData(Output):
314
320
  label_map,
315
321
  vmin,
316
322
  vmax,
317
- weight_turbine,
318
323
  to_file,
319
324
  write_pars,
320
325
  ret_states,
@@ -352,7 +357,6 @@ class SliceData(Output):
352
357
  vmax={},
353
358
  states_sel=None,
354
359
  states_isel=None,
355
- weight_turbine=0,
356
360
  to_file=None,
357
361
  write_pars={},
358
362
  ret_states=False,
@@ -407,8 +411,6 @@ class SliceData(Output):
407
411
  Reduce to selected states
408
412
  states_isel: list, optional
409
413
  Reduce to the selected states indices
410
- weight_turbine: int, optional
411
- Index of the turbine from which to take the weight
412
414
  to_file: str, optional
413
415
  Write data to this file name
414
416
  write_pars: dict
@@ -463,7 +465,6 @@ class SliceData(Output):
463
465
  label_map,
464
466
  vmin,
465
467
  vmax,
466
- weight_turbine,
467
468
  to_file,
468
469
  write_pars,
469
470
  ret_states,
@@ -501,7 +502,6 @@ class SliceData(Output):
501
502
  vmax={},
502
503
  states_sel=None,
503
504
  states_isel=None,
504
- weight_turbine=0,
505
505
  to_file=None,
506
506
  write_pars={},
507
507
  ret_states=False,
@@ -556,8 +556,6 @@ class SliceData(Output):
556
556
  Reduce to selected states
557
557
  states_isel: list, optional
558
558
  Reduce to the selected states indices
559
- weight_turbine: int, optional
560
- Index of the turbine from which to take the weight
561
559
  to_file: str, optional
562
560
  Write data to this file name
563
561
  write_pars: dict
@@ -612,7 +610,6 @@ class SliceData(Output):
612
610
  label_map,
613
611
  vmin,
614
612
  vmax,
615
- weight_turbine,
616
613
  to_file,
617
614
  write_pars,
618
615
  ret_states,
@@ -1,4 +1,3 @@
1
- from tabnanny import verbose
2
1
  import matplotlib.pyplot as plt
3
2
  import numpy as np
4
3
  import pandas as pd
@@ -182,19 +181,19 @@ class TurbineTypeCurves(Output):
182
181
  t = f"{vv}, {turbine_type}" if titles[i] is None else titles[i]
183
182
  ax.set_title(t)
184
183
 
185
- l = "Wind speed [m/s]" if x_label is None else x_label
186
- ax.set_xlabel(l)
184
+ lb = "Wind speed [m/s]" if x_label is None else x_label
185
+ ax.set_xlabel(lb)
187
186
 
188
187
  if y_labels[i] is None:
189
188
  if v == FV.P:
190
- l = f"Power [kW]"
189
+ lb = "Power [kW]"
191
190
  elif v == FV.CT:
192
- l = "ct [-]"
191
+ lb = "ct [-]"
193
192
  else:
194
- l = v
193
+ lb = v
195
194
  else:
196
- l = y_labels[i]
197
- ax.set_ylabel(l)
195
+ lb = y_labels[i]
196
+ ax.set_ylabel(lb)
198
197
 
199
198
  ax.grid()
200
199
 
foxes/utils/__init__.py CHANGED
@@ -2,23 +2,41 @@
2
2
  General utilities.
3
3
  """
4
4
 
5
- from .wind_dir import wd2uv, wd2wdvec, wdvec2wd, uv2wd, delta_wd
6
- from .pandas_utils import PandasFileHelper
7
- from .xarray_utils import write_nc
8
- from .subclasses import all_subclasses, new_cls, new_instance
9
- from .dict import Dict
10
- from .factory import Factory, FDict, WakeKFactory
11
- from .data_book import DataBook
12
- from .cubic_roots import cubic_roots
13
- from .geopandas_utils import read_shp, shp2csv, read_shp_polygons, shp2geom2d
14
- from .load import import_module, load_module
15
- from .exec_python import exec_python
16
- from .regularize import sqrt_reg
17
- from .tab_files import read_tab_file
18
- from .random_xy import random_xy_square
19
- from .dev_utils import print_mem
20
- from .wrg_utils import ReaderWRG
5
+ from .wind_dir import wd2uv as wd2uv
6
+ from .wind_dir import wd2wdvec as wd2wdvec
7
+ from .wind_dir import wdvec2wd as wdvec2wd
8
+ from .wind_dir import uv2wd as uv2wd
9
+ from .wind_dir import delta_wd as delta_wd
21
10
 
22
- from . import two_circles
23
- from . import abl
24
- from . import geom2d
11
+ from .subclasses import all_subclasses as all_subclasses
12
+ from .subclasses import new_cls as new_cls
13
+ from .subclasses import new_instance as new_instance
14
+
15
+ from .factory import Factory as Factory
16
+ from .factory import FDict as FDict
17
+ from .factory import WakeKFactory as WakeKFactory
18
+
19
+ from .geopandas_utils import read_shp as read_shp
20
+ from .geopandas_utils import shp2csv as shp2csv
21
+ from .geopandas_utils import read_shp_polygons as read_shp_polygons
22
+ from .geopandas_utils import shp2geom2d as shp2geom2d
23
+
24
+ from .load import import_module as import_module
25
+ from .load import load_module as load_module
26
+
27
+ from .pandas_utils import PandasFileHelper as PandasFileHelper
28
+ from .xarray_utils import write_nc as write_nc
29
+ from .dict import Dict as Dict
30
+ from .data_book import DataBook as DataBook
31
+ from .cubic_roots import cubic_roots as cubic_roots
32
+ from .exec_python import exec_python as exec_python
33
+ from .regularize import sqrt_reg as sqrt_reg
34
+ from .tab_files import read_tab_file as read_tab_file
35
+ from .random_xy import random_xy_square as random_xy_square
36
+ from .dev_utils import print_mem as print_mem
37
+ from .wrg_utils import ReaderWRG as ReaderWRG
38
+ from .weibull import weibull_weights as weibull_weights
39
+
40
+ from . import two_circles as two_circles
41
+ from . import abl as abl
42
+ from . import geom2d as geom2d
@@ -2,7 +2,7 @@
2
2
  Atmospheric boundary layer functions.
3
3
  """
4
4
 
5
- from . import neutral
6
- from . import stable
7
- from . import unstable
8
- from . import sheared
5
+ from . import neutral as neutral
6
+ from . import stable as stable
7
+ from . import unstable as unstable
8
+ from . import sheared as sheared
@@ -104,7 +104,7 @@ def test_cubic_roots(roots, a0, a1, a2, a3=None, tol=1.0e-12):
104
104
  c2 = a2[n]
105
105
  c3 = a3[n]
106
106
 
107
- print(f"Polynomial {n}: a = {(c0,c1,c2,c3)}")
107
+ print(f"Polynomial {n}: a = {(c0, c1, c2, c3)}")
108
108
 
109
109
  rts = np.unique(roots[n])
110
110
  rts = rts[~np.isnan(rts)]
foxes/utils/data_book.py CHANGED
@@ -66,9 +66,10 @@ class DataBook:
66
66
  except AttributeError:
67
67
  contents = list(resources.contents(package))
68
68
 
69
- check_f = lambda f: any(
70
- [len(f) > len(s) and f[-len(s) :] == s for s in file_sfx]
71
- )
69
+ def check_f(f):
70
+ """little helper function to check file endings"""
71
+ return any([len(f) > len(s) and f[-len(s) :] == s for s in file_sfx])
72
+
72
73
  contents = [f for f in contents if check_f(f)]
73
74
 
74
75
  try:
foxes/utils/dict.py CHANGED
@@ -77,9 +77,9 @@ class Dict(dict):
77
77
  """
78
78
  try:
79
79
  if len(deflt):
80
- assert (
81
- len(deflt) == 1
82
- ), f"Expecting a single default entry, got {len(deflt)}"
80
+ assert len(deflt) == 1, (
81
+ f"Expecting a single default entry, got {len(deflt)}"
82
+ )
83
83
  data = self.get(key, deflt[0])
84
84
  else:
85
85
  data = self[key]
@@ -1,7 +1,7 @@
1
- import numpy as np
2
- import pandas as pd
3
- import xarray as xr
4
- import matplotlib.pyplot as plt
1
+ import numpy as np # noqa: F401
2
+ import pandas as pd # noqa: F401
3
+ import xarray as xr # noqa: F401
4
+ import matplotlib.pyplot as plt # noqa: F401
5
5
 
6
6
 
7
7
  def exec_python(s, indicator="%", newline=";", globals=globals(), locals={}):
@@ -38,7 +38,7 @@ def exec_python(s, indicator="%", newline=";", globals=globals(), locals={}):
38
38
  L = len(indicator)
39
39
  if len(s) > L and s[:L] == indicator:
40
40
  a = s[L:]
41
- if not indicator in a:
41
+ if indicator not in a:
42
42
  exec(a, globals, locals)
43
43
  else:
44
44
  ilist = a.split(indicator)
foxes/utils/factory.py CHANGED
@@ -526,9 +526,7 @@ class WakeKFactory:
526
526
  s += f"\n {v} from {list(f0.options[v])}"
527
527
  else:
528
528
  s += f"\n {v}={f0.hints.get(v, '(value)')}"
529
- s += (
530
- f"\n [wake_k]=(None or k<k> or ka<ka> or ka<ka>_kb<kb>, e.g. 004 for 0.04)"
531
- )
529
+ s += "\n [wake_k]=(None or k<k> or ka<ka> or ka<ka>_kb<kb>, e.g. 004 for 0.04)"
532
530
  return s
533
531
 
534
532
 
@@ -2,8 +2,10 @@
2
2
  Geometries in two dimensions.
3
3
  """
4
4
 
5
- from .area_geometry import AreaGeometry, InvertedAreaGeometry
6
- from .area_geometry import AreaUnion, AreaIntersection
7
- from .polygon import ClosedPolygon
8
- from .circle import Circle
9
- from .half_plane import HalfPlane
5
+ from .area_geometry import AreaGeometry as AreaGeometry
6
+ from .area_geometry import InvertedAreaGeometry as InvertedAreaGeometry
7
+ from .area_geometry import AreaUnion as AreaUnion
8
+ from .area_geometry import AreaIntersection as AreaIntersection
9
+ from .polygon import ClosedPolygon as ClosedPolygon
10
+ from .circle import Circle as Circle
11
+ from .half_plane import HalfPlane as HalfPlane