Skip to content

Instantly share code, notes, and snippets.

@coroa
Created May 23, 2019 13:08
Show Gist options
  • Save coroa/4470bb2461c7e73490bcac7abc86545e to your computer and use it in GitHub Desktop.
Save coroa/4470bb2461c7e73490bcac7abc86545e to your computer and use it in GitHub Desktop.
Energy System Optimization With Julia Dive Into The Packages
Display the source blob
Display the rendered blob
Raw
{
"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