{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Wind sector management" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In this example we switch off, derate or boost turbines according to wind conditions. Here are our imports: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "import foxes\n", "import foxes.variables as FV\n", "import foxes.constants as FC" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Our wind conditions come from the Bremen wind rose (part of `foxes`' static data):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "states = foxes.input.states.StatesTable(\n", " data_source=\"wind_rose_bremen.csv\",\n", " output_vars=[FV.WS, FV.WD, FV.TI, FV.RHO],\n", " var2col={FV.WS: \"ws\", FV.WD: \"wd\", FV.WEIGHT: \"weight\"},\n", " fixed_vars={FV.RHO: 1.225, FV.TI: 0.05},\n", ")\n", "\n", "o = foxes.output.StatesRosePlotOutput(states, point=[0., 0., 100.])\n", "fig = o.get_figure(16, FV.AMB_WS, [0, 3.5, 6, 10, 15, 20], figsize=(6, 6))\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The rules of wind sector management can either be given by a `pandas` readable file like `.csv`, or directly by a `pandas.DataFrame` object. Here we are persuing the latter option, for a wind farm that consists of two turbines, labelled `T0` and `T1`, where turbine `T1` is located east of turbine `T0`. This creates the table of rules:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "rules = pd.DataFrame(columns=[\"tname\", \"WD_min\", \"WD_max\", \"WS_min\", \"WS_max\", \"MAXP\"])\n", "rules.index.name = \"rule\"\n", "rules.loc[0] = [\"T0\", 170, 191, 3, 15, 500]\n", "rules.loc[1] = [\"T0\", 250, 290, 9, 99, 0]\n", "rules.loc[2] = [\"T0\", 340, 50, 0, 99, 0]\n", "rules.loc[3] = [\"T1\", 70, 110, 3, 99, 0]\n", "rules.loc[4] = [\"T1\", 250, 290, 9, 99, 6000]\n", "rules" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Note that we can add multiple rules per turbine. Additional conditions on ranges of other variables can be added in addition to `WD` and `WS` by simply adding the corresponsing columns with min and max data.\n", "\n", "The final column `MAXP` defines the values of the state-turbine variable that should be set if the current wind conditions fulfill the formulated range conditions. It is possible to add more variables by adding the corresponding columns to the table.\n", "\n", "Let's setup the model book, featuring the `SectorManagement` turbine model based on the above rules:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mbook = foxes.models.ModelBook()\n", "ttype = foxes.models.turbine_types.PCtFile(\"NREL-5MW-D126-H90.csv\")\n", "mbook.turbine_types[ttype.name] = ttype\n", "\n", "mbook.turbine_models[\"sector_rules\"] = foxes.models.turbine_models.SectorManagement(\n", " data_source=rules,\n", " col_tnames=\"tname\",\n", " range_vars=[FV.WD, FV.REWS],\n", " target_vars=[FV.MAX_P],\n", " colmap={\"REWS_min\": \"WS_min\", \"REWS_max\": \"WS_max\"},\n", ")" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Due to the stated ``range_vars` the model will look for columns `WD_min`, `WD_max`, `REWS_min`, `REWS_max`. The latter two have slightly different names in the DataFrame, hence the entries in the `colmap` dict. Notice that also target variable names could be mapped to other column names, if needed.\n", "\n", "Now we create the wind farm with the two wind turbines in west-east orientation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "farm = foxes.WindFarm()\n", "foxes.input.farm_layout.add_row(\n", " farm=farm,\n", " xy_base=[0.0, 0.0],\n", " xy_step=[600.0, 0.0],\n", " n_turbines=2,\n", " turbine_models=[ttype.name, \"sector_rules\", \"PMask\"],\n", ")\n", "\n", "ax = foxes.output.FarmLayoutOutput(farm).get_figure(figsize=(4, 3))\n", "plt.show(ax.get_figure())" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The turbine model `PMask` was added in order to evaluate the variable `MAXP` that was set by the `sector_rules` model. It is responsible for switching off, derating or boosting turbines, cf. example `Power mask`." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Now let's create an algorithm object and run the case:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "algo = foxes.algorithms.Downwind(\n", " mbook,\n", " farm,\n", " states=states,\n", " rotor_model=\"centre\",\n", " wake_models=[\"Bastankhah2014_linear_k002\"],\n", " wake_frame=\"rotor_wd\",\n", " partial_wakes_model=\"auto\",\n", " chunks={FC.STATE: 500},\n", " verbosity=0,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "farm_results = algo.calc_farm()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The effect of the rules is best visualized in rose plots for the two turbines:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "o = foxes.output.RosePlotOutput(farm_results)\n", "fig = o.get_figure(\n", " 16,\n", " FV.P,\n", " [100, 1000, 2000, 4000, 5001, 7000],\n", " turbine=0,\n", " title=\"Power turbine 0\",\n", " figsize=(12, 6),\n", " rect=[0.05, 0.1, 0.4, 0.8],\n", ")\n", "\n", "o = foxes.output.RosePlotOutput(farm_results)\n", "fig = o.get_figure(\n", " 16,\n", " FV.P,\n", " [100, 1000, 2000, 4000, 5001, 7000],\n", " turbine=1,\n", " title=\"Power turbine 1\",\n", " fig=fig,\n", " rect=[0.35, 0.1, 0.8, 0.8],\n", ")\n", "plt.show()" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The wind sector management has the following effects (compare to the `rules` table above):\n", "\n", "- Turbine 0 switches off at high wind speeds for westerly wind directions\n", "- Turbine 1 is boosted for such winds\n", "- Turbine 1 switches off completely for wind from east\n", "- Turbine 0 is derated for wind from south\n", "- Turbine 0 switches off for wind from north" ] } ], "metadata": { "kernelspec": { "display_name": "foxes", "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.10" }, "vscode": { "interpreter": { "hash": "67848f0d19d90e849d6febfe41e182bd0ecfb4ff4f03c83c0ab525da86fd1c48" } } }, "nbformat": 4, "nbformat_minor": 2 }