{ "cells": [ { "cell_type": "markdown", "id": "6ef7c0e8", "metadata": {}, "source": [ "# Borders, Obstacles & Buffering" ] }, { "cell_type": "markdown", "id": "ed13a6b8-1d5b-4ce0-9cd4-b81bac7b07dd", "metadata": {}, "source": [ "**OptiWindNet** models site bounds with an exterior **border** (allowed area) and interior **obstacles** (exclusion zones), and keeps electrical network design compliant with the bounds. This notebook walks from initialization and optimization under constraints, through cleaning and buffering the geometry, to validating turbine/substation placement. We will explore following features (methods):\n", "\n", "* **Optimize under bounds**: `.optimize()`: optimize electrical network while enforcing border/obstacle constraints.\n", "* **Merge & clean boundary**: `.merge_obstacles_into_border()`: resolve intersections/touching constraints, absorb irrelevant obstacles, and simplify the exterior boundary.\n", "* **Buffer geometry**: `.add_buffer(buffer_dist=...)`: expand the border and shrink obstacles to add safety margins; might smooth concavities or remove obstacles depending on `buffer_dist`.\n", "* **Compare originals vs buffered**: `.plot_original_vs_buffered()`: overlay plot of border/obstacles before and after buffering to inspect how buffering changed shapes.\n", "* **Validate placement**: `.optimize()` raises a `ValueError` if any turbine or substation lies outside the border or inside an obstacle." ] }, { "cell_type": "markdown", "id": "1998fe8b", "metadata": {}, "source": [ "Import required packages" ] }, { "cell_type": "code", "execution_count": 1, "id": "b0f61785-6be5-4a0f-8282-5c17f4cc28ad", "metadata": {}, "outputs": [], "source": [ "from optiwindnet.api import WindFarmNetwork\n", "import numpy as np\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "id": "fc07dcc1", "metadata": {}, "outputs": [], "source": [ "# Display figures as SVG in Jupyter notebooks\n", "%config InlineBackend.figure_formats = ['svg']" ] }, { "cell_type": "markdown", "id": "f624996b", "metadata": {}, "source": [ "## Borders and obstacles" ] }, { "cell_type": "markdown", "id": "9779f2b9", "metadata": {}, "source": [ "### 1. Initialize\n", "Create a `WindFarmNetwork` instances from an `osm.pbf´ file and optimize it." ] }, { "cell_type": "code", "execution_count": 3, "id": "4e702047", "metadata": {}, "outputs": [], "source": [ "wfn1 = WindFarmNetwork.from_pbf(filepath='data/DTU_letters.osm.pbf', cables=7)\n" ] }, { "cell_type": "markdown", "id": "cf12b38e", "metadata": {}, "source": [ "Plot the location geometry and the optimized network to confirm that the borders and obstacles are properly initialized and considered for optimization." ] }, { "cell_type": "code", "execution_count": 4, "id": "142de4c6", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn1" ] }, { "cell_type": "code", "execution_count": 5, "id": "00e76735", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "40" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn1.L.graph['T']" ] }, { "cell_type": "code", "execution_count": 6, "id": "07bf9dea", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 1 647.1 m(+2) [-1]: 8κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res_optimize = wfn1.optimize()\n", "wfn1" ] }, { "cell_type": "markdown", "id": "669f3a6a", "metadata": {}, "source": [ "> Note: OptiWindNet works properly without borders/obstacles also." ] }, { "cell_type": "markdown", "id": "af7ea1dd", "metadata": {}, "source": [ "### 2. Obstacles intersecting with the exterior borders" ] }, { "cell_type": "markdown", "id": "2a3bf5dd", "metadata": {}, "source": [ "Let's create an instance of WindFarmNetwork directly via coordinates to have full control over border/obstacle definition." ] }, { "cell_type": "code", "execution_count": 7, "id": "bfeef076", "metadata": {}, "outputs": [], "source": [ "turbinesC = np.array([\n", " [ 316976, 6175410],\n", " [ 316998, 6175380],\n", " [ 316965, 6175368],\n", " [ 316997, 6175347],\n", " [ 316967 , 6175314],\n", " [ 317009 , 6175267],\n", " [ 317044, 6175282],\n", " [ 316994 , 6175296],\n", " [ 317065, 6175335],\n", " [ 317030, 6175318],\n", " [ 317029 , 6175366],\n", " [ 317026, 6175401],\n", " [ 317057, 6175379],\n", " [ 317085, 6175354],\n", " [ 317068, 6175406],\n", " [ 317144, 6175403],\n", " [ 317115, 6175342],\n", " [ 317091, 6175320],\n", " [ 317240, 6175259],\n", " [ 317111 , 6175293],\n", " [ 317126, 6175262],\n", " [ 317152, 6175320],\n", " [ 317102, 6175385],\n", " [ 317179, 6175383],\n", " [ 317143, 6175367],\n", " [ 317223, 6175399],\n", " [ 317222, 6175358],\n", " [ 317185, 6175347],\n", " [ 317208, 6175323],\n", " [ 317188, 6175299],\n", " [ 317205, 6175270],\n", " [ 317231, 6175296],\n", " [ 317272, 6175287],\n", " [ 317244, 6175340],\n", " [ 317283, 6175321],\n", " [ 317285, 6175360],\n", " [ 316960, 6175270],\n", " [ 317253, 6175380],\n", " [ 317287, 6175397],\n", " [ 317152, 6175286],\n", " ])\n", "\n", "borderC = np.array([\n", " [316956, 6175267],\n", " [317022, 6175265],\n", " [317043, 6175275],\n", " [317059 , 6175295],\n", " [317068, 6175322],\n", " [317069, 6175349],\n", " [317090, 6175348],\n", " [317086, 6175262],\n", " [317153, 6175259],\n", " [317157, 6175346],\n", " [317178 , 6175345],\n", " [317177, 6175316],\n", " [317184, 6175289],\n", " [317199, 6175268],\n", " [317218, 6175256],\n", " [317240, 6175256],\n", " [317260, 6175266],\n", " [317276, 6175286],\n", " [317285, 6175312],\n", " [317289, 6175399],\n", " [317242, 6175401],\n", " [317239, 6175319],\n", " [317238, 6175312],\n", " [317235, 6175308],\n", " [317232, 6175305],\n", " [317229, 6175305],\n", " [317226, 6175308],\n", " [317224, 6175313],\n", " [317223, 6175319],\n", " [317227, 6175402],\n", " [316963, 6175413],\n", " ])\n", "\n", "obstaclesC_ = [\n", " np.array([\n", " [316998, 6175301],\n", " [317001 , 6175376],\n", " [317013, 6175375],\n", " [317021, 6175369],\n", " [317026, 6175359],\n", " [317029, 6175345],\n", " [317029, 6175330],\n", " [317025, 6175316],\n", " [317019, 6175306],\n", " [317011, 6175301],\n", " ]),\n", " np.array([\n", " [316920, 6175300],\n", " [316920, 6175400],\n", " [316950, 6175400],\n", " [316950, 6175300],\n", " ]),\n", " np.array([\n", " [317100, 6175450],\n", " [317100, 6175400],\n", " [317080, 6175400],\n", " [317080, 6175450],\n", " ]),\n", " ]\n", "\n", "substationsC = np.array([\n", " [317167 , 6175351]])" ] }, { "cell_type": "code", "execution_count": 8, "id": "e74498a4", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn2 = WindFarmNetwork(turbinesC=turbinesC, substationsC=substationsC, borderC=borderC, obstacleC_=obstaclesC_, cables=7)\n", "wfn2" ] }, { "cell_type": "code", "execution_count": 9, "id": "955c4d56", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 1 712.4 m(+1) [-1]: 7κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res_optimize = wfn2.optimize()\n", "wfn2" ] }, { "cell_type": "markdown", "id": "ca61cc80", "metadata": {}, "source": [ "We can use `.merge_obstacles_into_border()` to refine the borders, simplify the boundary constraints and remove irrelevant obstacles." ] }, { "cell_type": "code", "execution_count": 10, "id": "19171ff2", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Obstacle at index 1 is completely outside the border and is neglected.\n", "Obstacle at index 2 intersects with the exteriour border and is merged into the exterior border.\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 1 712.1 m(+1) [-1]: 7κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn2.merge_obstacles_into_border()\n", "res_optimize = wfn2.optimize()\n", "wfn2" ] }, { "cell_type": "markdown", "id": "94cee1a3", "metadata": {}, "source": [ "## Buffering\n", "After initializing the WindFarmNetwork, a buffer can be applied to borders and obstacles via the `.add_buffer()` method. The exterior border will be expanded, while interior obstacles will be shrunk accordingly." ] }, { "cell_type": "markdown", "id": "720bd420", "metadata": {}, "source": [ "Initialize `WindFarmNetwork` instance" ] }, { "cell_type": "code", "execution_count": 11, "id": "8b234771", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 1 647.1 m(+2) [-1]: 8κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn3 = WindFarmNetwork.from_pbf(filepath='data/DTU_letters.osm.pbf', cables=7)\n", "res_optimize = wfn3.optimize()\n", "wfn3" ] }, { "cell_type": "markdown", "id": "b4f7bcce", "metadata": {}, "source": [ "apply buffering to `wfn3`." ] }, { "cell_type": "code", "execution_count": 12, "id": "308c5173", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "The defined border is non-convex and buffering may introduce unexpected changes. For visual comparison use plot_original_vs_buffered().\n" ] }, { "data": { "image/svg+xml": [ "Σλ = 1 702.6 m(+1) [-1]: 7κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn3.add_buffer(buffer_dist=5)\n", "res_optimize = wfn3.optimize()\n", "wfn3" ] }, { "cell_type": "markdown", "id": "edb3d90d-5939-437f-b286-a06ed0bd945d", "metadata": {}, "source": [ "Original vs buffered border/obstacles can be visualized using plot_original_vs_buffered()" ] }, { "cell_type": "code", "execution_count": 13, "id": "52dac514", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " image/svg+xml\n", " \n", " \n", " OptiWindNet\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Original and Buffered Shapes\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Original Border\n", " \n", " \n", " \n", " \n", " \n", " Original Obstacle\n", " \n", " \n", " \n", " \n", " \n", " Buffered Border\n", " \n", " \n", " \n", " \n", " \n", " Buffered Obstacle\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "wfn3.plot_original_vs_buffered();" ] }, { "cell_type": "markdown", "id": "2afef74e", "metadata": {}, "source": [ "### Removal of a concavity\n", "In this case a message is printed out, providing information about the potential changes in the border." ] }, { "cell_type": "code", "execution_count": 14, "id": "2bd324eb", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "The defined border is non-convex and buffering may introduce unexpected changes. For visual comparison use plot_original_vs_buffered().\n" ] } ], "source": [ "wfn4 = WindFarmNetwork.from_pbf(filepath='data/DTU_letters.osm.pbf', cables=7)\n", "wfn4.add_buffer(buffer_dist=10)" ] }, { "cell_type": "markdown", "id": "5d481a21", "metadata": {}, "source": [ "Plotting original vs buffered borders confirms that one of the concavities is removed after buffering." ] }, { "cell_type": "code", "execution_count": 15, "id": "c583e0d2", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " image/svg+xml\n", " \n", " \n", " OptiWindNet\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Original and Buffered Shapes\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Original Border\n", " \n", " \n", " \n", " \n", " \n", " Original Obstacle\n", " \n", " \n", " \n", " \n", " \n", " Buffered Border\n", " \n", " \n", " \n", " \n", " \n", " Buffered Obstacle\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "wfn4.plot_original_vs_buffered();" ] }, { "cell_type": "markdown", "id": "fbbe3176", "metadata": {}, "source": [ "**Optimize**\n", "\n", "The optimized network might change and use new routes after buffering." ] }, { "cell_type": "code", "execution_count": 16, "id": "1806e2b5", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 1 577.4 m(+1) [-1]: 7κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res_optimize = wfn4.optimize()\n", "wfn4" ] }, { "cell_type": "markdown", "id": "f3f5d1ac", "metadata": {}, "source": [ "### Removal of an obstacle" ] }, { "cell_type": "code", "execution_count": 17, "id": "319644b3", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "The defined border is non-convex and buffering may introduce unexpected changes. For visual comparison use plot_original_vs_buffered().\n", "Buffering by 15.00 completely removed the obstacle at index 0. For visual comparison use plot_original_vs_buffered().\n" ] } ], "source": [ "wfn5 = WindFarmNetwork.from_pbf(filepath='data/DTU_letters.osm.pbf', cables=7)\n", "wfn5.add_buffer(buffer_dist=15)" ] }, { "cell_type": "markdown", "id": "1882cf0a", "metadata": {}, "source": [ "Plotting original vs buffered borders confirms that obstacle (inside D letter) is removed after buffering." ] }, { "cell_type": "code", "execution_count": 18, "id": "05465845", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "\n", "\n", "\n", " \n", " \n", " \n", " \n", " image/svg+xml\n", " \n", " \n", " OptiWindNet\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Original and Buffered Shapes\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " Original Border\n", " \n", " \n", " \n", " \n", " \n", " Original Obstacle\n", " \n", " \n", " \n", " \n", " \n", " Buffered Border\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "\n" ], "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "wfn5.plot_original_vs_buffered();" ] }, { "cell_type": "markdown", "id": "82ab5351", "metadata": {}, "source": [ "**Optimize**\n", "\n", "The optimized network might change and use new routes after buffering." ] }, { "cell_type": "code", "execution_count": 19, "id": "12b7adf6", "metadata": {}, "outputs": [ { "data": { "image/svg+xml": [ "Σλ = 1 577.4 m(+1) [-1]: 7κ = 7, T = 40" ], "text/plain": [ "" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "wfn5.optimize()\n", "wfn5" ] }, { "cell_type": "markdown", "id": "1c43d62a", "metadata": {}, "source": [ "### Turbines outside the border or inside the obstacles\n", "\n", "When `wfn.optimize()` is called, it first checks if the all turbines are within the allowed area and not inside any exclusion zone. A **ValueError** exception is raised if this is not the case." ] }, { "cell_type": "code", "execution_count": 20, "id": "3fdb9fbc", "metadata": {}, "outputs": [], "source": [ "turbinesC = np.array([\n", " [0, 0],\n", " [ 316976, 6175410],\n", " [ 316998, 6175380],\n", " ])\n", "\n", "borderC = np.array([\n", " [316956, 6175267],\n", " [317022, 6175265],\n", " [317043, 6175275],\n", " [317059 , 6175295],\n", " [317068, 6175322],\n", " [317069, 6175349],\n", " [317090, 6175348],\n", " [317086, 6175262],\n", " [317153, 6175259],\n", " [317157, 6175346],\n", " [317178 , 6175345],\n", " [317177, 6175316],\n", " [317184, 6175289],\n", " [317199, 6175268],\n", " [317218, 6175256],\n", " [317240, 6175256],\n", " [317260, 6175266],\n", " [317276, 6175286],\n", " [317285, 6175312],\n", " [317289, 6175399],\n", " [317242, 6175401],\n", " [317239, 6175319],\n", " [317238, 6175312],\n", " [317235, 6175308],\n", " [317232, 6175305],\n", " [317229, 6175305],\n", " [317226, 6175308],\n", " [317224, 6175313],\n", " [317223, 6175319],\n", " [317227, 6175402],\n", " [316963, 6175413],\n", " ])\n", "\n", "substationsC = np.array([\n", " [317167 , 6175351]])" ] }, { "cell_type": "code", "execution_count": 21, "id": "cc1b2043-8b01-46fa-b0b4-387bd110a959", "metadata": {}, "outputs": [], "source": [ "wfn6 = WindFarmNetwork(\n", " turbinesC=turbinesC,\n", " substationsC=substationsC,\n", " borderC=borderC,\n", " obstacleC_=obstaclesC_,\n", " cables=7,\n", ")" ] }, { "cell_type": "code", "execution_count": 22, "id": "a4757a44", "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "Turbine out of bounds!", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mValueError\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[23]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m wfn6.optimize()\n", "\u001b[36mFile \u001b[39m\u001b[32m~/docs/git/OptiWindNet.git/build/__editable__.optiwindnet-0.2.2.dev82+g4d9174546-py3-none-any/optiwindnet/api.py:602\u001b[39m, in \u001b[36mWindFarmNetwork.optimize\u001b[39m\u001b[34m(self, turbinesC, substationsC, router, verbose)\u001b[39m\n\u001b[32m 598\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m 599\u001b[39m warmstart = {}\n\u001b[32m 601\u001b[39m \u001b[38;5;28mself\u001b[39m._S, \u001b[38;5;28mself\u001b[39m._G = router.route(\n\u001b[32m--> \u001b[39m\u001b[32m602\u001b[39m P=\u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43mP\u001b[39;49m,\n\u001b[32m 603\u001b[39m A=\u001b[38;5;28mself\u001b[39m.A,\n\u001b[32m 604\u001b[39m cables=\u001b[38;5;28mself\u001b[39m.cables,\n\u001b[32m 605\u001b[39m cables_capacity=\u001b[38;5;28mself\u001b[39m.cables_capacity,\n\u001b[32m 606\u001b[39m verbose=verbose,\n\u001b[32m 607\u001b[39m **warmstart,\n\u001b[32m 608\u001b[39m )\n\u001b[32m 609\u001b[39m \u001b[38;5;28mself\u001b[39m._is_stale_SG = \u001b[38;5;28;01mFalse\u001b[39;00m\n\u001b[32m 611\u001b[39m terse_links = \u001b[38;5;28mself\u001b[39m.terse_links()\n", "\u001b[36mFile \u001b[39m\u001b[32m~/docs/git/OptiWindNet.git/build/__editable__.optiwindnet-0.2.2.dev82+g4d9174546-py3-none-any/optiwindnet/api.py:267\u001b[39m, in \u001b[36mWindFarmNetwork.P\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 265\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mTriangular mesh over `L` (navigation mesh).\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 266\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._is_stale_PA:\n\u001b[32m--> \u001b[39m\u001b[32m267\u001b[39m \u001b[30;43mself\u001b[39;49m\u001b[30;43m.\u001b[39;49m\u001b[30;43m_refresh_planar\u001b[39;49m\u001b[30;43m(\u001b[39;49m\u001b[30;43m)\u001b[39;49m\n\u001b[32m 268\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m._P\n", "\u001b[36mFile \u001b[39m\u001b[32m~/docs/git/OptiWindNet.git/build/__editable__.optiwindnet-0.2.2.dev82+g4d9174546-py3-none-any/optiwindnet/api.py:226\u001b[39m, in \u001b[36mWindFarmNetwork._refresh_planar\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 222\u001b[39m out_of_bounds -= obstacle.exterior\n\u001b[32m 223\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m out_of_bounds.is_empty:\n\u001b[32m 224\u001b[39m \u001b[38;5;66;03m# TODO: if relevant, get coordinates of turbines from out_of_bounds\u001b[39;00m\n\u001b[32m 225\u001b[39m \u001b[38;5;66;03m# print(list(out_of_bounds.geoms))\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m226\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33m'\u001b[39m\u001b[33mTurbine out of bounds!\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m 227\u001b[39m \u001b[38;5;28mself\u001b[39m._P, \u001b[38;5;28mself\u001b[39m._A = make_planar_embedding(\u001b[38;5;28mself\u001b[39m._L)\n\u001b[32m 228\u001b[39m \u001b[38;5;28mself\u001b[39m._is_stale_PA = \u001b[38;5;28;01mFalse\u001b[39;00m\n", "\u001b[31mValueError\u001b[39m: Turbine out of bounds!" ] } ], "source": [ "wfn6.optimize()" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }