{ "cells": [ { "cell_type": "markdown", "source": [ "# ACOPF with [PowerSimulations.jl](https://github.com/NREL-SIIP/PowerSimulations.jl) using [PowerModels.jl](https://github.com/lanl-ansi/PowerModels.jl)" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "**Originally Contributed by**: Clayton Barrows" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Introduction" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "PowerSimulations.jl supports non-linear AC optimal power flow through a deep integration\n", "with [PowerModels.jl](https://github.com/lanl-ansi/PowerModels.jl). This example shows a\n", "single multi-period optimization of economic dispatch with a full representation of\n", "AC optimal power flow. However, since we use a case where generators are subject to\n", "minimum operating points, we need to also execute a unit commitment problem to provide the\n", "ACOPF with a valid commitment pattern. This example uses a `Simulation` with two\n", "`DecisionModels` to execute the UC-ACOPF workflow for a single period." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Dependencies" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using SIIPExamples\n", "using PowerSystems\n", "using PowerSimulations\n", "using PowerSystemCaseBuilder\n", "using Dates\n", "sim_folder = mktempdir(\".\", cleanup = true)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "We'll just use a suitable `System` that contains valid AC power flow parameters" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sys = build_system(PSITestSystems, \"modified_RTS_GMLC_DA_sys\")\n", "transform_single_time_series!(sys, 1, Hour(1))" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Since we'll be doing non-linear optimization, we need a solver that supports non-linear\n", "problems. Ipopt is quite good. And, we'll need a separate solver that can handle integer variables.\n", "So, we'll use HiGHS for the UC problem." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using Ipopt\n", "solver = optimizer_with_attributes(Ipopt.Optimizer)\n", "using HiGHS # mip solver\n", "uc_solver = optimizer_with_attributes(HiGHS.Optimizer, \"mip_rel_gap\" => 0.5)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Here, we want do define an economic dispatch (linear generation decisions) with an ACOPF\n", "network representation.\n", "So, starting with the network, we can select from _almost_ any of the endpoints on this\n", "tree:" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "print_tree(PowerSimulations.PM.AbstractPowerModel)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "First, we can setup a template with a suitable ACOPF network formulation, and formulations\n", "that represent each of the relevant device categories" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "ed_template = ProblemTemplate()\n", "set_device_model!(ed_template, ThermalStandard, ThermalStandardDispatch)\n", "set_device_model!(ed_template, PowerLoad, StaticPowerLoad)\n", "set_device_model!(ed_template, Line, StaticBranch)\n", "set_device_model!(ed_template, TapTransformer, StaticBranch)\n", "set_device_model!(ed_template, Transformer2W, StaticBranch)\n", "set_device_model!(ed_template, HVDCLine, HVDCDispatch)\n", "set_network_model!(ed_template, NetworkModel(ACPPowerModel, use_slacks = true))" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "We also need to setup a UC template with a simplified network representation" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "uc_template = ProblemTemplate(DCPPowerModel)\n", "set_device_model!(uc_template, ThermalStandard, ThermalBasicUnitCommitment)\n", "set_device_model!(uc_template, PowerLoad, StaticPowerLoad)\n", "set_device_model!(uc_template, Line, StaticBranch)\n", "set_device_model!(uc_template, TapTransformer, StaticBranch)\n", "set_device_model!(uc_template, Transformer2W, StaticBranch)\n", "set_device_model!(uc_template, HVDCLine, HVDCDispatch)\n", "set_service_model!(uc_template, VariableReserve{ReserveUp}, RangeReserve)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Now we can build a simulation to solve the UC, pass the commitment pattern to the ACOPF\n", "and then solve the ACOPF." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "models = SimulationModels(\n", " decision_models = [\n", " DecisionModel(uc_template, sys, name = \"UC\", optimizer = uc_solver),\n", " DecisionModel(\n", " ed_template,\n", " sys,\n", " name = \"ACOPF\",\n", " optimizer = solver,\n", " initialize_model = false,\n", " ),\n", " ],\n", ")\n", "sequence = SimulationSequence(\n", " models = models,\n", " feedforwards = Dict(\n", " \"ACOPF\" => [\n", " SemiContinuousFeedforward(\n", " component_type = ThermalStandard,\n", " source = OnVariable,\n", " affected_values = [ActivePowerVariable, ReactivePowerVariable],\n", " ),\n", " ],\n", " ),\n", " ini_cond_chronology = InterProblemChronology(),\n", ")" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Note that in the above feedforward definition, the `OnVariable` for the `ThermalStandard`\n", "components is affecting both the `ActivePowerVariable` and the `ReactivePowerVariable`.\n", "This is the connection that restricts the ACOPF to only represent active and reactive\n", "power injections from the units that are committed in the UC problem. It's not guaranteed\n", "that the UC result generates an AC feasible initial condition, so this problem selects\n", "a particular period (`initial_time`) where the conditions are suitable." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sim = Simulation(\n", " name = \"UC-ACOPF\",\n", " steps = 12,\n", " models = models,\n", " sequence = sequence,\n", " simulation_folder = sim_folder,\n", ")\n", "\n", "build!(sim)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "And solve it ..." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "execute!(sim, enable_progress_bar = false)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "And extract some results" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "results = SimulationResults(sim)\n", "ac_results = get_problem_results(results, \"ACOPF\")\n", "\n", "slack_keys = [\n", " k for k in list_variable_keys(ac_results) if\n", " PSI.get_entry_type(k) ∈ [SystemBalanceSlackDown, SystemBalanceSlackUp]\n", "]\n", "slack_vars = read_realized_variables(ac_results, slack_keys)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Plot the slack values" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "plot_results(slack_vars);" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "---\n", "\n", "*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*" ], "metadata": {} } ], "nbformat_minor": 3, "metadata": { "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.7.2" }, "kernelspec": { "name": "julia-1.7", "display_name": "Julia 1.7.2", "language": "julia" } }, "nbformat": 4 }