{ "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": [ "113587.95387324075" ] }, "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 576 711 €Σλ = 113 588 m(+4) [-1]: 10, [-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.13 \n", "Build Date: Apr 1 2026 \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/tmpzrnuowmq.pyomo.lp -mipstart /tmp/tmp6ns_4g1b.cbc.soln -stat=1 -solve -solu /tmp/tmpzrnuowmq.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/tmp6ns_4g1b.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 - 1.24 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 113493\n", "Cbc0012I Integer solution of 113493.06 found by Reduced search after 0 iterations and 0 nodes (0.25 seconds)\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 264 rows 154 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 264 rows 154 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 264 rows 154 columns\n", "Cbc0038I Full problem 3881 rows 2892 columns, reduced to 412 rows 230 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 305 rows 188 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 305 rows 188 columns\n", "Cbc0038I Full problem 3882 rows 2892 columns, reduced to 305 rows 188 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.382 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.055 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.028 seconds - new frequency is 1\n", "Cbc0010I After 0 nodes, 1 on tree, 113493.06 best solution, best possible 104895.91 (1.51 seconds)\n", "Cbc0010I After 100 nodes, 56 on tree, 113493.06 best solution, best possible 104955.58 (5.29 seconds)\n", "Cbc0010I After 200 nodes, 109 on tree, 113493.06 best solution, best possible 104955.58 (6.71 seconds)\n", "Cbc0010I After 300 nodes, 163 on tree, 113493.06 best solution, best possible 104955.58 (7.65 seconds)\n", "Cbc0010I After 400 nodes, 215 on tree, 113493.06 best solution, best possible 104955.58 (8.41 seconds)\n", "Cbc0010I After 500 nodes, 250 on tree, 113493.06 best solution, best possible 104955.58 (8.94 seconds)\n", "Cbc0010I After 600 nodes, 293 on tree, 113493.06 best solution, best possible 104955.58 (9.32 seconds)\n", "Cbc0010I After 700 nodes, 310 on tree, 113493.06 best solution, best possible 104955.58 (9.60 seconds)\n", "Cbc0010I After 800 nodes, 318 on tree, 113493.06 best solution, best possible 104955.58 (9.90 seconds)\n", "Cbc0010I After 900 nodes, 317 on tree, 113493.06 best solution, best possible 104955.58 (10.11 seconds)\n", "Cbc0010I After 1000 nodes, 324 on tree, 113493.06 best solution, best possible 104955.58 (10.33 seconds)\n", "Cbc0010I After 1100 nodes, 329 on tree, 113493.06 best solution, best possible 104955.58 (10.56 seconds)\n", "Cbc0010I After 1200 nodes, 336 on tree, 113493.06 best solution, best possible 104955.58 (10.82 seconds)\n", "Cbc0010I After 1300 nodes, 343 on tree, 113493.06 best solution, best possible 104955.58 (11.01 seconds)\n", "Cbc0010I After 1400 nodes, 345 on tree, 113493.06 best solution, best possible 104955.58 (11.21 seconds)\n", "Cbc0010I After 1500 nodes, 338 on tree, 113493.06 best solution, best possible 104955.58 (11.41 seconds)\n", "Cbc0010I After 1600 nodes, 340 on tree, 113493.06 best solution, best possible 104955.58 (11.57 seconds)\n", "Cbc0010I After 1700 nodes, 338 on tree, 113493.06 best solution, best possible 104955.58 (11.69 seconds)\n", "Cbc0010I After 1800 nodes, 334 on tree, 113493.06 best solution, best possible 104955.58 (11.82 seconds)\n", "Cbc0010I After 1900 nodes, 333 on tree, 113493.06 best solution, best possible 104955.58 (11.99 seconds)\n", "Cbc0010I After 2000 nodes, 345 on tree, 113493.06 best solution, best possible 104955.58 (12.18 seconds)\n", "Cbc0010I After 2100 nodes, 354 on tree, 113493.06 best solution, best possible 104955.58 (12.39 seconds)\n", "Cbc0010I After 2200 nodes, 345 on tree, 113493.06 best solution, best possible 104955.58 (12.55 seconds)\n", "Cbc0010I After 2300 nodes, 340 on tree, 113493.06 best solution, best possible 104955.58 (12.68 seconds)\n", "Cbc0010I After 2400 nodes, 359 on tree, 113493.06 best solution, best possible 104955.58 (12.83 seconds)\n", "Cbc0010I After 2500 nodes, 338 on tree, 113493.06 best solution, best possible 104955.58 (12.96 seconds)\n", "Cbc0010I After 2600 nodes, 356 on tree, 113493.06 best solution, best possible 104955.58 (13.13 seconds)\n", "Cbc0010I After 2700 nodes, 360 on tree, 113493.06 best solution, best possible 104955.58 (13.25 seconds)\n", "Cbc0010I After 2800 nodes, 346 on tree, 113493.06 best solution, best possible 104955.58 (13.39 seconds)\n", "Cbc0010I After 2900 nodes, 356 on tree, 113493.06 best solution, best possible 104955.58 (13.51 seconds)\n", "Cbc0010I After 3000 nodes, 340 on tree, 113493.06 best solution, best possible 104955.58 (13.68 seconds)\n", "Cbc0010I After 3100 nodes, 346 on tree, 113493.06 best solution, best possible 104955.58 (13.90 seconds)\n", "Cbc0010I After 3200 nodes, 344 on tree, 113493.06 best solution, best possible 104955.58 (14.07 seconds)\n", "Cbc0010I After 3300 nodes, 338 on tree, 113493.06 best solution, best possible 104955.58 (14.26 seconds)\n", "Cbc0010I After 3400 nodes, 331 on tree, 113493.06 best solution, best possible 104955.58 (14.40 seconds)\n", "Cbc0010I After 3500 nodes, 331 on tree, 113493.06 best solution, best possible 104955.58 (14.57 seconds)\n", "Cbc0010I After 3600 nodes, 340 on tree, 113493.06 best solution, best possible 104955.58 (14.75 seconds)\n", "Cbc0010I After 3700 nodes, 346 on tree, 113493.06 best solution, best possible 104955.58 (14.98 seconds)\n", "Cbc0010I After 3800 nodes, 341 on tree, 113493.06 best solution, best possible 104955.58 (15.16 seconds)\n", "Cbc0010I After 3900 nodes, 341 on tree, 113493.06 best solution, best possible 104955.58 (15.27 seconds)\n", "Cbc0010I After 4000 nodes, 337 on tree, 113493.06 best solution, best possible 104955.58 (15.43 seconds)\n", "Cbc0010I After 4100 nodes, 334 on tree, 113493.06 best solution, best possible 104955.58 (15.60 seconds)\n", "Cbc0010I After 4200 nodes, 337 on tree, 113493.06 best solution, best possible 104955.58 (15.82 seconds)\n", "Cbc0010I After 4300 nodes, 332 on tree, 113493.06 best solution, best possible 104955.58 (16.03 seconds)\n", "Cbc0010I After 4400 nodes, 350 on tree, 113493.06 best solution, best possible 104955.58 (16.25 seconds)\n", "Cbc0010I After 4500 nodes, 346 on tree, 113493.06 best solution, best possible 104955.58 (16.49 seconds)\n", "Cbc0010I After 4600 nodes, 350 on tree, 113493.06 best solution, best possible 104955.58 (16.63 seconds)\n", "Cbc0010I After 4700 nodes, 351 on tree, 113493.06 best solution, best possible 104955.58 (16.79 seconds)\n", "Cbc0010I After 4800 nodes, 358 on tree, 113493.06 best solution, best possible 104955.58 (17.02 seconds)\n", "Cbc0010I After 4900 nodes, 397 on tree, 113493.06 best solution, best possible 104955.58 (17.27 seconds)\n", "Cbc0010I After 5000 nodes, 417 on tree, 113493.06 best solution, best possible 104955.58 (17.53 seconds)\n", "Cbc0010I After 5100 nodes, 435 on tree, 113493.06 best solution, best possible 104955.58 (17.70 seconds)\n", "Cbc0010I After 5200 nodes, 442 on tree, 113493.06 best solution, best possible 104955.58 (17.85 seconds)\n", "Cbc0010I After 5300 nodes, 450 on tree, 113493.06 best solution, best possible 104955.58 (18.06 seconds)\n", "Cbc0010I After 5400 nodes, 454 on tree, 113493.06 best solution, best possible 104955.58 (18.24 seconds)\n", "Cbc0010I After 5500 nodes, 467 on tree, 113493.06 best solution, best possible 104955.58 (18.48 seconds)\n", "Cbc0010I After 5600 nodes, 480 on tree, 113493.06 best solution, best possible 104955.58 (18.74 seconds)\n", "Cbc0010I After 5700 nodes, 501 on tree, 113493.06 best solution, best possible 104955.58 (18.92 seconds)\n", "Cbc0010I After 5800 nodes, 502 on tree, 113493.06 best solution, best possible 104955.58 (19.09 seconds)\n", "Cbc0010I After 5900 nodes, 517 on tree, 113493.06 best solution, best possible 104955.58 (19.25 seconds)\n", "Cbc0010I After 6000 nodes, 519 on tree, 113493.06 best solution, best possible 104955.58 (19.34 seconds)\n", "Cbc0010I After 6100 nodes, 516 on tree, 113493.06 best solution, best possible 104955.58 (19.47 seconds)\n", "Cbc0010I After 6200 nodes, 517 on tree, 113493.06 best solution, best possible 104955.58 (19.65 seconds)\n", "Cbc0010I After 6300 nodes, 544 on tree, 113493.06 best solution, best possible 104955.58 (19.87 seconds)\n", "Cbc0010I After 6400 nodes, 548 on tree, 113493.06 best solution, best possible 104955.58 (20.07 seconds)\n", "Cbc0010I After 6500 nodes, 549 on tree, 113493.06 best solution, best possible 104955.58 (20.27 seconds)\n", "Cbc0010I After 6600 nodes, 560 on tree, 113493.06 best solution, best possible 104955.58 (20.47 seconds)\n", "Cbc0010I After 6700 nodes, 563 on tree, 113493.06 best solution, best possible 104955.58 (20.73 seconds)\n", "Cbc0010I After 6800 nodes, 578 on tree, 113493.06 best solution, best possible 104955.58 (20.97 seconds)\n", "Cbc0010I After 6900 nodes, 579 on tree, 113493.06 best solution, best possible 104955.58 (21.10 seconds)\n", "Cbc0010I After 7000 nodes, 593 on tree, 113493.06 best solution, best possible 104955.58 (21.29 seconds)\n", "Cbc0010I After 7100 nodes, 627 on tree, 113493.06 best solution, best possible 104955.58 (21.47 seconds)\n", "Cbc0010I After 7200 nodes, 642 on tree, 113493.06 best solution, best possible 104955.58 (21.64 seconds)\n", "Cbc0010I After 7300 nodes, 649 on tree, 113493.06 best solution, best possible 104955.58 (21.80 seconds)\n", "Cbc0010I After 7400 nodes, 640 on tree, 113493.06 best solution, best possible 104955.58 (21.94 seconds)\n", "Cbc0010I After 7500 nodes, 650 on tree, 113493.06 best solution, best possible 104955.58 (22.09 seconds)\n", "Cbc0010I After 7600 nodes, 645 on tree, 113493.06 best solution, best possible 104955.58 (22.25 seconds)\n", "Cbc0010I After 7700 nodes, 634 on tree, 113493.06 best solution, best possible 104955.58 (22.42 seconds)\n", "Cbc0010I After 7800 nodes, 644 on tree, 113493.06 best solution, best possible 104955.58 (22.54 seconds)\n", "Cbc0010I After 7900 nodes, 637 on tree, 113493.06 best solution, best possible 104955.58 (22.63 seconds)\n", "Cbc0010I After 8000 nodes, 630 on tree, 113493.06 best solution, best possible 104955.58 (22.74 seconds)\n", "Cbc0010I After 8100 nodes, 641 on tree, 113493.06 best solution, best possible 104955.58 (22.96 seconds)\n", "Cbc0010I After 8200 nodes, 655 on tree, 113493.06 best solution, best possible 104955.58 (23.15 seconds)\n", "Cbc0010I After 8300 nodes, 672 on tree, 113493.06 best solution, best possible 104955.58 (23.28 seconds)\n", "Cbc0010I After 8400 nodes, 673 on tree, 113493.06 best solution, best possible 104955.58 (23.40 seconds)\n", "Cbc0010I After 8500 nodes, 671 on tree, 113493.06 best solution, best possible 104955.58 (23.51 seconds)\n", "Cbc0010I After 8600 nodes, 684 on tree, 113493.06 best solution, best possible 104955.58 (23.61 seconds)\n", "Cbc0010I After 8700 nodes, 679 on tree, 113493.06 best solution, best possible 104955.58 (23.69 seconds)\n", "Cbc0010I After 8800 nodes, 670 on tree, 113493.06 best solution, best possible 104955.58 (23.81 seconds)\n", "Cbc0010I After 8900 nodes, 666 on tree, 113493.06 best solution, best possible 104955.58 (23.92 seconds)\n", "Cbc0010I After 9000 nodes, 669 on tree, 113493.06 best solution, best possible 104955.58 (24.04 seconds)\n", "Cbc0010I After 9100 nodes, 657 on tree, 113493.06 best solution, best possible 104955.58 (24.19 seconds)\n", "Cbc0010I After 9200 nodes, 664 on tree, 113493.06 best solution, best possible 104955.58 (24.37 seconds)\n", "Cbc0010I After 9300 nodes, 679 on tree, 113493.06 best solution, best possible 104955.58 (24.46 seconds)\n", "Cbc0010I After 9400 nodes, 677 on tree, 113493.06 best solution, best possible 104955.58 (24.55 seconds)\n", "Cbc0010I After 9500 nodes, 672 on tree, 113493.06 best solution, best possible 104955.58 (24.62 seconds)\n", "Cbc0010I After 9600 nodes, 663 on tree, 113493.06 best solution, best possible 104955.58 (24.71 seconds)\n", "Cbc0010I After 9700 nodes, 670 on tree, 113493.06 best solution, best possible 104955.58 (24.81 seconds)\n", "Cbc0010I After 9800 nodes, 671 on tree, 113493.06 best solution, best possible 104955.58 (24.89 seconds)\n", "Cbc0010I After 9900 nodes, 655 on tree, 113493.06 best solution, best possible 104955.58 (25.04 seconds)\n", "Cbc0010I After 10000 nodes, 667 on tree, 113493.06 best solution, best possible 104955.58 (25.15 seconds)\n", "Cbc0010I After 10100 nodes, 662 on tree, 113493.06 best solution, best possible 104955.58 (25.24 seconds)\n", "Cbc0010I After 10200 nodes, 671 on tree, 113493.06 best solution, best possible 104955.58 (25.34 seconds)\n", "Cbc0010I After 10300 nodes, 662 on tree, 113493.06 best solution, best possible 104955.58 (25.50 seconds)\n", "Cbc0010I After 10400 nodes, 676 on tree, 113493.06 best solution, best possible 104955.58 (25.65 seconds)\n", "Cbc0010I After 10500 nodes, 678 on tree, 113493.06 best solution, best possible 104955.58 (25.83 seconds)\n", "Cbc0010I After 10600 nodes, 667 on tree, 113493.06 best solution, best possible 104955.58 (26.04 seconds)\n", "Cbc0010I After 10700 nodes, 675 on tree, 113493.06 best solution, best possible 104955.58 (26.24 seconds)\n", "Cbc0010I After 10800 nodes, 680 on tree, 113493.06 best solution, best possible 104955.58 (26.40 seconds)\n", "Cbc0010I After 10900 nodes, 693 on tree, 113493.06 best solution, best possible 104955.58 (26.55 seconds)\n", "Cbc0010I After 11000 nodes, 693 on tree, 113493.06 best solution, best possible 104955.58 (26.70 seconds)\n", "Cbc0010I After 11100 nodes, 742 on tree, 113493.06 best solution, best possible 104991.32 (28.81 seconds)\n", "Cbc0010I After 11200 nodes, 790 on tree, 113493.06 best solution, best possible 105011.32 (30.08 seconds)\n", "Cbc0010I After 11300 nodes, 841 on tree, 113493.06 best solution, best possible 105022.26 (31.32 seconds)\n", "Cbc0010I After 11400 nodes, 892 on tree, 113493.06 best solution, best possible 105031.78 (32.33 seconds)\n", "Cbc0010I After 11500 nodes, 940 on tree, 113493.06 best solution, best possible 105037.9 (33.34 seconds)\n", "Cbc0010I After 11600 nodes, 992 on tree, 113493.06 best solution, best possible 105043.82 (34.17 seconds)\n", "Cbc0010I After 11700 nodes, 1041 on tree, 113493.06 best solution, best possible 105048.23 (34.90 seconds)\n", "Cbc0010I After 11800 nodes, 1091 on tree, 113493.06 best solution, best possible 105051.8 (35.63 seconds)\n", "Cbc0010I After 11900 nodes, 1142 on tree, 113493.06 best solution, best possible 105054.67 (36.33 seconds)\n", "Cbc0010I After 12000 nodes, 1191 on tree, 113493.06 best solution, best possible 105059.11 (36.97 seconds)\n", "Cbc0010I After 12100 nodes, 1241 on tree, 113493.06 best solution, best possible 105061.41 (37.70 seconds)\n", "Cbc0010I After 12200 nodes, 1291 on tree, 113493.06 best solution, best possible 105064.36 (38.30 seconds)\n", "Cbc0010I After 12300 nodes, 1341 on tree, 113493.06 best solution, best possible 105066.92 (38.96 seconds)\n", "Cbc0010I After 12400 nodes, 1391 on tree, 113493.06 best solution, best possible 105068.51 (39.56 seconds)\n", "Cbc0010I After 12500 nodes, 1440 on tree, 113493.06 best solution, best possible 105071.32 (40.19 seconds)\n", "Cbc0010I After 12600 nodes, 1491 on tree, 113493.06 best solution, best possible 105073.43 (40.74 seconds)\n", "Cbc0010I After 12700 nodes, 1541 on tree, 113493.06 best solution, best possible 105075.31 (41.36 seconds)\n", "Cbc0010I After 12800 nodes, 1592 on tree, 113493.06 best solution, best possible 105077.11 (41.85 seconds)\n", "Cbc0010I After 12900 nodes, 1641 on tree, 113493.06 best solution, best possible 105079.22 (42.37 seconds)\n", "Cbc0010I After 13000 nodes, 1692 on tree, 113493.06 best solution, best possible 105080.72 (42.91 seconds)\n", "Cbc0010I After 13100 nodes, 1741 on tree, 113493.06 best solution, best possible 105082.24 (43.41 seconds)\n", "Cbc0010I After 13200 nodes, 1791 on tree, 113493.06 best solution, best possible 105083.53 (44.04 seconds)\n", "Cbc0010I After 13300 nodes, 1840 on tree, 113493.06 best solution, best possible 105085.01 (44.49 seconds)\n", "Cbc0010I After 13400 nodes, 1890 on tree, 113493.06 best solution, best possible 105085.89 (45.02 seconds)\n", "Cbc0010I After 13500 nodes, 1940 on tree, 113493.06 best solution, best possible 105087.02 (45.56 seconds)\n", "Cbc0010I After 13600 nodes, 1990 on tree, 113493.06 best solution, best possible 105088.34 (46.04 seconds)\n", "Cbc0010I After 13700 nodes, 2039 on tree, 113493.06 best solution, best possible 105089.38 (46.58 seconds)\n", "Cbc0010I After 13800 nodes, 2089 on tree, 113493.06 best solution, best possible 105090.61 (47.20 seconds)\n", "Cbc0010I After 13900 nodes, 2139 on tree, 113493.06 best solution, best possible 105091.37 (47.67 seconds)\n", "Cbc0010I After 14000 nodes, 2190 on tree, 113493.06 best solution, best possible 105092.37 (48.15 seconds)\n", "Cbc0010I After 14100 nodes, 2240 on tree, 113493.06 best solution, best possible 105093.13 (48.59 seconds)\n", "Cbc0010I After 14200 nodes, 2289 on tree, 113493.06 best solution, best possible 105093.91 (49.08 seconds)\n", "Cbc0010I After 14300 nodes, 2340 on tree, 113493.06 best solution, best possible 105094.71 (49.51 seconds)\n", "Cbc0010I After 14400 nodes, 2389 on tree, 113493.06 best solution, best possible 105095.7 (49.98 seconds)\n", "Cbc0010I After 14500 nodes, 2439 on tree, 113493.06 best solution, best possible 105096.22 (50.50 seconds)\n", "Cbc0010I After 14600 nodes, 2489 on tree, 113493.06 best solution, best possible 105097.14 (51.01 seconds)\n", "Cbc0010I After 14700 nodes, 2539 on tree, 113493.06 best solution, best possible 105098.05 (51.48 seconds)\n", "Cbc0010I After 14800 nodes, 2589 on tree, 113493.06 best solution, best possible 105098.78 (51.96 seconds)\n", "Cbc0010I After 14900 nodes, 2639 on tree, 113493.06 best solution, best possible 105099.47 (52.47 seconds)\n", "Cbc0010I After 15000 nodes, 2690 on tree, 113493.06 best solution, best possible 105100.11 (52.95 seconds)\n", "Cbc0010I After 15100 nodes, 2739 on tree, 113493.06 best solution, best possible 105100.88 (53.48 seconds)\n", "Cbc0010I After 15200 nodes, 2789 on tree, 113493.06 best solution, best possible 105101.48 (53.94 seconds)\n", "Cbc0010I After 15300 nodes, 2839 on tree, 113493.06 best solution, best possible 105102.13 (54.50 seconds)\n", "Cbc0010I After 15400 nodes, 2889 on tree, 113493.06 best solution, best possible 105102.97 (55.03 seconds)\n", "Cbc0010I After 15500 nodes, 2939 on tree, 113493.06 best solution, best possible 105103.51 (55.53 seconds)\n", "Cbc0010I After 15600 nodes, 2990 on tree, 113493.06 best solution, best possible 105104.16 (56.06 seconds)\n", "Cbc0010I After 15700 nodes, 3038 on tree, 113493.06 best solution, best possible 105104.68 (56.54 seconds)\n", "Cbc0010I After 15800 nodes, 3088 on tree, 113493.06 best solution, best possible 105105.58 (57.06 seconds)\n", "Cbc0010I After 15900 nodes, 3139 on tree, 113493.06 best solution, best possible 105106.2 (57.52 seconds)\n", "Cbc0010I After 16000 nodes, 3189 on tree, 113493.06 best solution, best possible 105106.81 (58.02 seconds)\n", "Cbc0010I After 16100 nodes, 3239 on tree, 113493.06 best solution, best possible 105107.34 (58.47 seconds)\n", "Cbc0010I After 16200 nodes, 3288 on tree, 113493.06 best solution, best possible 105108.03 (58.97 seconds)\n", "Cbc0010I After 16300 nodes, 3340 on tree, 113493.06 best solution, best possible 105108.52 (59.49 seconds)\n", "Cbc0030I Thread 0 used 2811 times, waiting to start 0.60903478, 16178 locks, 0.47207999 locked, 0.061329126 waiting for locks\n", "Cbc0030I Thread 1 used 2699 times, waiting to start 0.64490891, 15731 locks, 0.45184684 locked, 0.060606003 waiting for locks\n", "Cbc0030I Thread 2 used 2748 times, waiting to start 1.0223918, 15789 locks, 0.45806575 locked, 0.061781645 waiting for locks\n", "Cbc0030I Thread 3 used 2663 times, waiting to start 1.1283371, 15371 locks, 0.44218516 locked, 0.058873415 waiting for locks\n", "Cbc0030I Thread 4 used 2718 times, waiting to start 1.2782054, 15693 locks, 0.45033574 locked, 0.06493783 waiting for locks\n", "Cbc0030I Thread 5 used 2743 times, waiting to start 1.4361572, 15793 locks, 0.46110439 locked, 0.061211109 waiting for locks\n", "Cbc0030I Main thread 56.102583 waiting for threads, 32946 locks, 0.016206026 locked, 0.12429452 waiting for locks\n", "Cbc0020I Exiting on maximum time\n", "Cbc0005I Partial search - best objective 113493.06 (best possible 105108.52), took 1162855 iterations and 16377 nodes (60.06 seconds)\n", "Cbc0032I Strong branching done 36962 times (1043579 iterations), fathomed 1810 nodes and fixed 4615 variables\n", "Cbc0035I Maximum depth 101, 333990 variables fixed on reduced cost\n", "Cuts at root node changed objective from 104281 to 104896\n", "Gomory was tried 5688 times and created 5409 cuts of which 0 were active after adding rounds of cuts (18.316 seconds)\n", "MixedIntegerRounding2 was tried 8005 times and created 4059 cuts of which 0 were active after adding rounds of cuts (10.955 seconds)\n", "FlowCover was tried 5686 times and created 27650 cuts of which 0 were active after adding rounds of cuts (4.672 seconds)\n", "\n", "Result - Stopped on time limit\n", "\n", "Objective value: 113493.05766610\n", "Lower bound: 105108.517\n", "Gap: 0.08\n", "Enumerated nodes: 16377\n", "Total iterations: 1162855\n", "Time (CPU seconds): 343.85\n", "Time (Wallclock seconds): 60.08\n", "\n", "Total time (CPU seconds): 344.24 (Wallclock seconds): 60.11\n", "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO:optiwindnet.MILP.pyomo:>>> Solution <<<\n", "SolutionInfo(runtime=60.11, bound=105108.52, objective=113493.0576661, relgap=0.07387709731786019, 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': 60.11,\n", " 'bound': 105108.52,\n", " 'objective': 113493.0576661,\n", " 'relgap': 0.07387709731786019,\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": [ "113587.95387324075" ] }, "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": [ "113587.95387324075" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn.length()" ] }, { "cell_type": "markdown", "id": "9a449527", "metadata": {}, "source": [ "A topology-aware `TerseLinks` object is returned by `wfn.optimize()`. It behaves like a NumPy array and carries the solution architecture in its `topology` attribute. If the result is not assigned to a variable (for example, `res`), it remains available through `wfn.terse_links()`." ] }, { "cell_type": "code", "execution_count": 13, "id": "00effc9d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "TerseLinks(scope='topology', topology='branched', T=122, R=2, links=122)" ] }, "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": [ "216 576 711 €Σλ = 113 588 m(+4) [-1]: 10, [-2]: 10κ = 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 }