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