{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Some experiments on a 5 substations test case\n", "Try me out interactively with: [![Binder](./img/badge_logo.svg)](https://mybinder.org/v2/gh/rte-france/Grid2Op/master)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To demonstrate the use of the grid2op framework, we propose here to show how to make some quick studies on a purely fictious test case, a 5 bus system.\n", "\n", "This system should not be used for deep research purpose. It is provided here as an example and a tool to get used to how some analyses can be performed using grid2op." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First, we can create a environment:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import grid2op\n", "from tqdm.notebook import tqdm # for easy progress bar\n", "from grid2op.PlotGrid import PlotMatplot\n", "env = grid2op.make(\"rte_case5_example\", test=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Inspect the powergrid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In grid2op, to make more concrete the powergrid, we also added some visual capabilities to represent, for example, the names of the objects on the grid, or the thermal limit, or any other data you want. All of that is for now only available in the matplotlib \"plot helper\" and can be accessed as followed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting the layout of the graph\n", "This utility function allows you to visualize where are the object located on the map. Each object has its own color, and is represented with its name and its id (id starts at 0, following python convention)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plot_helper = PlotMatplot(env.observation_space)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_ = plot_helper.plot_layout()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Visualizing data on the grid" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is, with the same method, also possible to visualize any data on the powergrid, for example, we can inspect the thermal limit (line property) as follow:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_ = plot_helper.plot_info(line_values=env._thermal_limit_a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, it is possible to display some data about the generators, for example the maximum value of power they can produce." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_ = plot_helper.plot_info(gen_values=env.gen_pmax)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course we can also project on the powergrid some information about the loads, for example their ID" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_ = plot_helper.plot_info(load_values=[el for el in range(env.n_load)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create an agent" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can see how well the \"do nothing\" agent (the most basic imaginable) can performe, using some \"gym like\" methods" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from grid2op.Agent import DoNothingAgent\n", "my_agent = DoNothingAgent(env.action_space)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now do the standard gym loop, and we save all the observations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_obs = []\n", "obs = env.reset()\n", "all_obs.append(obs)\n", "reward = env.reward_range[0]\n", "done = False\n", "nb_step = 0\n", "with tqdm(total=env.chronics_handler.max_timestep()) as pbar:\n", " while True:\n", " action = my_agent.act(obs, reward, done)\n", " obs, reward, done, _ = env.step(action)\n", " pbar.update(1)\n", " if done:\n", " break\n", " all_obs.append(obs)\n", " nb_step += 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can check if the episode has been completed, or if there has been a game over:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Number of timesteps computed: {}\".format(nb_step))\n", "print(\"Total maximum number of timesteps possible: {}\".format(env.chronics_handler.max_timestep()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we see here, there is a game over: the agent successfully managed 94 timesteps, while the episode could have lasted 2016.\n", "\n", "Let's try to investigate this, for example by plotting the last observation. First we need to create a utilities that will make the plot:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "last_obs = all_obs[-1]\n", "_ = plot_helper.plot_obs(last_obs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, the last obsevation is pretty clear: 4 powerlines have been disconnected, thus isolating the load on the bottom right. This lead to a game over. \n", "\n", "It's also possible, of course, to inspect the previous state, just before this one:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "previous_obs = all_obs[-2]\n", "_ = plot_helper.plot_obs(previous_obs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we can know the cause for this problem: all the powerlines that could provide power on the bottom right load are overloaded in this situation, so the protection worked and disconnect them to prevent hurting the surroundings." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Highly non linear, non local effects\n", "\n", "The previous case was particularly suited to get started with the problem adressed by the grid2op platform. On this second section we will show what is the principal way of acting on a grid and illustrate why it is rather difficult to do so.\n", "\n", "For that we will use the \"rte_case14_realistic\" grid showed bellow" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "env_14 = grid2op.make(\"rte_case14_realistic\", test=True)\n", "plot_helper_14 = PlotMatplot(env_14.observation_space)\n", "_ = plot_helper_14.plot_layout()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's, like before, plot an observation" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "obs_before = env_14.reset()\n", "_ = plot_helper_14.plot_obs(obs_before)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As stated in the previous notebooks, there are 2 main types of actions in grid2op: action that consists in changing the status of the powerlines. Note that connecting / disconnecting powerline has a global, really non linear impact on the powergrid as illustrated below, when we disconnect the powerline of id `17` going from substation `4` to substations `5`. \n", "\n", "The way we interact with the environment is described in detail in notebook [3_Action_GridManipulation](3_Action_GridManipulation.ipynb), so we focus here only on the consequences of these actions." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "act = env_14.action_space.disconnect_powerline(line_name='4_5_17')\n", "obs_after, reward, done, info = env_14.step(act)\n", "_ = plot_helper_14.plot_obs(obs_after)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can have a \"quick\" look on the effect of this action. \n", "\n", "First let's look at the bottom right part of the grid. We can see that flow there did not change too much:\n", "\n", "|origin | extremity | flow before | flow after |\n", "|-------|-----------|-------------|------------|\n", "| 0 | 1 | 46.01% |43.42%|\n", "| 0 | 4 | 36.85% |33.96%|\n", "| 1 | 4 | 77.39% |71.06%|\n", "| 1 | 2 | 28.35% |28.43%|\n", "| 1 | 3 | 40.10% |42.33%|\n", "| 2 | 3 | 15.65% |17.80%|\n", "| 4 | 3 | 36.42% |56.29%|\n", "\n", "Though some of these powerlines are really close (in terms of graph distance) they don't seemed to be impacted too much (especially powerlines going from 0 to 4 and the one going from 1 to 4).\n", "\n", "On the other hand, if you look at the topmost part of the grid, you can spot really high differences, though these power are extremely far (in terms of graph distance \\*\\*) from the powerline disconnected (3 or 4 substations apart for some). \n", "\n", "|origin | extremity | flow before | flow after |\n", "|-------|-----------|-------------|------------|\n", "| 3 | 8 | 22.72% |37.84% |\n", "| 8 | 9 | 7.35% |144.79% (opposite direction)|\n", "| 9 | 10 | 41.52% |42.61% (opposite direction)|\n", "| 8 | 13 | 45.53% |97.78%|\n", "\n", "To recap, to recap some powerline next to the disconnected have approximately the same flows (36.85% to 33.96% for example) while some others \"really far away\"\\* are dramatically impacted by this changes, seeing their flow completely blows up from $\\approx 7\\%$ to more than $\\approx 140\\%$.\n", "\n", "\\* the maximum \"graph distance\"\\*\\* between two powerlines on this graph is 4 (between line 1->2 and 12->13 for example)\n", "\n", "\\*\\* when we mention distance on graph it's more of a figure of speech rather a true mathematical definition. We can say intuitively that the \"graph distance\" between two powerlines is the smallest on powerline i need to \"walk one\" if i want to move from one to the other.\n", "\n", "Of course, the same kind of effect can be observe by change the topology of some substations. We will not illustrate them here however." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.8.2" } }, "nbformat": 4, "nbformat_minor": 2 }