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 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 JuMP@v0.18\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