{
"cells": [
{
"cell_type": "markdown",
"id": "fbed597e",
"metadata": {},
"source": [
"# HGSRouter example"
]
},
{
"cell_type": "markdown",
"id": "5767fd33",
"metadata": {},
"source": [
"This notebook uses `OptiWindNet` to route the collector system cables via `HGSRouter`."
]
},
{
"cell_type": "markdown",
"id": "9fe197e1",
"metadata": {},
"source": [
"## 🧬 HGS (Hybrid Genetic Search)"
]
},
{
"cell_type": "markdown",
"id": "6b901e0f",
"metadata": {},
"source": [
"`HGSRouter` is a *metaheuristic based router* that applies *Hybrid Genetic Search (HGS)* to optimize electrical network of a defined turbine-layout as a *Capacitated Vehicle Routing Problem (CVRP)*. It can handle both single and multiple substations and is well-suited for *fast and high-quality networks*.\n",
"\n",
"This router is slower than `EWRouter` but typically yields *better-quality solutions*, especially for medium and large windfarms with one substation."
]
},
{
"cell_type": "markdown",
"id": "1435a3f2",
"metadata": {},
"source": [
"### 🔧 Constructor: `HGSRouter(...)`"
]
},
{
"cell_type": "markdown",
"id": "917f3e68",
"metadata": {},
"source": [
"**Required arguments:**\n",
"\n",
"| Argument | Type | Description |\n",
"| ------------ | ----- | ----------------------------------------------------------------------------------------------------------------------- |\n",
"| `time_limit` | `int` | Time limit (in seconds) which controls how long the genetic algorithm can search for better solutions. |\n",
"\n",
"**Optional arguments:**\n",
"\n",
"| Argument | Type | Description |\n",
"| -------------- | ------------- | --------------------------------------------------------------------------------------- |\n",
"| `feeder_limit` | `int or None` | Maximum number of feeders (only used in single-substation problems). |\n",
"| `max_iter` | `int` | Maximum number of local iterations (default: `10`). |\n",
"| `balanced` | `bool` | If `True`, tries to balance the number of turbines per feeder. |\n",
"| `seed` | `int` | Random seed for reproducibility (default: `0`). |\n",
"| `verbose` | `bool` | If `True`, prints routing details and warnings. |\n",
"\n",
"**✅ Example**\n",
"\n",
"```python\n",
"router = HGSRouter(time_limit=60, feeder_limit=10, balanced=True)\n",
"wf = WindFarmNetwork(cables=..., turbinesC=..., substationsC=..., router=router)\n",
"wf.optimize()\n",
"```\n",
"* HGSRouter trades speed for *higher-quality networks* and is particularly useful when:\n",
"\n",
" * A better solution is worth longer runtime (respect to `EWRouter`)\n",
" * The number of turbines connected to each feeder needs to be balanced\n",
"\n",
"* In *multi-substation networks*, the `feeder_limit` is ignored (not yet supported)."
]
},
{
"cell_type": "markdown",
"id": "b9ee6aad",
"metadata": {},
"source": [
">This router is implemented [vidalt/HGS-CVRP: Modern implementation of the hybrid genetic search (HGS) algorithm specialized to the capacitated vehicle routing problem (CVRP). This code also includes an additional neighborhood called SWAP\\*.](https://github.com/vidalt/HGS-CVRP)\n",
">\n",
">HGSRouter can only produce *radial* topologies. Since a *radial* topology is a special case of the *branched* topology, solutions produced by this method can be used to warm-start both *branched*- and *radial*-topology models."
]
},
{
"cell_type": "markdown",
"id": "ce9294e2",
"metadata": {},
"source": [
"## Load data"
]
},
{
"cell_type": "markdown",
"id": "89e1961f",
"metadata": {},
"source": [
"import required modules"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "c42a3703-113b-4aee-8dfb-a0b3b54663e6",
"metadata": {},
"outputs": [],
"source": [
"from optiwindnet.api import WindFarmNetwork, HGSRouter"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "dcede524",
"metadata": {},
"outputs": [],
"source": [
"# Display figures as SVG in Jupyter notebooks\n",
"%config InlineBackend.figure_formats = ['svg']"
]
},
{
"cell_type": "markdown",
"id": "bde9df37",
"metadata": {},
"source": [
"Create an instance of `wfn` using `.from_pbf()`\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "ed908310",
"metadata": {},
"outputs": [],
"source": [
"wfn = WindFarmNetwork.from_pbf(filepath='data/DTU_letters.osm.pbf', cables= [(7, 2000.0)])"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "c838598f",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wfn"
]
},
{
"cell_type": "markdown",
"id": "5d38a18d-ab5e-4b03-ae74-9ccb4dedbe07",
"metadata": {},
"source": [
"## Optimize with HGSRouter"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "7884b794",
"metadata": {},
"outputs": [],
"source": [
"router = HGSRouter(time_limit=10)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "98fc84a8",
"metadata": {},
"outputs": [],
"source": [
"res = wfn.optimize(router=router)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "fbb5bb95",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1596.158040734816"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wfn.length()"
]
},
{
"cell_type": "markdown",
"id": "b4165029",
"metadata": {},
"source": [
"### Get solution_time"
]
},
{
"cell_type": "markdown",
"id": "3d18f6e4",
"metadata": {},
"source": [
"We can see the solution time for HGS using:\n",
"```python\n",
"wfn.S.graph['solution_time']\n",
"```\n",
"It prints the computation time for each subgroup of turbines assigned to a specific substation.\n",
"The HGS algorithm groups turbines and allocates each group to a substation prior to optimization."
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "5aaefea4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.06\n"
]
}
],
"source": [
"print(wfn.S.graph['solution_time'])"
]
},
{
"cell_type": "markdown",
"id": "2bb4e742",
"metadata": {},
"source": [
"### Choosing `time_limit` wisely"
]
},
{
"cell_type": "markdown",
"id": "ed68ae5c",
"metadata": {},
"source": [
"Based on the solution times observed in the previous step, we can make an informed decision about the time limit for the HGS router. If increasing the time limit does not significantly improve the solution (e.g., does not result in a noticeably shorter cable length), we can consider reducing it to save computational resources. In this case, a time limit of 0.1 second appears to be sufficient, as it is well above all the solution times."
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "45d586b9",
"metadata": {},
"outputs": [],
"source": [
"router_reduced_timelimit = HGSRouter(time_limit=0.1)\n",
"res_reduced_timelimit = wfn.optimize(router=router_reduced_timelimit)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "c8947907",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.05\n"
]
}
],
"source": [
"print(wfn.S.graph['solution_time'])"
]
},
{
"cell_type": "markdown",
"id": "c61410af",
"metadata": {},
"source": [
"#### Check the length\n",
"\n",
"We can see that, as expected, reducing the time limt from 10 seconds to 1 seconds has not affected the resultant length."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "045e232b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1596.158040734816"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wfn.length()"
]
},
{
"cell_type": "markdown",
"id": "8d7ad952",
"metadata": {},
"source": [
"### Plot the Optimized Network Graph"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "696b6ca2",
"metadata": {},
"outputs": [
{
"data": {
"image/svg+xml": [
""
],
"text/plain": [
""
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wfn"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "OptiWindNet",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}