{ "cells": [ { "cell_type": "markdown", "id": "87017013-6aed-47ae-87cb-12980d706950", "metadata": {}, "source": [ "## Network Topologies" ] }, { "cell_type": "markdown", "id": "5dab12ae-ae0c-4579-b745-fd63b9c16d3b", "metadata": {}, "source": [ "OptiWindNet supports three electrical topologies:\n", "\n", "- **Branched:** a forest of rooted trees; terminals may have any number of neighbors.\n", "- **Radial:** a collection of root-to-leaf paths; each terminal has at most two neighbors.\n", "- **Ringed:** a collection of cyclic paths (multi-terminal *\"loops\"*), each including one or two roots (roots are implicitly neighboring each other). Only roots may belong to more than one path. Each terminal has exactly two neighbors. Single-terminal cycles degenerate to a single link. Each cycle has a link with `load=0` which splits the ring at its mid-point. `capacity` is the feeder limit of the split ring, so a ring can hold up to `2 * capacity` terminals." ] }, { "cell_type": "markdown", "id": "78131fa5-0800-4b00-aaf7-f29fb9312bae", "metadata": {}, "source": [ "> Attention: The term **topology** is also used to refer to the solution topology `S`. In the latter context, it means that S is just the connection-level network representation, not including the geometric details of the cable routes." ] }, { "cell_type": "markdown", "id": "d1c8b019-1ab9-4ec0-8fc0-9faea3f2d14a", "metadata": {}, "source": [ "### Topologies, routesets, and validation\n", "\n", "A topology `S` describes the electrical parent–child relations. `G_from_S(S, A)` gives the corresponding tentative physical graph. A routeset is the graph after routing, e.g. with `PathFinder(...).create_detours()`.\n", "\n", "When working with the advanced API, validate each representation at the boundary where it is created. `describe_G()` provides a compact diagnostic summary that is useful alongside a plot." ] }, { "cell_type": "code", "execution_count": 1, "id": "595796df", "metadata": {}, "outputs": [], "source": [ "from optiwindnet.importer import load_repository\n", "from optiwindnet.mesh import make_planar_embedding\n", "from optiwindnet.svg import svgplot\n", "from optiwindnet.heuristics import constructor\n", "from optiwindnet.MILP import ModelOptions, solver_factory\n", "from optiwindnet.interarraylib import describe_G, validate_routeset, validate_topology" ] }, { "cell_type": "code", "execution_count": 2, "id": "a788fbe7", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "locations = load_repository()\n", "L = locations.kaskasi\n", "P, A = make_planar_embedding(L)\n", "capacity = 5\n", "svgplot(L)" ] }, { "cell_type": "code", "execution_count": 3, "id": "cb61db9f-7f63-4773-930f-1b2e4959c31b", "metadata": {}, "outputs": [], "source": [ "solver = solver_factory('highs')" ] }, { "cell_type": "markdown", "id": "4f8da320-482c-491a-918b-df564948bcb4", "metadata": {}, "source": [ "### The three topology types" ] }, { "cell_type": "markdown", "id": "a8b266ac", "metadata": {}, "source": [ "The following cell is deliberately shared by the solver examples below: it plots the tentative physical graph corresponding to each topology. The link geometry is still direct at this stage." ] }, { "cell_type": "markdown", "id": "2954bc2b-8a1b-49c6-8b10-abd04d8fea0d", "metadata": {}, "source": [ "### Warm-starts" ] }, { "cell_type": "markdown", "id": "78d38e88", "metadata": {}, "source": [ "`constructor()` can generate warmstarts for all three topology types through `method`." ] }, { "cell_type": "code", "execution_count": 4, "id": "d0c4da1a-bccd-4311-8a69-d672435a7fab", "metadata": {}, "outputs": [], "source": [ "S_branched = constructor(A, capacity=capacity, method='rootlust')" ] }, { "cell_type": "code", "execution_count": 5, "id": "7ef2bdff-eaa8-4fde-8334-124af20d91c6", "metadata": {}, "outputs": [], "source": [ "S_radial = constructor(A, capacity=capacity, method='radial_EW')" ] }, { "cell_type": "code", "execution_count": 6, "id": "94a65099-fea5-4863-84e7-24272e889b40", "metadata": {}, "outputs": [], "source": [ "S_ring = constructor(A, capacity=capacity, method='ringed')" ] }, { "cell_type": "markdown", "id": "7393b416-587e-4613-ba06-8a254a201405", "metadata": {}, "source": [ "Function `validate_topology()` may be used to check if a solution is feasible from the electrical perspective." ] }, { "cell_type": "code", "execution_count": 7, "id": "053bae7e-76ad-45c3-bdb9-eb59fd0f1449", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "validate_topology(S_ring)" ] }, { "cell_type": "markdown", "id": "6cbb251d-3317-4896-a451-f5a3b75c80a5", "metadata": {}, "source": [ "### Branched" ] }, { "cell_type": "code", "execution_count": 8, "id": "8b0c4ef9-1853-4d0c-a7c1-b9c7ed5bf7cc", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SolutionInfo(runtime=30.010845184326172, bound=36688.03385242913, objective=37816.911975099436, relgap=0.029851144996017043, termination='maxTimeLimit')" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# branched\n", "solver.set_problem(P, A, capacity, model_options=ModelOptions(), warmstart=S_branched)\n", "solver.solve(time_limit=30, mip_gap=1e-3)" ] }, { "cell_type": "code", "execution_count": 9, "id": "510984e5-3e4d-420b-a386-ed8dfd5917ce", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 38 119 m(+0) OSS: 8κ = 5, T = 38" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S, G = solver.get_solution()\n", "svgplot(G)" ] }, { "cell_type": "markdown", "id": "ca4ca27f-3fcc-4c46-903c-951fcdb7aa42", "metadata": {}, "source": [ "### Radial" ] }, { "cell_type": "code", "execution_count": 10, "id": "77399c22-27f1-462c-8139-a38103190f08", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SolutionInfo(runtime=30.016808032989502, bound=37060.99661553814, objective=37911.327005923136, relgap=0.022429454665412907, termination='maxTimeLimit')" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# radial\n", "solver.set_problem(P, A, capacity, model_options=ModelOptions(topology='radial'), warmstart=S_radial)\n", "solver.solve(time_limit=30, mip_gap=1e-3)" ] }, { "cell_type": "code", "execution_count": 11, "id": "7e737799-01f0-4969-8123-893eded29129", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 38 208 m(+0) OSS: 8κ = 5, T = 38" ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S, G = solver.get_solution()\n", "svgplot(G)" ] }, { "cell_type": "markdown", "id": "4dee7304-49c3-45c6-aecf-effd8b6ee41a", "metadata": {}, "source": [ "### Ringed" ] }, { "cell_type": "code", "execution_count": 12, "id": "5ae509ba-67bd-47a8-ad8b-8a244011a05b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "SolutionInfo(runtime=60.01727795600891, bound=39898.47982086679, objective=42992.10955420628, relgap=0.07195808173681062, termination='maxTimeLimit')" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# ringed\n", "solver.set_problem(P, A, capacity, model_options=ModelOptions(topology='ringed'), warmstart=S_ring)\n", "solver.solve(time_limit=60, mip_gap=1e-3)" ] }, { "cell_type": "code", "execution_count": 13, "id": "98d4ff2e-9443-4c5f-8576-5cb9ada67388", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 42 788 m(+1) OSS: 9κ = 5, T = 38" ], "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "S, G = solver.get_solution()\n", "svgplot(G)" ] }, { "cell_type": "markdown", "id": "e5c88d52-7578-4cd1-b0f4-f8d4bd25d776", "metadata": {}, "source": [ "Function `validate_routeset()` may be used to check if a routeset is correct (it calls `validate_topology()` internally)." ] }, { "cell_type": "code", "execution_count": 14, "id": "ee3ad692-3206-4a7e-9359-23d35c668432", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "validate_routeset(G)" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }