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,482 +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 GeomRegGrids(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
|
-
min_dist: float
|
|
21
|
-
The minimal distance between points
|
|
22
|
-
n_grids: int
|
|
23
|
-
The number of grids
|
|
24
|
-
n_max: int
|
|
25
|
-
The maximal number of points
|
|
26
|
-
n_row_max: int
|
|
27
|
-
The maximal number of points in a row
|
|
28
|
-
max_dist: float
|
|
29
|
-
The maximal distance between points
|
|
30
|
-
D: float
|
|
31
|
-
The diameter of circle fully within boundary
|
|
32
|
-
|
|
33
|
-
:group: opt.problems.layout.geom_layouts
|
|
34
|
-
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
def __init__(
|
|
38
|
-
self,
|
|
39
|
-
boundary,
|
|
40
|
-
min_dist,
|
|
41
|
-
n_grids,
|
|
42
|
-
n_max=None,
|
|
43
|
-
n_row_max=None,
|
|
44
|
-
max_dist=None,
|
|
45
|
-
D=None,
|
|
46
|
-
):
|
|
47
|
-
"""
|
|
48
|
-
Constructor.
|
|
49
|
-
|
|
50
|
-
Parameters
|
|
51
|
-
----------
|
|
52
|
-
boundary: foxes.utils.geom2d.AreaGeometry
|
|
53
|
-
The boundary geometry
|
|
54
|
-
min_dist: float
|
|
55
|
-
The minimal distance between points
|
|
56
|
-
n_grids: int
|
|
57
|
-
The number of grids
|
|
58
|
-
n_max: int, optional
|
|
59
|
-
The maximal number of points
|
|
60
|
-
n_row_max: int, optional
|
|
61
|
-
The maximal number of points in a row
|
|
62
|
-
max_dist: float, optional
|
|
63
|
-
The maximal distance between points
|
|
64
|
-
D: float, optional
|
|
65
|
-
The diameter of circle fully within boundary
|
|
66
|
-
|
|
67
|
-
"""
|
|
68
|
-
super().__init__(name="geom_reg_grids")
|
|
69
|
-
|
|
70
|
-
self.boundary = boundary
|
|
71
|
-
self.n_grids = n_grids
|
|
72
|
-
self.n_max = n_max
|
|
73
|
-
self.n_row_max = n_row_max
|
|
74
|
-
self.min_dist = float(min_dist)
|
|
75
|
-
self.max_dist = float(max_dist) if max_dist is not None else max_dist
|
|
76
|
-
self.D = D
|
|
77
|
-
|
|
78
|
-
self._NX = [f"nx{i}" for i in range(self.n_grids)]
|
|
79
|
-
self._NY = [f"ny{i}" for i in range(self.n_grids)]
|
|
80
|
-
self._OX = [f"ox{i}" for i in range(self.n_grids)]
|
|
81
|
-
self._OY = [f"oy{i}" for i in range(self.n_grids)]
|
|
82
|
-
self._DX = [f"dx{i}" for i in range(self.n_grids)]
|
|
83
|
-
self._DY = [f"dy{i}" for i in range(self.n_grids)]
|
|
84
|
-
self._ALPHA = [f"alpha{i}" for i in range(self.n_grids)]
|
|
85
|
-
|
|
86
|
-
def initialize(self, verbosity=1):
|
|
87
|
-
"""
|
|
88
|
-
Initialize the object.
|
|
89
|
-
|
|
90
|
-
Parameters
|
|
91
|
-
----------
|
|
92
|
-
verbosity: int
|
|
93
|
-
The verbosity level, 0 = silent
|
|
94
|
-
|
|
95
|
-
"""
|
|
96
|
-
super().initialize(verbosity)
|
|
97
|
-
|
|
98
|
-
pmin = self.boundary.p_min()
|
|
99
|
-
pmax = self.boundary.p_max()
|
|
100
|
-
self._span = pmax - pmin
|
|
101
|
-
self._diag = np.linalg.norm(self._span)
|
|
102
|
-
self.max_dist = self._diag if self.max_dist is None else self.max_dist
|
|
103
|
-
self._nrow = self.n_row_max
|
|
104
|
-
if self.n_row_max is None:
|
|
105
|
-
if self.n_max is None:
|
|
106
|
-
self._nrow = int(self._diag / self.min_dist)
|
|
107
|
-
if self._nrow * self.min_dist < self._diag:
|
|
108
|
-
self._nrow += 1
|
|
109
|
-
self._nrow += 1
|
|
110
|
-
else:
|
|
111
|
-
self._nrow = self.n_max
|
|
112
|
-
if self.n_max is None:
|
|
113
|
-
self.n_max = self.n_grids * self._nrow**2
|
|
114
|
-
elif self.n_max <= self._nrow:
|
|
115
|
-
self._nrow = self.n_max
|
|
116
|
-
self._pmin = pmin - self._diag - self.min_dist
|
|
117
|
-
self._pmax = pmax + self.min_dist
|
|
118
|
-
|
|
119
|
-
if verbosity > 0:
|
|
120
|
-
print(f"Grid data:")
|
|
121
|
-
print(f" pmin = {self._pmin}")
|
|
122
|
-
print(f" pmax = {self._pmax}")
|
|
123
|
-
print(f" min dist = {self.min_dist}")
|
|
124
|
-
print(f" max dist = {self.max_dist}")
|
|
125
|
-
print(f" n row max = {self._nrow}")
|
|
126
|
-
print(f" n max = {self.n_max}")
|
|
127
|
-
print(f" n grids = {self.n_grids}")
|
|
128
|
-
|
|
129
|
-
self.apply_individual(self.initial_values_int(), self.initial_values_float())
|
|
130
|
-
|
|
131
|
-
def var_names_int(self):
|
|
132
|
-
"""
|
|
133
|
-
The names of int variables.
|
|
134
|
-
|
|
135
|
-
Returns
|
|
136
|
-
-------
|
|
137
|
-
names: list of str
|
|
138
|
-
The names of the int variables
|
|
139
|
-
|
|
140
|
-
"""
|
|
141
|
-
return list(np.array([self._NX, self._NY]).T.flat)
|
|
142
|
-
|
|
143
|
-
def initial_values_int(self):
|
|
144
|
-
"""
|
|
145
|
-
The initial values of the int variables.
|
|
146
|
-
|
|
147
|
-
Returns
|
|
148
|
-
-------
|
|
149
|
-
values: numpy.ndarray
|
|
150
|
-
Initial int values, shape: (n_vars_int,)
|
|
151
|
-
|
|
152
|
-
"""
|
|
153
|
-
return np.full(self.n_grids * 2, 2, dtype=FC.ITYPE)
|
|
154
|
-
|
|
155
|
-
def min_values_int(self):
|
|
156
|
-
"""
|
|
157
|
-
The minimal values of the integer variables.
|
|
158
|
-
|
|
159
|
-
Use -self.INT_INF for unbounded.
|
|
160
|
-
|
|
161
|
-
Returns
|
|
162
|
-
-------
|
|
163
|
-
values: numpy.ndarray
|
|
164
|
-
Minimal int values, shape: (n_vars_int,)
|
|
165
|
-
|
|
166
|
-
"""
|
|
167
|
-
return np.ones(self.n_grids * 2, dtype=FC.ITYPE)
|
|
168
|
-
|
|
169
|
-
def max_values_int(self):
|
|
170
|
-
"""
|
|
171
|
-
The maximal values of the integer variables.
|
|
172
|
-
|
|
173
|
-
Use self.INT_INF for unbounded.
|
|
174
|
-
|
|
175
|
-
Returns
|
|
176
|
-
-------
|
|
177
|
-
values: numpy.ndarray
|
|
178
|
-
Maximal int values, shape: (n_vars_int,)
|
|
179
|
-
|
|
180
|
-
"""
|
|
181
|
-
return np.full(self.n_grids * 2, self._nrow, dtype=FC.ITYPE)
|
|
182
|
-
|
|
183
|
-
def var_names_float(self):
|
|
184
|
-
"""
|
|
185
|
-
The names of float variables.
|
|
186
|
-
|
|
187
|
-
Returns
|
|
188
|
-
-------
|
|
189
|
-
names: list of str
|
|
190
|
-
The names of the float variables
|
|
191
|
-
|
|
192
|
-
"""
|
|
193
|
-
return list(
|
|
194
|
-
np.array([self._OX, self._OY, self._DX, self._DY, self._ALPHA]).T.flat
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
def initial_values_float(self):
|
|
198
|
-
"""
|
|
199
|
-
The initial values of the float variables.
|
|
200
|
-
|
|
201
|
-
Returns
|
|
202
|
-
-------
|
|
203
|
-
values: numpy.ndarray
|
|
204
|
-
Initial float values, shape: (n_vars_float,)
|
|
205
|
-
|
|
206
|
-
"""
|
|
207
|
-
n = 5
|
|
208
|
-
vals = np.zeros((self.n_grids, n), dtype=FC.DTYPE)
|
|
209
|
-
vals[:, :2] = self._pmin + self._diag + self.min_dist + self._span / 2
|
|
210
|
-
vals[:, 2:4] = 2 * self.min_dist
|
|
211
|
-
vals[:, 5:] = 0
|
|
212
|
-
return vals.reshape(self.n_grids * n)
|
|
213
|
-
|
|
214
|
-
def min_values_float(self):
|
|
215
|
-
"""
|
|
216
|
-
The minimal values of the float variables.
|
|
217
|
-
|
|
218
|
-
Use -numpy.inf for unbounded.
|
|
219
|
-
|
|
220
|
-
Returns
|
|
221
|
-
-------
|
|
222
|
-
values: numpy.ndarray
|
|
223
|
-
Minimal float values, shape: (n_vars_float,)
|
|
224
|
-
|
|
225
|
-
"""
|
|
226
|
-
n = 5
|
|
227
|
-
vals = np.zeros((self.n_grids, n), dtype=FC.DTYPE)
|
|
228
|
-
vals[:, :2] = self._pmin
|
|
229
|
-
vals[:, 2:4] = self.min_dist
|
|
230
|
-
vals[:, 5:] = -self._diag / 3
|
|
231
|
-
return vals.reshape(self.n_grids * n)
|
|
232
|
-
|
|
233
|
-
def max_values_float(self):
|
|
234
|
-
"""
|
|
235
|
-
The maximal values of the float variables.
|
|
236
|
-
|
|
237
|
-
Use numpy.inf for unbounded.
|
|
238
|
-
|
|
239
|
-
Returns
|
|
240
|
-
-------
|
|
241
|
-
values: numpy.ndarray
|
|
242
|
-
Maximal float values, shape: (n_vars_float,)
|
|
243
|
-
|
|
244
|
-
"""
|
|
245
|
-
n = 5
|
|
246
|
-
vals = np.zeros((self.n_grids, n), dtype=FC.DTYPE)
|
|
247
|
-
vals[:, :2] = self._pmax
|
|
248
|
-
vals[:, 2:4] = self.max_dist
|
|
249
|
-
vals[:, 4] = 90.0
|
|
250
|
-
vals[:, 5:] = self._diag / 3
|
|
251
|
-
return vals.reshape(self.n_grids * n)
|
|
252
|
-
|
|
253
|
-
def apply_individual(self, vars_int, vars_float):
|
|
254
|
-
"""
|
|
255
|
-
Apply new variables to the problem.
|
|
256
|
-
|
|
257
|
-
Parameters
|
|
258
|
-
----------
|
|
259
|
-
vars_int: np.array
|
|
260
|
-
The integer variable values, shape: (n_vars_int,)
|
|
261
|
-
vars_float: np.array
|
|
262
|
-
The float variable values, shape: (n_vars_float,)
|
|
263
|
-
|
|
264
|
-
Returns
|
|
265
|
-
-------
|
|
266
|
-
problem_results: Any
|
|
267
|
-
The results of the variable application
|
|
268
|
-
to the problem
|
|
269
|
-
|
|
270
|
-
"""
|
|
271
|
-
vint = vars_int.reshape(self.n_grids, 2)
|
|
272
|
-
vflt = vars_float.reshape(self.n_grids, 5)
|
|
273
|
-
nx = vint[:, 0]
|
|
274
|
-
ny = vint[:, 1]
|
|
275
|
-
ox = vflt[:, 0]
|
|
276
|
-
oy = vflt[:, 1]
|
|
277
|
-
dx = vflt[:, 2]
|
|
278
|
-
dy = vflt[:, 3]
|
|
279
|
-
a = np.deg2rad(vflt[:, 4])
|
|
280
|
-
s = vflt[:, 5:]
|
|
281
|
-
n_points = self.n_max
|
|
282
|
-
|
|
283
|
-
nax = np.stack([np.cos(a), np.sin(a), np.zeros_like(a)], axis=-1)
|
|
284
|
-
naz = np.zeros_like(nax)
|
|
285
|
-
naz[:, 2] = 1
|
|
286
|
-
nay = np.cross(naz, nax)
|
|
287
|
-
|
|
288
|
-
valid = np.zeros(n_points, dtype=bool)
|
|
289
|
-
pts = np.full((n_points, 2), np.nan, dtype=FC.DTYPE)
|
|
290
|
-
n0 = 0
|
|
291
|
-
for gi in range(self.n_grids):
|
|
292
|
-
n = nx[gi] * ny[gi]
|
|
293
|
-
n1 = n0 + n
|
|
294
|
-
|
|
295
|
-
if n1 <= n_points:
|
|
296
|
-
qts = pts[n0:n1].reshape(nx[gi], ny[gi], 2)
|
|
297
|
-
else:
|
|
298
|
-
qts = np.zeros((nx[gi], ny[gi], 2), dtype=FC.DTYPE)
|
|
299
|
-
|
|
300
|
-
qts[:, :, 0] = ox[gi]
|
|
301
|
-
qts[:, :, 1] = oy[gi]
|
|
302
|
-
qts[:] += (
|
|
303
|
-
np.arange(nx[gi])[:, None, None] * dx[gi] * nax[gi, None, None, :2]
|
|
304
|
-
)
|
|
305
|
-
qts[:] += (
|
|
306
|
-
np.arange(ny[gi])[None, :, None] * dy[gi] * nay[gi, None, None, :2]
|
|
307
|
-
)
|
|
308
|
-
qts = qts.reshape(n, 2)
|
|
309
|
-
|
|
310
|
-
if n1 > n_points:
|
|
311
|
-
n1 = n_points
|
|
312
|
-
qts = qts[: (n1 - n0)]
|
|
313
|
-
pts[n0:] = qts
|
|
314
|
-
|
|
315
|
-
# set out of boundary points invalid:
|
|
316
|
-
if self.D is None:
|
|
317
|
-
valid[n0:n1] = self.boundary.points_inside(qts)
|
|
318
|
-
else:
|
|
319
|
-
valid[n0:n1] = self.boundary.points_inside(qts) & (
|
|
320
|
-
self.boundary.points_distance(qts) >= self.D / 2
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
# set points invalid which are too close to other grids:
|
|
324
|
-
if n0 > 0:
|
|
325
|
-
dists = cdist(qts, pts[:n0])
|
|
326
|
-
valid[n0:n1][np.any(dists < self.min_dist, axis=1)] = False
|
|
327
|
-
|
|
328
|
-
n0 = n1
|
|
329
|
-
if n0 >= n_points:
|
|
330
|
-
break
|
|
331
|
-
|
|
332
|
-
return pts, valid
|
|
333
|
-
|
|
334
|
-
def apply_population(self, vars_int, vars_float):
|
|
335
|
-
"""
|
|
336
|
-
Apply new variables to the problem,
|
|
337
|
-
for a whole population.
|
|
338
|
-
|
|
339
|
-
Parameters
|
|
340
|
-
----------
|
|
341
|
-
vars_int: np.array
|
|
342
|
-
The integer variable values, shape: (n_pop, n_vars_int)
|
|
343
|
-
vars_float: np.array
|
|
344
|
-
The float variable values, shape: (n_pop, n_vars_float)
|
|
345
|
-
|
|
346
|
-
Returns
|
|
347
|
-
-------
|
|
348
|
-
problem_results: Any
|
|
349
|
-
The results of the variable application
|
|
350
|
-
to the problem
|
|
351
|
-
|
|
352
|
-
"""
|
|
353
|
-
n_pop = vars_int.shape[0]
|
|
354
|
-
vint = vars_int.reshape(n_pop, self.n_grids, 2)
|
|
355
|
-
vflt = vars_float.reshape(n_pop, self.n_grids, 5)
|
|
356
|
-
nx = vint[:, :, 0]
|
|
357
|
-
ny = vint[:, :, 1]
|
|
358
|
-
ox = vflt[:, :, 0]
|
|
359
|
-
oy = vflt[:, :, 1]
|
|
360
|
-
dx = vflt[:, :, 2]
|
|
361
|
-
dy = vflt[:, :, 3]
|
|
362
|
-
a = np.deg2rad(vflt[:, :, 4])
|
|
363
|
-
s = vflt[:, :, 5:]
|
|
364
|
-
n_points = self.n_max
|
|
365
|
-
|
|
366
|
-
nax = np.stack([np.cos(a), np.sin(a), np.zeros_like(a)], axis=-1)
|
|
367
|
-
naz = np.zeros_like(nax)
|
|
368
|
-
naz[:, :, 2] = 1
|
|
369
|
-
nay = np.cross(naz, nax)
|
|
370
|
-
|
|
371
|
-
valid = np.zeros((n_pop, n_points), dtype=bool)
|
|
372
|
-
pts = np.full((n_pop, n_points, 2), np.nan, dtype=FC.DTYPE)
|
|
373
|
-
for pi in range(n_pop):
|
|
374
|
-
n0 = 0
|
|
375
|
-
for gi in range(self.n_grids):
|
|
376
|
-
n = nx[pi, gi] * ny[pi, gi]
|
|
377
|
-
n1 = n0 + n
|
|
378
|
-
|
|
379
|
-
if n1 <= n_points:
|
|
380
|
-
qts = pts[pi, n0:n1].reshape(nx[pi, gi], ny[pi, gi], 2)
|
|
381
|
-
else:
|
|
382
|
-
qts = np.zeros((nx[pi, gi], ny[pi, gi], 2), dtype=FC.DTYPE)
|
|
383
|
-
|
|
384
|
-
qts[:, :, 0] = ox[pi, gi]
|
|
385
|
-
qts[:, :, 1] = oy[pi, gi]
|
|
386
|
-
qts[:] += (
|
|
387
|
-
np.arange(nx[pi, gi])[:, None, None]
|
|
388
|
-
* dx[pi, gi]
|
|
389
|
-
* nax[pi, gi, None, None, :2]
|
|
390
|
-
)
|
|
391
|
-
qts[:] += (
|
|
392
|
-
np.arange(ny[pi, gi])[None, :, None]
|
|
393
|
-
* dy[pi, gi]
|
|
394
|
-
* nay[pi, gi, None, None, :2]
|
|
395
|
-
)
|
|
396
|
-
qts = qts.reshape(n, 2)
|
|
397
|
-
|
|
398
|
-
if n1 > n_points:
|
|
399
|
-
n1 = n_points
|
|
400
|
-
qts = qts[: (n1 - n0)]
|
|
401
|
-
pts[pi, n0:] = qts
|
|
402
|
-
|
|
403
|
-
# set out of boundary points invalid:
|
|
404
|
-
if self.D is None:
|
|
405
|
-
valid[pi, n0:n1] = self.boundary.points_inside(qts)
|
|
406
|
-
else:
|
|
407
|
-
valid[pi, n0:n1] = self.boundary.points_inside(qts) & (
|
|
408
|
-
self.boundary.points_distance(qts) >= self.D / 2
|
|
409
|
-
)
|
|
410
|
-
|
|
411
|
-
# set points invalid which are too close to other grids:
|
|
412
|
-
if n0 > 0:
|
|
413
|
-
dists = cdist(qts, pts[pi, :n0])
|
|
414
|
-
valid[pi, n0:n1][np.any(dists < self.min_dist, axis=1)] = False
|
|
415
|
-
|
|
416
|
-
n0 = n1
|
|
417
|
-
|
|
418
|
-
if n0 >= n_points:
|
|
419
|
-
break
|
|
420
|
-
|
|
421
|
-
return pts, valid
|
|
422
|
-
|
|
423
|
-
def get_fig(
|
|
424
|
-
self, xy=None, valid=None, ax=None, title=None, true_circle=True, **bargs
|
|
425
|
-
):
|
|
426
|
-
"""
|
|
427
|
-
Return plotly figure axis.
|
|
428
|
-
|
|
429
|
-
Parameters
|
|
430
|
-
----------
|
|
431
|
-
xy: numpy.ndarary, optional
|
|
432
|
-
The xy coordinate array, shape: (n_points, 2)
|
|
433
|
-
valid: numpy.ndarray, optional
|
|
434
|
-
Boolean array of validity, shape: (n_points,)
|
|
435
|
-
ax: pyplot.Axis, optional
|
|
436
|
-
The figure axis
|
|
437
|
-
title: str, optional
|
|
438
|
-
The figure title
|
|
439
|
-
true_circle: bool
|
|
440
|
-
Draw points as circles with diameter self.D
|
|
441
|
-
bars: dict, optional
|
|
442
|
-
The boundary plot arguments
|
|
443
|
-
|
|
444
|
-
Returns
|
|
445
|
-
-------
|
|
446
|
-
ax: pyplot.Axis
|
|
447
|
-
The figure axis
|
|
448
|
-
|
|
449
|
-
"""
|
|
450
|
-
if ax is None:
|
|
451
|
-
__, ax = plt.subplots()
|
|
452
|
-
|
|
453
|
-
hbargs = {"fill_mode": "inside_lightgray"}
|
|
454
|
-
hbargs.update(bargs)
|
|
455
|
-
self.boundary.add_to_figure(ax, **hbargs)
|
|
456
|
-
|
|
457
|
-
if xy is not None:
|
|
458
|
-
if valid is not None:
|
|
459
|
-
xy = xy[valid]
|
|
460
|
-
if not true_circle or self.D is None:
|
|
461
|
-
ax.scatter(xy[:, 0], xy[:, 1], color="orange")
|
|
462
|
-
else:
|
|
463
|
-
for x, y in xy:
|
|
464
|
-
ax.add_patch(
|
|
465
|
-
plt.Circle((x, y), self.D / 2, color="blue", fill=True)
|
|
466
|
-
)
|
|
467
|
-
|
|
468
|
-
ax.set_aspect("equal", adjustable="box")
|
|
469
|
-
ax.set_xlabel("x [m]")
|
|
470
|
-
ax.set_ylabel("y [m]")
|
|
471
|
-
|
|
472
|
-
if title is None:
|
|
473
|
-
if xy is None:
|
|
474
|
-
title = f"Optimization area"
|
|
475
|
-
else:
|
|
476
|
-
l = len(xy) if xy is not None else 0
|
|
477
|
-
dists = cdist(xy, xy)
|
|
478
|
-
np.fill_diagonal(dists, 1e20)
|
|
479
|
-
title = f"N = {l}, min_dist = {np.min(dists):.1f} m"
|
|
480
|
-
ax.set_title(title)
|
|
481
|
-
|
|
482
|
-
return ax
|