Commit 38d6ffab authored by mmpe's avatar mmpe

Added a n_random parameter to smart_start to allow multiple different...

Added a n_random parameter to smart_start to allow multiple different undeterministic (suboptimal) solutions
parent 8ee21f2b
Pipeline #16767 passed with stages
in 3 minutes and 32 seconds
......@@ -485,7 +485,7 @@ class TopFarmProblem(Problem):
def turbine_positions(self):
return np.array([self[k] for k in [topfarm.x_key, topfarm.y_key]]).T
def smart_start(self, XX, YY, ZZ, radius=None):
def smart_start(self, XX, YY, ZZ, radius=None, n_random=0, plot=False):
if len(XX.shape) == 1:
XX, YY = np.meshgrid(XX, YY)
assert XX.shape == YY.shape
......@@ -509,7 +509,7 @@ class TopFarmProblem(Problem):
X, Y = X[mask], Y[mask]
if not ZZ_is_func:
Z = Z[mask]
x, y = smart_start(X, Y, Z, self.n_wt, min_spacing, radius)
x, y = smart_start(X, Y, Z, self.n_wt, min_spacing, radius, n_random, plot)
self.update_state({topfarm.x_key: x, topfarm.y_key: y})
return x, y
......
......@@ -15,20 +15,23 @@ from py_wake.site._site import UniformSite
import pytest
def tests_smart_start():
xs_ref = [1.6, 14.1, 1.6, 7.9, 14.1, 7.9, 19.9, 19.9, 7.8,
5.8, 14.2, 5.8, 1.5, 16.2, 16.2, 1.6, 3.7, 14.1, 7.9, 3.7]
ys_ref = [1.6, 1.6, 7.9, 1.6, 7.9, 7.9, 1.6, 7.9, 5.8, 7.8, 5.8, 1.5, 5.8, 7.8, 1.5, 3.7, 1.6, 3.7, 3.7, 7.9]
def egg_tray_map():
x = np.arange(0, 20, 0.1)
y = np.arange(0, 10, 0.1)
YY, XX = np.meshgrid(y, x)
val = np.sin(XX) + np.sin(YY)
return XX, YY, val
def tests_smart_start():
xs_ref = [1.6, 14.1, 1.6, 7.9, 14.1, 7.9, 19.9, 19.9, 7.8, 5.8, 14.2,
5.8, 1.5, 16.2, 16.2, 1.6, 3.7, 14.1, 7.9, 3.7]
ys_ref = [1.6, 1.6, 7.9, 1.6, 7.9, 7.9, 1.6, 7.9, 5.8, 7.8, 5.8, 1.5, 5.8, 7.8, 1.5, 3.7, 1.6, 3.7, 3.7, 7.9]
N_WT = 20
min_space = 2.1
np.random.seed(0)
XX, YY, val = egg_tray_map()
xs, ys = smart_start(XX, YY, val, N_WT, min_space)
npt.assert_array_almost_equal([xs, ys], [xs_ref, ys_ref])
if 0:
import matplotlib.pyplot as plt
......@@ -42,29 +45,44 @@ def tests_smart_start():
plt.axis('equal')
plt.show()
npt.assert_array_almost_equal([xs, ys], [xs_ref, ys_ref])
def tests_smart_start_no_feasible():
x = np.arange(0, 20, 0.1)
y = np.arange(0, 10, 0.1)
YY, XX = np.meshgrid(y, x)
val = np.sin(XX) + np.sin(YY)
N_WT = 20
min_space = 5.1
def tests_smart_start_random():
xs_ref = [14.3, 1.4, 1.5, 7.7, 13.9, 19.9, 7.9, 19.4, 8.2, 9.8, 3.5, 1.7,
16.1, 7.4, 3.6, 12.1, 10.0, 19.9, 5.7, 14.1]
ys_ref = [1.6, 1.6, 8.0, 1.5, 7.9, 7.8, 8.1, 1.3, 5.9, 1.6, 1.9, 5.9, 7.8, 3.6, 8.2, 1.9, 7.6, 3.5, 7.6, 3.7]
xs, ys = smart_start(XX, YY, val, N_WT, min_space)
N_WT = 20
min_space = 2.1
np.random.seed(0)
XX, YY, val = egg_tray_map()
np.random.seed(0)
xs, ys = smart_start(XX, YY, val, N_WT, min_space, n_random=100)
if 0:
import matplotlib.pyplot as plt
plt.contourf(XX, YY, val, 100)
plt.plot(XX, YY, ',k')
for i in range(N_WT):
circle = plt.Circle((xs[i], ys[i]), min_space / 2, color='b', fill=False)
plt.gcf().gca().add_artist(circle)
plt.plot(xs[i], ys[i], 'rx')
print(np.round(xs, 1).tolist())
print(np.round(ys, 1).tolist())
plt.axis('equal')
plt.show()
print(xs)
assert np.isnan(xs).sum() == 12
npt.assert_array_almost_equal([xs, ys], [xs_ref, ys_ref])
def tests_smart_start_no_feasible():
XX, YY, val = egg_tray_map()
N_WT = 20
min_space = 5.1
with pytest.raises(Exception, match="No feasible positions for wt 8"):
xs, ys = smart_start(XX, YY, val, N_WT, min_space)
@pytest.mark.parametrize('seed,radius,resolution,tol', [(1, 500, 10, 5),
......@@ -94,7 +112,7 @@ def test_smart_start_aep_map(seed, radius, resolution, tol):
y = np.arange(-radius, radius, resolution)
XX, YY = np.meshgrid(x, y)
tf.smart_start(XX, YY, aep_comp.get_aep4smart_start(wd=wd_lst, ws=ws_lst), radius=40)
tf.smart_start(XX, YY, aep_comp.get_aep4smart_start(wd=wd_lst, ws=ws_lst), radius=40, plot=0)
tf.evaluate()
if 0:
......
import numpy as np
import matplotlib.pyplot as plt
from numpy import newaxis as na
def smart_start(XX, YY, ZZ, N_WT, min_space, radius=None):
def smart_start(XX, YY, ZZ, N_WT, min_space, radius=None, n_random=0, plot=False):
"""Selects the a number of gridpoints (N_WT) in the grid defined by x and y,
where ZZ has the maximum value, while chosen points spacing (min_space)
is respected.
......@@ -19,6 +21,8 @@ def smart_start(XX, YY, ZZ, N_WT, min_space, radius=None):
number of wind turbines
min_space: float
minimum space between turbines
n_random : integer
select by random one of the <n_random> best points
Returns
-------
......@@ -34,46 +38,56 @@ def smart_start(XX, YY, ZZ, N_WT, min_space, radius=None):
arr = np.array([XX.flatten(), YY.flatten()])
else:
arr = np.array([XX.flatten(), YY.flatten(), ZZ.flatten()])
# set radius to None(faster) if if grid resolution > radius
if radius is not None and (np.diff(np.sort(np.unique(arr[0]))).min() > radius and
(np.diff(np.sort(np.unique(arr[1]))).min() > radius)):
radius = None
xs, ys = [], []
for _ in range(N_WT):
try:
if ZZ_is_func:
z = ZZ(arr[0], arr[1], xs, ys)
ind = np.where(z == z.max())[0]
if radius is None or len(ind) == len(z):
max_ind = ind[np.random.randint(len(ind))]
else:
x, y = arr
z_rotor = np.array([np.mean(z[(x[i] - x)**2 + (y[i] - y)**2 < radius**2]) for i in ind])
ind = ind[np.where(z_rotor == z_rotor.max())[0]]
max_ind = ind[np.random.randint(len(ind))]
else:
z = arr[2]
ind = np.where(z == z.max())[0]
max_ind = ind[np.random.randint(len(ind))]
x0 = arr[0][max_ind]
y0 = arr[1][max_ind]
xs.append(x0)
ys.append(y0)
index = np.where((arr[0] - x0)**2 + (arr[1] - y0)**2 >= min_space**2)[0]
arr = arr[:, index]
import os
except ValueError:
xs.append(np.nan)
ys.append(np.nan)
print('Could not respect the spacing constraint')
for i in range(N_WT):
if arr.shape[1] == 0:
raise Exception('No feasible positions for wt %d' % i)
if ZZ_is_func:
z = ZZ(arr[0], arr[1], xs, ys)
else:
z = arr[2]
if radius is not None:
# average over the rotor area, i.e. all points within one radius from the point
x, y = arr
z = np.array([np.mean(z[ind]) for ind in np.hypot((x - x[:, na]), (y - y[:, na])) < radius])
if n_random <= 1:
# pick one of the optimal points
next_ind = np.random.choice(np.where(z == z.max())[0])
else:
# pick one of the <n_random> best points
next_ind = np.random.choice(np.argsort(z)[-(n_random):])
x0 = arr[0][next_ind]
y0 = arr[1][next_ind]
xs.append(x0)
ys.append(y0)
if plot:
plt.figure()
c = plt.scatter(arr[0], arr[1], c=z)
plt.colorbar(c)
plt.plot(xs, ys, '2k', ms=10)
plt.plot(xs[-1], ys[-1], '2r', ms=10)
plt.axis('equal')
plt.show()
# Remove all point within min_space from the newly added wt
index = np.where((arr[0] - x0)**2 + (arr[1] - y0)**2 >= min_space**2)[0]
arr = arr[:, index]
return xs, ys
def main():
if __name__ == '__main__':
import matplotlib.pyplot as plt
N_WT = 30
min_space = 2.1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment