diff --git a/.github/workflows/doc-preview-cleanup.yml b/.github/workflows/doc-preview-cleanup.yml new file mode 100644 index 000000000..7fb591415 --- /dev/null +++ b/.github/workflows/doc-preview-cleanup.yml @@ -0,0 +1,35 @@ +name: Doc Preview Cleanup + +on: + pull_request: + types: [closed] + +# Ensure that only one "Doc Preview Cleanup" workflow is force pushing at a time +concurrency: + group: doc-preview-cleanup + cancel-in-progress: false + +jobs: + doc-preview-cleanup: + runs-on: ubuntu-latest + if: github.event.pull_request.head.repo.fork == false + # This workflow pushes to gh-pages; permissions are per-job and independent of docs.yml + permissions: + contents: write + steps: + - name: Checkout gh-pages branch + uses: actions/checkout@v4 + with: + ref: gh-pages + - name: Delete preview and history + push changes + run: | + if [ -d "${preview_dir}" ]; then + git config user.name "Documenter.jl" + git config user.email "documenter@juliadocs.github.io" + git rm -rf "${preview_dir}" + git commit -m "delete preview" + git branch gh-pages-new "$(echo "delete history" | git commit-tree "HEAD^{tree}")" + git push --force origin gh-pages-new:gh-pages + fi + env: + preview_dir: previews/PR${{ github.event.number }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f68a56b7d..cf1475cf3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -18,6 +18,16 @@ jobs: version: 1 - name: Install dependencies run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + + - name: Set DOCUMENTER_CURRENT_VERSION for tutorial download links + run: | + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + echo "DOCUMENTER_CURRENT_VERSION=previews/PR${{ github.event.pull_request.number }}" >> "$GITHUB_ENV" + elif [[ "${{ github.ref }}" == refs/tags/* ]]; then + echo "DOCUMENTER_CURRENT_VERSION=${GITHUB_REF_NAME}" >> "$GITHUB_ENV" + elif [[ "${{ github.ref }}" == "refs/heads/main" ]] || [[ "${{ github.ref }}" =~ ^refs/heads/release- ]]; then + echo "DOCUMENTER_CURRENT_VERSION=dev" >> "$GITHUB_ENV" + fi - name: Build and deploy env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..2cdcf3837 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: + - repo: local + hooks: + - id: julia-formatter + name: Run Julia formatter + entry: julia scripts/formatter/formatter_code.jl + language: system + types: [file] + pass_filenames: false diff --git a/docs/Project.toml b/docs/Project.toml index 85dae0c28..7d9b05862 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,6 +2,7 @@ DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DocumenterInterLinks = "d12716ef-a0f6-4df4-a9f1-a5a34e75c656" DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" diff --git a/docs/make.jl b/docs/make.jl index 291cda1f7..51d8dc457 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,14 +1,22 @@ using Documenter, PowerSystems, DocStringExtensions, PowerSimulationsDynamics - -const _DOCS_BASE_URL = "https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable" +using DocumenterInterLinks include(joinpath(@__DIR__, "make_tutorials.jl")) make_tutorials() +links = InterLinks( + "PowerSystems" => "https://sienna-platform.github.io/PowerSystems.jl/stable/", + "PowerSystemCaseBuilder" => "https://sienna-platform.github.io/PowerSystemCaseBuilder.jl/stable/", +) + makedocs(; modules = [PowerSimulationsDynamics], - format = Documenter.HTML(; mathengine = Documenter.MathJax()), + format = Documenter.HTML(; + prettyurls = haskey(ENV, "GITHUB_ACTIONS"), + mathengine = Documenter.MathJax(), + ), sitename = "PowerSimulationsDynamics.jl", + plugins = [links], pages = Any[ "Welcome Page" => "index.md", "Quick Start Guide" => "tutorials/generated_quick_start_guide.md", diff --git a/docs/make_tutorials.jl b/docs/make_tutorials.jl index 14b01e4d6..0c7c19951 100644 --- a/docs/make_tutorials.jl +++ b/docs/make_tutorials.jl @@ -3,40 +3,50 @@ using Literate using DataFrames using PrettyTables -# Override show for DataFrames to limit output size during doc builds -# This ensures large DataFrames are truncated when displayed as expression results in @example blocks -# Explicit show() calls in tutorials with their own arguments are NOT affected (they use their own kwargs) -# We override both text/plain and text/html since Documenter may use either -# -# Strategy: Call PrettyTables.pretty_table directly with explicit row/column limits. -# This bypasses DataFrames' default display logic and gives us full control. - -function Base.show(io::IO, mime::MIME"text/plain", df::DataFrame) - # Call PrettyTables directly with row/column limits - # This ensures only 10 rows are shown regardless of DataFrame size +# Limit DataFrame rendering during docs generation to avoid huge literal outputs. +# Notes: +# - Environment-variable approaches tested (`DATAFRAMES_ROWS`, `DATAFRAMES_COLUMNS`, +# `LINES`, `COLUMNS`) did not constrain DataFrames output in this pipeline. +# - We keep a docs-local Base.show override as a fallback and accept `kwargs...` +# so explicit show(...; kwargs) calls do not error on unsupported keywords. +function _env_int(name::String, default::Int) + parsed = tryparse(Int, get(ENV, name, string(default))) + return something(parsed, default) +end + +const _DF_MAX_ROWS = _env_int("SIENNA_DOCS_DF_MAX_ROWS", 10) +const _DF_MAX_COLS = _env_int("SIENNA_DOCS_DF_MAX_COLS", 80) + +function Base.show(io::IO, mime::MIME"text/plain", df::DataFrame; kwargs...) + # Keep docs output bounded while allowing explicit caller kwargs. PrettyTables.pretty_table(io, df; backend = :text, - maximum_number_of_rows = 10, - maximum_number_of_columns = 80, - #display_size = (10, 80), # Show only 10 rows and 80 columns + maximum_number_of_rows = _DF_MAX_ROWS, + maximum_number_of_columns = _DF_MAX_COLS, show_omitted_cell_summary = true, compact_printing = false, - limit_printing = true) + limit_printing = true, + kwargs...) end -function Base.show(io::IO, mime::MIME"text/html", df::DataFrame) - # For HTML output (which Documenter prefers for large outputs) - # Use PrettyTables HTML backend with explicit row/column limits +function Base.show(io::IO, mime::MIME"text/html", df::DataFrame; kwargs...) PrettyTables.pretty_table(io, df; backend = :html, - maximum_number_of_rows = 10, - maximum_number_of_columns = 80, + maximum_number_of_rows = _DF_MAX_ROWS, + maximum_number_of_columns = _DF_MAX_COLS, show_omitted_cell_summary = true, compact_printing = false, - limit_printing = true) + limit_printing = true, + kwargs...) end -# Function to clean up old generated files +# Remove previously generated tutorial artifacts so a docs build only reflects +# current source tutorials. +# +# Input: +# - dir: tutorial output directory that can contain generated_*.md/ipynb. +# Output: +# - Deletes matching files in-place and logs each deletion. function clean_old_generated_files(dir::String) if !isdir(dir) @warn "Directory does not exist: $dir" @@ -58,12 +68,77 @@ end # Literate post-processing functions for tutorial generation ######################################################### -# postprocess function to insert md +# Compute docs base URL from Documenter deploy context. +# +# Behavior: +# - previews/PR123 -> .../previews/PR123 +# - dev (or custom DOCUMENTER_DEVURL) -> .../dev +# - tagged versions like v0.9 -> .../v0.9 +# - fallback -> .../stable +# +# This keeps generated download/view-online links correct across preview, dev, +# tagged, and stable deployments. +function _compute_docs_base_url() + base = "https://sienna-platform.github.io/PowerSimulationsDynamics.jl" + + current_version = get(ENV, "DOCUMENTER_CURRENT_VERSION", "") + + # Preview builds (e.g. "previews/PR123") + if startswith(current_version, "previews/PR") + return "$base/$current_version" + end + + # Dev builds + if current_version == "dev" + dev_suffix = get(ENV, "DOCUMENTER_DEVURL", "dev") + return "$base/$dev_suffix" + end + + # Tagged/versioned builds (e.g. "v0.9", "v1.2.3") + if !isempty(current_version) && current_version != "stable" + return "$base/$current_version" + end + + # Default to stable + return "$base/stable" +end + +const _DOCS_BASE_URL = _compute_docs_base_url() + +""" +Choose how tutorial download links are written in generated markdown. + +- **Absolute** (under `_DOCS_BASE_URL/tutorials/`): CI / Documenter context (`GITHUB_ACTIONS` or + non-empty `DOCUMENTER_CURRENT_VERSION`) so previews, `dev`, and versioned URLs match + `_compute_docs_base_url()`. +- **Relative** (bare filenames): local/offline builds; files sit next to `generated_*.md` + under `docs/src/tutorials/`. + +Override: `SIENNA_DOCS_DOWNLOAD_LINKS`=`absolute` or `relative`. +""" +function _downloads_use_absolute_urls() + o = get(ENV, "SIENNA_DOCS_DOWNLOAD_LINKS", "") + o == "absolute" && return true + o == "relative" && return false + haskey(ENV, "GITHUB_ACTIONS") && return true + !isempty(get(ENV, "DOCUMENTER_CURRENT_VERSION", "")) && return true + return false +end + +# Replace APPEND_MARKDOWN("path/to/file.md") placeholders with file contents. +# +# Sample input: +# "Before\nAPPEND_MARKDOWN(\"docs/src/tutorials/_snippet.md\")\nAfter" +# Sample output: +# "Before\n\nAfter" +# +# Notes: +# - Uses a non-greedy-safe capture (`[^\"]*`) so multiple placeholders can be +# replaced independently. function insert_md(content) - m = match(r"APPEND_MARKDOWN\(\"(.*)\"\)", content) - if !isnothing(m) - md_content = read(m.captures[1], String) - content = replace(content, r"APPEND_MARKDOWN\(\"(.*)\"\)" => md_content) + pattern = r"APPEND_MARKDOWN\(\"([^\"]*)\"\)" + if occursin(pattern, content) + content = replace(content, pattern => m -> read(m.captures[1], String)) end return content end @@ -130,12 +205,26 @@ function preprocess_admonitions_for_notebook(str::AbstractString) return join(out, '\n') end -# Function to add download links to generated markdown +# Inject a short "download tutorial files" sentence after the first markdown +# heading in generated tutorial pages. +# +# Sample input: +# "# Title\nBody..." +# Sample output (conceptual): +# "# Title\n\n*To follow along... [Julia script](.../tutorial.jl)...*\n\nBody..." +# +# Download links: +# - **Deployed / CI**: absolute URLs under `_DOCS_BASE_URL` when `_downloads_use_absolute_urls()` is true. +# - **Local**: bare filenames (siblings of `generated_*.md` in `docs/src/tutorials/`). function add_download_links(content, jl_file, ipynb_file) - # Add download links at the top of the file after the first heading + script_link, notebook_link = if _downloads_use_absolute_urls() + ("$_DOCS_BASE_URL/tutorials/$(jl_file)", "$_DOCS_BASE_URL/tutorials/$(ipynb_file)") + else + (jl_file, ipynb_file) + end download_section = """ -*To follow along, you can download this tutorial as a [Julia script (.jl)]($(jl_file)) or [Jupyter notebook (.ipynb)]($(ipynb_file)).* +*To follow along, you can download this tutorial as a [Julia script (.jl)]($(script_link)) or [Jupyter notebook (.ipynb)]($(notebook_link)).* """ # Insert after the first heading (which should be the title) @@ -148,7 +237,12 @@ function add_download_links(content, jl_file, ipynb_file) return content end -# Function to add Pkg.status() to notebook within the first markdown cell +# Insert a setup preface and captured `Pkg.status()` into the first markdown +# cell of a generated notebook, immediately after the first heading. +# +# Sample effect: +# - First markdown cell gains a "Set up" blockquote and an embedded code block +# containing package versions from the docs build environment. function add_pkg_status_to_notebook(nb::Dict) cells = get(nb, "cells", []) if isempty(cells) @@ -246,8 +340,11 @@ end # Add italicized "view online" comment after each image from ```@raw html ... ``` (or # the raw HTML / markdown form Literate writes). Used as a postprocess in Literate.notebook. -# Expects _DOCS_BASE_URL to be defined by the includer (e.g. in make.jl). # Literate strips the backtick wrapper and outputs raw HTML; we match that multi-line block. +# Sample effect: +# - If a markdown cell contains one or more image fragments, append exactly one +# "view online" fallback note at the end of that cell. +# - If the note already exists in the cell, no change is applied. function add_image_links(nb::Dict, outputfile_base::AbstractString) tutorial_url = "$_DOCS_BASE_URL/tutorials/$(outputfile_base)/" msg = "_If image is not available when viewing in a Jupyter notebook, view the tutorial online [here]($tutorial_url)._" @@ -261,17 +358,36 @@ function add_image_links(nb::Dict, outputfile_base::AbstractString) contains(text, "If image is not available when viewing in a Jupyter notebook") && continue suffix = "\n\n" * msg * "\n" - append_after = m -> string(m) * suffix - # Use a single non-overlapping regex to match image-containing fragments: - # - ......

(Literate raw HTML paragraphs) - # - ```@raw html ... ``` blocks - # - Markdown images ![...](...) - # - standalone tags (only if not already matched by

wrapper) - text = replace( - text, - r"(?:]*>[\s\S]*?|```@raw html[\s\S]*?```|!\[[^\]]*\]\([^\)]*\)|]*?/?>)" => - append_after, + # If the cell has any of the image shapes below, we append one "view online" note. + # We build one alternation pattern from sub-patterns (each line is one case). + # + # HTML paragraph wrapping an (Literate often emits

). + # ]*> — opening

and attributes + # [\s\S]*? — any chars, non-greedy, up to the first — from + p_with_img_pattern = r"]*>[\s\S]*?" + # Documenter @raw html chunk that Literate inlines in the notebook (backticks removed in output). + # ```@raw html — start marker + # [\s\S]*? — block body, non-greedy + # ``` — end fence + raw_html_block_pattern = r"```@raw html[\s\S]*?```" + # Standard markdown image: ![alt text](url) + # !\[…\] — alt in brackets; \(…\) — path in parens + markdown_image_pattern = r"!\[[^\]]*\]\([^\)]*\)" + # A bare not already covered by the

case above. + # ]*? — attributes; /?> — self-closing or > + standalone_img_pattern = r"]*?/?>" + # Union of the four cases: (?: A | B | C | D ) + image_fragment_pattern = Regex( + "(?:" * + p_with_img_pattern.pattern * "|" * + raw_html_block_pattern.pattern * "|" * + markdown_image_pattern.pattern * "|" * + standalone_img_pattern.pattern * ")", ) + if occursin(image_fragment_pattern, text) + text *= suffix + end # Convert back to notebook source array (lines, last without trailing \n if non-empty) lines = split(text, "\n"; keepempty = true) new_source = String[] @@ -293,31 +409,35 @@ end # Process tutorials with Literate ######################################################### -# Markdown files are postprocessed to add download links for the Julia script and Jupyter notebook -# Jupyter notebooks are postprocessed to add image links and pkg.status() +# Generate tutorial markdown + notebook artifacts from literate .jl sources. +# +# Pipeline: +# 1) discover tutorial .jl files (excluding helper files starting with "_") +# 2) generate Documenter-flavored markdown with injected download links +# 3) generate notebook with admonition conversion, setup preface, and image note function make_tutorials() + tutorials_dir = abspath(joinpath(@__DIR__, "src", "tutorials")) # Exclude helper scripts that start with "_" - if isdir("docs/src/tutorials") + if isdir(tutorials_dir) tutorial_files = filter( - x -> occursin(".jl", x) && !startswith(x, "_"), - readdir("docs/src/tutorials"), + x -> endswith(x, ".jl") && !startswith(x, "_"), + readdir(tutorials_dir), ) if !isempty(tutorial_files) # Clean up old generated tutorial files - tutorial_outputdir = joinpath(pwd(), "docs", "src", "tutorials") + tutorial_outputdir = tutorials_dir clean_old_generated_files(tutorial_outputdir) for file in tutorial_files @show file - infile_path = joinpath(pwd(), "docs", "src", "tutorials", file) + infile_path = joinpath(tutorials_dir, file) execute = if occursin("EXECUTE = TRUE", uppercase(readline(infile_path))) true else false end - execute && include(infile_path) outputfile = string("generated_", replace("$file", ".jl" => "")) diff --git a/docs/src/code_base_developer_guide/developer.md b/docs/src/code_base_developer_guide/developer.md index e6a2b9683..2efb0a147 100644 --- a/docs/src/code_base_developer_guide/developer.md +++ b/docs/src/code_base_developer_guide/developer.md @@ -4,8 +4,8 @@ In order to contribute to `PowerSimulationsDynamics.jl` repository please read t sections of [`InfrastructureSystems.jl`](https://github.com/Sienna-Platform/InfrastructureSystems.jl) documentation in detail: -1. [Style Guide](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/style/) -2. [Contributing Guidelines](https://github.com/Sienna-Platform/PowerSystems.jl/blob/master/CONTRIBUTING.md) + 1. [Style Guide](https://sienna-platform.github.io/InfrastructureSystems.jl/stable/style/) + 2. [Contributing Guidelines](https://github.com/Sienna-Platform/PowerSystems.jl/blob/master/CONTRIBUTING.md) Pull requests are always welcome to fix bugs or add additional modeling capabilities. diff --git a/docs/src/component_models/avr.md b/docs/src/component_models/avr.md index e602be276..dd6c658ba 100644 --- a/docs/src/component_models/avr.md +++ b/docs/src/component_models/avr.md @@ -2,11 +2,11 @@ AVR are used to determine the voltage in the field winding ``v_f`` (or ``V_f``) in the model. -## Fixed AVR ```[AVRFixed]``` +## Fixed AVR [`PowerSystems.AVRFixed`](@extref) This is a simple model that set the field voltage to be equal to a desired constant value ``v_f = v_{\text{fix}}``. -## Simple AVR ```[AVRSimple]``` +## Simple AVR [`PowerSystems.AVRSimple`](@extref) This depicts the most basic AVR, on which the field voltage is an integrator over the difference of the measured voltage and a reference: @@ -16,7 +16,7 @@ This depicts the most basic AVR, on which the field voltage is an integrator ove \end{align} ``` -## AVR Type I ```[AVRTypeI]``` +## AVR Type I [`PowerSystems.AVRTypeI`](@extref) This AVR is a simplified version of the IEEE DC1 AVR model: @@ -37,7 +37,7 @@ S_e(v_f) = A_e \exp(B_e|v_f|) \end{align*} ``` -## AVR Type II ```[AVRTypeII]``` +## AVR Type II [`PowerSystems.AVRTypeII`](@extref) This model represents a static exciter with higher gains and faster response than the Type I: @@ -59,7 +59,7 @@ S_e(v_f) &= A_e \exp(B_e|v_f|) \end{align*} ``` -## Excitation System AC1A ```[ESAC1A]``` +## Excitation System AC1A [`PowerSystems.ESAC1A`](@extref) The model represents the 5-states IEEE Type AC1A Excitation System Model: @@ -95,7 +95,7 @@ f(I_N) &= \left\{\begin{array}{cl} on which ``X_{ad}I_{fd}`` is the field current coming from the generator and ``V_{h}`` is the terminal voltage, and ``A,B`` are the saturation coefficients computed using the ``E_1, E_2, S_e(E_1), S_e(E_2)`` data. -## Simplified Excitation System ```[SEXS]``` +## Simplified Excitation System [`PowerSystems.SEXS`](@extref) The model for the 2 states excitation system SEXS: @@ -107,6 +107,7 @@ The model for the 2 states excitation system SEXS: ``` with + ```math \begin{align*} V_{in} &= V_{ref} + V_s - V_h \\ @@ -116,8 +117,7 @@ V_{LL} &= V_r + \frac{T_a}{T_b}V_{in} \\ on which ``V_h`` is the terminal voltage and ``V_s`` is the PSS output signal. - -## Excitation System ST1 ```[EXST1]``` +## Excitation System ST1 [`PowerSystems.EXST1`](@extref) The model represents the 4-states IEEE Type ST1 Excitation System Model: @@ -130,7 +130,7 @@ The model represents the 4-states IEEE Type ST1 Excitation System Model: \end{align} ``` -with +with ```math \begin{align*} @@ -143,7 +143,7 @@ V_f &= V_r \\ on which ``V_h`` is the terminal voltage. -## Excitation System EXAC1 ```[EXAC1]``` +## Excitation System EXAC1 [`PowerSystems.EXAC1`](@extref) The model represents the 5-states IEEE Type EXAC1 Excitation System Model: @@ -179,7 +179,7 @@ f(I_N) &= \left\{\begin{array}{cl} on which ``X_{ad}I_{fd}`` is the field current coming from the generator and ``V_{h}`` is the terminal voltage, and ``A,B`` are the saturation coefficients computed using the ``E_1, E_2, S_e(E_1), S_e(E_2)`` data. -## Excitation System ST8C ```[ST8C]``` +## Excitation System ST8C [`PowerSystems.ST8C`](@extref) The model represents the 5-states IEEE Type ST8C Excitation System Model: @@ -228,12 +228,11 @@ on which ``I_{fd}`` is the field current from the generator, ``V_{h}`` is the te ### Notes -- The rectifier function ``f(I_N)`` models the characteristic of a three-phase full-wave rectifier -- Terminal current feedforward (``K_{i2}``) is not currently implemented and must be set to 0.0 -- Voltage compensation is not implemented (``V_e = K_p``) + - The rectifier function ``f(I_N)`` models the characteristic of a three-phase full-wave rectifier + - Terminal current feedforward (``K_{i2}``) is not currently implemented and must be set to 0.0 + - Voltage compensation is not implemented (``V_e = K_p``) - -## Excitation System ST6B ```[ST6B]``` +## Excitation System ST6B [`PowerSystems.ST6B`](@extref) The model represents the 4-states IEEE Type ST6B Excitation System Model: @@ -266,21 +265,20 @@ E_{fd} &= V_r V_m \\ ``` on which ``X_{ad} I_{fd}`` is the field current from the generator, ``V_{h}`` is the terminal voltage, and ``V_s`` is the PSS output signal. Finally, the derivative block implements a high-pass filter: + ```math \text{PD output} = x_d + \frac{K_{da}}{T_{da}} u, \quad T_{da} \dot{x}_d = -\frac{K_{da}}{T_{da}} u - x_d ``` + while the current limiter ensures: + ```math V_{r1} = \max((I_{lr} K_{ci} - X_{ad} I_{fd}) K_{lr}, V_{r_{min}}) ``` ### Notes -- The derivative term uses a high-pass filter implementation -- Current limiting is active when field current exceeds the reference value ``I_{lr}`` -- The exciter output is the minimum of voltage-limited and current-limited values -- During initialization, ``I_{lr}`` is typically adjusted to match operating conditions - - - - + - The derivative term uses a high-pass filter implementation + - Current limiting is active when field current exceeds the reference value ``I_{lr}`` + - The exciter output is the minimum of voltage-limited and current-limited values + - During initialization, ``I_{lr}`` is typically adjusted to match operating conditions diff --git a/docs/src/component_models/converter.md b/docs/src/component_models/converter.md index e636ead9e..454b79ff1 100644 --- a/docs/src/component_models/converter.md +++ b/docs/src/component_models/converter.md @@ -2,7 +2,7 @@ This component can be used to model the dynamics of the switching process. -## Average Model ```[AverageConverter]``` +## Average Model [`PowerSystems.AverageConverter`](@extref) The average model outputs the desired reference signal since: @@ -15,7 +15,7 @@ v_{q}^{\text{cv}} \approx m_{q} v_{\text{dc}} \approx \frac{v_{q}^{\text{ref-sig where ``m_{dq}`` is the modulation signal, and ``v_{dq}^{\text{ref-signal}}`` is the voltage reference signal from the inner loop control. -## Generic Renewable Converter Type A ```[RenewableEnergyConverterTypeA] +## Generic Renewable Converter Type A [`PowerSystems.RenewableEnergyConverterTypeA`](@extref) This block represents the [REGCA](https://www.powerworld.com/WebHelp/Content/TransientModels_HTML/Machine%20Model%20REGC_A.htm) model. The equations (without the limiters) are: @@ -67,4 +67,4 @@ This current source is usually modeled as a Norton equivalent using a parallel i I_{cv} &= I_r + jI_i \\ v_r^\text{cv} + jv_i^\text{cv} &= \frac{I_{cv} + \frac{v^\text{grid}}{Z_f}}{\frac{1}{Z_{sorce}} + \frac{1}{Z_f}} \tag{2i} \end{align*} -``` \ No newline at end of file +``` diff --git a/docs/src/component_models/dc_source.md b/docs/src/component_models/dc_source.md index a62a38072..0329c16d3 100644 --- a/docs/src/component_models/dc_source.md +++ b/docs/src/component_models/dc_source.md @@ -2,6 +2,6 @@ This component can be used to model the dynamics of the DC side of the converter. -## Fixed DC Source ```[FixedDCSource]``` +## Fixed DC Source [`PowerSystems.FixedDCSource`](@extref) This is a model that set the DC voltage to a fixed value ``v_{\text{dc}} = v_{\text{dc}}^{\text{fix}}``. diff --git a/docs/src/component_models/filters.md b/docs/src/component_models/filters.md index c7bf560dc..24ad90e71 100644 --- a/docs/src/component_models/filters.md +++ b/docs/src/component_models/filters.md @@ -1,6 +1,6 @@ # Filters -## LCL Filter ```[LCLFilter]``` +## LCL Filter [`PowerSystems.LCLFilter`](@extref) A standard LCL filter is proposed to connect the output of the converter to the grid. In this case, ``v_r`` and ``v_i`` are voltages in the capacitor, while ``v_r^{\text{grid}}`` @@ -29,7 +29,7 @@ v_r^\text{cv} + jv_i^\text{cv} = (v_d^\text{cv} + jv_q^\text{cv})e^{j\delta\thet that comes from the converter model. -## RL Filter ```[RLFilter]``` +## RL Filter [`PowerSystems.RLFilter`](@extref) The algebraic RL filter is used to connect the output of the converter through a RL series filter using algebraic phasor equations. The equations for the output current are: @@ -39,4 +39,4 @@ The algebraic RL filter is used to connect the output of the converter through a \end{align} ``` -on which ``v_r^\text{cv} + jv_i^\text{cv}`` comes from the converter model. \ No newline at end of file +on which ``v_r^\text{cv} + jv_i^\text{cv}`` comes from the converter model. diff --git a/docs/src/component_models/freq_esti.md b/docs/src/component_models/freq_esti.md index 10ad92450..d28f09dcd 100644 --- a/docs/src/component_models/freq_esti.md +++ b/docs/src/component_models/freq_esti.md @@ -2,13 +2,13 @@ This component is used to estimate the frequency of the grid based on the voltage at the bus. -## Fixed Frequency ```[FixedFrequency]``` +## Fixed Frequency [`PowerSystems.FixedFrequency`](@extref) This is a simple model that set the measured frequency to a desired constant value (i.e. does not measure the frequency) -``\omega_{pll} = \omega_{\text{fix}}`` (usually ``\omega_{\text{fix}} = 1.0`` p.u.). Used by default when grid-forming -inverters do not use frequency estimators. +``\omega_{pll} = \omega_{\text{fix}}`` (usually ``\omega_{\text{fix}} = 1.0`` p.u.). Used by default when grid-forming +inverters do not use frequency estimators. -## Phase-Locked Loop (PLL) for VSM ```[KauraPLL]``` +## Phase-Locked Loop (PLL) for VSM [`PowerSystems.KauraPLL`](@extref) The following equations present a PLL used to estimate the frequency and PLL angle of the grid. There are two reference frames considered in this inverter. Those are the VSM @@ -41,7 +41,7 @@ on which ``v_r + jv_i`` is the voltage in the grid reference frame on which the measuring (i.e. point of common coupling), that could be in the capacitor of an LCL filter or the last branch of such filter. -## Reduced Order Phase-Locked Loop (PLL) ```[ReducedOrderPLL]``` +## Reduced Order Phase-Locked Loop (PLL) [`PowerSystems.ReducedOrderPLL`](@extref) The following equations presents a simplified PLL used to estimate the frequency and PLL angle of the grid. The model attempts to steer the voltage in the q-axis to zero (i.e. lock the q-axis to zero) using a PI controller. With that the equations are given by: @@ -54,6 +54,7 @@ The following equations presents a simplified PLL used to estimate the frequency ``` with + ```math \begin{align} \delta\omega_{\text{pll}} &= 1.0 - \omega_{\text{sys}} + k_{p,\text{pll}} v_{q,\text{pll}} + k_{i,\text{pll}} \varepsilon_{\text{pll}} \tag{2d} \\ diff --git a/docs/src/component_models/inner_control.md b/docs/src/component_models/inner_control.md index 4054a4dc7..6b902daeb 100644 --- a/docs/src/component_models/inner_control.md +++ b/docs/src/component_models/inner_control.md @@ -4,7 +4,7 @@ This component defines voltage and current controllers to generate the reference for the converter. Although in many controls the current and voltage control are separate blocks we propose a more general control approach that considers them as a joint control logic. -## Integrated Virtual Impedance, Voltage and Current Controller ```[VoltageModeControl]``` +## Integrated Virtual Impedance, Voltage and Current Controller [`PowerSystems.VoltageModeControl`](@extref) The following model receives both the outer loop control frequency and reference voltage signal to generate the reference signal for the converters. The virtual impedance plays a @@ -55,8 +55,7 @@ i_{d,\text{cv}} + ji_{q,\text{cv}} = (i_{r,\text{cv}} + ji_{i,\text{cv}})e^{-j\d \end{align*} ``` - -## Current Mode Controller ```[CurrentModeControl]``` +## Current Mode Controller [`PowerSystems.CurrentModeControl`](@extref) The following model receives the current reference (in ``dq`` axis) from an outer loop controller that outputs current references such as the PI outer controller used for grid following inverters. @@ -88,7 +87,7 @@ i_{d,\text{cv}} + ji_{q,\text{cv}} = (i_{r,\text{cv}} + ji_{i,\text{cv}})e^{-j\t In here ``\theta_{olc}`` is the outer-loop angle. In the case of grid-following models, this angle is equal to the angle provided from the PLL. -## Generic Renewable Inner Controller Type B ```[RECurrentControlB]``` +## Generic Renewable Inner Controller Type B [`PowerSystems.RECurrentControlB`](@extref) This models the inner control part of the [REECB](https://www.powerworld.com/WebHelp/Content/TransientModels_HTML/Exciter%20REEC_B.htm) model. The equations (without limiters) when `Q_Flag = 1` are: @@ -127,4 +126,4 @@ on which ``I_\text{oc,qcmd}`` comes from the Outer Controller and the output cur I_\text{qcmd} &= I_{icv} + I_\text{qinj} \tag{3j} \\ I_{\text{qinj}} &= K_{qv} (V_\text{ref0} - V_\text{t,flt}) \tag{3k} \end{align} -``` \ No newline at end of file +``` diff --git a/docs/src/component_models/loads.md b/docs/src/component_models/loads.md index 9c9ec3842..6305dbad5 100644 --- a/docs/src/component_models/loads.md +++ b/docs/src/component_models/loads.md @@ -1,4 +1,4 @@ -Here we discuss the models used to describe load modeling in `PowerSimulationsDynamics.jl`. +Here we discuss the models used to describe load modeling in `PowerSimulationsDynamics.jl`. In a similar fashion of other devices, loads will withdraw power (i.e. current) from the current-injection balances at the nodal level. Based on the specified parameters and model chosen, the equations for computing such withdrawal will change. ## Static Loads (or Algebraic Loads) @@ -55,6 +55,7 @@ I_\text{im}^p = \frac{V_i \cdot P_\text{power} - V_r \cdot Q_\text{power}}{V^2} ``` Then the total current withdrawed from the ZIP load model is simply + ```math \begin{align} I_\text{zip}^\text{re} &= I_\text{re}^z + I_\text{re}^i + I_\text{re}^p \tag{1k} \\ @@ -72,6 +73,7 @@ Q_\text{exp} = Q_0 \cdot \left(\frac{V}{V_0}\right)^\beta \tag{1n} ``` The current taken for the load is computed as: + ```math \begin{align} I_\text{exp} &= \frac{(P_\text{exp} + j Q_\text{exp})^*}{(V_r + j V_i)^*} \tag{1o} \\ @@ -80,6 +82,7 @@ I_\text{exp} &= \frac{P_\text{exp} - j Q_\text{exp}}{V_r - j V_i} \tag{1p} ``` that results: + ```math \begin{align} I_\text{exp}^\text{re} &= V_r \cdot P_0 \cdot \frac{V^{\alpha - 2}}{V_0^\alpha} + V_i \cdot Q_0 \cdot \frac{V^{\beta - 2}}{V_0^\beta} \tag{1q}\\ @@ -89,7 +92,7 @@ I_\text{exp}^\text{im} &= V_i \cdot P_0 \cdot \frac{V^{\alpha - 2}}{V_0^\alpha} ## Dynamic loads -### 5th-order Single Cage Induction Machine ```[SingleCageInductionMachine]``` +### 5th-order Single Cage Induction Machine [`PowerSystems.SingleCageInductionMachine`](@extref) The following model is used to model a 5th-order induction machine with a quadratic relationship speed-torque. Refer to "Analysis of Electric Machinery and Drive Systems" by Paul Krause, Oleg Wasynczuk and Scott Sudhoff for the equations derivation @@ -121,6 +124,7 @@ i_{ds} &= \frac{1}{X_{ls}} (\psi_{ds} - \psi_{md}) \\ ``` Finally, the withdrawed current from the bus is: + ```math \begin{align*} I_r = \left(\frac{S_\text{motor}}{S_\text{base}}\right) (i_{ds} - v_{qs} B_{sh}) \\ @@ -128,7 +132,7 @@ I_i = \left(\frac{S_\text{motor}}{S_\text{base}}\right) (i_{qs} + v_{ds} B_{sh}) \end{align*} ``` -### 3rd-order Single Cage Induction Machine ```[SimplifiedSingleCageInductionMachine]``` +### 3rd-order Single Cage Induction Machine [`PowerSystems.SimplifiedSingleCageInductionMachine`](@extref) The following models approximates the stator fluxes dynamics of the 5th-order model by using algebraic equations. @@ -141,6 +145,7 @@ The following models approximates the stator fluxes dynamics of the 5th-order mo ``` where + ```math \begin{align*} v_{qs} &= V_i^\text{bus} \\ @@ -155,6 +160,7 @@ i_{dr} &= \frac{1}{X_{rr}} (\psi_{dr} - X_m i_{ds}) \\ ``` Finally, the withdrawed current from the bus is: + ```math \begin{align*} I_r = \left(\frac{S_\text{motor}}{S_\text{base}}\right) (i_{ds} - v_{qs} B_{sh}) \\ @@ -164,9 +170,10 @@ I_i = \left(\frac{S_\text{motor}}{S_\text{base}}\right) (i_{qs} + v_{ds} B_{sh}) ### Active Constant Power Load Model -The following 12-state model Active Load model that measures the AC side using a Phase-Lock-Loop (PLL) and regulates a DC voltage to supply a resistor $r_L$. This model induces a constant power load-like behavior as it tries to maintain a fixed DC voltage to supply ``P = v_\text{DC}^2 / r_L``. The model is based on [the following reference](https://www.sciencedirect.com/science/article/pii/S0142061516000740). +The following 12-state model Active Load model that measures the AC side using a Phase-Lock-Loop (PLL) and regulates a DC voltage to supply a resistor $r_L$. This model induces a constant power load-like behavior as it tries to maintain a fixed DC voltage to supply ``P = v_\text{DC}^2 / r_L``. The model is based on [the following reference](https://www.sciencedirect.com/science/article/pii/S0142061516000740). The complete model is given by: + ```math \begin{align} \dot{\theta} &= \Omega_b (\omega_\text{pll} - \omega_s) \tag{4a} \\ @@ -181,4 +188,5 @@ The complete model is given by: v_\text{cv}^{q,\star} &= k_\text{pc}( i_\text{cv}^q - i_\text{cv}^{q,\star}) + k_\text{ic} \gamma_q - \omega_\text{pll} l_f i_\text{cv}^d \tag{4j} \end{align} ``` -Equations (4a)--(4c) describes the PLL dynamics to lock the active load to the grid. Equations (4d)-(4e) describes the DC Voltage Controller to steer the DC voltage to ``v_\text{DC}^\star``, while equation (4f) describes the DC voltage dynamics at the capacitor assuming an ideal converter. Finally, equations (4g)--(4j) describes the dynamics of the AC Current Controller. Additionally six states are defined for the LCL filter in a similar fashion of GFM inverters. \ No newline at end of file + +Equations (4a)--(4c) describes the PLL dynamics to lock the active load to the grid. Equations (4d)-(4e) describes the DC Voltage Controller to steer the DC voltage to ``v_\text{DC}^\star``, while equation (4f) describes the DC voltage dynamics at the capacitor assuming an ideal converter. Finally, equations (4g)--(4j) describes the dynamics of the AC Current Controller. Additionally six states are defined for the LCL filter in a similar fashion of GFM inverters. diff --git a/docs/src/component_models/machines.md b/docs/src/component_models/machines.md index 905af2dbb..30eead90a 100644 --- a/docs/src/component_models/machines.md +++ b/docs/src/component_models/machines.md @@ -2,7 +2,7 @@ The machine component describes the stator-rotor electromagnetic dynamics. -## Classical Model (Zero Order) ```[BaseMachine]``` +## Classical Model (Zero Order) [`PowerSystems.BaseMachine`](@extref) This is the classical order model that does not have differential equations in its machine model (``\delta`` and ``\omega`` are defined in the shaft): @@ -14,7 +14,7 @@ p_e \approx \tau_e &= (v_q + r_a i_q)i_q + (v_d + r_ai_d)i_d \tag{1b} \end{align} ``` -## One d- One q- Model (2nd Order) ```[OneDOneQMachine]``` +## One d- One q- Model (2nd Order) [`PowerSystems.OneDOneQMachine`](@extref) This model includes two transient emf with their respective differential equations: @@ -27,7 +27,7 @@ p_e \approx \tau_e &= (v_q + r_a i_q)i_q + (v_d + r_ai_d)i_d \tag{2d} \end{align} ``` -## Marconato Machine (6th Order) ```[MarconatoMachine]``` +## Marconato Machine (6th Order) [`PowerSystems.MarconatoMachine`](@extref) The Marconato model defines 6 differential equations, two for stator fluxes and 4 for transient and subtransient emfs: @@ -54,7 +54,7 @@ with \end{align*} ``` -## Simplified Marconato Machine (4th Order) ```[SimpleMarconatoMachine]``` +## Simplified Marconato Machine (4th Order) [`PowerSystems.SimpleMarconatoMachine`](@extref) This model neglects the derivative of stator fluxes (``\dot{\psi}_d`` and ``\dot{\psi}_q``) and assume that the rotor speed stays close to 1 pu (``\omega\psi_{d}=\psi_{d}`` and ``\omega\psi_{q}=\psi_{q}``) that allows to remove the stator fluxes variables from the Marconato model. @@ -78,7 +78,7 @@ with \end{align*} ``` -## Anderson-Fouad Machine (6th Order) ```[AndersonFouadMachine]``` +## Anderson-Fouad Machine (6th Order) [`PowerSystems.AndersonFouadMachine`](@extref) The Anderson-Fouad model also defines 6 differential equations, two for stator fluxes and 4 for transient and subtransient emfs and is derived from the Marconato model by defining ``\gamma_d \approx \gamma_q \approx T_{AA} \approx 0``: @@ -96,7 +96,7 @@ i_q &= \frac{1}{x_q''} (-e_d'' - \psi_q) \tag{5h} \\ \end{align} ``` -## Simplified Anderson-Fouad Machine (4th Order) ```[SimpleAFMachine]``` +## Simplified Anderson-Fouad Machine (4th Order) [`PowerSystems.SimpleAFMachine`](@extref) Similar to the Simplified Marconato Model, this model neglects the derivative of stator fluxes (``\dot{\psi}_d`` and ``\dot{\psi}_q``) and assume that the rotor speed stays close to 1 pu (``\omega \psi_d = \psi_d`` and ``\omega \psi_q = \psi_q``) that allows to remove the stator fluxes variables from the model: @@ -111,7 +111,7 @@ p_e \approx \tau_e &= (v_q + r_a i_q)i_q + (v_d + r_ai_d)i_d \tag{6f} \end{align} ``` -## Round Rotor Machine (4th Order) ```[RoundRotorQuadratic, RoundRotorExponential]``` +## Round Rotor Machine (4th Order) [`PowerSystems.RoundRotorQuadratic`](@extref), [`PowerSystems.RoundRotorExponential`](@extref) This model represents the traditional round rotor models GENROU/GENROE models implemented in PSLF/PSSE/PowerWorld. Similar to the Simplified Marconato Model, this model neglects the derivative of stator fluxes (``\dot{\psi}_d`` and ``\dot{\psi}_q``). Round rotor machines must satisfy ``x_d'' = x_q''``. @@ -163,8 +163,7 @@ and for the GENROE model the function used is: The parameters ``A`` and ``B`` for each function are computed using the two points given ``(1.0, \text{Se}(1.0))`` and ``(1.2, \text{Se}(1.2))``. - -## Salient Pole Machine (3rd Order) ```[SalientPoleQuadratic, SalientPoleExponential]``` +## Salient Pole Machine (3rd Order) [`PowerSystems.SalientPoleQuadratic`](@extref), [`PowerSystems.SalientPoleExponential`](@extref) This model represents the traditional round rotor models GENSAL/GENSAE models implemented in PSLF/PSSE/PowerWorld. Similar to the GENROU Model, this model neglects the derivative of stator fluxes (``\dot{\psi}_d`` and ``\dot{\psi}_q``). @@ -210,8 +209,7 @@ and for the GENSAE model the function used is: The parameters ``A`` and ``B`` for each function are computed using the two points given ``(1.0, \text{Se}(1.0))`` and ``(1.2, \text{Se}(1.2))``. - -## SauerPai Machine (6th Order) ```[SauerPaiMachine]``` +## SauerPai Machine (6th Order) [`PowerSystems.SauerPaiMachine`](@extref) The Sauer Pai model defines 6 differential equations as follows: @@ -238,4 +236,4 @@ with \gamma_{d2} &= \frac{1 - \gamma_d1}{x_d' - x_l} \\ \gamma_{q2} &= \frac{1 - \gamma_q1}{x_q' - x_l} \end{align*} -``` \ No newline at end of file +``` diff --git a/docs/src/component_models/outer_control.md b/docs/src/component_models/outer_control.md index 0b9cc2d02..e9274202a 100644 --- a/docs/src/component_models/outer_control.md +++ b/docs/src/component_models/outer_control.md @@ -4,10 +4,10 @@ This component defines controllers for both active and reactive power. The joint on the fact that many novel control techniques can be based on joint control of active and reactive power. -## Virtual Inertia and Q-droop ```[OuterControl]``` +## Virtual Inertia and Q-droop [`PowerSystems.OuterControl`](@extref) The following model represent a virtual synchronous machine model to represent how active -power is going to be deployed. The constructor is ```OuterControl{VirtualInertia, ReactivePowerDroop}```. +power is going to be deployed. The constructor is `OuterControl{VirtualInertia, ReactivePowerDroop}`. It defines a new SRF denoted as ``\theta_{\text{olc}}`` for the active power controller and uses a simple voltage droop for dispatching reactive power: @@ -33,11 +33,10 @@ In this case, the measurement of power are being done in the capacitor of the LC However, depending on the model, this measurements could be different depending on where is the point of common coupling. - -## Active Power Droop (P-droop) and Q-droop ```[OuterControl]``` +## Active Power Droop (P-droop) and Q-droop [`PowerSystems.OuterControl`](@extref) The following model represent a ``P\text{-}f`` droop model to represent how active -power is going to be deployed. The constructor is ```OuterControl{ActivePowerDroop, ReactivePowerDroop}```. +power is going to be deployed. The constructor is `OuterControl{ActivePowerDroop, ReactivePowerDroop}`. It defines a new SRF denoted as ``\theta_{\text{olc}}`` for the active power controller and uses a simple voltage droop for dispatching reactive power. Both active and reactive power are measured via a low-pass filter: @@ -64,12 +63,13 @@ In this case, the measurement of power are being done in the capacitor of the LC However, depending on the model, this measurements could be different depending on where is the point of common coupling. -## Active and Reactive Virtual Oscillator Controllers ```[OuterControl]``` +## Active and Reactive Virtual Oscillator Controllers [`PowerSystems.OuterControl`](@extref) The following model represents a Virtual Oscillator Controller for both active and reactive power -to generate the voltage references that will be used in the Voltage Controller. The contructor is ```OuterControl{ActiveVirtualOscillator, ReactiveVirtualOscillator}``` +to generate the voltage references that will be used in the Voltage Controller. The contructor is `OuterControl{ActiveVirtualOscillator, ReactiveVirtualOscillator}` It defines a new SRF denoted as ``\theta_{\text{olc}}`` and a voltage reference ``E_{\text{olc}}``. The equations are: + ```math \begin{align} \dot{\theta}_{\text{olc}} &= \Omega_b (\omega_{\text{olc}} - \omega_{\text{sys}}) \tag{3a} \\ @@ -78,6 +78,7 @@ The equations are: ``` with + ```math \begin{align} \gamma &= \psi - \frac{\pi}{2} \tag{3c} \\ @@ -87,12 +88,11 @@ with \end{align} ``` - -## Active and Reactive Power PI Controllers (Grid Following) ```[OuterControl]``` +## Active and Reactive Power PI Controllers (Grid Following) [`PowerSystems.OuterControl`](@extref) The following model represents a PI controller for both active and reactive power to generate the current references that will be used in the Current Controller of the inner control -```CurrentModeControl```. The constructor is ```OuterControl{ActivePowerPI, ReactivePowerPI}```. +`CurrentModeControl`. The constructor is `OuterControl{ActivePowerPI, ReactivePowerPI}`. The equations are: ```math @@ -119,14 +119,14 @@ with This models requires a PLL to have a SRF for an internal ``dq`` reference frame. Contrary to the Grid-Forming model, it cannot work without a PLL. Since this Outer Control outputs -a current reference, it can only be used with a current mode inner control (i.e. that receives +a current reference, it can only be used with a current mode inner control (i.e. that receives a current reference instead of a voltage reference). -## Active and Reactive Generic Renewable Controller Type AB ```[OuterControl]``` +## Active and Reactive Generic Renewable Controller Type AB [`PowerSystems.OuterControl`](@extref) The following model represents an outer controller for both active and reactive power from generic industrial models REPCA and REECB to generate the current references that will be used in the Current Controller of the inner control -```RECurrentControlB```. The constructor is ```OuterControl{ActiveRenewableControllerAB, ReactiveRenewableControllerAB}```. +`RECurrentControlB`. The constructor is `OuterControl{ActiveRenewableControllerAB, ReactiveRenewableControllerAB}`. The equations will depend on the flags used. ### Active part @@ -213,4 +213,4 @@ In the case of `VC_Flag = 0, Ref_Flag = 0, PF_Flag = 0, V_Flag = 1` the equation \end{align} ``` -The remaining models for other flags will be included when implemented in `PowerSimulationsDynamics.jl`. \ No newline at end of file +The remaining models for other flags will be included when implemented in `PowerSimulationsDynamics.jl`. diff --git a/docs/src/component_models/pss.md b/docs/src/component_models/pss.md index a7add5958..95e058f86 100644 --- a/docs/src/component_models/pss.md +++ b/docs/src/component_models/pss.md @@ -2,11 +2,11 @@ PSS are used to add an additional signal ``v_s`` to the input signal of the AVR: ``v_\text{ref} = v_\text{ref}^{\text{avr}} + v_s``. -## Fixed PSS ```[PSSFixed]``` +## Fixed PSS [`PowerSystems.PSSFixed`](@extref) This is a simple model that set the stabilization signal to be equal to a desired constant value ``v_s = v_{s}^{\text{fix}}``. The absence of PSS can be modelled using this component with ``v_s^{\text{fix}} = 0``. -## Simple PSS ```[PSSSimple]``` +## Simple PSS [`PowerSystems.PSSSimple`](@extref) This is the most basic PSS that can be implemented, on which the stabilization signal is a proportional controller over the frequency and electrical power: @@ -16,7 +16,7 @@ v_s = K_{\omega}(\omega - \omega_s) + K_p(\omega \tau_e - P_{\text{ref}}) \tag{1 \end{align} ``` -## IEEE Stabilizer ```[IEEEST]``` +## IEEE Stabilizer [`PowerSystems.IEEEST`](@extref) The 7th-order PSS model is: @@ -33,6 +33,7 @@ T_6\dot{x}_7 &= -\left(\frac{K_s T_5}{T_6} y_{LL2} + x_7 \right) \tag{2g} ``` with + ```math \begin{align*} y_f &= \frac{T_4}{T_2} x_2 + \left(T_3 - T_1 \frac{T_4}{T_2}\right) x_3 + \left(1 - \frac{T_4}{T_2}\right)x_4 \\ @@ -45,7 +46,7 @@ V_s &= \text{clamp}(y_{out}, \text{Ls}_\text{min}, \text{Ls}_\text{max}) on which ``u`` is the input signal to the PSS, that depends on the flag. Currently, rotor speed, electric torque, mechanical torque and voltage magnitude are supported inputs. -## STAB1 PSS ```[STAB1]``` +## STAB1 PSS [`PowerSystems.STAB1`](@extref) The 3rd-order PSS model is: @@ -58,10 +59,11 @@ T_4\dot{x}_3 &= \left(1 - \frac{T_2}{T_4}\right) y_{LL} - x_2 \tag{3c} \\ ``` with + ```math \begin{align*} y_{LL} = x_2 + \frac{T_1}{T_3} x_1 \\ y_{out} = x_3 + \frac{T_2}{T_4} y_{LL} \\ V_s = \text{clamp}(y_{out}, -H_{lim}, H_{lim}) \end{align*} -``` \ No newline at end of file +``` diff --git a/docs/src/component_models/shafts.md b/docs/src/component_models/shafts.md index 3fe21d4af..6119b9f72 100644 --- a/docs/src/component_models/shafts.md +++ b/docs/src/component_models/shafts.md @@ -2,7 +2,7 @@ The shaft component defines the rotating mass of the synchronous generator. -## Rotor Mass Shaft ```[SingleMass]``` +## Rotor Mass Shaft [`PowerSystems.SingleMass`](@extref) This is the standard model, on which one single mass (typically the rotor) is used to model the entire inertia of the synchronous generator. Each generator's rotating frame use a reference frequency ``\omega_s``, that typically is the synchronous one (i.e. ``\omega_s = 1.0``). The model defines two differential equations for the rotor angle ``\delta`` and the rotor speed ``\omega``: @@ -13,7 +13,7 @@ This is the standard model, on which one single mass (typically the rotor) is us \end{align} ``` -## Five-Mass Shaft ```[FiveMassShaft]``` +## Five-Mass Shaft [`PowerSystems.FiveMassShaft`](@extref) This model describes model connecting a high-pressure (hp) steam turbine, intermediate-pressure (ip) steam turbine, low-pressure (lp) steam pressure, rotor and exciter (ex) connected in series (in that order) in the same shaft using a spring-mass model: diff --git a/docs/src/component_models/turbine_gov.md b/docs/src/component_models/turbine_gov.md index 26ada375a..887971180 100644 --- a/docs/src/component_models/turbine_gov.md +++ b/docs/src/component_models/turbine_gov.md @@ -2,11 +2,11 @@ This section describes how mechanical power is modified to provide primary frequency control with synchronous generators. It is assumed that ``\tau_{\text{ref}} = P_{\text{ref}}`` since they are decided at nominal frequency ``ω = 1``. -## Fixed TG ```[TGFixed]``` +## Fixed TG [`PowerSystems.TGFixed`](@extref) This a simple model that set the mechanical torque to be equal to a proportion of the desired reference ``\tau_m = \eta P_{\text{ref}}``. To set the mechanical torque to be equal to the desired power, the value of ``\eta`` is set to 1. -## TG Type I ```[TGTypeI]``` +## TG Type I [`PowerSystems.TGTypeI`](@extref) This turbine governor is described by a droop controller and a low-pass filter to model the governor and two lead-lag blocks to model the servo and reheat of the turbine governor. @@ -27,7 +27,7 @@ p_{\text{in}} = P_{\text{ref}} + \frac{1}{R}(\omega_s - 1.0) \end{align*} ``` -## TG Type II ```[TGTypeII]``` +## TG Type II [`PowerSystems.TGTypeII`](@extref) This turbine governor is a simplified model of the Type I. @@ -38,7 +38,7 @@ This turbine governor is a simplified model of the Type I. \end{align} ``` -## TG Simple ```[TGSimple]``` +## TG Simple [`PowerSystems.TGSimple`](@extref) This turbine governor represents a simple first-order model with droop control. It's a 1-state model suitable for basic frequency response studies. @@ -48,10 +48,9 @@ T_m \dot{\tau}_m &= \left(P_{\text{ref}} + d_t (\omega_{\text{ref}} - \omega)\ri \end{align} ``` - The `TGSimple` uses a linear relationship between frequency deviation and power output and a first order lag response with time constant ``T_m``. It is suitable for studies where detailed turbine dynamics are not critical since provides basic primary frequency response through droop control. -## TGOV1 ```[SteamTurbineGov1]``` +## TGOV1 [`PowerSystems.SteamTurbineGov1`](@extref) This represents a classical Steam-Turbine Governor, known as TGOV1. @@ -76,7 +75,7 @@ x_{g1}^\text{sat} &= \left\{ \begin{array}{cl} \end{align} ``` -## GAST ```[GasTG]``` +## GAST [`PowerSystems.GasTG`](@extref) This turbine governor represents the Gas Turbine representation, known as GAST. @@ -102,7 +101,7 @@ x_{g1}^\text{sat} &= \left\{ \begin{array}{cl} \end{align} ``` -## HYGOV ```[HydroTurbineGov]``` +## HYGOV [`PowerSystems.HydroTurbineGov`](@extref) This represents a classical hydro governor, known as HYGOV. @@ -126,7 +125,7 @@ h &= \left(\frac{x_{g4}}{x_{g3}}\right)^2 \tag{6g}\\ \end{align} ``` -## DEGOV ```[DEGOV]``` +## DEGOV [`PowerSystems.DEGOV`](@extref) This turbine governor represents the IEEE Type DEGOV Diesel Engine Governor Model. It's a 5-state model commonly used for diesel generators. @@ -155,7 +154,7 @@ P_m &= T_d y_{delay} \cdot \omega \\ Note that the model includes a time delay ``T_d`` applied to the final actuator output `x_{a3}`. -## DEGOV1 ```[DEGOV1]``` +## DEGOV1 [`PowerSystems.DEGOV1`](@extref) This is an enhanced version of the DEGOV model with optional droop control. It's a 5-state or 6-state model depending on the droop flag. @@ -195,10 +194,10 @@ P_m &= x_{g5}(T_d) \cdot \omega \\ ### Notes -- When droop flag = 0: feedback comes from actuator output (speed droop) -- When droop flag = 1: feedback comes from electrical power (load droop) + - When droop flag = 0: feedback comes from actuator output (speed droop) + - When droop flag = 1: feedback comes from electrical power (load droop) -## WPIDHY ```[WPIDHY]``` +## WPIDHY [`PowerSystems.WPIDHY`](@extref) This model represents a Woodward PID Hydro Turbine Governor, a 7-state model designed for hydro turbine control. @@ -234,10 +233,10 @@ P_m &= \text{clamp}(x_{g7}, P_{min}, P_{max}) - D(\omega - \omega_{sys}) \\ Note that this model includes: -- Includes nonlinear gate-to-power mapping function -- Water inertia modeled with lead-lag compensation + - Includes nonlinear gate-to-power mapping function + - Water inertia modeled with lead-lag compensation -## PIDGOV ```[PIDGOV]``` +## PIDGOV [`PowerSystems.PIDGOV`](@extref) This model represents a PID Turbine Governor, typically used for hydro applications. It's a 7-state model with configurable feedback. @@ -273,9 +272,7 @@ P_m &= x_{g7} - D_{turb}(\omega - \omega_{sys}) \\ Note that this model includes: -- Configurable feedback: electrical power or gate position -- Modified integrator with rate limiting for gate servo -- Water column dynamics with surge tank effects -- Nonlinear gate-to-power characteristic curve - - + - Configurable feedback: electrical power or gate position + - Modified integrator with rate limiting for gate servo + - Water column dynamics with surge tank effects + - Nonlinear gate-to-power characteristic curve diff --git a/docs/src/execute.md b/docs/src/execute.md index e1a99deda..f6990b193 100644 --- a/docs/src/execute.md +++ b/docs/src/execute.md @@ -1,12 +1,12 @@ # Executing a Simulation -After constructing the System data from `PowerSystems.jl` with its dynamic components, a `Simulation` structure must be constructed. Check the API for [`Simulation`](@ref) and [`Simulation!`](@ref) for its construction and available arguments. +After constructing a [`PowerSystems.System`](@extref) with its dynamic components (see [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) documentation), a [`Simulation`](@ref) structure must be constructed. Check the API for [`Simulation`](@ref) and [`Simulation!`](@ref) for its construction and available arguments. -Once a Simulation is constructed and properly initialized, the `execute!` command is used to run the Simulation. If no perturbation was included, then a steady state simulation will be run over the time span defined. See the API of [`execute!`](@ref) for more details. +Once a [`Simulation`](@ref) is constructed and properly initialized, the [`execute!`](@ref) command is used to run the simulation. If no perturbation was included, then a steady state simulation will be run over the time span defined. See the API of [`execute!`](@ref) for more details. ## Solvers -Solvers must be chosen accordingly depending on the type of model used in the Simulation. For example, a Residual model can be executed using Sundials IDA solver: +Solvers must be chosen accordingly depending on the type of model used in the [`Simulation`](@ref). For example, a [`ResidualModel`](@ref) can be executed using Sundials IDA solver: ```julia using Sundials @@ -21,11 +21,12 @@ execute!(sim, IDA()) ``` Results can be explored using: + ```julia results = read_results(sim) ``` -Similarly, a Mass Matrix model can be executed using `Rodas4` solver. +Similarly, a [`MassMatrixModel`](@ref) can be executed using `Rodas4` solver. ```julia using OrdinaryDiffEq @@ -41,7 +42,7 @@ execute!(sim2, Rodas4()) ## Exploring the Solution -Once a Simulation is executed and the results are stored via `results = read_results(sim)`, the following functions can be used to explore the Simulation solution: +Once a [`Simulation`](@ref) is executed and the results are stored via `results = read_results(sim)` (see [`read_results`](@ref)), the following functions can be used to explore the [`SimulationResults`](@ref): ### Show initial conditions @@ -69,12 +70,12 @@ The function [`get_setpoints`](@ref)`(sim)` can be used to obtain the reference ## Keyword Arguments -Any solver option available in `DifferentialEquations.jl` can be passed as keyword arguments in the `execute!` function. Please see the [Common Solver Options](https://diffeq.sciml.ai/stable/basics/common_solver_opts/) in the `DifferentialEquations.jl` documentation for more details. +Any solver option available in `DifferentialEquations.jl` can be passed as keyword arguments in [`execute!`](@ref). Please see the [Common Solver Options](https://diffeq.sciml.ai/stable/basics/common_solver_opts/) in the `DifferentialEquations.jl` documentation for more details. Most common solver options used are `dtmax` to control the maximum dt for adaptive timestepping. `abstol` and `reltol` are also commonly used to control the tolerance in the adaptive timestepping. `saveat` is also used to store the results at a specified time stamps. For example, the following code is valid to further specify your solver options: ```julia -execute!(sim, IDA(), dtmax = 0.01, abstol = 1e-9, reltol = 1e-6, saveat = 0.01) +execute!(sim, IDA(); dtmax = 0.01, abstol = 1e-9, reltol = 1e-6, saveat = 0.01) ``` In addition, the keyword argument `enable_progress_bar = false` can be used to disable the progress bar. diff --git a/docs/src/generic.md b/docs/src/generic.md index a3fab3c15..7729d64c9 100644 --- a/docs/src/generic.md +++ b/docs/src/generic.md @@ -2,7 +2,7 @@ ## Connection with the Inverter Metamodel -Generic Renewable Models for PV solar or battery devices used in industrial tools, such as PSS/E or PowerWorld, does not necessary resemble the proposed structure of our proposed metamodel. +Generic Renewable Models for PV solar or battery devices used in industrial tools, such as PSS/E or PowerWorld, does not necessary resemble the proposed structure of our proposed metamodel. In general terms, a generic renewable model (for PV plant or battery) is typically a Grid Following inverter that uses a Renewable Energy Plant Controller (REPC), a Renewable Energy Electrical Controller (REEC) and a Renewable Energy Generic Converter (REGC) model. The following figure is useful to understand the general structure of such models: @@ -22,7 +22,7 @@ The following example join the active power controllers from [REPCA](https://www ```@raw html -``` ⠀ +``` An important thing to consider with the industrial models, is that the change of Flags can significantly vary the model and purpose of the controller. @@ -32,8 +32,7 @@ Similar to the active controller, the following figure presents the reactive con ```@raw html -``` ⠀ - +``` ### Inner Controller @@ -41,7 +40,7 @@ Finally, the remaining part from [REECB](https://www.powerworld.com/WebHelp/Cont ```@raw html -``` ⠀ +``` The [REGCA](https://www.powerworld.com/WebHelp/Content/TransientModels_HTML/Machine%20Model%20REGC_A.htm)model was directly included in a Converter Block, and the filter can be bypassed using an `RLFilter` block with `rf = lf = 0`. @@ -56,10 +55,10 @@ For the active controller, both `Freq_Flag = 0` (ignoring frequency regulation) The following table describes the current available combination of flags in PSID: | `REF_Flag` | `PF_Flag` | `V_Flag` | `Q_Flag` | -|:--------:|:-------:|:------:|:------:| -| 0 | 0 | 0 | 0 | -| 0 | 0 | 1 | 0 | -| 1 | 0 | 1 | 1 | -| 1 | 0 | 0 | 0 | +|:----------:|:---------:|:--------:|:--------:| +| 0 | 0 | 0 | 0 | +| 0 | 0 | 1 | 0 | +| 1 | 0 | 1 | 1 | +| 1 | 0 | 0 | 0 | -Any combination outside of these cases may not converge to a feasible operating point. Check the following [CAISO report](http://www.caiso.com/Documents/InverterBasedInterconnectionRequestsIBRDynamicModelReviewGuideline.pdf) for the description and compliance of each flag combination. \ No newline at end of file +Any combination outside of these cases may not converge to a feasible operating point. Check the following [CAISO report](http://www.caiso.com/Documents/InverterBasedInterconnectionRequestsIBRDynamicModelReviewGuideline.pdf) for the description and compliance of each flag combination. diff --git a/docs/src/index.md b/docs/src/index.md index 987c053e1..92f85fc70 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -27,20 +27,6 @@ year={2023} } ``` -## Installation - -The latest stable release of PowerSimulationsDynamics.jl can be installed using the Julia package manager with - -```julia -] add PowerSimulationsDynamics -``` - -For the current development version, "checkout" this package with - -```julia -] add PowerSimulationsDynamics#master -``` - ## Structure The following figure shows the interactions between `PowerSimulationsDynamics.jl`, `PowerSystems.jl`, `ForwardDiff.jl`, `DiffEqBase.jl` and the integrators. @@ -53,9 +39,29 @@ BDF and Rosenbrock methods. ```@raw html -``` ⠀ +``` + +## About Sienna + +`PowerSimulationsDynamics.jl` is part of the National Laboratory of the Rockies (formerly known as NREL)'s +[Sienna ecosystem](https://sienna-platform.github.io/Sienna/), an open source framework for +power system modeling, simulation, and optimization. The Sienna ecosystem can be +[found on Github](https://github.com/Sienna-Platform/). It contains three applications: + + - [Sienna\Data](https://sienna-platform.github.io/Sienna/pages/applications/sienna_data.html) enables + efficient data input, analysis, and transformation + - [Sienna\Ops](https://sienna-platform.github.io/Sienna/pages/applications/sienna_ops.html) enables + enables system scheduling simulations by formulating and solving optimization problems + - [Sienna\Dyn](https://sienna-platform.github.io/Sienna/pages/applications/sienna_dyn.html) enables + system transient analysis including small signal stability and full system dynamic + simulations + +Each application uses multiple packages in the [`Julia`](http://www.julialang.org) +programming language. + +## Installation and Quick Links ------------- -PowerSimulationsDynamics.jl has been developed as part of the Scalable Integrated Infrastructure Planning -(SIIP) initiative at the U.S. Department of Energy's National Renewable Energy -Laboratory ([NREL](https://www.nrel.gov/)) + - [Sienna installation page](https://sienna-platform.github.io/Sienna/SiennaDocs/docs/build/how-to/install/): + Instructions to install `PowerSimulationsDynamics.jl` and other Sienna\Dyn packages + - [Sienna Documentation Hub](https://sienna-platform.github.io/Sienna/SiennaDocs/docs/build/index.html): + Links to other Sienna packages' documentation diff --git a/docs/src/initialization.md b/docs/src/initialization.md index d32f92d89..d41a6ad05 100644 --- a/docs/src/initialization.md +++ b/docs/src/initialization.md @@ -26,16 +26,17 @@ inner vars. `PowerSimulationsDynamics.jl` handles all this initializations by de ## Initialization interface By default `PowerSimulationsDynamics.jl` initializes the system following the steps described below. -it is possible to provide an initial guess for the initial conditions to speed up the initialization process. +It is possible to provide an initial guess for the initial conditions to speed up the initialization process. +The following uses [`Simulation`](@ref) with [`ResidualModel`](@ref) (other simulation models and kwargs are available in the API reference): ```julia Simulation( - ResidualModel, - sys, - pwd(), - (0.0, 20.0); - initial_conditions = x0_init, - ) + ResidualModel, + sys, + pwd(), + (0.0, 20.0); + initial_conditions = x0_init, +) ``` It is also possible to initialize the simulation using a flat start (`V_mag = 1.0`, `V_angle = 0.0` and `x0 = zeros`) @@ -44,12 +45,12 @@ result in a valid initial condition for the simulation. ```julia Simulation( - ResidualModel, - sys, - pwd(), - (0.0, 20.0); - initialize_simulation = false, - ) + ResidualModel, + sys, + pwd(), + (0.0, 20.0); + initialize_simulation = false, +) ``` If you want to avoid `PowerSimulationsDynamics.jl` from finding an stable equilibrium automatically @@ -57,13 +58,13 @@ and provide the initial condition manually you can use the following flag combin ```julia Simulation( - ResidualModel, - sys, - pwd(), - (0.0, 20.0); - initialize_simulation = false, - initial_conditions = x0_init, - ) + ResidualModel, + sys, + pwd(), + (0.0, 20.0); + initialize_simulation = false, + initial_conditions = x0_init, +) ``` *WARNING!*: when the `initialize_simulation` is set to `false`, @@ -105,19 +106,19 @@ detailed documentation of the process. ![init_machine](assets/inverter_init.png) -1. The first component to be initialized is the filter. Given that the filter is an RLC - circuit connected to the grid, its currents and voltages need to match the results of the - power flow. The initialization of the filter provides the values for the ``P`` and ``Q`` - used in the outer control and the ``V`` and ``I`` needed in the inner controls. -2. Based on the bus voltage in the system's reference frame ``V_r`` and the bus angle ``\theta`` - the PLL's can be initialized to obtain the angle and frequency estimates needed by the - outer control. -3. The Outer Control calculates the internal angle ``\delta_{olc}`` required by the inner control - to estimate the voltage and current phase difference. -4. The DC Source uses the power set-point consistent with the power outputs of the filter - to initialize the ``V_{dc}`` set-points. This value is used in the inner control. -5. The inner control takes the phase angle ``\delta_{olc}`` and the ``V_{dc}`` to estimate the - modulation values of the PWM converter. + 1. The first component to be initialized is the filter. Given that the filter is an RLC + circuit connected to the grid, its currents and voltages need to match the results of the + power flow. The initialization of the filter provides the values for the ``P`` and ``Q`` + used in the outer control and the ``V`` and ``I`` needed in the inner controls. + 2. Based on the bus voltage in the system's reference frame ``V_r`` and the bus angle ``\theta`` + the PLL's can be initialized to obtain the angle and frequency estimates needed by the + outer control. + 3. The Outer Control calculates the internal angle ``\delta_{olc}`` required by the inner control + to estimate the voltage and current phase difference. + 4. The DC Source uses the power set-point consistent with the power outputs of the filter + to initialize the ``V_{dc}`` set-points. This value is used in the inner control. + 5. The inner control takes the phase angle ``\delta_{olc}`` and the ``V_{dc}`` to estimate the + modulation values of the PWM converter. **Note:** The initialization of an inverter through the proposed meta-model is actively under development and subject to change. This page will maintain the latest version of the sequence. diff --git a/docs/src/models.md b/docs/src/models.md index e6d8c84fb..67fe2bc58 100644 --- a/docs/src/models.md +++ b/docs/src/models.md @@ -1,13 +1,12 @@ - # Models ## Simulation Models -PowerSimulations dynamics supports two formulations for the simulation model and define different methods for each simulation model. You can pass `ResidualModel` or `MassMatrixModel` to a call to Simulation to define the preferred formulation. +PowerSimulations dynamics supports two formulations for the simulation model and define different methods for each simulation model. You can pass [`ResidualModel`](@ref) or [`MassMatrixModel`](@ref) to a call to [`Simulation`](@ref) to define the preferred formulation. In this way, we provide a common set of development requirements for contributors of new models that maintains the same flexibility in choosing the solving algorithm. -- *MassMatrixModel*: Defines models that can be solved using [Mass-Matrix Solvers](https://diffeq.sciml.ai/stable/solvers/dae_solve/#OrdinaryDiffEq.jl-(Mass-Matrix)). The model is formulated as follows: + - [`MassMatrixModel`](@ref): Defines models that can be solved using [Mass-Matrix Solvers](https://diffeq.sciml.ai/stable/solvers/dae_solve/#OrdinaryDiffEq.jl-(Mass-Matrix)). The model is formulated as follows: ```math \begin{align} @@ -17,8 +16,7 @@ M\frac{dx(t)}{dt} = f(x(t)) At this stage we have not conducted extensive tests with all the solvers in [DifferentialEquations](https://diffeq.sciml.ai/) most of our tests use `Rodas5()`. - -- *ResidualModel*: Define models that can be solved using [Implicit ODE solvers](https://diffeq.sciml.ai/stable/solvers/dae_solve/#OrdinaryDiffEq.jl-(Implicit-ODE)) and also the solver IDA from [Sundials](https://diffeq.sciml.ai/stable/solvers/dae_solve/#Sundials.jl). The model is formulated to solved the following problem: + - [`ResidualModel`](@ref): Define models that can be solved using [Implicit ODE solvers](https://diffeq.sciml.ai/stable/solvers/dae_solve/#OrdinaryDiffEq.jl-(Implicit-ODE)) and also the solver IDA from [Sundials](https://diffeq.sciml.ai/stable/solvers/dae_solve/#Sundials.jl). The model is formulated to solved the following problem: ```math \begin{align} @@ -30,7 +28,7 @@ At this stage we have not conducted extensive tests with all the solvers in [Dif ### The dynamic system model in PowerSimulationsDynamics -In order to support both formulations, the default implementation of the ResidualModel solves the following problem: +In order to support both formulations, the default implementation of [`ResidualModel`](@ref) solves the following problem: ```math \begin{align} @@ -50,16 +48,16 @@ For more details, check Brian Stott paper ["Power system dynamic response calcul ## Generator Models -Here we discuss the structure and models used to model generators in `PowerSimulationsDynamics.jl`. See [`PowerSystems.jl` dynamic devices](https://sienna-platform.github.io/PowerSystems.jl/stable/modeler_guide/example_dynamic_data/) -for details. +Here we discuss the structure and models used to model generators in `PowerSimulationsDynamics.jl`. See the explanation on [Dynamic Devices](@extref) +in [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) for details. -Each generator is a data structure composed of the following components defined in `PowerSystems.jl`: +Each generator is a data structure composed of the following components defined in [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/): -- [`Machine`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_Machine/#Machine): That defines the stator electro-magnetic dynamics. -- [`Shaft`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_Shaft/#Shaft): That describes the rotor electro-mechanical dynamics. -- [`Automatic Voltage Regulator`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_AVR/#AVR): Electromotive dynamics to model an AVR controller. -- [`Power System Stabilizer`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_PSS/#PSS): Control dynamics to define an stabilization signal for the AVR. -- [`Prime Mover and Turbine Governor`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_TurbineGov/#TurbineGov): Thermo-mechanical dynamics and associated controllers. + - [`PowerSystems.Machine`](@extref): That defines the stator electro-magnetic dynamics. + - [`PowerSystems.Shaft`](@extref): That describes the rotor electro-mechanical dynamics. + - [`PowerSystems.AVR`](@extref): Electromotive dynamics to model an AVR controller. + - [`PowerSystems.PSS`](@extref): Control dynamics to define an stabilization signal for the AVR. + - [`PowerSystems.TurbineGov`](@extref): Thermo-mechanical dynamics and associated controllers. The implementation of Synchronous generators as components uses the following structure to share values across components. @@ -70,16 +68,16 @@ share values across components. ## Inverter Models -Here we discuss the structure and models used to model inverters in `PowerSimulationsDynamics.jl`. See [`PowerSystems.jl` dynamic devices](https://sienna-platform.github.io/PowerSystems.jl/stable/modeler_guide/example_dynamic_data/) -for details. One of the key contributions in this software package is a separation of the +Here we discuss the structure and models used to model inverters in `PowerSimulationsDynamics.jl`. See the explanation on [Dynamic Devices](@extref) +in [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) for details. One of the key contributions in this software package is a separation of the components in a way that resembles current practices for synchronoues machine modeling. -- [`DC Source`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_DCSource/#DCSource): Defines the dynamics of the DC side of the converter. -- [`Frequency Estimator`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_FrequencyEstimator/#FrequencyEstimator): That describes how the frequency of the grid can be estimated using the grid voltages. Typically a phase-locked loop (PLL). -- [`Outer Loop Control`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/outer_control/#OuterControl): That describes the active and reactive power control dynamics. -- [`Inner Loop Control`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_InnerControl/#InnerControl): That can describe virtual impedance, voltage control and current control dynamics. -- [`Converter`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_Converter/#Converter): That describes the dynamics of the pulse width modulation (PWM) or space vector modulation (SVM). -- [`Filter`](https://sienna-platform.github.io/PowerSystems.jl/stable/model_library/generated_Filter/): Used to connect the converter output to the grid. + - [`PowerSystems.DCSource`](@extref): Defines the dynamics of the DC side of the converter. + - [`PowerSystems.FrequencyEstimator`](@extref): That describes how the frequency of the grid can be estimated using the grid voltages. Typically a phase-locked loop (PLL). + - [`PowerSystems.OuterControl`](@extref): That describes the active and reactive power control dynamics. + - [`PowerSystems.InnerControl`](@extref): That can describe virtual impedance, voltage control and current control dynamics. + - [`PowerSystems.Converter`](@extref): That describes the dynamics of the pulse width modulation (PWM) or space vector modulation (SVM). + - [`PowerSystems.Filter`](@extref): Used to connect the converter output to the grid. The following figure summarizes the components of a inverter and which variables they share: @@ -94,4 +92,4 @@ these posibilities. ## Reference -For models, check the library in [PowerSystems.jl](https://sienna-platform.github.io/PowerSystems.jl/stable/) +For models, check the library in [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/). diff --git a/docs/src/perturbations.md b/docs/src/perturbations.md index 2c4345ab8..6caea8b20 100644 --- a/docs/src/perturbations.md +++ b/docs/src/perturbations.md @@ -4,32 +4,33 @@ Perturbations are used to alter the system from its steady state operation. If a ## List of perturbations -- [`NetworkSwitch`](@ref): allows to modify directly the admittance matrix, `Ybus`, used in the Simulation. -- [`BranchTrip`](@ref): completely disconnects a branch from the system. -- [`BranchImpedanceChange`](@ref): change the impedance of a branch by a user defined multiplier. -- [`GeneratorTrip`](@ref): allows to disconnect a Dynamic Generation unit from the system. -- [`ControlReferenceChange`](@ref): allows to change the reference setpoint provided by a generator/inverter. -- [`LoadChange`](@ref): allows to change the active or reactive power setpoint from a load. -- [`LoadTrip`](@ref): allows the user to disconnect a load from the system. -- [`SourceBusVoltageChange`](@ref): allows to change the reference setpoint provided by a voltage source. + - [`NetworkSwitch`](@ref): allows to modify directly the admittance matrix, `Ybus`, used in the Simulation. + - [`BranchTrip`](@ref): completely disconnects a branch from the system. + - [`BranchImpedanceChange`](@ref): change the impedance of a branch by a user defined multiplier. + - [`GeneratorTrip`](@ref): allows to disconnect a Dynamic Generation unit from the system. + - [`ControlReferenceChange`](@ref): allows to change the reference setpoint provided by a generator/inverter. + - [`LoadChange`](@ref): allows to change the active or reactive power setpoint from a load. + - [`LoadTrip`](@ref): allows the user to disconnect a load from the system. + - [`SourceBusVoltageChange`](@ref): allows to change the reference setpoint provided by a voltage source. ## Examples -### Example 1: Circuit Disconnection using `NetworkSwitch` +### Example 1: Circuit Disconnection using [`NetworkSwitch`](@ref) Consider a two bus system connected via a double circuit line, on which each circuit has parameters, `r = 0.0, x = 0.1, b = 0.0` per unit, then the admittance matrix of the original system is given by: ```julia -yb = [0.0 - 20.0im 0.0 + 20.0im - 0.0 + 20.0im 0.0 - 20.0im] +yb = [0.0-20.0im 0.0+20.0im + 0.0+20.0im 0.0-20.0im] ``` Triping one circuit can be modeled by doubling the impedance, i.e., dividing by 2 the admittance: ```julia -new_yb = [0.0 - 10.0im 0.0 + 10.0im - 0.0 + 10.0im 0.0 - 10.0im] +new_yb = [0.0-10.0im 0.0+10.0im + 0.0+10.0im 0.0-10.0im] ``` + To apply a Network Switch, we require to use a sparse matrix, so we can do this by simply: ```julia @@ -38,18 +39,20 @@ new_yb = sparse(new_yb) ``` Then, this perturbation ocurring at ``t = 1.0`` seconds can be included as: + ```julia ns1 = NetworkSwitch(1.0, new_yb) ``` -### Example 2: Three Phase Fault using `NetworkSwitch` +### Example 2: Three Phase Fault using [`NetworkSwitch`](@ref) Another perturbation that can be modeled is a three phase fault at Bus 1 with impedance `r_f = 0.0001, x_f = 0.0` per unit, then the admittance of this new system is: ```julia -new_yb2 = [10000.0 - 20.0im 0.0 + 20.0im - 0.0 + 20.0im 0.0 - 20.0im] +new_yb2 = [10000.0-20.0im 0.0+20.0im + 0.0+20.0im 0.0-20.0im] ``` + Then, this perturbation ocurring at ``t = 1.0`` seconds can be included as: ```julia @@ -60,8 +63,8 @@ ns2 = NetworkSwitch(1.0, new_yb2) Now, consider that the fault is cleared at ``t = 1.05`` seconds by disconnecting the Circuit 2 of the line. This can be modeled with the single circuit admittance matrix: ```julia -new_yb3 = [0.0 - 10.0im 0.0 + 10.0im - 0.0 + 10.0im 0.0 - 10.0im] +new_yb3 = [0.0-10.0im 0.0+10.0im + 0.0+10.0im 0.0-10.0im] ``` and the perturbation as: @@ -79,8 +82,7 @@ three_fault = [ns2, ns3] that can be passed as a perturbation argument in the Simulation construction. - -### Example 3: `BranchTrip` +### Example 3: [`BranchTrip`](@ref) Consider the following 2 bus system defined by: @@ -91,29 +93,29 @@ buses = [ ] line1 = Line( - "Circuit1", - true, - 0.0, - 0.0, - Arc(from = buses[1], to = buses[2]), - 0.00, - 0.1, - (from = 0.0, to = 0.0), - 2.0, - (min = -0.7, max = 0.7), - ) + "Circuit1", + true, + 0.0, + 0.0, + Arc(; from = buses[1], to = buses[2]), + 0.00, + 0.1, + (from = 0.0, to = 0.0), + 2.0, + (min = -0.7, max = 0.7), +) line2 = Line( - "Circuit2", - true, - 0.0, - 0.0, - Arc(from = buses[1], to = buses[2]), - 0.0, - 0.1, - (from = 0.0, to = 0.0), - 2.0, - (min = -0.7, max = 0.7), - ) + "Circuit2", + true, + 0.0, + 0.0, + Arc(; from = buses[1], to = buses[2]), + 0.0, + 0.1, + (from = 0.0, to = 0.0), + 2.0, + (min = -0.7, max = 0.7), +) sys = System(100.0, buses, [], [], [line1, line2]) ``` @@ -124,16 +126,17 @@ A Branch Trip of Circuit 2 at time ``t = 1.0`` seconds, can be implemented as: b_trip = BranchTrip(1.0, Line, "Circuit2") ``` -**Note:** Islanding is currently not supported in `PowerSimulationsDynamics.jl`. If a `BranchTrip` isolates a generation unit, the system may diverge due to the isolated generator. +**Note:** Islanding is currently not supported in `PowerSimulationsDynamics.jl`. If a [`BranchTrip`](@ref) isolates a generation unit, the system may diverge due to the isolated generator. -### Example 4: `BranchImpedanceChange` +### Example 4: [`BranchImpedanceChange`](@ref) Following the same example as before, it is possible to amplify the impedance of a single circuit by 2.0 (that would represent that this Circuit is actually composed by 2 circuits) using the following perturbation: + ```julia b_change = BranchImpedanceChange(1.0, Line, "Circuit2", 2.0) ``` -### Example 5: `GeneratorTrip` +### Example 5: [`GeneratorTrip`](@ref) Consider that you have a generator at bus 102, named `"generator-102-1"` in your system called `sys`. The constructor to trip it from the system is: @@ -141,7 +144,8 @@ Consider that you have a generator at bus 102, named `"generator-102-1"` in your g = get_component(DynamicGenerator, sys, "generator-102-1") g_trip = GeneratorTrip(1.0, g) ``` -### Example 6: `ControlReferenceChange` + +### Example 6: [`ControlReferenceChange`](@ref) Consider that you have a generator at bus 102, named `"generator-102-1"` in your system called `sys`. The constructor to change is active power reference to `0.5` is: @@ -150,7 +154,7 @@ g = get_component(DynamicGenerator, sys, "generator-102-1") crc = ControlReferenceChange(1.0, g, :P_ref, 0.5) ``` -### Example 7: `LoadChange` +### Example 7: [`LoadChange`](@ref) Consider that you have a load at bus 103, named `"load-103-1"` in your system called `sys`. The constructor to change is active power reference to `0.8` per unit at ``t = 1.0`` seconds is: @@ -159,7 +163,7 @@ l_device = get_component(ElectricLoad, sys, "load-103-1") l_change = LoadChange(1.0, l_device, :P_ref, 0.8) ``` -### Example 8: `LoadTrip` +### Example 8: [`LoadTrip`](@ref) Consider that you have a load at bus 103, named `"load-103-1"` in your system called `sys`. The constructor to disconnect such load at ``t = 1.0`` seconds is: @@ -168,11 +172,11 @@ l_device = get_component(ElectricLoad, sys, "load-103-1") l_trip = LoadTrip(1.0, l_device) ``` -### Example 9: `SourceBusVoltageChange` +### Example 9: [`SourceBusVoltageChange`](@ref) Consider that you have a voltage source at bus 101, named `"source-101-1"` in your system called `sys`. The constructor to change is voltage magnitude reference to `1.02` per unit at ``t = 1.0`` seconds is: ```julia s_device = get_component(Source, sys, "source-101-1") s_change = SourceBusVoltageChange(1.0, s_device, 1, 1.02) -``` \ No newline at end of file +``` diff --git a/docs/src/reference_frames.md b/docs/src/reference_frames.md index a76c7f75f..abb72db72 100644 --- a/docs/src/reference_frames.md +++ b/docs/src/reference_frames.md @@ -31,7 +31,7 @@ frame. The previously convention is not the standard one used for modeling inverters. Most of inverter and phase-lock loop (PLL) models follow the next convention: - ```math +```math \begin{align} v_d + jv_q &= (v_r + jv_i) e^{-j \delta} \tag{2a} \\ v_d &= v_h \cos(\delta - \theta) \tag{2b} \\ diff --git a/docs/src/small.md b/docs/src/small.md index b47e0cf75..22ca99ecc 100644 --- a/docs/src/small.md +++ b/docs/src/small.md @@ -46,9 +46,9 @@ approximation: \left[\begin{array}{c} 0 \\ \Delta\dot{x} - \end{array}\right] = \underbrace{\left[\begin{array} - ~g(y_{eq},x_{eq},p) \\ - f(y_{eq},x_{eq},p) \end{array}\right]}_{ =~ 0} + \end{array}\right] = \underbrace{\left[\begin{array}{c} + g(y_{eq},x_{eq},p) \\ + f(y_{eq},x_{eq},p) \end{array}\right]}_{= 0} + J[y_{eq}, x_{eq}, p] \left[\begin{array}{c} \Delta y \\ \Delta x @@ -94,21 +94,21 @@ on which we can compute its eigenvalues to analyze local stability. ## Accessing the Jacobian function -You can retrieve the Jacobian function for a simulation using the `get_jacobian` function as follows: +You can retrieve the Jacobian function for a simulation using the [`get_jacobian`](@ref) function as follows: ```julia -jacobian = function get_jacobian(ResidualModel, system) +jacobian = get_jacobian(ResidualModel, system) ``` optionally you can pass the number of iterations to check for sparsity as follows: ```julia -jacobian = function get_jacobian(ResidualModel, system, 0) +jacobian = get_jacobian(ResidualModel, system, 0) ``` if you specify 0, the jacobian function will use a full matrix. -The return of `get_jacobian` is known as a functor in Julia and can be used to make evaluations. +The return of [`get_jacobian`](@ref) is known as a functor in Julia and can be used to make evaluations. Currently, any function can be evaluated with the following inputs: ```julia diff --git a/docs/src/time_delays.md b/docs/src/time_delays.md index 799af868c..df95e1cd3 100644 --- a/docs/src/time_delays.md +++ b/docs/src/time_delays.md @@ -12,11 +12,11 @@ For more information on solving such models, refer to the documentation for [Del The following models include time delays: -* `DEGOV` + - `DEGOV` There is currently limited support for including models with time delays. The following limitations apply: -* Only constant delays are supported (state dependent delays are not). -* System models with delays must use `MassMatrixModel` formulation (`ResidualModel` is not currently compatible). -* System models with delays are not compatible with small signal analysis tools. -* The system formulation with delays is not compatible with automatic differentiation for calculating the gradient with respect to time. The setting `autodiff=false` should be set when passing the solver (e.g. `MethodofSteps(Rodas5(autodiff=false))`). + - Only constant delays are supported (state dependent delays are not). + - System models with delays must use [`MassMatrixModel`](@ref) formulation ([`ResidualModel`](@ref) is not currently compatible). + - System models with delays are not compatible with small signal analysis tools. + - The system formulation with delays is not compatible with automatic differentiation for calculating the gradient with respect to time. The setting `autodiff=false` should be set when passing the solver (e.g. `MethodofSteps(Rodas5(autodiff=false))`). diff --git a/docs/src/tutorials/quick_start_guide.jl b/docs/src/tutorials/quick_start_guide.jl index 491360139..5a754ced7 100644 --- a/docs/src/tutorials/quick_start_guide.jl +++ b/docs/src/tutorials/quick_start_guide.jl @@ -1,12 +1,11 @@ # # Quick Start Guide # -# The data for these tutorials is provided in [PowerSystemCaseBuilder](https://github.com/nrel-sienna/PowerSystemCaseBuilder.jl). +# The data for these tutorials is provided in [`PowerSystemCaseBuilder.jl`](https://sienna-platform.github.io/PowerSystemCaseBuilder.jl/stable/). # If you want to build your own case, take a look at the tutorial # [Creating and Handling Data for Dynamic Simulations](@ref) # # For more details about loading data and adding more dynamic components check the -# [Creating a System with Dynamic devices](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/system_dynamic_data/) -# section of the documentation in `PowerSystems.jl`. +# tutorial on [Adding Data for Dynamic Simulations](@extref) in [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/). # # For a detailed tutorial about this case visit [One Machine against Infinite Bus (OMIB) Simulation](@ref) # @@ -22,7 +21,7 @@ using Plots omib_sys = build_system(PSIDSystems, "OMIB System") -# ## Define the Simulation +# ## Define the [`Simulation`](@ref) time_span = (0.0, 30.0) perturbation_trip = BranchTrip(1.0, Line, "BUS 1-BUS 2-i_1") diff --git a/docs/src/tutorials/tutorial_240bus.jl b/docs/src/tutorials/tutorial_240bus.jl index e3c15a1dd..42d07e359 100644 --- a/docs/src/tutorials/tutorial_240bus.jl +++ b/docs/src/tutorials/tutorial_240bus.jl @@ -1,6 +1,4 @@ -# # [PSSE 240 Bus Case system with Renewables](https://www.nrel.gov/grid/test-case-repository.html) -# -# **Originally Contributed by**: José Daniel Lara +# # [PSSE 240 Bus Case system with Renewables](https://www.nlr.gov/grid/test-case-repository) # # ## Introduction # @@ -19,8 +17,7 @@ using OrdinaryDiffEq # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # # ## Load the system and transform load data # @@ -39,9 +36,8 @@ end # The next step is to create the simulation structure. This will create the indexing of our # system that will be used to formulate the differential-algebraic system of equations. To # do so, it is required to specify the perturbation that will occur in the system. In this -# case, we will use a ResidualModel formulation, for more details about the formulation -# checkout the [Models Section](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/models/) -# in `PowerSimulationsDynamics.jl` documentation. +# case, we will use a [`ResidualModel`](@ref) formulation, for more details about the formulation +# checkout the [Models](@ref) section. using Logging sim_ida = Simulation( @@ -73,9 +69,8 @@ plot(v1101_ida) # ## Run the simulation using Rodas4() # -# In this case, we will use a MassMatrixModel formulation, for more details about the -# formulation checkout the [Models Section](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/models/) -# in `PowerSimulationsDynamics.jl` documentation +# In this case, we will use a [`MassMatrixModel`](@ref) formulation, for more details about the +# formulation checkout the [Models](@ref) section sim_rodas = Simulation( MassMatrixModel, diff --git a/docs/src/tutorials/tutorial_activeload.jl b/docs/src/tutorials/tutorial_activeload.jl index 9d5ab7847..947152da7 100644 --- a/docs/src/tutorials/tutorial_activeload.jl +++ b/docs/src/tutorials/tutorial_activeload.jl @@ -1,11 +1,9 @@ # # Tutorial Active Constant Power Load model # -# **Originally Contributed by**: Rodrigo Henriquez-Auba -# # ## Introduction # # This tutorial will introduce you to the functionality of `PowerSimulationsDynamics` and -# `PowerSystems` to explore active load components and a small-signal analysis. +# [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) to explore active load components and a small-signal analysis. # # This tutorial presents a simulation of a two-bus system with a GFM inverter at bus 1, and # a load on bus 2. We will change the model from a constant power load model, to a constant @@ -22,10 +20,9 @@ const PSY = PowerSystems; # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # -# `PowerSystems` (abbreviated with `PSY`) is used to properly define the data structure and +# [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) (abbreviated with `PSY`) is used to properly define the data structure and # establish an equilibrium point initial condition with a power flow routine using `PowerFlows`. # # ## Load the system @@ -46,7 +43,7 @@ first(get_components(PSY.ExponentialLoad, sys)) # ## Run a small-signal analysis # -# We set up the Simulation. Since the droop model does not have a frequency state, we use a +# We set up the [`Simulation`](@ref). Since the droop model does not have a frequency state, we use a # constant frequency reference frame for the network. sim = Simulation(ResidualModel, diff --git a/docs/src/tutorials/tutorial_continuation_pf.jl b/docs/src/tutorials/tutorial_continuation_pf.jl index 6f5a98c77..13eb1ea37 100644 --- a/docs/src/tutorials/tutorial_continuation_pf.jl +++ b/docs/src/tutorials/tutorial_continuation_pf.jl @@ -1,7 +1,5 @@ # # Tutorial Small Signal Analysis with Continuation Power Flow # -# **Originally Contributed by**: Rodrigo Henriquez-Auba -# # ## Introduction # # This tutorial will introduce you to the functionality of `PowerSimulationsDynamics` and @@ -31,10 +29,9 @@ Logging.disable_logging(Logging.Warn); # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # -# `PowerSystems` (abbreviated with `PSY`) is used to properly define the data structure and +# [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) (abbreviated with `PSY`) is used to properly define the data structure and # establish an equilibrium point initial condition with a power flow routine using `PowerFlows`. # # ## Load the system @@ -156,7 +153,7 @@ for p in P_range set_active_power!(load, power) q_power = power * tan(acos(load_pf)) set_reactive_power!(load, q_power) - ## Construct Simulation + ## Construct [`Simulation`](@ref) sim = Simulation(ResidualModel, sys, mktempdir(), (0.0, 1.0)) if sim.status == PSID.BUILT ## Check small-signal stability diff --git a/docs/src/tutorials/tutorial_dynamic_data.jl b/docs/src/tutorials/tutorial_dynamic_data.jl index 555858103..eb73b36da 100644 --- a/docs/src/tutorials/tutorial_dynamic_data.jl +++ b/docs/src/tutorials/tutorial_dynamic_data.jl @@ -1,13 +1,11 @@ # # Creating and Handling Data for Dynamic Simulations # -# **Originally Contributed by**: Rodrigo Henriquez and José Daniel Lara -# # ## Introduction # -# This tutorial briefly introduces how to create a system using `PowerSystems.jl` data -# structures. For more details visit [`PowerSystems.jl` Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/) +# This tutorial briefly introduces how to create a system using [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) data +# structures. # -# Start by calling `PowerSystems.jl` and `PowerSystemCaseBuilder.jl`: +# Start by calling [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) and `PowerSystemCaseBuilder.jl`: using PowerSystems using PowerSystemCaseBuilder @@ -16,24 +14,23 @@ const PSY = PowerSystems; # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # # ## System description # # Next we need to define the different elements required to run a simulation. To run a -# simulation in `PowerSimulationsDynamics`, it is required to define a `System` that +# simulation in `PowerSimulationsDynamics`, it is required to define a [`PowerSystems.System`](@extref) that # contains the following components: # # ### Static Components # # We called static components to those that are used to run a Power Flow problem. # -# - Vector of `Bus` elements, that define all the buses in the network. -# - Vector of `Branch` elements, that define all the branches elements (that connect two buses) in the network. -# - Vector of `StaticInjection` elements, that define all the devices connected to buses that can inject (or withdraw) power. These static devices, typically generators, in `PowerSimulationsDynamics` are used to solve the Power Flow problem that determines the active and reactive power provided for each device. -# - Vector of `PowerLoad` elements, that define all the loads connected to buses that can withdraw current. These are also used to solve the Power Flow. -# - Vector of `Source` elements, that define source components behind a reactance that can inject or withdraw current. +# - Vector of [`PowerSystems.Bus`](@extref) elements, that define all the buses in the network. +# - Vector of [`PowerSystems.ACBranch`](@extref) elements, that define all the branches elements (that connect two buses) in the network. +# - Vector of [`PowerSystems.StaticInjection`](@extref) elements, that define all the devices connected to buses that can inject (or withdraw) power. These static devices, typically generators, in `PowerSimulationsDynamics` are used to solve the Power Flow problem that determines the active and reactive power provided for each device. +# - Vector of [`PowerSystems.PowerLoad`](@extref) elements, that define all the loads connected to buses that can withdraw current. These are also used to solve the Power Flow. +# - Vector of [`PowerSystems.Source`](@extref) elements, that define source components behind a reactance that can inject or withdraw current. # - The base of power used to define per unit values, in MVA as a `Float64` value. # - The base frequency used in the system, in Hz as a `Float64` value. # @@ -41,8 +38,8 @@ const PSY = PowerSystems; # # Dynamic components are those that define differential equations to run a transient simulation. # -# - Vector of `DynamicInjection` elements. These components must be attached to a `StaticInjection` that connects the power flow solution to the dynamic formulation of such device. `DynamicInjection` can be `DynamicGenerator` or `DynamicInverter`, and its specific formulation (i.e. differential equations) will depend on the specific components that define such device. -# - (Optional) Selecting which of the `Lines` (of the `Branch` vector) elements must be modeled of `DynamicLines` elements, that can be used to model lines with differential equations. +# - Vector of [`PowerSystems.DynamicInjection`](@extref) elements. These components must be attached to a [`PowerSystems.StaticInjection`](@extref) that connects the power flow solution to the dynamic formulation of such device. [`PowerSystems.DynamicInjection`](@extref) can be [`PowerSystems.DynamicGenerator`](@extref) or [`PowerSystems.DynamicInverter`](@extref), and its specific formulation (i.e. differential equations) will depend on the specific components that define such device. +# - (Optional) Selecting which of the `Lines` (of the [`PowerSystems.ACBranch`](@extref) vector) elements must be modeled of `DynamicLines` elements, that can be used to model lines with differential equations. # # To start we will define the data structures for the network. # @@ -53,7 +50,7 @@ const PSY = PowerSystems; # ## Static System creation # # To create the system you need to load data using `PowerSystemCaseBuilder.jl`. This system -# was originally created from following [raw file](https://github.com/NREL-Sienna/PowerSystemsTestData/blob/master/psid_tests/data_tests/ThreeBusInverter.raw). +# was originally created from following [raw file](https://github.com/sienna-platform/PowerSystemsTestData/blob/master/psid_tests/data_tests/ThreeBusInverter.raw). sys = build_system(PSIDSystems, "3 Bus Inverter Base"; force_build = true) @@ -117,7 +114,7 @@ tg_none() = TGFixed(1.0) #efficiency ## *PSS: No PSS* pss_none() = PSSFixed(0.0) -# The next lines receives a static generator name, and creates a `DynamicGenerator` based on +# The next lines receives a static generator name, and creates a [`PowerSystems.DynamicGenerator`](@extref) based on # that specific static generator, with the specific components defined previously. This is a # classic machine model without AVR, Turbine Governor and PSS. diff --git a/docs/src/tutorials/tutorial_dynamic_lines.jl b/docs/src/tutorials/tutorial_dynamic_lines.jl index 869af1abf..9be7b37cf 100644 --- a/docs/src/tutorials/tutorial_dynamic_lines.jl +++ b/docs/src/tutorials/tutorial_dynamic_lines.jl @@ -1,7 +1,5 @@ # # Line Modeling Simulations # -# **Originally Contributed by**: Rodrigo Henriquez-Auba and José Daniel Lara -# # ## Introduction # # This tutorial will introduce an example of considering dynamic lines in @@ -29,8 +27,7 @@ using Plots # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # # ### Step 2: Data creation # @@ -72,7 +69,7 @@ Ybus_change = NetworkSwitch( #Time span of our simulation tspan = (0.0, 30.0) -#Define Simulation +#Define [`Simulation`](@ref) sim = Simulation( ResidualModel, #Type of model used threebus_sys, #system @@ -144,7 +141,7 @@ Ybus_change_dyn = NetworkSwitch( # # Now, we construct the simulation: -## Define Simulation +## Define [`Simulation`](@ref) sim_dyn = Simulation( ResidualModel, #Type of model used threebus_sys_dyn, #system diff --git a/docs/src/tutorials/tutorial_inverter_modeling.jl b/docs/src/tutorials/tutorial_inverter_modeling.jl index 4d566093a..e5efc6f86 100644 --- a/docs/src/tutorials/tutorial_inverter_modeling.jl +++ b/docs/src/tutorials/tutorial_inverter_modeling.jl @@ -1,7 +1,5 @@ # # Inverter Modeling simulation # -# **Originally Contributed by**: José Daniel Lara -# # ## Introduction # # This tutorial will introduce the modeling of an inverter with Virtual Inertia in a @@ -28,8 +26,7 @@ using Plots # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # # Create the system using `PowerSystemCaseBuilder.jl`: @@ -39,7 +36,7 @@ sys = build_system(PSIDSystems, "14 Bus Base Case") # in the documentation and tutorials. Normally you would pass your local files to create the # system data. # -# Define Simulation Problem with a 20 second simulation period and the branch trip at t = 1.0: +# Define [`Simulation`](@ref) Problem with a 20 second simulation period and the branch trip at t = 1.0: sim = Simulation( ResidualModel, #Type of model used @@ -131,7 +128,7 @@ storage = EnergyReservoirStorage(; add_component!(sys, storage) # A good sanity check it running a power flow on the system to make sure all the components -# are properly scaled and that the system is properly balanced. We can use `PowerSystems` to +# are properly scaled and that the system is properly balanced. We can use [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) to # perform this check. We can get the results back and perform a sanity check. res = solve_power_flow(ACPowerFlow(), sys) @@ -174,7 +171,7 @@ add_component!(sys, inverter, storage) sys -# Define Simulation problem using the same parameters: +# Define [`Simulation`](@ref) problem using the same parameters: sim = Simulation( ResidualModel, #Type of model used diff --git a/docs/src/tutorials/tutorial_omib.jl b/docs/src/tutorials/tutorial_omib.jl index b85459872..906af59f7 100644 --- a/docs/src/tutorials/tutorial_omib.jl +++ b/docs/src/tutorials/tutorial_omib.jl @@ -1,7 +1,5 @@ # # One Machine against Infinite Bus (OMIB) Simulation # -# **Originally Contributed by**: Rodrigo Henriquez-Auba and José Daniel Lara -# # ## Introduction # # This tutorial will introduce you to the functionality of `PowerSimulationsDynamics` @@ -26,10 +24,9 @@ gr() # !!! note # `PowerSystemCaseBuilder.jl` is a helper library that makes it easier to reproduce # examples in the documentation and tutorials. Normally you would pass your local files -# to create the system data instead of calling the function `build_system`. -# For more details visit [PowerSystemCaseBuilder Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) +# to create the system data instead of calling the function [`PowerSystemCaseBuilder.build_system`](@extref). # -# `PowerSystems` (abbreviated with `PSY`) is used to properly define the data structure and +# [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) (abbreviated with `PSY`) is used to properly define the data structure and # establish an equilibrium point initial condition with a power flow routine, while `Sundials` # is used to solve the problem defined in `PowerSimulationsDynamics`. # @@ -67,7 +64,7 @@ sim = PSID.Simulation( show_states_initial_value(sim) -# ## Run the Simulation +# ## Run the [`Simulation`](@ref) # # Finally, to run the simulation we simply use: @@ -89,14 +86,14 @@ results = read_results(sim) # `PowerSimulationsDynamics` has two functions to obtain different states of the solution: # -# - `get_state_series(results, ("generator-102-1", :δ))`: can be used to obtain the solution +# - [`get_state_series`](@ref): can be used to obtain the solution # as a tuple of time and the required state. In this case, we are obtaining the rotor angle # `:δ` of the generator named `"generator-102-1"`. angle = get_state_series(results, ("generator-102-1", :δ)); plot(angle; xlabel = "time", ylabel = "rotor angle [rad]", label = "rotor angle") -# - `get_voltage_magnitude_series(results, 102)`: can be used to obtain the voltage magnitude +# - [`get_voltage_magnitude_series`](@ref): can be used to obtain the voltage magnitude # as a tuple of time and voltage. In this case, we are obtaining the voltage magnitude at # bus 102 (where the generator is located). diff --git a/docs/src/tutorials_page.md b/docs/src/tutorials_page.md index 05943a396..4d2208005 100644 --- a/docs/src/tutorials_page.md +++ b/docs/src/tutorials_page.md @@ -7,7 +7,7 @@ All the tutorials for the SIIP project are part of a separate repository Specific examples of common workflows and models: -- [Loading Dynamic Data](https://nbviewer.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/2_PowerSystems_examples/09_loading_dynamic_systems_data.ipynb) -- [Solving a One Machine against Infinite Bus model](https://nbviewer.jupyter.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/4_PowerSimulationsDynamics_examples/01_omib.ipynb) -- [Changing line modeling assumptions](https://nbviewer.jupyter.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/4_PowerSimulationsDynamics_examples/02_line_dynamics.ipynb) -- [Using an Inverter in a Multi-Machine Model](https://nbviewer.jupyter.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/4_PowerSimulationsDynamics_examples/03_inverter_model.ipynb) + - [Loading Dynamic Data](https://nbviewer.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/2_PowerSystems_examples/09_loading_dynamic_systems_data.ipynb) + - [Solving a One Machine against Infinite Bus model](https://nbviewer.jupyter.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/4_PowerSimulationsDynamics_examples/01_omib.ipynb) + - [Changing line modeling assumptions](https://nbviewer.jupyter.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/4_PowerSimulationsDynamics_examples/02_line_dynamics.ipynb) + - [Using an Inverter in a Multi-Machine Model](https://nbviewer.jupyter.org/github/Sienna-Platform/SIIPExamples.jl/blob/notebook/4_PowerSimulationsDynamics_examples/03_inverter_model.ipynb) diff --git a/scripts/formatter/formatter_code.jl b/scripts/formatter/formatter_code.jl index 75bc991e6..d55dddd91 100644 --- a/scripts/formatter/formatter_code.jl +++ b/scripts/formatter/formatter_code.jl @@ -5,23 +5,25 @@ Pkg.update() using JuliaFormatter -main_paths = ["."] +main_paths = ["./src", "./test", "./docs/src"] for main_path in main_paths for (root, dir, files) in walkdir(main_path) for f in files - @show file_path = abspath(root, f) - !occursin(".jl", f) && continue - format(file_path; - whitespace_ops_in_indices = true, - remove_extra_newlines = true, - verbose = true, - always_for_in = true, - whitespace_typedefs = true, - conditional_to_if = true, - join_lines_based_on_source = true, - separate_kwargs_with_semicolon = true, + @show file_path = abspath(root, f) + !((occursin(".jl", f) || occursin(".md", f))) && continue + format(file_path; + whitespace_ops_in_indices = true, + remove_extra_newlines = true, + verbose = true, + always_for_in = true, + whitespace_typedefs = true, + conditional_to_if = true, + join_lines_based_on_source = true, + separate_kwargs_with_semicolon = true, + format_markdown = true, + #ignore = [] # list of file that cause formatter to error - # always_use_return = true. # Disabled since it throws a lot of false positives + # always_use_return = true. # Disabled since it throws a lot of false positives ) end end diff --git a/src/base/device_wrapper.jl b/src/base/device_wrapper.jl index 5e9ba4038..d248fb72e 100644 --- a/src/base/device_wrapper.jl +++ b/src/base/device_wrapper.jl @@ -27,7 +27,7 @@ get_delays( Float64[PSY.get_Td(PSY.get_prime_mover(dynamic_injector))] """ -Wraps DynamicInjection devices from PowerSystems to handle changes in controls and connection +Wraps [`PowerSystems.DynamicInjection`](@extref) devices from [`PowerSystems.jl`](https://sienna-platform.github.io/PowerSystems.jl/stable/) to handle changes in controls and connection status, and allocate the required indexes of the state space. """ struct DynamicWrapper{T <: PSY.DynamicInjection} diff --git a/src/base/frequency_reference.jl b/src/base/frequency_reference.jl index 288b4ec9c..6a04806b5 100644 --- a/src/base/frequency_reference.jl +++ b/src/base/frequency_reference.jl @@ -1,4 +1,17 @@ +""" +Frequency-reference mode that keeps system frequency fixed at 1.0 p.u. + +Use this mode when the network frequency should not track a dynamic device +state during simulation. +""" struct ConstantFrequency end + +""" +Frequency-reference mode that tracks the frequency state at the reference bus. + +If a dynamic injector at the slack bus provides a compatible frequency state, +that state is used as the network frequency reference. +""" struct ReferenceBus end function _get_frequency_state(d::DynamicWrapper{T}) where {T <: PSY.DynamicGenerator} diff --git a/src/base/jacobian.jl b/src/base/jacobian.jl index 0fe421ad0..756617c77 100644 --- a/src/base/jacobian.jl +++ b/src/base/jacobian.jl @@ -223,15 +223,15 @@ end """ function get_jacobian( ::Type{T}, - system::PSY.System, + system::[`PowerSystems.System`](@extref), sparse_retrieve_loop::Int = 3, ) where {T <: SimulationModel} Returns the jacobian function of the system model resulting from the system data. # Arguments: -- `::SimulationModel` : Type of Simulation Model. `ResidualModel` or `MassMatrixModel`. See [Models Section](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/models/) for more details -- `system::PowerSystems.System` : System data +- `::SimulationModel` : Type of Simulation Model. [`ResidualModel`](@ref) or [`MassMatrixModel`](@ref). +- `system`: [`PowerSystems.System`](@extref) — power system data - `sparse_retrieve_loop::Int` : Number of loops for sparsity detection. If 0, builds the Jacobian with a DenseMatrix """ function get_jacobian( diff --git a/src/base/perturbations.jl b/src/base/perturbations.jl index 8e18db678..06cc47ba9 100644 --- a/src/base/perturbations.jl +++ b/src/base/perturbations.jl @@ -3,18 +3,18 @@ abstract type Perturbation end """ mutable struct BranchTrip <: Perturbation time::Float64 - branch_type::Type{<:PowerSystems.ACBranch} + branch_type::Type{<:[`PowerSystems.ACBranch`](@extref)} branch_name::String end -A BranchTrip completely disconnects a branch from the system. Currently there is only support for static branches disconnection, `PowerSystems.Line` and `PowerSystems.Transformer2W`. +A BranchTrip completely disconnects a branch from the system. Currently there is only support for static branches disconnection, [`PowerSystems.Line`](@extref) and [`PowerSystems.Transformer2W`](@extref). Future releases will provide support for a Dynamic Line disconnection. -**Note:** Islanding is currently not supported in `PowerSimulationsDynamics.jl`. If a `BranchTrip` isolates a generation unit, the system may diverge due to the isolated generator. +**Note:** Islanding is currently not supported in `PowerSimulationsDynamics.jl`. If a [`BranchTrip`](@ref) isolates a generation unit, the system may diverge due to the isolated generator. # Arguments: - `time::Float64` : Defines when the Branch Trip will happen. This time should be inside the time span considered in the Simulation -- `branch_tipe::Type{<:PowerSystems.ACBranch}` : Type of branch disconnected +- `branch_tipe::Type{<:PowerSystems.ACBranch}` : Branch type (subtype of [`PowerSystems.ACBranch`](@extref)) - `branch_name::String` : User defined name for identifying the branch """ mutable struct BranchTrip <: Perturbation @@ -31,13 +31,13 @@ end multiplier::Float64 end -A BranchImpedanceChange change the impedance of a branch by a user defined multiplier. Currently there is only support for static branches disconnection, `PowerSystems.Line` and `PowerSystems.Transformer2W`. +A BranchImpedanceChange change the impedance of a branch by a user defined multiplier. Currently there is only support for static branches disconnection, [`PowerSystems.Line`](@extref) and [`PowerSystems.Transformer2W`](@extref). Future releases will provide support for a Dynamic Line disconnection. # Arguments: - `time::Float64` : Defines when the Branch Impedance Change will happen. This time should be inside the time span considered in the Simulation -- `branch_tipe::Type{<:PowerSystems.ACBranch}` : Type of branch modified +- `branch_tipe::Type{<:PowerSystems.ACBranch}` : Branch type (subtype of [`PowerSystems.ACBranch`](@extref)) - `branch_name::String` : User defined name for identifying the branch - `multiplier::Float64` : User defined value for impedance multiplier. """ @@ -376,7 +376,7 @@ end """ mutable struct ControlReferenceChange <: Perturbation time::Float64 - device::PowerSystems.DynamicInjection + device::[`PowerSystems.DynamicInjection`](@extref) signal::Symbol ref_value::Float64 end @@ -386,7 +386,7 @@ A ControlReferenceChange allows to change the reference setpoint provided by a g # Arguments: - `time::Float64` : Defines when the Control Reference Change will happen. This time should be inside the time span considered in the Simulation -- `device::Type{<:PowerSystems.DynamicInjection}` : Dynamic device modified +- `device::Type{<:PowerSystems.DynamicInjection}` : Dynamic device ([`PowerSystems.DynamicInjection`](@extref)) - `signal::Symbol` : determines which reference setpoint will be modified. The accepted signals are: - `:P_ref`: Modifies the active power reference setpoint. - `:V_ref`: Modifies the voltage magnitude reference setpoint (if used). @@ -488,7 +488,7 @@ A `SourceBusVoltageChange` allows to change the reference setpoint provided by a # Arguments: - `time::Float64` : Defines when the Control Reference Change will happen. This time should be inside the time span considered in the Simulation -- `device::Type{<:PowerSystems.Source}` : Device modified +- `device::Type{<:PowerSystems.Source}` : Voltage source device ([`PowerSystems.Source`](@extref)) - `signal::Symbol` : determines which reference setpoint will be modified. The accepted signals are: - :V_ref Modifies the internal voltage magnitude reference setpoint. - :θ_ref Modifies the internal voltage angle reference setpoint. @@ -519,7 +519,7 @@ end """ mutable struct GeneratorTrip <: Perturbation time::Float64 - device::PowerSystems.DynamicInjection + device::[`PowerSystems.DynamicInjection`](@extref) end A `GeneratorTrip` allows to disconnect a Dynamic Generation unit from the system at a specified time. @@ -527,7 +527,7 @@ A `GeneratorTrip` allows to disconnect a Dynamic Generation unit from the system # Arguments: - `time::Float64` : Defines when the Generator Trip will happen. This time should be inside the time span considered in the Simulation -- `device::Type{<:PowerSystems.DynamicInjection}` : Device to be disconnected +- `device::Type{<:PowerSystems.DynamicInjection}` : Device to disconnect ([`PowerSystems.DynamicInjection`](@extref)) """ mutable struct GeneratorTrip <: Perturbation time::Float64 @@ -552,7 +552,7 @@ end """ mutable struct LoadChange <: Perturbation time::Float64 - device::PowerSystems.ElectricLoad + device::[`PowerSystems.ElectricLoad`](@extref) signal::Symbol ref_value::Float64 end @@ -562,7 +562,7 @@ A LoadChange allows to change the active or reactive power setpoint from a load. # Arguments: - `time::Float64` : Defines when the Load Change will happen. This time should be inside the time span considered in the Simulation -- `device::Type{<:PowerSystems.ElectricLoad}` : Dynamic device modified +- `device::Type{<:PowerSystems.ElectricLoad}` : Load device ([`PowerSystems.ElectricLoad`](@extref)) - `signal::Symbol` : determines which reference setpoint will be modified. The accepted signals are: - `:P_ref`: Modifies the active power reference setpoint. - `:Q_ref`: Modifies the reactive power reference setpoint. @@ -715,7 +715,7 @@ end """ mutable struct LoadTrip <: Perturbation time::Float64 - device::PowerSystems.ElectricLoad + device::[`PowerSystems.ElectricLoad`](@extref) end A `LoadTrip` allows the user to disconnect a load from the system. @@ -723,7 +723,7 @@ A `LoadTrip` allows the user to disconnect a load from the system. # Arguments: - `time::Float64` : Defines when the Generator Trip will happen. This time should be inside the time span considered in the Simulation -- `device::Type{<:PowerSystems.ElectricLoad}` : Device to be disconnected +- `device::Type{<:PowerSystems.ElectricLoad}` : Load to disconnect ([`PowerSystems.ElectricLoad`](@extref)) """ mutable struct LoadTrip <: Perturbation time::Float64 diff --git a/src/base/simulation.jl b/src/base/simulation.jl index 469d91c8f..6e5d3f950 100644 --- a/src/base/simulation.jl +++ b/src/base/simulation.jl @@ -81,7 +81,7 @@ end """ function Simulation! ::SimulationModel - system::PowerSystems.System + system::[`PowerSystems.System`](@extref) simulation_folder::String tspan::NTuple{2, Float64}, perturbations::Vector{<:Perturbation} = Vector{Perturbation}(); @@ -91,16 +91,16 @@ end Builds the simulation object and conducts the indexing process. The initial conditions are stored in the system. # Arguments: -- `::SimulationModel` : Type of Simulation Model. `ResidualModel` or `MassMatrixModel`. See [Models Section](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/models/) for more details -- `system::PowerSystems.System` : System data +- `::SimulationModel` : Type of Simulation Model. [`ResidualModel`](@ref) or [`MassMatrixModel`](@ref). +- `system`: [`PowerSystems.System`](@extref) — power system data - `simulation_folder::String` : Folder directory - `tspan::NTuple{2, Float64}` : Time span for simulation - `perturbations::Vector{<:Perturbation}` : Vector of Perturbations for the Simulation. Default: No Perturbations -- `initialize_simulation::Bool` : Runs the initialization routine. If false, simulation runs based on the operation point stored in System +- `initialize_simulation::Bool` : Runs the initialization routine. If false, simulation runs based on the operating point stored in [`PowerSystems.System`](@extref) - `initial_conditions::Vector{Float64}` : Allows the user to pass a vector with the initial condition values desired in the simulation. If initialize_simulation = true, these values are used as a first guess and overwritten. -- `frequency_reference` : Default `ReferenceBus`. Determines which frequency model is used for the network. Currently there are two options available: - - `ConstantFrequency` assumes that the network frequency is 1.0 per unit at all times. - - `ReferenceBus` will use the frequency state of a Dynamic Generator (rotor speed) or Dynamic Inverter (virtual speed) connected to the Reference Bus (defined in the Power Flow data) as the network frequency. If multiple devices are connected to such bus, the device with larger base power will be used as a reference. If a Voltage Source is connected to the Reference Bus, then a `ConstantFrequency` model will be used. +- `frequency_reference` : Default [`ReferenceBus`](@ref). Determines which frequency model is used for the network. Currently there are two options available: + - [`ConstantFrequency`](@ref) assumes that the network frequency is 1.0 per unit at all times. + - [`ReferenceBus`](@ref) will use the frequency state of a Dynamic Generator (rotor speed) or Dynamic Inverter (virtual speed) connected to the Reference Bus (defined in the Power Flow data) as the network frequency. If multiple devices are connected to such bus, the device with larger base power will be used as a reference. If a Voltage Source is connected to the Reference Bus, then a [`ConstantFrequency`](@ref) model will be used. - `system_to_file::Bool` : Default `false`. Serializes the initialized system - `console_level::Logging` : Default `Logging.Warn`. Sets the level of logging output to the console. Can be set to `Logging.Error`, `Logging.Warn`, `Logging.Info` or `Logging.Debug` - `file_level::Logging` : Default `Logging.Info`. Sets the level of logging output to file. Can be set to `Logging.Error`, `Logging.Warn`, `Logging.Info` or `Logging.Debug` @@ -138,7 +138,7 @@ end """ function Simulation ::SimulationModel - system::PowerSystems.System + system::[`PowerSystems.System`](@extref) simulation_folder::String tspan::NTuple{2, Float64}, perturbations::Vector{<:Perturbation} = Vector{Perturbation}(); @@ -148,16 +148,16 @@ end Builds the simulation object and conducts the indexing process. The original system is not modified and a copy its created and stored in the Simulation. # Arguments: -- `::SimulationModel` : Type of Simulation Model. `ResidualModel` or `MassMatrixModel`. See [Models Section](https://sienna-platform.github.io/PowerSimulationsDynamics.jl/stable/models/) for more details -- `system::PowerSystems.System` : System data +- `::SimulationModel` : Type of Simulation Model. [`ResidualModel`](@ref) or [`MassMatrixModel`](@ref). +- `system`: [`PowerSystems.System`](@extref) — power system data - `simulation_folder::String` : Folder directory - `tspan::NTuple{2, Float64}` : Time span for simulation - `perturbations::Vector{<:Perturbation}` : Vector of Perturbations for the Simulation. Default: No Perturbations -- `initialize_simulation::Bool` : Runs the initialization routine. If false, simulation runs based on the operation point stored in System +- `initialize_simulation::Bool` : Runs the initialization routine. If false, simulation runs based on the operating point stored in [`PowerSystems.System`](@extref) - `initial_conditions::Vector{Float64}` : Allows the user to pass a vector with the initial condition values desired in the simulation. If initialize_simulation = true, these values are used as a first guess and overwritten. -- `frequency_reference` : Default `ReferenceBus`. Determines which frequency model is used for the network. Currently there are two options available: - - `ConstantFrequency` assumes that the network frequency is 1.0 per unit at all times. - - `ReferenceBus` will use the frequency state of a Dynamic Generator (rotor speed) or Dynamic Inverter (virtual speed) connected to the Reference Bus (defined in the Power Flow data) as the network frequency. If multiple devices are connected to such bus, the device with larger base power will be used as a reference. If a Voltage Source is connected to the Reference Bus, then a `ConstantFrequency` model will be used. +- `frequency_reference` : Default [`ReferenceBus`](@ref). Determines which frequency model is used for the network. Currently there are two options available: + - [`ConstantFrequency`](@ref) assumes that the network frequency is 1.0 per unit at all times. + - [`ReferenceBus`](@ref) will use the frequency state of a Dynamic Generator (rotor speed) or Dynamic Inverter (virtual speed) connected to the Reference Bus (defined in the Power Flow data) as the network frequency. If multiple devices are connected to such bus, the device with larger base power will be used as a reference. If a Voltage Source is connected to the Reference Bus, then a [`ConstantFrequency`](@ref) model will be used. - `system_to_file::Bool` : Default `false`. Serializes the initialized system - `console_level::Logging` : Default `Logging.Warn`. Sets the level of logging output to the console. Can be set to `Logging.Error`, `Logging.Warn`, `Logging.Info` or `Logging.Debug` - `file_level::Logging` : Default `Logging.Info`. Sets the level of logging output to file. Can be set to `Logging.Error`, `Logging.Warn`, `Logging.Info` or `Logging.Debug` @@ -567,8 +567,8 @@ end Solves the time-domain dynamic simulation model. # Arguments -- `sim::Simulation` : Initialized simulation object -- `solver` : Solver used for numerical integration. Must be passed correctly depending on the Type of Simulation Model +- **`sim`**: [`Simulation`](@ref) — initialized simulation object +- **`solver`**: solver used for numerical integration; must match the formulation (e.g. solvers for [`ResidualModel`](@ref) vs [`MassMatrixModel`](@ref)) - `enable_progress_bar::Bool` : Default: `true`. Enables progress bar for the integration routine. - Additional solver keyword arguments can be included. See [Common Solver Options](https://diffeq.sciml.ai/stable/basics/common_solver_opts/) in the `DifferentialEquations.jl` documentation for more details. """ @@ -586,6 +586,15 @@ function execute!(sim::Simulation, solver; kwargs...) return sim.status end +""" + read_results(sim::Simulation) + +Return the [`SimulationResults`](@ref) stored in `sim` after [`execute!`](@ref) completes (or the last available results object). + +# Arguments + +- **`sim`**: [`Simulation`](@ref) to read from +""" function read_results(sim::Simulation) return sim.results end @@ -601,7 +610,7 @@ Function that returns the reference setpoints for all the dynamic devices. # Arguments -- `sim::Simulation` : Simulation object that contains the initial condition and setpoints. +- **`sim`**: [`Simulation`](@ref) — object that contains the initial condition and setpoints """ function get_setpoints(sim::Simulation) return get_setpoints(get_simulation_inputs(sim)) diff --git a/src/base/simulation_results.jl b/src/base/simulation_results.jl index 89cb9bf7f..e1690ba30 100644 --- a/src/base/simulation_results.jl +++ b/src/base/simulation_results.jl @@ -1,3 +1,10 @@ +""" +Container for the output of a dynamic simulation run. + +`SimulationResults` stores the solved trajectory together with lookup structures +used by post-processing utilities (state maps, bus lookup, setpoints, and +auxiliary pointers). +""" struct SimulationResults global_index::MAPPING_DICT bus_lookup::Dict{Int, Int} diff --git a/src/base/small_signal.jl b/src/base/small_signal.jl index 441c15e5b..702b79e8c 100644 --- a/src/base/small_signal.jl +++ b/src/base/small_signal.jl @@ -196,10 +196,10 @@ end sim::Simulation, ) -Returns the Small Signal Output object that contains the eigenvalues and participation factors. +Returns the small-signal output object that contains the eigenvalues and participation factors. # Arguments -- `sim::Simulation` : Small Signal Output object that contains the eigenvalues and participation factors +- **`sim`**: [`Simulation`](@ref) for a system **without** time delays """ function small_signal_analysis(sim::Simulation{T}; kwargs...) where {T <: SimulationModel} inputs = get_simulation_inputs(sim)