foxes 0.6.1__py3-none-any.whl → 0.7__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 (129) hide show
  1. foxes/VERSION +1 -1
  2. foxes/algorithms/downwind/downwind.py +131 -65
  3. foxes/algorithms/downwind/models/__init__.py +2 -1
  4. foxes/algorithms/downwind/models/farm_wakes_calc.py +87 -55
  5. foxes/algorithms/downwind/models/init_farm_data.py +134 -0
  6. foxes/algorithms/downwind/models/point_wakes_calc.py +54 -65
  7. foxes/algorithms/downwind/models/{calc_order.py → reorder_farm_output.py} +28 -26
  8. foxes/algorithms/iterative/iterative.py +100 -51
  9. foxes/algorithms/iterative/models/convergence.py +3 -3
  10. foxes/algorithms/iterative/models/farm_wakes_calc.py +55 -48
  11. foxes/algorithms/sequential/models/seq_state.py +7 -6
  12. foxes/algorithms/sequential/sequential.py +81 -44
  13. foxes/constants.py +33 -18
  14. foxes/core/__init__.py +2 -2
  15. foxes/core/algorithm.py +31 -12
  16. foxes/core/data.py +335 -41
  17. foxes/core/data_calc_model.py +27 -23
  18. foxes/core/farm_controller.py +27 -28
  19. foxes/core/farm_data_model.py +26 -4
  20. foxes/core/model.py +186 -129
  21. foxes/core/partial_wakes_model.py +84 -81
  22. foxes/core/point_data_model.py +51 -18
  23. foxes/core/rotor_model.py +59 -77
  24. foxes/core/states.py +6 -6
  25. foxes/core/turbine_model.py +4 -4
  26. foxes/core/turbine_type.py +24 -0
  27. foxes/core/vertical_profile.py +3 -3
  28. foxes/core/wake_frame.py +91 -50
  29. foxes/core/wake_model.py +74 -43
  30. foxes/core/wake_superposition.py +29 -26
  31. foxes/input/farm_layout/__init__.py +1 -0
  32. foxes/input/farm_layout/from_random.py +49 -0
  33. foxes/input/states/__init__.py +1 -1
  34. foxes/input/states/create/__init__.py +1 -0
  35. foxes/input/states/create/random_abl_states.py +6 -2
  36. foxes/input/states/create/random_timeseries.py +56 -0
  37. foxes/input/states/field_data_nc.py +12 -8
  38. foxes/input/states/multi_height.py +24 -14
  39. foxes/input/states/scan_ws.py +13 -17
  40. foxes/input/states/single.py +28 -20
  41. foxes/input/states/states_table.py +22 -18
  42. foxes/models/axial_induction_models/betz.py +1 -1
  43. foxes/models/farm_models/turbine2farm.py +2 -2
  44. foxes/models/model_book.py +40 -14
  45. foxes/models/partial_wakes/__init__.py +2 -2
  46. foxes/models/partial_wakes/axiwake.py +73 -200
  47. foxes/models/partial_wakes/centre.py +40 -0
  48. foxes/models/partial_wakes/grid.py +7 -63
  49. foxes/models/partial_wakes/rotor_points.py +53 -147
  50. foxes/models/partial_wakes/segregated.py +158 -0
  51. foxes/models/partial_wakes/top_hat.py +88 -196
  52. foxes/models/point_models/set_uniform_data.py +4 -4
  53. foxes/models/point_models/tke2ti.py +4 -4
  54. foxes/models/point_models/wake_deltas.py +4 -4
  55. foxes/models/rotor_models/centre.py +15 -19
  56. foxes/models/rotor_models/grid.py +2 -1
  57. foxes/models/rotor_models/levels.py +2 -1
  58. foxes/models/turbine_models/__init__.py +0 -1
  59. foxes/models/turbine_models/calculator.py +11 -7
  60. foxes/models/turbine_models/kTI_model.py +13 -11
  61. foxes/models/turbine_models/lookup_table.py +22 -9
  62. foxes/models/turbine_models/power_mask.py +81 -51
  63. foxes/models/turbine_models/rotor_centre_calc.py +17 -20
  64. foxes/models/turbine_models/sector_management.py +5 -6
  65. foxes/models/turbine_models/set_farm_vars.py +49 -20
  66. foxes/models/turbine_models/table_factors.py +5 -5
  67. foxes/models/turbine_models/thrust2ct.py +9 -5
  68. foxes/models/turbine_models/yaw2yawm.py +7 -13
  69. foxes/models/turbine_models/yawm2yaw.py +7 -11
  70. foxes/models/turbine_types/PCt_file.py +84 -3
  71. foxes/models/turbine_types/PCt_from_two.py +7 -3
  72. foxes/models/turbine_types/null_type.py +2 -2
  73. foxes/models/turbine_types/wsrho2PCt_from_two.py +2 -2
  74. foxes/models/turbine_types/wsti2PCt_from_two.py +6 -2
  75. foxes/models/wake_frames/farm_order.py +26 -22
  76. foxes/models/wake_frames/rotor_wd.py +32 -31
  77. foxes/models/wake_frames/seq_dynamic_wakes.py +112 -64
  78. foxes/models/wake_frames/streamlines.py +51 -47
  79. foxes/models/wake_frames/timelines.py +59 -47
  80. foxes/models/wake_frames/yawed_wakes.py +63 -40
  81. foxes/models/wake_models/axisymmetric.py +31 -35
  82. foxes/models/wake_models/dist_sliced.py +50 -56
  83. foxes/models/wake_models/gaussian.py +33 -35
  84. foxes/models/wake_models/induction/rankine_half_body.py +79 -87
  85. foxes/models/wake_models/induction/rathmann.py +56 -63
  86. foxes/models/wake_models/induction/self_similar.py +59 -62
  87. foxes/models/wake_models/ti/crespo_hernandez.py +83 -74
  88. foxes/models/wake_models/ti/iec_ti.py +65 -75
  89. foxes/models/wake_models/top_hat.py +60 -69
  90. foxes/models/wake_models/wake_mirror.py +49 -54
  91. foxes/models/wake_models/wind/bastankhah14.py +44 -66
  92. foxes/models/wake_models/wind/bastankhah16.py +84 -111
  93. foxes/models/wake_models/wind/jensen.py +67 -89
  94. foxes/models/wake_models/wind/turbopark.py +93 -133
  95. foxes/models/wake_superpositions/ti_linear.py +33 -27
  96. foxes/models/wake_superpositions/ti_max.py +33 -27
  97. foxes/models/wake_superpositions/ti_pow.py +35 -27
  98. foxes/models/wake_superpositions/ti_quadratic.py +33 -27
  99. foxes/models/wake_superpositions/ws_linear.py +39 -32
  100. foxes/models/wake_superpositions/ws_max.py +40 -33
  101. foxes/models/wake_superpositions/ws_pow.py +39 -32
  102. foxes/models/wake_superpositions/ws_product.py +35 -28
  103. foxes/models/wake_superpositions/ws_quadratic.py +39 -32
  104. foxes/opt/constraints/min_dist.py +1 -1
  105. foxes/opt/objectives/farm_vars.py +1 -1
  106. foxes/opt/problems/layout/farm_layout.py +38 -97
  107. foxes/output/__init__.py +1 -0
  108. foxes/output/farm_results_eval.py +1 -1
  109. foxes/output/flow_plots_2d/flow_plots.py +2 -0
  110. foxes/output/flow_plots_2d/get_fig.py +2 -0
  111. foxes/output/grids.py +1 -1
  112. foxes/output/rose_plot.py +3 -3
  113. foxes/output/rotor_point_plots.py +117 -0
  114. foxes/output/turbine_type_curves.py +2 -2
  115. foxes/utils/__init__.py +2 -1
  116. foxes/utils/load.py +29 -0
  117. foxes/utils/random_xy.py +56 -0
  118. foxes/utils/runners/runners.py +13 -1
  119. foxes/utils/windrose_plot.py +1 -1
  120. foxes/variables.py +10 -0
  121. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/METADATA +13 -7
  122. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/RECORD +126 -122
  123. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/WHEEL +1 -1
  124. foxes/models/partial_wakes/distsliced.py +0 -322
  125. foxes/models/partial_wakes/mapped.py +0 -252
  126. foxes/models/turbine_models/set_XYHD.py +0 -130
  127. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/LICENSE +0 -0
  128. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/top_level.txt +0 -0
  129. {foxes-0.6.1.dist-info → foxes-0.7.dist-info}/zip-safe +0 -0
foxes/output/rose_plot.py CHANGED
@@ -33,7 +33,7 @@ class RosePlotOutput(Output):
33
33
  The calculation results (farm or points)
34
34
 
35
35
  """
36
- dims = list(results.dims.keys())
36
+ dims = list(results.sizes.keys())
37
37
  if dims[1] == FC.TURBINE:
38
38
  self._rtype = FC.TURBINE
39
39
  elif dims[1] == FC.POINT:
@@ -170,7 +170,7 @@ class RosePlotOutput(Output):
170
170
  data[wd_var] = pd.cut(data["wd"], wdb, labels=wds)
171
171
  data[lgd] = pd.cut(data[lgd], var_bins, right=False, include_lowest=True)
172
172
 
173
- grp = data[[wd_var, lgd, "frequency"]].groupby([wd_var, lgd])
173
+ grp = data[[wd_var, lgd, "frequency"]].groupby([wd_var, lgd], observed=False)
174
174
  data = grp.sum().reset_index()
175
175
 
176
176
  data[wd_var] = data[wd_var].astype(np.float64)
@@ -386,7 +386,7 @@ class StatesRosePlotOutput(RosePlotOutput):
386
386
  )
387
387
 
388
388
  mbook = mbook if mbook is not None else ModelBook()
389
- algo = Downwind(mbook, farm, states, wake_models=[], verbosity=0)
389
+ algo = Downwind(farm, states, wake_models=[], mbook=mbook, verbosity=0)
390
390
 
391
391
  results = algo.calc_farm(ambient=True).rename_vars({ws_var: FV.AMB_WS})
392
392
 
@@ -0,0 +1,117 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from matplotlib import colormaps
4
+ from matplotlib.colors import LinearSegmentedColormap
5
+
6
+ from foxes.input.states import SingleStateStates
7
+ from foxes.core import WindFarm
8
+ from foxes.algorithms import Downwind
9
+
10
+
11
+ class RotorPointPlot:
12
+ """
13
+ Visualizes rotor points and their weights.
14
+
15
+ Attributes
16
+ ----------
17
+ rotor_model: foxes.core.RotorModel
18
+ The rotor model
19
+ algo: foxes.core.Algorithm, optional
20
+ The algorithm
21
+
22
+ :group: output
23
+
24
+ """
25
+
26
+ def __init__(self, rotor_model, algo=None):
27
+ """
28
+ Constructor.
29
+
30
+ Parameters
31
+ ----------
32
+ rotor_model: foxes.core.RotorModel
33
+ The rotor model
34
+ algo: foxes.core.Algorithm, optional
35
+ The algorithm
36
+
37
+ """
38
+ self.rotor_model = rotor_model
39
+ self.algo = algo
40
+
41
+ if self.algo is None:
42
+ farm = WindFarm()
43
+ states = SingleStateStates(ws=9, wd=270, ti=0.1, rho=1.225)
44
+ self.algo = Downwind(farm, states, [])
45
+
46
+ def get_point_figure(
47
+ self,
48
+ ax=None,
49
+ fig=None,
50
+ figsize=(5, 5),
51
+ title=None,
52
+ **kwargs,
53
+ ):
54
+ """
55
+ Get a scatter plot of the rotor points.
56
+
57
+ Parameters
58
+ ----------
59
+ ax: matplotlib.Axes, optional
60
+ The plot axes
61
+ fig: matplotlib.Figure, optional
62
+ The figure object
63
+ figsize: tuple
64
+ The default figure size
65
+ title: str, optional
66
+ The plot title
67
+ kwargs: dict, optional
68
+ Additional arguments for pyplot.scatter
69
+
70
+ Returns
71
+ -------
72
+ ax: matplotlib.Axes
73
+ The plot axes
74
+
75
+ """
76
+ if fig is None:
77
+ fig = plt.figure(figsize=figsize)
78
+ ax = fig.add_subplot(111)
79
+ else:
80
+ ax = fig.axes[0] if ax is None else ax
81
+
82
+ if not self.rotor_model.initialized:
83
+ self.rotor_model.initialize(self.algo)
84
+
85
+ points = self.rotor_model.design_points()
86
+ weights = self.rotor_model.rotor_point_weights() * 100
87
+
88
+ cmap = colormaps[kwargs.pop("cmap", "viridis_r")]
89
+ wlist = np.sort(np.unique(weights))
90
+
91
+ im = ax.scatter(points[:, 1], points[:, 2], c=weights, cmap=cmap, **kwargs)
92
+ ax.add_patch(plt.Circle((0, 0), 1, color="black", fill=False, alpha=0.8))
93
+
94
+ ax.set_xlabel("x/D")
95
+ ax.set_ylabel("y/D")
96
+ if title is None:
97
+ title = str(self.rotor_model)
98
+ if title != "":
99
+ ax.set_title(title)
100
+ ax.set_aspect("equal", adjustable="box")
101
+
102
+ tlabels = [f"{wlist[-1]:.02f}"]
103
+ for i in range(len(wlist) - 2, -1, -1):
104
+ w = wlist[i]
105
+ w1 = wlist[i + 1]
106
+ if (w1 - w) / (wlist[-1] - wlist[0]) > 0.05:
107
+ tlabels.insert(0, f"{w:.2f}")
108
+ elif i == 0:
109
+ tlabels[0] = ""
110
+ tlabels.insert(0, f"{w:.2f}")
111
+ else:
112
+ tlabels.insert(0, "")
113
+
114
+ cbar = fig.colorbar(im, ax=ax, label="Point weight [%]", shrink=0.8)
115
+ cbar.set_ticks(ticks=wlist, labels=tlabels)
116
+
117
+ return im
@@ -133,7 +133,7 @@ class TurbineTypeCurves(Output):
133
133
  verbosity=0,
134
134
  )
135
135
 
136
- algo = Downwind(self.mbook, farm, states, wake_models=[], verbosity=0)
136
+ algo = Downwind(farm, states, wake_models=[], mbook=self.mbook, verbosity=0)
137
137
 
138
138
  results = algo.calc_farm()
139
139
 
@@ -149,7 +149,7 @@ class TurbineTypeCurves(Output):
149
149
  verbosity=0,
150
150
  )
151
151
 
152
- algo = Downwind(self.mbook, farm, states, wake_models=[], verbosity=0)
152
+ algo = Downwind(farm, states, wake_models=[], mbook=self.mbook, verbosity=0)
153
153
 
154
154
  results1 = algo.calc_farm()
155
155
 
foxes/utils/__init__.py CHANGED
@@ -10,11 +10,12 @@ from .dict import Dict
10
10
  from .data_book import DataBook
11
11
  from .cubic_roots import cubic_roots
12
12
  from .geopandas_utils import read_shp, shp2csv, read_shp_polygons, shp2geom2d
13
- from .load import import_module
13
+ from .load import import_module, load_module
14
14
  from .exec_python import exec_python
15
15
  from .regularize import sqrt_reg
16
16
  from .windrose_plot import TabWindroseAxes
17
17
  from .tab_files import read_tab_file
18
+ from .random_xy import random_xy_square
18
19
 
19
20
  from . import two_circles
20
21
  from . import abl
foxes/utils/load.py CHANGED
@@ -1,4 +1,6 @@
1
1
  import importlib
2
+ import importlib.util
3
+ import sys
2
4
 
3
5
 
4
6
  def import_module(name, package=None, hint=None):
@@ -29,3 +31,30 @@ def import_module(name, package=None, hint=None):
29
31
  mdl = name if package is None else f"{package}.{name}"
30
32
  hint = hint if hint is not None else f"pip install {name}"
31
33
  raise ModuleNotFoundError(f"Module '{mdl}' not found, maybe try '{hint}'")
34
+
35
+
36
+ def load_module(name, path):
37
+ """
38
+ Imports a module from file path
39
+
40
+ Parameters
41
+ ----------
42
+ name: str
43
+ The name of the module
44
+ path: str
45
+ The path to the python file
46
+
47
+ Returns
48
+ -------
49
+ module:
50
+ The module object
51
+
52
+ :group: utils
53
+
54
+ """
55
+ spec = importlib.util.spec_from_file_location(name, path)
56
+ module = importlib.util.module_from_spec(spec)
57
+ sys.modules[name] = module
58
+ spec.loader.exec_module(module)
59
+
60
+ return module
@@ -0,0 +1,56 @@
1
+ import numpy as np
2
+ from scipy.spatial.distance import cdist
3
+
4
+
5
+ def random_xy_square(
6
+ n,
7
+ min_dist=500,
8
+ xmax_ini=None,
9
+ growth=1.02,
10
+ seed=None,
11
+ verbosity=1,
12
+ ):
13
+ """
14
+ Creates random xy positions within a square,
15
+ with mean (0, 0)
16
+
17
+ Parameters
18
+ ----------
19
+ n: int
20
+ The number of positions
21
+ min_dist: float
22
+ The minimal distance between any two positions
23
+ xmax_ini: float, optional
24
+ The initial maximal distance of any coordinates
25
+ growth: float
26
+ The growth factor of the initial radius, must be
27
+ greater 1
28
+ seed: int, optional
29
+ The random seed
30
+ verbosity: int
31
+ The verbosity level. 0 = silent
32
+
33
+ Returns
34
+ -------
35
+ xy: numpy.ndarray
36
+ The positions, shape: (n, 2)
37
+
38
+ :group: utils
39
+
40
+ """
41
+ if seed:
42
+ np.random.seed(seed)
43
+
44
+ xmax = np.sqrt(n) * min_dist if xmax_ini is None else xmax_ini
45
+ xy = np.random.uniform(0, xmax, (n, 2))
46
+ while True:
47
+ dists = cdist(xy, xy)
48
+ np.fill_diagonal(dists, np.inf)
49
+ sel = np.unique(np.where(dists < min_dist)[0])
50
+ if not len(sel):
51
+ break
52
+ if verbosity > 0:
53
+ print(f"Re-generating coordinates: {len(sel)}, xmax = {xmax:.1f}")
54
+ xmax *= growth
55
+ xy[sel] = np.random.uniform(0, xmax, (len(sel), 2))
56
+ return xy - np.mean(xy, axis=0)[None, :]
@@ -194,7 +194,19 @@ class DaskRunner(Runner):
194
194
  """
195
195
  Initialize the runner
196
196
  """
197
- if self.scheduler == "distributed":
197
+ if self.scheduler is not None:
198
+ dask.config.set(scheduler=self.scheduler)
199
+
200
+ if self.scheduler == "dthreads":
201
+ self.print("Launching local dask cluster..")
202
+
203
+ cargs = deepcopy(self.cluster_args)
204
+ del cargs["processes"]
205
+ self._client = Client(processes=False, **self.client_args, **cargs)
206
+
207
+ self.print(f"Dashboard: {self._client.dashboard_link}\n")
208
+
209
+ elif self.scheduler == "distributed":
198
210
  self.print("Launching local dask cluster..")
199
211
 
200
212
  self._cluster = LocalCluster(**self.cluster_args)
@@ -104,6 +104,7 @@ class TabWindroseAxes(WindroseAxes):
104
104
  angle = 360.0 / nsector
105
105
  dir_bins = np.arange(-angle / 2, 360.0 + angle, angle, dtype=float)
106
106
  dir_edges = dir_bins.tolist()
107
+
107
108
  dir_edges.pop(-1)
108
109
  dir_edges[0] = dir_edges.pop(-1)
109
110
  dir_bins[0] = 0.0
@@ -119,7 +120,6 @@ class TabWindroseAxes(WindroseAxes):
119
120
  bins,
120
121
  table,
121
122
  )
122
-
123
123
  return bins, nbins, nsector, colors, angles, kwargs
124
124
 
125
125
  def legend(self, loc="upper right", *args, **kwargs):
foxes/variables.py CHANGED
@@ -34,6 +34,16 @@ ORDER = "order"
34
34
  :group: foxes.variables
35
35
  """
36
36
 
37
+ ORDER_INV = "order_inv"
38
+ """ The inverse of the turbine order
39
+ :group: foxes.variables
40
+ """
41
+
42
+ ORDER_SSEL = "order_ssel"
43
+ """ The states selection for applying the order
44
+ :group: foxes.variables
45
+ """
46
+
37
47
  WS = "WS"
38
48
  """ The wind speed in m/s
39
49
  :group: foxes.variables
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foxes
3
- Version: 0.6.1
3
+ Version: 0.7
4
4
  Summary: Farm Optimization and eXtended yield Evaluation Software
5
5
  Author: Fraunhofer IWES
6
6
  Author-email: jonas.schmidt@iwes.fraunhofer.de
@@ -43,6 +43,7 @@ Requires-Dist: nbsphinx ; extra == 'doc'
43
43
  Requires-Dist: ipykernel ; extra == 'doc'
44
44
  Requires-Dist: ipywidgets ; extra == 'doc'
45
45
  Requires-Dist: m2r2 ; extra == 'doc'
46
+ Requires-Dist: lxml-html-clean ; extra == 'doc'
46
47
  Provides-Extra: io
47
48
  Requires-Dist: windio >=1.0 ; extra == 'io'
48
49
  Provides-Extra: scripts
@@ -102,7 +103,7 @@ Evaluation Software"`
102
103
  }
103
104
  ```
104
105
 
105
- ## Requirements
106
+ ## Installation via pip
106
107
 
107
108
  The supported Python versions are:
108
109
 
@@ -110,8 +111,7 @@ The supported Python versions are:
110
111
  - `Python 3.9`
111
112
  - `Python 3.10`
112
113
  - `Python 3.11`
113
-
114
- ## Installation via pip
114
+ - `Python 3.12`
115
115
 
116
116
  ### Virtual Python environment
117
117
 
@@ -162,6 +162,14 @@ The last line makes sure that all your code changes are included whenever import
162
162
 
163
163
  ## Installation via conda
164
164
 
165
+ The supported Python versions are:
166
+
167
+ - `Python 3.8`
168
+ - `Python 3.9`
169
+ - `Python 3.10`
170
+ - `Python 3.11`
171
+ - `Python 3.12`
172
+
165
173
  ### Preparation
166
174
 
167
175
  It is strongly recommend to use the `libmamba` dependency solver instead of the default solver. Install it once by
@@ -233,12 +241,10 @@ import foxes
233
241
 
234
242
  states = foxes.input.states.Timeseries("timeseries_3000.csv.gz", ["WS", "WD","TI","RHO"])
235
243
 
236
- mbook = foxes.ModelBook()
237
-
238
244
  farm = foxes.WindFarm()
239
245
  foxes.input.farm_layout.add_from_file(farm, "test_farm_67.csv", turbine_models=["NREL5MW"])
240
246
 
241
- algo = foxes.algorithms.Downwind(mbook, farm, states, ["Jensen_linear_k007"])
247
+ algo = foxes.algorithms.Downwind(farm, states, ["Jensen_linear_k007"])
242
248
  farm_results = algo.calc_farm()
243
249
 
244
250
  print(farm_results)