foxes 0.7.4.25__py3-none-any.whl → 0.8.1__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.
- foxes/VERSION +1 -1
- {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/METADATA +20 -116
- {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/RECORD +7 -33
- foxes/opt/__init__.py +0 -9
- foxes/opt/constraints/__init__.py +0 -6
- foxes/opt/constraints/area_geometry.py +0 -214
- foxes/opt/constraints/min_dist.py +0 -239
- foxes/opt/core/__init__.py +0 -9
- foxes/opt/core/farm_constraint.py +0 -96
- foxes/opt/core/farm_objective.py +0 -97
- foxes/opt/core/farm_opt_problem.py +0 -346
- foxes/opt/core/farm_vars_problem.py +0 -219
- foxes/opt/core/pop_states.py +0 -206
- foxes/opt/objectives/__init__.py +0 -6
- foxes/opt/objectives/farm_vars.py +0 -323
- foxes/opt/objectives/max_n_turbines.py +0 -142
- foxes/opt/problems/__init__.py +0 -7
- foxes/opt/problems/layout/__init__.py +0 -9
- foxes/opt/problems/layout/farm_layout.py +0 -137
- foxes/opt/problems/layout/geom_layouts/__init__.py +0 -10
- foxes/opt/problems/layout/geom_layouts/constraints.py +0 -802
- foxes/opt/problems/layout/geom_layouts/geom_layout.py +0 -290
- foxes/opt/problems/layout/geom_layouts/geom_layout_gridded.py +0 -276
- foxes/opt/problems/layout/geom_layouts/geom_reggrid.py +0 -351
- foxes/opt/problems/layout/geom_layouts/geom_reggrids.py +0 -482
- foxes/opt/problems/layout/geom_layouts/objectives.py +0 -666
- foxes/opt/problems/layout/reggrids_layout.py +0 -417
- foxes/opt/problems/layout/regular_layout.py +0 -350
- foxes/opt/problems/opt_farm_vars.py +0 -586
- {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/LICENSE +0 -0
- {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/WHEEL +0 -0
- {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/top_level.txt +0 -0
- {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/zip-safe +0 -0
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
import matplotlib.pyplot as plt
|
|
3
|
-
from scipy.spatial.distance import cdist
|
|
4
|
-
from iwopy import Problem
|
|
5
|
-
|
|
6
|
-
import foxes.constants as FC
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class GeomRegGrid(Problem):
|
|
10
|
-
"""
|
|
11
|
-
A regular grid within a boundary geometry.
|
|
12
|
-
|
|
13
|
-
This optimization problem does not involve
|
|
14
|
-
wind farms.
|
|
15
|
-
|
|
16
|
-
Attributes
|
|
17
|
-
----------
|
|
18
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
19
|
-
The boundary geometry
|
|
20
|
-
n_turbines: int
|
|
21
|
-
The number of turbines in the layout
|
|
22
|
-
min_dist: float
|
|
23
|
-
The minimal distance between points
|
|
24
|
-
max_dist: float
|
|
25
|
-
The maximal distance between points
|
|
26
|
-
D: float
|
|
27
|
-
The diameter of circle fully within boundary
|
|
28
|
-
|
|
29
|
-
:group: opt.problems.layout.geom_layouts
|
|
30
|
-
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
def __init__(
|
|
34
|
-
self,
|
|
35
|
-
boundary,
|
|
36
|
-
n_turbines,
|
|
37
|
-
min_dist,
|
|
38
|
-
max_dist=None,
|
|
39
|
-
D=None,
|
|
40
|
-
):
|
|
41
|
-
"""
|
|
42
|
-
Constructor.
|
|
43
|
-
|
|
44
|
-
Parameters
|
|
45
|
-
----------
|
|
46
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
47
|
-
The boundary geometry
|
|
48
|
-
n_turbines: int
|
|
49
|
-
The number of turbines in the layout
|
|
50
|
-
min_dist: float
|
|
51
|
-
The minimal distance between points
|
|
52
|
-
max_dist: float, optional
|
|
53
|
-
The maximal distance between points
|
|
54
|
-
D: float, optional
|
|
55
|
-
The diameter of circle fully within boundary
|
|
56
|
-
|
|
57
|
-
"""
|
|
58
|
-
super().__init__(name="geom_reg_grid")
|
|
59
|
-
|
|
60
|
-
self.boundary = boundary
|
|
61
|
-
self.n_turbines = n_turbines
|
|
62
|
-
self.min_dist = float(min_dist)
|
|
63
|
-
self.max_dist = float(max_dist) if max_dist is not None else max_dist
|
|
64
|
-
self.D = D
|
|
65
|
-
|
|
66
|
-
self._SX = "sx"
|
|
67
|
-
self._SY = "sy"
|
|
68
|
-
self._DX = "dx"
|
|
69
|
-
self._DY = "dy"
|
|
70
|
-
self._ALPHA = "alpha"
|
|
71
|
-
|
|
72
|
-
def initialize(self, verbosity=1):
|
|
73
|
-
"""
|
|
74
|
-
Initialize the object.
|
|
75
|
-
|
|
76
|
-
Parameters
|
|
77
|
-
----------
|
|
78
|
-
verbosity: int
|
|
79
|
-
The verbosity level, 0 = silent
|
|
80
|
-
|
|
81
|
-
"""
|
|
82
|
-
super().initialize(verbosity)
|
|
83
|
-
|
|
84
|
-
pmin = self.boundary.p_min()
|
|
85
|
-
pmax = self.boundary.p_max()
|
|
86
|
-
self._pc = 0.5 * (pmin + pmax)
|
|
87
|
-
self._diag = np.linalg.norm(pmax - pmin)
|
|
88
|
-
self.max_dist = self._diag if self.max_dist is None else self.max_dist
|
|
89
|
-
self._nrow = (
|
|
90
|
-
int(np.maximum(self._diag / self.min_dist, np.sqrt(self.n_turbines) + 0.5))
|
|
91
|
-
+ 3
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
if verbosity > 0:
|
|
95
|
-
print(f"Grid data:")
|
|
96
|
-
print(f" pmin = {pmin}")
|
|
97
|
-
print(f" pmax = {pmax}")
|
|
98
|
-
print(f" min dist = {self.min_dist}")
|
|
99
|
-
print(f" max dist = {self.max_dist}")
|
|
100
|
-
print(f" n row max = {self._nrow}")
|
|
101
|
-
print(f" n max = {self._nrow**2}")
|
|
102
|
-
|
|
103
|
-
self.apply_individual(self.initial_values_int(), self.initial_values_float())
|
|
104
|
-
|
|
105
|
-
def var_names_float(self):
|
|
106
|
-
"""
|
|
107
|
-
The names of float variables.
|
|
108
|
-
|
|
109
|
-
Returns
|
|
110
|
-
-------
|
|
111
|
-
names: list of str
|
|
112
|
-
The names of the float variables
|
|
113
|
-
|
|
114
|
-
"""
|
|
115
|
-
return list(np.array([self._SX, self._SY, self._DX, self._DY, self._ALPHA]))
|
|
116
|
-
|
|
117
|
-
def initial_values_float(self):
|
|
118
|
-
"""
|
|
119
|
-
The initial values of the float variables.
|
|
120
|
-
|
|
121
|
-
Returns
|
|
122
|
-
-------
|
|
123
|
-
values: numpy.ndarray
|
|
124
|
-
Initial float values, shape: (n_vars_float,)
|
|
125
|
-
|
|
126
|
-
"""
|
|
127
|
-
vals = np.zeros(5, dtype=FC.DTYPE)
|
|
128
|
-
vals[2:4] = self.min_dist
|
|
129
|
-
return vals
|
|
130
|
-
|
|
131
|
-
def min_values_float(self):
|
|
132
|
-
"""
|
|
133
|
-
The minimal values of the float variables.
|
|
134
|
-
|
|
135
|
-
Use -numpy.inf for unbounded.
|
|
136
|
-
|
|
137
|
-
Returns
|
|
138
|
-
-------
|
|
139
|
-
values: numpy.ndarray
|
|
140
|
-
Minimal float values, shape: (n_vars_float,)
|
|
141
|
-
|
|
142
|
-
"""
|
|
143
|
-
vals = np.zeros(5, dtype=FC.DTYPE)
|
|
144
|
-
vals[:2] = -0.5
|
|
145
|
-
vals[2:4] = self.min_dist
|
|
146
|
-
return vals
|
|
147
|
-
|
|
148
|
-
def max_values_float(self):
|
|
149
|
-
"""
|
|
150
|
-
The maximal values of the float variables.
|
|
151
|
-
|
|
152
|
-
Use numpy.inf for unbounded.
|
|
153
|
-
|
|
154
|
-
Returns
|
|
155
|
-
-------
|
|
156
|
-
values: numpy.ndarray
|
|
157
|
-
Maximal float values, shape: (n_vars_float,)
|
|
158
|
-
|
|
159
|
-
"""
|
|
160
|
-
vals = np.zeros(5, dtype=FC.DTYPE)
|
|
161
|
-
vals[:2] = 0.5
|
|
162
|
-
vals[2:4] = self.max_dist
|
|
163
|
-
vals[4] = 90.0
|
|
164
|
-
return vals
|
|
165
|
-
|
|
166
|
-
def apply_individual(self, vars_int, vars_float):
|
|
167
|
-
"""
|
|
168
|
-
Apply new variables to the problem.
|
|
169
|
-
|
|
170
|
-
Parameters
|
|
171
|
-
----------
|
|
172
|
-
vars_int: np.array
|
|
173
|
-
The integer variable values, shape: (n_vars_int,)
|
|
174
|
-
vars_float: np.array
|
|
175
|
-
The float variable values, shape: (n_vars_float,)
|
|
176
|
-
|
|
177
|
-
Returns
|
|
178
|
-
-------
|
|
179
|
-
problem_results: Any
|
|
180
|
-
The results of the variable application
|
|
181
|
-
to the problem
|
|
182
|
-
|
|
183
|
-
"""
|
|
184
|
-
sx, sy, dx, dy, alpha = vars_float
|
|
185
|
-
|
|
186
|
-
a = np.deg2rad(alpha)
|
|
187
|
-
nax = np.stack([np.cos(a), np.sin(a)], axis=-1)
|
|
188
|
-
nay = np.stack([-np.sin(a), np.cos(a)], axis=-1)
|
|
189
|
-
|
|
190
|
-
pts = (
|
|
191
|
-
self._pc[None, None, :]
|
|
192
|
-
+ (np.arange(self._nrow)[:, None, None] - (self._nrow - 1) / 2 + sx)
|
|
193
|
-
* dx
|
|
194
|
-
* nax[None, None, :]
|
|
195
|
-
+ (np.arange(self._nrow)[None, :, None] - (self._nrow - 1) / 2 + sy)
|
|
196
|
-
* dy
|
|
197
|
-
* nay[None, None, :]
|
|
198
|
-
)
|
|
199
|
-
pts = pts.reshape(self._nrow**2, 2)
|
|
200
|
-
|
|
201
|
-
if self.D is None:
|
|
202
|
-
valid = self.boundary.points_inside(pts)
|
|
203
|
-
else:
|
|
204
|
-
valid = self.boundary.points_inside(pts) & (
|
|
205
|
-
self.boundary.points_distance(pts) >= self.D / 2
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
nvl = np.sum(valid)
|
|
209
|
-
if nvl >= self.n_turbines:
|
|
210
|
-
return pts[valid][: self.n_turbines], np.ones(self.n_turbines, dtype=bool)
|
|
211
|
-
else:
|
|
212
|
-
qts = np.append(pts[valid], pts[~valid][: (self.n_turbines - nvl)], axis=0)
|
|
213
|
-
vld = np.zeros(self.n_turbines, dtype=bool)
|
|
214
|
-
vld[:nvl] = True
|
|
215
|
-
return qts, vld
|
|
216
|
-
|
|
217
|
-
def apply_population(self, vars_int, vars_float):
|
|
218
|
-
"""
|
|
219
|
-
Apply new variables to the problem,
|
|
220
|
-
for a whole population.
|
|
221
|
-
|
|
222
|
-
Parameters
|
|
223
|
-
----------
|
|
224
|
-
vars_int: np.array
|
|
225
|
-
The integer variable values, shape: (n_pop, n_vars_int)
|
|
226
|
-
vars_float: np.array
|
|
227
|
-
The float variable values, shape: (n_pop, n_vars_float)
|
|
228
|
-
|
|
229
|
-
Returns
|
|
230
|
-
-------
|
|
231
|
-
problem_results: Any
|
|
232
|
-
The results of the variable application
|
|
233
|
-
to the problem
|
|
234
|
-
|
|
235
|
-
"""
|
|
236
|
-
n_pop = vars_float.shape[0]
|
|
237
|
-
sx = vars_float[:, 0]
|
|
238
|
-
sy = vars_float[:, 1]
|
|
239
|
-
dx = vars_float[:, 2]
|
|
240
|
-
dy = vars_float[:, 3]
|
|
241
|
-
alpha = vars_float[:, 4]
|
|
242
|
-
|
|
243
|
-
a = np.deg2rad(alpha)
|
|
244
|
-
nax = np.stack([np.cos(a), np.sin(a)], axis=-1)
|
|
245
|
-
nay = np.stack([-np.sin(a), np.cos(a)], axis=-1)
|
|
246
|
-
|
|
247
|
-
pts = (
|
|
248
|
-
self._pc[None, None, None, :]
|
|
249
|
-
+ (
|
|
250
|
-
np.arange(self._nrow)[None, :, None, None]
|
|
251
|
-
- (self._nrow - 1) / 2
|
|
252
|
-
+ sx[:, None, None, None]
|
|
253
|
-
)
|
|
254
|
-
* dx[:, None, None, None]
|
|
255
|
-
* nax[:, None, None, :]
|
|
256
|
-
+ (
|
|
257
|
-
np.arange(self._nrow)[None, None, :, None]
|
|
258
|
-
- (self._nrow - 1) / 2
|
|
259
|
-
+ sy[:, None, None, None]
|
|
260
|
-
)
|
|
261
|
-
* dy[:, None, None, None]
|
|
262
|
-
* nay[:, None, None, :]
|
|
263
|
-
)
|
|
264
|
-
pts = pts.reshape(n_pop * self._nrow**2, 2)
|
|
265
|
-
|
|
266
|
-
if self.D is None:
|
|
267
|
-
valid = self.boundary.points_inside(pts)
|
|
268
|
-
else:
|
|
269
|
-
valid = self.boundary.points_inside(pts) & (
|
|
270
|
-
self.boundary.points_distance(pts) >= self.D / 2
|
|
271
|
-
)
|
|
272
|
-
valid = valid.reshape(n_pop, self._nrow**2)
|
|
273
|
-
pts = pts.reshape(n_pop, self._nrow**2, 2)
|
|
274
|
-
|
|
275
|
-
nvl = np.sum(valid, axis=1)
|
|
276
|
-
qts = np.zeros((n_pop, self.n_turbines, 2), dtype=FC.DTYPE)
|
|
277
|
-
vld = np.zeros((n_pop, self.n_turbines), dtype=bool)
|
|
278
|
-
for pi in range(n_pop):
|
|
279
|
-
if nvl[pi] >= self.n_turbines:
|
|
280
|
-
qts[pi] = pts[pi, valid[pi]][: self.n_turbines]
|
|
281
|
-
vld[pi] = np.ones(self.n_turbines, dtype=bool)
|
|
282
|
-
else:
|
|
283
|
-
qts[pi] = np.append(
|
|
284
|
-
pts[pi, valid[pi]],
|
|
285
|
-
pts[pi, ~valid[pi]][: (self.n_turbines - nvl[pi])],
|
|
286
|
-
axis=0,
|
|
287
|
-
)
|
|
288
|
-
vld[pi, : nvl[pi]] = True
|
|
289
|
-
|
|
290
|
-
return qts, vld
|
|
291
|
-
|
|
292
|
-
def get_fig(
|
|
293
|
-
self, xy=None, valid=None, ax=None, title=None, true_circle=True, **bargs
|
|
294
|
-
):
|
|
295
|
-
"""
|
|
296
|
-
Return plotly figure axis.
|
|
297
|
-
|
|
298
|
-
Parameters
|
|
299
|
-
----------
|
|
300
|
-
xy: numpy.ndarary, optional
|
|
301
|
-
The xy coordinate array, shape: (n_points, 2)
|
|
302
|
-
valid: numpy.ndarray, optional
|
|
303
|
-
Boolean array of validity, shape: (n_points,)
|
|
304
|
-
ax: pyplot.Axis, optional
|
|
305
|
-
The figure axis
|
|
306
|
-
title: str, optional
|
|
307
|
-
The figure title
|
|
308
|
-
true_circle: bool
|
|
309
|
-
Draw points as circles with diameter self.D
|
|
310
|
-
bars: dict, optional
|
|
311
|
-
The boundary plot arguments
|
|
312
|
-
|
|
313
|
-
Returns
|
|
314
|
-
-------
|
|
315
|
-
ax: pyplot.Axis
|
|
316
|
-
The figure axis
|
|
317
|
-
|
|
318
|
-
"""
|
|
319
|
-
if ax is None:
|
|
320
|
-
__, ax = plt.subplots()
|
|
321
|
-
|
|
322
|
-
hbargs = {"fill_mode": "inside_lightgray"}
|
|
323
|
-
hbargs.update(bargs)
|
|
324
|
-
self.boundary.add_to_figure(ax, **hbargs)
|
|
325
|
-
|
|
326
|
-
if xy is not None:
|
|
327
|
-
if valid is not None:
|
|
328
|
-
xy = xy[valid]
|
|
329
|
-
if not true_circle or self.D is None:
|
|
330
|
-
ax.scatter(xy[:, 0], xy[:, 1], color="orange")
|
|
331
|
-
else:
|
|
332
|
-
for x, y in xy:
|
|
333
|
-
ax.add_patch(
|
|
334
|
-
plt.Circle((x, y), self.D / 2, color="blue", fill=True)
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
ax.set_aspect("equal", adjustable="box")
|
|
338
|
-
ax.set_xlabel("x [m]")
|
|
339
|
-
ax.set_ylabel("y [m]")
|
|
340
|
-
|
|
341
|
-
if title is None:
|
|
342
|
-
if xy is None:
|
|
343
|
-
title = f"Optimization area"
|
|
344
|
-
else:
|
|
345
|
-
l = len(xy) if xy is not None else 0
|
|
346
|
-
dists = cdist(xy, xy)
|
|
347
|
-
np.fill_diagonal(dists, 1e20)
|
|
348
|
-
title = f"N = {l}, min_dist = {np.min(dists):.1f} m"
|
|
349
|
-
ax.set_title(title)
|
|
350
|
-
|
|
351
|
-
return ax
|