diff --git a/doc/source/api.rst b/doc/source/api.rst deleted file mode 100644 index 2e05197..0000000 --- a/doc/source/api.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _api_reference: - -============= -API reference -============= - - diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 9056741..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,124 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.autosummary', - 'sphinx.ext.githubpages', - 'sphinx.ext.intersphinx', - 'sphinx.ext.mathjax', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', - 'sphinx_panels', - 'IPython.sphinxext.ipython_directive', - 'IPython.sphinxext.ipython_console_highlighting', - 'matplotlib.sphinxext.plot_directive', - 'numpydoc', - 'sphinx_copybutton', - 'myst_nb', -] - -templates_path = ['_templates'] -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -exclude_patterns = [] - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = "en" - -# General information about the project. -project = 'AMS' -copyright = '2023, Jinning Wang' -author = 'Jinning Wang' -release = '0.4' - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = 'pydata_sphinx_theme' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -html_theme_options = { - "use_edit_page_button": True, -} - -html_context = { - "github_url": "https://github.com", - "github_user": "jinningwang", - "github_repo": "ams", - "github_version": "master", - "doc_path": "docs/source", -} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'ams' - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -# texinfo_documents = [ -# (master_doc, 'andes', 'ANDES Manual', -# author, 'andes', 'Python Software for Symbolic Power System Modeling and Numerical Analysis', -# 'Miscellaneous'), -# ] - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - 'python': ('https://docs.python.org/3/', None), - 'numpy': ('https://docs.scipy.org/doc/numpy/', None), - 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), - 'pandas': ('https://pandas.pydata.org/pandas-docs/stable', None), - 'matplotlib': ('https://matplotlib.org', None), -} - -# Favorite icon -html_favicon = 'images/curent.ico' - -# Disable smartquotes to display double dashes correctly -smartquotes = False - -# import and execute model reference generation script -exec(open("genroutineref.py").read()) - -# sphinx-panels shouldn't add bootstrap css since the pydata-sphinx-theme -# already loads it -panels_add_bootstrap_css = False diff --git a/doc/source/examples/index.rst b/doc/source/examples/index.rst deleted file mode 100644 index faed285..0000000 --- a/doc/source/examples/index.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. _scripting_examples: - -Examples -======== diff --git a/doc/source/genroutineref.py b/doc/source/genroutineref.py deleted file mode 100644 index 05cf809..0000000 --- a/doc/source/genroutineref.py +++ /dev/null @@ -1,3 +0,0 @@ -""" -This file is used to generate reStructuredText tables for Routine references. -""" \ No newline at end of file diff --git a/doc/source/getting_started/index.rst b/doc/source/getting_started/index.rst deleted file mode 100644 index 65fb479..0000000 --- a/doc/source/getting_started/index.rst +++ /dev/null @@ -1,21 +0,0 @@ - -.. raw:: html - - -

AMS

- -

- Python Library for Power System Dispatch Modeling and Dispatch-Dynamic Co-Simulation

- - -.. _getting-started: - -=============== -Getting started -=============== - -.. toctree:: - :maxdepth: 3 - :hidden: diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 988ae05..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. AMS documentation master file, created by - sphinx-quickstart on Thu Jan 26 15:32:32 2023. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -================== -AMS documentation -================== -**Useful Links**: `Source Repository`_ | `Report Issues`_ | `Q&A`_ - -.. _`Source Repository`: https://github.com/jinningwang/ams -.. _`Report Issues`: https://github.com/jinningwang/ams/issues -.. _`Q&A`: https://github.com/jinningwang/ams/discussions -.. _`LTB Repository`: https://github.com/CURENT/ltb2 - -AMS is still under DEVELOPMENT, stay tuned! - -AMS is an open-source packages for dispatch modeling and co-simulation with dynanic. - -AMS is the dispatch simulation engine for the CURENT Largescale Testbed (LTB). -More information about CURENT LTB can be found at the `LTB Repository`_. - - -.. toctree:: - :maxdepth: 3 - :caption: AMS Manual - :hidden: - - getting_started/index - examples/index - modeling/index - release-notes - api diff --git a/doc/source/modeling/index.rst b/doc/source/modeling/index.rst deleted file mode 100644 index 7cf3934..0000000 --- a/doc/source/modeling/index.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _development: - -=========== -Development -=========== - -Modeling guide for AMS. \ No newline at end of file diff --git a/doc/source/release-notes.rst b/doc/source/release-notes.rst deleted file mode 100644 index 12a4e54..0000000 --- a/doc/source/release-notes.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. _ReleaseNotes: - -============= -Release notes -============= - -The APIs before v3.0.0 are in beta and may change without prior notice. - -Pre-v1.0.0 -========== - -v0.5 (2023-02-17) -------------------- - -- Base System setup -- Development preparation - -v0.4 (2023-01) -------------------- - -This release outlines the package. \ No newline at end of file diff --git a/doc/Makefile b/docs/Makefile similarity index 72% rename from doc/Makefile rename to docs/Makefile index d0c3cbf..b4a5893 100644 --- a/doc/Makefile +++ b/docs/Makefile @@ -1,10 +1,10 @@ # Minimal makefile for Sphinx documentation # -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build +# You can set these variables from the command line. +SPHINXOPTS = "-W" # This flag turns warnings into errors. +SPHINXBUILD = sphinx-build +SPHINXPROJ = PackagingScientificPython SOURCEDIR = source BUILDDIR = build diff --git a/doc/make.bat b/docs/make.bat similarity index 76% rename from doc/make.bat rename to docs/make.bat index 061f32f..2be8306 100644 --- a/doc/make.bat +++ b/docs/make.bat @@ -9,6 +9,7 @@ if "%SPHINXBUILD%" == "" ( ) set SOURCEDIR=source set BUILDDIR=build +set SPHINXPROJ=PackagingScientificPython if "%1" == "" goto help @@ -21,15 +22,15 @@ if errorlevel 9009 ( echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ + echo.http://sphinx-doc.org/ exit /b 1 ) -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% :end popd diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt new file mode 100644 index 0000000..84bbd06 --- /dev/null +++ b/docs/requirements-rtd.txt @@ -0,0 +1,17 @@ +cvxopt +numpy +scipy +sympy +pandas +matplotlib +openpyxl +xlsxwriter +dill +pathos +tqdm +pyyaml +coloredlogs +ipython +numpydoc +sphinx-copybutton +sphinx_rtd_theme diff --git a/docs/source/_static/.placeholder b/docs/source/_static/.placeholder new file mode 100644 index 0000000..e69de29 diff --git a/docs/source/andes.rst b/docs/source/andes.rst new file mode 100644 index 0000000..39c6d43 --- /dev/null +++ b/docs/source/andes.rst @@ -0,0 +1,54 @@ +Subpackages +=========== + +.. toctree:: + + moduledoc/andes.core + moduledoc/andes.io + moduledoc/andes.models + moduledoc/andes.routines + moduledoc/andes.utils + moduledoc/andes.variables + +Submodules +========== + +andes.cli module +---------------- + +.. automodule:: andes.cli + :members: + :undoc-members: + :show-inheritance: + +andes.main module +----------------- + +.. automodule:: andes.main + :members: + :undoc-members: + :show-inheritance: + +andes.plot module +----------------- + +.. automodule:: andes.plot + :members: + :undoc-members: + :show-inheritance: + +andes.shared module +------------------- + +.. automodule:: andes.shared + :members: + :undoc-members: + :show-inheritance: + +andes.system module +------------------- + +.. automodule:: andes.system + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/cases.rst b/docs/source/cases.rst new file mode 100644 index 0000000..1dda6e4 --- /dev/null +++ b/docs/source/cases.rst @@ -0,0 +1,405 @@ +.. _cases: + +*********************** +Test Cases and Parsers +*********************** + +Directory +========= + +ANDES comes with several test cases in the ``andes/cases/`` folder. +Currently, the Kundur's 2-area system, IEEE 14-bus system, +NPCC 140-bus system, and the WECC 179-bus system has been verified +against DSATools TSAT. + +The test case library will continue to build as more models get implemented. + +A tree view of the test directory is as follows. :: + + cases/ + ├── 5bus/ + │ └── pjm5bus.xlsx + ├── GBnetwork/ + │ ├── GBnetwork.m + │ ├── GBnetwork.xlsx + │ └── README.md + ├── ieee14/ + │ ├── ieee14.dyr + │ └── ieee14.raw + ├── kundur/ + │ ├── kundur.raw + │ ├── kundur_aw.xlsx + │ ├── kundur_coi.xlsx + │ ├── kundur_coi_empty.xlsx + │ ├── kundur_esdc2a.xlsx + │ ├── kundur_esst3a.xlsx + │ ├── kundur_exdc2_zero_tb.xlsx + │ ├── kundur_exst1.xlsx + │ ├── kundur_freq.xlsx + │ ├── kundur_full.dyr + │ ├── kundur_full.xlsx + │ ├── kundur_gentrip.xlsx + │ ├── kundur_ieeeg1.xlsx + │ ├── kundur_ieeest.xlsx + │ ├── kundur_sexs.xlsx + │ └── kundur_st2cut.xlsx + ├── matpower/ + │ ├── case118.m + │ ├── case14.m + │ ├── case300.m + │ └── case5.m + ├── nordic44/ + │ ├── N44_BC.dyr + │ ├── N44_BC.raw + │ └── README.md + ├── npcc/ + │ ├── npcc.raw + │ └── npcc_full.dyr + ├── wecc/ + │ ├── wecc.raw + │ ├── wecc.xlsx + │ ├── wecc_full.dyr + │ ├── wecc_gencls.dyr + └── wscc9/ + ├── wscc9.raw + └── wscc9.xlsx + +MATPOWER Cases +============================== + +MATPOWER cases has been tested in ANDES for power flow calculation. +All following cases are calculated with the provided initial values +using the full Newton-Raphson iterative approach. + +The numerical library used for sparse matrix factorization is KLU. +In addition, Jacobians are updated in place ``spmatrix.ipadd``. +Computations are performed on macOS 10.15.4 with i9-9980H, 16 GB +2400 MHz DDR4, running ANDES 0.9.1, CVXOPT 1.2.4 and NumPy 1.18.1. + +The statistics of convergence, number of iterations, and solution time +(including equation evaluation, Jacobian, and factorization time) are +reported in the following table. +The computation time may vary depending on operating system and hardware. + ++--------------------------+------------+-----------------+----------+ +| File Name | Converged? | # of Iterations | Time [s] | ++==========================+============+=================+==========+ +| case30.m | 1 | 3 | 0.012 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg500.m | 1 | 3 | 0.019 | ++--------------------------+------------+-----------------+----------+ +| case13659pegase.m | 1 | 5 | 0.531 | ++--------------------------+------------+-----------------+----------+ +| case9Q.m | 1 | 3 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg200.m | 1 | 2 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case24_ieee_rts.m | 1 | 4 | 0.014 | ++--------------------------+------------+-----------------+----------+ +| case300.m | 1 | 5 | 0.026 | ++--------------------------+------------+-----------------+----------+ +| case6495rte.m | 1 | 5 | 0.204 | ++--------------------------+------------+-----------------+----------+ +| case39.m | 1 | 1 | 0.009 | ++--------------------------+------------+-----------------+----------+ +| case18.m | 1 | 4 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case_RTS_GMLC.m | 1 | 3 | 0.014 | ++--------------------------+------------+-----------------+----------+ +| case1951rte.m | 1 | 3 | 0.047 | ++--------------------------+------------+-----------------+----------+ +| case6ww.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case5.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case69.m | 1 | 3 | 0.014 | ++--------------------------+------------+-----------------+----------+ +| case6515rte.m | 1 | 4 | 0.168 | ++--------------------------+------------+-----------------+----------+ +| case2383wp.m | 1 | 6 | 0.084 | ++--------------------------+------------+-----------------+----------+ +| case30Q.m | 1 | 3 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case2868rte.m | 1 | 4 | 0.074 | ++--------------------------+------------+-----------------+----------+ +| case1354pegase.m | 1 | 4 | 0.047 | ++--------------------------+------------+-----------------+----------+ +| case2848rte.m | 1 | 3 | 0.063 | ++--------------------------+------------+-----------------+----------+ +| case4_dist.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case6470rte.m | 1 | 4 | 0.175 | ++--------------------------+------------+-----------------+----------+ +| case2746wp.m | 1 | 4 | 0.074 | ++--------------------------+------------+-----------------+----------+ +| case_SyntheticUSA.m | 1 | 21 | 11.120 | ++--------------------------+------------+-----------------+----------+ +| case118.m | 1 | 3 | 0.014 | ++--------------------------+------------+-----------------+----------+ +| case30pwl.m | 1 | 3 | 0.021 | ++--------------------------+------------+-----------------+----------+ +| case57.m | 1 | 3 | 0.017 | ++--------------------------+------------+-----------------+----------+ +| case89pegase.m | 1 | 5 | 0.024 | ++--------------------------+------------+-----------------+----------+ +| case6468rte.m | 1 | 6 | 0.232 | ++--------------------------+------------+-----------------+----------+ +| case2746wop.m | 1 | 4 | 0.075 | ++--------------------------+------------+-----------------+----------+ +| case85.m | 1 | 3 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case22.m | 1 | 2 | 0.008 | ++--------------------------+------------+-----------------+----------+ +| case4gs.m | 1 | 3 | 0.012 | ++--------------------------+------------+-----------------+----------+ +| case14.m | 1 | 2 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg10k.m | 1 | 4 | 0.251 | ++--------------------------+------------+-----------------+----------+ +| case2869pegase.m | 1 | 6 | 0.136 | ++--------------------------+------------+-----------------+----------+ +| case_ieee30.m | 1 | 2 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case2737sop.m | 1 | 5 | 0.087 | ++--------------------------+------------+-----------------+----------+ +| case9target.m | 1 | 5 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case1888rte.m | 1 | 2 | 0.037 | ++--------------------------+------------+-----------------+----------+ +| case145.m | 1 | 3 | 0.018 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg2000.m | 1 | 3 | 0.059 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg70k.m | 1 | 15 | 7.043 | ++--------------------------+------------+-----------------+----------+ +| case9241pegase.m | 1 | 6 | 0.497 | ++--------------------------+------------+-----------------+----------+ +| case9.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case141.m | 1 | 3 | 0.012 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg25k.m | 1 | 7 | 1.040 | ++--------------------------+------------+-----------------+----------+ +| case118.m | 1 | 3 | 0.015 | ++--------------------------+------------+-----------------+----------+ +| case1354pegase.m | 1 | 4 | 0.048 | ++--------------------------+------------+-----------------+----------+ +| case13659pegase.m | 1 | 5 | 0.523 | ++--------------------------+------------+-----------------+----------+ +| case14.m | 1 | 2 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case141.m | 1 | 3 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case145.m | 1 | 3 | 0.017 | ++--------------------------+------------+-----------------+----------+ +| case18.m | 1 | 4 | 0.012 | ++--------------------------+------------+-----------------+----------+ +| case1888rte.m | 1 | 2 | 0.037 | ++--------------------------+------------+-----------------+----------+ +| case1951rte.m | 1 | 3 | 0.052 | ++--------------------------+------------+-----------------+----------+ +| case22.m | 1 | 2 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case2383wp.m | 1 | 6 | 0.086 | ++--------------------------+------------+-----------------+----------+ +| case24_ieee_rts.m | 1 | 4 | 0.015 | ++--------------------------+------------+-----------------+----------+ +| case2736sp.m | 1 | 4 | 0.074 | ++--------------------------+------------+-----------------+----------+ +| case2737sop.m | 1 | 5 | 0.108 | ++--------------------------+------------+-----------------+----------+ +| case2746wop.m | 1 | 4 | 0.093 | ++--------------------------+------------+-----------------+----------+ +| case2746wp.m | 1 | 4 | 0.089 | ++--------------------------+------------+-----------------+----------+ +| case2848rte.m | 1 | 3 | 0.065 | ++--------------------------+------------+-----------------+----------+ +| case2868rte.m | 1 | 4 | 0.079 | ++--------------------------+------------+-----------------+----------+ +| case2869pegase.m | 1 | 6 | 0.137 | ++--------------------------+------------+-----------------+----------+ +| case30.m | 1 | 3 | 0.033 | ++--------------------------+------------+-----------------+----------+ +| case300.m | 1 | 5 | 0.102 | ++--------------------------+------------+-----------------+----------+ +| case30Q.m | 1 | 3 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case30pwl.m | 1 | 3 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case39.m | 1 | 1 | 0.008 | ++--------------------------+------------+-----------------+----------+ +| case4_dist.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case4gs.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case5.m | 1 | 3 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case57.m | 1 | 3 | 0.015 | ++--------------------------+------------+-----------------+----------+ +| case6468rte.m | 1 | 6 | 0.229 | ++--------------------------+------------+-----------------+----------+ +| case6470rte.m | 1 | 4 | 0.170 | ++--------------------------+------------+-----------------+----------+ +| case6495rte.m | 1 | 5 | 0.198 | ++--------------------------+------------+-----------------+----------+ +| case6515rte.m | 1 | 4 | 0.169 | ++--------------------------+------------+-----------------+----------+ +| case69.m | 1 | 3 | 0.012 | ++--------------------------+------------+-----------------+----------+ +| case6ww.m | 1 | 3 | 0.011 | ++--------------------------+------------+-----------------+----------+ +| case85.m | 1 | 3 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case89pegase.m | 1 | 5 | 0.020 | ++--------------------------+------------+-----------------+----------+ +| case9.m | 1 | 3 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case9241pegase.m | 1 | 6 | 0.487 | ++--------------------------+------------+-----------------+----------+ +| case9Q.m | 1 | 3 | 0.013 | ++--------------------------+------------+-----------------+----------+ +| case9target.m | 1 | 5 | 0.015 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg10k.m | 1 | 4 | 0.257 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg200.m | 1 | 2 | 0.014 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg2000.m | 1 | 3 | 0.058 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg25k.m | 1 | 7 | 1.118 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg500.m | 1 | 3 | 0.027 | ++--------------------------+------------+-----------------+----------+ +| case_ACTIVSg70k.m | 1 | 15 | 6.931 | ++--------------------------+------------+-----------------+----------+ +| case_RTS_GMLC.m | 1 | 3 | 0.014 | ++--------------------------+------------+-----------------+----------+ +| case_SyntheticUSA.m | 1 | 21 | 11.103 | ++--------------------------+------------+-----------------+----------+ +| case_ieee30.m | 1 | 2 | 0.010 | ++--------------------------+------------+-----------------+----------+ +| case3375wp.m | 0 | - | 0.061 | ++--------------------------+------------+-----------------+----------+ +| case33bw.m | 0 | - | 0.007 | ++--------------------------+------------+-----------------+----------+ +| case3120sp.m | 0 | - | 0.037 | ++--------------------------+------------+-----------------+----------+ +| case3012wp.m | 0 | - | 0.082 | ++--------------------------+------------+-----------------+----------+ +| case3120sp.m | 0 | - | 0.039 | ++--------------------------+------------+-----------------+----------+ +| case3375wp.m | 0 | - | 0.059 | ++--------------------------+------------+-----------------+----------+ +| case33bw.m | 0 | - | 0.007 | ++--------------------------+------------+-----------------+----------+ + +PSS/E Dyr Parser +================ +ANDES supporting parsing PSS/E dynamic files in the format of ``.dyr``. +Support new dynamic models can be added by editing the input and output +conversion definition file in ``andes/io/psse-dyr.yaml``, +which is in the standard YAML format. +To add support for a new dynamic model, it is recommended to start with +an existing model of similar functionality. + +Consider a ``GENCLS`` entry in a dyr file. The entry looks like :: + + 1 'GENCLS' 1 13.0000 0.000000 / + +where the fields are in the order of bus index, model name, +generator index on the bus, inertia (H) and damping coefficient (D). + +The input-output conversion definition for GENCLS is as follows :: + + GENCLS: + destination: GENCLS + inputs: + - BUS + - ID + - H + - D + find: + gen: + StaticGen: + bus: BUS + subidx: ID + get: + u: + StaticGen: + src: u + idx: gen + Sn: + StaticGen: + src: Sn + idx: gen + Vn: + Bus: + src: Vn + idx: BUS + ra: + StaticGen: + src: ra + idx: gen + xs: + StaticGen: + src: xs + idx: gen + outputs: + u: u + bus: BUS + gen: gen + Sn: Sn + Vn: Vn + D: D + M: "GENCLS.H; lambda x: 2 * x" + ra: ra + xd1: xs + +It begins with a base-level definition of the model name to be parsed from the +dyr file, namely, ``GENCLS``. Five directives can be defined for each model: +``destination``, ``inputs``, ``outputs``, ``find`` and ``get``. +Note that ``find`` and ``get`` are optional, but the other three are mandatory. + +- ``destination`` is ANDES model to which the original PSS/E model will be + converted. In this case, the ANDES model have the same name ``GENCLS``. +- ``inputs`` is a list of the parameter names for the PSS/E data. + Arbitrary names can be used, but it is recommended to use the same notation + following the PSS/E manual. +- ``outputs`` is a dictionary where the keys are the ANDES model parameter and + the values are the input parameter or lambda functions that processes the inputs + (see notes below). +- ``find`` is a dictionary with the keys being the temporary parameter name to store + the ``idx`` of + external devices and the values being the criteria to locate the devices. + In the example above, ``GENCLS`` will try to find the ``idx`` of ``StaticGen`` + with ``bus == BUS`` and the ``subidx == ID``, where ``BUS`` and ``ID`` are from + the dyr file. +- ``get`` is a dictionary with each key being a temporary parameter name for storing + an external parameter and each value being the criteria to find the external parameter. + In the example above, a temporary parameter ``u`` is the ``u`` parameter of ``StaticGen`` + whose ``idx == gen``. Note that ``gen`` is the ``idx`` of ``StaticGen`` retrieved + in the above ``find`` section. + +For the ``inputs`` section, one will need to skip the model name +because for any model, the second field is always the model name. +That is why for ``GENCLS`` below, we only list four input parameters. :: + + 1 'GENCLS' 1 13.0000 0.000000 / + +For the ``outputs`` section, the order can be arbitrary, but it is recommended +to follow the input order as much as possible for maintainability. +In particular, the right-hand-side of the outputs can be either an input parameter name +or an anonymous expression that processes the input parameters. +For the example of GENCLS, since ANDES internally uses the parameter of ``M = 2H``, +the input ``H`` needs to be multiplied by 2. +It is done by the following :: + + M: "GENCLS.H; lambda x: 2 * x" + +where the left-hand-side is the output parameter name (destination ANDES model parameter name), +and the right-hand-side is arguments and the lambda function separated by semi-colon, all in a +pair of double quotation marks. +Multiple arguments are accepted and should be separated by comma. +Arguments can come from the same model or another model. +In the case of the same model, the model name can be neglected, namely, by writing +``M: "H; lambda x: 2 * x"``. diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..cd74f6f --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# ANDES documentation build configuration file, created by +# sphinx-quickstart on Thu Jun 28 12:35:56 2018. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.githubpages', + 'sphinx.ext.intersphinx', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'IPython.sphinxext.ipython_directive', + 'IPython.sphinxext.ipython_console_highlighting', + 'matplotlib.sphinxext.plot_directive', + 'numpydoc', + 'sphinx_copybutton', +] + +# Configuration options for plot_directive. See: +# https://github.com/matplotlib/matplotlib/blob/f3ed922d935751e08494e5fb5311d3050a3b637b/lib/matplotlib/sphinxext/plot_directive.py#L81 +plot_html_show_source_link = False +plot_html_show_formats = False + +# Generate the API documentation when building +autosummary_generate = True +numpydoc_show_class_members = False + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'ANDES' +copyright = '2021, Hantao Cui' +author = 'Hantao Cui' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +import andes +# The short X.Y version. +version = andes.__version__ +# The full version, including alpha/beta/rc tags. +release = andes.__version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' +import sphinx_rtd_theme +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# This is required for the alabaster theme +# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars +html_sidebars = { + '**': [ + 'relations.html', # needs 'show_related': True theme option to display + 'searchbox.html', + ] +} + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'andes' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + 'preamble': r'\DeclareUnicodeCharacter{2588}{-}', + 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + 'pointsize': '11pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'andes.tex', 'ANDES Manual', + 'Hantao Cui', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'andes', 'ANDES Manual', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'andes', 'ANDES Manual', + author, 'andes', 'Python Software for Symbolic Power System Modeling and Numerical Analysis', + 'Miscellaneous'), +] + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = { + 'python': ('https://docs.python.org/3/', None), + 'numpy': ('https://docs.scipy.org/doc/numpy/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable', None), + 'matplotlib': ('https://matplotlib.org', None), +} + +# Favorite icon +html_favicon = 'images/curent.ico' + + +# Disable smartquotes to display double dashes correctly +smartquotes = False + +# import and execute model reference generation script +exec(open("modelref.py").read()) diff --git a/docs/source/copyright.rst b/docs/source/copyright.rst new file mode 100644 index 0000000..0f56c15 --- /dev/null +++ b/docs/source/copyright.rst @@ -0,0 +1,23 @@ +.. role:: raw-html(raw) + :format: html + +******* +License +******* + +GNU Public License v3 +********************* +| Copyright :raw-html:`©` 2015-2020 Hantao Cui. + +ANDES is free software; you can redistribute it and/or modify it under +the terms of the +`GNU General Public License `_ +as published by the Free Software Foundation; either version 3 of the +License, or (at your option) any later version. + +ANDES is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the +`GNU General Public License `_ +for more details. \ No newline at end of file diff --git a/docs/source/faq.rst b/docs/source/faq.rst new file mode 100644 index 0000000..4f1ca8d --- /dev/null +++ b/docs/source/faq.rst @@ -0,0 +1,51 @@ +.. _faq: + +************************** +Frequently Asked Questions +************************** + +General +======= + +Q: What is the Hybrid Symbolic-Numeric Framework in ANDES? + +A: It is a modeling and simulation framework that uses symbolic computation for descriptive +modeling and code generation for fast numerical simulation. +The goal of the framework is to reduce the programming efforts associated with implementing +complex models and automate the research workflow of modeling, simulation, and documentation. + +The framework reduces the modeling efforts from two aspects: +(1) allowing modeling by typing in equations, and (2) allowing modeling using modularized +control blocks and discontinuous components. +One only needs to describe the model using equations and blocks without having to write the +numerical code to implement the computation. +The framework automatically generate symbolic expressions, computes partial derivatives, +and generates vectorized numerical code. + +Modeling +======== + +Admittance matrix +----------------- + +Q: Where to find the line admittance matrix? + +A: ANDES does not build line admittance matrix for computing +line power injections. Instead, line power injections are +computed as vectors on the two line terminal. This approach +generalizes line as a power injection model. + +Q: Without admittance matrix, how to switch out lines? + +A: Lines can be switched out and in by using ``Toggler``. +See the example in ``cases/kundur/kundur_full.xlsx``. +One does not need to manually trigger a Jacobian matrix rebuild +because ``Toggler`` automatically triggers it using the new +connectivity status. + +Reference of the existing model +------------------------------- + +Q: Is there any further reference of the existing model? + +A: Most of them can be found online, such as ESIG and PowerWorld. diff --git a/doc/source/images/curent.ico b/docs/source/images/curent.ico similarity index 100% rename from doc/source/images/curent.ico rename to docs/source/images/curent.ico diff --git a/docs/source/images/diagrams/ieeest.png b/docs/source/images/diagrams/ieeest.png new file mode 100644 index 0000000..efff463 Binary files /dev/null and b/docs/source/images/diagrams/ieeest.png differ diff --git a/docs/source/images/example-kundur/efd.png b/docs/source/images/example-kundur/efd.png new file mode 100644 index 0000000..33acff2 Binary files /dev/null and b/docs/source/images/example-kundur/efd.png differ diff --git a/docs/source/images/example-kundur/omega.png b/docs/source/images/example-kundur/omega.png new file mode 100644 index 0000000..0df661f Binary files /dev/null and b/docs/source/images/example-kundur/omega.png differ diff --git a/docs/source/images/example-npcc/omega.png b/docs/source/images/example-npcc/omega.png new file mode 100644 index 0000000..17db4d4 Binary files /dev/null and b/docs/source/images/example-npcc/omega.png differ diff --git a/docs/source/images/example-tgov1/tgov1.png b/docs/source/images/example-tgov1/tgov1.png new file mode 100644 index 0000000..0cabf42 Binary files /dev/null and b/docs/source/images/example-tgov1/tgov1.png differ diff --git a/docs/source/images/example-tgov1/tgov1_class.png b/docs/source/images/example-tgov1/tgov1_class.png new file mode 100644 index 0000000..3e00991 Binary files /dev/null and b/docs/source/images/example-tgov1/tgov1_class.png differ diff --git a/docs/source/images/example-tgov1/tgov1_eqns.png b/docs/source/images/example-tgov1/tgov1_eqns.png new file mode 100644 index 0000000..ba54454 Binary files /dev/null and b/docs/source/images/example-tgov1/tgov1_eqns.png differ diff --git a/docs/source/images/example-wecc/omega.png b/docs/source/images/example-wecc/omega.png new file mode 100644 index 0000000..1ccfa20 Binary files /dev/null and b/docs/source/images/example-wecc/omega.png differ diff --git a/docs/source/images/misc/doc-screenshot.png b/docs/source/images/misc/doc-screenshot.png new file mode 100644 index 0000000..82e373a Binary files /dev/null and b/docs/source/images/misc/doc-screenshot.png differ diff --git a/docs/source/images/misc/ieeeg1-screenshot.png b/docs/source/images/misc/ieeeg1-screenshot.png new file mode 100644 index 0000000..e01dea6 Binary files /dev/null and b/docs/source/images/misc/ieeeg1-screenshot.png differ diff --git a/docs/source/images/sponsors/curent.jpg b/docs/source/images/sponsors/curent.jpg new file mode 100644 index 0000000..2eb3ec7 Binary files /dev/null and b/docs/source/images/sponsors/curent.jpg differ diff --git a/docs/source/images/sponsors/doe.png b/docs/source/images/sponsors/doe.png new file mode 100644 index 0000000..1221c2b Binary files /dev/null and b/docs/source/images/sponsors/doe.png differ diff --git a/docs/source/images/sponsors/inl.jpg b/docs/source/images/sponsors/inl.jpg new file mode 100644 index 0000000..185121c Binary files /dev/null and b/docs/source/images/sponsors/inl.jpg differ diff --git a/docs/source/images/sponsors/llnl.jpg b/docs/source/images/sponsors/llnl.jpg new file mode 100644 index 0000000..4ee693c Binary files /dev/null and b/docs/source/images/sponsors/llnl.jpg differ diff --git a/docs/source/images/sponsors/nsf.jpg b/docs/source/images/sponsors/nsf.jpg new file mode 100644 index 0000000..dbbd470 Binary files /dev/null and b/docs/source/images/sponsors/nsf.jpg differ diff --git a/docs/source/images/tutorial/xlsx-bus.png b/docs/source/images/tutorial/xlsx-bus.png new file mode 100644 index 0000000..406e36f Binary files /dev/null and b/docs/source/images/tutorial/xlsx-bus.png differ diff --git a/docs/source/images/tutorial/xlsx-pq.png b/docs/source/images/tutorial/xlsx-pq.png new file mode 100644 index 0000000..0dce10e Binary files /dev/null and b/docs/source/images/tutorial/xlsx-pq.png differ diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..9448712 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,98 @@ +.. ANDES documentation master file, created by + sphinx-quickstart on Thu Jun 21 11:11:34 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +.. raw:: html + + +

ANDES

+ +

+ Python Software for Symbolic Power System Modeling and Numerical Analysis

+ + +**** +Home +**** + +ANDES is a Python-based free software package for power system simulation, control and analysis. +It establishes a unique **hybrid symbolic-numeric framework** for modeling differential algebraic +equations (DAEs) for numerical analysis. Main features of ANDES include + +* a unique hybrid symbolic-numeric approach to modeling and simulation that enables descriptive DAE modeling and + automatic numerical code generation +* a rich library of transfer functions and discontinuous components (including limiters, dead-bands, and + saturation) available for prototyping models, which can be readily instantiated as multiple devices for + system analysis +* industry-grade second-generation renewable models (solar PV, type 3 and type 4 wind), + distributed PV and energy storage model +* comes with the Newton method for power flow calculation, the implicit trapezoidal method for time-domain + simulation, and full eigenvalue calculation +* strictly verified models with commercial software. ANDES obtains identical time-domain simulation results for + IEEE 14-bus and NPCC system with GENROU and multiple controller models. See the verification link for details. +* developed with performance in mind. While written in Python, ANDES comes with a performance package and can + finish a 20-second transient simulation of a 2000-bus system in a few seconds on a typical desktop computer +* out-of-the-box PSS/E raw and dyr file support for available models. Once a model is developed, inputs from a + dyr file can be readily supported +* an always up-to-date equation documentation of implemented models + +ANDES is currently under active development. To get involved, + +* Follow the tutorial at + `https://andes.readthedocs.io `_ +* Checkout the Notebook examples in the + `examples folder `_ +* Try ANDES in Jupyter Notebook + `with Binder `_ +* Download the PDF manual at + `download `_ +* Report issues in the + `GitHub issues page `_ +* Learn version control with + `the command-line git `_ or + `GitHub Desktop `_ +* If you are looking to develop models, read the + `Modeling Cookbook `_ + +This work was supported in part by the Engineering Research Center Program of +the National Science Foundation and the Department of Energy under NSF Award +Number EEC-1041877 and the `CURENT `_ Industry Partnership Program. +**ANDES is made open source as part of the CURENT Large Scale Testbed project.** + +ANDES is developed and actively maintained by `Hantao Cui `_. +See the GitHub repository for a full list of contributors. + +.. toctree:: + :caption: ANDES Manual + :maxdepth: 3 + :hidden: + + install.rst + tutorial.rst + modeling.rst + cases.rst + modelref.rst + configref.rst + faq.rst + troubleshooting.rst + misc.rst + release-notes.rst + copyright.rst + + +.. toctree:: + :hidden: + :caption: API References + :maxdepth: 3 + + andes.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/install.rst b/docs/source/install.rst new file mode 100644 index 0000000..02d2b4d --- /dev/null +++ b/docs/source/install.rst @@ -0,0 +1,195 @@ +.. _install: + +************************* +Installation +************************* + +ANDES can be installed in Python 3.6+. +Please follow the installation guide carefully. + +Environment +=========== + +Setting Up Miniconda +-------------------- +We recommend the Miniconda distribution that includes the conda package manager and Python. +Downloaded and install the latest Miniconda (x64, with Python 3) +from https://conda.io/miniconda.html. + +Step 1: Open terminal (on Linux or maxOS) or `Anaconda Prompt` (on Windows, **not the cmd +program!!**). +Make sure you are in a conda environment - you should see ``(base)`` prepended to the +command-line prompt, such as ``(base) C:\Users\user>``. + +Create a conda environment for ANDES (recommended) + +.. code:: bash + + conda create --name andes python=3.7 + +Activate the new environment with + +.. code:: bash + + conda activate andes + +You will need to activate the ``andes`` environment every time in a new Anaconda Prompt or +shell. + +Step 2: Add the ``conda-forge`` channel and set it as default + +.. code:: bash + + conda config --add channels conda-forge + conda config --set channel_priority flexible + +If these steps complete without an error, continue to `Install Andes`_. + +Existing Python Environment (Advanced) +-------------------------------------- +This is for advanced user only and is **not recommended on Microsoft Windows**. +Please skip it if you have set up a Conda environment. + +Instead of using Conda, if you prefer an existing Python environment, +you can install ANDES with `pip`: + +.. code:: bash + + python3 -m pip install andes + +If you see a `Permission denied` error, you will need to +install the packages locally with `--user` + +Install ANDES +============= + +ANDES can be installed in the user mode and the development mode. + +- If you want to use ANDES without modifying the source code, install it in the `User Mode`_. +- If you want to develop models or routine, install it in the `Development Mode`_. + +User Mode +--------- +.. warning :: + Please skip this section and install ANDES in the `Development Mode`_ + if you want to modify ANDES code or receive unreleased development + updates. + +The User Model installation will install the latest stable version. +In the Anaconda environment, run + +.. code:: bash + + conda install andes + +You will be prompted to confirm the installation, + +This command installs ANDES into the active environment, which should be called ``andes`` if +you followed all the above steps. + +.. note:: + To use ``andes``, you will need to activate the ``andes`` environment every time in a new Anaconda Prompt or + shell. + + +Development Mode +---------------- +This is for users who want to hack into the code and, for example, develop new models or routines. +The usage of ANDES is the same in development mode as in user mode. +In addition, changes to source code will be reflected immediately without re-installation. + +Step 1: Get ANDES source code + +As a developer, you are strongly encouraged to clone the source code using ``git`` +from either your fork or the original repository: + +.. code:: bash + + git clone https://github.com/cuihantao/andes + +In this way, you can easily update to the latest source code using ``git``. + +Alternatively, you can download the ANDES source code from +https://github.com/cuihantao/andes and extract all files to the path of your choice. +Although this will work, this is not recommended since tracking changes and pushing back code +would be painful. + +Step 2: Install dependencies + +In the Anaconda environment, use ``cd`` to change directory to the ANDES root folder. + +Install dependencies with + +.. code:: bash + + conda install --file requirements.txt + conda install --file requirements-dev.txt + +Step 3: Install ANDES in the development mode using + +.. code:: bash + + python3 -m pip install -e . + +Note the dot at the end. Pip will take care of the rest. + +Updating ANDES +============== + +Regular ANDES updates will be pushed to both ``conda-forge`` and Python package index. +It is recommended to use the latest version for bug fixes and new features. +We also recommended you to check the :ref:`ReleaseNotes` before updating to stay informed +of changes that might break your downstream code. + +Depending you how you installed ANDES, you will use one of the following ways to upgrade. + +If you installed it from conda (most common for users), run + +.. code:: bash + + conda install -c conda-forge --yes andes + +If you install it from PyPI (namely, through ``pip``), run + +.. code:: bash + + python3 -m pip install --yes andes + +If you installed ANDES from source code (in the `Development Mode`_), +and the source was cloned using ``git``, +you can use ``git pull`` to pull in changes from remote. However, if your source +code was downloaded, you will have to download the new source code again and manually +overwrite the existing one. + +In rare cases, after updating the source code, command-line ``andes`` will complain +about missing dependency. If this ever happens, it means the new ANDES has introduced +new dependencies. In such cases, reinstall andes in the development mode to fix. +Change directory to the ANDES source code folder that contains ``setup.py`` and run + +.. code:: bash + + python3 -m pip install -e . + +Performance Packages +==================== +.. note:: + + Performance packages can be safely skipped and will not affect the + functionality of ANDES. + +KVXOPT +------ + +KVXOPT is a fork of the CVXOPT with KLU by Uriel Sandoval (@sanurielf). +KVXOPT interfaces to KLU, which is +roughly 20% faster than UMFPACK for circuit simulations based on our testing. + +KVXOPT contains inplace add and set functions for sparse matrix +contributed by CURENT. +These inplace functions significantly speed up large-scale system simulations. + +To install ``KVXOPT`` run + +.. code:: bash + + python -m pip install kvxopt diff --git a/docs/source/misc.rst b/docs/source/misc.rst new file mode 100644 index 0000000..b356ebc --- /dev/null +++ b/docs/source/misc.rst @@ -0,0 +1,112 @@ +.. _misc: + +********************** +Miscellaneous +********************** + +Notes +===== + +Modeling Blocks +--------------- + +State Freeze +```````````` + +State freeze is used by converter controllers during fault transients +to fix a variable at the pre-fault values. The concept of state freeze +is applicable to both state or algebraic variables. +For example, in the renewable energy electric control model (REECA), +the proportional-integral controllers for reactive power error and voltage +error are subject to state freeze when voltage dip is observed. +The internal and output states should be frozen when the freeze signal +turns one and freed when the signal turns back to zero. + +Freezing a state variable can be easily implemented by multiplying the freeze +signal with the right-hand side (RHS) of the differential equation: + +.. math :: + T \dot{x} = (1 - z_f) \times f(x) + +where :math:`f(x)` is the original RHS of the differential equation, +and :math:`z_f` is the freeze signal. When :math:`z_f` becomes zero +the differential equation will evaluate to zero, making the increment +zero. + +Freezing an algebraic variable is more complicate to implement. +One might consider a similar solution to freezing a differential variable +by constructing a piecewise equation, for example, + +.. math:: + 0 = (1 - z_f)\times g(y) + +where :math:`g(y)` is the original RHS of the algebraic equation. +One might also need to add a small value to the diagonals of ``dae.gy`` +associated with the algebraic variable to avoid singularity. +The rationale behind this implementation is to zero out the algebraic +equation mismatch and thus stop incremental correction: +in the frozen state, since :math:`z_f` switches to zero, +the algebraic increment should be forced to zero. +This method, however, would not work when a dishonest Newton method is +used. + +If the Jacobian matrix is not updated after :math:`z_f` switches to one, +in the row associated with the equation, the derivatives will remain the +same. For the algebraic equation of the PI controller given by + +.. math:: + + 0 = (K_p u + x_i) - y + +where :math:`K_p` is the proportional gain, :math:`u` is the input, +:math:`x_I` is the integrator output, and :math:`y` is the PI controller +output, the derivatives w.r.t :math:`u`, :math:`x_i` and :math:`y` are +nonzero in the pre-frozen state. These derivative corrects :math:`y` +following the changes of :math:`u` and :math:`x`. +Although :math:`x` has been frozen, if the Jacobian is not rebuilt, +correction will still be made due to the change of :math:`u`. +Since this equation is linear, only one iteration is needed to let +:math:`y` track the changes of :math:`u`. +For nonlinear algebraic variables, this approach will likely give wrong +results, since the residual is pegged at zero. + +To correctly freeze an algebraic variable, the freezing signal needs to +be passed to an ``EventFlag``, which will set an ``custom_event`` flag +if any input changes. +``EventFlag`` is a ``VarService`` that will be evaluated at each +iteration after discrete components and before equations. + +Per Unit System +============================== + +The bases for AC system are + +- :math:`S_b^{ac}`: three-phase power in MVA. By default, :math:`S_b^{ac}=100 MVA` (in ``System.config.mva``). + +- :math:`V_b^{ac}`: phase-to-phase voltage in kV. + +- :math:`I_b^{ac}`: current base :math:`I_b^{ac} = \frac{S_b^{ac}} {\sqrt{3} V_b^{ac}}` + +The bases for DC system are + +- :math:`S_b^{dc}`: power in MVA. It is assumed to be the same as :math:`S_b^{ac}`. + +- :math:`V_b^{dc}`: voltage in kV. + +Some device parameters with specific properties are per unit values under the corresponding +device base ``Sn`` and ``Vn`` (if applicable). +These properties are documented in :py:mod:`andes.core.param.NumParam`. + +After setting up the system, these parameters will be converted to the system base MVA +as specified in the config file (100 MVA by default). +The parameter values in the system base will be stored in the ``v`` attribute of the ``NumParam``, +and the original inputs in the device base will be stored to the ``vin`` attribute. +Values in the ``v`` attribute is what get utilized in computation. +Writing new values directly to ``vin`` will not affect the values in ``v`` afterwards. + +Profiling Import +======================================== +To speed up the command-line program, import profiling is used to breakdown the program loading time. + +With tool ``profimp``, ``andes`` can be profiled with ``profimp "import andes" --html > andes_import.htm``. The +report can be viewed in any web browser. diff --git a/docs/source/modeling.rst b/docs/source/modeling.rst new file mode 100644 index 0000000..f089a5b --- /dev/null +++ b/docs/source/modeling.rst @@ -0,0 +1,1424 @@ +.. _modeling: + +***************** +Modeling Cookbook +***************** + +This chapter contains advanced topics on modeling and simulation and how they are implemented in ANDES. +It aims to provide an in-depth explanation of how the ANDES framework is set up for symbolic modeling and +numerical simulation. It also provides an example for interested users to implement customized DAE models. + +System +====== + +Overview +-------- +System is the top-level class for organizing power system models and orchestrating calculations. + +.. autoclass:: andes.system.System + :noindex: + +.. note:: + `andes.System` is an alias of `andes.system.System`. + +Dynamic Imports +``````````````` +System dynamically imports groups, models, and routines at creation. +To add new models, groups or routines, edit the corresponding file by adding entries following examples. + +.. autofunction:: andes.system.System.import_models + :noindex: + +.. autofunction:: andes.system.System.import_groups + :noindex: + +.. autofunction:: andes.system.System.import_routines + :noindex: + +Code Generation +``````````````` +Under the hood, all symbolically defined equations need to be generated into anonymous function calls for +accelerating numerical simulations. +This process is automatically invoked for the first time ANDES is run command line. +It takes several seconds up to a minute to finish the generation. + +.. note:: + Code generation has been done if one has executed ``andes``, ``andes selftest``, or ``andes prepare``. + +.. warning:: + When models are modified (such as adding new models or changing equation strings), code generation needs + to be executed again for consistency. It can be more conveniently triggered from command line with + ``andes prepare -i``. + +.. autofunction:: andes.system.System.prepare + :noindex: + +Since the process is slow, generated numerical functions (Python Callable) will be serialized into a file +for future speed up. +The package used for serializing/de-serializing numerical calls is ``dill``. +System has a function called ``dill`` for serializing using the ``dill`` package. + +.. autofunction:: andes.system.System.dill + :noindex: + +.. autofunction:: andes.system.System.undill + :noindex: + +DAE Storage +----------- + +``System.dae`` is an instance of the numerical DAE class. + +.. autofunction:: andes.variables.dae.DAE + :noindex: + +Model and DAE Values +-------------------- +ANDES uses a decentralized architecture between models and DAE value arrays. +In this architecture, variables are initialized and equations are evaluated inside each model. +Then, ``System`` provides methods for collecting initial values and equation values into ``DAE``, as well as +copying solved values to each model. + +The collection of values from models needs to follow protocols to avoid conflicts. +Details are given in the subsection Variables. + +.. autofunction:: andes.system.System.vars_to_dae + :noindex: + +.. autofunction:: andes.system.System.vars_to_models + :noindex: + +.. autofunction:: andes.system.System._e_to_dae + :noindex: + +Matrix Sparsity Patterns +```````````````````````` +The largest overhead in building and solving nonlinear equations is the building of Jacobian matrices. +This is especially relevant when we use the implicit integration approach which algebraized the differential +equations. +Given the unique data structure of power system models, the sparse matrices for Jacobians are built +**incrementally**, model after model. + +There are two common approaches to incrementally build a sparse matrix. The first one is to use simple in-place +add on sparse matrices, such as doing :: + + self.fx += spmatrix(v, i, j, (n, n), 'd') + +Although the implementation is simple, it involves creating and discarding temporary objects on the right hand +side and, even worse, changing the sparse pattern of ``self.fx``. + +The second approach is to store the rows, columns and values in an array-like object and construct the Jacobians +at the end. +This approach is very efficient but has one caveat: it does not allow accessing the sparse matrix while building. + +ANDES uses a pre-allocation approach to avoid the change of sparse patterns by filling values into a known the +sparse matrix pattern matrix. +System collects the indices of rows and columns for each Jacobian matrix. +Before in-place additions, ANDES builds a temporary zero-filled `spmatrix`, to which the actual Jacobian values +are written later. +Since these in-place add operations are only modifying existing values, it does not change the pattern and thus +avoids memory copying. +In addition, updating sparse matrices can be done with the exact same code as the first approach. + +Still, this approach creates and discards temporary objects. +It is however feasible to write a C function which takes three array-likes and modify the sparse matrices in +place. +This is feature to be developed, and our prototype shows a promising acceleration up to 50%. + +.. autofunction:: andes.system.System.store_sparse_pattern + :noindex: + +Calling Model Methods +--------------------- + +System is an orchestrator for calling shared methods of models. These API methods are defined +for initialization, equation update, Jacobian update, and discrete flags update. + +The following methods take an argument `models`, which should be an `OrderedDict` of models with names as keys +and instances as values. + +.. autofunction:: andes.system.System.init + :noindex: + +.. autofunction:: andes.system.System.e_clear + :noindex: + +.. autofunction:: andes.system.System.l_update_var + :noindex: + +.. autofunction:: andes.system.System.f_update + :noindex: + +.. autofunction:: andes.system.System.l_update_eq + :noindex: + +.. autofunction:: andes.system.System.g_update + :noindex: + +.. autofunction:: andes.system.System.j_update + :noindex: + + +Configuration +------------- +System, models and routines have a member attribute `config` for model-specific or routine-specific configurations. +System manages all configs, including saving to a config file and loading back. + +.. autofunction:: andes.system.System.get_config + :noindex: + +.. autofunction:: andes.system.System.save_config + :noindex: + +.. autofunction:: andes.system.System.load_config + :noindex: + +.. warning:: + + It is important to note that configs from files is passed to *model constructors* during instantiation. + If one needs to modify config for a run, it needs to be done before instantiating ``System``, or before running + ``andes`` from command line. + Directly modifying ``Model.config`` may not take effect or have side effect as for the current implementation. + +Group +====== +A group is a collection of similar functional models with common variables and parameters. +It is mandatory to enforce the common variables and parameters when develop new models. +The common variables and parameters are typically the interface when connecting different group models. + +For example, the Group `RenGen` has variables `Pe` and `Qe`, which are active power output and reactive power output. +Such common variables can be retrieved by other models, such as one in the +Group `RenExciter` for further calculation. + +In such a way, the same variable interface is realized so that all model in the same group could carry out similar +function. + +Models +====== +This section introduces the modeling of power system devices. The terminology "model" is used to describe the +mathematical representation of a *type* of device, such as synchronous generators or turbine governors. The +terminology "device" is used to describe a particular instance of a model, for example, a specific generator. + +To define a model in ANDES, two classes, ``ModelData`` and ``Model`` need to be utilized. Class ``ModelData`` is +used for defining parameters that will be provided from input files. It provides API for adding data from +devices and managing the data. +Class ``Model`` is used for defining other non-input parameters, service +variables, and DAE variables. It provides API for converting symbolic equations, storing Jacobian patterns, and +updating equations. + +Model Data +---------- +.. autoclass:: andes.core.model.ModelData + :noindex: + +Cache +````` +`ModelData` uses a lightweight class :py:class:`andes.core.model.ModelCache` +for caching its data as a dictionary +or a pandas DataFrame. Four attributes are defined in `ModelData.cache`: + +- `dict`: all data in a dictionary with the parameter names as keys and `v` values as arrays. +- `dict_in`: the same as `dict` except that the values are from `v_in`, the original input. +- `df`: all data in a pandas DataFrame. +- `df_in`: the same as `df` except that the values are from `v_in`. + +Other attributes can be added by registering with `cache.add_callback`. + +.. autofunction:: andes.core.model.ModelCache.add_callback + :noindex: + +Define Voltage Ratings +`````````````````````` +If a model is connected to an AC Bus or a DC Node, namely, if ``bus``, ``bus1``, ``node`` or ``node1`` exists +as parameter, it must provide the corresponding parameter, ``Vn``, ``Vn1``, ``Vdcn`` or ``Vdcn1``, for rated +voltages. + +Controllers not connected to Bus or Node will have its rated voltages omitted and thus ``Vb = Vn = 1``, unless +one uses :py:class:`andes.core.param.ExtParam` to retrieve the bus/node values. + +As a rule of thumb, controllers not directly connected to the network shall use system-base per unit for voltage +and current parameters. +Controllers (such as a turbine governor) may inherit rated power from controlled models and thus power parameters +will be converted consistently. + + +Define a DAE Model +-------------------- +.. autoclass:: andes.core.model.Model + :noindex: + +Dynamicity Under the Hood +------------------------- +The magic for automatic creation of variables are all hidden in :py:func:`andes.core.model.Model.__setattr__`, +and the code is incredible simple. +It sets the name, tex_name, and owner model of the attribute instance and, more importantly, +does the book keeping. +In particular, when the attribute is a :py:class:`andes.core.block.Block` subclass, ``__setattr__`` captures the +exported instances, recursively, and prepends the block name to exported ones. +All these convenience owe to the dynamic feature of Python. + +During the code generation phase, the symbols are created by checking the book-keeping attributes, such as +`states`, `algebs`, and attributes in `Model.cache`. + +In the numerical evaluation phase, `Model` provides a method, :py:func:`andes.core.model.get_inputs`, to +collect the variable value arrays in a dictionary, which can be effortlessly passed as arguments to numerical +functions. + +Commonly Used Attributes in Models +`````````````````````````````````` +The following ``Model`` attributes are commonly used for debugging. +If the attribute is an `OrderedDict`, the keys are attribute names in str, and corresponding values are the +instances. + +- ``params`` and ``params_ext``, two `OrderedDict` for internal (both numerical and non-numerical) and external + parameters, respectively. +- ``num_params`` for numerical parameters, both internal and external. +- ``states`` and ``algebs``, two ``OrderedDict`` for state variables and algebraic variables, respectively. +- ``states_ext`` and ``algebs_ext``, two ``OrderedDict`` for external states and algebraics. +- ``discrete``, an `OrderedDict` for discrete components. +- ``blocks``, an `OrderedDict` for blocks. +- ``services``, an `OrderedDict` for services with ``v_str``. +- ``services_ext``, an `OrderedDict` for externally retrieved services. + +Attributes in `Model.cache` +``````````````````````````` +Attributes in `Model.cache` are additional book-keeping structures for variables, parameters and services. +The following attributes are defined. + +- ``all_vars``: all the variables. +- ``all_vars_names``, a list of all variable names. +- ``all_params``, all parameters. +- ``all_params_names``, a list of all parameter names. +- ``algebs_and_ext``, an `OrderedDict` of internal and external algebraic variables. +- ``states_and_ext``, an `OrderedDict` of internal and external differential variables. +- ``services_and_ext``, an `OrderedDict` of internal and external service variables. +- ``vars_int``, an `OrderedDict` of all internal variables, states and then algebs. +- ``vars_ext``, an `OrderedDict` of all external variables, states and then algebs. + +Equation Generation +------------------- +``Model.syms``, an instance of ``SymProcessor``, handles the symbolic to numeric generation when called. The +equation generation is a multi-step process with symbol preparation, equation generation, Jacobian generation, +initializer generation, and pretty print generation. + +.. autoclass:: andes.core.model.SymProcessor + :members: generate_symbols, generate_equations, generate_jacobians, generate_init + :noindex: + +Next, function ``generate_equation`` converts each DAE equation set to one numerical function calls and store +it in ``Model.calls``. The attributes for differential equation set and algebraic equation set are ``f`` +and ``g``. Differently, service variables will be generated one by one and store in an ``OrderedDict`` +in ``Model.calls.s``. + + +Jacobian Storage +---------------- + +Abstract Jacobian Storage +````````````````````````` +Using the ``.jacobian`` method on ``sympy.Matrix``, the symbolic Jacobians can be easily obtained. The complexity +lies in the storage of the Jacobian elements. Observed that the Jacobian equation generation happens before any +system is loaded, thus only the variable indices in the variable array is available. For each non-zero item in each +Jacobian matrix, ANDES stores the equation index, variable index, and the Jacobian value (either a constant +number or a callable function returning an array). + +Note that, again, a non-zero entry in a Jacobian matrix can be either a constant or an expression. For efficiency, +constant numbers and lambdified callables are stored separately. Constant numbers, therefore, can be loaded into +the sparse matrix pattern when a particular system is given. + +.. warning:: + + Data structure for the Jacobian storage has changed. Pending documentation update. Please check + :py:mod:`andes.core.common.JacTriplet` class for more details. + +The triplets, the equation (row) index, variable (column) index, and values (constant numbers or callable) are +stored in ``Model`` attributes with the name of ``_{i, j, v}{Jacobian Name}{c or None}``, where +``{i, j, v}`` is a single character for row, column or value, ``{Jacobian Name}`` is a two-character Jacobian +name chosen from ``fx, fy, gx, and gy``, and ``{c or None}`` is either character ``c`` or no character, +indicating whether it corresponds to the constants or non-constants in the Jacobian. + +For example, the triplets for the +constants in Jacobian ``gy`` are stored in ``_igyc``, ``_jgyc``, and ``_vgyc``. + +In terms of the non-constant entries in Jacobians, the callable functions are stored in the corresponding +``_v{Jacobian Name}`` array. Note the differences between, for example, ``_vgy`` an ``_vgyc``: ``_vgy`` is a +list of callables, while ``_vgyc`` is a list of constant numbers. + +Concrete Jacobian Storage +````````````````````````` +When a specific system is loaded and the addresses are assigned to variables, the abstract Jacobian triplets, +more specifically, the rows and columns, are replaced with the array of addresses. The new addresses and values +will be stored in ``Model`` attributes with the names ``{i, j, v}{Jacobian Name}{c or None}``. Note that there +is no underscore for the concrete Jacobian triplets. + +For example, if model ``PV`` has a list of variables ``[p, q, a, v]`` . +The equation associated with ``p`` is ``- u * p0``, and the equation associated with ``q`` is ``u * (v0 - v)``. +Therefore, the derivative of equation ``v0 - v`` over ``v`` is ``-u``. Note that ``u`` is unknown at generation +time, thus the value is NOT a constant and should to go ``vgy``. + +The values in ``_igy``, ``_jgy`` and ``_vgy`` contains, respectively, ``1``, ``3``, and a lambda function which +returns ``-u``. + +When a specific system is loaded, for example, a 5-bus system, the addresses for the ``q`` and ``v`` are ``[11, +13, 15``, and ``[5, 7, 9]``. +``PV.igy`` and ``PV.jgy`` will thus query the corresponding address list based on ``PV._igy`` and ``PV._jgy`` +and store ``[11, 13, 15``, and ``[5, 7, 9]``. + +Initialization +-------------- +Value providers such as services and DAE variables need to be initialized. Services are initialized before +any DAE variable. Both Services and DAE Variables are initialized *sequentially* in the order of declaration. + +Each Service, in addition to the standard ``v_str`` for symbolic initialization, provides a ``v_numeric`` hook +for specifying a custom function for initialization. Custom initialization functions for DAE variables, are +lumped in a single function in ``Model.v_numeric``. + +ANDES has an *experimental* Newton-Krylov method based iterative initialization. All DAE variables with ``v_iter`` +will be initialized using the iterative approach + +Additional Numerical Equations +------------------------------ +Addition numerical equations are allowed to complete the "hybrid symbolic-numeric" framework. Numerical function +calls are useful when the model DAE is non-standard or hard to be generalized. Since the +symbolic-to-numeric generation is an additional layer on top of the numerical simulation, it is fundamentally +the same as user-provided numerical function calls. + +ANDES provides the following hook functions in each ``Model`` subclass for custom numerical functions: + +- ``v_numeric``: custom initialization function +- ``s_numeric``: custom service value function +- ``g_numeric``: custom algebraic equations; update the ``e`` of the corresponding variable. +- ``f_numeric``: custom differential equations; update the ``e`` of the corresponding variable. +- ``j_numeric``: custom Jacobian equations; the function should append to ``_i``, ``_j`` and ``_v`` structures. + +For most models, numerical function calls are unnecessary and not recommended as it increases code complexity. +However, when the data structure or the DAE are difficult to generalize in the symbolic framework, the numerical +equations can be used. + +For interested readers, see the ``COI`` symbolic implementation which calculated the +center-of-inertia speed of generators. The ``COI`` could have been implemented numerically with for loops +instead of ``NumReduce``, ``NumRepeat`` and external variables. + +.. + Atoms + ANDES defines several types of atoms for building DAE models, including parameters, DAE variables, + and service variables. Atoms can be used to build models and libraries, combined with discrete + components and blocks. + + +Atom Types +============ +ANDES contains three types of atom classes for building DAE models. +These types are parameter, variable and service. + +Value Provider +-------------- + +Before addressing specific atom classes, the terminology `v-provider`, and `e-provider` are discussed. +A value provider class (or `v-provider` for short) references any class with a member attribute named ``v``, +which should be a list or a 1-dimensional array of values. +For example, all parameter classes are v-providers, since a parameter class should provide +values for that parameter. + +.. note:: + In fact, all types of atom classes are v-providers, meaning that an instance of an atom class must contain values. + +The values in the `v` attribute of a particular instance are values that will substitute the instance for computation. +If in a model, one has a parameter :: + + self.v0 = NumParam() + self.b = NumParam() + + # where self.v0.v = np.array([1., 1.05, 1.1] + # and self.b.v = np.array([10., 10., 10.] + +Later, this parameter is used in an equation, such as :: + + self.v = ExtAlgeb(model='Bus', src='v', + indexer=self.bus, + e_str='v0 **2 * b') + +While computing `v0 ** 2 * b`, `v0` and `b` will be substituted with the values in `self.v0.v` and `self.b.v`. + +Sharing this interface `v` allows interoperability among parameters and variables and services. +In the above example, if one defines `v0` as a `ConstService` instance, such as :: + + self.v0 = ConstService(v_str='1.0') + +Calculations will still work without modification. + +Equation Provider +----------------- +Similarly, an equation provider class (or `e-provider`) references any class with a member attribute named ``e``, +which should be a 1-dimensional array of values. +The values in the `e` array are the results from the equation and will be summed to the numerical DAE at the addresses +specified by the attribute `a`. + +.. note:: + Currently, only variables are `e-provider` types. + +If a model has an external variable that links to Bus.v (voltage), such as :: + + self.v = ExtAlgeb(model='Bus', src='v', + indexer=self.bus, + e_str='v0 **2 * b') + +The addresses of the corresponding voltage variables will be retrieved into `self.v.a`, +and the equation evaluation results will be stored in `self.v.e` + +Parameters +========== + +Background +----------- + +Parameter is a type of building atom for DAE models. +Most parameters are read directly from an input file and passed to equation, +and other parameters can be calculated from existing parameters. + +The base class for parameters in ANDES is `BaseParam`, which defines interfaces for adding values and +checking the number of values. `BaseParam` has its values stored in a plain list, the member attribute `v`. +Subclasses such as `NumParam` stores values using a NumPy ndarray. + +An overview of supported parameters is given below. + ++---------------+----------------------------------------------------------------------------+ +| Subclasses | Description | ++===============+============================================================================+ +| DataParam | An alias of `BaseParam`. Can be used for any non-numerical parameters. | ++---------------+----------------------------------------------------------------------------+ +| NumParam | The numerical parameter type. Used for all parameters in equations | ++---------------+----------------------------------------------------------------------------+ +| IdxParam | The parameter type for storing `idx` into other models | ++---------------+----------------------------------------------------------------------------+ +| ExtParam | Externally defined parameter | ++---------------+----------------------------------------------------------------------------+ +| TimerParam | Parameter for storing the action time of events | ++---------------+----------------------------------------------------------------------------+ + +Data Parameters +--------------- +.. autoclass:: andes.core.param.BaseParam + :noindex: + +.. autoclass:: andes.core.param.DataParam + :noindex: + +.. autoclass:: andes.core.param.IdxParam + :noindex: + +Numeric Parameters +------------------ +.. autoclass:: andes.core.param.NumParam + :noindex: + +External Parameters +------------------- +.. autoclass:: andes.core.param.ExtParam + :noindex: + +Timer Parameter +--------------- +.. autoclass:: andes.core.param.TimerParam + :noindex: + + +Variables +========= +DAE Variables, or variables for short, are unknowns to be solved using numerical or analytical methods. +A variable stores values, equation values, and addresses in the DAE array. The base class for variables is +`BaseVar`. +In this subsection, `BaseVar` is used to represent any subclass of `VarBase` list in the table below. + ++-----------+---------------------------------------------------------------------------------------+ +| Class | Description | ++===========+=======================================================================================+ +| State | A state variable and associated diff. equation :math:`\textbf{T} \dot{x} = \textbf{f}`| ++-----------+---------------------------------------------------------------------------------------+ +| Algeb | An algebraic variable and an associated algebraic equation :math:`0 = \textbf{g}` | ++-----------+---------------------------------------------------------------------------------------+ +| ExtState | An external state variable and part of the differential equation (uncommon) | ++-----------+---------------------------------------------------------------------------------------+ +| ExtAlgeb | An external algebraic variable and part of the algebraic equation | ++-----------+---------------------------------------------------------------------------------------+ + +`BaseVar` has two types: the differential variable type `State` and the algebraic variable type `Algeb`. +State variables are described by differential equations, whereas algebraic variables are described by +algebraic equations. State variables can only change continuously, while algebraic variables +can be discontinuous. + +Based on the model the variable is defined, variables can be internal or external. Most variables are internal +and only appear in equations in the same model. +Some models have "public" variables that can be accessed by other +models. For example, a `Bus` defines `v` for the voltage magnitude. +Each device attached to a particular bus needs to access the value and impose the reactive power injection. +It can be done with `ExtAlgeb` or `ExtState`, which links with an existing variable from a model or a group. + +Variable, Equation and Address +------------------------------ +Subclasses of `BaseVar` are value providers and equation providers. +Each `BaseVar` has member attributes `v` and `e` for variable values and equation values, respectively. +The initial value of `v` is set by the initialization routine, and the initial value of `e` is set to zero. +In the process of power flow calculation or time domain simulation, `v` is not directly modifiable by models +but rather updated after solving non-linear equations. `e` is updated by the models and summed up before +solving equations. + +Each `BaseVar` also stores addresses of this variable, for all devices, in its member attribute `a`. The +addresses are *0-based* indices into the numerical DAE array, `f` or `g`, based on the variable type. + +For example, `Bus` has ``self.a = Algeb()`` as the voltage phase angle variable. +For a 5-bus system, ``Bus.a.a`` stores the addresses of the `a` variable for all +the five Bus devices. Conventionally, `Bus.a.a` will be assigned `np.array([0, 1, 2, 3, 4])`. + +Value and Equation Strings +-------------------------- +The most important feature of the symbolic framework is allowing to define equations using strings. +There are three types of strings for a variable, stored in the following member attributes, respectively: + +- `v_str`: equation string for **explicit** initialization in the form of `v = v_str(x, y)`. +- `v_iter`: equation string for **implicit** initialization in the form of `v_iter(x, y) = 0` +- `e_str`: equation string for (full or part of) the differential or algebraic equation. + +The difference between `v_str` and `v_iter` should be clearly noted. `v_str` evaluates directly into the +initial value, while all `v_iter` equations are solved numerically using the Newton-Krylov iterative method. + +Values Between DAE and Models +----------------------------- +ANDES adopts a decentralized architecture which provides each model a copy of variable values before equation +evaluation. This architecture allows to parallelize the equation evaluation (in theory, or in practice if one +works round the Python GIL). However, this architecture requires a coherent protocol for updating the DAE arrays +and the ``BaseVar`` arrays. More specifically, how the variable and equations values from model ``VarBase`` +should be summed up or forcefully set at the DAE arrays needs to be defined. + +The protocol is relevant when a model defines subclasses of `BaseVar` that are supposed to be "public". +Other models share this variable with `ExtAlgeb` or `ExtState`. + +By default, all `v` and `e` at the same address are summed up. +This is the most common case, such as a Bus connected by multiple devices: power injections from +devices should be summed up. + +In addition, `BaseVar` provides two flags, `v_setter` and `e_setter`, for cases when one `VarBase` +needs to overwrite the variable or equation values. + +Flags for Value Overwriting +--------------------------- +`BaseVar` have special flags for handling value initialization and equation values. +This is only relevant for public or external variables. +The `v_setter` is used to indicate whether a particular `BaseVar` instance sets the initial value. +The `e_setter` flag indicates whether the equation associated with a `BaseVar` sets the equation value. + +The `v_setter` flag is checked when collecting data from models to the numerical DAE array. If +`v_setter is False`, variable values of the same address will be added. +If one of the variable or external variable has `v_setter is True`, it will, at the end, set the values in the +DAE array to its value. Only one `BaseVar` of the same address is allowed to have `v_setter == True`. + +A `v_setter` Example +------------------------ +A Bus is allowed to default the initial voltage magnitude to 1 and the voltage phase angle to 0. +If a PV device is connected to a Bus device, the PV should be allowed to override the voltage initial value +with the voltage set point. + +In `Bus.__init__()`, one has :: + + self.v = Algeb(v_str='1') + +In `PV.__init__`, one can use :: + + self.v0 = Param() + self.bus = IdxParam(model='Bus') + + self.v = ExtAlgeb(src='v', + model='Bus', + indexer=self.bus, + v_str='v0', + v_setter=True) + +where an `ExtAlgeb` is defined to access `Bus.v` using indexer `self.bus`. The `v_str` line sets the +initial value to `v0`. In the variable initialization phase for `PV`, `PV.v.v` is set to `v0`. + +During the value collection into `DAE.y` by the `System` class, `PV.v`, as a final `v_setter`, will +overwrite the voltage magnitude for Bus devices with the indices provided in `PV.bus`. + +.. autoclass:: andes.core.var.BaseVar + :noindex: + +.. autoclass:: andes.core.var.ExtVar + :noindex: + +.. autoclass:: andes.core.var.State + :noindex: + +.. autoclass:: andes.core.var.Algeb + :noindex: + +.. autoclass:: andes.core.var.ExtState + :noindex: + +.. autoclass:: andes.core.var.ExtAlgeb + :noindex: + +.. autoclass:: andes.core.var.AliasState + :noindex: + +.. autoclass:: andes.core.var.AliasAlgeb + :noindex: + +Services +======== +Services are helper variables outside the DAE variable list. Services are most often used for storing intermediate +constants but can be used for special operations to work around restrictions in the symbolic framework. +Services are value providers, meaning each service has an attribute ``v`` for storing service values. The +base class of services is ``BaseService``, and the supported services are listed as follows. + ++------------------+-----------------------------------------------------------------+ +| Class | Description | ++==================+=================================================================+ +| ConstService | Internal service for constant values. | ++------------------+-----------------------------------------------------------------+ +| VarService | Variable service updated at each iteration before equations. | ++------------------+-----------------------------------------------------------------+ +| ExtService | External service for retrieving values from value providers. | ++------------------+-----------------------------------------------------------------+ +| PostInitService | Constant service evaluated after TDS initialization | ++------------------+-----------------------------------------------------------------+ +| NumReduce | The service type for reducing linear 2-D arrays into 1-D arrays | ++------------------+-----------------------------------------------------------------+ +| NumRepeat | The service type for repeating a 1-D array to linear 2-D arrays | ++------------------+-----------------------------------------------------------------+ +| IdxRepeat | The service type for repeating a 1-D list to linear 2-D list | ++------------------+-----------------------------------------------------------------+ +| EventFlag | Service type for flagging changes in inputs as an event | ++------------------+-----------------------------------------------------------------+ +| VarHold | Hold input value when a hold signal is active | ++------------------+-----------------------------------------------------------------+ +| ExtendedEvent | Extend an event signal for a given period of time | ++------------------+-----------------------------------------------------------------+ +| DataSelect | Select optional str data if provided or use the fallback | ++------------------+-----------------------------------------------------------------+ +| NumSelect | Select optional numerical data if provided | ++------------------+-----------------------------------------------------------------+ +| DeviceFinder | Finds or creates devices linked to the given devices | ++------------------+-----------------------------------------------------------------+ +| BackRef | Collects idx-es for the backward references | ++------------------+-----------------------------------------------------------------+ +| RefFlatten | Converts BackRef list of lists into a 1-D list | ++------------------+-----------------------------------------------------------------+ +| InitChecker | Checks initial values against typical values | ++------------------+-----------------------------------------------------------------+ +| FlagValue | Flags values that equals the given value | ++------------------+-----------------------------------------------------------------+ +| Replace | Replace values that returns True for the given lambda func | ++------------------+-----------------------------------------------------------------+ + + +Internal Constants +--------------------------- +The most commonly used service is `ConstService`. It is used to store an array of constants, whose value is +evaluated from a provided symbolic string. They are only evaluated once in the model initialization phase, ahead +of variable initialization. `ConstService` comes handy when one wants to calculate intermediate constants from +parameters. + +For example, a turbine governor has a `NumParam` `R` for the +droop. `ConstService` allows to calculate the inverse of the droop, the gain, and use it in equations. The +snippet from a turbine governor's ``__init__()`` may look like :: + + self.R = NumParam() + self.G = ConstService(v_str='u/R') + +where `u` is the online status parameter. The model can thus use `G` in subsequent variable or equation +strings. + +.. autoclass:: andes.core.service.ConstService + :noindex: + +.. autoclass:: andes.core.service.VarService + :noindex: + +.. autoclass:: andes.core.service.PostInitService + :noindex: + +External Constants +------------------------ +Service constants whose value is retrieved from an external model or group. Using `ExtService` is +similar to using external variables. The values of `ExtService` will be retrieved once during the +initialization phase before `ConstService` evaluation. + +For example, a synchronous generator needs to retrieve the `p` and `q` values from static generators +for initialization. `ExtService` is used for this purpose. In the ``__init__()`` of a synchronous generator +model, one can define the following to retrieve `StaticGen.p` as `p0`:: + + self.p0 = ExtService(src='p', + model='StaticGen', + indexer=self.gen, + tex_name='P_0') + +.. autoclass:: andes.core.service.ExtService + :noindex: + +Shape Manipulators +------------------------------------------- +This section is for advanced model developer. + +All generated equations operate on 1-dimensional arrays and can use algebraic calculations only. +In some cases, one model would use `BackRef` to retrieve 2-dimensional indices and will use such indices to +retrieve variable addresses. +The retrieved addresses usually has a different length of the referencing model and cannot be used directly for calculation. +Shape manipulator services can be used in such case. + +`NumReduce` is a helper Service type which reduces a linearly stored 2-D ExtParam into 1-D Service. +`NumRepeat` is a helper Service type which repeats a 1-D value into linearly stored 2-D value based on the +shape from a `BackRef`. + +.. autoclass:: andes.core.service.BackRef + :noindex: + +.. autoclass:: andes.core.service.NumReduce + :noindex: + +.. autoclass:: andes.core.service.NumRepeat + :noindex: + +.. autoclass:: andes.core.service.IdxRepeat + :noindex: + +.. autoclass:: andes.core.service.RefFlatten + :noindex: + + +Value Manipulation +------------------ +.. autoclass:: andes.core.service.Replace + :noindex: + +.. autoclass:: andes.core.service.FlagValue + :noindex: + + +Idx and References +------------------------------------------- +.. autoclass:: andes.core.service.DeviceFinder + :noindex: + +.. autoclass:: andes.core.service.BackRef + :noindex: + +.. autoclass:: andes.core.service.RefFlatten + :noindex: + + +Events +---------- +.. autoclass:: andes.core.service.EventFlag + :noindex: + +.. autoclass:: andes.core.service.ExtendedEvent + :noindex: + + +Data Select +----------- +.. autoclass:: andes.core.service.DataSelect + :noindex: + +.. autoclass:: andes.core.service.NumSelect + :noindex: + + +Miscellaneous +------------- +.. autoclass:: andes.core.service.InitChecker + :noindex: + + + +Discrete +======== + +Background +---------- +The discrete component library contains a special type of block for modeling the discontinuity in power system +devices. Such continuities can be device-level physical constraints or algorithmic limits imposed on controllers. + +The base class for discrete components is :py:mod:`andes.core.discrete.Discrete`. + +.. autoclass:: andes.core.discrete.Discrete + :noindex: + +The uniqueness of discrete components is the way it works. +Discrete components take inputs, criteria, and exports a set of flags with the component-defined meanings. +These exported flags can be used in algebraic or differential equations to build piece-wise equations. + +For example, `Limiter` takes a v-provider as input, two v-providers as the upper and the lower bound. +It exports three flags: `zi` (within bound), `zl` (below lower bound), and `zu` (above upper bound). +See the code example in ``models/pv.py`` for an example voltage-based PQ-to-Z conversion. + +It is important to note when the flags are updated. +Discrete subclasses can use three methods to check and update the value and equations. +Among these methods, `check_var` is called *before* equation evaluation, but `check_eq` and `set_eq` are +called *after* equation update. +In the current implementation, `check_var` updates flags for variable-based discrete components (such as +`Limiter`). +`check_eq` updates flags for equation-involved discrete components (such as `AntiWindup`). +`set_var`` is currently only used by `AntiWindup` to store the pegged states. + +ANDES includes the following types of discrete components. + +Limiters +-------- +.. autoclass:: andes.core.discrete.Limiter + :noindex: + +.. autoclass:: andes.core.discrete.SortedLimiter + :noindex: + +.. autoclass:: andes.core.discrete.HardLimiter + :noindex: + +.. autoclass:: andes.core.discrete.AntiWindup + :noindex: + +Comparers +--------- +.. autoclass:: andes.core.discrete.LessThan + :noindex: + +.. autoclass:: andes.core.discrete.Selector + :noindex: + +.. autoclass:: andes.core.discrete.Switcher + :noindex: + +Deadband +-------- +.. autoclass:: andes.core.discrete.DeadBand + :noindex: + +Blocks +====== + +Background +---------- +The block library contains commonly used blocks (such as transfer functions and nonlinear functions). +Variables and equations are pre-defined for blocks to be used as "lego pieces" for scripting DAE models. +The base class for blocks is :py:mod:`andes.core.block.Block`. + +The supported blocks include ``Lag``, ``LeadLag``, ``Washout``, ``LeadLagLimit``, ``PIController``. In addition, +the base class for piece-wise nonlinear functions, ``PieceWise`` is provided. ``PieceWise`` is used for +implementing the quadratic saturation function ``MagneticQuadSat`` and exponential saturation function +``MagneticExpSat``. + +All variables in a block must be defined as attributes in the constructor, just like variable definition in +models. The difference is that the variables are "exported" from a block to the capturing model. All exported +variables need to placed in a dictionary, ``self.vars`` at the end of the block constructor. + +Blocks can be nested as advanced usage. See the following API documentation for more details. + +.. autoclass:: andes.core.block.Block + :noindex: + +Transfer Functions +------------------ + +The following transfer function blocks have been implemented. +They can be imported to build new models. + +Algebraic +````````` +.. autoclass:: andes.core.block.Gain + :members: define + :noindex: + +First Order +``````````` +.. autoclass:: andes.core.block.Integrator + :members: define + :noindex: + +.. autoclass:: andes.core.block.IntegratorAntiWindup + :members: define + :noindex: + +.. autoclass:: andes.core.block.Lag + :members: define + :noindex: + +.. autoclass:: andes.core.block.LagAntiWindup + :members: define + :noindex: + +.. autoclass:: andes.core.block.Washout + :members: define + :noindex: + +.. autoclass:: andes.core.block.WashoutOrLag + :members: define + :noindex: + +.. autoclass:: andes.core.block.LeadLag + :members: define + :noindex: + +.. autoclass:: andes.core.block.LeadLagLimit + :members: define + :noindex: + +Second Order +```````````` +.. autoclass:: andes.core.block.Lag2ndOrd + :members: define + :noindex: + +.. autoclass:: andes.core.block.LeadLag2ndOrd + :members: define + :noindex: + +Saturation +---------- +.. autoclass:: andes.models.exciter.ExcExpSat + :members: define + :noindex: + + +Others +------ + +Value Selector +`````````````` +.. autoclass:: andes.core.block.HVGate + :noindex: + +.. autoclass:: andes.core.block.LVGate + :noindex: + +Naming Convention +----------------- + +We loosely follow a naming convention when using modeling blocks. +An instance of a modeling block is named with a two-letter +acronym, followed by a number or a meaningful but short variaiable name. +The acronym and the name are spelled in one word without underscore, as +the output of the block already contains ``_y``. + +For example, two washout filters can be names ``WO1`` and ``WO2``. +In another case, a first-order lag function for voltage sensing +can be called ``LGv``, or even ``LG`` if there is only one Lag +instance in the model. + +Naming conventions are not strictly enforced. Expressiveness +and concision are encouraged. + +Examples +======== +We show two examples to demonstrate modeling from equations and modeling from +control block diagrams. + +- The TGOV1 example shows code snippet for equation-based modeling + and, as well as code for block-based modeling. +- The IEEEST example walks through the source code and explains the complete + setup, including optional parameters, input selection, and manual per-unit + conversion. + +TGOV1 +----- +The TGOV1_ turbine governor model is shown as a practical example using the library. + +.. image:: images/example-tgov1/tgov1.png + :align: center + +This model is composed of a lead-lag transfer function and a first-order lag transfer function +with an anti-windup limiter, which are sufficiently complex for demonstration. +The corresponding differential equations and algebraic equations are given below. + +.. math:: + + \left[ + \begin{matrix} + \dot{x}_{LG} \\ + \dot{x}_{LL} + \end{matrix} + \right] + = + \left[ + \begin{matrix}z_{i,lim}^{LG} \left(P_{d} - x_{LG}\right) / {T_1} + \\ + \left(x_{LG} - x_{LL}\right) / T_3 + \end{matrix} + \right] + + \left[ + \begin{matrix} + 0 \\ + 0 \\ + 0 \\ + 0 \\ + 0 \\ + 0 + \end{matrix} + \right] + = + \left[ + \begin{matrix} + (1 - \omega) - \omega_{d} \\ + R \times \tau_{m0} - P_{ref} \\ + \left(P_{ref} + \omega_{d}\right)/R - P_{d}\\ + D_{t} \omega_{d} + y_{LL} - P_{OUT}\\ + \frac{T_2}{T_3} \left(x_{LG} - x_{LL}\right) + x_{LL} - y_{LL}\\ + u \left(P_{OUT} - \tau_{m0}\right) + \end{matrix} + \right] + +where *LG* and *LL* denote the lag block and the lead-lag block, :math:`\dot{x}_{LG}` and :math:`\dot{x}_{LL}` +are the internal states, :math:`y_{LL}` is the lead-lag output, :math:`\omega` the generator speed, +:math:`\omega_d` the generator under-speed, :math:`P_d` the droop output, :math:`\tau_{m0}` the steady-state +torque input, and :math:`P_{OUT}` the turbine output that will be summed at the generator. + +The code to describe the above model using equations is given below. +The complete code can be found in class ``TGOV1ModelAlt`` in +``andes/models/governor.py``. + +.. code:: python + + def __init__(self, system, config): + # 1. Declare parameters from case file inputs. + self.R = NumParam(info='Turbine governor droop', + non_zero=True, ipower=True) + # Other parameters are omitted. + + # 2. Declare external variables from generators. + self.omega = ExtState(src='omega', + model='SynGen', + indexer=self.syn, + info='Generator speed') + self.tm = ExtAlgeb(src='tm', + model='SynGen', + indexer=self.syn, + e_str='u*(pout-tm0)', + info='Generator torque input') + + # 3. Declare initial values from generators. + self.tm0 = ExtService(src='tm', + model='SynGen', + indexer=self.syn, + info='Initial torque input') + + # 4. Declare variables and equations. + self.pref = Algeb(info='Reference power input', + v_str='tm0*R', + e_str='tm0*R-pref') + self.wd = Algeb(info='Generator under speed', + e_str='(1-omega)-wd') + self.pd = Algeb(info='Droop output', + v_str='tm0', + e_str='(wd+pref)/R-pd') + self.LG_x = State(info='State in the lag TF', + v_str='pd', + e_str='LG_lim_zi*(pd-LG_x)/T1') + self.LG_lim = AntiWindup(u=self.LG_x, + lower=self.VMIN, + upper=self.VMAX) + self.LL_x = State(info='State in the lead-lag TF', + v_str='LG_x', + e_str='(LG_x-LL_x)/T3') + self.LL_y = Algeb(info='Lead-lag Output', + v_str='LG_x', + e_str='T2/T3*(LG_x-LL_x)+LL_x-LL_y') + self.pout = Algeb(info='Turbine output power', + v_str='tm0', + e_str='(LL_y+Dt*wd)-pout') + + +Another implementation of TGOV1_ makes extensive use of the modeling blocks. +The resulting code is more readable as follows. + +.. code:: python + + def __init__(self, system, config): + TGBase.__init__(self, system, config) + + self.gain = ConstService(v_str='u/R') + + self.pref = Algeb(info='Reference power input', + tex_name='P_{ref}', + v_str='tm0 * R', + e_str='tm0 * R - pref', + ) + + self.wd = Algeb(info='Generator under speed', + unit='p.u.', + tex_name=r'\omega_{dev}', + v_str='0', + e_str='(wref - omega) - wd', + ) + self.pd = Algeb(info='Pref plus under speed times gain', + unit='p.u.', + tex_name="P_d", + v_str='u * tm0', + e_str='u*(wd + pref + paux) * gain - pd') + + self.LAG = LagAntiWindup(u=self.pd, + K=1, + T=self.T1, + lower=self.VMIN, + upper=self.VMAX, + ) + + self.LL = LeadLag(u=self.LAG_y, + T1=self.T2, + T2=self.T3, + ) + + self.pout.e_str = '(LL_y + Dt * wd) - pout' + +The complete code can be found in class ``TGOV1Model`` in ``andes/models/governor.py``. + +IEEEST +------ +In this example, we will explain step-by-step how IEEEST_ is programmed. +The block diagram of IEEEST is given as follows. +We recommend you to open up the source code in ``andes/models/pss.py`` and +then continue reading. + +.. image:: images/diagrams/ieeest.png + :align: center + +First of all, modeling components are imported at the beginning. + +Next, ``PSSBaseData`` is defined to hold parameters shared by all PSSs. +``PSSBaseData`` inherits from ``ModelData`` and calls the base constructor. +There is only one field ``avr`` defined for the linked exciter idx. + +Then, ``IEEESTData`` defines the input parameters for IEEEST. +Use ``IdxParam`` for fields that store idx-es of devices that IEEEST devices link to. +Use ``NumParam`` for numerical parameters. + +PSSBase +``````` +``PSSBase`` is defined for the common (external) parameters, services and variables +shared by all PSSs. +The class and constructor signatures are + +.. code:: python + + class PSSBase(Model): + def __init__(self, system, config): + super().__init__(system, config) + +``PSSBase`` inherits from ``Model`` and calls the base constructor. +Note that the call to ``Model``'s constructor takes two positional arguments, ``system`` +and ``config`` of types ``System`` and ``ModelConfig``. +Next, the group is specified, and the model flags are set. + +.. code:: python + + self.group = 'PSS' + self.flags.update({'tds': True}) + +Next, ``Replace`` is used to replace input parameters that satisfy a lambda function +with new values. + +.. code:: python + + self.VCUr = Replace(self.VCU, lambda x: np.equal(x, 0.0), 999) + self.VCLr = Replace(self.VCL, lambda x: np.equal(x, 0.0), -999) + +The value replacement happens when ``VCUr`` and ``VCLr`` is first accessed. +``Replace`` is executed in the model initialization phase (at the end of +services update). + +Next, the indices of connected generators, buses, and bus frequency measurements +are retrieved. +Synchronous generator idx is retrieved with + +.. code:: python + + self.syn = ExtParam(model='Exciter', src='syn', indexer=self.avr, export=False, + info='Retrieved generator idx', vtype=str) + +Using the retrieved ``self.syn``, it retrieves the buses to which +the generators are connected. + +.. code:: python + + self.bus = ExtParam(model='SynGen', src='bus', indexer=self.syn, export=False, + info='Retrieved bus idx', vtype=str, default=None, + ) + +PSS models support an optional remote bus specified through parameter ``busr``. +When ``busr`` is ``None``, the generator-connected bus should be used. +The following code uses ``DataSelect`` to select ``busr`` if available but falls +back to ``bus`` otherwise. + +.. code:: python + + self.buss = DataSelect(self.busr, self.bus, info='selected bus (bus or busr)') + +Each PSS links to a bus frequency measurement device. +If the input data does not specify one or the specified one does not exist, +``DeviceFinder`` can find the correct measurement device for the bus +where frequency measurements should be taken. + +.. code:: python + + self.busfreq = DeviceFinder(self.busf, link=self.buss, idx_name='bus') + +where ``busf`` is the optional frequency measurement device idx, ``buss`` is the bus idx +for which measurement device needs to be found or created. + +Next, external parameters, variables and services are retrieved. +Note that the PSS output ``vsout`` is pre-allocated but the equation string +is left to specific models. + +IEEESTModel +``````````` +``IEEESTModel`` inherits from ``PSSBase`` and adds specific model components. +After calling ``PSSBase``'s constructor, IEEESTModel adds config entries +to allow specifying the model for frequency measurement, because +there may be multiple frequency measurement models in the future. + +.. code:: python + + self.config.add(OrderedDict([('freq_model', 'BusFreq')])) + self.config.add_extra('_help', {'freq_model': 'default freq. measurement model'}) + self.config.add_extra('_alt', {'freq_model': ('BusFreq',)}) + +We set the chosen measurement model to ``busf`` so that ``DeviceFinder`` knows which +model to use if it needs to create new devices. + +.. code:: python + + self.busf.model = self.config.freq_model + +Next, because bus voltage is an algebraic variable, we use ``Derivative`` to calculate +the finite difference to approximate its derivative. + +.. code:: python + + self.dv = Derivative(self.v, tex_name='dV/dt', info='Finite difference of bus voltage') + +Then, we retrieve the coefficient to convert power from machine base to system base +using ``ConstService``, given by Sb / Sn. +This is needed for input mode 3, electric power in machine base. + +.. code:: python + + self.SnSb = ExtService(model='SynGen', src='M', indexer=self.syn, attr='pu_coeff', + info='Machine base to sys base factor for power', + tex_name='(Sb/Sn)') + +Note that the ``ExtService`` access the ``pu_coeff`` field of the ``M`` variables of +synchronous generators. +Since ``M`` is a machine-base power quantity, ``M.pu_coeff`` stores the multiplication coefficient +to convert each of them from machine bases to the system base, which is Sb / Sn. + +The input mode is parsed into boolean flags using ``Switcher``: + +.. code:: python + + self.SW = Switcher(u=self.MODE, + options=[0, 1, 2, 3, 4, 5, 6], + ) + +where the input ``u`` is the MODE parameter, and ``options`` is a list of accepted +values. +``Switcher`` boolean arrays ``s0``, ``s1``, ..., ``sN``, where ``N = len(options) - 1``. +We added ``0`` to ``options`` for padding so that ``SW_s1`` corresponds to MODE 1. +It improves the readability of the code as we will see next. + +The input signal ``sig`` is an algebraic variable given by + +.. code:: python + + self.sig = Algeb(tex_name='S_{ig}', + info='Input signal', + ) + + self.sig.v_str = 'SW_s1*(omega-1) + SW_s2*0 + SW_s3*(tm0/SnSb) + ' \ + 'SW_s4*(tm-tm0) + SW_s5*v + SW_s6*0' + + self.sig.e_str = 'SW_s1*(omega-1) + SW_s2*(f-1) + SW_s3*(te/SnSb) + ' \ + 'SW_s4*(tm-tm0) + SW_s5*v + SW_s6*dv_v - sig' + +The ``v_str`` and ``e_str`` are separated from the constructor to improve readability. +They construct piece-wise functions to select the correct initial values and equations +based on mode. +For any variables in ``v_str``, they must be defined before ``sig`` so that +they will be initialized ahead of ``sig``. +Clearly, ``omega``, ``tm``, and ``v`` are defined in ``PSSBase`` and thus +come before ``sig``. + +The following comes the most effective part: modeling using transfer function blocks. +We utilized several blocks to describe the model from the diagram. +Note that the output of a block is always the block name followed by ``_y``. +For example, the input of ``F2`` is the output of ``F1``, given by ``F1_y``. + +.. code:: python + + self.F1 = Lag2ndOrd(u=self.sig, K=1, T1=self.A1, T2=self.A2) + + self.F2 = LeadLag2ndOrd(u=self.F1_y, T1=self.A3, T2=self.A4, + T3=self.A5, T4=self.A6, zero_out=True) + + self.LL1 = LeadLag(u=self.F2_y, T1=self.T1, T2=self.T2, zero_out=True) + + self.LL2 = LeadLag(u=self.LL1_y, T1=self.T3, T2=self.T4, zero_out=True) + + self.Vks = Gain(u=self.LL2_y, K=self.KS) + + self.WO = WashoutOrLag(u=self.Vks_y, T=self.T6, K=self.T5, name='WO', + zero_out=True) # WO_y == Vss + + self.VLIM = Limiter(u=self.WO_y, lower=self.LSMIN, upper=self.LSMAX, + info='Vss limiter') + + self.Vss = Algeb(tex_name='V_{ss}', info='Voltage output before output limiter', + e_str='VLIM_zi * WO_y + VLIM_zu * LSMAX + VLIM_zl * LSMIN - Vss') + + self.OLIM = Limiter(u=self.v, lower=self.VCLr, upper=self.VCUr, + info='output limiter') + + self.vsout.e_str = 'OLIM_zi * Vss - vsout' + +In the end, the output equation is assigned to ``vsout.e_str``. +It completes the equations of the IEEEST model. + +Finalize +```````` +Assemble ``IEEESTData`` and ``IEEESTModel`` into ``IEEEST``: + +.. code:: python + + class IEEEST(IEEESTData, IEEESTModel): + def __init__(self, system, config): + IEEESTData.__init__(self) + IEEESTModel.__init__(self, system, config) + +Locate ``andes/models/__init__.py``, in ``file_classes``, +find the key ``pss`` and add ``IEEEST`` to its value list. +In ``file_classes``, keys are the ``.py`` file names under the folder ``models``, +and values are class names to be imported from that file. +If the file name does not exist as a key in ``file_classes``, +add it after all prerequisite models. +For example, PSS should be added after exciters (and generators, +of course). + +Finally, locate ``andes/models/group.py``, check if the class +with ``PSS`` exist. +It is the name of IEEEST's group name. +If not, create one by inheriting from ``GroupBase``: + +.. code:: python + + class PSS(GroupBase): + """Power system stabilizer group.""" + + def __init__(self): + super().__init__() + self.common_vars.extend(('vsout',)) + +where we added ``vsout`` to the ``common_vars`` list. +All models in the PSS group must have a variable named +``vsout``, which is defined in ``PSSBase``. + +This completes the IEEEST model. +When developing new models, use ``andes prepare`` to generate numerical code and +start debugging. diff --git a/docs/source/modelref.py b/docs/source/modelref.py new file mode 100644 index 0000000..ce7f175 --- /dev/null +++ b/docs/source/modelref.py @@ -0,0 +1,58 @@ +""" +This file is used to generate reStructuredText tables for Group and Model references. +""" +import os +import andes + +if not (os.path.isfile('modelref.rst') and os.path.isfile('configref.rst')): + + ss = andes.prepare(nomp=True) + + # write the top-level index file + + out = '' + out += '.. _modelref:\n\n' + out += '****************\n' + out += 'Model References\n' + out += '****************\n' + out += '\n' + + out += ss.supported_models(export='rest') + + out += '\n' + out += '.. toctree ::\n' + out += ' :maxdepth: 2\n' + out += '\n' + + file_tpl = ' groupdoc/{}\n' + + for group in ss.groups.values(): + out += file_tpl.format(group.class_name) + + with open('modelref.rst', 'w') as f: + f.write(out) + + # write individual files + + os.makedirs('groupdoc', exist_ok=True) + + for group in ss.groups.values(): + with open(f'groupdoc/{group.class_name}.rst', 'w') as f: + f.write(group.doc_all(export='rest')) + + # Config Reference Section + + out = '' + out += '.. _configref:\n\n' + out += '*****************\n' + out += 'Config References\n' + out += '*****************\n' + out += '\n' + + out += ss.config.doc(export='rest', target=True, symbol=False) + + for r in ss.routines.values(): + out += r.config.doc(export='rest', target=True, symbol=False) + + with open('configref.rst', 'w') as f: + f.write(out) diff --git a/docs/source/moduledoc/andes.core.rst b/docs/source/moduledoc/andes.core.rst new file mode 100644 index 0000000..ff91362 --- /dev/null +++ b/docs/source/moduledoc/andes.core.rst @@ -0,0 +1,78 @@ +andes.core package +================== + +Submodules +---------- + +andes.core.block module +----------------------- + +.. automodule:: andes.core.block + :members: + :undoc-members: + :show-inheritance: + +andes.core.discrete module +-------------------------- + +.. automodule:: andes.core.discrete + :members: + :undoc-members: + :show-inheritance: + +andes.core.model module +----------------------- + +.. automodule:: andes.core.model + :members: + :undoc-members: + :show-inheritance: + +andes.core.param module +----------------------- + +.. automodule:: andes.core.param + :members: + :undoc-members: + :show-inheritance: + +andes.core.service module +------------------------- + +.. automodule:: andes.core.service + :members: + :undoc-members: + :show-inheritance: + +andes.core.solver module +------------------------ + +.. automodule:: andes.core.solver + :members: + :undoc-members: + :show-inheritance: + +andes.core.common module +------------------------ + +.. automodule:: andes.core.common + :members: + :undoc-members: + :show-inheritance: + +andes.core.var module +--------------------- + +.. automodule:: andes.core.var + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: andes.core + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/moduledoc/andes.io.rst b/docs/source/moduledoc/andes.io.rst new file mode 100644 index 0000000..07df204 --- /dev/null +++ b/docs/source/moduledoc/andes.io.rst @@ -0,0 +1,46 @@ +andes.io package +================ + +Submodules +---------- + +andes.io.matpower module +------------------------ + +.. automodule:: andes.io.matpower + :members: + :undoc-members: + :show-inheritance: + +andes.io.psse module +-------------------- + +.. automodule:: andes.io.psse + :members: + :undoc-members: + :show-inheritance: + +andes.io.txt module +------------------- + +.. automodule:: andes.io.txt + :members: + :undoc-members: + :show-inheritance: + +andes.io.xlsx module +-------------------- + +.. automodule:: andes.io.xlsx + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: andes.io + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/moduledoc/andes.models.rst b/docs/source/moduledoc/andes.models.rst new file mode 100644 index 0000000..bc2da78 --- /dev/null +++ b/docs/source/moduledoc/andes.models.rst @@ -0,0 +1,94 @@ +andes.models package +==================== + +Submodules +---------- + +andes.models.area module +------------------------ + +.. automodule:: andes.models.area + :members: + :undoc-members: + :show-inheritance: + +andes.models.bus module +----------------------- + +.. automodule:: andes.models.bus + :members: + :undoc-members: + :show-inheritance: + +andes.models.governor module +---------------------------- + +.. automodule:: andes.models.governor + :members: + :undoc-members: + :show-inheritance: + +andes.models.group module +------------------------- + +.. automodule:: andes.models.group + :members: + :undoc-members: + :show-inheritance: + +andes.models.line module +------------------------ + +.. automodule:: andes.models.line + :members: + :undoc-members: + :show-inheritance: + +andes.models.pq module +---------------------- + +.. automodule:: andes.models.pq + :members: + :undoc-members: + :show-inheritance: + +andes.models.pv module +---------------------- + +.. automodule:: andes.models.pv + :members: + :undoc-members: + :show-inheritance: + +andes.models.shunt module +------------------------- + +.. automodule:: andes.models.shunt + :members: + :undoc-members: + :show-inheritance: + +andes.models.synchronous module +------------------------------- + +.. automodule:: andes.models.synchronous + :members: + :undoc-members: + :show-inheritance: + +andes.models.timer module +------------------------- + +.. automodule:: andes.models.timer + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: andes.models + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/moduledoc/andes.routines.rst b/docs/source/moduledoc/andes.routines.rst new file mode 100644 index 0000000..ed9e5e1 --- /dev/null +++ b/docs/source/moduledoc/andes.routines.rst @@ -0,0 +1,46 @@ +andes.routines package +====================== + +Submodules +---------- + +andes.routines.base module +-------------------------- + +.. automodule:: andes.routines.base + :members: + :undoc-members: + :show-inheritance: + +andes.routines.eig module +------------------------- + +.. automodule:: andes.routines.eig + :members: + :undoc-members: + :show-inheritance: + +andes.routines.pflow module +--------------------------- + +.. automodule:: andes.routines.pflow + :members: + :undoc-members: + :show-inheritance: + +andes.routines.tds module +------------------------- + +.. automodule:: andes.routines.tds + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: andes.routines + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/moduledoc/andes.utils.rst b/docs/source/moduledoc/andes.utils.rst new file mode 100644 index 0000000..f389021 --- /dev/null +++ b/docs/source/moduledoc/andes.utils.rst @@ -0,0 +1,54 @@ +andes.utils package +=================== + +Submodules +---------- + +andes.utils.cached module +------------------------- + +.. automodule:: andes.utils.cached + :members: + :undoc-members: + :show-inheritance: + +andes.utils.paths module +------------------------ + +.. automodule:: andes.utils.paths + :members: + :undoc-members: + :show-inheritance: + +andes.utils.func module +----------------------- + +.. automodule:: andes.utils.func + :members: + :undoc-members: + :show-inheritance: + +andes.utils.misc module +----------------------- + +.. automodule:: andes.utils.misc + :members: + :undoc-members: + :show-inheritance: + +andes.utils.tab module +---------------------- + +.. automodule:: andes.utils.tab + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: andes.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/moduledoc/andes.variables.rst b/docs/source/moduledoc/andes.variables.rst new file mode 100644 index 0000000..d266faf --- /dev/null +++ b/docs/source/moduledoc/andes.variables.rst @@ -0,0 +1,38 @@ +andes.variables package +======================= + +Submodules +---------- + +andes.variables.dae module +-------------------------- + +.. automodule:: andes.variables.dae + :members: + :undoc-members: + :show-inheritance: + +andes.variables.fileman module +------------------------------ + +.. automodule:: andes.variables.fileman + :members: + :undoc-members: + :show-inheritance: + +andes.variables.report module +----------------------------- + +.. automodule:: andes.variables.report + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: andes.variables + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/old/about.md b/docs/source/old/about.md similarity index 100% rename from doc/source/old/about.md rename to docs/source/old/about.md diff --git a/doc/source/old/advanced_usage.md b/docs/source/old/advanced_usage.md similarity index 100% rename from doc/source/old/advanced_usage.md rename to docs/source/old/advanced_usage.md diff --git a/doc/source/old/basic_usage.md b/docs/source/old/basic_usage.md similarity index 100% rename from doc/source/old/basic_usage.md rename to docs/source/old/basic_usage.md diff --git a/doc/source/old/data_and_models.md b/docs/source/old/data_and_models.md similarity index 100% rename from doc/source/old/data_and_models.md rename to docs/source/old/data_and_models.md diff --git a/doc/source/old/img/accuracy_039_1.png b/docs/source/old/img/accuracy_039_1.png similarity index 100% rename from doc/source/old/img/accuracy_039_1.png rename to docs/source/old/img/accuracy_039_1.png diff --git a/doc/source/old/img/accuracy_039_2.png b/docs/source/old/img/accuracy_039_2.png similarity index 100% rename from doc/source/old/img/accuracy_039_2.png rename to docs/source/old/img/accuracy_039_2.png diff --git a/doc/source/old/img/comp_speed_458.png b/docs/source/old/img/comp_speed_458.png similarity index 100% rename from doc/source/old/img/comp_speed_458.png rename to docs/source/old/img/comp_speed_458.png diff --git a/doc/source/old/img/comp_time_039.png b/docs/source/old/img/comp_time_039.png similarity index 100% rename from doc/source/old/img/comp_time_039.png rename to docs/source/old/img/comp_time_039.png diff --git a/doc/source/old/img/contingency_458.png b/docs/source/old/img/contingency_458.png similarity index 100% rename from doc/source/old/img/contingency_458.png rename to docs/source/old/img/contingency_458.png diff --git a/doc/source/old/img/ssa_benchmarking.png b/docs/source/old/img/ssa_benchmarking.png similarity index 100% rename from doc/source/old/img/ssa_benchmarking.png rename to docs/source/old/img/ssa_benchmarking.png diff --git a/doc/source/old/index.md b/docs/source/old/index.md similarity index 100% rename from doc/source/old/index.md rename to docs/source/old/index.md diff --git a/doc/source/old/installation.md b/docs/source/old/installation.md similarity index 100% rename from doc/source/old/installation.md rename to docs/source/old/installation.md diff --git a/doc/source/old/sas_basics.md b/docs/source/old/sas_basics.md similarity index 100% rename from doc/source/old/sas_basics.md rename to docs/source/old/sas_basics.md diff --git a/docs/source/release-notes.rst b/docs/source/release-notes.rst new file mode 100644 index 0000000..293b3ae --- /dev/null +++ b/docs/source/release-notes.rst @@ -0,0 +1,522 @@ +.. _ReleaseNotes: + +============= +Release Notes +============= + +The APIs before v3.0.0 are in beta and may change without prior notice. + +v1.4 Notes +---------- + +v1.4.3 (2021-09-25) +``````````````````` +This release features parallel processing that cuts the time for +``andes prepare`` by more than half. + +- ``andes prepare`` supports multiprocessing and uses it by default. +- Added aliases ``andes st`` and ``andes prep`` for + ``andes selftest`` and ``andes prepare``. +- ``andes.config_logger`` supports setting new ``stream_level`` and + ``file_level``. + +New exciter models are contributed by Jinning Wang. + +- Added ``AC8B``, ``IEEET3`` and ``ESAC1A``. + +Other changes include disallowing numba's ``nopython`` mode. + +v1.4.2 (2021-09-12) +``````````````````` +- Bug fixes +- Dropped support for ``cvxoptklu``. + +v1.4.1 (2021-09-12) +``````````````````` +- Bug fixes. +- Overhaul of the ``prepare`` and ``undill`` methods. +- ``andes prepare`` can be called for specific models through + ``-m``, which takes one or many model names as arguments. + +v1.4.0 (2021-09-08) +``````````````````` +This release highlights the distributed energy resource protection model. + +- Added ``DGPRCT1`` model to provide DG models with voltage- + and frequency-based protection following IEEE 1547-2018. +- ``REECA1E`` supports frequency droop on power. +- Throws TypeError if type mismatches when using ExtAlgeb and ExtState. + +v1.3 Notes +---------- +v1.3.12 (2021-08-22) +```````````````````` +Plot enhancements: + +- ``plot()`` takes an argument ``mark`` for masking y-axis data based on + the ``left`` and ``right`` range parameters. +- ``TDS.plt`` provides a ``panoview`` method for plotting an panoramic view + for selected variables and devices of a model. + +Models: + +- Added WIP EV models and protection models. + +Test case: +- Added CURENT EI test system. +- Added a number of IEEE 14 bus test systems for specific models. + +v1.3.11 (2021-07-27) +```````````````````` +- Added ``REECA1E`` model with inertia emulation. +- Fixed an issue where the ``vtype`` of services was ignored. +- Changed default DPI for plotting to 100. + +v1.3.10 (2021-06-08) +```````````````````` +- Bug fixes for controllers when generators are off. + +v1.3.9 (2021-06-02) +``````````````````` +- Bug fixes in exciters when generators are offline. +- Added `safe_div` function for initialization equations. + +v1.3.8 (2021-06-02) +``````````````````` +- Added ``REGCVSG`` model for voltage-source controlled renewables. +- Turbine governors are now aware of the generator connection status. + +v1.3.7 (2021-05-03) +``````````````````` +- Allow manually specifying variables needing initialization + preceding a variable. Specify a list of variable names through + ``BaseVar.deps``. + +v1.3.6 (2021-04-23) +``````````````````` +- Patched ESD1 model. Converted `distributed.py` into a package. +- Bug fixes. + +v1.3.5 (2021-03-20) +``````````````````` +- Fixed a bug in connectivity check when bus 0 is islanded. +- Updated notebook examples. +- Updated tutorials. + +v1.3.4 (2021-03-13) +``````````````````` +- Fixed a bug for the generated renewable energy code. + +v1.3.2 (2021-03-08) +``````````````````` +- Relaxed the version requirements for NumPy and SymPy. + +v1.3.1 (2021-03-07) +``````````````````` +- Writes all generated Python code to ``~/.andes/pycode`` by default. +- Uses generated Python code by default instead of `calls.pkl`. +- Works with NumPy 1.20; works on Apple Silicon (use `miniforge`) to + install native Python and NumPy for Apple Silicon. +- Generalized model initialization: automatically determines the + initialization sequence and solve equations iteratively when + necessary. +- In `System.config`, `save_pycode` and `use_pycode` are now + deprecated. + + +v1.3.0 (2021-02-20) +``````````````````` +- Allow `State` variable set `check_init=False` to skip + initialization test. One use case is for integrators + with non-zero inputs (such as state-of-charge integration). +- Solves power flow for systems with multiple areas, each with + one Slack generator. +- Added `Jumper` for connecting two buses with zero impedance. +- `REGCA1` and synchronous generators can take power ratio + parameters `gammap` and `gammaq`. +- New models: `IEESGO` and `IEEET1`, `EXAC4`. +- Refactored exciters, turbine governors, and renewable models + into modules. + + +v1.2 Notes +---------- +v1.2.9 (2021-01-16) +``````````````````` +- Added system connectivity check for islanded buses. +- Depend on `openpyxl` for reading excel files since `xlrd` dropped + support for any format but `xlsx` since v2.0.0. + +v1.2.7 (2020-12-08) +``````````````````` +- Time-domain integration now evaluates anti-windup limiter before + algebraic residuals. It assures that algebraic residuals are + calculated with the new state values if pegged at limits. +- Fixed the conditions for Iq ramping in REGC; + removed ``Iqmax`` and ``Iqmin``. +- Added a new plot function ``plotn`` to allow multiple subplots in + one figure. +- ``TDS.config.g_scale`` is now now used as a factor for scaling + algebraic equations for better convergence. Setting it to 1.0 + functions the same as before. + +v1.2.6 (2020-12-01) +``````````````````` +- Added `TGOV1N` model which sums `pref` and `paux` after + the 1/droop block. +- Added `ZIP` and `FLoad` for dynamic analysis. Need to be initialized + after power flow. +- Added `DAETimeSeries.get_data()` method. +- Added IEEE 14-bus test cases with solar PV (ieee14_solar.xlsx) and + Generic Type 3 wind (ieee14_wt3.xlsx). + +v1.2.5 (2020-11-19) +``````````````````` +- Added `Summary` model to allow arbitrary information for + a test case. Works in `xlsx` and `json` formats. +- PV reactive power limit works. Automatically determines + the number of PVs to convert if `npv2pq=0`. +- Limiter and AntiWindup limiter can use `sign_upper=-1` and + `sign_lower=-1` to negate the provided limits. +- Improved error messages for inconsistent data. +- `DAETimeSeries` functions refactored. + +v1.2.4 (2020-11-13) +``````````````````` +- Added switched shunt class `ShuntSw`. +- BaseParam takes `inconvert` and `oconvert` for converting parameter + elements from and to files. + +v1.2.3 (2020-11-02) +``````````````````` +- Support variable `sys_mva` (system base mva) in equation strings. +- Default support for KVXOPT through ``pip`` installation. + +v1.2.2 (2020-11-01) +``````````````````` +New Models: + +- ``PVD1`` model, WECC distributed PV model. + Supports multiple PVD1 devices on the same bus. +- Added ``ACEc`` model, ACE calculation with continuous freq. + +Changes and fixes: + +- Renamed `TDS._itm_step` to `TDS.itm_step` as a public API. +- Allow variable `sys_f` (system frequency) in equation strings. +- Fixed ACE equation. + measurement. +- Support ``kvxopt`` as a drop-in replacement for ``cvxopt`` + to bring KLU to Windows (and other platforms). +- Added ``kvxopt`` as a dependency for PyPI installation. + +v1.2.1 (2020-10-11) +``````````````````` +- Renamed `models.non_jit` to `models.file_classes`. +- Removed `models/jit.py` as models have to be loaded and instantiated + anyway before undill. +- Skip generating empty equation calls. + +v1.2.0 (2020-10-10) +``````````````````` +This version contains major refactor for speed improvement. + +- Refactored Jacobian calls generation so that for each model, one call + is generated for each Jacobian type. +- Refactored Service equation generation so that the exact arguments are + passed. + +Also contains an experimental Python code dump function. + +- Controlled in ``System.config``, one can turn on ``save_pycode`` to dump + equation and Jacobian calls to ``~/.andes/pycode``. Requires one call to + ``andes prepare``. +- The Python code dump can be reformatted with ``yapf`` through the config + option ``yapf_pycode``. Requires separate installation. +- The dumped Python code can be used for subsequent simulations through + the config option ``use_pycode``. + +v1.1 Notes +---------- +v1.1.5 (2020-10-08) +``````````````````` +- Allow plotting to existing axes with the same plot API. +- Added TGOV1DB model (TGOV1 with an input dead-band). +- Added an experimental numba support. +- Patched `LazyImport` for a snappier command-line interface. +- ``andes selftest -q`` now skips code generation. + +v1.1.4 (2020-09-22) +``````````````````` +- Support `BackRef` for groups. +- Added CLI ``--pool`` to use ``multiprocess.Pool`` for multiple cases. + When combined with ``--shell``, ``--pool`` returns ``System`` Objects + in the list ``system``. +- Fixed bugs and improved manual. + +v1.1.3 (2020-09-05) +``````````````````` +- Improved documentation. +- Minor bug fixes. + +v1.1.2 (2020-09-03) +``````````````````` +- Patched time-domain for continuing simulation. + +v1.1.1 (2020-09-02) +``````````````````` +- Added back quasi-real-time speed control through `--qrt` + and `--kqrt KQRT`. +- Patched the time-domain routine for the final step. + +v1.1.0 (2020-09-01) +``````````````````` +- Defaulted `BaseVar.diag_eps` to `System.Config.diag_eps`. +- Added option `TDS.config.g_scale` to allow for scaling the + algebraic mismatch with step size. +- Added induction motor models `Motor3` and `Motor5` (PSAT models). +- Allow a PFlow-TDS model to skip TDS initialization by setting + `ModelFlags.tds_init` to False. +- Added Motor models `Motor3` and `Motor5`. +- Imported `get_case` and `list_cases` to the root package level. +- Added test cases (Kundur's system) with wind. + +Added Generic Type 3 wind turbine component models: + +- Drive-train models `WTDTA1` (dual-mass model) and `WTDS` + (single-mass model). +- Aerodynamic model `WTARA1`. +- Pitch controller model `WTPTA1`. +- Torque (a.k.a. Pref) model `WTTQA1`. + + +v1.0 Notes +---------- + +v1.0.8 (2020-07-29) +``````````````````` +New features and models: + +- Added renewable energy models `REECA1` and `REPCA1`. +- Added service `EventFlag` which automatically calls events + if its input changes. +- Added service `ExtendedEvent` which flags an extended event + for a given time. +- Added service `ApplyFunc` to apply a numeric function. + For the most cases where one would need `ApplyFunc`, + consider using `ConstService` first. +- Allow `selftest -q` for quick selftest by skipping codegen. +- Improved time stepping logic and convergence tests. +- Updated examples. + +Default behavior changes include: + +- ``andes prepare`` now takes three mutually exclusive arguments, + `full`, `quick` and `incremental`. The command-line now defaults + to the quick mode. ``andes.prepare()`` still uses the full mode. +- ``Model.s_update`` now evaluates the generated and the + user-provided calls in sequence for each service in order. +- Renamed model `REGCAU1` to `REGCA1`. + +v1.0.7 (2020-07-18) +``````````````````` +- Use in-place assignment when updating Jacobian values in Triplets. +- Patched a major but simple bug where the Jacobian refactorization + flag is set to the wrong place. +- New models: PMU, REGCAU1 (tests pending). +- New blocks: DeadBand1, PIFreeze, PITrackAW, PITrackAWFreeze (tests + pending), and LagFreeze (tests pending). +- `andes plot` supports dashed horizontal and vertical lines through + `hline1`, `hline2`, `vline1` and `vline2`. +- Discrete: renamed `DeadBand` to `DeadBandRT` (deadband with + return). +- Service: renamed `FlagNotNone` to `FlagValue` with an option + to flip the flags. +- Other tweaks. + +v1.0.6 (2020-07-08) +``````````````````` +- Patched step size adjustment algorithm. +- Added Area Control Error (ACE) model. + +v1.0.5 (2020-07-02) +``````````````````` +- Minor bug fixes for service initialization. +- Added a wrapper to call TDS.fg_update to + allow passing variables from caller. +- Added pre-event time to the switch_times. + +v1.0.4 (2020-06-26) +``````````````````` +- Implemented compressed NumPy format (npz) for time-domain + simulation output data file. +- Implemented optional attribute `vtype` for specifying data type + for Service. +- Patched COI speed initialization. +- Patched PSS/E parser for two-winding transformer winding and + impedance modes. + +v1.0.3 (2020-06-02) +``````````````````` +- Patches `PQ` model equations where the "or" logic "|" is ignored in + equation strings. To adjust PQ load in time domain simulation, refer + to the note in `pq.py`. +- Allow `Model.alter` to update service values. + +v1.0.2 (2020-06-01) +``````````````````` +- Patches the conda-forge script to use SymPy < 1.6. After SymPy version + 1.5.1, comparison operations cannot be sympified. Pip installations are + not affected. + +v1.0.1 (2020-05-27) +``````````````````` +- Generate one lambda function for each of f and g, instead of generating + one for each single f/g equation. Requires to run `andes prepare` after + updating. + +v1.0.0 (2020-05-25) +``````````````````` +This release is going to be tagged as v0.9.5 and later tagged as v1.0.0. + +- Added verification results using IEEE 14-bus, NPCC, and WECC systems + under folder `examples`. +- Patches GENROU and EXDC2 models. +- Updated test cases for WECC, NPCC IEEE 14-bus. +- Documentation improvements. +- Various tweaks. + +Pre-v1.0.0 +---------- + +v0.9.4 (2020-05-20) +``````````````````` + +- Added exciter models EXST1, ESST3A, ESDC2A, SEXS, and IEEEX1, + turbine governor model IEEEG1 (dual-machine support), and stabilizer + model ST2CUT. +- Added blocks HVGate and LVGate with a work-around for sympy.maximum/ + minimum. +- Added services `PostInitService` (for storing initialized values), and + `VarService` (variable services that get updated) after limiters and before + equations). +- Added service `InitChecker` for checking initialization values against + typical values. Warnings will be issued when out of bound or equality/ + inequality conditions are not met. +- Allow internal variables to be associated with a discrete component which + will be updated before initialization (through `BaseVar.discrete`). +- Allow turbine governors to specify an optional `Tn` (turbine rating). If + not provided, turbine rating will fall back to `Sn` (generator rating). +- Renamed `OptionalSelect` to `DataSelect`; Added `NumSelect`, the array-based + version of `DataSelect`. +- Allow to regenerate code for updated models through ``andes prepare -qi``. +- Various patches to allow zeroing out time constants in transfer functions. + +v0.9.3 (2020-05-05) +``````````````````` +This version contains bug fixes and performance tweaks. + +- Fixed an `AntiWindup` issue that causes variables to stuck at limits. +- Allow ``TDS.run()`` to resume from a stopped simulation and run to the new + end time in ``TDS.config.tf``. +- Improved TDS data dump speed by not constructing DataFrame by default. +- Added tests for `kundur_full.xlsx` and `kundur_aw.xlsx` to ensure + results are the same as known values. +- Other bug fixes. + +v0.9.1 (2020-05-02) +``````````````````` +This version accelerates computations by about 35%. + +- Models with flag ``collate=False``, which is the new default, + will slice DAE arrays for all internal vars to reduce copying back and forth. +- The change above greatly reduced computation time. + For ``kundur_ieeest.xlsx``, simulation time is down from 2.50 sec to 1.64 sec. +- The side-effects include a change in variable ordering in output lst file. + It also eliminated the feasibility of evaluating model equations in + parallel, which has not been implemented and does not seem promising in Python. +- Separated symbolic processor and documentation generator from Model into + ``SymProcessor`` and ``Documenter`` classes. +- ``andes prepare`` now shows progress in the console. +- Store exit code in ``System.exit_code`` and returns to system when called + from CLI. +- Refactored the solver interface. +- Patched Config.check for routines. +- SciPy Newton-Krylov power flow solver is no longer supported. +- Patched a bug in v0.9.0 related to `dae.Tf`. + +v0.8.8 (2020-04-28) +``````````````````` +This update contains a quick but significant fix to boost the simulation speed by avoiding +calls to empty user-defined numerical calls. + +- In `Model.flags` and `Block.flags`, added `f_num`, `g_num` and `j_num` to indicate + if user-defined numerical calls exist. +- In `Model.f_update`, `Model.g_update` and `Model.j_update`, check the above flags + to avoid unnecessary calls to empty numeric functions. +- For the `kundur_ieeest.xlsx` case, simulation time was reduced from 3.5s to 2.7s. + +v0.8.7 (2020-04-28) +``````````````````` +- Changed `RefParam` to a service type called `BackRef`. +- Added `DeviceFinder`, a service type to find device idx when not provided. + `DeviceFinder` will also automatically add devices if not found. +- Added `OptionalSelect`, a service type to select optional parameters if provided + and select fallback ones otherwise. +- Added discrete types `Derivative`, `Delay`, and `Average`, +- Implemented full IEEEST stabilizer. +- Implemented COI for generator speed and angle measurement. + +v0.8.6 (2020-04-21) +``````````````````` +This release contains important documentation fixes and two new blocks. + +- Fixed documentations in `andes doc` to address a misplacement of symbols and equations. +- Converted all blocks to the division-free formulation (with `dae.zf` renamed to `dae.Tf`). +- Fixed equation errors in the block documentation. +- Implemented two new blocks: Lag2ndOrd and LeadLag2ndOrd. +- Added a prototype for IEEEST stabilizer with some fixes needed. + +v0.8.5 (2020-04-17) +``````````````````` +- Converted the differential equations to the form of ``T \dot{x} = f(x, y)``, where T is supplied to + ``t_const`` of ``State/ExtState``. +- Added the support for Config fields in documentation (in ``andes doc`` and on readthedocs). +- Added Config consistency checking. +- Converted `Model.idx` from a list to `DataParam`. +- Renamed the API of routines (summary, init, run, report). +- Automatically generated indices now start at 1 (i.e., "GENCLS_1" is the first GENCLS device). +- Added test cases for WECC system. The model with classical generators is verified against TSAT. +- Minor features: `andes -v 1` for debug output with levels and line numbers. + +v0.8.4 (2020-04-07) +``````````````````` +- Added support for JSON case files. Convert existing case file to JSON with ``--convert json``. +- Added support for PSS/E dyr files, loadable with ``-addfile ADDFILE``. +- Added ``andes plot --xargs`` for searching variable name and plotting. See example 6. +- Various bug fixes: Fault power injection fix; + +v0.8.3 (2020-03-25) +``````````````````` +- Improved storage for Jacobian triplets (see ``andes.core.triplet.JacTriplet``). +- On-the-fly parameter alteration for power flow calculations (``Model.alter`` method). +- Exported frequently used functions to the root package + (``andes.config_logger``, ``andes.run``, ``andes.prepare`` and ``andes.load``). +- Return a list of System objects when multiprocessing in an interactive environment. +- Exported classes to `andes.core`. +- Various bug fixes and documentation improvements. + +v0.8.0 (2020-02-12) +``````````````````` +- First release of the hybrid symbolic-numeric framework in ANDES. +- A new framework is used to describe DAE models, generate equation documentation, and generate code for + numerical simulation. +- Models are written in the new framework. Supported models include GENCLS, GENROU, EXDC2, TGOV1, TG2 +- PSS/E raw parser, MATPOWER parser, and ANDES xlsx parser. +- Newton-Raphson power flow, trapezoidal rule for numerical integration, and full eigenvalue analysis. + +v0.6.9 (2020-02-12) +``````````````````` +- Version 0.6.9 is the last version for the numeric-only modeling framework. +- This version will not be updated any more. + But, models, routines and functions will be ported to the new version. \ No newline at end of file diff --git a/docs/source/troubleshooting.rst b/docs/source/troubleshooting.rst new file mode 100644 index 0000000..28670b6 --- /dev/null +++ b/docs/source/troubleshooting.rst @@ -0,0 +1,59 @@ +.. _troubleshooting: + +************************** +Troubleshooting +************************** + +Import Errors +============= + +ImportError: DLL load failed +---------------------------- + +Platform: Windows, error message: + + ImportError: DLL load failed: The specified module could not be found. + +This usually happens when andes is not installed in a Conda environment +but instead in a system-wide Python whose library path was not correctly +set in environment variables. + +The easiest fix is to install andes in a Conda environment. + + +Runtime Errors +============== + +EOFError: Ran out of input +-------------------------- + +The error message looks like :: + + Traceback (most recent call last): + File "/home/user/miniconda3/envs/andes/bin/andes", line 11, in + load_entry_point('andes', 'console_scripts', 'andes')() + File "/home/user/repos/andes/andes/cli.py", line 179, in main + return func(cli=True, **vars(args)) + File "/home/user/repos/andes/andes/main.py", line 514, in run + system = run_case(cases[0], codegen=codegen, **kwargs) + File "/home/user/repos/andes/andes/main.py", line 304, in run_case + system = load(case, codegen=codegen, **kwargs) + File "/home/user/repos/andes/andes/main.py", line 284, in load + system.undill() + File "/home/user/repos/andes/andes/system.py", line 980, in undill + loaded_calls = self._load_pkl() + File "/home/user/repos/andes/andes/system.py", line 963, in _load_pkl + loaded_calls = dill.load(f) + File "/home/user/miniconda3/envs/andes/lib/python3.7/site-packages/dill/_dill.py", line 270, in load + return Unpickler(file, ignore=ignore, **kwds).load() + File "/home/user/miniconda3/envs/andes/lib/python3.7/site-packages/dill/_dill.py", line 473, in load + obj = StockUnpickler.load(self) + EOFError: Ran out of input + +Resolution: + +The error indicates the file for generated code is corrupt or inaccessible. +It can be fixed by running ``andes prepare`` from the command line. + +If the issue persists, try removing ``~/.andes/calls.pkl`` and running +``andes prepare`` agian. \ No newline at end of file diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst new file mode 100644 index 0000000..6c7b67c --- /dev/null +++ b/docs/source/tutorial.rst @@ -0,0 +1,1058 @@ +.. _tutorial: + +******** +Tutorial +******** +ANDES can be used as a command-line tool or a library. +The command-line interface (CLI) comes handy to run studies. +As a library, it can be used interactively in the IPython shell or the Jupyter Notebook. +This chapter describes the most common usages. + +Please see the cheat sheet if you are looking for quick help. + +.. _sec-command: + +Command Line Usage +================== + +Basic Usage +----------- + +ANDES is invoked from the command line using the command ``andes``. +Running ``andes`` without any input is equal to ``andes -h`` or ``andes --help``. +It prints out a preamble with version and environment information and help commands:: + + _ _ | Version 1.3.4 + /_\ _ _ __| |___ ___ | Python 3.8.6 on Linux, 03/17/2021 11:28:55 AM + / _ \| ' \/ _` / -_|_-< | + /_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY. + + usage: andes [-h] [-v {1,10,20,30,40}] + {run,plot,doc,misc,prepare,selftest} ... + + positional arguments: + {run,plot,doc,misc,prepare,selftest} + [run] run simulation routine; [plot] plot results; + [doc] quick documentation; [misc] misc. functions; + [prepare] prepare the numerical code; [selftest] run + self test. + + optional arguments: + -h, --help show this help message and exit + -v {1,10,20,30,40}, --verbose {1,10,20,30,40} + Verbosity level in 10-DEBUG, 20-INFO, 30-WARNING, or + 40-ERROR. + +.. note:: + + If the ``andes`` command is not found, check if (1) the installation was successful, and + (2) you have activated the environment where ANDES is installed. + +The first-level commands are chosen from ``{run,plot,doc,misc,prepare,selftest}``. +Each command contains a group of sub-commands, which can be looked up with ``-h``. +For example, use ``andes run -h`` to look up the sub-commands for ``run``. +The most frequently used commands are explained in the following. + +``andes`` has an option for the program verbosity level, controlled by ``-v LEVEL`` or ``--verbose LEVEL``, +where level is a number chosen from the following: +1 (DEBUG with code location info), 10 (DEBUG), 20 (INFO), 30 (WARNING), 40 (ERROR), or 50 (CRITICAL). +For example, to show debugging outputs, use ``andes -v 10``, followed by the first-level commands. +The default logging level is 20 (INFO). + +andes selftest +-------------- +After the installation, please run ``andes selftest`` from the command line to test ANDES functionality. +It might take a minute to run the full self-test suite. +An example output looks like :: + + test_docs (test_1st_system.TestCodegen) ... ok + test_alter_param (test_case.Test5Bus) ... ok + ... + ... (outputs are truncated) + ... + test_pflow_mpc (test_pflow_matpower.TestMATPOWER) ... ok + + ---------------------------------------------------------------------- + Ran 23 tests in 13.834s + + OK + +There may be more test than what is shown above. Make sure that all tests have passed. + +.. warning :: + ANDES is getting updates frequently. After every update, please run + ``andes selftest`` to confirm the functionality. + The command also makes sure the generated code is up to date. + See `andes prepare`_ for more details on automatic code generation. + +andes prepare +----------------- +.. _`andes prepare`: + +The symbolically defined models in ANDES need to be generated into numerical code for simulation. +The code generation can be manually called with ``andes prepare``. +Generated code are serialized to ``~/.andes/calls.pkl`` and dumped as Python code to ``~/.andes/pycode``. +In addition, ``andes selftest`` implicitly calls the code generation. +If you are using ANDES as a package in the user mode (namely, you have not modified or updated ANDES code), +you will not need to call it again. + +.. note :: + To developers: + As of version 1.3.0, ANDES stores all generated Python code explicitly + in ``.py`` files under the folder ``~/.andes/pycode``. + Priority is given to Python code when reloading for simulation. + +Option ``-q`` or ``--quick`` (enabled by default) can be used to speed up the code generation. +It skips the generation of :math:`\LaTeX`-formatted equations, which are only used in documentation and the interactive +mode. + +Option ``-i`` or ``--incremental``, instead of ``-q``, can be used to further speed up the code generation +during model development. +``andes prepare -i`` only generates code for models that have been modified since the last code generation. + +.. note :: + To developers: + ``andes prepare -i`` needs to be called immediately following any model equation modification. + Otherwise, simulation results will not reflect the new equations and will likely lead to an error. + +andes run +------------- +``andes run`` is the entry point for power system analysis routines. +``andes run`` takes one positional argument, ``filename`` , along with other optional keyword arguments. +``filename`` is the test case path, either relative or absolute. + +For example, the command ``andes run kundur_full.xlsx`` uses a relative path. +If will work only if ``kundur_full.xlsx`` exists in the current directory of the command line. +The commands ``andes run /Users/hcui7/kundur_full.xlsx`` (on macOS) or +``andes run C:/Users/hcui7/kundur_full.xlsx`` (on Windows) use absolute paths to the case files +and do not depend on the command-line current directory. + +.. note :: + When working with the command line, use ``cd`` to change directory to the folder + containing your test case. + Spaces in folder and file names need to be escaped properly. + +Routine +....... +Option ``-r`` or ``-routine`` is used for specifying the analysis routine, +followed by the routine name. +Available routine names include ``pflow, tds, eig``: +- ``pflow`` for power flow +- ``tds`` for time domain simulation +- ``eig`` for eigenvalue analysis + +``pflow`` is the default if ``-r`` is not given. + +Power flow +.......... +Locate the ``kundur_full.xlsx`` file at ``andes/cases/kundur/kundur_full.xlsx`` under the source code folder, +or download it from +`the repository `_. + +Change to the directory containing ``kundur_full.xlsx``. +To run power flow, execute the following in the command line: + +.. code:: bash + + andes run kundur_full.xlsx + +The full path to the case file is also recognizable, for example, + +.. code:: bash + + andes run /home/user/andes/cases/kundur/kundur_full.xlsx + +The power flow report will be saved to the current directory where ANDES is run. +The report contains four sections: a) system statistics, b) ac bus +and dc node data, c) ac line data, and d) the initialized values of other +algebraic variables and state variables. + +Time-domain simulation +...................... + +To run the time domain simulation (TDS) for ``kundur_full.xlsx``, run + +.. code:: bash + + andes run kundur_full.xlsx -r tds + +The output looks like:: + + Parsing input file + Input file kundur_full.xlsx parsed in 0.5425 second. + -> Power flow calculation with Newton Raphson method: + 0: |F(x)| = 14.9283 + 1: |F(x)| = 3.60859 + 2: |F(x)| = 0.170093 + 3: |F(x)| = 0.00203827 + 4: |F(x)| = 3.76414e-07 + Converged in 5 iterations in 0.0080 second. + Report saved to in 0.0036 second. + -> Time Domain Simulation: + Initialization tests passed. + Initialization successful in 0.0152 second. + 0%| | 0/100 [00:00: Applying status toggle on Line idx=Line_8 + 100%|██████████████████████████████████████████| 100/100 [00:03<00:00, 28.99%/s] + Simulation completed in 3.4500 seconds. + TDS outputs saved in 0.0377 second. + -> Single process finished in 4.4310 seconds. + +This execution first solves the power flow as a starting point. +Next, the numerical integration simulates 20 seconds, during which a predefined +breaker opens at 2 seconds. + +TDS produces two output files by default: +a compressed NumPy data file ``kundur_full_out.npz`` +and a variable name list file ``kundur_full_out.lst``. +The list file contains three columns: +variable indices, variable name in plain text, and variable +name in the :math:`\LaTeX` format. +The variable indices are needed to plot the needed variable. + +Disable output +.............. +The output files can be disabled with option ``--no-output`` or ``-n``. +It is useful when only computation is needed without saving the results. + +Profiling +......... +Profiling is useful for analyzing the computation time and code efficiency. +Option ``--profile`` enables the profiling of ANDES execution. +The profiling output will be written in two files in the current folder, one ending with ``_prof.txt`` and the +other one with ``_prof.prof``. + +The text file can be opened with a text editor, and the ``.prof`` file can be visualized with ``snakeviz``, +which can be installed with ``pip install snakeviz``. + +If the output is disabled, profiling results will be printed to stdio. + +Multiprocessing +............... +ANDES takes multiple files inputs or wildcard. +Multiprocessing will be triggered if more than one valid input files are found. +For example, to run power flow for files with a prefix of ``case5`` and a suffix (file extension) +of ``.m``, run + +.. code:: bash + + andes run case5*.m + +Test cases that match the pattern, including ``case5.m`` and ``case57.m``, will be processed. + +Option ``--ncpu NCPU`` can be used to specify the maximum number of parallel processes. +By default, all cores will be used. A small number can be specified to increase operation system responsiveness. + +Format converter +................ +.. _`format converter`: + +ANDES recognizes a few input formats and can convert input systems into the ``xlsx`` format. +This function is useful when one wants to use models that are unique in ANDES. + +The command for converting is ``--convert`` (or ``-c``), +following the output format (only ``xlsx`` is currently supported). +For example, to convert ``case5.m`` into the ``xlsx`` format, run + +.. code:: bash + + andes run case5.m --convert xlsx + +The output messages will look like :: + + Parsing input file + CASE5 Power flow data for modified 5 bus, 5 gen case based on PJM 5-bus system + Input file case5.m parsed in 0.0033 second. + xlsx file written to + Converted file /Users/user/repos/andes/cases/matpower/case5.xlsx written in 0.5079 second. + -> Single process finished in 0.8765 second. + +Note that ``--convert`` will only create sheets for existing models. + +In case one wants to create template sheets to add models later, ``--convert-all`` can be used instead. + +If one wants to add workbooks to an existing xlsx file, +one can combine option ``--add-book ADD_BOOK`` (or ``-b ADD_BOOK``), +where ``ADD_BOOK`` can be a single model name or comma-separated +model names (without any space). For example, + +.. code:: bash + + andes run kundur.raw -c -b Toggler + +will convert file ``kundur.raw`` into an ANDES xlsx file (kundur.xlsx) and add +a template workbook for `Toggler`. + +.. Warning:: + With ``--add-book``, the xlsx file will be overwritten. + Any **empty or non-existent models** will be REMOVED. + +PSS/E inputs +............ +To work with PSS/E input files (.raw and .dyr), one need to provide the +raw file through ``casefile`` and pass the dyr file through ``--addfile``. +For example, in ``andes/cases/kundur``, one can run the power flow using + +.. code:: bash + + andes run kundur.raw + +and run a no-disturbance time-domain simulation using + +.. code:: bash + + andes run kundur.raw --addfile kundur_full.dyr -r tds + +.. note:: + If one wants to modify the parameters of models that are supported + by both PSS/E and ANDES, one can directly + edit those dynamic parameters in the ``.raw`` and ``.dyr`` files + to maintain interoperability with other tools. + +To create add a disturbance, there are two options. +The recommended option is to convert the PSS/E data into an ANDES xlsx file, +edit it and run (see the previous subsection). + +An alternative is to edit the ``.dyr`` file with a planin-text editor (such as Notepad) +and append lines customized for ANDES models. +This is for advanced users after referring to ``andes/io/psse-dyr.yaml``, +at the end of which one can find the format of ``Toggler``: :: + + # === Custom Models === + Toggler: + inputs: + - model + - dev + - t + +To define two Togglers in the ``.dyr`` file, one can append lines to the end +of the file using, for example, :: + + Line 'Toggler' Line_2 1 / + Line 'Toggler' Line_2 1.1 / + +which is separated by spaces and ended with a slash. The second parameter +is fixed to the model name quoted by a pair of single quotation marks, +and the others correspond to the fields defined in the above``inputs``. +Each entry is properly terminated with a forward slash. + +andes plot +-------------- +``andes plot`` is the command-line tool for plotting. +It currently supports time-domain simulation data. +Three positional arguments are required, and a dozen of optional arguments are supported. + +positional arguments: + + +----------------+----------------------------------------------------------------------+ + | Argument | Description | + +================+======================================================================+ + | filename | simulation output file name, which should end with | + | | `out`. File extension can be omitted. | + +----------------+----------------------------------------------------------------------+ + | x | the X-axis variable index, typically 0 for Time | + +----------------+----------------------------------------------------------------------+ + | y | Y-axis variable indices. Space-separated indices or a | + | | colon-separated range is accepted | + +----------------+----------------------------------------------------------------------+ + +For example, to plot the generator speed variable of synchronous generator 1 +``omega GENROU 0`` versus time, read the indices of the variable (2) and time +(0), run + +.. code:: bash + + andes plot kundur_full_out.lst 0 2 + +In this command, ``andes plot`` is the plotting command for TDS output files. +``kundur_full_out.lst`` is list file name. ``0`` is the index of ``Time`` for +the x-axis. ``2`` is the index of ``omega GENROU 0``. Note that for the the file name, +either ``kundur_full_out.lst`` or ``kundur_full_out.npy`` works, as the program will +automatically extract the file name. + +The y-axis variabla indices can also be specified in the Python range fashion +. For example, ``andes plot kundur_full_out.npy 0 2:21:6`` will plot the +variables at indices 2, 8, 14 and 20. + +``andes plot`` will attempt to render with :math:`\LaTeX` if ``dvipng`` program is in the search path. +Figures rendered by :math:`\LaTeX` is considerably better in symbols quality but takes much longer time. +In case :math:`\LaTeX` is available but fails (frequently happens on Windows), the option ``-d`` can be used to disable +:math:`\LaTeX` rendering. + +Other optional arguments are listed in the following. + +optional arguments: + ============================ ====================================================== + Argument Description + ---------------------------- ------------------------------------------------------ + optional arguments: + -h, --help show this help message and exit + --xmin LEFT minimum value for X axis + --xmax RIGHT maximum value for X axis + --ymax YMAX maximum value for Y axis + --ymin YMIN minimum value for Y axis + --find FIND find variable indices that matches the given pattern + ---------------------------- ------------------------------------------------------ + --xargs XARGS find variable indices and return as a list of + arguments usable with "| xargs andes plot" + ---------------------------- ------------------------------------------------------ + --exclude EXCLUDE pattern to exclude in find or xargs results + -x XLABEL, --xlabel XLABEL x-axis label text + -y YLABEL, --ylabel YLABEL y-axis label text + -s, --savefig save figure. The default fault is `png`. + ---------------------------- ------------------------------------------------------ + -format SAVE_FORMAT format for savefig. Common formats such as png, pdf, jpg are supported + ---------------------------- ------------------------------------------------------ + --dpi DPI image resolution in dot per inch (DPI) + -g, --grid grid on + --greyscale greyscale on + -d, --no-latex disable LaTeX formatting + -n, --no-show do not show the plot window + --ytimes YTIMES scale the y-axis values by YTIMES + -c, --to-csv convert npy output to csv + ============================ ====================================================== + +.. _andes_doc: + +andes doc +--------- +``andes doc`` is a tool for quick lookup of model and routine documentation. +It is intended as a quick way for documentation. + +The basic usage of ``andes doc`` is to provide a model name or a routine name as the positional argument. +For a model, it will print out model parameters, variables, and equations to the stdio. +For a routine, it will print out fields in the Config file. +If you are looking for full documentation, visit `andes.readthedocs.io `_. + +For example, to check the parameters for model ``Toggler``, run + +.. code-block:: shell-session + + $ andes doc Toggler + Model in Group + + Time-based connectivity status toggler. + + Parameters + + Name | Description | Default | Unit | Type | Properties + -------+------------------------------+---------+------+------------+----------- + u | connection status | 1 | bool | NumParam | + name | device name | | | DataParam | + model | Model or Group of the device | | | DataParam | mandatory + | to control | | | | + dev | idx of the device to control | | | IdxParam | mandatory + t | switch time for connection | -1 | | TimerParam | mandatory + | status | | | | + +To list all supported models, run + +.. code-block:: shell-session + + $ andes doc -l + Supported Groups and Models + + Group | Models + -----------------+------------------------------------------- + ACLine | Line + ACTopology | Bus + Collection | Area + DCLink | Ground, R, L, C, RCp, RCs, RLs, RLCs, RLCp + DCTopology | Node + Exciter | EXDC2 + Experimental | PI2 + FreqMeasurement | BusFreq, BusROCOF + StaticACDC | VSCShunt + StaticGen | PV, Slack + StaticLoad | PQ + StaticShunt | Shunt + SynGen | GENCLS, GENROU + TimedEvent | Toggler, Fault + TurbineGov | TG2, TGOV1 + +To view the Config fields for a routine, run + +.. code-block:: shell-session + + $ andes doc TDS + Config Fields in [TDS] + + Option | Value | Info | Acceptable values + -----------+-------+----------------------------------------+------------------- + sparselib | klu | linear sparse solver name | ('klu', 'umfpack') + tol | 0.000 | convergence tolerance | float + t0 | 0 | simulation starting time | >=0 + tf | 20 | simulation ending time | >t0 + fixt | 0 | use fixed step size (1) or variable | (0, 1) + | | (0) | + shrinkt | 1 | shrink step size for fixed method if | (0, 1) + | | not converged | + tstep | 0.010 | the initial step step size | float + max_iter | 15 | maximum number of iterations | >=10 + + +andes misc +---------- +``andes misc`` contains miscellaneous functions, such as configuration and output cleaning. + +Configuration +............. +ANDES uses a configuration file to set runtime configs for the system routines, and models. +``andes misc --save-config`` saves all configs to a file. +By default, it saves to ``~/.andes/andes.conf`` file, where ``~`` +is the path to your home directory. + +With ``andes misc --edit-config``, you can edit ANDES configuration handy. +The command will automatically save the configuration to the default location if not exist. +The shorter version ``--edit`` can be used instead as Python matches it with ``--edit-config``. + +You can pass an editor name to ``--edit``, such as ``--edit vim``. +If the editor name is not provided, it will use the following defaults: +- Microsoft Windows: notepad. +- GNU/Linux: the ``$EDITOR`` environment variable, or ``vim`` if not exist. + +For macOS users, the default is vim. +If not familiar with vim, you can use nano with ``--edit nano`` or TextEdit with +``--edit "open -a TextEdit"``. + +Cleanup +....... +``andes misc -C, --clean`` + +Option to remove any generated files. Removes files with any of the following +suffix: ``_out.txt`` (power flow report), ``_out.npy`` (time domain data), +``_out.lst`` (time domain variable list), and ``_eig.txt`` (eigenvalue report). + +Interactive Usage +================= +This section is a tutorial for using ANDES in an interactive environment. +All interactive shells are supported, including Python shell, IPython, Jupyter Notebook and Jupyter Lab. +The examples below uses Jupyter Notebook. + +Jupyter Notebook +---------------- +Jupyter notebook is a convenient tool to run Python code and present results. +Jupyter notebook can be installed with + +.. code:: bash + + conda install jupyter notebook + +After the installation, change directory to the folder where you wish to store notebooks, +then start the notebook with + +.. code:: bash + + jupyter notebook + +A browser window should open automatically with the notebook browser loaded. +To create a new notebook, use the "New" button near the upper-right corner. + +.. note:: + + Code lines following ``>>>`` are Python code. + Python code should be typed into a Python shell, IPython, or Jupyter Notebook, + not a Anaconda Prompt or command-line shell. + +Import +------ +Like other Python libraries, ANDES needs to be imported into an interactive Python environment. + +.. code:: python + + >>> import andes + >>> andes.config_logger() + +Verbosity +--------- +If you are debugging ANDES, you can enable debug messages with + +.. code:: python + + >>> andes.config_logger(stream_level=10) + +The ``stream_level`` uses the same verbosity levels (see `Basic Usage`_) as for the command-line. +If not explicitly enabled, the default level 20 (INFO) will apply. + +To set a new logging level for the current session, call ``config_logger`` with +the desired new levels. + +Making a System +--------------- +Before running studies, a "System" object needs to be create to hold the system data. +The System object can be created by passing the path to the case file the entry-point function. +For example, to run the file ``kundur_full.xlsx`` in the same directory as the notebook, use + +.. code:: python + + >>> ss = andes.run('kundur_full.xlsx') + +This function will parse the input file, run the power flow, and return the system as an object. +Outputs will look like :: + + Parsing input file + Input file kundur_full.xlsx parsed in 0.4172 second. + -> Power flow calculation with Newton Raphson method: + 0: |F(x)| = 14.9283 + 1: |F(x)| = 3.60859 + 2: |F(x)| = 0.170093 + 3: |F(x)| = 0.00203827 + 4: |F(x)| = 3.76414e-07 + Converged in 5 iterations in 0.0222 second. + Report saved to in 0.0015 second. + -> Single process finished in 0.4677 second. + +In this example, ``ss`` is an instance of ``andes.System``. +It contains member attributes for models, routines, and numerical DAE. + +Naming convention for the ``System`` attributes are as follows + +- Model attributes share the same name as class names. For example, ``ss.Bus`` is the ``Bus`` instance. +- Routine attributes share the same name as class names. For example, ``ss.PFlow`` and ``ss.TDS`` are the + routine instances. +- The numerical DAE instance is in lower case ``ss.dae``. + +To work with PSS/E inputs, refer to notebook `Example 2`_. + +.. _`Example 2`: https://github.com/cuihantao/andes/blob/master/examples/2.%20inspect_data.ipynb + +Output path +........... +By default, outputs will be saved to the folder where Python is run (or where the notebook is run). +In case you need to organize outputs, a path prefix can be passed to ``andes.run()`` through +``output_path``. +For example, + +.. code:: python + + >>> ss = andes.run('kundur_full.xlsx', output_path='outputs/') + +will put outputs into folder ``outputs`` relative to the current path. +You can also supply an absolute path to ``output_path``. + +No output +......... +Outputs can be disabled by passing ``output_path=True`` to ``andes.run()``. +This is useful when one wants to test code without looking at results. +For example, do + +.. code:: python + + >>> ss = andes.run('kundur_full.xlsx', no_output=True) + +Inspecting Parameter +-------------------- + +DataFrame +......... +Parameters for the loaded system can be easily inspected in Jupyter Notebook using Pandas. + +Input parameters for each model instance is returned by the ``as_df()`` function. +For example, to view the input parameters for ``Bus``, use + +.. code:: python + + >>> ss.Bus.as_df() + +A table will be printed with the columns being each parameter and the rows being Bus instances. +Parameter in the table is the same as the input file without per-unit conversion. + +Parameters have been converted to per unit values under system base. +To view the per unit values, use the ``as_df(vin=True)`` method. +For example, to view the system-base per unit value of ``GENROU``, use + +.. code:: python + + >>> ss.GENROU.as_df(vin=True) + +Dict +.... +In case you need the parameters in ``dict``, use ``as_dict()``. +Values returned by ``as_dict()`` are system-base per unit values. +To retrieve the input data, use ``as_dict(vin=True)``. + +For example, to retrieve the original input data of GENROU's, use + +.. code:: python + + >>> ss.GENROU.as_dict(vin=True) + +Running Studies +--------------- + +Three routines are currently supported: PFlow, TDS and EIG. +Each routine provides a ``run()`` method to execute. +The System instance contains member attributes having the same names. +For example, to run the time-domain simulation for ``ss``, use + +.. code:: python + + >>> ss.TDS.run() + +Checking Exit Code +------------------ +``andes.System`` contains field ``exit_code`` for checking if error +occurred in run time. +A normal completion without error should always have ``exit_code == 0``. +One should read output messages carefully and check the exit code, which is +particularly useful for batch simulations. + +Error may occur in any phase - data parsing, power flow, or simulation. +To diagnose, split the simulation steps and check the outputs from each one. + +Plotting TDS Results +-------------------- +TDS comes with a plotting utility for interactive usage. +After running the simulation, a ``plotter`` attributed will be created for ``TDS``. +To use the plotter, provide the attribute instance of the variable to plot. +For example, to plot all the generator speed, use + +.. code:: python + + >>> ss.TDS.plotter.plot(ss.GENROU.omega) + +.. note:: + + If you see the error + + AttributeError: 'NoneType' object has no attribute 'plot' + + You will need to manually load plotter with + + .. code:: python + + >>> ss.TDS.load_plotter() + +Optional indices is accepted to choose the specific elements to plot. +It can be passed as a tuple to the ``a`` argument + +.. code:: python + + >>> ss.TDS.plotter.plot(ss.GENROU.omega, a=(0, )) + +In the above example, the speed of the "zero-th" generator will be plotted. + +Scaling +....... +A lambda function can be passed to argument ``ycalc`` to scale the values. +This is useful to convert a per-unit variable to nominal. +For example, to plot generator speed in Hertz, use + +.. code:: python + + >>> ss.TDS.plotter.plot(ss.GENROU.omega, a=(0, ), + ycalc=lambda x: 60*x, + ) + +Formatting +.......... +A few formatting arguments are supported: + +- ``grid = True`` to turn on grid display +- ``greyscale = True`` to switch to greyscale +- ``ylabel`` takes a string for the y-axis label + +Extracting Data +--------------- +One can extract data from ANDES for custom plotting. +Variable names can be extracted from the following fields of +``ss.dae``: + +Un-formatted names (non-LaTeX): + +- ``x_name``: state variable names +- ``y_name``: algebraic variable names +- ``xy_name``: state variable names followed by algebraic ones + +LaTeX-formatted names: + +- ``x_tex_name``: state variable names +- ``y_tex_name``: algebraic variable names +- ``xy_tex_name``: state variable names followed by algebraic ones + +These lists only contain the variable names used in the current analysis routine. +If you only ran power flow, ``ss.dae.y_name`` will only contain the power flow +algebraic variables, and ``ss.dae.x_name`` will likely be empty. +After initializing time-domain simulation, these lists will be extended to include +all variables used by TDS. + +In case you want to extract the discontinuous flags from TDS, you can +set ``store_z`` to ``1`` in the config file under section ``[TDS]``. +When enabled, discontinuous flag names will be populated at + +- ``ss.dae.z_name``: discontinuous flag names +- ``ss.dae.z_tex_name``: LaTeX-formatted discontinuous flag names + +If not enabled, both lists will be empty. + +Power flow solutions +.................... +The full power flow solutions are stored at ``ss.dae.xy`` after running +power flow (and before initializing dynamic models). +You can extract values from ``ss.dae.xy``, which corresponds to the names +in ``ss.dae.xy_name`` or ``ss.dae.xy_tex_name``. + +If you want to extract variables from a particular model, for example, +bus voltages, you can directly access the ``v`` field of that variable + +.. code:: python + + >>> import numpy as np + >>> voltages = np.array(ss.Bus.v.v) + +which stores a **copy** of the bus voltage values. Note that the first ``v`` +is the voltage variable of ``Bus``, and the second ``v`` stands for *value*. +It is important to make a copy by using ``np.array()`` to avoid accidental +changes to the solutions. + +If you want to extract bus voltage phase angles, do + +.. code:: python + + >>> angle = np.array(ss.Bus.a.v) + +where ``a`` is the field name for voltage angle. + +To find out names of variables in a model, refer to andes_doc_. + +Time-domain data +................ + +Time-domain simulation data will be ready when simulation completes. +It is stored in ``ss.dae.ts``, which has the following fields: + +- ``txyz``: a two-dimensional array. The first column is time stamps, + and the following are variables. Each row contains all variables + for that time step. +- ``t``: all time stamps. +- ``x``: all state variables (one column per variable). +- ``y``: all algebraic variables (one column per variable). +- ``z``: all discontinuous flags (if enabled, one column per flag). + +If you want the output in pandas DataFrame, call + +.. code:: python + + ss.dae.ts.unpack(df=True) + +Dataframes are stored in the following fields of ``ss.dae.ts``: + +- ``df``: dataframe for states and algebraic variables +- ``df_z``: dataframe for discontinuous flags (if enabled) + +For both dataframes, time is the index column, and each column correspond to +one variable. + +Pretty Print of Equations +---------------------------------------- +Each ANDES models offers pretty print of :math:`\LaTeX`-formatted equations in the jupyter notebook environment. + +To use this feature, symbolic equations need to be generated in the current session using + +.. code:: python + + import andes + ss = andes.System() + ss.prepare() + +Or, more concisely, one can do + +.. code:: python + + import andes + ss = andes.prepare() + +This process may take a few minutes to complete. +To save time, you can selectively generate it only for interested models. +For example, to generate for the classical generator model ``GENCLS``, do + +.. code:: python + + import andes + ss = andes.System() + ss.GENROU.prepare() + +Once done, equations can be viewed by accessing ``ss..syms.``, +where ```` is the model name, and ```` is the +equation or Jacobian name. + +.. Note :: + + Pretty print only works for the particular ``System`` instance whose ``prepare()`` method is called. + In the above example, pretty print only works for ``ss`` after calling ``prepare()``. + +Supported equation names include the following: + +- ``xy``: variables in the order of `State`, `ExtState`, `Algeb` and `ExtAlgeb` +- ``f``: the **right-hand side of** differential equations :math:`T \dot{\mathbf{x}} = \mathbf{f}` +- ``g``: implicit algebraic equations :math:`0 = \mathbf{g}` +- ``df``: derivatives of ``f`` over all variables ``xy`` +- ``dg``: derivatives of ``g`` over all variables ``xy`` +- ``s``: the value equations for `ConstService` + +For example, to print the algebraic equations of model ``GENCLS``, one can use ``ss.GENCLS.syms.g``. + +Finding Help +------------ + +General help +............ + +To find help on a Python class, method, or function, use the built-in ``help()`` function. +For example, to check how the ``get`` method of ``GENROU`` should be called, do + +.. code:: python + + help(ss.GENROU.get) + +In Jupyter notebook, this can be simplified into ``?ss.GENROU.get`` or ``ss.GENROU.get?``. + +Model docs +.......... + +Model docs can be shown by printing the return of ``doc()``. +For example, to check the docs of ``GENCLS``, do + +.. code:: python + + print(ss.GENCLS.doc()) + +It is the same as calling ``andes doc GENCLS`` from the command line. + +Notebook Examples +================= +Check out more examples in Jupyter Notebook in the `examples` folder of the repository at +`here `_. +You can run the examples in a live Jupyter Notebook online using +`Binder `_. + +.. _formats: + +I/O Formats +=========== + +Input Formats +------------- + +ANDES currently supports the following input formats: + +- ANDES Excel (.xlsx) +- PSS/E RAW (.raw) and DYR (.dyr) +- MATPOWER (.m) + + +ANDES xlsx Format +----------------- + +The ANDES xlsx format is a newly introduced format since v0.8.0. +This format uses Microsoft Excel for conveniently viewing and editing model parameters. +You can use `LibreOffice `_ or `WPS Office `_ alternatively to +Microsoft Excel. + +xlsx Format Definition +...................... + +The ANDES xlsx format contains multiple workbooks (tabs at the bottom). +Each workbook contains the parameters of all instances of the model, whose name is the workbook name. +The first row in a worksheet is used for the names of parameters available to the model. +Starting from the second row, each row corresponds to an instance with the parameters in the corresponding columns. +An example of the ``Bus`` workbook is shown in the following. + +.. image:: images/tutorial/xlsx-bus.png + :width: 600 + :alt: Example workbook for Bus + +A few columns are used across all models, including ``uid``, ``idx``, ``name`` and ``u``. + +- ``uid`` is an internally generated unique instance index. This column can be left empty if the xlsx file is + being manually created. Exporting the xlsx file with ``--convert`` will automatically assign the ``uid``. +- ``idx`` is the unique instance index for referencing. An unique ``idx`` should be provided explicitly for each + instance. Accepted types for ``idx`` include numbers and strings without spaces. +- ``name`` is the instance name. +- ``u`` is the connectivity status of the instance. Accepted values are 0 and 1. Unexpected behaviors may occur + if other numerical values are assigned. + +As mentioned above, ``idx`` is the unique index for an instance to be referenced. +For example, a PQ instance can reference a Bus instance so that the PQ is connected to the Bus. +This is done through providing the ``idx`` of the desired bus as the ``bus`` parameter of the PQ. + +.. image:: images/tutorial/xlsx-pq.png + :width: 600 + :alt: Example workbook for PQ + +In the example PQ workbook shown above, there are two PQ instances on buses with ``idx`` being 7 and 8, +respectively. + +Convert to xlsx +............... +Please refer to the the ``--convert`` command for converting a recognized file to xlsx. +See `format converter`_ for more detail. + +Data Consistency +................ + +Input data needs to have consistent types for ``idx``. +Both string and numerical types are allowed +for ``idx``, but the original type and the referencing type must be the same. +Suppose we have a bus and a connected PQ. +The Bus device may use ``1`` or ``'1'`` as its ``idx``, as long as the +PQ device uses the same value for its ``bus`` parameter. + +The ANDES xlsx reader will try to convert data into numerical types when possible. +This is especially relevant when the input ``idx`` is string literal of numbers, +the exported file will have them converted to numbers. +The conversion does not affect the consistency of data. + +Parameter Check +............... +The following parameter checks are applied after converting input values to array: + +- Any ``NaN`` values will raise a ``ValueError`` +- Any ``inf`` will be replaced with :math:`10^{8}`, and ``-inf`` will be replaced with :math:`-10^{8}`. + + +Cheatsheet +=========== +A cheatsheet is available for quick lookup of supported commands. + +View the PDF version at + +https://www.cheatography.com//cuihantao/cheat-sheets/andes-for-power-system-simulation/pdf/ + +Make Documentation +================== + +The documentation you are viewing can be made locally in a variety of formats. +To make HTML documentation, change directory to ``docs``, and do + +.. code:: bash + + make html + +After a minute, HTML documentation will be saved to ``docs/build/html`` with the index page being ``index.html``. + +A list of supported formats is as follows. Note that some format require additional compiler or library :: + + html to make standalone HTML files + dirhtml to make HTML files named index.html in directories + singlehtml to make a single large HTML file + pickle to make pickle files + json to make JSON files + htmlhelp to make HTML files and an HTML help project + qthelp to make HTML files and a qthelp project + devhelp to make HTML files and a Devhelp project + epub to make an epub + latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + latexpdf to make LaTeX and PDF files (default pdflatex) + latexpdfja to make LaTeX files and run them through platex/dvipdfmx + text to make text files + man to make manual pages + texinfo to make Texinfo files + info to make Texinfo files and run them through makeinfo + gettext to make PO message catalogs + changes to make an overview of all changed/added/deprecated items + xml to make Docutils-native XML files + pseudoxml to make pseudoxml-XML files for display purposes + linkcheck to check all external links for integrity + doctest to run all doctests embedded in the documentation (if enabled) + coverage to run coverage check of the documentation (if enabled)