From 2e0413e963bf8e2e34d1820223750001bb0a43bf Mon Sep 17 00:00:00 2001
From: mikf <mikf@dtu.dk>
Date: Tue, 26 Jun 2018 10:16:42 +0200
Subject: [PATCH] renamed recording to utils new random initial positions
 feature that respects the boundaries and tries to respect the min spacing

---
 topfarm/_topfarm.py                           |   2 +-
 .../spacing_component.py                      |  14 +-
 topfarm/recording.py                          |  39 -----
 topfarm/utils.py                              | 139 ++++++++++++++++++
 4 files changed, 147 insertions(+), 47 deletions(-)
 delete mode 100644 topfarm/recording.py
 create mode 100644 topfarm/utils.py

diff --git a/topfarm/_topfarm.py b/topfarm/_topfarm.py
index 1344dc02..c210f2fb 100644
--- a/topfarm/_topfarm.py
+++ b/topfarm/_topfarm.py
@@ -10,7 +10,7 @@ from topfarm.constraint_components.boundary_component import BoundaryComp,\
     PolygonBoundaryComp
 from topfarm.constraint_components.spacing_component import SpacingComp
 from topfarm.plotting import PlotComp
-from topfarm.recording import pos_from_case, latest_id
+from topfarm.utils import pos_from_case, latest_id
 
 
 class TopFarm(object):
diff --git a/topfarm/constraint_components/spacing_component.py b/topfarm/constraint_components/spacing_component.py
index 318948d9..ec97351d 100644
--- a/topfarm/constraint_components/spacing_component.py
+++ b/topfarm/constraint_components/spacing_component.py
@@ -60,7 +60,7 @@ class SpacingComp(ExplicitComponent):
         nTurbines = self.nTurbines
 
         # initialize gradient calculation array
-        dS = np.zeros((int((nTurbines - 1.) * nTurbines / 2.), 2 * nTurbines))
+#        dS = np.zeros((int((nTurbines - 1.) * nTurbines / 2.), 2 * nTurbines))
         dSdx = np.zeros((int((nTurbines - 1.) * nTurbines / 2.),  nTurbines)) #col: dx_1-dx_n, row: d12, d13,..,d1n, d23..d2n,..
         dSdy = np.zeros((int((nTurbines - 1.) * nTurbines / 2.),  nTurbines))
 
@@ -71,20 +71,20 @@ class SpacingComp(ExplicitComponent):
         for i in range(0, nTurbines):
             for j in range(i + 1, nTurbines):
                 # separation wrt Xj
-                dS[k, j] = 2 * (turbineX[j] - turbineX[i])
+#                dS[k, j] = 2 * (turbineX[j] - turbineX[i])
                 dSdx[k,j]= 2 * (turbineX[j] - turbineX[i])
                 # separation wrt Xi
-                dS[k, i] = -2 * (turbineX[j] - turbineX[i])
+#                dS[k, i] = -2 * (turbineX[j] - turbineX[i])
                 dSdx[k, i] = -2 * (turbineX[j] - turbineX[i])
                 # separation wrt Yj
-                dS[k, j + nTurbines] = 2 * (turbineY[j] - turbineY[i])
+#                dS[k, j + nTurbines] = 2 * (turbineY[j] - turbineY[i])
                 dSdy[k, j] = 2 * (turbineY[j] - turbineY[i])
                 # separation wrt Yi
-                dS[k, i + nTurbines] = -2 * (turbineY[j] - turbineY[i])
+#                dS[k, i + nTurbines] = -2 * (turbineY[j] - turbineY[i])
                 dSdy[k, i] = -2 * (turbineY[j] - turbineY[i])
                 # increment turbine pair counter
                 k += 1
 
         # populate Jacobian dict
-        J['wtSeparationSquared', 'turbineX'] = dS[:, :nTurbines]
-        J['wtSeparationSquared', 'turbineY'] = dS[:, nTurbines:]
+        J['wtSeparationSquared', 'turbineX'] = dSdx
+        J['wtSeparationSquared', 'turbineY'] = dSdy
diff --git a/topfarm/recording.py b/topfarm/recording.py
deleted file mode 100644
index 3b367276..00000000
--- a/topfarm/recording.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import os
-import numpy as np
-from openmdao.api import CaseReader
-
-
-def pos_from_case(case_recorder_filename):
-    cr = CaseReader(case_recorder_filename)
-    case_list = cr.driver_cases.list_cases()
-    case_len = len(case_list)
-    case_arg = 'rank0:SLSQP|{:d}'.format(case_len-1)
-    case = cr.driver_cases.get_case(case_arg)
-    x = np.array(case.desvars['turbineX'])
-    y = np.array(case.desvars['turbineY'])
-    turbines = np.column_stack((x, y))
-    return turbines
-
-
-def latest_id(case_recorder_dir):
-    files = os.listdir(case_recorder_dir)
-    files = [x for x in files if x.startswith('cases_') and x.endswith('.sql')]
-    if len(files) == 0:
-        string = 'No recorded files found in the specified directory: '
-        string += case_recorder_dir + '\n' + 9*' '
-        string += 'Start a new optimization or specify another directory '
-        string += 'for resumed optimization'
-        raise Warning(string)
-    latest = max(files)
-    latest = os.path.join(case_recorder_dir,latest)
-    return latest
-    
-if __name__ == '__main__':
-    crf = r"C:\Sandbox\Git\TopFarm2\topfarm\cases_20180621_104446.sql"
-    case_recorder_filename = crf
-    turbines = pos_from_case(case_recorder_filename)
-    print(turbines)
-
-    case_recorder_dir = r'C:\Sandbox\Git\TopFarm2\topfarm'
-    latest_id = latest_id(case_recorder_dir)
-    print(latest_id)
diff --git a/topfarm/utils.py b/topfarm/utils.py
new file mode 100644
index 00000000..16cdaaf7
--- /dev/null
+++ b/topfarm/utils.py
@@ -0,0 +1,139 @@
+import os
+from copy import copy
+import numpy as np
+from openmdao.api import CaseReader
+import matplotlib.pyplot as plt
+from topfarm.constraint_components.boundary_component import \
+    PolygonBoundaryComp
+from topfarm.constraint_components.spacing_component import SpacingComp
+
+
+def pos_from_case(case_recorder_filename):
+    if not os.path.exists(case_recorder_filename):
+        string = 'The specified optimization recording does not exists: '
+        string += case_recorder_filename
+        raise Warning(string)
+    cr = CaseReader(case_recorder_filename)
+    case_list = cr.driver_cases.list_cases()
+    case_len = len(case_list)
+    case_arg = 'rank0:SLSQP|{:d}'.format(case_len-1)
+    case = cr.driver_cases.get_case(case_arg)
+    x = np.array(case.desvars['turbineX'])
+    y = np.array(case.desvars['turbineY'])
+    turbines = np.column_stack((x, y))
+    return turbines
+
+
+def latest_id(case_recorder_dir):
+    files = os.listdir(case_recorder_dir)
+    files = [x for x in files if x.startswith('cases_') and x.endswith('.sql')]
+    if len(files) == 0:
+        string = 'No recorded files found in the specified directory: '
+        string += case_recorder_dir + '\n' + 9*' '
+        string += 'Start a new optimization or specify another directory '
+        string += 'for resumed optimization'
+        raise Warning(string)
+    latest = max(files)
+    latest = os.path.join(case_recorder_dir, latest)
+    return latest
+
+
+def random_positions(boundary, n_wt, n_iter, step_size, min_space,
+                     plot=False, verbose=True):
+    ba = np.array(boundary).T
+    x_max = max(ba[0])
+    x_min = min(ba[0])
+    y_max = max(ba[1])
+    y_min = min(ba[1])
+    x = np.random.rand(n_wt)
+    y = np.random.rand(n_wt)
+    xm = (x_max+x_min)/2
+    ym = (y_max+y_min)/2
+    xa = (x_max-xm)
+    ya = (y_max-ym)
+    x *= 2*xa
+    y *= 2*ya
+    x += xm-xa
+    y += ym-ya
+
+    boundary_comp = PolygonBoundaryComp(boundary, n_wt)
+    spacing_comp = SpacingComp(nTurbines=n_wt)
+    turbineX = copy(x)
+    turbineY = copy(y)
+    inputs = {}
+    outputs = {}
+    J = {}
+    inputs['turbineX'] = turbineX
+    inputs['turbineY'] = turbineY
+    min_space2 = min_space**2
+    bx = np.append(ba[0], ba[0][0])
+    by = np.append(ba[1], ba[1][0])
+    if plot:
+        plt.cla()
+        plt.plot(bx, by)
+        plt.plot(x, y, '.')
+    for j in range(n_iter):
+        spacing_comp.compute(inputs, outputs)
+        spacing_comp.compute_partials(inputs, J)
+        dx = J['wtSeparationSquared', 'turbineX']
+        dy = J['wtSeparationSquared', 'turbineY']
+        dist = outputs['wtSeparationSquared']
+        index = np.argmin(dist)
+        if dist[index] < min_space2:
+            turbineX += dx[index]*step_size
+            turbineY += dy[index]*step_size
+            turbineX, turbineY = _contain(n_wt, turbineX, turbineY,
+                                          boundary_comp)
+        else:
+            if verbose:
+                print('Obtained required spacing after {} iterations'.format(
+                        j))
+            break
+    if plot:
+        plt.plot(turbineX, turbineY, 'o')
+    spacing_comp.compute(inputs, outputs)
+    dist = outputs['wtSeparationSquared']
+    index = np.argmin(dist)
+    if verbose:
+        print('Spacing obtained: {}'.format(dist[index]**0.5))
+        print('Spacing required: {}'.format(min_space))
+    turbines = np.array([turbineX, turbineY]).T
+    return turbines
+
+
+def _contain(n_wt, turbineX, turbineY, boundary_comp):
+    for i in range(0, n_wt):
+        dng = boundary_comp.calc_distance_and_gradients(turbineX,
+                                                        turbineY)
+        dist = dng[0][i]
+        if dist < 0:
+            dx = dng[1][i]
+            dy = dng[2][i]
+            turbineX[i] -= dx*dist*1.1
+            turbineY[i] -= dy*dist*1.1
+            dng = boundary_comp.calc_distance_and_gradients(turbineX,
+                                                            turbineY)
+            dist = dng[0][i]
+    return turbineX, turbineY
+
+
+if __name__ == '__main__':
+    crf = r"C:\Sandbox\Git\TopFarm2\topfarm\cases_20180621_111710.sql"
+    case_recorder_filename = crf
+    turbines = pos_from_case(case_recorder_filename)
+    print(turbines)
+
+    case_recorder_dir = r'C:\Sandbox\Git\TopFarm2\topfarm'
+    latest_id = latest_id(case_recorder_dir)
+    print(latest_id)
+
+    boundary = [(0, 0), (6, 1), (7, -11), (-1, -10)]
+    n_wt = 20
+    n_iter = 1000
+    step_size = 0.1
+    min_space = 2.1
+    plot = True
+    verbose = True
+    turbines = random_positions(boundary, n_wt, n_iter, step_size, min_space,
+                                plot, verbose)
+    print(turbines)
-- 
GitLab