diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ef6c4dd9052007bd5f81ad9e6aae80033d7d49cc..749598d69845e908a21c03abcaa8dcd8f7b1b040 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ check_code_style: test script: - pip install -e . - - pycodestyle --ignore=E501,W504,E741 edwin + - pycodestyle --ignore=E501,W504,E741 ed_win tags: - python @@ -29,10 +29,29 @@ test_EDWIN_windows: - "if (test-path $PROFILE.CurrentUserAllHosts) { & $PROFILE.CurrentUserAllHosts}" - conda activate py36_openmdao26 - pip install -e .[test] - - pytest --cov-report term-missing:skip-covered --cov=py_wake --cov-config .coveragerc + - pytest --cov-report term-missing:skip-covered --cov=ed_win --cov-config .coveragerc tags: - ANMH_old + +# ===== BUILD DOCS AND PUSH TO PUBLIC WEBSITE ===== +pages: + stage: + deploy + script: + - pip install -e . + - cd docs; make html + - cd ../; mv docs/build/html public/ + artifacts: + paths: + - public + only: + - master + - /^test_doc.*/ + tags: + - python + + pypi: stage: deploy diff --git a/.pep8 b/.pep8 new file mode 100644 index 0000000000000000000000000000000000000000..8f1d49a635c1fcf51fed70e1c7901bdcd96e3eb7 --- /dev/null +++ b/.pep8 @@ -0,0 +1,2 @@ +[pycodestyle] +ignore = E501,W504,E741 \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..63376f9b3d8be5f10a19f40ea5464328bb58f639 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = python -msphinx +SPHINXPROJ = EDWIN +SOURCEDIR = . +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/__init__.py b/docs/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docs/api/Classes.rst b/docs/api/Classes.rst new file mode 100644 index 0000000000000000000000000000000000000000..45358fde741715f7e0692135e3d1fc10dd64c720 --- /dev/null +++ b/docs/api/Classes.rst @@ -0,0 +1,37 @@ + +Edwin classes +================= + + +WindFarmNetwork +----------------- + +.. autoclass:: edwin.wind_farm_network.WindFarmNetwork + :members: + + .. autosummary:: + setup + design + plot + + + +Driver +----------------- + +.. autoclass:: edwin.wind_farm_network.Driver + + + .. automethod:: __init__ + + + +HeuristicDriver +------------------ + +.. autoclass:: edwin.wind_farm_network.HeuristicDriver + + .. automethod:: __init__ + + + diff --git a/docs/api/__init__.py b/docs/api/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..c5ad1bda28b764e90cd9d257c09c4c4fe6d3ee64 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,281 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('..')) +sys.path.append(r"C:\Users\mikf\Anaconda3\envs\topfarm\Library\bin") + +from py_wake import __version__ +from py_wake import __release__ + +# -- Project information ----------------------------------------------------- + +project = 'EDWIN' +copyright = '2021, DTU Wind Energy' +author = 'DTU Wind Energy' + +# The short X.Y version +version = __version__ +# The full version, including alpha/beta/rc tags +release = __release__ + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.intersphinx', + 'sphinx.ext.mathjax', + 'sphinx.ext.napoleon', + 'sphinx.ext.viewcode', + 'sphinx.ext.inheritance_diagram', + 'nbsphinx', + 'sphinx.ext.doctest', + #'sphinx.ext.imgconverter', +] + +intersphinx_mapping = { + 'python': ('https://docs.python.org/3/', None), + 'numpy': ('https://docs.scipy.org/doc/numpy/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), +} + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +source_suffix = ['.rst', '.md'] + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [ + # Slow notebook: + #'notebooks/neural_network_with_tfds_data.ipynb', + # ipynb checkpoints + 'notebooks/.ipynb_checkpoints/*.ipynb', + 'build/*' +] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +autosummary_generate = True +napolean_use_rtype = False + +# -- Options for nbsphinx ----------------------------------------------------- + +# Execute notebooks before conversion: 'always', 'never', 'auto' (default) +# We execute all notebooks, exclude the slow ones using 'exclude_patterns' +nbsphinx_execute = 'always' + +# Use this kernel instead of the one stored in the notebook metadata: +#nbsphinx_kernel_name = 'python3' + +# List of arguments to be passed to the kernel that executes the notebooks: +# nbsphinx_execute_arguments = [] + +# If True, the build process is continued even if an exception occurs: +#nbsphinx_allow_errors = True + + +# Controls when a cell will time out (defaults to 30; use -1 for no timeout): +nbsphinx_timeout = 180 + +# Default Pygments lexer for syntax highlighting in code cells: +#nbsphinx_codecell_lexer = 'ipython3' + +# Width of input/output prompts used in CSS: +#nbsphinx_prompt_width = '8ex' + +# If window is narrower than this, input/output prompts are on separate lines: +#nbsphinx_responsive_width = '700px' + +# This is processed by Jinja2 and inserted before each notebook +nbsphinx_prolog = r""" +{% set docname = 'docs/' + env.doc2path(env.docname, base=None) %} + + +.. only:: html + + .. role:: raw-html(raw) + :format: html + + .. nbinfo:: + + + :raw-html:`<a href="https://colab.research.google.com/github/DTUWindEnergy/EDWIN/blob/master/{{ docname }}"><img alt="Open and run in Colab (interactive)" src="https://colab.research.google.com/assets/colab-badge.svg" style="vertical-align:text-bottom"></a> + <a href="https://gitlab.windenergy.dtu.dk/TOPFARM/EDWIN/-/tree/master/{{ docname }}"><img alt="Edit on Gitlab" src="https://img.shields.io/badge/Edit%20on-Gitlab-blue?style=flat&logo=gitlab" style="vertical-align:text-bottom"></a>` + +""" + +# This is processed by Jinja2 and inserted after each notebook +# nbsphinx_epilog = r""" +# """ + +# Input prompt for code cells. "%s" is replaced by the execution count. +#nbsphinx_input_prompt = 'In [%s]:' + +# Output prompt for code cells. "%s" is replaced by the execution count. +#nbsphinx_output_prompt = 'Out[%s]:' + +# Specify conversion functions for custom notebook formats: +#import jupytext +# nbsphinx_custom_formats = { +# '.Rmd': lambda s: jupytext.reads(s, '.Rmd'), +#} + +# Link or path to require.js, set to empty string to disable +#nbsphinx_requirejs_path = '' + +# Options for loading require.js +#nbsphinx_requirejs_options = {'async': 'async'} + +mathjax_config = { + 'TeX': {'equationNumbers': {'autoNumber': 'AMS', 'useLabelIds': True}}, +} + +# Additional files needed for generating LaTeX/PDF output: +# latex_additional_files = ['references.bib'] + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + # TOC options + #'navigation_depth': 2, # only show 2 levels on left sidebar + 'collapse_navigation': False, # don't allow sidebar to collapse +} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'EDWINdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'EDWIN.tex', 'EDWIN Documentation', + 'DTU Wind Energy', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'ed_win', 'EDWIN Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'EDWIN', 'EDWIN Documentation', + author, 'EDWIN', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] + + +# -- Extension configuration ------------------------------------------------- diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..cc34d0c17ed5a42630ef8f27764c4f046ebe95bc --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,34 @@ +.. EDWIN documentation master file + + +Welcome to Edwin +=========================================== + +*- an open source simulation tool capable of designing and optimizing electrical networks in wind farms.* + + +**Quick Start**:: + + pip install ed_win + +Source code repository (and issue tracker): + https://gitlab.windenergy.dtu.dk/TOPFARM/Edwin + +License: + MIT_ + +.. _MIT: https://gitlab.windenergy.dtu.dk/TOPFARM/Edwin/blob/master/LICENSE + + +Contents: + .. toctree:: + :maxdepth: 2 + + installation + + + .. toctree:: + :caption: API + + api/Classes + diff --git a/docs/install_python.rst b/docs/install_python.rst new file mode 100644 index 0000000000000000000000000000000000000000..e1698641f5d4be9fcb2f2c92f52dd89cc2e83366 --- /dev/null +++ b/docs/install_python.rst @@ -0,0 +1,30 @@ + + +Install Python +============== + + For all platforms we recommend that you download and install the Anaconda - + a professional grade, full blown scientific Python distribution. + + Installing Anaconda, activate root environment: + + * Download and install Anaconda (Python 3.x version, 64 bit installer is recommended) from https://www.continuum.io/downloads + + * Update the root Anaconda environment (type in a terminal): + + ``>> conda update --all`` + + * Activate the Anaconda root environment in a terminal as follows: + + ``>> activate`` + +Create envirronment +=================== + + If you have other Python programs besides EDWIN, it is a good idea to install + each program in its own environment to ensure that the dependencies for the + different packages do not conflict with one another. The commands to create and + then activate an environment in an Anaconda prompt are:: + + conda create --name edwin python=3.9 + activate edwin \ No newline at end of file diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000000000000000000000000000000000000..c458b188f5b486cdea1285ea8a20dcf8d3a1d3e0 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,41 @@ + + + +Installation +=========================== + +.. toctree:: + :maxdepth: 2 + + install_python + + + + +Install EDWIN (Simple user) +---------------------------- + +* Install from PyPi.org (official releases):: + + pip install ed_win + +* Install from gitlab (includes any recent updates):: + + pip install git+https://gitlab.windenergy.dtu.dk/TOPFARM/EDWIN.git + + + +Install EDWIN (Developer) +-------------------------- + +We highly recommend developers install EDWIN into its own environment. (See +instructions above.) The commands to clone and install EDWIN with developer +options including dependencies required to run the tests into the current active +environment in an Anaconda Prommpt are as follows:: + + git clone https://gitlab.windenergy.dtu.dk/TOPFARM/EDWIN.git + cd EDWIN + pip install -e .[test] + + + diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000000000000000000000000000000000000..a8333763fe1bbbbf99291a4964fbaddfcb5dfa9b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) + +set SOURCEDIR=. +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -D graphviz_dot="C:\Anaconda3\envs\py36\Library\bin\graphviz\dot.exe" +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/edwin/__init__.py b/ed_win/__init__.py similarity index 95% rename from edwin/__init__.py rename to ed_win/__init__.py index b325f3b6db0997eb03ed3fc50895062d0f59017f..a4bbf1f9d3be8aad8929d173f0a8c72cc4af153a 100644 --- a/edwin/__init__.py +++ b/ed_win/__init__.py @@ -1,3 +1,3 @@ -# 'filled_by_setup.py' -__version__ = '0.0.0' -__release__ = '0.0.0' +# 'filled_by_setup.py' +__version__ = '0.0.0' +__release__ = '0.0.0' diff --git a/edwin/c_mst.py b/ed_win/c_mst.py similarity index 98% rename from edwin/c_mst.py rename to ed_win/c_mst.py index 23720f81ade3b84ca7898d1dca926b2e1522a656..95a8569b92f545d94e68cdc92bc6204d0622f914 100644 --- a/edwin/c_mst.py +++ b/ed_win/c_mst.py @@ -1,454 +1,454 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu May 28 08:12:54 2020 - -@author: juru -""" -import numpy as np -import matplotlib.pyplot as plt -from edwin.intersection_checker import intersection_checker - - -def capacitated_spanning_tree(X=[], Y=[], option=3, UL=100, Inters_const=True, max_it=20000): - """ - Calculate a minimum spanning tree distance for a layout. - Capacitated minimum spanning tree heuristics algorithm for Topfarm. - - Parameters - ---------- - *X, Y: list([n_wt_oss]) or array type as well - X,Y positions of the wind turbines and oss - *option: Heuristic type. option=1 is Prim. option=2 is Kruskal. option=3 is Esau-Williams - *max_it: Maximm number of iterations for the heuristics - *UL: Upper limit for the max number of wind turbines connectable by the biggest available cable - *Inters_const=Bool. True is cable crossings are not allowed. False if they are allowed. - - :return: T: Array. First column is first node, second column is second noce, third column is the distance between nodes - The OSS is always the node number 1. The WTs go from 2 to number of WTs plus one - feasible: Bool. True is solution is feasible. False if not. - - """ -# %% Initializing arrays, lists, variables (until line 46 .m file) - n_wt_oss = len(X) # Defining number of wind turbines with OSS - half = int(n_wt_oss * (n_wt_oss - 1) / 2) - edges_tot = np.zeros((2 * half, 5)) # Defining the matrix with Edges information - cont_edges = 0 - for i in range(n_wt_oss): - for j in range(i + 1, n_wt_oss): - edges_tot[cont_edges, 0] = i + 1 # First element is first node (Element =1 is the OSS. and from 2 to Nwt the WTs) - edges_tot[cont_edges, 1] = j + 1 # Second element is second node - edges_tot[cont_edges, 2] = np.sqrt((X[j] - X[i])**2 + (Y[j] - Y[i])**2) # Third element is the length of the edge - cont_edges += 1 - CP = [x for x in range(n_wt_oss)] # Initializing component position list for each node. A component goes from 0 until n_wt_oss-1. Fixed length. - address_nodes = [-1 for x in range(n_wt_oss)] # Initializing address list for each node. It indicates the root node for each node in the tree and in subtrees from OSS. Fixed length. - address_nodes[0] = 0 - address_nodes = np.array(address_nodes, dtype=int) - C = [[x + 1] for x in range(n_wt_oss)] # Initializing component list (nodes belonging to each comonent). A component goes from 0 until n_wt_oss-1, and its length decreases until 1 (component 0). Variable length. - S = [1 for x in range(n_wt_oss)] # Initializing size of components list (how many nodes are in each component). A component goes from 0 until n_wt_oss-1, and its length decreases until 1 (component 0 with n_wt_oss-1 elements). Variable length. - go, it, node1, node2, weight = True, 0, 0, 0, np.zeros((n_wt_oss, 1)) # Initializing variables for iterations - if option == 1: # Initializing weight of nodes. Each index represents a node, such as Node=Index+1 - weight[0], weight[1:n_wt_oss] = 0, -10**50 - elif option == 2: - weight - elif option == 3: - weight[0], weight[1:n_wt_oss] = 0, edges_tot[0:n_wt_oss - 1, 2].reshape(n_wt_oss - 1, 1) - else: - raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) - for i in range(2 * half): # Forming the big matrix with all edges and corresponding trade-off values (fixed size). - if i <= half - 1: - edges_tot[i, 3] = weight[edges_tot[i, 0].astype(int) - 1, 0] - edges_tot[i, 4] = edges_tot[i, 2] - edges_tot[i, 3] - else: - edges_tot[i, 0] = edges_tot[i - half, 1] - edges_tot[i, 1] = edges_tot[i - half, 0] - edges_tot[i, 2] = edges_tot[i - half, 2] - edges_tot[i, 3] = weight[edges_tot[i, 0].astype(int) - 1, 0] - edges_tot[i, 4] = edges_tot[i, 2] - edges_tot[i, 3] - mst_edges = np.zeros(2 * half, dtype=bool) # Array containing the activation variables of selected edges - feasible = False -# %% Main (until line 609 .m file) - while go: - flag1, flag2, flag3, flag4 = True, True, True, True - it += 1 - value_potential_edge, pos_potential_edge = np.min(edges_tot[:, 4]), np.argmin(edges_tot[:, 4]) - if (value_potential_edge > 10**49) or (it == max_it): # Condition to stop if a C-MST cannot be found - # print(it) - # print(value_potential_edge) - break - node1, node2 = edges_tot[pos_potential_edge, 0].astype(int), edges_tot[pos_potential_edge, 1].astype(int) - if (CP[node1 - 1] == CP[node2 - 1]) and (flag1) and (flag2) and (flag3) and (flag4): # Condition for avoiding the creation of loops - flag1 = False # Boolean for loops creation - if pos_potential_edge <= half - 1: # Eliminiating edges which connect the same component - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - # %% Next code is when the potential edge is connected directly to the OSS (node==1) and it does not create loops - if ((node1 == 1) or (node2 == 1)) and (flag1) and (flag2) and (flag3) and (flag4): # Evaluation of the number of nodes in a subtree rooted at 1 - flag2 = False - if node1 == 1: # If the selected edge has a node 1 the OSS - if (S[CP[node2 - 1]] > UL): # Evaluation of the capacity constraint: If true, proceeding to eliminate edges - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - else: # If capacity constraint not violated, then evaluate no-crossing cables constraint - if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree - mst_edges[pos_potential_edge] = True # Add it to the tree. line 88 .m file - # Update node address - address_nodes[node2 - 1] = 1 - C_sliced_n2 = C[CP[node2 - 1]] - for j in range(len(C_sliced_n2)): # This could be replaced without for loop as address_nodes is now an array (before was a list) - if C_sliced_n2[j] == node2: - pass - else: - address_nodes[C_sliced_n2[j] - 1] = node2 - # Update weights and cost functions - if option == 1: - weight[node2 - 1] = 0 - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] - elif option == 2: - pass - elif option == 3: - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - weight[C_sliced_n1[j] - 1] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] - else: - raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 126 .m file - # Eliminating selected edge from edges potential list - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - # Updating auxiliary matrix CP, C, S - u, v = min(node1, node2), max(node1, node2) - C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] - S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components - C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge - old_pos = CP[v - 1] - for j in range(len(C_sliced_v)): # Updating components position for each merged node - CP[C_sliced_v[j] - 1] = CP[u - 1] - for j in range(len(CP)): - if CP[j] > old_pos: - CP[j] -= 1 - del C[old_pos] # Deleting old component - del S[old_pos] # Deleting old component size (line 167 .m file) - else: # If a cable crossing is detected - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - if node2 == 1: # If the selected edge has a node 2 the OSS - if (S[CP[node1 - 1]] > UL): # Evaluation of the capacity constraint: If true, proceeding to eliminate edges - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - else: - if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree - mst_edges[pos_potential_edge] = True # Add it to the tree. line 190 .m file - # Update node address - address_nodes[node1 - 1] = 1 - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - if C_sliced_n1[j] == node1: - pass - else: - address_nodes[C_sliced_n1[j] - 1] = node1 - # Update weights and cost functions - if option == 1: - weight[node2 - 1] = 0 - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] - elif option == 2: - pass - elif option == 3: - # C_sliced_n1=C[CP[node1-1]] - for j in range(len(C_sliced_n1)): - weight[C_sliced_n1[j] - 1] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] - else: - raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 226 .m file - # Eliminating selected edge from edges potential list - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # line 234 .m file - # Updating auxiliary matrix CP, C, S - u, v = min(node1, node2), max(node1, node2) - C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] - S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components - C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge - old_pos = CP[v - 1] - for j in range(len(C_sliced_v)): # Updating components position for each merged node - CP[C_sliced_v[j] - 1] = CP[u - 1] - for j in range(len(CP)): - if CP[j] > old_pos: - CP[j] -= 1 - del C[old_pos] # Deleting old component - del S[old_pos] # Deleting old component size (line 267 .m file) - else: # If a cable crossing is detected - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - # %% Next code is when the potential edge is not connected directly to the OSS (node==1) and it does not create loops. Two cases: One of the components has as element node=1 or none of them. - if (flag1) and (flag2) and (flag3) and (flag4): - if (1 in C[CP[node1 - 1]]) or (1 in C[CP[node2 - 1]]): # One of the components has an element '1' (OSS) - flag3 = False # line 284 .m file - if (1 in C[CP[node1 - 1]]): # The component of node1 includes the root 1 - if address_nodes[node1 - 1] == 1: # The node 1 is connected directly to the OSS (element '1') - tot_nodes = np.where(address_nodes == node1)[0].size + S[CP[node2 - 1]] + 1 - else: # The node 1 is not connected directly to the OSS (element '1') - tot_nodes = np.where(address_nodes == address_nodes[node1 - 1])[0].size + S[CP[node2 - 1]] + 1 - if tot_nodes > UL: # Evaluation of the capacity constraint: If true, proceeding to eliminate edges - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - else: # No violation of capacity constraint - if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree - mst_edges[pos_potential_edge] = True # Add it to the tree. line 301 .m file - # Update node address - if address_nodes[node1 - 1] == 1: - C_sliced_n2 = C[CP[node2 - 1]] - for j in range(len(C_sliced_n2)): - address_nodes[C_sliced_n2[j] - 1] = node1 - else: - C_sliced_n2 = C[CP[node2 - 1]] - for j in range(len(C_sliced_n2)): - address_nodes[C_sliced_n2[j] - 1] = address_nodes[node1 - 1] # line 318 .m file - # Update weights and cost functions - if option == 1: - weight[node2 - 1] = 0 - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] - elif option == 2: - pass - elif option == 3: - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - weight[C_sliced_n1[j] - 1] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] - else: - raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 344 .m file - # Eliminating selected edge from edges potential list - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # line 352 .m file - # Updating auxiliary matrix CP, C, S - u, v = min(node1, node2), max(node1, node2) - C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] - S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components - C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge - old_pos = CP[v - 1] - for j in range(len(C_sliced_v)): # Updating components position for each merged node - CP[C_sliced_v[j] - 1] = CP[u - 1] - for j in range(len(CP)): - if CP[j] > old_pos: - CP[j] -= 1 - del C[old_pos] # Deleting old component - del S[old_pos] # Deleting old component size (line 385 .m file) - else: # If a cable crossing is detected - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # (line 396 .m file) - else: # The component of node2 includes the root 1 - if address_nodes[node2 - 1] == 1: # The node 2 is connected directly to the OSS (element '1') - tot_nodes = np.where(address_nodes == node2)[0].size + S[CP[node1 - 1]] + 1 - else: # The node 2 is not connected directly to the OSS (element '1') - tot_nodes = np.where(address_nodes == address_nodes[node2 - 1])[0].size + S[CP[node1 - 1]] + 1 - if tot_nodes > UL: # Evaluation of the capacity constraint: If true, proceeding to eliminate edges - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - else: # No violation of capacity constraint - if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree - mst_edges[pos_potential_edge] = True # Add it to the tree. line 413 .m file - # Update node address - if address_nodes[node2 - 1] == 1: - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - address_nodes[C_sliced_n1[j] - 1] = node2 - else: - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - address_nodes[C_sliced_n1[j] - 1] = address_nodes[node2 - 1] # line 430 .m file - # Update weights and cost functions - if option == 1: - weight[node2 - 1] = 0 - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] - elif option == 2: - pass - elif option == 3: - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - weight[C_sliced_n1[j] - 1] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] - else: - raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 456 .m file - # Eliminating selected edge from edges potential list - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # line 464 .m file - # Updating auxiliary matrix CP, C, S - u, v = min(node1, node2), max(node1, node2) - C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] - S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components - C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge - old_pos = CP[v - 1] - for j in range(len(C_sliced_v)): # Updating components position for each merged node - CP[C_sliced_v[j] - 1] = CP[u - 1] - for j in range(len(CP)): - if CP[j] > old_pos: - CP[j] -= 1 - del C[old_pos] # Deleting old component - del S[old_pos] # Deleting old component size (line 497 .m file) - else: # If a cable crossing is detected - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # (line 507 .m file) - else: # Node of the components has as element '1' (OSS) - flag4 = False - if (S[CP[node1 - 1]] + S[CP[node2 - 1]] > UL): # Evaluation of the capacity constraint: If true, proceeding to eliminate edges - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - else: # If no violation of the capacity constraint - if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree - mst_edges[pos_potential_edge] = True # Add it to the tree. line 522 .m file - # Update weights and cost functions - if option == 1: - weight[node2 - 1] = 0 - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] - elif option == 2: - pass - elif option == 3: - C_sliced_n1 = C[CP[node1 - 1]] - for j in range(len(C_sliced_n1)): - weight[C_sliced_n1[j] - 1] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ - edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] - else: - raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 548 .m file - # Eliminating selected edge from edges potential list - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - # Updating auxiliary matrix CP, C, S - u, v = min(node1, node2), max(node1, node2) - C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] - S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components - C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge - old_pos = CP[v - 1] - for j in range(len(C_sliced_v)): # Updating components position for each merged node - CP[C_sliced_v[j] - 1] = CP[u - 1] - for j in range(len(CP)): - if CP[j] > old_pos: - CP[j] -= 1 - del C[old_pos] # Deleting old component - del S[old_pos] # Deleting old component size (line 590 .m file) - else: # If a cable crossing is detected - if pos_potential_edge <= half - 1: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 - else: - edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 - edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 - if len(C) == 1: - go = False # (line 606 .m file) - feasible = True - T = np.zeros((len(np.where(mst_edges)[0]), 3)) - T[:, 0] = edges_tot[np.where(mst_edges)[0], 0] - T[:, 1] = edges_tot[np.where(mst_edges)[0], 1] - T[:, 2] = edges_tot[np.where(mst_edges)[0], 2] -# %% Running the function - return T, feasible - - -if __name__ == "__main__": - # First X,Y are for artifitial wind farm Diagonal 10 (10 WTs + 1 OSS) - X = [10000, 8285.86867841725, 9097.62726321941, 8736.91009361509, 9548.66867841725, 10360.4272632194, 9187.95150881294, 9999.71009361510, 10811.4686784173, 10450.7515088129, 11262.5100936151] - Y = [10000, 9426, 8278, 10574, 9426, 8278, 11722, 10574, 9426, 11722, 10574] - # Next X,Y are for real-world wind farm Ormonde (30 WTs + 1 OSS) - # X=[473095,471790,471394,470998,470602,470207,469811,472523,469415,472132,471742,471351,470960,470569,470179,469788,472866,472480,472094,471708,471322,470937,470551,473594,473213,472833,472452,472071,471691,471310,470929] - # Y=[5992345,5991544,5991899,5992252,5992607,5992960,5993315,5991874,5993668,5992236,5992598,5992960,5993322,5993684,5994047,5994409,5992565,5992935,5993306,5993675,5994045,5994416,5994786,5992885,5993264,5993643,5994021,5994400,5994779,5995156,5995535] - # Next X, Y are for real-world wind farm DanTysk (80 WTs + 1 OSS) - # X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300] - # Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000] - X = np.array(X) - Y = np.array(Y) - option = 3 - UL = 15 - Inters_const = True - T, feasible = capacitated_spanning_tree(X, Y, option, UL, Inters_const) - - print("The total length of the solution is {value:.2f} m".format(value=sum(T[:, 2]))) - print("Feasibility: {feasible1}".format(feasible1=feasible)) - plt.figure() - plt.plot(X[1:], Y[1:], 'r+', markersize=10, label='Turbines') - plt.plot(X[0], Y[0], 'ro', markersize=10, label='OSS') - for i in range(len(X)): - plt.text(X[i] + 50, Y[i] + 50, str(i + 1)) - n1xs = X[T[:, 0].astype(int) - 1].ravel().T - n2xs = X[T[:, 1].astype(int) - 1].ravel().T - n1ys = Y[T[:, 0].astype(int) - 1].ravel().T - n2ys = Y[T[:, 1].astype(int) - 1].ravel().T - xs = np.vstack([n1xs, n2xs]) - ys = np.vstack([n1ys, n2ys]) - plt.plot(xs, ys, 'b') - plt.legend() +# -*- coding: utf-8 -*- +""" +Created on Thu May 28 08:12:54 2020 + +@author: juru +""" +import numpy as np +import matplotlib.pyplot as plt +from ed_win.intersection_checker import intersection_checker + + +def capacitated_spanning_tree(X=[], Y=[], option=3, UL=100, Inters_const=True, max_it=20000): + """ + Calculate a minimum spanning tree distance for a layout. + Capacitated minimum spanning tree heuristics algorithm for Topfarm. + + Parameters + ---------- + *X, Y: list([n_wt_oss]) or array type as well + X,Y positions of the wind turbines and oss + *option: Heuristic type. option=1 is Prim. option=2 is Kruskal. option=3 is Esau-Williams + *max_it: Maximm number of iterations for the heuristics + *UL: Upper limit for the max number of wind turbines connectable by the biggest available cable + *Inters_const=Bool. True is cable crossings are not allowed. False if they are allowed. + + :return: T: Array. First column is first node, second column is second noce, third column is the distance between nodes + The OSS is always the node number 1. The WTs go from 2 to number of WTs plus one + feasible: Bool. True is solution is feasible. False if not. + + """ +# %% Initializing arrays, lists, variables (until line 46 .m file) + n_wt_oss = len(X) # Defining number of wind turbines with OSS + half = int(n_wt_oss * (n_wt_oss - 1) / 2) + edges_tot = np.zeros((2 * half, 5)) # Defining the matrix with Edges information + cont_edges = 0 + for i in range(n_wt_oss): + for j in range(i + 1, n_wt_oss): + edges_tot[cont_edges, 0] = i + 1 # First element is first node (Element =1 is the OSS. and from 2 to Nwt the WTs) + edges_tot[cont_edges, 1] = j + 1 # Second element is second node + edges_tot[cont_edges, 2] = np.sqrt((X[j] - X[i])**2 + (Y[j] - Y[i])**2) # Third element is the length of the edge + cont_edges += 1 + CP = [x for x in range(n_wt_oss)] # Initializing component position list for each node. A component goes from 0 until n_wt_oss-1. Fixed length. + address_nodes = [-1 for x in range(n_wt_oss)] # Initializing address list for each node. It indicates the root node for each node in the tree and in subtrees from OSS. Fixed length. + address_nodes[0] = 0 + address_nodes = np.array(address_nodes, dtype=int) + C = [[x + 1] for x in range(n_wt_oss)] # Initializing component list (nodes belonging to each comonent). A component goes from 0 until n_wt_oss-1, and its length decreases until 1 (component 0). Variable length. + S = [1 for x in range(n_wt_oss)] # Initializing size of components list (how many nodes are in each component). A component goes from 0 until n_wt_oss-1, and its length decreases until 1 (component 0 with n_wt_oss-1 elements). Variable length. + go, it, node1, node2, weight = True, 0, 0, 0, np.zeros((n_wt_oss, 1)) # Initializing variables for iterations + if option == 1: # Initializing weight of nodes. Each index represents a node, such as Node=Index+1 + weight[0], weight[1:n_wt_oss] = 0, -10**50 + elif option == 2: + weight + elif option == 3: + weight[0], weight[1:n_wt_oss] = 0, edges_tot[0:n_wt_oss - 1, 2].reshape(n_wt_oss - 1, 1) + else: + raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) + for i in range(2 * half): # Forming the big matrix with all edges and corresponding trade-off values (fixed size). + if i <= half - 1: + edges_tot[i, 3] = weight[edges_tot[i, 0].astype(int) - 1, 0] + edges_tot[i, 4] = edges_tot[i, 2] - edges_tot[i, 3] + else: + edges_tot[i, 0] = edges_tot[i - half, 1] + edges_tot[i, 1] = edges_tot[i - half, 0] + edges_tot[i, 2] = edges_tot[i - half, 2] + edges_tot[i, 3] = weight[edges_tot[i, 0].astype(int) - 1, 0] + edges_tot[i, 4] = edges_tot[i, 2] - edges_tot[i, 3] + mst_edges = np.zeros(2 * half, dtype=bool) # Array containing the activation variables of selected edges + feasible = False +# %% Main (until line 609 .m file) + while go: + flag1, flag2, flag3, flag4 = True, True, True, True + it += 1 + value_potential_edge, pos_potential_edge = np.min(edges_tot[:, 4]), np.argmin(edges_tot[:, 4]) + if (value_potential_edge > 10**49) or (it == max_it): # Condition to stop if a C-MST cannot be found + # print(it) + # print(value_potential_edge) + break + node1, node2 = edges_tot[pos_potential_edge, 0].astype(int), edges_tot[pos_potential_edge, 1].astype(int) + if (CP[node1 - 1] == CP[node2 - 1]) and (flag1) and (flag2) and (flag3) and (flag4): # Condition for avoiding the creation of loops + flag1 = False # Boolean for loops creation + if pos_potential_edge <= half - 1: # Eliminiating edges which connect the same component + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + # %% Next code is when the potential edge is connected directly to the OSS (node==1) and it does not create loops + if ((node1 == 1) or (node2 == 1)) and (flag1) and (flag2) and (flag3) and (flag4): # Evaluation of the number of nodes in a subtree rooted at 1 + flag2 = False + if node1 == 1: # If the selected edge has a node 1 the OSS + if (S[CP[node2 - 1]] > UL): # Evaluation of the capacity constraint: If true, proceeding to eliminate edges + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + else: # If capacity constraint not violated, then evaluate no-crossing cables constraint + if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree + mst_edges[pos_potential_edge] = True # Add it to the tree. line 88 .m file + # Update node address + address_nodes[node2 - 1] = 1 + C_sliced_n2 = C[CP[node2 - 1]] + for j in range(len(C_sliced_n2)): # This could be replaced without for loop as address_nodes is now an array (before was a list) + if C_sliced_n2[j] == node2: + pass + else: + address_nodes[C_sliced_n2[j] - 1] = node2 + # Update weights and cost functions + if option == 1: + weight[node2 - 1] = 0 + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] + elif option == 2: + pass + elif option == 3: + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + weight[C_sliced_n1[j] - 1] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] + else: + raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 126 .m file + # Eliminating selected edge from edges potential list + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + # Updating auxiliary matrix CP, C, S + u, v = min(node1, node2), max(node1, node2) + C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] + S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components + C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge + old_pos = CP[v - 1] + for j in range(len(C_sliced_v)): # Updating components position for each merged node + CP[C_sliced_v[j] - 1] = CP[u - 1] + for j in range(len(CP)): + if CP[j] > old_pos: + CP[j] -= 1 + del C[old_pos] # Deleting old component + del S[old_pos] # Deleting old component size (line 167 .m file) + else: # If a cable crossing is detected + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + if node2 == 1: # If the selected edge has a node 2 the OSS + if (S[CP[node1 - 1]] > UL): # Evaluation of the capacity constraint: If true, proceeding to eliminate edges + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + else: + if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree + mst_edges[pos_potential_edge] = True # Add it to the tree. line 190 .m file + # Update node address + address_nodes[node1 - 1] = 1 + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + if C_sliced_n1[j] == node1: + pass + else: + address_nodes[C_sliced_n1[j] - 1] = node1 + # Update weights and cost functions + if option == 1: + weight[node2 - 1] = 0 + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] + elif option == 2: + pass + elif option == 3: + # C_sliced_n1=C[CP[node1-1]] + for j in range(len(C_sliced_n1)): + weight[C_sliced_n1[j] - 1] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] + else: + raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 226 .m file + # Eliminating selected edge from edges potential list + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # line 234 .m file + # Updating auxiliary matrix CP, C, S + u, v = min(node1, node2), max(node1, node2) + C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] + S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components + C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge + old_pos = CP[v - 1] + for j in range(len(C_sliced_v)): # Updating components position for each merged node + CP[C_sliced_v[j] - 1] = CP[u - 1] + for j in range(len(CP)): + if CP[j] > old_pos: + CP[j] -= 1 + del C[old_pos] # Deleting old component + del S[old_pos] # Deleting old component size (line 267 .m file) + else: # If a cable crossing is detected + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + # %% Next code is when the potential edge is not connected directly to the OSS (node==1) and it does not create loops. Two cases: One of the components has as element node=1 or none of them. + if (flag1) and (flag2) and (flag3) and (flag4): + if (1 in C[CP[node1 - 1]]) or (1 in C[CP[node2 - 1]]): # One of the components has an element '1' (OSS) + flag3 = False # line 284 .m file + if (1 in C[CP[node1 - 1]]): # The component of node1 includes the root 1 + if address_nodes[node1 - 1] == 1: # The node 1 is connected directly to the OSS (element '1') + tot_nodes = np.where(address_nodes == node1)[0].size + S[CP[node2 - 1]] + 1 + else: # The node 1 is not connected directly to the OSS (element '1') + tot_nodes = np.where(address_nodes == address_nodes[node1 - 1])[0].size + S[CP[node2 - 1]] + 1 + if tot_nodes > UL: # Evaluation of the capacity constraint: If true, proceeding to eliminate edges + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + else: # No violation of capacity constraint + if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree + mst_edges[pos_potential_edge] = True # Add it to the tree. line 301 .m file + # Update node address + if address_nodes[node1 - 1] == 1: + C_sliced_n2 = C[CP[node2 - 1]] + for j in range(len(C_sliced_n2)): + address_nodes[C_sliced_n2[j] - 1] = node1 + else: + C_sliced_n2 = C[CP[node2 - 1]] + for j in range(len(C_sliced_n2)): + address_nodes[C_sliced_n2[j] - 1] = address_nodes[node1 - 1] # line 318 .m file + # Update weights and cost functions + if option == 1: + weight[node2 - 1] = 0 + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] + elif option == 2: + pass + elif option == 3: + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + weight[C_sliced_n1[j] - 1] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] + else: + raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 344 .m file + # Eliminating selected edge from edges potential list + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # line 352 .m file + # Updating auxiliary matrix CP, C, S + u, v = min(node1, node2), max(node1, node2) + C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] + S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components + C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge + old_pos = CP[v - 1] + for j in range(len(C_sliced_v)): # Updating components position for each merged node + CP[C_sliced_v[j] - 1] = CP[u - 1] + for j in range(len(CP)): + if CP[j] > old_pos: + CP[j] -= 1 + del C[old_pos] # Deleting old component + del S[old_pos] # Deleting old component size (line 385 .m file) + else: # If a cable crossing is detected + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # (line 396 .m file) + else: # The component of node2 includes the root 1 + if address_nodes[node2 - 1] == 1: # The node 2 is connected directly to the OSS (element '1') + tot_nodes = np.where(address_nodes == node2)[0].size + S[CP[node1 - 1]] + 1 + else: # The node 2 is not connected directly to the OSS (element '1') + tot_nodes = np.where(address_nodes == address_nodes[node2 - 1])[0].size + S[CP[node1 - 1]] + 1 + if tot_nodes > UL: # Evaluation of the capacity constraint: If true, proceeding to eliminate edges + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + else: # No violation of capacity constraint + if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree + mst_edges[pos_potential_edge] = True # Add it to the tree. line 413 .m file + # Update node address + if address_nodes[node2 - 1] == 1: + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + address_nodes[C_sliced_n1[j] - 1] = node2 + else: + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + address_nodes[C_sliced_n1[j] - 1] = address_nodes[node2 - 1] # line 430 .m file + # Update weights and cost functions + if option == 1: + weight[node2 - 1] = 0 + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] + elif option == 2: + pass + elif option == 3: + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + weight[C_sliced_n1[j] - 1] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] + else: + raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 456 .m file + # Eliminating selected edge from edges potential list + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # line 464 .m file + # Updating auxiliary matrix CP, C, S + u, v = min(node1, node2), max(node1, node2) + C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] + S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components + C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge + old_pos = CP[v - 1] + for j in range(len(C_sliced_v)): # Updating components position for each merged node + CP[C_sliced_v[j] - 1] = CP[u - 1] + for j in range(len(CP)): + if CP[j] > old_pos: + CP[j] -= 1 + del C[old_pos] # Deleting old component + del S[old_pos] # Deleting old component size (line 497 .m file) + else: # If a cable crossing is detected + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 # (line 507 .m file) + else: # Node of the components has as element '1' (OSS) + flag4 = False + if (S[CP[node1 - 1]] + S[CP[node2 - 1]] > UL): # Evaluation of the capacity constraint: If true, proceeding to eliminate edges + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + else: # If no violation of the capacity constraint + if (not(intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const))): # If no cables crossing, add the edge to the tree + mst_edges[pos_potential_edge] = True # Add it to the tree. line 522 .m file + # Update weights and cost functions + if option == 1: + weight[node2 - 1] = 0 + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 4] = edges_tot[np.where(edges_tot[:, 0] == node2)[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == node2)[0], 3] + elif option == 2: + pass + elif option == 3: + C_sliced_n1 = C[CP[node1 - 1]] + for j in range(len(C_sliced_n1)): + weight[C_sliced_n1[j] - 1] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] = weight[node2 - 1] + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 4] = edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 2] -\ + edges_tot[np.where(edges_tot[:, 0] == C_sliced_n1[j])[0], 3] + else: + raise Exception('option should be either 1, 2 or 3 The value of x was: {}'.format(option)) # Weight and cost function updated. line 548 .m file + # Eliminating selected edge from edges potential list + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + # Updating auxiliary matrix CP, C, S + u, v = min(node1, node2), max(node1, node2) + C_sliced_u, C_sliced_v = C[CP[u - 1]], C[CP[v - 1]] + S[CP[u - 1]] = len(C_sliced_u) + len(C_sliced_v) # Updating size of components + C[CP[u - 1]] += C[CP[v - 1]] # Merging two lists due to component's merge + old_pos = CP[v - 1] + for j in range(len(C_sliced_v)): # Updating components position for each merged node + CP[C_sliced_v[j] - 1] = CP[u - 1] + for j in range(len(CP)): + if CP[j] > old_pos: + CP[j] -= 1 + del C[old_pos] # Deleting old component + del S[old_pos] # Deleting old component size (line 590 .m file) + else: # If a cable crossing is detected + if pos_potential_edge <= half - 1: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge + half, 4] = edges_tot[pos_potential_edge + half, 2] + 10**50 + else: + edges_tot[pos_potential_edge, 4] = edges_tot[pos_potential_edge, 2] + 10**50 + edges_tot[pos_potential_edge - half, 4] = edges_tot[pos_potential_edge - half, 2] + 10**50 + if len(C) == 1: + go = False # (line 606 .m file) + feasible = True + T = np.zeros((len(np.where(mst_edges)[0]), 3)) + T[:, 0] = edges_tot[np.where(mst_edges)[0], 0] + T[:, 1] = edges_tot[np.where(mst_edges)[0], 1] + T[:, 2] = edges_tot[np.where(mst_edges)[0], 2] +# %% Running the function + return T, feasible + + +if __name__ == "__main__": + # First X,Y are for artifitial wind farm Diagonal 10 (10 WTs + 1 OSS) + X = [10000, 8285.86867841725, 9097.62726321941, 8736.91009361509, 9548.66867841725, 10360.4272632194, 9187.95150881294, 9999.71009361510, 10811.4686784173, 10450.7515088129, 11262.5100936151] + Y = [10000, 9426, 8278, 10574, 9426, 8278, 11722, 10574, 9426, 11722, 10574] + # Next X,Y are for real-world wind farm Ormonde (30 WTs + 1 OSS) + # X=[473095,471790,471394,470998,470602,470207,469811,472523,469415,472132,471742,471351,470960,470569,470179,469788,472866,472480,472094,471708,471322,470937,470551,473594,473213,472833,472452,472071,471691,471310,470929] + # Y=[5992345,5991544,5991899,5992252,5992607,5992960,5993315,5991874,5993668,5992236,5992598,5992960,5993322,5993684,5994047,5994409,5992565,5992935,5993306,5993675,5994045,5994416,5994786,5992885,5993264,5993643,5994021,5994400,5994779,5995156,5995535] + # Next X, Y are for real-world wind farm DanTysk (80 WTs + 1 OSS) + # X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300] + # Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000] + X = np.array(X) + Y = np.array(Y) + option = 3 + UL = 15 + Inters_const = True + T, feasible = capacitated_spanning_tree(X, Y, option, UL, Inters_const) + + print("The total length of the solution is {value:.2f} m".format(value=sum(T[:, 2]))) + print("Feasibility: {feasible1}".format(feasible1=feasible)) + plt.figure() + plt.plot(X[1:], Y[1:], 'r+', markersize=10, label='Turbines') + plt.plot(X[0], Y[0], 'ro', markersize=10, label='OSS') + for i in range(len(X)): + plt.text(X[i] + 50, Y[i] + 50, str(i + 1)) + n1xs = X[T[:, 0].astype(int) - 1].ravel().T + n2xs = X[T[:, 1].astype(int) - 1].ravel().T + n1ys = Y[T[:, 0].astype(int) - 1].ravel().T + n2ys = Y[T[:, 1].astype(int) - 1].ravel().T + xs = np.vstack([n1xs, n2xs]) + ys = np.vstack([n1ys, n2ys]) + plt.plot(xs, ys, 'b') + plt.legend() diff --git a/edwin/c_mst_cables.py b/ed_win/c_mst_cables.py similarity index 97% rename from edwin/c_mst_cables.py rename to ed_win/c_mst_cables.py index a34aa34a7c0701ab267581e68c5eb36a917342bd..461b2081146776873f3d487ea85b31fd13623d3c 100644 --- a/edwin/c_mst_cables.py +++ b/ed_win/c_mst_cables.py @@ -9,7 +9,7 @@ import numpy as np import networkx as nx import matplotlib.pyplot as plt import time -from edwin.c_mst import capacitated_spanning_tree +from ed_win.c_mst import capacitated_spanning_tree def cmst_cables(X=[], Y=[], T=[], Cables=[], plot=False): diff --git a/edwin/collection_system.py b/ed_win/collection_system.py similarity index 95% rename from edwin/collection_system.py rename to ed_win/collection_system.py index ee309855dcfd0e2c2899f4faf898928dc8c98045..801c33295623e47a5dc6f78878cd16982efc7026 100644 --- a/edwin/collection_system.py +++ b/ed_win/collection_system.py @@ -1,48 +1,48 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Jun 22 10:59:47 2020 - -@author: juru -""" -import numpy as np -from edwin.c_mst import capacitated_spanning_tree -from edwin.c_mst_cables import cmst_cables - - -def collection_system(X=[], Y=[], option=3, Inters_const=True, max_it=20000, Cables=[], plot=False): - UL = max(Cables[:, 1]) - T, feasible = capacitated_spanning_tree(X, Y, option, UL, Inters_const) - T_cables_cost = ((T[:, -1].sum()) / 1000) * Cables[-1, 2] - T_cables = np.concatenate((T, np.full((T.shape[0], 2), Cables.shape[1] - 1)), axis=1) - if feasible: - T_cables = cmst_cables(X, Y, T, Cables, plot) - T_cables_cost = T_cables[:, -1].sum() - return T_cables, T_cables_cost - - -if __name__ == "__main__": - # X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300] - # Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000] - # X=np.array(X) - # Y=np.array(Y) - 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]) - - option = 3 - # UL=5 - Inters_const = True - Cables = np.array([[500, 3, 100000], [800, 5, 150000], [1000, 10, 250000]]) - - T, amount = collection_system(X, Y, option, Inters_const, Cables=Cables, plot=True) +# -*- coding: utf-8 -*- +""" +Created on Mon Jun 22 10:59:47 2020 + +@author: juru +""" +import numpy as np +from ed_win.c_mst import capacitated_spanning_tree +from ed_win.c_mst_cables import cmst_cables + + +def collection_system(X=[], Y=[], option=3, Inters_const=True, max_it=20000, Cables=[], plot=False): + UL = max(Cables[:, 1]) + T, feasible = capacitated_spanning_tree(X, Y, option, UL, Inters_const) + T_cables_cost = ((T[:, -1].sum()) / 1000) * Cables[-1, 2] + T_cables = np.concatenate((T, np.full((T.shape[0], 2), Cables.shape[1] - 1)), axis=1) + if feasible: + T_cables = cmst_cables(X, Y, T, Cables, plot) + T_cables_cost = T_cables[:, -1].sum() + return T_cables, T_cables_cost + + +if __name__ == "__main__": + # X=[387100,383400,383400,383900,383200,383200,383200,383200,383200,383200,383200,383200,383300,384200,384200,384100,384000,383800,383700,383600,383500,383400,383600,384600,385400,386000,386100,386200,386300,386500,386600,386700,386800,386900,387000,387100,387200,383900,387400,387500,387600,387800,387900,388000,387600,386800,385900,385000,384100,384500,384800,385000,385100,385200,385400,385500,385700,385800,385900,385900,385500,385500,386000,386200,386200,384500,386200,386700,386700,386700,384300,384400,384500,384600,384300,384700,384700,384700,385500,384300,384300] + # Y=[6109500,6103800,6104700,6105500,6106700,6107800,6108600,6109500,6110500,6111500,6112400,6113400,6114000,6114200,6115100,6115900,6116700,6118400,6119200,6120000,6120800,6121800,6122400,6122000,6121700,6121000,6120000,6119100,6118100,6117200,6116200,6115300,6114300,6113400,6112400,6111500,6110700,6117600,6108900,6108100,6107400,6106300,6105200,6104400,6103600,6103600,6103500,6103400,6103400,6104400,6120400,6119500,6118400,6117400,6116500,6115500,6114600,6113500,6112500,6111500,6105400,6104200,6110400,6109400,6108400,6121300,6107500,6106400,6105300,6104400,6113300,6112500,6111600,6110800,6110100,6109200,6108400,6107600,6106500,6106600,6105000] + # X=np.array(X) + # Y=np.array(Y) + 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]) + + option = 3 + # UL=5 + Inters_const = True + Cables = np.array([[500, 3, 100000], [800, 5, 150000], [1000, 10, 250000]]) + + T, amount = collection_system(X, Y, option, Inters_const, Cables=Cables, plot=True) diff --git a/edwin/intersection_checker.py b/ed_win/intersection_checker.py similarity index 92% rename from edwin/intersection_checker.py rename to ed_win/intersection_checker.py index 54adefa5ca25016a1ccdba806e1768f54707ef50..2e25a58b1a58346d4187887e45286a5eb6e8948e 100644 --- a/edwin/intersection_checker.py +++ b/ed_win/intersection_checker.py @@ -1,31 +1,31 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri May 29 10:08:54 2020 - -@author: juru -""" - -import numpy as np -from edwin.two_lines_intersecting import two_lines_intersecting - - -def intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const): - current_edges = np.where(mst_edges)[0] - current_edges_size = current_edges.size - intersection = False - if Inters_const: - if current_edges_size == 0: - pass - else: - for i in range(current_edges_size): - line1 = np.array([[X[edges_tot[pos_potential_edge, 0].astype(int) - 1], Y[edges_tot[pos_potential_edge, 0].astype(int) - 1]], - [X[edges_tot[pos_potential_edge, 1].astype(int) - 1], Y[edges_tot[pos_potential_edge, 1].astype(int) - 1]]]) - line2 = np.array([[X[edges_tot[current_edges[i], 0].astype(int) - 1], Y[edges_tot[current_edges[i], 0].astype(int) - 1]], - [X[edges_tot[current_edges[i], 1].astype(int) - 1], Y[edges_tot[current_edges[i], 1].astype(int) - 1]]]) - if two_lines_intersecting(line1, line2): - intersection = True - break - return intersection - -# if __name__ == '__main__': - # cross=intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y) +# -*- coding: utf-8 -*- +""" +Created on Fri May 29 10:08:54 2020 + +@author: juru +""" + +import numpy as np +from ed_win.two_lines_intersecting import two_lines_intersecting + + +def intersection_checker(pos_potential_edge, edges_tot, mst_edges, X, Y, Inters_const): + current_edges = np.where(mst_edges)[0] + current_edges_size = current_edges.size + intersection = False + if Inters_const: + if current_edges_size == 0: + pass + else: + for i in range(current_edges_size): + line1 = np.array([[X[edges_tot[pos_potential_edge, 0].astype(int) - 1], Y[edges_tot[pos_potential_edge, 0].astype(int) - 1]], + [X[edges_tot[pos_potential_edge, 1].astype(int) - 1], Y[edges_tot[pos_potential_edge, 1].astype(int) - 1]]]) + line2 = np.array([[X[edges_tot[current_edges[i], 0].astype(int) - 1], Y[edges_tot[current_edges[i], 0].astype(int) - 1]], + [X[edges_tot[current_edges[i], 1].astype(int) - 1], Y[edges_tot[current_edges[i], 1].astype(int) - 1]]]) + if two_lines_intersecting(line1, line2): + intersection = True + break + return intersection + +# if __name__ == '__main__': + # cross=intersection_checker(pos_potential_edge,edges_tot,mst_edges,X,Y) diff --git a/edwin/tests/__init__.py b/ed_win/tests/__init__.py similarity index 100% rename from edwin/tests/__init__.py rename to ed_win/tests/__init__.py diff --git a/ed_win/tests/__pycache__/__init__.cpython-39.pyc b/ed_win/tests/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc1e7fdf4ee8a9106ca57d916cbdf9a610644874 Binary files /dev/null and b/ed_win/tests/__pycache__/__init__.cpython-39.pyc differ 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 new file mode 100644 index 0000000000000000000000000000000000000000..a5318aa33695c99f0edc297875fb7ea7ee1942de Binary files /dev/null and b/ed_win/tests/__pycache__/test_wind_farm_network.cpython-39-pytest-6.2.4.pyc differ diff --git a/edwin/tests/test_wind_farm_network.py b/ed_win/tests/test_wind_farm_network.py similarity index 98% rename from edwin/tests/test_wind_farm_network.py rename to ed_win/tests/test_wind_farm_network.py index ce4a2e614343bdba21b78572c388df14c517202a..53e92952b46c36c60f4e393fef701950e73d2ddb 100644 --- a/edwin/tests/test_wind_farm_network.py +++ b/ed_win/tests/test_wind_farm_network.py @@ -1,5 +1,5 @@ import numpy as np -from edwin.wind_farm_network import WindFarmNetwork, HeuristicDriver +from ed_win.wind_farm_network import WindFarmNetwork, HeuristicDriver import numpy.testing as npt initial_layout = dict(x=np.array([0., 2000., 4000., 6000., diff --git a/edwin/two_lines_intersecting.py b/ed_win/two_lines_intersecting.py similarity index 100% rename from edwin/two_lines_intersecting.py rename to ed_win/two_lines_intersecting.py diff --git a/edwin/wind_farm_network.py b/ed_win/wind_farm_network.py similarity index 96% rename from edwin/wind_farm_network.py rename to ed_win/wind_farm_network.py index 2ad44abe68f24c0a77d7b0dd978bb448af05d852..99038b8b4b9e28618c3aa3337e2ae74d0f8e477a 100644 --- a/edwin/wind_farm_network.py +++ b/ed_win/wind_farm_network.py @@ -1,6 +1,6 @@ from abc import ABC, abstractmethod -from edwin.collection_system import collection_system -from edwin.c_mst_cables import plot_network +from ed_win.collection_system import collection_system +from ed_win.c_mst_cables import plot_network import pandas as pd import numpy as np @@ -61,7 +61,7 @@ class WindFarmNetwork(): return cost, state def plot(self): - if self.state is not None: + if self.state is None: self.design() plot_network(self.x, self.y, self.cables, self.T) diff --git a/ed_win/wind_farm_network.py.bak b/ed_win/wind_farm_network.py.bak new file mode 100644 index 0000000000000000000000000000000000000000..b264f6b3fb7501a14e900ccd1f93a29a0c09a1fa --- /dev/null +++ b/ed_win/wind_farm_network.py.bak @@ -0,0 +1,110 @@ +from abc import ABC, abstractmethod +from edwin.collection_system import collection_system +from edwin.c_mst_cables import plot_network +import pandas as pd +import numpy as np + + +class Driver(ABC): + @abstractmethod + def run(): + ''' + + ''' + + +class HeuristicDriver(Driver): + def __init__(self, option=3, Inters_const=True, max_it=20000): + self.option = option + self.Inters_const = Inters_const + self.max_it = max_it + Driver.__init__(self) + + def run(self, x, y): + T, cables_cost = collection_system(x, + y, + self.option, + self.Inters_const, + self.max_it, + self.wfn.cables) + return T, cables_cost + + +class WindFarmNetwork(): + def __init__(self, initial_layout, driver=HeuristicDriver(), cables=[]): + self.initial_layout = initial_layout + self.driver = driver + self.cables = cables + self.state = None + self.T = None + self.columns = ['from_node', 'to_node', 'cable_length', 'cable_type', 'cable_cost'] + self.setup() + + def setup(self): + setattr(self.driver, 'wfn', self) + + def design(self, x=None, y=None, **kwargs): +<<<<<<< HEAD + x = x or self.initial_layout['x'] + y = y or self.initial_layout['y'] +======= + if isinstance(x, type(None)): + x = self.initial_layout['x'] + if isinstance(y, type(None)): + y = self.initial_layout['y'] +>>>>>>> upd + 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 + + def plot(self): + if self.state is not None: + self.design() + plot_network(self.x, self.y, self.cables, self.T) + + +class Constraints(dict): + def __init__(self, **kwargs): + dict.__init__(self, {'crossing': False, + 'tree': False, + 'thermal_capacity': False, + 'number_of_main_feeders': False}) + self.update(kwargs) + + +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])) + 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), + cables=cables) + cost, state = wfn.design() + wfn.plot() + + +main() diff --git a/setup.py b/setup.py index a51e0c92028d4903dc7493a08fcf647642f1dca8..aa18686762a9e413e2c8ed6ad05917927552cd11 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ import pkg_resources repo = os.path.dirname(__file__) try: from git_utils import write_vers - version = write_vers(vers_file='edwin/__init__.py', repo=repo, skip_chars=1) + version = write_vers(vers_file='ed_win/__init__.py', repo=repo, skip_chars=1) except Exception: version = '999' @@ -24,11 +24,11 @@ except ImportError: def read_md(f): return open(f, 'r').read() -setup(name='edwin', +setup(name='ed_win', version=version, description='EDWIN an optimization and design package for electrical networks in windfarms', long_description=read_md('README.md'), - url='https://gitlab.windenergy.dtu.dk/TOPFARM/edwin', + url='https://gitlab.windenergy.dtu.dk/TOPFARM/EDWIN', author='DTU Wind Energy', author_email='juru@dtu.dk', license='MIT',