{ "cells": [ { "cell_type": "markdown", "source": [ "# Operations problems with [PowerSimulations.jl](https://github.com/NREL-SIIP/PowerSimulations.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 the construction and solution of optimal power system\n", "scheduling problems (Operations Problems). Operations problems form the fundamental\n", "building blocks for [sequential simulations](https://nbviewer.jupyter.org/github/NREL-SIIP/SIIPExamples.jl/blob/master/notebook/3_PowerSimulations_examples/02_sequential_simulations.ipynb).\n", "This example shows how to specify and customize a the mathematics that will be applied to the data with\n", "an `ProblemTemplate`, build and execute an `DecisionModel`, and access the results." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "## Dependencies" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using SIIPExamples" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Modeling Packages" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using PowerSystems\n", "using PowerSimulations\n", "const PSI = PowerSimulations\n", "using PowerSystemCaseBuilder" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Optimization packages" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using HiGHS # solver" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Data\n", "This data depends upon the [RTS-GMLC](https://github.com/gridmod/rts-gmlc) dataset. Let's\n", "use [PowerSystemCaseBuilder.jl](https://nbviewer.jupyter.org/github/NREL-SIIP/SIIPExamples.jl/blob/master/notebook/3_PowerSimulations_examples/10_PowerSystemCaseBuilder.ipynb) to download and build a `System`." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "sys = build_system(PSITestSystems, \"modified_RTS_GMLC_DA_sys\")" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## Define a problem specification with an `ProblemTemplate`\n", "You can create an empty template with:" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "template_uc = ProblemTemplate()" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Now, you can add a `DeviceModel` for each device type to create an assignment between PowerSystems device types\n", "and the subtypes of `AbstractDeviceFormulation`. PowerSimulations has a variety of different\n", "`AbstractDeviceFormulation` subtypes that can be applied to different PowerSystems device types,\n", "each dispatching to different methods for populating optimization problem objectives, variables,\n", "and constraints." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "print_tree(PSI.AbstractDeviceFormulation)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Branch Formulations\n", "Here is an example of relatively standard branch formulations. Other formulations allow\n", "for selective enforcement of transmission limits and greater control on transformer settings." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "set_device_model!(template_uc, Line, StaticBranch)\n", "set_device_model!(template_uc, Transformer2W, StaticBranch)\n", "set_device_model!(template_uc, TapTransformer, StaticBranch)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Injection Device Formulations\n", "Here we define template entries for all devices that inject or withdraw power on the\n", "network. For each device type, we can define a distinct `AbstractDeviceFormulation`. In\n", "this case, we're defining a basic unit commitment model for thermal generators,\n", "curtailable renewable generators, and fixed dispatch (net-load reduction) formulations\n", "for `HydroDispatch` and `RenewableFix` devices." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment)\n", "set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch)\n", "set_device_model!(template_uc, PowerLoad, StaticPowerLoad)\n", "set_device_model!(template_uc, HydroDispatch, FixedOutput)\n", "set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver)\n", "set_device_model!(template_uc, RenewableFix, FixedOutput)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Service Formulations\n", "We have two `VariableReserve` types, parameterized by their direction. So, similar to\n", "creating `DeviceModel`s, we can create `ServiceModel`s. The primary difference being\n", "that `DeviceModel` objects define how constraints get created, while `ServiceModel` objects\n", "define how constraints get modified." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "set_service_model!(template_uc, VariableReserve{ReserveUp}, RangeReserve)\n", "set_service_model!(template_uc, VariableReserve{ReserveDown}, RangeReserve)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Network Formulations\n", "Finally, we can define the transmission network specification that we'd like to model. For simplicity, we'll\n", "choose a copper plate formulation. But there are dozens of specifications available through\n", "an integration with [PowerModels.jl](https://github.com/lanl-ansi/powermodels.jl). *Note that\n", "many formulations will require appropriate data and may be computationally intractable*" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "set_network_model!(template_uc, NetworkModel(CopperPlatePowerModel))" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## `DecisionModel`\n", "Now that we have a `System` and an `ProblemTemplate`, we can put the two together\n", "to create an `DecisionModel` that we solve." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "### Optimizer\n", "It's most convenient to define an optimizer instance upfront and pass it into the\n", "`DecisionModel` constructor. For this example, we can use the free HiGHS solver with a\n", "relatively relaxed MIP gap (`ratioGap`) setting to improve speed." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "solver = optimizer_with_attributes(HiGHS.Optimizer, \"mip_rel_gap\" => 0.5)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Build an `DecisionModel`\n", "The construction of an `DecisionModel` essentially applies an `ProblemTemplate`\n", "to `System` data to create a JuMP model." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "problem = DecisionModel(template_uc, sys; optimizer = solver, horizon = 24)\n", "\n", "build!(problem, output_dir = mktempdir())" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "The principal component of the `DecisionModel` is the JuMP model. For small problems,\n", "you can inspect it by simply printing it to the screen:\n", "```julia\n", "PSI.get_jump_model(problem)\n", "```\n", "\n", "For anything of reasonable size, that will be unmanageable. But you can print to a file:\n", "```julia\n", "f = open(\"testmodel.txt\",\"w\"); print(f,PSI.get_jump_model(problem)); close(f)\n", "```\n", "\n", "In addition to the JuMP model, an `DecisionModel` keeps track of a bunch of metadata\n", "about the problem and some references to pretty names for constraints and variables.\n", "All of these details are contained within the `optimization_container` field." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "print_struct(typeof(PSI.get_optimization_container(problem)))" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Solve an `DecisionModel`" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "solve!(problem)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## Results Inspection\n", "PowerSimulations collects the `DecisionModel` results into a struct:" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "print_struct(PSI.ProblemResults)\n", "\n", "res = ProblemResults(problem);" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Optimizer Stats\n", "The optimizer summary is included" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "get_optimizer_stats(res)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Objective Function Value" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "get_objective_value(res)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "### Variable, Parameter, Auxillary Variable, Dual, and Expression Values\n", "The solution value data frames for variables, parameters, auxillary variables, duals and\n", "expressions can be accessed using the `read_` methods:" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "read_variables(res)" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "Or, you can read a single parameter values for parameters that exist in the results." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "list_parameter_names(res)\n", "read_parameter(res, \"ActivePowerTimeSeriesParameter__RenewableDispatch\")" ], "metadata": {}, "execution_count": null }, { "cell_type": "markdown", "source": [ "## Plotting\n", "Take a look at the examples in [the plotting folder.](../../notebook/3_PowerSimulations_examples/Plotting)" ], "metadata": {} }, { "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 }