The core design of the Scalable Integrated Infrastructure Planning (SIIP) simulation platform is that models are comprised of two major parts:
PowerSystems.jl Takes advantage of Julia's dynamic types and functional dispatch to define data schemas for Power System's data in a structured yet extensible way.
PowerSimulations.jl We leverage the types/structs defined in PowerSystems.jl
to utilize multiple dispatch in the construction of device models within operational models for power systems analysis.
PowerSimulations.jl
can be described as follows: The contributions are:
] activate nb-environs/SMD_env
] instantiate
] up
using Logging
# Testing Topological components of the schema
gl = global_logger()
global_logger(ConsoleLogger(gl.stream, Logging.Error));
tsteps = 2
include("SIIP-Design-Demo/demo-preload.jl");
For this presentation, we will use the 5-bus test system for examples.
sys5b_th
sys5b_th.generators
sys5b_th.buses[1]
sys5b_th.branches[1]
Optimization problems are created by applying model formulations to the device data structure.
PowerSimulations.jl
builds a device formulation by calling functions with common constraint structures, enabling code re-usability and consistency across device formulations.
The equations that comprise each device formulation are dispatched based on the specification of the device type, device formulation and transmission formulation.
display(TypeTree(PSI.AbstractRenewableFormulation,init_expand = 2,scopesep="\n"))
function activepower_constraints(ps_m::CanonicalModel,
devices::Array{T,1},
device_formulation::Type{D},
system_formulation::Type{S},
time_range::UnitRange{Int64})
where {T <: PSY.ThermalGen,
D <: AbstractThermalFormulation,
S <: PM.AbstractPowerFormulation}
range_data = [(g.name, g.tech.activepowerlimits) for g in devices]
device_semicontinuousrange(ps_m, range_data, time_range,
:thermal_active_range, :Pth, :on_th)
return
end
ThermalDispatch
is used, the active power variables constraints are created as a range without the binary component.
function activepower_constraints(ps_m::CanonicalModel,
devices::Array{T,1},
device_formulation::Type{D},
system_formulation::Type{S},
time_range::UnitRange{Int64})
where {T <: PSY.ThermalGen,
D <: AbstractThermalDispatchForm,
S <: PM.AbstractPowerFormulation}
range_data = [(g.name, g.tech.activepowerlimits) for g in devices]
device_range(ps_m, range_data, time_range,
:thermal_active_range, :Pth)
return
end
function device_range(ps_m::CanonicalModel,
range_data::Array{Tuple{String,NamedTuple{(:min, :max),Tuple{Float64,Float64}}},1},
time_range::UnitRange{Int64},
cons_name::Symbol,
var_name::Symbol)
ps_m.constraints[cons_name] =
JuMP.Containers.DenseAxisArray{JuMP.ConstraintRef}
(undef, [r[1] for r in range_data], time_range)
for t in time_range, r in range_data
ps_m.constraints[cons_name][r[1], t] =
JuMP.@constraint(ps_m.JuMPmodel, r[2].min <= ps_m.variables[var_name][r[1], t] <= r[2].max)
end
return
end
ED = PSI.EconomicDispatch(sys5b_th, PSI.CopperPlatePowerModel; optimizer = GLPK_optimizer);
UC = PSI.UnitCommitment(sys5b_th, PSI.CopperPlatePowerModel; optimizer = GLPK_optimizer);
ED.devices[:ThermalGenerators]
ED.canonical_model.constraints[:thermal_active_range]["Alta",1]
keys(ED.canonical_model.constraints)
In a Unit Commitment (UC) model the thermal generators output limits are described as a semi-continuous range.
UC.devices[:ThermalGenerators]
display(UC.canonical_model.constraints[:thermal_active_range_ub]["Alta",1])
display(UC.canonical_model.constraints[:thermal_active_range_lb]["Alta",1])
keys(UC.canonical_model.constraints)
A common requirement is the capability to define different device models for a particular problem in order to answer questions about the system's operation under different conditions.
For instance, how does the system dispatch change when the units have little flexibility?
ED.devices[:ThermalGenerators] = PSI.DeviceModel(PSY.ThermalGen, PSI.ThermalRampLimited)
PSI.build_op_model!(ED);
ED.canonical_model.constraints[:ramp_thermal_up][:,2]
PowerSimulations.jl
can specify the network formulation independently in the model. PowerSystems.jl
(NREL) and PowerSimulations.jl
(NREL) with PowerModels.jl
(LANL) to enable nonlinear AC power flow representations and relaxations.EDPF = PSI.EconomicDispatch(sys5b_th, PSI.StandardPTDFForm ; optimizer = GLPK_optimizer, PTDF = PTDF);
display(ED.transmission)
ED.canonical_model.constraints[:CopperPlateBalance][1]
display(EDPF.transmission)
display(EDPF.canonical_model.constraints[:network_flow]["1",1])
display(EDPF.canonical_model.constraints[:nodal_balance]["nodeA",1])
ED_AC= PSI.EconomicDispatch(sys5b_th, PM.StandardACPForm ; optimizer = ipopt_optimizer);
This capability is supported by the use of JuMP.DenseAxisArrays
to keep track of the affine expressions (AffnExpr
) that make up for the total injections at the nodes at each time-step.
ED_AC.canonical_model.expressions[:var_active]
ED_AC.canonical_model.expressions[:var_reactive]
PowerSimulations.jl
includes a specification for services based on the formulation and the collection of devices that participate in the provision of the service.The design of PowerSimulations.jl
separates all the modeling by device, network, and service, and wraps it all into single struct.
display(ED.devices)
display(ED.branches)
display(ED.transmission)
display(ED.services)
EDPF.canonical_model.expressions[:var_active]
ED.canonical_model.constraints
res = solve_op_model!(UC, optimizer = GLPK_optimizer);
res.optimizer_log
StructJuMP.jl
+ PowerSimulations.jl
for Expansion Problem Definition¶ParameterJuMP
or use MOI
constraint modification?Systems
and Simulations
packages for water and gas.