{
"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": [
""
],
"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": [
""
],
"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": [
""
],
"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
}