Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,17 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
[weakdeps]
PowerFlows = "94fada2c-0ca5-4b90-a1fb-4bc5b59ccfc7"

[sources]
InfrastructureSystems = {rev = "IS4", url = "https://github.com/Sienna-Platform/InfrastructureSystems.jl"}
PowerSystems = {rev = "psy6", url = "https://github.com/Sienna-Platform/PowerSystems.jl"}
InfrastructureOptimizationModels = {rev = "ac/hvdc-vsc", url = "https://github.com/Sienna-Platform/InfrastructureOptimizationModels.jl"}

[extensions]
PowerFlowsExt = "PowerFlows"

[sources]
InfrastructureSystems = {url = "https://github.com/NREL-Sienna/InfrastructureSystems.jl", rev = "IS4"}
PowerSystems = {url = "https://github.com/NREL-Sienna/PowerSystems.jl", rev = "psy6"}
InfrastructureOptimizationModels = {url = "https://github.com/NREL-Sienna/InfrastructureOptimizationModels.jl", rev = "lk/pom-test-fixes"}

[compat]
Dates = "1"
DocStringExtensions = "~0.8, ~0.9"
InfrastructureOptimizationModels = "0.1"
InfrastructureSystems = "3"
InteractiveUtils = "1.11.0"
JuMP = "^1.28"
Expand Down
28 changes: 12 additions & 16 deletions src/PowerOperationsModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ include("common_models/add_to_expression.jl")
include("common_models/add_parameters.jl")
include("common_models/make_system_expressions.jl")
include("common_models/reserve_range_constraints.jl")
include("common_models/quadratic_converter_loss.jl")
include("common_models/network_conditional.jl")

# Market bid cost plumbing (PSY orchestration moved out of IOM). Must be included
# before device-specific files that reference MBC_TYPES / IEC_TYPES.
Expand Down Expand Up @@ -505,24 +507,14 @@ export PostContingencyActivePowerReserveDeploymentVariable
# HVDC Variables
export DCVoltage
export DCLineCurrent
export ConverterPowerDirection
export ConverterCurrent
export SquaredConverterCurrent
export InterpolationSquaredCurrentVariable
export InterpolationBinarySquaredCurrentVariable
export ConverterPositiveCurrent
export ConverterNegativeCurrent
export SquaredDCVoltage
export InterpolationSquaredVoltageVariable
export InterpolationBinarySquaredVoltageVariable
export AuxBilinearConverterVariable
export AuxBilinearSquaredConverterVariable
export InterpolationSquaredBilinearVariable
export InterpolationBinarySquaredBilinearVariable
export CurrentAbsoluteValueVariable
export HVDCFlowDirectionVariable
export HVDCLosses
export ConverterDCPower
export ConverterCurrentDirection
export HVDCFromDCVoltage
export HVDCToDCVoltage
export HVDCReactivePowerFromVariable
export HVDCReactivePowerToVariable

Comment thread
acostarelli marked this conversation as resolved.
# Load Variables
export ShiftUpActivePowerVariable
Expand Down Expand Up @@ -770,11 +762,15 @@ export HVDCTwoTerminalLossless
export HVDCTwoTerminalDispatch
export HVDCTwoTerminalPiecewiseLoss
export HVDCTwoTerminalLCC
export HVDCTwoTerminalVSCNLP
export HVDCTwoTerminalVSCLP

# Converter Formulations
export LosslessConverter
export LinearLossConverter
export QuadraticLossConverter
export AbstractQuadraticLossConverter
export QuadraticLossConverterMILP
export QuadraticLossConverterNLP

# DC Line Formulations
export DCLosslessLine
Expand Down
146 changes: 146 additions & 0 deletions src/ac_transmission_models/branch_constructor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1670,3 +1670,149 @@ function construct_device!(
add_feedforward_constraints!(container, device_model, devices)
return
end

############################################################################
####################### Two-Terminal VSC HVDC Construct ####################
############################################################################

# Quadratic / bilinear approximation traits — same scheme used by the MT
# converter formulations.
_quad_config(::Type{HVDCTwoTerminalVSCNLP}) = IOM.NoQuadApproxConfig()
_quad_config(::Type{HVDCTwoTerminalVSCLP}) =
IOM.SolverSOS2QuadConfig(DEFAULT_INTERPOLATION_LENGTH)
_bilinear_config(::Type{HVDCTwoTerminalVSCNLP}) = IOM.NoBilinearApproxConfig()
_bilinear_config(::Type{HVDCTwoTerminalVSCLP}) =
IOM.Bin2Config(IOM.SolverSOS2QuadConfig(DEFAULT_INTERPOLATION_LENGTH))

function construct_device!(
container::OptimizationContainer,
sys::PSY.System,
::ArgumentConstructStage,
device_model::DeviceModel{PSY.TwoTerminalVSCLine, F},
network_model::NetworkModel{<:AbstractPowerModel},
) where {F <: AbstractTwoTerminalVSCFormulation}
devices = get_available_components(device_model, sys)

add_variables!(container, FlowActivePowerFromToVariable, devices, F)
add_variables!(container, FlowActivePowerToFromVariable, devices, F)
add_variables!(container, DCLineCurrentFlowVariable, devices, F)
add_variables!(container, HVDCFromDCVoltage, devices, F)
add_variables!(container, HVDCToDCVoltage, devices, F)

_maybe_add_reactive_power_variables!(
container, devices, device_model, network_model,
(HVDCReactivePowerFromVariable, HVDCReactivePowerToVariable),
)

add_variables!(container, CurrentAbsoluteValueVariable, devices, F)

add_to_expression!(
container, ActivePowerBalance, FlowActivePowerFromToVariable,
devices, device_model, network_model,
)
add_to_expression!(
container, ActivePowerBalance, FlowActivePowerToFromVariable,
devices, device_model, network_model,
)

add_feedforward_arguments!(container, device_model, devices)
return
end

function construct_device!(
container::OptimizationContainer,
sys::PSY.System,
::ModelConstructStage,
device_model::DeviceModel{PSY.TwoTerminalVSCLine, F},
network_model::NetworkModel{<:AbstractPowerModel},
) where {F <: AbstractTwoTerminalVSCFormulation}
devices = get_available_components(device_model, sys)
time_steps = get_time_steps(container)
line_names = [PSY.get_name(d) for d in devices]

v_f_var = get_variable(container, HVDCFromDCVoltage, PSY.TwoTerminalVSCLine)
v_t_var = get_variable(container, HVDCToDCVoltage, PSY.TwoTerminalVSCLine)
i_var = get_variable(container, DCLineCurrentFlowVariable, PSY.TwoTerminalVSCLine)

v_f_bounds = PSY.get_voltage_limits_from.(devices)
v_t_bounds = PSY.get_voltage_limits_to.(devices)
i_bounds = [
(min = -_vsc_cable_i_max(d), max = _vsc_cable_i_max(d)) for d in devices
]

quad_cfg, bilin_cfg = _quad_config(F), _bilinear_config(F)

v_f_sq_expr = IOM._add_quadratic_approx!(
quad_cfg, container, PSY.TwoTerminalVSCLine,
line_names, time_steps, v_f_var, v_f_bounds, "v_f_sq",
)
v_t_sq_expr = IOM._add_quadratic_approx!(
quad_cfg, container, PSY.TwoTerminalVSCLine,
line_names, time_steps, v_t_var, v_t_bounds, "v_t_sq",
)
i_sq_expr = IOM._add_quadratic_approx!(
quad_cfg, container, PSY.TwoTerminalVSCLine,
line_names, time_steps, i_var, i_bounds, "i_sq",
)

IOM._add_bilinear_approx!(
bilin_cfg, container, PSY.TwoTerminalVSCLine,
line_names, time_steps,
v_f_sq_expr, i_sq_expr, v_f_var, i_var,
v_f_bounds, i_bounds, "vi_ft",
)
IOM._add_bilinear_approx!(
bilin_cfg, container, PSY.TwoTerminalVSCLine,
line_names, time_steps,
v_t_sq_expr, i_sq_expr, v_t_var, i_var,
v_t_bounds, i_bounds, "vi_tf",
)

_register_pq_sq_expressions!(
container, devices, line_names, time_steps, device_model,
network_model,
)

_add_abs_value_constraints!(
container, devices, device_model, network_model,
DCLineCurrentFlowVariable,
)

add_constraints!(
container, HVDCCableOhmsLawConstraint, devices, device_model, network_model,
)
add_constraints!(
container, HVDCVSCConverterPowerConstraint, devices, device_model, network_model,
)
_maybe_add_reactive_power_constraints!(
container, devices, device_model, network_model,
HVDCVSCApparentPowerLimitConstraint,
)

add_constraint_dual!(container, sys, device_model)
add_feedforward_constraints!(container, device_model, devices)
return
end

# AreaBalancePowerModel warning (consistent with other two-terminal formulations).
function construct_device!(
::OptimizationContainer,
::PSY.System,
::ArgumentConstructStage,
::DeviceModel{PSY.TwoTerminalVSCLine, <:AbstractTwoTerminalVSCFormulation},
::NetworkModel{AreaBalancePowerModel},
)
@warn "AreaBalancePowerModel doesn't model individual line flows for PSY.TwoTerminalVSCLine. Arguments not built"
return
end

function construct_device!(
::OptimizationContainer,
::PSY.System,
::ModelConstructStage,
::DeviceModel{PSY.TwoTerminalVSCLine, <:AbstractTwoTerminalVSCFormulation},
::NetworkModel{AreaBalancePowerModel},
)
@warn "AreaBalancePowerModel doesn't model individual line flows for PSY.TwoTerminalVSCLine. Model not built"
return
end
39 changes: 39 additions & 0 deletions src/common_models/add_to_expression.jl
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,45 @@ function add_to_expression!(
return
end

# A VSC terminal can inject or consume Q freely, so the variable enters
# `ReactivePowerBalance` as a signed injection (+1.0) rather than a load (−1.0).
# Side selection picks the from- or to-terminal bus via dispatch on the
# variable type, so the body is written once.
_vsc_q_terminal_bus(d, ::Type{HVDCReactivePowerFromVariable}) = PSY.get_arc(d).from
_vsc_q_terminal_bus(d, ::Type{HVDCReactivePowerToVariable}) = PSY.get_arc(d).to

function add_to_expression!(
container::OptimizationContainer,
::Type{T},
::Type{U},
devices::IS.FlattenIteratorWrapper{V},
::DeviceModel{V, W},
network_model::NetworkModel{X},
) where {
T <: ReactivePowerBalance,
U <: Union{HVDCReactivePowerFromVariable, HVDCReactivePowerToVariable},
V <: PSY.TwoTerminalVSCLine,
W <: AbstractTwoTerminalVSCFormulation,
X <: ACPPowerModel,
}
var = get_variable(container, U, V)
nodal_expr = get_expression(container, T, PSY.ACBus)
network_reduction = get_network_reduction(network_model)
time_steps = get_time_steps(container)
for d in devices
name = PSY.get_name(d)
bus_no = PNM.get_mapped_bus_number(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little surprised to see this get_mapped_bus_number call here. What's the status of our support and testing for network reductions? Problem is that anything bus-associated gets weird...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LCC does something similar.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is needed for network reductions I think

network_reduction, _vsc_q_terminal_bus(d, U),
)
for t in time_steps
add_proportional_to_jump_expression!(
nodal_expr[bus_no, t], var[name, t], 1.0,
)
end
end
return
end

"""
PWL implementation to add FromTo branch variables to SystemBalanceExpressions
"""
Expand Down
59 changes: 59 additions & 0 deletions src/common_models/network_conditional.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Helpers for variables/constraints that should only appear when the network
# model actually represents the relevant physical quantity (e.g. reactive
# power on AC networks). Each helper has a no-op method that dispatches on
# `NetworkModel{<:AbstractActivePowerModel}`; Julia's method resolution picks
# the more specific no-op over the AC body for DC formulations.

"""
Add reactive-power variables for a device and register them in the system's
`ReactivePowerBalance` expression. `var_types` is a tuple/iterable of
`VariableType` subtypes; each is added via `add_variables!` and then linked
into `ReactivePowerBalance` via `add_to_expression!`. The caller's
device-specific `add_to_expression!` methods are responsible for the actual
bus mapping and sign convention.
"""
function _maybe_add_reactive_power_variables!(
container::OptimizationContainer,
devices,
model::DeviceModel{D, F},
network_model::NetworkModel{<:AbstractPowerModel},
var_types,
) where {D <: PSY.Device, F}
for V in var_types
add_variables!(container, V, devices, F)
add_to_expression!(
container, ReactivePowerBalance, V, devices, model, network_model,
)
end
return
end

_maybe_add_reactive_power_variables!(
::OptimizationContainer,
_devices,
::DeviceModel{D, F},
::NetworkModel{<:AbstractActivePowerModel},
_var_types,
) where {D <: PSY.Device, F} = nothing

"""
Add a reactive-power-related constraint for a device on AC networks.
"""
function _maybe_add_reactive_power_constraints!(
container::OptimizationContainer,
devices,
model::DeviceModel{D, F},
network_model::NetworkModel{<:AbstractPowerModel},
constraint_type::Type{<:ConstraintType},
) where {D <: PSY.Device, F}
add_constraints!(container, constraint_type, devices, model, network_model)
return
end

_maybe_add_reactive_power_constraints!(
::OptimizationContainer,
_devices,
::DeviceModel{D, F},
::NetworkModel{<:AbstractActivePowerModel},
::Type{<:ConstraintType},
) where {D <: PSY.Device, F} = nothing
Loading