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.

Files changed (33) hide show
  1. foxes/VERSION +1 -1
  2. {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/METADATA +20 -116
  3. {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/RECORD +7 -33
  4. foxes/opt/__init__.py +0 -9
  5. foxes/opt/constraints/__init__.py +0 -6
  6. foxes/opt/constraints/area_geometry.py +0 -214
  7. foxes/opt/constraints/min_dist.py +0 -239
  8. foxes/opt/core/__init__.py +0 -9
  9. foxes/opt/core/farm_constraint.py +0 -96
  10. foxes/opt/core/farm_objective.py +0 -97
  11. foxes/opt/core/farm_opt_problem.py +0 -346
  12. foxes/opt/core/farm_vars_problem.py +0 -219
  13. foxes/opt/core/pop_states.py +0 -206
  14. foxes/opt/objectives/__init__.py +0 -6
  15. foxes/opt/objectives/farm_vars.py +0 -323
  16. foxes/opt/objectives/max_n_turbines.py +0 -142
  17. foxes/opt/problems/__init__.py +0 -7
  18. foxes/opt/problems/layout/__init__.py +0 -9
  19. foxes/opt/problems/layout/farm_layout.py +0 -137
  20. foxes/opt/problems/layout/geom_layouts/__init__.py +0 -10
  21. foxes/opt/problems/layout/geom_layouts/constraints.py +0 -802
  22. foxes/opt/problems/layout/geom_layouts/geom_layout.py +0 -290
  23. foxes/opt/problems/layout/geom_layouts/geom_layout_gridded.py +0 -276
  24. foxes/opt/problems/layout/geom_layouts/geom_reggrid.py +0 -351
  25. foxes/opt/problems/layout/geom_layouts/geom_reggrids.py +0 -482
  26. foxes/opt/problems/layout/geom_layouts/objectives.py +0 -666
  27. foxes/opt/problems/layout/reggrids_layout.py +0 -417
  28. foxes/opt/problems/layout/regular_layout.py +0 -350
  29. foxes/opt/problems/opt_farm_vars.py +0 -586
  30. {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/LICENSE +0 -0
  31. {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/WHEEL +0 -0
  32. {foxes-0.7.4.25.dist-info → foxes-0.8.1.dist-info}/top_level.txt +0 -0
  33. {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