From a7bf2e79a2378a7b97e434fa0aa5e36f8ad3f611 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mikkel=20Friis-M=C3=B8ller?= <mikf@dtu.dk>
Date: Mon, 29 Nov 2021 12:55:33 +0000
Subject: [PATCH] Docs

---
 .../tests/__pycache__/__init__.cpython-39.pyc | Bin 184 -> 0 bytes
 ...d_farm_network.cpython-39-pytest-6.2.4.pyc | Bin 2681 -> 0 bytes
 ed_win/tests/test_wind_farm_network.py        |  36 +--
 ed_win/wind_farm_network.py                   | 234 +++++++++++++-----
 4 files changed, 197 insertions(+), 73 deletions(-)
 delete mode 100644 ed_win/tests/__pycache__/__init__.cpython-39.pyc
 delete mode 100644 ed_win/tests/__pycache__/test_wind_farm_network.cpython-39-pytest-6.2.4.pyc

diff --git a/ed_win/tests/__pycache__/__init__.cpython-39.pyc b/ed_win/tests/__pycache__/__init__.cpython-39.pyc
deleted file mode 100644
index 2033630fc9237359db49115b1ee0b063ee726ccb..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 184
zcmYe~<>g`kg3H|V5|x4UV-N=!FabFZKwK;YBvKes7;_k+7*ZLs7^9d{7=sx!nO*|L
z8T>SvZ?Wc;<`z^&v6rM4mt^LpM=|FWl&oYZVg^csiC<>URx!bec_~Tx6){1n1^F={
z{sC@|LB27rF5#YjF{vr><(YXgAnnC5@$s2?nI-Y@dIgoYIBatBQ%ZAE?HGYZ6@wha
G!3Y3H^ekZj

diff --git a/ed_win/tests/__pycache__/test_wind_farm_network.cpython-39-pytest-6.2.4.pyc b/ed_win/tests/__pycache__/test_wind_farm_network.cpython-39-pytest-6.2.4.pyc
deleted file mode 100644
index 12363c49943350713d310929043b741f76630b45..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 2681
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

diff --git a/ed_win/tests/test_wind_farm_network.py b/ed_win/tests/test_wind_farm_network.py
index 53e9295..0400f7d 100644
--- a/ed_win/tests/test_wind_farm_network.py
+++ b/ed_win/tests/test_wind_farm_network.py
@@ -1,27 +1,29 @@
 import numpy as np
-from ed_win.wind_farm_network import WindFarmNetwork, HeuristicDriver
+from ed_win.wind_farm_network import WindFarmNetwork, TwoStepHeuristicDriver
 import numpy.testing as npt
 
-initial_layout = dict(x=np.array([0., 2000., 4000., 6000.,
-                                  8000., 498.65600569, 2498.65600569, 4498.65600569,
-                                  6498.65600569, 8498.65600569, 997.31201137, 2997.31201137,
-                                  4997.31201137, 11336.25662483, 8997.31201137, 1495.96801706,
-                                  3495.96801706, 5495.96801706, 10011.39514341, 11426.89538545,
-                                  1994.62402275, 3994.62402275, 5994.62402275, 7994.62402275,
-                                  10588.90471566]),
-                      y=np.array([0., 0., 0., 0.,
-                                  0., 2000., 2000., 2000.,
-                                  2000., 2000., 4000., 4000.,
-                                  4000., 6877.42528387, 4000., 6000.,
-                                  6000., 6000., 3179.76530545, 5953.63051694,
-                                  8000., 8000., 8000., 8000.,
-                                  4734.32972738]))
+turbine_positions = np.asarray([[2000., 4000., 6000.,
+                                 8000., 498.65600569, 2498.65600569, 4498.65600569,
+                                 6498.65600569, 8498.65600569, 997.31201137, 2997.31201137,
+                                 4997.31201137, 11336.25662483, 8997.31201137, 1495.96801706,
+                                 3495.96801706, 5495.96801706, 10011.39514341, 11426.89538545,
+                                 1994.62402275, 3994.62402275, 5994.62402275, 7994.62402275,
+                                 10588.90471566],
+                               [0., 0., 0.,
+                                0., 2000., 2000., 2000.,
+                                2000., 2000., 4000., 4000.,
+                                4000., 6877.42528387, 4000., 6000.,
+                                6000., 6000., 3179.76530545, 5953.63051694,
+                                8000., 8000., 8000., 8000.,
+                                4734.32972738]])
+substation_positions = np.asarray([[0], [0]])
 settings = {'option': 3,
             'Inters_const': True,
             'max_it': 20000}
 cables = np.array([[500, 3, 100000], [800, 5, 150000], [1000, 10, 250000]])
-wfn = WindFarmNetwork(initial_layout=initial_layout,
-                      driver=HeuristicDriver(**settings),
+wfn = WindFarmNetwork(turbine_positions=turbine_positions,
+                      substation_positions=substation_positions,
+                      drivers=TwoStepHeuristicDriver(**settings),
                       cables=cables)
 
 T_ref = np.asarray([[1.00000000e+00, 2.00000000e+00, 2.00000000e+03, 1.00000000e+00,
diff --git a/ed_win/wind_farm_network.py b/ed_win/wind_farm_network.py
index a366587..d4909bb 100644
--- a/ed_win/wind_farm_network.py
+++ b/ed_win/wind_farm_network.py
@@ -1,26 +1,118 @@
 from abc import ABC, abstractmethod
 from ed_win.collection_system import collection_system
 from ed_win.c_mst_cables import plot_network
+# from ed_win.repair import repair
 import pandas as pd
 import numpy as np
 
 
 class Driver(ABC):
+    def __init__(self, **kwargs):
+        '''
+        '''
+
+    def run(self, x=None, y=None, T=None):
+        '''
+        x : array-like
+            concatenated array of sub-station and turbine x-coordinates
+        y : array-like
+            concatenated array of sub-station and turbine y-coordinates
+        T : array-like
+            solution tree
+
+        '''
+        T, cables_cost = self._run(x=x, y=y, T=T)
+        return T, cables_cost
+
     @abstractmethod
-    def run():
+    def _run():
         '''
 
         '''
 
 
-class HeuristicDriver(Driver):
-    def __init__(self, option=3, Inters_const=True, max_it=20000):
+class Repair(Driver):
+    def __init__(self, **kwargs):
+        self.supports_constraints = False
+        self.supports_primary = False
+        self.supports_secondary = True
+
+        Driver.__init__(self, **kwargs)
+
+    def _run(self, T, **kwargs):
+        print('I will repair T')
+        cost = self.wfn.cost
+        return T, cost
+
+
+class Refine(Driver):
+    def __init__(self, **kwargs):
+        self.supports_constraints = False
+        self.supports_primary = False
+        self.supports_secondary = True
+
+        Driver.__init__(self, **kwargs)
+
+    def _run(self, T, **kwargs):
+        print('I will refine T')
+        cost = self.wfn.cost
+        return T, cost
+
+
+class TwoStepHeuristicDriver(Driver):
+    def __init__(self, option=3, Inters_const=True, max_it=20000, **kwargs):
+        self.supports_constraints = False
+        self.supports_primary = True
+        self.supports_secondary = False
+
+        self.option = option
+        self.Inters_const = Inters_const
+        self.max_it = max_it
+        Driver.__init__(self, **kwargs)
+
+    def _run(self, x, y, **kwargs):
+        T, cables_cost = collection_system(x,
+                                           y,
+                                           self.option,
+                                           self.Inters_const,
+                                           self.max_it,
+                                           self.wfn.cables)
+        return T, cables_cost
+
+
+class GlobalDriver(Driver):
+    def __init__(self, option=3, Inters_const=True, max_it=20000, **kwargs):
+        self.supports_constraints = True
+        self.supports_primary = True
+        self.supports_secondary = True
+
         self.option = option
         self.Inters_const = Inters_const
         self.max_it = max_it
-        Driver.__init__(self)
+        Driver.__init__(self, **kwargs)
 
-    def run(self, x, y):
+    def _run(self, x, y, T, **kwargs):
+        T, cables_cost = collection_system(x,
+                                           y,
+                                           self.option,
+                                           self.Inters_const,
+                                           self.max_it,
+                                           self.wfn.cables)
+        return T, cables_cost
+
+
+class GeneticAlgorithmDriver(Driver):
+    def __init__(self, option=3, Inters_const=True, max_it=20000, **kwargs):
+        self.supports_constraints = True
+        self.supports_primary = True
+        self.supports_secondary = True
+
+        self.option = option
+        self.Inters_const = Inters_const
+        self.max_it = max_it
+        Driver.__init__(self, **kwargs)
+
+    def _run(self, x, y, T, **kwargs):
         T, cables_cost = collection_system(x,
                                            y,
                                            self.option,
@@ -31,68 +123,92 @@ class HeuristicDriver(Driver):
 
 
 class WindFarmNetwork():
-    def __init__(self, initial_layout, driver=HeuristicDriver(), cables=[]):
+    def __init__(self, turbine_positions, substation_positions, drivers=[TwoStepHeuristicDriver()], cables=[], T=None, sequence=None):
         """WindFarmNetwork object
 
         Parameters
         ----------
-        initial_layout : array-like
-            The shape of the array is (i, j), where i is 2 and j is the number of  turbines + 1.
-            i=1 is x and i=2 is y. j=0 is the coordinates of the offshore sub station and j=1: are the turbine coordinates.
-        driver : Driver
-            Driver object
+        turbine_positions : array-like
+            Two dimentional array with turbine x- and y-coordinates
+        substation_positions : array-like
+            Two dimentional array with sub station x- and y-coordinates
+        drivers : list
+            List of Driver objects
         cables : array-like
             The shape of the array is (n, m), where n is the number of available cables and m is 3.
             m=1 is cross-section, m=2 is the allowed number of connected WTs and m=3 is the price/km of the cable
         """
-        self.initial_layout = initial_layout
-        self.driver = driver
+        if not isinstance(drivers, list):
+            drivers = [drivers]
+        self.turbine_positions = turbine_positions
+        self.substation_positions = substation_positions
+        self.drivers = drivers
         self.cables = cables
         self.state = None
-        self.T = None
+        self.T = T
         self.columns = ['from_node', 'to_node', 'cable_length', 'cable_type', 'cable_cost']
+        if isinstance(sequence, type(None)):
+            sequence = range(len(drivers))
+        self.sequence = sequence
         self.setup()
 
     def setup(self):
-        setattr(self.driver, 'wfn', self)
+        for driver in self.drivers:
+            setattr(driver, 'wfn', self)
 
-    def design(self, x=None, y=None, **kwargs):
+    def design(self, turbine_positions=None, T=None, **kwargs):
         """designs or optimizes the electrical wind farm network
 
         Parameters
         ----------
-        x : array-like
-            concatenated list of sub station and turbine x-coordinates
-        y : array-like
-            concatenated list of sub station and turbine y-coordinates
+        turbine_positions : array-like
+            Two dimentional array with turbine x- and y-coordinates
+
+        T : array
+            The current network tree with the columns f{self.columns}
 
         Returns
         -------
         cost : float
             The cost of the electrical network
-        state : DataFrame
+        T : array
             The current network tree with the columns f{self.columns}
         """
-        if isinstance(x, type(None)):
-            x = self.initial_layout['x']
-        if isinstance(y, type(None)):
-            y = self.initial_layout['y']
-        self.x = x
-        self.y = y
-        T, cost = self.driver.run(x, y)
-        state = pd.DataFrame(T, columns=self.columns)
-        state = state.astype({'from_node': int,
-                              'to_node': int,
-                              'cable_type': int})
-        self.T = T
-        self.cost = cost
-        self.state = state
-        return cost, state
+        if not isinstance(turbine_positions, type(None)):
+            self.turbine_positions = turbine_positions
+        if isinstance(T, type(None)):
+            T = self.T
+
+        x, y = self.positions_to_xy()
+
+        for n, driver_no in enumerate(self.sequence):
+            driver = self.drivers[driver_no]
+            if n == 0 and not driver.supports_primary:
+                raise Exception(driver + ' cannot be the first driver in a sequence')
+            elif n > 0 and not driver.supports_secondary:
+                raise Exception(driver + ' cannot be used as a secondary driver')
+            T, cost = driver.run(x=x, y=y, T=T)
+            self.T = T
+            self.cost = cost
+
+        return cost, T
+
+    def positions_to_xy(self):
+        return [np.concatenate((self.substation_positions[i], self.turbine_positions[i]), axis=0) for i in [0, 1]]
+
+    def tree_as_table(self):
+        tree_table = pd.DataFrame(self.T, columns=self.columns)
+        tree_table = tree_table.astype({'from_node': int,
+                                        'to_node': int,
+                                        'cable_type': int})
+        return tree_table
+
+    def get_edges(self, x, y):
+        return 'edges'
 
     def plot(self):
-        if self.state is None:
-            self.design()
-        plot_network(self.x, self.y, self.cables, self.T)
+        x, y = self.positions_to_xy()
+        plot_network(x, y, self.cables, self.T)
 
 
 class Constraints(dict):
@@ -106,29 +222,35 @@ class Constraints(dict):
 
 def main():
     if __name__ == '__main__':
-        initial_layout = dict(x=np.array([0., 2000., 4000., 6000.,
-                                          8000., 498.65600569, 2498.65600569, 4498.65600569,
-                                          6498.65600569, 8498.65600569, 997.31201137, 2997.31201137,
-                                          4997.31201137, 11336.25662483, 8997.31201137, 1495.96801706,
-                                          3495.96801706, 5495.96801706, 10011.39514341, 11426.89538545,
-                                          1994.62402275, 3994.62402275, 5994.62402275, 7994.62402275,
-                                          10588.90471566]),
-                              y=np.array([0., 0., 0., 0.,
-                                          0., 2000., 2000., 2000.,
-                                          2000., 2000., 4000., 4000.,
-                                          4000., 6877.42528387, 4000., 6000.,
-                                          6000., 6000., 3179.76530545, 5953.63051694,
-                                          8000., 8000., 8000., 8000.,
-                                          4734.32972738]))
+        turbine_positions = np.asarray([[2000., 4000., 6000.,
+                                         8000., 498.65600569, 2498.65600569, 4498.65600569,
+                                         6498.65600569, 8498.65600569, 997.31201137, 2997.31201137,
+                                         4997.31201137, 11336.25662483, 8997.31201137, 1495.96801706,
+                                         3495.96801706, 5495.96801706, 10011.39514341, 11426.89538545,
+                                         1994.62402275, 3994.62402275, 5994.62402275, 7994.62402275,
+                                         10588.90471566],
+                                       [0., 0., 0.,
+                                        0., 2000., 2000., 2000.,
+                                        2000., 2000., 4000., 4000.,
+                                        4000., 6877.42528387, 4000., 6000.,
+                                        6000., 6000., 3179.76530545, 5953.63051694,
+                                        8000., 8000., 8000., 8000.,
+                                        4734.32972738]])
+        substation_positions = np.asarray([[0], [0]])
         settings = {'option': 3,
                     'Inters_const': True,
-                    'max_it': 20000}
+                    'max_it': 20000,
+                    'repair': True}
         cables = np.array([[500, 3, 100000], [800, 5, 150000], [1000, 10, 250000]])
-        wfn = WindFarmNetwork(initial_layout=initial_layout,
-                              driver=HeuristicDriver(**settings),
+        wfn = WindFarmNetwork(turbine_positions=turbine_positions,
+                              substation_positions=substation_positions,
+                              drivers=[TwoStepHeuristicDriver(**settings), Refine(), Repair()],
+                              sequence=[0, 2, 1],
                               cables=cables)
         cost, state = wfn.design()
         wfn.plot()
+        print(wfn.tree_as_table())
+        print(cost)
 
 
 main()
-- 
GitLab