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,290 +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 GeomLayout(Problem):
|
|
10
|
-
"""
|
|
11
|
-
A layout within a boundary geometry, purely
|
|
12
|
-
defined by geometrical optimization (no wakes).
|
|
13
|
-
|
|
14
|
-
This optimization problem does not involve
|
|
15
|
-
wind farms.
|
|
16
|
-
|
|
17
|
-
Attributes
|
|
18
|
-
----------
|
|
19
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
20
|
-
The boundary geometry
|
|
21
|
-
n_turbines: int
|
|
22
|
-
The number of turbines in the layout
|
|
23
|
-
min_dist: float
|
|
24
|
-
The minimal distance between points
|
|
25
|
-
D: float
|
|
26
|
-
The diameter of circle fully within boundary
|
|
27
|
-
calc_valid: bool
|
|
28
|
-
Evaluate validity
|
|
29
|
-
|
|
30
|
-
:group: opt.problems.layout.geom_layouts
|
|
31
|
-
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
def __init__(
|
|
35
|
-
self,
|
|
36
|
-
boundary,
|
|
37
|
-
n_turbines,
|
|
38
|
-
min_dist=None,
|
|
39
|
-
D=None,
|
|
40
|
-
calc_valid=None,
|
|
41
|
-
):
|
|
42
|
-
"""
|
|
43
|
-
Constructor.
|
|
44
|
-
|
|
45
|
-
Parameters
|
|
46
|
-
----------
|
|
47
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
48
|
-
The boundary geometry
|
|
49
|
-
n_turbines: int
|
|
50
|
-
The number of turbines in the layout
|
|
51
|
-
min_dist: float, optional
|
|
52
|
-
The minimal distance between points
|
|
53
|
-
D: float, optional
|
|
54
|
-
The diameter of circle fully within boundary
|
|
55
|
-
calc_valid: bool, optional
|
|
56
|
-
Evaluate validity
|
|
57
|
-
|
|
58
|
-
"""
|
|
59
|
-
super().__init__(name="geom_reg_grids")
|
|
60
|
-
|
|
61
|
-
self.boundary = boundary
|
|
62
|
-
self.n_turbines = n_turbines
|
|
63
|
-
self.D = D
|
|
64
|
-
self.min_dist = min_dist
|
|
65
|
-
self.calc_valid = calc_valid
|
|
66
|
-
if calc_valid is None:
|
|
67
|
-
self.calc_valid = min_dist is not None or D is not None
|
|
68
|
-
|
|
69
|
-
self._X = [f"x{i}" for i in range(self.n_turbines)]
|
|
70
|
-
self._Y = [f"y{i}" for i in range(self.n_turbines)]
|
|
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
|
-
self.apply_individual(self.initial_values_int(), self.initial_values_float())
|
|
84
|
-
|
|
85
|
-
def var_names_float(self):
|
|
86
|
-
"""
|
|
87
|
-
The names of float variables.
|
|
88
|
-
|
|
89
|
-
Returns
|
|
90
|
-
-------
|
|
91
|
-
names: list of str
|
|
92
|
-
The names of the float variables
|
|
93
|
-
|
|
94
|
-
"""
|
|
95
|
-
return list(np.array([self._X, self._Y]).T.flat)
|
|
96
|
-
|
|
97
|
-
def initial_values_float(self):
|
|
98
|
-
"""
|
|
99
|
-
The initial values of the float variables.
|
|
100
|
-
|
|
101
|
-
Returns
|
|
102
|
-
-------
|
|
103
|
-
values: numpy.ndarray
|
|
104
|
-
Initial float values, shape: (n_vars_float,)
|
|
105
|
-
|
|
106
|
-
"""
|
|
107
|
-
pmin = self.boundary.p_min()
|
|
108
|
-
pmax = self.boundary.p_max()
|
|
109
|
-
pc = 0.5 * (pmin + pmax)
|
|
110
|
-
delta = 0.8 * (pmax - pmin)
|
|
111
|
-
|
|
112
|
-
vals = np.zeros((self.n_turbines, 2), dtype=FC.DTYPE)
|
|
113
|
-
vals[:] = pc[None, :] - 0.5 * delta[None, :]
|
|
114
|
-
vals[:] += (
|
|
115
|
-
np.arange(self.n_turbines)[:, None] * delta[None, :] / (self.n_turbines - 1)
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
return vals.reshape(self.n_turbines * 2)
|
|
119
|
-
|
|
120
|
-
def min_values_float(self):
|
|
121
|
-
"""
|
|
122
|
-
The minimal values of the float variables.
|
|
123
|
-
|
|
124
|
-
Use -numpy.inf for unbounded.
|
|
125
|
-
|
|
126
|
-
Returns
|
|
127
|
-
-------
|
|
128
|
-
values: numpy.ndarray
|
|
129
|
-
Minimal float values, shape: (n_vars_float,)
|
|
130
|
-
|
|
131
|
-
"""
|
|
132
|
-
vals = np.zeros((self.n_turbines, 2), dtype=FC.DTYPE)
|
|
133
|
-
vals[:] = self.boundary.p_min()[None, :]
|
|
134
|
-
return vals.reshape(self.n_turbines * 2)
|
|
135
|
-
|
|
136
|
-
def max_values_float(self):
|
|
137
|
-
"""
|
|
138
|
-
The maximal values of the float variables.
|
|
139
|
-
|
|
140
|
-
Use numpy.inf for unbounded.
|
|
141
|
-
|
|
142
|
-
Returns
|
|
143
|
-
-------
|
|
144
|
-
values: numpy.ndarray
|
|
145
|
-
Maximal float values, shape: (n_vars_float,)
|
|
146
|
-
|
|
147
|
-
"""
|
|
148
|
-
vals = np.zeros((self.n_turbines, 2), dtype=FC.DTYPE)
|
|
149
|
-
vals[:] = self.boundary.p_max()[None, :]
|
|
150
|
-
return vals.reshape(self.n_turbines * 2)
|
|
151
|
-
|
|
152
|
-
def apply_individual(self, vars_int, vars_float):
|
|
153
|
-
"""
|
|
154
|
-
Apply new variables to the problem.
|
|
155
|
-
|
|
156
|
-
Parameters
|
|
157
|
-
----------
|
|
158
|
-
vars_int: np.array
|
|
159
|
-
The integer variable values, shape: (n_vars_int,)
|
|
160
|
-
vars_float: np.array
|
|
161
|
-
The float variable values, shape: (n_vars_float,)
|
|
162
|
-
|
|
163
|
-
Returns
|
|
164
|
-
-------
|
|
165
|
-
problem_results: Any
|
|
166
|
-
The results of the variable application
|
|
167
|
-
to the problem
|
|
168
|
-
|
|
169
|
-
"""
|
|
170
|
-
xy = vars_float.reshape(self.n_turbines, 2)
|
|
171
|
-
|
|
172
|
-
valid = None
|
|
173
|
-
if self.calc_valid:
|
|
174
|
-
if self.D is None:
|
|
175
|
-
valid = self.boundary.points_inside(xy)
|
|
176
|
-
else:
|
|
177
|
-
valid = self.boundary.points_inside(xy) & (
|
|
178
|
-
self.boundary.points_distance(xy) >= self.D / 2
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
if self.min_dist is not None:
|
|
182
|
-
dists = cdist(xy, xy)
|
|
183
|
-
np.fill_diagonal(dists, 1e20)
|
|
184
|
-
dists = np.min(dists, axis=1)
|
|
185
|
-
valid[dists < self.min_dist] = False
|
|
186
|
-
|
|
187
|
-
return xy, valid
|
|
188
|
-
|
|
189
|
-
def apply_population(self, vars_int, vars_float):
|
|
190
|
-
"""
|
|
191
|
-
Apply new variables to the problem,
|
|
192
|
-
for a whole population.
|
|
193
|
-
|
|
194
|
-
Parameters
|
|
195
|
-
----------
|
|
196
|
-
vars_int: np.array
|
|
197
|
-
The integer variable values, shape: (n_pop, n_vars_int)
|
|
198
|
-
vars_float: np.array
|
|
199
|
-
The float variable values, shape: (n_pop, n_vars_float)
|
|
200
|
-
|
|
201
|
-
Returns
|
|
202
|
-
-------
|
|
203
|
-
problem_results: Any
|
|
204
|
-
The results of the variable application
|
|
205
|
-
to the problem
|
|
206
|
-
|
|
207
|
-
"""
|
|
208
|
-
n_pop = vars_float.shape[0]
|
|
209
|
-
xy = vars_float.reshape(n_pop, self.n_turbines, 2)
|
|
210
|
-
|
|
211
|
-
valid = None
|
|
212
|
-
if self.calc_valid:
|
|
213
|
-
qts = xy.reshape(n_pop * self.n_turbines, 2)
|
|
214
|
-
if self.D is None:
|
|
215
|
-
valid = self.boundary.points_inside(qts)
|
|
216
|
-
else:
|
|
217
|
-
valid = self.boundary.points_inside(qts) & (
|
|
218
|
-
self.boundary.points_distance(qts) >= self.D / 2
|
|
219
|
-
)
|
|
220
|
-
valid = valid.reshape(n_pop, self.n_turbines)
|
|
221
|
-
|
|
222
|
-
if self.min_dist is not None:
|
|
223
|
-
for pi in range(n_pop):
|
|
224
|
-
dists = cdist(xy[pi], xy[pi])
|
|
225
|
-
np.fill_diagonal(dists, 1e20)
|
|
226
|
-
dists = np.min(dists, axis=1)
|
|
227
|
-
valid[pi, dists < self.min_dist] = False
|
|
228
|
-
|
|
229
|
-
return xy, valid
|
|
230
|
-
|
|
231
|
-
def get_fig(
|
|
232
|
-
self, xy=None, valid=None, ax=None, title=None, true_circle=True, **bargs
|
|
233
|
-
):
|
|
234
|
-
"""
|
|
235
|
-
Return plotly figure axis.
|
|
236
|
-
|
|
237
|
-
Parameters
|
|
238
|
-
----------
|
|
239
|
-
xy: numpy.ndarary, optional
|
|
240
|
-
The xy coordinate array, shape: (n_points, 2)
|
|
241
|
-
valid: numpy.ndarray, optional
|
|
242
|
-
Boolean array of validity, shape: (n_points,)
|
|
243
|
-
ax: pyplot.Axis, optional
|
|
244
|
-
The figure axis
|
|
245
|
-
title: str, optional
|
|
246
|
-
The figure title
|
|
247
|
-
true_circle: bool
|
|
248
|
-
Draw points as circles with diameter self.D
|
|
249
|
-
bars: dict, optional
|
|
250
|
-
The boundary plot arguments
|
|
251
|
-
|
|
252
|
-
Returns
|
|
253
|
-
-------
|
|
254
|
-
ax: pyplot.Axis
|
|
255
|
-
The figure axis
|
|
256
|
-
|
|
257
|
-
"""
|
|
258
|
-
if ax is None:
|
|
259
|
-
__, ax = plt.subplots()
|
|
260
|
-
|
|
261
|
-
hbargs = {"fill_mode": "inside_lightgray"}
|
|
262
|
-
hbargs.update(bargs)
|
|
263
|
-
self.boundary.add_to_figure(ax, **hbargs)
|
|
264
|
-
|
|
265
|
-
if xy is not None:
|
|
266
|
-
if valid is not None:
|
|
267
|
-
xy = xy[valid]
|
|
268
|
-
if not true_circle or self.D is None:
|
|
269
|
-
ax.scatter(xy[:, 0], xy[:, 1], color="orange")
|
|
270
|
-
else:
|
|
271
|
-
for x, y in xy:
|
|
272
|
-
ax.add_patch(
|
|
273
|
-
plt.Circle((x, y), self.D / 2, color="blue", fill=True)
|
|
274
|
-
)
|
|
275
|
-
|
|
276
|
-
ax.set_aspect("equal", adjustable="box")
|
|
277
|
-
ax.set_xlabel("x [m]")
|
|
278
|
-
ax.set_ylabel("y [m]")
|
|
279
|
-
|
|
280
|
-
if title is None:
|
|
281
|
-
if xy is None:
|
|
282
|
-
title = f"Optimization area"
|
|
283
|
-
else:
|
|
284
|
-
l = len(xy) if xy is not None else 0
|
|
285
|
-
dists = cdist(xy, xy)
|
|
286
|
-
np.fill_diagonal(dists, 1e20)
|
|
287
|
-
title = f"N = {l}, min_dist = {np.min(dists):.1f} m"
|
|
288
|
-
ax.set_title(title)
|
|
289
|
-
|
|
290
|
-
return ax
|
|
@@ -1,276 +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 GeomLayoutGridded(Problem):
|
|
10
|
-
"""
|
|
11
|
-
A layout within a boundary geometry, purely
|
|
12
|
-
defined by geometrical optimization (no wakes),
|
|
13
|
-
on a fixes background point grid.
|
|
14
|
-
|
|
15
|
-
This optimization problem does not involve
|
|
16
|
-
wind farms.
|
|
17
|
-
|
|
18
|
-
Attributes
|
|
19
|
-
----------
|
|
20
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
21
|
-
The boundary geometry
|
|
22
|
-
n_turbines: int
|
|
23
|
-
The number of turbines in the layout
|
|
24
|
-
grid_spacing: float
|
|
25
|
-
The background grid spacing
|
|
26
|
-
min_dist: float
|
|
27
|
-
The minimal distance between points
|
|
28
|
-
D: float
|
|
29
|
-
The diameter of circle fully within boundary
|
|
30
|
-
|
|
31
|
-
:group: opt.problems.layout.geom_layouts
|
|
32
|
-
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
def __init__(
|
|
36
|
-
self,
|
|
37
|
-
boundary,
|
|
38
|
-
n_turbines,
|
|
39
|
-
grid_spacing,
|
|
40
|
-
min_dist=None,
|
|
41
|
-
D=None,
|
|
42
|
-
):
|
|
43
|
-
"""
|
|
44
|
-
Constructor.
|
|
45
|
-
|
|
46
|
-
Parameters
|
|
47
|
-
----------
|
|
48
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
49
|
-
The boundary geometry
|
|
50
|
-
n_turbines: int
|
|
51
|
-
The number of turbines in the layout
|
|
52
|
-
grid_spacing: float
|
|
53
|
-
The background grid spacing
|
|
54
|
-
min_dist: float, optional
|
|
55
|
-
The minimal distance between points
|
|
56
|
-
D: float, optional
|
|
57
|
-
The diameter of circle fully within boundary
|
|
58
|
-
|
|
59
|
-
"""
|
|
60
|
-
super().__init__(name="geom_reg_grids")
|
|
61
|
-
|
|
62
|
-
self.boundary = boundary
|
|
63
|
-
self.n_turbines = n_turbines
|
|
64
|
-
self.grid_spacing = grid_spacing
|
|
65
|
-
self.D = D
|
|
66
|
-
self.min_dist = min_dist
|
|
67
|
-
|
|
68
|
-
self._I = [f"i{i}" for i in range(self.n_turbines)]
|
|
69
|
-
|
|
70
|
-
def initialize(self, verbosity=1):
|
|
71
|
-
"""
|
|
72
|
-
Initialize the object.
|
|
73
|
-
|
|
74
|
-
Parameters
|
|
75
|
-
----------
|
|
76
|
-
verbosity: int
|
|
77
|
-
The verbosity level, 0 = silent
|
|
78
|
-
|
|
79
|
-
"""
|
|
80
|
-
super().initialize(verbosity)
|
|
81
|
-
|
|
82
|
-
pmin = self.boundary.p_min()
|
|
83
|
-
pmax = self.boundary.p_max() + self.grid_spacing
|
|
84
|
-
self._pts = np.stack(
|
|
85
|
-
np.meshgrid(
|
|
86
|
-
np.arange(pmin[0], pmax[0], self.grid_spacing),
|
|
87
|
-
np.arange(pmin[1], pmax[1], self.grid_spacing),
|
|
88
|
-
indexing="ij",
|
|
89
|
-
),
|
|
90
|
-
axis=-1,
|
|
91
|
-
)
|
|
92
|
-
nx, ny = self._pts.shape[:2]
|
|
93
|
-
self._pts = self._pts.reshape(nx * ny, 2)
|
|
94
|
-
|
|
95
|
-
if self.D is None:
|
|
96
|
-
valid = self.boundary.points_inside(self._pts)
|
|
97
|
-
else:
|
|
98
|
-
valid = self.boundary.points_inside(self._pts) & (
|
|
99
|
-
self.boundary.points_distance(self._pts) >= self.D / 2
|
|
100
|
-
)
|
|
101
|
-
self._pts = self._pts[valid]
|
|
102
|
-
self._N = len(self._pts)
|
|
103
|
-
|
|
104
|
-
if verbosity > 0:
|
|
105
|
-
print(f"Problem '{self.name}': n_bgd_pts = {self._N}")
|
|
106
|
-
|
|
107
|
-
if self._N < self.n_turbines:
|
|
108
|
-
raise ValueError(
|
|
109
|
-
f"Problem '{self.name}': Background grid only provides {self._N} points for {self.n_turbines} turbines"
|
|
110
|
-
)
|
|
111
|
-
|
|
112
|
-
self.apply_individual(self.initial_values_int(), self.initial_values_float())
|
|
113
|
-
|
|
114
|
-
def var_names_int(self):
|
|
115
|
-
"""
|
|
116
|
-
The names of int variables.
|
|
117
|
-
|
|
118
|
-
Returns
|
|
119
|
-
-------
|
|
120
|
-
names: list of str
|
|
121
|
-
The names of the int variables
|
|
122
|
-
|
|
123
|
-
"""
|
|
124
|
-
return self._I
|
|
125
|
-
|
|
126
|
-
def initial_values_int(self):
|
|
127
|
-
"""
|
|
128
|
-
The initial values of the int variables.
|
|
129
|
-
|
|
130
|
-
Returns
|
|
131
|
-
-------
|
|
132
|
-
values: numpy.ndarray
|
|
133
|
-
Initial int values, shape: (n_vars_int,)
|
|
134
|
-
|
|
135
|
-
"""
|
|
136
|
-
return np.arange(self.n_turbines, dtype=FC.ITYPE)
|
|
137
|
-
|
|
138
|
-
def min_values_int(self):
|
|
139
|
-
"""
|
|
140
|
-
The minimal values of the int variables.
|
|
141
|
-
|
|
142
|
-
Returns
|
|
143
|
-
-------
|
|
144
|
-
values: numpy.ndarray
|
|
145
|
-
Minimal int values, shape: (n_vars_int,)
|
|
146
|
-
|
|
147
|
-
"""
|
|
148
|
-
return np.zeros(self.n_turbines, dtype=FC.ITYPE)
|
|
149
|
-
|
|
150
|
-
def max_values_int(self):
|
|
151
|
-
"""
|
|
152
|
-
The maximal values of the int variables.
|
|
153
|
-
|
|
154
|
-
Returns
|
|
155
|
-
-------
|
|
156
|
-
values: numpy.ndarray
|
|
157
|
-
Maximal int values, shape: (n_vars_int,)
|
|
158
|
-
|
|
159
|
-
"""
|
|
160
|
-
return np.full(self.n_turbines, self._N - 1, dtype=FC.ITYPE)
|
|
161
|
-
|
|
162
|
-
def apply_individual(self, vars_int, vars_float):
|
|
163
|
-
"""
|
|
164
|
-
Apply new variables to the problem.
|
|
165
|
-
|
|
166
|
-
Parameters
|
|
167
|
-
----------
|
|
168
|
-
vars_int: np.array
|
|
169
|
-
The integer variable values, shape: (n_vars_int,)
|
|
170
|
-
vars_float: np.array
|
|
171
|
-
The float variable values, shape: (n_vars_float,)
|
|
172
|
-
|
|
173
|
-
Returns
|
|
174
|
-
-------
|
|
175
|
-
problem_results: Any
|
|
176
|
-
The results of the variable application
|
|
177
|
-
to the problem
|
|
178
|
-
|
|
179
|
-
"""
|
|
180
|
-
xy = self._pts[vars_int.astype(FC.ITYPE)]
|
|
181
|
-
__, ui = np.unique(vars_int, return_index=True)
|
|
182
|
-
valid = np.zeros(self.n_turbines, dtype=bool)
|
|
183
|
-
valid[ui] = True
|
|
184
|
-
return xy, valid
|
|
185
|
-
|
|
186
|
-
def apply_population(self, vars_int, vars_float):
|
|
187
|
-
"""
|
|
188
|
-
Apply new variables to the problem,
|
|
189
|
-
for a whole population.
|
|
190
|
-
|
|
191
|
-
Parameters
|
|
192
|
-
----------
|
|
193
|
-
vars_int: np.array
|
|
194
|
-
The integer variable values, shape: (n_pop, n_vars_int)
|
|
195
|
-
vars_float: np.array
|
|
196
|
-
The float variable values, shape: (n_pop, n_vars_float)
|
|
197
|
-
|
|
198
|
-
Returns
|
|
199
|
-
-------
|
|
200
|
-
problem_results: Any
|
|
201
|
-
The results of the variable application
|
|
202
|
-
to the problem
|
|
203
|
-
|
|
204
|
-
"""
|
|
205
|
-
n_pop = vars_int.shape[0]
|
|
206
|
-
|
|
207
|
-
vint = vars_int.reshape(n_pop * self.n_turbines).astype(FC.ITYPE)
|
|
208
|
-
xy = self._pts[vint, :].reshape(n_pop, self.n_turbines, 2)
|
|
209
|
-
|
|
210
|
-
valid = np.zeros((n_pop, self.n_turbines), dtype=bool)
|
|
211
|
-
for pi in range(n_pop):
|
|
212
|
-
__, ui = np.unique(vars_int[pi], return_index=True)
|
|
213
|
-
valid[pi, ui] = True
|
|
214
|
-
|
|
215
|
-
return xy, valid
|
|
216
|
-
|
|
217
|
-
def get_fig(
|
|
218
|
-
self, xy=None, valid=None, ax=None, title=None, true_circle=True, **bargs
|
|
219
|
-
):
|
|
220
|
-
"""
|
|
221
|
-
Return plotly figure axis.
|
|
222
|
-
|
|
223
|
-
Parameters
|
|
224
|
-
----------
|
|
225
|
-
xy: numpy.ndarary, optional
|
|
226
|
-
The xy coordinate array, shape: (n_points, 2)
|
|
227
|
-
valid: numpy.ndarray, optional
|
|
228
|
-
Boolean array of validity, shape: (n_points,)
|
|
229
|
-
ax: pyplot.Axis, optional
|
|
230
|
-
The figure axis
|
|
231
|
-
title: str, optional
|
|
232
|
-
The figure title
|
|
233
|
-
true_circle: bool
|
|
234
|
-
Draw points as circles with diameter self.D
|
|
235
|
-
bars: dict, optional
|
|
236
|
-
The boundary plot arguments
|
|
237
|
-
|
|
238
|
-
Returns
|
|
239
|
-
-------
|
|
240
|
-
ax: pyplot.Axis
|
|
241
|
-
The figure axis
|
|
242
|
-
|
|
243
|
-
"""
|
|
244
|
-
if ax is None:
|
|
245
|
-
__, ax = plt.subplots()
|
|
246
|
-
|
|
247
|
-
hbargs = {"fill_mode": "inside_lightgray"}
|
|
248
|
-
hbargs.update(bargs)
|
|
249
|
-
self.boundary.add_to_figure(ax, **hbargs)
|
|
250
|
-
|
|
251
|
-
if xy is not None:
|
|
252
|
-
if valid is not None:
|
|
253
|
-
xy = xy[valid]
|
|
254
|
-
if not true_circle or self.D is None:
|
|
255
|
-
ax.scatter(xy[:, 0], xy[:, 1], color="orange")
|
|
256
|
-
else:
|
|
257
|
-
for x, y in xy:
|
|
258
|
-
ax.add_patch(
|
|
259
|
-
plt.Circle((x, y), self.D / 2, color="blue", fill=True)
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
ax.set_aspect("equal", adjustable="box")
|
|
263
|
-
ax.set_xlabel("x [m]")
|
|
264
|
-
ax.set_ylabel("y [m]")
|
|
265
|
-
|
|
266
|
-
if title is None:
|
|
267
|
-
if xy is None:
|
|
268
|
-
title = f"Optimization area"
|
|
269
|
-
else:
|
|
270
|
-
l = len(xy) if xy is not None else 0
|
|
271
|
-
dists = cdist(xy, xy)
|
|
272
|
-
np.fill_diagonal(dists, 1e20)
|
|
273
|
-
title = f"N = {l}, min_dist = {np.min(dists):.1f} m"
|
|
274
|
-
ax.set_title(title)
|
|
275
|
-
|
|
276
|
-
return ax
|