{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Interoperation with ANDES" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One of the most interesting feature of AMS is its interoperation with dynamic simulator ANDES.\n", "\n", "Interoperation includes compatible case conversion and data exchange, thus it facilitates dispatch-dynamic co-simulation using AMS and ANDES." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "import andes\n", "import ams\n", "\n", "import datetime" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Last run time: 2024-11-24 17:47:02\n", "andes:1.9.2\n", "ams:0.9.12\n" ] } ], "source": [ "print(\"Last run time:\", datetime.datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\"))\n", "\n", "print(f'andes:{andes.__version__}')\n", "print(f'ams:{ams.__version__}')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "ams.config_logger(stream_level=20)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Dispatch" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Working directory: \"/Users/jinningwang/work/ams/examples\"\n", "Parsing input file \"/Users/jinningwang/work/miniconda3/envs/amsre/lib/python3.12/site-packages/ams/cases/ieee14/ieee14_uced.xlsx\"...\n", "Input file parsed in 0.0261 seconds.\n", "System set up in 0.0016 seconds.\n" ] } ], "source": [ "sp = ams.load(ams.get_case('ieee14/ieee14_uced.xlsx'),\n", " setup=True,\n", " no_output=True,)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Building system matrices\n", "Parsing OModel for \n", "Evaluating OModel for \n", "Finalizing OModel for \n", " initialized in 0.0106 seconds.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.RTED.init()" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " solved as optimal in 0.0115 seconds, converged in 10 iterations with CLARABEL.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.RTED.run(solver='CLARABEL')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Convert to ANDES" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The built-in ANDES interface can convert an AMS case to ANDES case in memory.\n", "\n", "The bridge between AMS and converted ANDES is the shared power flow devices, Bus, PQ, PV, Slack, Line, and Shunt." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "> Reloaded generated Python code of module \"pycode\".\n", "Generated code for is stale.\n", "Numerical code generation (rapid incremental mode) started...\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Generating code for 3 models on 12 processes.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "Saved generated pycode to \"/Users/jinningwang/.andes/pycode\"\n", "> Reloaded generated Python code of module \"pycode\".\n", "Generated numerical code for 3 models in 0.4299 seconds.\n", "Parsing additional file \"/Users/jinningwang/work/miniconda3/envs/amsre/lib/python3.12/site-packages/andes/cases/ieee14/ieee14_full.xlsx\"...\n", "Following PFlow models in addfile will be overwritten: , , , , , , \n", "Addfile parsed in 0.0278 seconds.\n", "System converted to ANDES in 0.5277 seconds.\n", "AMS system 0x32344ab70 is linked to the ANDES system 0x32344a060.\n", "System internal structure set up in 0.0179 seconds.\n", "> Reloaded generated Python code of module \"pycode\".\n", "System internal structure set up in 0.0140 seconds.\n", "Parsing OModel for \n", "Evaluating OModel for \n", "Finalizing OModel for \n", "-> System connectivity check results:\n", " No islanded bus detected.\n", " System is interconnected.\n", " Each island has a slack bus correctly defined and enabled.\n", "\n", "-> Power flow calculation\n", " Numba: Off\n", " Sparse solver: KLU\n", " Solution method: NR method\n", "Power flow initialized in 0.0020 seconds.\n", "0: |F(x)| = 0.7340879087\n", "1: |F(x)| = 0.01697227038\n", "2: |F(x)| = 3.214367857e-05\n", "3: |F(x)| = 1.533653204e-10\n", "Converged in 4 iterations in 0.0027 seconds.\n", "-> System connectivity check results:\n", " No islanded bus detected.\n", " System is interconnected.\n", " Each island has a slack bus correctly defined and enabled.\n", "\n", "-> Power flow calculation\n", " Numba: Off\n", " Sparse solver: KLU\n", " Solution method: NR method\n", "Power flow initialized in 0.0019 seconds.\n", "0: |F(x)| = 0.7340879087\n", "1: |F(x)| = 0.01697227038\n", "2: |F(x)| = 3.214367857e-05\n", "3: |F(x)| = 1.533653204e-10\n", "Converged in 4 iterations in 0.0023 seconds.\n", "Power flow results are consistent.\n" ] } ], "source": [ "sa = sp.to_andes(setup=True,\n", " addfile=andes.get_case('ieee14/ieee14_full.xlsx'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you wish to add devices to the converted ANDES system, set `setup=False` to skip the ANDES setup process.\n", "\n", "As indicated by the output information, in the conversion process, ANDES power flow devices will be overwritten by AMS ones, if exists.\n", "\n", "Upon a successful conversion, you are ready to enjoy full capability of ANDES." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``help`` command can give a quick reference." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on method to_andes in module ams.system:\n", "\n", "to_andes(setup=True, addfile=None, **kwargs) method of ams.system.System instance\n", " Convert the AMS system to an ANDES system.\n", "\n", " A preferred dynamic system file to be added has following features:\n", " 1. The file contains both power flow and dynamic models.\n", " 2. The file can run in ANDES natively.\n", " 3. Power flow models are in the same shape as the AMS system.\n", " 4. Dynamic models, if any, are in the same shape as the AMS system.\n", "\n", " Parameters\n", " ----------\n", " setup : bool, optional\n", " Whether to call `setup()` after the conversion. Default is True.\n", " addfile : str, optional\n", " The additional file to be converted to ANDES dynamic mdoels.\n", " **kwargs : dict\n", " Keyword arguments to be passed to `andes.system.System`.\n", "\n", " Returns\n", " -------\n", " andes : andes.system.System\n", " The converted ANDES system.\n", "\n", " Examples\n", " --------\n", " >>> import ams\n", " >>> import andes\n", " >>> sp = ams.load(ams.get_case('ieee14/ieee14_rted.xlsx'), setup=True)\n", " >>> sa = sp.to_andes(setup=False,\n", " ... addfile=andes.get_case('ieee14/ieee14_wt3.xlsx'),\n", " ... overwrite=True, no_keep=True, no_output=True)\n", "\n" ] } ], "source": [ "help(sp.to_andes)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interoperation with ANDES" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the interface class ``dyn``, the link table is stored in ``dyn.link``.\n", "\n", "It describes the mapping relationships between power flow devices and dynamic devices." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\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", " \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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
stg_idxbus_idxsyg_idxgov_idxdg_idxrg_idxgammapgammaq
0Slack_11GENROU_1TGOV1_1NaNNaN1.01.0
1PV_58GENROU_5TGOV1_5NaNNaN1.01.0
2PV_46GENROU_4TGOV1_4NaNNaN1.01.0
3PV_33GENROU_3TGOV1_3NaNNaN1.01.0
4PV_22GENROU_2TGOV1_2NaNNaN1.01.0
\n", "
" ], "text/plain": [ " stg_idx bus_idx syg_idx gov_idx dg_idx rg_idx gammap gammaq\n", "0 Slack_1 1 GENROU_1 TGOV1_1 NaN NaN 1.0 1.0\n", "1 PV_5 8 GENROU_5 TGOV1_5 NaN NaN 1.0 1.0\n", "2 PV_4 6 GENROU_4 TGOV1_4 NaN NaN 1.0 1.0\n", "3 PV_3 3 GENROU_3 TGOV1_3 NaN NaN 1.0 1.0\n", "4 PV_2 2 GENROU_2 TGOV1_2 NaN NaN 1.0 1.0" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.dyn.link" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Send" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As there is a gap between DC-based dispatch and AC-based TDS, a conversion is required to ensure the TDS initialization." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Parsing OModel for \n", "Evaluating OModel for \n", "Finalizing OModel for \n", " initialized in 0.0032 seconds.\n", " solved in 0.1401 seconds, converged in 12 iterations with PYPOWER-PIPS.\n", "Parsing OModel for \n", " converted to AC.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.RTED.dc2ac()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the RTED routine, there are two mapping dictionaries to define the data exchange, namely, `map1` for receiving data from ANDES and `map2` for sending data to ANDES." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('vBus', ('Bus', 'v0')),\n", " ('ug', ('StaticGen', 'u')),\n", " ('pg', ('StaticGen', 'p0'))])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.RTED.map2" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Send results to ANDES <0x32344a060>...\n", "*Send to StaticGen.v0\n", "Send to Bus.v0\n", "Send to StaticGen.u\n", "Send to StaticGen.p0\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.dyn.send(adsys=sa, routine='RTED')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Run ANDES" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes, the ANDES TDS initialization may fail due to inapproriate limits.\n", "\n", "Here, we alleviate the `TGOV1` limit issue by enlarging the `Pmax` and `Pmin` to the same value." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "sa.TGOV1.alter(src='VMAX', idx=sa.TGOV1.idx.v, value=100*np.ones(sa.TGOV1.n))\n", "sa.TGOV1.alter(src='VMIN', idx=sa.TGOV1.idx.v, value=np.zeros(sa.TGOV1.n))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Run power flow." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "-> System connectivity check results:\n", " No islanded bus detected.\n", " System is interconnected.\n", " Each island has a slack bus correctly defined and enabled.\n", "\n", "-> Power flow calculation\n", " Numba: Off\n", " Sparse solver: KLU\n", " Solution method: NR method\n", "Power flow initialized in 0.0080 seconds.\n", "0: |F(x)| = 0.7743935696\n", "1: |F(x)| = 0.01847784692\n", "2: |F(x)| = 3.493405927e-05\n", "3: |F(x)| = 1.193747323e-10\n", "Converged in 4 iterations in 0.0125 seconds.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sa.PFlow.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try to init TDS." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Initialization for dynamics completed in 0.0198 seconds.\n", "Initialization was successful.\n" ] } ], "source": [ "_ = sa.TDS.init()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Run TDS." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\n", "-> Time Domain Simulation Summary:\n", "Sparse Solver: KLU\n", "Simulation time: 0.0-20.0 s.\n", "Fixed step size: h=33.33 ms. Shrink if not converged.\n", "Simulation to t=20.00 sec completed in 0.2986 seconds.\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sa.TDS.config.no_tqdm = True # disable progress bar\n", "sa.TDS.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Receive" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "OrderedDict([('ug', ('StaticGen', 'u')), ('pg0', ('StaticGen', 'p'))])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.RTED.map1" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Receive from SynGen.u\n", "Receive from SynGen.Pe\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.dyn.receive(adsys=sa, routine='RTED')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The RTED parameter ``pg0``, is retrieved from ANDES as the corresponding generator output power." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([1.79503641, 0.48417982, 0.01000094, 0.02000094, 0.01000095])" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sp.RTED.pg0.v" ] } ], "metadata": { "kernelspec": { "display_name": "amsre", "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.0" }, "orig_nbformat": 4 }, "nbformat": 4, "nbformat_minor": 2 }