{ "cells": [ { "cell_type": "markdown", "id": "08f22ef2", "metadata": {}, "source": [ "# A Large and Complex Wind Farm" ] }, { "cell_type": "markdown", "id": "3da71e0a-3861-4a7c-8eaa-de84bce11338", "metadata": {}, "source": [ "This notebook demonstrates how to apply *OptiWindNet* to optimize electrical network (cable routing) for a large-scale wind farm with 122 turbines and 2 substations, set in a concave area containing an internal obstacle. We will use `EWRouter` for warm-starting, then run `MILPRouter` with the COIN-OR CBC solver to find a high-quality branched cable network. The process covers loading real-world location data, generating and visualizing warm-start solutions, configuring solver and model options, and plotting the final optimized network.\n", "\n", "\n", "> Note: Any additional geometric complexity will have negligible impact on solving time, as they do not increase the number of variables in the MILP optimization model.\n", "\n", "> This notebook uses *COIN-OR CBC* as solver, but examples for other solvers (*gurobi, cplex, ortools, scip, highs*) can be found in the *MILPRouter* notebooks. Gurobi and IBM ILOG CPLEX are comercial solvers (academic license available). Google's OR-Tools, COIN-OR CBC, SCIP and HiGHS are open-source software." ] }, { "cell_type": "code", "execution_count": 1, "id": "a1ae5f35-904c-48de-a19a-4be303e46327", "metadata": {}, "outputs": [], "source": [ "from optiwindnet.api import WindFarmNetwork, EWRouter, MILPRouter, ModelOptions, load_repository" ] }, { "cell_type": "markdown", "id": "c37992fa-ecd0-4eec-9485-01c721213b72", "metadata": {}, "source": [ "## Load input data\n", "\n", "> Note: the `load_repository()` functionality of *OptiWindNet* is used to load a prebuilt *Networkx.Graph* of the avaible locations. For more details on this functionality look into the notebook about [Load repositories containing location data](a03_load_repositories.ipynb)." ] }, { "cell_type": "code", "execution_count": 2, "id": "9e47e5ac-661d-4084-ba6b-157aebe72cd8", "metadata": {}, "outputs": [], "source": [ "locations = load_repository()" ] }, { "cell_type": "markdown", "id": "13a15e55-d94a-4af3-a2a2-a400367f926f", "metadata": {}, "source": [ "The example location from (Taylor_2023) provides suitable specifications for our purpose; a large wind farm with multiple substations and complex geometry." ] }, { "cell_type": "code", "execution_count": 3, "id": "e8f1b4f3", "metadata": {}, "outputs": [], "source": [ "wfn = WindFarmNetwork(\n", " L=locations.taylor_2023,\n", " cables=[(5, 1800.0), (8, 2200.0)],\n", ")" ] }, { "cell_type": "markdown", "id": "d3eaf120", "metadata": {}, "source": [ "> Note: To view output plots, trust this notebook first." ] }, { "cell_type": "code", "execution_count": 4, "id": "c3576c4e", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn" ] }, { "cell_type": "markdown", "id": "cbe51c02", "metadata": {}, "source": [ "There are two options for generating an initial solution to warm-start the `MILPRouter`:\n", "- heuristic: `EWRouter()`\n", "- meta-heuristic: `HGSRouter()`\n", "\n", "`EWRouter` has the downside of not limiting the number of feeders, thus the model to be warm-started must also have an unlimited number of feeders. This is usually not a problem, as most cable route sets produced by the `MILPRouter` uses the minimum number of feeders or only one more than the minimum." ] }, { "cell_type": "markdown", "id": "9bb10ad9", "metadata": {}, "source": [ "## Generate the warm-start solution" ] }, { "cell_type": "markdown", "id": "59c0d61e-4daf-44f3-af91-f096952f07ab", "metadata": {}, "source": [ "To generate a warm-start solution, simply run `wfn.optimize()` with the desired solver e.g.:\n", "\n", "```python\n", "wfn.optimize(router=warmstart_router)\n", "```\n", "\n", "In this example, we use `EWRouter` to warm-start the optimization model. Alternatively, `HGSRouter()` can be used for the same purpose.\n", "\n", "The resulting solution is stored within the `wfn` object. The next time `wfn.optimize()` is called, the stored solution (`S` which contains *selected-links*) will be reused as a warm start; provided that the solver in `MILPRouter` supports warm-starting.\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "afb280cc", "metadata": {}, "outputs": [], "source": [ "warmstart_router = EWRouter()\n", "res_warmstart= wfn.optimize(router=warmstart_router)" ] }, { "cell_type": "code", "execution_count": 6, "id": "b0048736", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "113112.15297348917" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.length()" ] }, { "cell_type": "markdown", "id": "cff4d530-ff92-483f-9a65-43bc6c89f08c", "metadata": {}, "source": [ "### Visualizing the warm-start solution" ] }, { "cell_type": "markdown", "id": "81de3bb0", "metadata": {}, "source": [ "`S` can be visualized using `wfn.plot_selected_links()`.\n", "\n", "> Check [the plotting tutorial](a04_Plotting.ipynb) for details on the available plots." ] }, { "cell_type": "code", "execution_count": 7, "id": "29fc5b50", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "216 613 758 €Σλ = 113 112 m(+3) [-1]: 9, [-2]: 10κ = 8, T = 122" ], "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn" ] }, { "cell_type": "markdown", "id": "5f88cdac", "metadata": {}, "source": [ "## MILP Router" ] }, { "cell_type": "markdown", "id": "966e3317", "metadata": {}, "source": [ "Create an instance of `MILPRouter` and choose COIN-OR Branch and Cut (CBC) as solver." ] }, { "cell_type": "markdown", "id": "708a88ce", "metadata": {}, "source": [ "When initializing a `MILPRouter` three arguments are required to be given:\n", "- solver name\n", "- time limit\n", "- gap" ] }, { "cell_type": "markdown", "id": "79b7673d", "metadata": {}, "source": [ "Solver options, including those set by OptiWindNet as well as additional configurable parameters, can be modified by creating a **dictionary** and passing it to the router. The same approach applies to **model options**. For a detailed explanation about model_options and solver_options of MILP routers see the notebook about [ModelOptions vs SolverOptions](a08_ModelOptions.ipynb)." ] }, { "cell_type": "code", "execution_count": 8, "id": "5c277e03", "metadata": {}, "outputs": [], "source": [ "solver_options=dict( # these are in addition to the default solver.options\n", " # if repeatable results are desired, set the seed\n", " RandomCbcSeed=1234567,\n", " # CBC works better if the number threads is set to the number of physical cores\n", " threads=6,\n", ")\n", "\n", "model_options = ModelOptions(\n", " topology='branched',\n", " feeder_limit='unlimited',\n", " feeder_route='segmented',\n", ")\n", "\n", "milp_router = MILPRouter(\n", " solver_name='cbc',\n", " time_limit=60,\n", " mip_gap=0.005,\n", " solver_options=solver_options,\n", " model_options=model_options,\n", ")" ] }, { "cell_type": "markdown", "id": "eda1ab2b", "metadata": {}, "source": [ "### Run optimization with MILP router" ] }, { "cell_type": "code", "execution_count": 9, "id": "8783cc8f", "metadata": { "scrolled": true }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:optiwindnet.MILP.pyomo:>>> pyomo.cbc solver options <<<\n", "Dins: 'on'\n", "RandomCbcSeed: 1234567\n", "Rens: 'on'\n", "Rins: 'on'\n", "VndVariableNeighborhoodSearch: 'on'\n", "cliqueCuts: 'off'\n", "flowCoverCuts: 'on'\n", "gomoryCuts: 'on'\n", "knapsackCuts: 'off'\n", "liftAndProjectCuts: 'off'\n", "mixedIntegerRoundingCuts: 'on'\n", "nodeStrategy: 'downFewest'\n", "pivotAndComplement: 'off'\n", "probingCuts: 'off'\n", "proximitySearch: 'off'\n", "ratioGap: 0.005\n", "residualCapacityCuts: 'off'\n", "seconds: 60\n", "threads: 6\n", "timeMode: 'elapsed'\n", "twoMirCuts: 'off'\n", "zeroHalfCuts: 'off'\n", "\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Welcome to the CBC MILP Solver \n", "Version: 2.10.12 \n", "Build Date: Sep 17 2024 \n", "\n", "command line - /usr/bin/cbc -threads 6 -timeMode elapsed -nodeStrategy downFewest -Dins on -VndVariableNeighborhoodSearch on -Rens on -Rins on -pivotAndComplement off -proximitySearch off -gomoryCuts on -mixedIntegerRoundingCuts on -flowCoverCuts on -cliqueCuts off -twoMirCuts off -knapsackCuts off -probingCuts off -zeroHalfCuts off -liftAndProjectCuts off -residualCapacityCuts off -RandomCbcSeed 1234567 -seconds 60 -ratioGap 0.005 -printingOptions all -import /tmp/tmpocvlmv_7.pyomo.lp -mipstart /tmp/tmp3cvhc7ga.cbc.soln -stat=1 -solve -solu /tmp/tmpocvlmv_7.pyomo.soln (default strategy 1)\n", "threads was changed from 0 to 6\n", "Option for timeMode changed from cpu to elapsed\n", "Option for nodeStrategy changed from fewest to downfewest\n", "Option for Dins changed from off to on\n", "Option for VndVariableNeighborhoodSearch changed from off to on\n", "Option for Rens changed from off to on\n", "Option for gomoryCuts changed from ifmove to on\n", "Option for mixedIntegerRoundingCuts changed from ifmove to on\n", "Option for flowCoverCuts changed from ifmove to on\n", "Option for cliqueCuts changed from ifmove to off\n", "Option for twoMirCuts changed from root to off\n", "Option for knapsackCuts changed from ifmove to off\n", "Option for probingCuts changed from on to off\n", "Option for zeroHalfCuts changed from ifmove to off\n", "randomCbcSeed was changed from -1 to 1234567\n", "seconds was changed from 1e+100 to 60\n", "ratioGap was changed from 0 to 0.005\n", "Option for printingOptions changed from normal to all\n", "opening mipstart file /tmp/tmp3cvhc7ga.cbc.soln.\n", "MIPStart values read for 244 variables.\n", "Presolve 4314 (-2) rows, 2891 (-1) columns and 14858 (-1442) elements\n", "Statistics for presolved model\n", "Original problem has 2892 integers (1446 of which binary)\n", "Presolved problem has 2891 integers (1445 of which binary)\n", "==== 1446 zero objective 840 different\n", "==== absolute objective values 840 different\n", "==== for integers 1446 zero objective 840 different\n", "==== for integers absolute objective values 840 different\n", "===== end objective counts\n", "\n", "\n", "Problem has 4314 rows, 2891 columns (1445 with objective) and 14858 elements\n", "Column breakdown:\n", "0 of type 0.0->inf, 1446 of type 0.0->up, 0 of type lo->inf, \n", "0 of type lo->up, 0 of type free, 0 of type fixed, \n", "0 of type -inf->0.0, 0 of type -inf->up, 1445 of type 0.0->1.0 \n", "Row breakdown:\n", "0 of type E 0.0, 243 of type E 1.0, 0 of type E -1.0, \n", "1 of type E other, 0 of type G 0.0, 0 of type G 1.0, \n", "1 of type G other, 2891 of type L 0.0, 1054 of type L 1.0, \n", "124 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other, \n", "0 of type Free \n", "Continuous objective value is 104281 - 0.49 seconds\n", "Cgl0003I 0 fixed, 0 tightened bounds, 528 strengthened rows, 0 substitutions\n", "Cgl0003I 0 fixed, 0 tightened bounds, 528 strengthened rows, 0 substitutions\n", "Cgl0003I 0 fixed, 0 tightened bounds, 202 strengthened rows, 0 substitutions\n", "Cgl0003I 0 fixed, 0 tightened bounds, 121 strengthened rows, 0 substitutions\n", "Cgl0004I processed model has 3881 rows, 2892 columns (2892 integer (1446 of which binary)) and 15680 elements\n", "Cbc0045I MIPStart provided solution with cost 113017\n", "Cbc0012I Integer solution of 113017.26 found by Reduced search after 0 iterations and 0 nodes (0.22 seconds)\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 255 rows 151 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 255 rows 151 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 255 rows 151 columns\n", "Cbc0038I Full problem 3881 rows 2892 columns, reduced to 405 rows 226 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 292 rows 181 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 292 rows 181 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 292 rows 181 columns\n", "Cbc0031I 88 added rows had average density of 88.568182\n", "Cbc0013I At root node, 88 cuts changed objective from 104281.43 to 104895.91 in 19 passes\n", "Cbc0014I Cut generator 0 (Gomory) - 230 row cuts average 346.8 elements, 0 column cuts (0 active) in 0.309 seconds - new frequency is 1\n", "Cbc0014I Cut generator 1 (MixedIntegerRounding2) - 2 row cuts average 356.0 elements, 0 column cuts (0 active) in 0.043 seconds - new frequency is 3\n", "Cbc0014I Cut generator 2 (FlowCover) - 163 row cuts average 16.7 elements, 0 column cuts (0 active) in 0.024 seconds - new frequency is 1\n", "Cbc0010I After 0 nodes, 1 on tree, 113017.26 best solution, best possible 104895.91 (1.27 seconds)\n", "Cbc0010I After 100 nodes, 56 on tree, 113017.26 best solution, best possible 104952.14 (4.87 seconds)\n", "Cbc0010I After 200 nodes, 108 on tree, 113017.26 best solution, best possible 104952.14 (6.10 seconds)\n", "Cbc0010I After 300 nodes, 162 on tree, 113017.26 best solution, best possible 104952.14 (7.18 seconds)\n", "Cbc0010I After 400 nodes, 212 on tree, 113017.26 best solution, best possible 104952.14 (8.25 seconds)\n", "Cbc0010I After 500 nodes, 252 on tree, 113017.26 best solution, best possible 104952.14 (8.80 seconds)\n", "Cbc0010I After 600 nodes, 277 on tree, 113017.26 best solution, best possible 104952.14 (9.36 seconds)\n", "Cbc0010I After 700 nodes, 291 on tree, 113017.26 best solution, best possible 104952.14 (9.76 seconds)\n", "Cbc0010I After 800 nodes, 298 on tree, 113017.26 best solution, best possible 104952.14 (10.08 seconds)\n", "Cbc0010I After 900 nodes, 299 on tree, 113017.26 best solution, best possible 104952.14 (10.42 seconds)\n", "Cbc0010I After 1000 nodes, 310 on tree, 113017.26 best solution, best possible 104952.14 (10.72 seconds)\n", "Cbc0010I After 1100 nodes, 340 on tree, 113017.26 best solution, best possible 104952.14 (11.19 seconds)\n", "Cbc0010I After 1200 nodes, 373 on tree, 113017.26 best solution, best possible 104952.14 (11.62 seconds)\n", "Cbc0010I After 1300 nodes, 406 on tree, 113017.26 best solution, best possible 104952.14 (12.03 seconds)\n", "Cbc0010I After 1400 nodes, 419 on tree, 113017.26 best solution, best possible 104952.14 (12.29 seconds)\n", "Cbc0010I After 1500 nodes, 417 on tree, 113017.26 best solution, best possible 104952.14 (12.50 seconds)\n", "Cbc0010I After 1600 nodes, 429 on tree, 113017.26 best solution, best possible 104952.14 (12.82 seconds)\n", "Cbc0010I After 1700 nodes, 457 on tree, 113017.26 best solution, best possible 104952.14 (13.16 seconds)\n", "Cbc0010I After 1800 nodes, 468 on tree, 113017.26 best solution, best possible 104952.14 (13.44 seconds)\n", "Cbc0010I After 1900 nodes, 497 on tree, 113017.26 best solution, best possible 104952.14 (13.85 seconds)\n", "Cbc0010I After 2000 nodes, 504 on tree, 113017.26 best solution, best possible 104952.14 (14.13 seconds)\n", "Cbc0010I After 2100 nodes, 520 on tree, 113017.26 best solution, best possible 104952.14 (14.47 seconds)\n", "Cbc0010I After 2200 nodes, 521 on tree, 113017.26 best solution, best possible 104952.14 (14.73 seconds)\n", "Cbc0010I After 2300 nodes, 560 on tree, 113017.26 best solution, best possible 104952.14 (15.09 seconds)\n", "Cbc0010I After 2400 nodes, 593 on tree, 113017.26 best solution, best possible 104952.14 (15.45 seconds)\n", "Cbc0010I After 2500 nodes, 631 on tree, 113017.26 best solution, best possible 104952.14 (15.85 seconds)\n", "Cbc0010I After 2600 nodes, 650 on tree, 113017.26 best solution, best possible 104952.14 (16.22 seconds)\n", "Cbc0010I After 2700 nodes, 666 on tree, 113017.26 best solution, best possible 104952.14 (16.57 seconds)\n", "Cbc0010I After 2800 nodes, 676 on tree, 113017.26 best solution, best possible 104952.14 (16.88 seconds)\n", "Cbc0010I After 2900 nodes, 688 on tree, 113017.26 best solution, best possible 104952.14 (17.02 seconds)\n", "Cbc0010I After 3000 nodes, 679 on tree, 113017.26 best solution, best possible 104952.14 (17.26 seconds)\n", "Cbc0010I After 3100 nodes, 701 on tree, 113017.26 best solution, best possible 104952.14 (17.65 seconds)\n", "Cbc0010I After 3200 nodes, 733 on tree, 113017.26 best solution, best possible 104952.14 (17.92 seconds)\n", "Cbc0012I Integer solution of 112696.94 found by heuristic after 184831 iterations and 3246 nodes (18.03 seconds)\n", "Cbc0010I After 3300 nodes, 594 on tree, 112696.94 best solution, best possible 104952.14 (18.48 seconds)\n", "Cbc0010I After 3400 nodes, 646 on tree, 112696.94 best solution, best possible 104952.14 (19.41 seconds)\n", "Cbc0010I After 3500 nodes, 698 on tree, 112696.94 best solution, best possible 104952.14 (20.45 seconds)\n", "Cbc0010I After 3600 nodes, 747 on tree, 112696.94 best solution, best possible 104952.14 (21.23 seconds)\n", "Cbc0010I After 3700 nodes, 798 on tree, 112696.94 best solution, best possible 104952.14 (22.07 seconds)\n", "Cbc0010I After 3800 nodes, 848 on tree, 112696.94 best solution, best possible 104952.14 (22.88 seconds)\n", "Cbc0010I After 3900 nodes, 897 on tree, 112696.94 best solution, best possible 104952.14 (23.52 seconds)\n", "Cbc0010I After 4000 nodes, 947 on tree, 112696.94 best solution, best possible 104952.14 (24.19 seconds)\n", "Cbc0010I After 4100 nodes, 997 on tree, 112696.94 best solution, best possible 104952.14 (24.91 seconds)\n", "Cbc0010I After 4200 nodes, 1049 on tree, 112696.94 best solution, best possible 104952.14 (25.40 seconds)\n", "Cbc0010I After 4300 nodes, 1098 on tree, 112696.94 best solution, best possible 104952.14 (25.91 seconds)\n", "Cbc0010I After 4400 nodes, 1147 on tree, 112696.94 best solution, best possible 104952.14 (26.40 seconds)\n", "Cbc0010I After 4500 nodes, 1200 on tree, 112696.94 best solution, best possible 104952.14 (26.88 seconds)\n", "Cbc0010I After 4600 nodes, 1247 on tree, 112696.94 best solution, best possible 104952.14 (27.34 seconds)\n", "Cbc0010I After 4700 nodes, 1296 on tree, 112696.94 best solution, best possible 104952.14 (27.84 seconds)\n", "Cbc0010I After 4800 nodes, 1346 on tree, 112696.94 best solution, best possible 104952.14 (28.29 seconds)\n", "Cbc0010I After 4900 nodes, 1395 on tree, 112696.94 best solution, best possible 104952.14 (28.84 seconds)\n", "Cbc0010I After 5000 nodes, 1447 on tree, 112696.94 best solution, best possible 104952.14 (29.30 seconds)\n", "Cbc0010I After 5100 nodes, 1495 on tree, 112696.94 best solution, best possible 104952.14 (29.78 seconds)\n", "Cbc0010I After 5200 nodes, 1546 on tree, 112696.94 best solution, best possible 104952.14 (30.23 seconds)\n", "Cbc0010I After 5300 nodes, 1595 on tree, 112696.94 best solution, best possible 104952.14 (30.72 seconds)\n", "Cbc0010I After 5400 nodes, 1647 on tree, 112696.94 best solution, best possible 104952.14 (31.10 seconds)\n", "Cbc0010I After 5500 nodes, 1695 on tree, 112696.94 best solution, best possible 104952.14 (31.60 seconds)\n", "Cbc0010I After 5600 nodes, 1746 on tree, 112696.94 best solution, best possible 104952.14 (32.03 seconds)\n", "Cbc0010I After 5700 nodes, 1796 on tree, 112696.94 best solution, best possible 104952.14 (32.43 seconds)\n", "Cbc0010I After 5800 nodes, 1846 on tree, 112696.94 best solution, best possible 104952.14 (32.76 seconds)\n", "Cbc0010I After 5900 nodes, 1896 on tree, 112696.94 best solution, best possible 104952.14 (33.03 seconds)\n", "Cbc0010I After 6000 nodes, 1945 on tree, 112696.94 best solution, best possible 104952.14 (33.33 seconds)\n", "Cbc0010I After 6100 nodes, 1995 on tree, 112696.94 best solution, best possible 104952.14 (33.63 seconds)\n", "Cbc0010I After 6200 nodes, 2047 on tree, 112696.94 best solution, best possible 104952.14 (34.17 seconds)\n", "Cbc0010I After 6300 nodes, 2095 on tree, 112696.94 best solution, best possible 104952.14 (34.87 seconds)\n", "Cbc0010I After 6400 nodes, 2148 on tree, 112696.94 best solution, best possible 104952.14 (35.32 seconds)\n", "Cbc0010I After 6500 nodes, 2199 on tree, 112696.94 best solution, best possible 104952.14 (35.78 seconds)\n", "Cbc0010I After 6600 nodes, 2249 on tree, 112696.94 best solution, best possible 104952.14 (36.22 seconds)\n", "Cbc0010I After 6700 nodes, 2299 on tree, 112696.94 best solution, best possible 104952.14 (36.75 seconds)\n", "Cbc0010I After 6800 nodes, 2349 on tree, 112696.94 best solution, best possible 104952.14 (37.21 seconds)\n", "Cbc0010I After 6900 nodes, 2398 on tree, 112696.94 best solution, best possible 104952.14 (37.67 seconds)\n", "Cbc0010I After 7000 nodes, 2449 on tree, 112696.94 best solution, best possible 104952.14 (38.10 seconds)\n", "Cbc0010I After 7100 nodes, 2498 on tree, 112696.94 best solution, best possible 104952.14 (38.51 seconds)\n", "Cbc0010I After 7200 nodes, 2549 on tree, 112696.94 best solution, best possible 104952.14 (38.91 seconds)\n", "Cbc0010I After 7300 nodes, 2598 on tree, 112696.94 best solution, best possible 104952.14 (39.35 seconds)\n", "Cbc0010I After 7400 nodes, 2649 on tree, 112696.94 best solution, best possible 104952.14 (39.80 seconds)\n", "Cbc0010I After 7500 nodes, 2700 on tree, 112696.94 best solution, best possible 104952.14 (40.24 seconds)\n", "Cbc0010I After 7600 nodes, 2747 on tree, 112696.94 best solution, best possible 104952.14 (40.69 seconds)\n", "Cbc0010I After 7700 nodes, 2799 on tree, 112696.94 best solution, best possible 104952.14 (41.03 seconds)\n", "Cbc0010I After 7800 nodes, 2849 on tree, 112696.94 best solution, best possible 104952.14 (41.34 seconds)\n", "Cbc0010I After 7900 nodes, 2897 on tree, 112696.94 best solution, best possible 104952.14 (41.69 seconds)\n", "Cbc0010I After 8000 nodes, 2945 on tree, 112696.94 best solution, best possible 104952.14 (41.99 seconds)\n", "Cbc0010I After 8100 nodes, 2995 on tree, 112696.94 best solution, best possible 104952.14 (42.32 seconds)\n", "Cbc0010I After 8200 nodes, 3044 on tree, 112696.94 best solution, best possible 104952.14 (42.56 seconds)\n", "Cbc0010I After 8300 nodes, 3091 on tree, 112696.94 best solution, best possible 104952.14 (42.79 seconds)\n", "Cbc0010I After 8400 nodes, 3141 on tree, 112696.94 best solution, best possible 104952.14 (43.00 seconds)\n", "Cbc0010I After 8500 nodes, 3186 on tree, 112696.94 best solution, best possible 104952.14 (43.30 seconds)\n", "Cbc0010I After 8600 nodes, 3237 on tree, 112696.94 best solution, best possible 104952.14 (43.57 seconds)\n", "Cbc0012I Integer solution of 109110.96 found by heuristic after 604114 iterations and 8630 nodes (43.66 seconds)\n", "Cbc0010I After 8700 nodes, 2757 on tree, 109110.96 best solution, best possible 104952.14 (43.99 seconds)\n", "Cbc0010I After 8800 nodes, 2808 on tree, 109110.96 best solution, best possible 104952.14 (44.54 seconds)\n", "Cbc0010I After 8900 nodes, 2854 on tree, 109110.96 best solution, best possible 104952.14 (45.06 seconds)\n", "Cbc0010I After 9000 nodes, 2905 on tree, 109110.96 best solution, best possible 104952.14 (45.52 seconds)\n", "Cbc0010I After 9100 nodes, 2960 on tree, 109110.96 best solution, best possible 104952.14 (46.06 seconds)\n", "Cbc0010I After 9200 nodes, 3013 on tree, 109110.96 best solution, best possible 104952.14 (46.53 seconds)\n", "Cbc0010I After 9300 nodes, 3060 on tree, 109110.96 best solution, best possible 104952.14 (46.99 seconds)\n", "Cbc0010I After 9400 nodes, 3108 on tree, 109110.96 best solution, best possible 104952.14 (47.53 seconds)\n", "Cbc0010I After 9500 nodes, 3158 on tree, 109110.96 best solution, best possible 104952.14 (48.00 seconds)\n", "Cbc0010I After 9600 nodes, 3207 on tree, 109110.96 best solution, best possible 104952.14 (48.44 seconds)\n", "Cbc0010I After 9700 nodes, 3257 on tree, 109110.96 best solution, best possible 104952.14 (48.95 seconds)\n", "Cbc0010I After 9800 nodes, 3307 on tree, 109110.96 best solution, best possible 104952.14 (49.43 seconds)\n", "Cbc0010I After 9900 nodes, 3358 on tree, 109110.96 best solution, best possible 104952.14 (49.93 seconds)\n", "Cbc0010I After 10000 nodes, 3409 on tree, 109110.96 best solution, best possible 104952.14 (50.40 seconds)\n", "Cbc0010I After 10100 nodes, 3458 on tree, 109110.96 best solution, best possible 104952.14 (50.92 seconds)\n", "Cbc0010I After 10200 nodes, 3508 on tree, 109110.96 best solution, best possible 104952.14 (51.40 seconds)\n", "Cbc0010I After 10300 nodes, 3558 on tree, 109110.96 best solution, best possible 104952.14 (51.87 seconds)\n", "Cbc0010I After 10400 nodes, 3607 on tree, 109110.96 best solution, best possible 104952.14 (52.41 seconds)\n", "Cbc0010I After 10500 nodes, 3658 on tree, 109110.96 best solution, best possible 104952.14 (52.86 seconds)\n", "Cbc0010I After 10600 nodes, 3709 on tree, 109110.96 best solution, best possible 104952.14 (53.29 seconds)\n", "Cbc0010I After 10700 nodes, 3759 on tree, 109110.96 best solution, best possible 104952.14 (53.85 seconds)\n", "Cbc0010I After 10800 nodes, 3807 on tree, 109110.96 best solution, best possible 104952.14 (54.42 seconds)\n", "Cbc0010I After 10900 nodes, 3858 on tree, 109110.96 best solution, best possible 104952.14 (54.95 seconds)\n", "Cbc0010I After 11000 nodes, 3907 on tree, 109110.96 best solution, best possible 104952.14 (55.48 seconds)\n", "Cbc0010I After 11100 nodes, 3956 on tree, 109110.96 best solution, best possible 104997.5 (58.14 seconds)\n", "Cbc0010I After 11200 nodes, 4007 on tree, 109110.96 best solution, best possible 105047.67 (59.14 seconds)\n", "Cbc0030I Thread 0 used 2009 times, waiting to start 0.58024645, 12370 locks, 0.51344633 locked, 0.061817169 waiting for locks\n", "Cbc0030I Thread 1 used 1813 times, waiting to start 0.62287974, 11233 locks, 0.4811151 locked, 0.058864355 waiting for locks\n", "Cbc0030I Thread 2 used 1947 times, waiting to start 0.95961857, 11940 locks, 0.48913431 locked, 0.075358391 waiting for locks\n", "Cbc0030I Thread 3 used 1805 times, waiting to start 1.0815144, 11250 locks, 0.48782825 locked, 0.07196784 waiting for locks\n", "Cbc0030I Thread 4 used 1827 times, waiting to start 1.1454339, 11165 locks, 0.48662019 locked, 0.063776255 waiting for locks\n", "Cbc0030I Thread 5 used 1873 times, waiting to start 1.2649052, 11668 locks, 0.47990203 locked, 0.075296402 waiting for locks\n", "Cbc0030I Main thread 56.001714 waiting for threads, 22676 locks, 0.042243719 locked, 0.067440033 waiting for locks\n", "Cbc0020I Exiting on maximum time\n", "Cbc0005I Partial search - best objective 109110.96 (best possible 105047.67), took 861277 iterations and 11269 nodes (59.93 seconds)\n", "Cbc0032I Strong branching done 30868 times (865069 iterations), fathomed 276 nodes and fixed 1243 variables\n", "Cbc0035I Maximum depth 96, 177829 variables fixed on reduced cost\n", "Cuts at root node changed objective from 104281 to 104896\n", "Gomory was tried 4873 times and created 4094 cuts of which 0 were active after adding rounds of cuts (19.984 seconds)\n", "MixedIntegerRounding2 was tried 6714 times and created 4833 cuts of which 0 were active after adding rounds of cuts (13.257 seconds)\n", "FlowCover was tried 4873 times and created 24956 cuts of which 0 were active after adding rounds of cuts (4.575 seconds)\n", "\n", "Result - Stopped on time limit\n", "\n", "Objective value: 109110.95820568\n", "Lower bound: 105047.674\n", "Gap: 0.04\n", "Enumerated nodes: 11269\n", "Total iterations: 861277\n", "Time (CPU seconds): 343.69\n", "Time (Wallclock seconds): 59.95\n", "\n", "Total time (CPU seconds): 343.85 (Wallclock seconds): 59.98\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:optiwindnet.MILP.pyomo:>>> Solution <<<\n", "SolutionInfo(runtime=59.98, bound=105047.67, objective=109110.95820568, relgap=0.03723996445911959, termination='maxTimeLimit')\n", "\n" ] } ], "source": [ "# Set logging level to INFO to display messages about solver options\n", "import logging\n", "logging.basicConfig(level=logging.INFO)\n", "\n", "# run optimization with the milp router (Set verbose=True to display messages about solver progress)\n", "res = wfn.optimize(router=milp_router, verbose=True)" ] }, { "cell_type": "code", "execution_count": 10, "id": "39ec2a2c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'router': 'MILPRouter',\n", " 'capacity': 8,\n", " 'solver_name': 'pyomo.cbc',\n", " 'mip_gap': 0.005,\n", " 'time_limit': 60,\n", " 'topology': ,\n", " 'feeder_route': ,\n", " 'feeder_limit': ,\n", " 'balanced': False,\n", " 'runtime': 59.98,\n", " 'bound': 105047.67,\n", " 'objective': 109110.95820568,\n", " 'relgap': 0.03723996445911959,\n", " 'termination': 'maxTimeLimit'}" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.solution_info()" ] }, { "cell_type": "code", "execution_count": 11, "id": "a9ccd926", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "109233.12538404304" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.G.size(weight='length')" ] }, { "cell_type": "code", "execution_count": 12, "id": "197f3308", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "109233.12538404304" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.length()" ] }, { "cell_type": "markdown", "id": "9a449527", "metadata": {}, "source": [ "Terse link of the optimized network is returned as output of `wfn.optimize()`. If not assigned to a variable (e.g. res), it can be easily accessed via `wfn.terse_links()`." ] }, { "cell_type": "code", "execution_count": 13, "id": "00effc9d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 6, 0, 1, 10, 11, 4, 5, 14, 7, 17, 9, 19, 20,\n", " 12, 13, 24, 15, 18, 26, -2, 29, 14, 31, 22, 25, 34,\n", " 27, 28, -2, -2, -2, 41, 33, 43, 35, 36, 37, -2, -2,\n", " -2, 30, 52, 32, 44, 55, 46, 47, 48, 38, 39, -2, 40,\n", " 53, 66, 42, 67, 57, 47, 57, 49, 50, 60, 51, 62, 65,\n", " 77, 79, -1, 80, 68, 69, 70, 71, 61, 73, 63, 75, 78,\n", " 89, -1, -1, -1, 81, 82, 83, 72, 73, 86, 75, 90, 91,\n", " -1, -1, -1, 95, 84, 95, 85, 87, 100, -1, 92, 101, 93,\n", " 103, 96, 114, 106, 100, 108, 102, 110, 104, 112, 113, 109, 115,\n", " 111, 117, 118, 116, 120])" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res" ] }, { "cell_type": "markdown", "id": "44d06e34-832a-49fd-9a49-6ecb0ed431ee", "metadata": {}, "source": [ "### Plot the optimized network graph" ] }, { "cell_type": "code", "execution_count": 14, "id": "42b84cd0-d148-4e5d-907c-7de61dc17450", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "213 776 367 €Σλ = 109 233 m(+0) [-1]: 8, [-2]: 8κ = 8, T = 122" ], "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }