Created
May 23, 2019 13:08
-
-
Save coroa/4470bb2461c7e73490bcac7abc86545e to your computer and use it in GitHub Desktop.
Energy System Optimization With Julia Dive Into The Packages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# Power System Optimization with Julia" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "## Installation instructions" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "install julia http://julialang.org/" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "```\n", | |
| "$ julia\n", | |
| "\n", | |
| "]add IJulia\n", | |
| "```" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "Once you are on a jupyter notebook with a julia kernel" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "### For Joulia" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "Get the example from https://github.com/JuliaEnergy/JouliaExamples\n", | |
| "\n", | |
| "]add [email protected]\n", | |
| "]add https://github.com/JuliaEnergy/Joulia.jl CSV DataFrames" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "### For PowerSystems/PowerSimulations" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "]add PowerSimulation PowerSystems\n", | |
| "\n", | |
| "https://github.com/NREL-SIIP/Examples" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "cd(\".../Examples\")\n", | |
| "]activate env; instantiate\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "### For EnergyModels" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "Pkg.add(\"https://gitlab.com/coroa/EnergyModels.git\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "## For PowerModels\n", | |
| "\n", | |
| "]add PowerModels\n", | |
| "\n", | |
| "https://github.com/NREL/PowerSystemsTestData/tree/master/matpower" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "MATPOWER_DIR = \"/home/coroa/.julia/dev/PowerSystems/data/pm_data/matpower\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "using D3TypeTrees\n", | |
| "\n", | |
| "using PowerModels\n", | |
| "using PowerSystems\n", | |
| "using PowerSimulations\n", | |
| "\n", | |
| "using Logging" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 156, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "MultiLogger(AbstractLogger[ConsoleLogger(IJuliaStdio{PipeEndpoint}(IOContext(PipeEndpoint(RawFD(0x0000002d) open, 0 bytes waiting))), Error, default_metafmt, true, 0, Dict{Any,Int64}()), SimpleLogger(IOStream(<file log.txt>), Info, Dict{Any,Int64}())], LogEventTracker(Dict(Error=>Dict(),Info=>Dict(),Warn=>Dict())))" | |
| ] | |
| }, | |
| "execution_count": 156, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "configure_logging(console_level=Logging.Error, set_global=true)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# <span style=\"color: green\">using</span> Joulia" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "using Joulia\n", | |
| "\n", | |
| "using DataFrames, CSV\n", | |
| "using Gurobi\n", | |
| "\n", | |
| "# data load for 2015 sample data\n", | |
| "# see http://doi.org/10.5281/zenodo.1044463\n", | |
| "pp_df = CSV.read(\"data_2015/power_plants.csv\")\n", | |
| "prices_df = CSV.read(\"data_2015/prices.csv\")\n", | |
| "\n", | |
| "# [...]\n", | |
| "\n", | |
| "# generation of Joulia data types\n", | |
| "pp = PowerPlants(pp_df, avail=avail_con_df, prices=prices_df)\n", | |
| "storages = Storages(storages_df)\n", | |
| "lines = Lines(lines_df)\n", | |
| "nodes = Nodes(nodes_df, load_df, exchange_df)\n", | |
| "res = RenewableEnergySource(res_df, avail)\n", | |
| "\n", | |
| "# generation of the Joulia model\n", | |
| "elmod = JouliaModel(pp, res, storages, nodes, lines)\n", | |
| "\n", | |
| "# sclicing the data in weeks with the first full week starting at hour 49\n", | |
| "slices = week_slices(49)\n", | |
| "\n", | |
| "# running the Joulia model for week 30 using the Gurobi solver\n", | |
| "results = run_model(elmod, slices[30], solver=GurobiSolver())\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# src/model.jl\n", | |
| "\n", | |
| "function create_model(pp::PowerPlants,\n", | |
| " res::RenewableEnergySource,\n", | |
| " nodes::Nodes)\n", | |
| "\n", | |
| " N = nodes.id\n", | |
| " P = pp.id\n", | |
| " RES = res.id\n", | |
| "\n", | |
| " mc = pp.mc\n", | |
| " load = nodes.load\n", | |
| " input_gen = pp.capacity\n", | |
| " input_res = res.infeed\n", | |
| "\n", | |
| " function build_model(T::Array{Int, 1})\n", | |
| "\n", | |
| " m = Model()\n", | |
| " @variables m begin\n", | |
| " G[P,T] >= 0\n", | |
| " G_RES[RES,T] >= 0\n", | |
| " end\n", | |
| "\n", | |
| " println(\"Set model objective\")\n", | |
| " @objective(m, Min, sum(mc[p][t] * G[p,t] for p in P, t in T))\n", | |
| "\n", | |
| " println(\"Building constraints:\")\n", | |
| "\n", | |
| " prog = Progress(length(T), 0.2, \"MarketClearing... \", 50)\n", | |
| "\n", | |
| " @constraintref MarketClearing[T]\n", | |
| " for t=T\n", | |
| " MarketClearing[t] = @constraint(m,\n", | |
| "\n", | |
| " sum(G[p,t] for p in P)\n", | |
| " + sum(G_RES[r,t] for r in RES)\n", | |
| " ==\n", | |
| " sum(load[n][t] for n in N))\n", | |
| " \n", | |
| " next!(prog)\n", | |
| " end\n", | |
| " JuMP.registercon(m, :MarketClearing, MarketClearing)\n", | |
| "\n", | |
| " @constraintref GenerationRestriction[P,T]\n", | |
| " prog = Progress(length(P)*length(T), 0.2, \"Max generation... \", 50)\n", | |
| "\n", | |
| " for p=P, t=T\n", | |
| " GenerationRestriction[p,t] = @constraint(m,\n", | |
| "\n", | |
| " G[p,t] <= input_gen[p][t] );\n", | |
| "\n", | |
| " next!(prog)\n", | |
| " end\n", | |
| "\n", | |
| " @constraintref ResRestriction[RES,T]\n", | |
| " prog = Progress(length(RES)*length(T), 0.2, \"Renewable infeed... \", 50)\n", | |
| "\n", | |
| " for r=RES, t=T\n", | |
| " ResRestriction[r,t] = @constraint(m,\n", | |
| "\n", | |
| " G_RES[r,t] <= input_res[r][t] );\n", | |
| "\n", | |
| " next!(prog)\n", | |
| "\n", | |
| " end\n", | |
| "\n", | |
| " return m\n", | |
| " end # end of build model\n", | |
| "\n", | |
| " return build_model\n", | |
| "end # end function `create_model`\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| " println(\"Building constraints:\")\n", | |
| "\n", | |
| " prog = Progress(length(T), 0.2, \"MarketClearing... \", 50)\n", | |
| "\n", | |
| " @constraintref MarketClearing[T]\n", | |
| " for t=T\n", | |
| " MarketClearing[t] = @constraint(m,\n", | |
| "\n", | |
| " sum(G[p,t] for p in P)\n", | |
| " + sum(G_RES[r,t] for r in RES)\n", | |
| " ==\n", | |
| " sum(load[n][t] for n in N))\n", | |
| " \n", | |
| " next!(prog)\n", | |
| " end\n", | |
| " JuMP.registercon(m, :MarketClearing, MarketClearing)\n", | |
| "\n", | |
| " @constraintref GenerationRestriction[P,T]\n", | |
| " prog = Progress(length(P)*length(T), 0.2, \"Max generation... \", 50)\n", | |
| "\n", | |
| " for p=P, t=T\n", | |
| " GenerationRestriction[p,t] = @constraint(m,\n", | |
| "\n", | |
| " G[p,t] <= input_gen[p][t] );\n", | |
| "\n", | |
| " next!(prog)\n", | |
| " end\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# <span style=\"color: green\">using</span> PowerModels" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "run_opf(\"case3.m\", DCPPowerModel, JuMP.with_optimizer(Gurobi.Optimizer))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "source": [ | |
| "is shorthand for" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "network_data = PowerModels.parse_file(\"case3.m\")\n", | |
| "pm = build_generic_model(network_data, ACPPowerModel, PowerModels.post_opf)\n", | |
| "solve_generic_model(pm, JuMP.with_optimizer(Gurobi.Optimizer))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "source": [ | |
| "- `network_data` holds the system parameters as stacked dictionaries (`bus`, `gen`, `branch`, ... as keys)\n", | |
| "- `ACPPowerModel` = `GenericPowerModel{ACPPowerForm}` selects the *formulation* of the power flow to use\n", | |
| "- The `post_opf` function defines the common *recipe* for building the model" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# src/prob/opf.jl\n", | |
| "\n", | |
| "function post_opf(pm::GenericPowerModel)\n", | |
| " variable_voltage(pm)\n", | |
| " variable_generation(pm)\n", | |
| " variable_branch_flow(pm)\n", | |
| " variable_dcline_flow(pm)\n", | |
| "\n", | |
| " objective_min_fuel_cost(pm)\n", | |
| "\n", | |
| " constraint_voltage(pm)\n", | |
| "\n", | |
| " for i in ids(pm, :ref_buses)\n", | |
| " constraint_theta_ref(pm, i)\n", | |
| " end\n", | |
| "\n", | |
| " for i in ids(pm, :bus)\n", | |
| " constraint_kcl_shunt(pm, i)\n", | |
| " end\n", | |
| "\n", | |
| " for i in ids(pm, :branch)\n", | |
| " constraint_ohms_yt_from(pm, i)\n", | |
| " constraint_ohms_yt_to(pm, i)\n", | |
| "\n", | |
| " constraint_voltage_angle_difference(pm, i)\n", | |
| "\n", | |
| " constraint_thermal_limit_from(pm, i)\n", | |
| " constraint_thermal_limit_to(pm, i)\n", | |
| " end\n", | |
| "\n", | |
| " for i in ids(pm, :dcline)\n", | |
| " constraint_dcline(pm, i)\n", | |
| " end\n", | |
| "end\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# src/prob/opf.jl\n", | |
| "\n", | |
| "function post_opf(pm::GenericPowerModel)\n", | |
| " # [...]\n", | |
| " variable_generation(pm)\n", | |
| " \n", | |
| " # [...]\n", | |
| "\n", | |
| " for i in ids(pm, :bus)\n", | |
| " constraint_kcl_shunt(pm, i)\n", | |
| " end\n", | |
| "\n", | |
| " # [...]\n", | |
| "end" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# src/core/variable.jl\n", | |
| "\n", | |
| "function variable_generation(pm::GenericPowerModel; nw::Int=pm.cnw, cnd::Int=pm.ccnd)\n", | |
| " var(pm, nw, cnd)[:pg] = JuMP.@variable(pm.model,\n", | |
| " [i in ids(pm, nw, :gen)],\n", | |
| " lower_bound = ref(pm, nw, :gen, i, \"pmin\", cnd),\n", | |
| " upper_bound = ref(pm, nw, :gen, i, \"pmax\", cnd)\n", | |
| " )\n", | |
| " # and the same for the reactive part\n", | |
| "end\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# src/form/dcp.jl\n", | |
| "\n", | |
| "function constraint_kcl_shunt(pm::AbstractPowerModel{T}, i::Int, nw::Int, cnd::Int) where T <: AbstractDCPForm\n", | |
| " bus_arcs = ref(pm, nw, :bus_arcs, i)\n", | |
| " bus_gens = ref(pm, nw, :bus_gens, i)\n", | |
| " bus_loads = ref(pm, nw, :bus_loads, i)\n", | |
| "\n", | |
| " bus_pd = Dict(k => ref(pm, nw, :load, k, \"pd\", cnd) for k in bus_loads)\n", | |
| "\n", | |
| " pg = var(pm, nw, cnd, :pg)\n", | |
| " p = var(pm, nw, cnd, :p)\n", | |
| "\n", | |
| " con(pm, nw, cnd, :kcl_p)[i] = JuMP.@constraint(pm.model,\n", | |
| " sum(p[a] for a in bus_arcs) ==\n", | |
| " sum(pg[g] for g in bus_gens) - sum(pd for pd in values(bus_pd)))\n", | |
| " # omit reactive constraint\n", | |
| "end" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# src/form/acp.jl\n", | |
| "\n", | |
| "function constraint_kcl_shunt(pm::GenericPowerModel{T}, i::Int, nw::Int, cnd::Int) where T <: AbstractACPForm\n", | |
| " [...]\n", | |
| "\n", | |
| " con(pm, n, c, :kcl_p)[i] = JuMP.@constraint(pm.model, sum(p[a] for a in bus_arcs) + sum(p_dc[a_dc] for a_dc in bus_arcs_dc) == sum(pg[g] for g in bus_gens) - sum(pd for pd in values(bus_pd)) - sum(gs for gs in values(bus_gs))*vm^2)\n", | |
| " con(pm, n, c, :kcl_q)[i] = JuMP.@constraint(pm.model, sum(q[a] for a in bus_arcs) + sum(q_dc[a_dc] for a_dc in bus_arcs_dc) == sum(qg[g] for g in bus_gens) - sum(qd for qd in values(bus_qd)) + sum(bs for bs in values(bus_bs))*vm^2)\n", | |
| "end" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# <span style=\"color: green\">using</span> PowerSystems" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 157, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "ps_dict = PowerSystems.parsestandardfiles(\"case5_re.m\");\n", | |
| "# ps_dict = PowerSystems.read_csv_data(\"<folder with gen.csv branch.csv bus.csv, .. load.csv>\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 158, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "System:\n", | |
| " buses: Bus[Bus(name=\"bus1\"), Bus(name=\"bus2\"), Bus(name=\"bus3\"), Bus(name=\"bus4\"), Bus(name=\"bus5\")]\n", | |
| " generators: \n", | |
| " GenClasses(T:5,R:2,H:0):\n", | |
| " thermal: ThermalDispatch[ThermalDispatch(name=\"Solitude\"), ThermalDispatch(name=\"Park City\"), ThermalDispatch(name=\"Alta\"), ThermalDispatch(name=\"Brighton\"), ThermalDispatch(name=\"Sundance\")]\n", | |
| " renewable: RenewableCurtailment[RenewableCurtailment(name=\"SolarBusC\"), RenewableCurtailment(name=\"WindBusA\")]\n", | |
| " hydro: nothing\n", | |
| " (end generators)\n", | |
| " loads: ElectricLoad[PowerLoad(name=\"bus2\"), PowerLoad(name=\"bus3\"), PowerLoad(name=\"bus4\")]\n", | |
| " branches: Branch[Line(name=\"1\"), Line(name=\"2\"), Line(name=\"3\"), Line(name=\"4\"), PhaseShiftingTransformer(name=\"5\"), PhaseShiftingTransformer(name=\"6\"), Line(name=\"7\")]\n", | |
| " storage: Storage[]\n", | |
| " basepower: 100.0\n", | |
| " time_periods: 25" | |
| ] | |
| }, | |
| "execution_count": 158, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "sys = PowerSystems.System(ps_dict)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 130, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Line:\n", | |
| " name: 1\n", | |
| " available: true\n", | |
| " connectionpoints: (from = Bus(name=\"bus1\"), to = Bus(name=\"bus2\"))\n", | |
| " r: 0.00281\n", | |
| " x: 0.0281\n", | |
| " b: (from = 0.00356, to = 0.00356)\n", | |
| " rate: 2.0\n", | |
| " anglelimits: (min = -0.5235987755982988, max = 0.5235987755982988)" | |
| ] | |
| }, | |
| "execution_count": 130, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "sys.branches[1]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 157, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "ps_dict = PowerSystems.parsestandardfiles(\"case5_re.m\");\n", | |
| "# ps_dict = PowerSystems.read_csv_data(\"<folder with gen.csv branch.csv bus.csv, .. load.csv>\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 158, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "System:\n", | |
| " buses: Bus[Bus(name=\"bus1\"), Bus(name=\"bus2\"), Bus(name=\"bus3\"), Bus(name=\"bus4\"), Bus(name=\"bus5\")]\n", | |
| " generators: \n", | |
| " GenClasses(T:5,R:2,H:0):\n", | |
| " thermal: ThermalDispatch[ThermalDispatch(name=\"Solitude\"), ThermalDispatch(name=\"Park City\"), ThermalDispatch(name=\"Alta\"), ThermalDispatch(name=\"Brighton\"), ThermalDispatch(name=\"Sundance\")]\n", | |
| " renewable: RenewableCurtailment[RenewableCurtailment(name=\"SolarBusC\"), RenewableCurtailment(name=\"WindBusA\")]\n", | |
| " hydro: nothing\n", | |
| " (end generators)\n", | |
| " loads: ElectricLoad[PowerLoad(name=\"bus2\"), PowerLoad(name=\"bus3\"), PowerLoad(name=\"bus4\")]\n", | |
| " branches: Branch[Line(name=\"1\"), Line(name=\"2\"), Line(name=\"3\"), Line(name=\"4\"), PhaseShiftingTransformer(name=\"5\"), PhaseShiftingTransformer(name=\"6\"), Line(name=\"7\")]\n", | |
| " storage: Storage[]\n", | |
| " basepower: 100.0\n", | |
| " time_periods: 25" | |
| ] | |
| }, | |
| "execution_count": 158, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "sys = PowerSystems.System(ps_dict)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 119, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "ThermalDispatch:\n", | |
| " name: Solitude\n", | |
| " available: true\n", | |
| " bus: Bus(name=\"bus3\")\n", | |
| " tech: TechThermal\n", | |
| " econ: EconThermal" | |
| ] | |
| }, | |
| "execution_count": 119, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "sys.generators.thermal[1]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 120, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "TechThermal:\n", | |
| " activepower: 3.24498\n", | |
| " activepowerlimits: (min = 0.0, max = 5.2)\n", | |
| " reactivepower: 3.9\n", | |
| " reactivepowerlimits: (min = -3.9, max = 3.9)\n", | |
| " ramplimits: (up = 0.0, down = 0.0)\n", | |
| " timelimits: nothing" | |
| ] | |
| }, | |
| "execution_count": 120, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "sys.generators.thermal[1].tech" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 121, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "EconThermal:\n", | |
| " capacity: 5.2\n", | |
| " variablecost: getfield(PowerSystems, Symbol(\"##441#451\")){Dict{String,Any}}(Dict{String,Any}(\"apf\"=>0.0,\"qc1max\"=>0.0,\"pg\"=>3.24498,\"model\"=>2,\"shutdown\"=>0.0,\"startup\"=>0.0,\"qc2max\"=>0.0,\"ramp_agc\"=>0.0,\"name\"=>\"Solitude\",\"qg\"=>3.9…))\n", | |
| " fixedcost: 0.0\n", | |
| " startupcost: 0.0\n", | |
| " shutdncost: 0.0\n", | |
| " annualcapacityfactor: nothing" | |
| ] | |
| }, | |
| "execution_count": 121, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "sys.generators.thermal[1].econ" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 128, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "6×1 TimeArray{Float64,1,DateTime,Array{Float64,1}} 2019-05-23T00:00:00 to 2019-05-23T05:00:00\n", | |
| "│ │ A │\n", | |
| "├─────────────────────┼───────┤\n", | |
| "│ 2019-05-23T00:00:00 │ 1.0 │\n", | |
| "│ 2019-05-23T01:00:00 │ 1.0 │\n", | |
| "│ 2019-05-23T02:00:00 │ 1.0 │\n", | |
| "│ 2019-05-23T03:00:00 │ 1.0 │\n", | |
| "│ 2019-05-23T04:00:00 │ 1.0 │\n", | |
| "│ 2019-05-23T05:00:00 │ 1.0 │" | |
| ] | |
| }, | |
| "execution_count": 128, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "head(sys.generators.renewable[1].scalingfactor)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 133, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "Bus:\n", | |
| " number: 1\n", | |
| " name: bus1\n", | |
| " bustype: PQ\n", | |
| " angle: 0.0\n", | |
| " voltage: 1.0\n", | |
| " voltagelimits: (min = 0.9, max = 1.1)\n", | |
| " basevoltage: 230.0" | |
| ] | |
| }, | |
| "execution_count": 133, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# <span style=\"color: green\">using</span> PowerSystems, PowerSimulations" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 174, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "ps_dict = PowerSystems.parsestandardfiles(\"case5_re.m\");\n", | |
| "sys = PowerSystems.System(ps_dict);" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 170, | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Academic license - for non-commercial use only\n", | |
| "Academic license - for non-commercial use only\n", | |
| "Warning, invalid warm-start basis discarded\n", | |
| "Warning, invalid warm-start basis discarded\n", | |
| "Optimize a model with 850 rows, 600 columns and 2025 nonzeros\n", | |
| "Coefficient statistics:\n", | |
| " Matrix range [1e+00, 2e+02]\n", | |
| " Objective range [1e+03, 4e+03]\n", | |
| " Bounds range [4e-01, 1e+01]\n", | |
| " RHS range [5e-01, 4e+00]\n", | |
| "Presolve removed 725 rows and 325 columns\n", | |
| "Presolve time: 0.00s\n", | |
| "Presolved: 125 rows, 275 columns, 550 nonzeros\n", | |
| "\n", | |
| "Iteration Objective Primal Inf. Dual Inf. Time\n", | |
| " 0 0.0000000e+00 1.427467e+02 0.000000e+00 0s\n", | |
| " 191 4.3503066e+05 0.000000e+00 0.000000e+00 0s\n", | |
| "\n", | |
| "Solved in 191 iterations and 0.00 seconds\n", | |
| "Optimal objective 4.350306626e+05\n" | |
| ] | |
| }, | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "PowerSimulations.OpertationModelResults(Dict(:Pre=>25×2 DataFrames.DataFrame\n", | |
| "│ Row │ SolarBusC │ WindBusA │\n", | |
| "│ │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │\n", | |
| "├─────┼───────────┼──────────┤\n", | |
| "│ 1 │ 0.6 │ 0.6 │\n", | |
| "│ 2 │ 0.6 │ 0.6 │\n", | |
| "│ 3 │ 0.6 │ 0.6 │\n", | |
| "│ 4 │ 0.6 │ 0.6 │\n", | |
| "│ 5 │ 0.6 │ 0.6 │\n", | |
| "│ 6 │ 0.6 │ 0.6 │\n", | |
| "│ 7 │ 0.6 │ 0.6 │\n", | |
| "│ 8 │ 0.6 │ 0.6 │\n", | |
| "│ 9 │ 0.6 │ 0.6 │\n", | |
| "│ 10 │ 0.6 │ 0.6 │\n", | |
| "⋮\n", | |
| "│ 15 │ 0.6 │ 0.6 │\n", | |
| "│ 16 │ 0.6 │ 0.6 │\n", | |
| "│ 17 │ 0.6 │ 0.6 │\n", | |
| "│ 18 │ 0.6 │ 0.6 │\n", | |
| "│ 19 │ 0.6 │ 0.6 │\n", | |
| "│ 20 │ 0.6 │ 0.6 │\n", | |
| "│ 21 │ 0.6 │ 0.6 │\n", | |
| "│ 22 │ 0.6 │ 0.6 │\n", | |
| "│ 23 │ 0.6 │ 0.6 │\n", | |
| "│ 24 │ 0.6 │ 0.6 │\n", | |
| "│ 25 │ 0.6 │ 0.6 │,:Pth=>25×5 DataFrames.DataFrame\n", | |
| "│ Row │ Solitude │ Park City │ Alta │ Brighton │ Sundance │\n", | |
| "│ │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │ \u001b[90mFloat64\u001b[39m │\n", | |
| "├─────┼──────────┼───────────┼─────────┼──────────┼──────────┤\n", | |
| "│ 1 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 2 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 3 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 4 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 5 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 6 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 7 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 8 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 9 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 10 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "⋮\n", | |
| "│ 15 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 16 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 17 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 18 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 19 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 20 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 21 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 22 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 23 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 24 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │\n", | |
| "│ 25 │ 3.8 │ 1.7 │ 0.4 │ 2.9 │ 0.0 │), Dict(:ED=>4.35031e5), Dict{Symbol,Any}(:dual_status=>FEASIBLE_POINT,:primal_status=>FEASIBLE_POINT,:termination_status=>OPTIMAL))" | |
| ] | |
| }, | |
| "execution_count": 170, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "econdispatch = PowerSimulations.EconomicDispatch(sys, PowerModels.DCPlosslessForm, optimizer=with_optimizer(Gurobi.Optimizer))\n", | |
| "solve_op_model!(econdispatch)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "devices = Dict{Symbol, PSI.DeviceModel}(:ThermalGenerators => PSI.DeviceModel(PSY.ThermalGen, PSI.ThermalDispatch),\n", | |
| " :RenewableGenerators => PSI.DeviceModel(PSY.RenewableGen, PSI.RenewableFullDispatch),\n", | |
| " :Loads => PSI.DeviceModel(PSY.PowerLoad, PSI.StaticPowerLoad))\n", | |
| "branches = Dict{Symbol, PSI.DeviceModel}(:Lines => PSI.DeviceModel(PSY.Branch, PSI.SeriesLine))\n", | |
| "\n", | |
| "# [...]\n", | |
| "\n", | |
| "econdispatch = PowerOperationModel(EconomicDispatch,\n", | |
| " PowerModels.DCPlosslessForm,\n", | |
| " devices,\n", | |
| " branches,\n", | |
| " services,\n", | |
| " system,\n", | |
| " optimizer = with_optimizer(Gurobi.Optimizer))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 193, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "(:JuMPmodel, :variables, :constraints, :cost_function, :expressions, :parameters, :initial_conditions, :pm_model)" | |
| ] | |
| }, | |
| "execution_count": 193, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "fieldnames(typeof(econdispatch.canonical_model))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# src/devices/device_constructors/thermalgeneration_constructor.jl\n", | |
| "\n", | |
| "function construct_device!(ps_m::CanonicalModel,\n", | |
| " device::Type{T},\n", | |
| " device_formulation::Type{D},\n", | |
| " system_formulation::Type{S},\n", | |
| " sys::PSY.System,\n", | |
| " time_range::UnitRange{Int64};\n", | |
| " kwargs...) where {T<: PSY.ThermalGen,\n", | |
| " D <: AbstractThermalDispatchForm,\n", | |
| " S <: PM.AbstractActivePowerFormulation}\n", | |
| "\n", | |
| " #Variables\n", | |
| " activepower_variables(ps_m, sys.generators.thermal, time_range);\n", | |
| "\n", | |
| " #Constraints\n", | |
| " activepower_constraints(ps_m, sys.generators.thermal, device_formulation, system_formulation, time_range)\n", | |
| "\n", | |
| " #Cost Function\n", | |
| " cost_function(ps_m, sys.generators.thermal, device_formulation, system_formulation)\n", | |
| "\n", | |
| " return\n", | |
| "\n", | |
| "end\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# in src/devices/device_models/thermal_generation.jl\n", | |
| "\n", | |
| "function activepower_constraints(ps_m::CanonicalModel,\n", | |
| " devices::Array{T,1},\n", | |
| " device_formulation::Type{D},\n", | |
| " system_formulation::Type{S},\n", | |
| " time_range::UnitRange{Int64}) where {T <: PSY.ThermalGen,\n", | |
| " D <: AbstractThermalDispatchForm,\n", | |
| " S <: PM.AbstractPowerFormulation}\n", | |
| "\n", | |
| " range_data = [(g.name, g.tech.activepowerlimits) for g in devices]\n", | |
| " \n", | |
| " device_range(ps_m, range_data, time_range, :thermal_active_range, :Pth)\n", | |
| "end" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# in src/devices/device_models/common/range_constraint.jl -- simplified\n", | |
| "\n", | |
| "function device_range(ps_m::CanonicalModel,\n", | |
| " range_data::Vector{NamedMinMax},\n", | |
| " time_range::UnitRange{Int64},\n", | |
| " cons_name::Symbol,\n", | |
| " var_name::Symbol)\n", | |
| "\n", | |
| " ps_m.constraints[cons_name] = JuMP.@constraint(ps_m.JuMPmodel, [r=range_data,t=time_range], r.min <= ps_m.variables[var_name][r, t] <= r.max)\n", | |
| "\n", | |
| "end" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# <span style=\"color: green\">using</span> EnergyModels" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "model = EnergyModel(\"elec_s_45_lv1.25_3H.nc\", solver=GurobiSolver())\n", | |
| "build(model);\n", | |
| "solve(model)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "source": [ | |
| "### Data-Model\n", | |
| "Everything is fetched on demand from NetCDF" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "get(model, :onwind, :p_nom) # -> AxisArray of data in netcdf file variable onwind::p_nom" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "source": [ | |
| "### Component models" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "```\n", | |
| "Component\n", | |
| "├──OnePort\n", | |
| "│ ├──Generator\n", | |
| "│ ├──StorageUnit\n", | |
| "│ └──Store\n", | |
| "├──PassiveBranch\n", | |
| "│ ├──Line\n", | |
| "│ └──Transformer\n", | |
| "└──ActiveBranch\n", | |
| " └──Link\n", | |
| "```" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "# src/components/oneport.jl\n", | |
| "\n", | |
| "cost(c::OnePort) = sum(c[:marginal_cost] .* c[:p]) + sum(c[:capital_cost] .* (c[:p_nom] - getparam(c, :p_nom)))\n", | |
| "function nodalbalance(c::OnePort) \n", | |
| " p = c[:p]\n", | |
| " c[:bus] => (o,t)->p[o,t]\n", | |
| "end\n", | |
| "\n", | |
| "## Generator\n", | |
| "function build(c::Generator)\n", | |
| " T = axis(c, :snapshots)\n", | |
| " G = axis(c)\n", | |
| "\n", | |
| " if isvar(c, :p_nom)\n", | |
| " @emvariable c c[:p_nom_min][g] <= p_nom[g=G] <= c[:p_nom_max][g]\n", | |
| " end\n", | |
| "\n", | |
| " @emvariable c c[:p_min_pu][g,t] * c[:p_nom][g] <= p[g=G,t=T] <= c[:p_max_pu][g,t] * c[:p_nom][g]\n", | |
| "end\n", | |
| "\n", | |
| "addelement(Generator, :generators, (:G, :T=>:snapshots), joinpath(@__DIR__, \"generators.csv\"))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "```\n", | |
| "# src/components/generators.csv\n", | |
| "```\n", | |
| "\n", | |
| "```csv\n", | |
| "attribute,quantitytype,dimensions,default,dtype\n", | |
| "p_nom,VarParam,G,0,float\n", | |
| "p_max_pu,Param,\"G,T\",1,float\n", | |
| "p_min_pu,Param,\"G,T\",0,float\n", | |
| "p_nom_min,Param,G,0,float\n", | |
| "p_nom_max,Param,G,Inf,float\n", | |
| "efficiency,Param,G,1,float\n", | |
| "carrier,Param,,,string\n", | |
| "marginal_cost,Param,\"G,T\",0.,float\n", | |
| "capital_cost,Param,G,0.,float\n", | |
| "bus,Param,G,,string\n", | |
| "p,Variable,\"G,T\",0,float\n", | |
| "```" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Julia 1.1.1", | |
| "language": "julia", | |
| "name": "julia-1.1" | |
| }, | |
| "language_info": { | |
| "file_extension": ".jl", | |
| "mimetype": "application/julia", | |
| "name": "julia", | |
| "version": "1.1.1" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 2 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment