diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 36af71cee2..98639c564f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -49,7 +49,9 @@ export PhaseAngleControl ######## HVDC models ######## export LossLessConverter +export QuadraticLossConverter export LossLessLine +export DCLossyLine ######## Load Models ######## export StaticPowerLoad export PowerLoadInterruption diff --git a/src/core/auxiliary_variables.jl b/src/core/auxiliary_variables.jl index c2baca4288..c4fc29faad 100644 --- a/src/core/auxiliary_variables.jl +++ b/src/core/auxiliary_variables.jl @@ -13,4 +13,18 @@ Auxiliary Variable for Thermal Generation Models that solve for power above min """ struct PowerOutput <: AuxVariableType end +""" +Auxiliary Variable of DC Current Variables for DC Lines formulations + +Docs abbreviation: ``i_l^{dc}`` +""" +struct DCLineCurrent <: AuxVariableType end + +""" +Auxiliary Variable of DC Current Variables for DC Lines formulations + +Docs abbreviation: ``p_l^{loss}`` +""" +struct DCLineLosses <: AuxVariableType end + convert_result_to_natural_units(::Type{PowerOutput}) = true diff --git a/src/core/constraints.jl b/src/core/constraints.jl index a36e8257cd..1e124252d1 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -416,3 +416,68 @@ struct LineFlowBoundConstraint <: ConstraintType end abstract type EventConstraint <: ConstraintType end struct OutageConstraint <: EventConstraint end + +""" +Struct to create the constraints that set the losses through a lossy Interconnecting Power Converter. + +For more information check [Converter Formulations](@ref PowerSystems.Converter-Formulations). + +The specified constraint is formulated as: + +```math +\\begin{align*} +& i_c^{dc} = \\sum_{j \\in \\mathcal{B}^{DC}} \\frac{1}{r_{i,j}} (v_i - v_j), \\quad \\forall t \\in \\{1,\\dots, T\\} +\\end{align*} +``` +""" +struct ConverterCurrentBalanceConstraint <: ConstraintType end + +""" +Struct to create the constraints that compute the converter DC power based on current and voltage. + +For more information check [Converter Formulations](@ref PowerSystems.Converter-Formulations). + +The specified constraints are formulated as: + +```math +\\begin{align*} +& p_c = 0.5 * (γ^sq - v^sq - i^sq), \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +& γ_c = v_c + i_c, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +\\end{align*} +``` +""" +struct ConverterPowerCalculationConstraint <: ConstraintType end + +""" +Struct to create the constraints that decide the operation direction of the converter. + +For more information check [Converter Formulations](@ref PowerSystems.Converter-Formulations). + +The specified constraints are formulated as: + +```math +\\begin{align*} +& I_c^{min} (1 - κ_c) <= i_c <= κ_c * I_c^{max}, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +& P_c^{min} (1 - κ_c) <= p_c <= κ_c * P_c^{max}, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +\\end{align*} +``` +""" +struct ConverterDirectionConstraint <: ConstraintType end + +""" +Struct to create the McCormick envelopes constraints that decide the bounds on the DC active power. + +For more information check [Converter Formulations](@ref PowerSystems.Converter-Formulations). + +The specified constraints are formulated as: + +```math +\\begin{align*} +& p_c >= V^{min} i_c + v_c I^{min} - I^{min}V^{min}, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +& p_c >= V^{max} i_c + v_c I^{max} - I^{max}V^{max}, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +& p_c <= V^{max} i_c + v_c I^{min} - I^{min}V^{max}, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +& p_c <= V^{min} i_c + v_c I^{max} - I^{max}V^{min}, \\quad \\forall t \\in \\{1,\\dots, T\\} \\\\ +\\end{align*} +``` +""" +struct ConverterMcCormickEnvelopes <: ConstraintType end diff --git a/src/core/expressions.jl b/src/core/expressions.jl index f5ad354a7d..1f901aba2c 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -14,11 +14,13 @@ struct ComponentReserveUpBalanceExpression <: ExpressionType end struct ComponentReserveDownBalanceExpression <: ExpressionType end struct InterfaceTotalFlow <: ExpressionType end struct PTDFBranchFlow <: ExpressionType end +struct DCCurrentBalance <: ExpressionType end should_write_resulting_value(::Type{<:CostExpressions}) = true should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true should_write_resulting_value(::Type{ActivePowerBalance}) = true should_write_resulting_value(::Type{ReactivePowerBalance}) = true +should_write_resulting_value(::Type{DCCurrentBalance}) = true convert_result_to_natural_units(::Type{InterfaceTotalFlow}) = true diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 1b6ddb109a..2764fa0dc6 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -145,11 +145,26 @@ LossLess InterconnectingConverter Model """ struct LossLessConverter <: AbstractConverterFormulation end +""" +Linear Loss InterconnectingConverter Model +""" +struct LinearLossConverter <: AbstractConverterFormulation end + +""" +Quadratic Loss InterconnectingConverter Model +""" +struct QuadraticLossConverter <: AbstractConverterFormulation end + """ LossLess Line Abstract Model """ struct LossLessLine <: AbstractBranchFormulation end +""" +DC Loss Line Abstract Model +""" +struct DCLossyLine <: AbstractBranchFormulation end + ############################## Network Model Formulations ################################## # These formulations are taken directly from PowerModels diff --git a/src/core/variables.jl b/src/core/variables.jl index 42d5bc0560..2a0b953794 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -168,6 +168,125 @@ Docs abbreviation: ``\\theta`` """ struct VoltageAngle <: VariableType end +""" +Struct to dispatch the creation of Voltage Variables for DC formulations + +Docs abbreviation: ``v^{dc}`` +""" +struct DCVoltage <: VariableType end + +""" +Struct to dispatch the creation of Squared Voltage Variables for DC formulations + +Docs abbreviation: ``v^{sq,dc}`` +""" +struct SquaredDCVoltage <: VariableType end + +""" +Struct to dispatch the creation of DC Converter Current Variables for DC formulations + +Docs abbreviation: ``i_c^{dc}`` +""" +struct ConverterCurrent <: VariableType end + +""" +Struct to dispatch the creation of DC Converter Power Variables for DC formulations + +Docs abbreviation: ``p_c^{dc}`` +""" +struct ConverterDCPower <: VariableType end + +""" +Struct to dispatch the creation of Squared DC Converter Current Variables for DC formulations + +Docs abbreviation: ``i_c^{sq,dc}`` +""" +struct SquaredConverterCurrent <: VariableType end + +""" +Struct to dispatch the creation of DC Converter Positive Term Current Variables for DC formulations + +Docs abbreviation: ``i_c^{+,dc}`` +""" +struct ConverterPositiveCurrent <: VariableType end + +""" +Struct to dispatch the creation of DC Converter Negative Term Current Variables for DC formulations + +Docs abbreviation: ``i_c^{-,dc}`` +""" +struct ConverterNegativeCurrent <: VariableType end + +""" +Struct to dispatch the creation of DC Converter Binary for Absolute Value Current Variables for DC formulations + +Docs abbreviation: `\\nu_c`` +""" +struct ConverterBinaryAbsoluteValueCurrent <: VariableType end + +""" +Struct to dispatch the creation of Binary Variable for Converter Power Direction + +Docs abbreviation: ``\\kappa_c^{dc}`` +""" +struct ConverterPowerDirection <: VariableType end + +""" +Struct to dispatch the creation of Auxiliary Variable for Converter Bilinear term: v * i + +Docs abbreviation: ``\\gamma_c^{dc}`` +""" +struct AuxBilinearConverterVariable <: VariableType end + +""" +Struct to dispatch the creation of Auxiliary Variable for Squared Converter Bilinear term: v * i + +Docs abbreviation: ``\\gamma_c^{sq,dc}`` +""" +struct AuxBilinearSquaredConverterVariable <: VariableType end + +""" +Struct to dispatch the creation of Continuous Interpolation Variable for Squared Converter Voltage + +Docs abbreviation: ``\\delta_c^{v}`` +""" +struct InterpolationSquaredVoltageVariable <: VariableType end + +""" +Struct to dispatch the creation of Binary Interpolation Variable for Squared Converter Voltage + +Docs abbreviation: ``z_c^{v}`` +""" +struct InterpolationBinarySquaredVoltageVariable <: VariableType end + +""" +Struct to dispatch the creation of Continuous Interpolation Variable for Squared Converter Current + +Docs abbreviation: ``\\delta_c^{i}`` +""" +struct InterpolationSquaredCurrentVariable <: VariableType end + +""" +Struct to dispatch the creation of Binary Interpolation Variable for Squared Converter Current + +Docs abbreviation: ``z_c^{i}`` +""" +struct InterpolationBinarySquaredCurrentVariable <: VariableType end + +""" +Struct to dispatch the creation of Continuous Interpolation Variable for Squared Converter AuxVar + +Docs abbreviation: ``\\delta_c^{\\gamma}`` +""" +struct InterpolationSquaredBilinearVariable <: VariableType end + +""" +Struct to dispatch the creation of Binary Interpolation Variable for Squared Converter AuxVar + +Docs abbreviation: ``z_c^{\\gamma}`` +""" +struct InterpolationBinarySquaredBilinearVariable <: VariableType end + """ Struct to dispatch the creation of bidirectional Active Power Flow Variables diff --git a/src/devices_models/device_constructors/hvdcsystems_constructor.jl b/src/devices_models/device_constructors/hvdcsystems_constructor.jl index 668b41f70e..edb39c2576 100644 --- a/src/devices_models/device_constructors/hvdcsystems_constructor.jl +++ b/src/devices_models/device_constructors/hvdcsystems_constructor.jl @@ -39,6 +39,153 @@ function construct_device!( return end +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{PSY.InterconnectingConverter, QuadraticLossConverter}, + network_model::NetworkModel{<:PM.AbstractActivePowerModel}, +) + devices = get_available_components( + model, + sys, + ) + ##################### + ##### Variables ##### + ##################### + + # Add Power Variable + add_variables!(container, ActivePowerVariable, devices, QuadraticLossConverter()) # p_c^{ac} + #add_variables!(container, ConverterDCPower, devices, QuadraticLossConverter()) # p_c + add_variables!(container, ConverterPowerDirection, devices, QuadraticLossConverter()) #κ + # Add Current Variables: i, δ^i, z^i, i+, i- + add_variables!(container, ConverterCurrent, devices, QuadraticLossConverter()) # i + add_variables!(container, SquaredConverterCurrent, devices, QuadraticLossConverter()) # i^sq + add_variables!( + container, + InterpolationSquaredCurrentVariable, + devices, + QuadraticLossConverter(), + ) # δ^i + add_variables!( + container, + InterpolationBinarySquaredCurrentVariable, + devices, + QuadraticLossConverter(), + ) # z^i + add_variables!(container, ConverterPositiveCurrent, devices, QuadraticLossConverter()) # i^+ + add_variables!(container, ConverterNegativeCurrent, devices, QuadraticLossConverter()) # i^- + add_variables!( + container, + ConverterBinaryAbsoluteValueCurrent, + devices, + QuadraticLossConverter(), + ) # ν + # Add Voltage Variables: v^sq, δ^v, z^v + add_variables!(container, SquaredDCVoltage, devices, QuadraticLossConverter()) + add_variables!( + container, + InterpolationSquaredVoltageVariable, + devices, + QuadraticLossConverter(), + ) # δ^v + add_variables!( + container, + InterpolationBinarySquaredVoltageVariable, + devices, + QuadraticLossConverter(), + ) # z^v + # Add Bilinear Variables: γ, γ^{sq} + add_variables!( + container, + AuxBilinearConverterVariable, + devices, + QuadraticLossConverter(), + ) # γ + add_variables!( + container, + AuxBilinearSquaredConverterVariable, + devices, + QuadraticLossConverter(), + ) # γ^{sq} + add_variables!( + container, + InterpolationSquaredBilinearVariable, + devices, + QuadraticLossConverter(), + ) # δ^γ + add_variables!( + container, + InterpolationBinarySquaredBilinearVariable, + devices, + QuadraticLossConverter(), + ) # z^γ + + ##################### + #### Expressions #### + ##################### + + # No losses for now: ActivePowerVariable = DCPower and ACPower + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{PSY.InterconnectingConverter, QuadraticLossConverter}, + network_model::NetworkModel{<:PM.AbstractActivePowerModel}, +) + devices = get_available_components( + model, + sys, + ) + # TODO Constraints + add_constraints!( + container, + sys, + ConverterCurrentBalanceConstraint, + devices, + model, + network_model, + ) + add_constraints!( + container, + ConverterPowerCalculationConstraint, + devices, + model, + network_model, + ) + add_constraints!( + container, + ConverterDirectionConstraint, + devices, + model, + network_model, + ) + add_constraints!( + container, + ConverterMcCormickEnvelopes, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + objective_function!(container, devices, model, get_network_formulation(network_model)) + add_constraint_dual!(container, sys, model) + return +end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -71,3 +218,35 @@ function construct_device!( ::NetworkModel{<:PM.AbstractActivePowerModel}, ) end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{PSY.TModelHVDCLine, DCLossyLine}, + network_model::NetworkModel{<:PM.AbstractActivePowerModel}, +) + devices = get_available_components( + model, + sys, + ) + + dc_buses = PSY.get_components( + PSY.DCBus, + sys, + ) + add_variables!(container, DCVoltage, dc_buses, DCLossyLine()) + #add_variables!(container, DCLineCurrent, devices, DCLossyLine()) + #add_variables!(container, DCLineLosses, devices, DCLossyLine()) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + ::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{PSY.TModelHVDCLine, DCLossyLine}, + ::NetworkModel{<:PM.AbstractActivePowerModel}, +) +end diff --git a/src/devices_models/devices/HVDCsystems.jl b/src/devices_models/devices/HVDCsystems.jl index ecf47f4d89..988c8d0b1a 100644 --- a/src/devices_models/devices/HVDCsystems.jl +++ b/src/devices_models/devices/HVDCsystems.jl @@ -1,8 +1,37 @@ #! format: off +### Binaries ### +# Converter get_variable_binary(::ActivePowerVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::ConverterPowerDirection, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = true +get_variable_binary(::ConverterCurrent, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::ConverterPositiveCurrent, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::ConverterNegativeCurrent, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::ConverterBinaryAbsoluteValueCurrent, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = true +get_variable_binary(::SquaredConverterCurrent, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::InterpolationSquaredCurrentVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::InterpolationBinarySquaredCurrentVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = true +get_variable_binary(::SquaredDCVoltage, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::InterpolationSquaredVoltageVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::InterpolationBinarySquaredVoltageVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = true +get_variable_binary(::AuxBilinearConverterVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::AuxBilinearSquaredConverterVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::InterpolationSquaredBilinearVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = false +get_variable_binary(::InterpolationBinarySquaredBilinearVariable, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = true +# DCBuses +get_variable_binary(::DCVoltage, ::Type{PSY.DCBus}, ::AbstractBranchFormulation) = false + +### Warm Start ### get_variable_warm_start_value(::ActivePowerVariable, d::PSY.InterconnectingConverter, ::AbstractConverterFormulation) = PSY.get_active_power(d) +get_variable_warm_start_value(::ConverterCurrent, d::PSY.InterconnectingConverter, ::AbstractConverterFormulation) = PSY.get_dc_current(d) + +### Lower Bounds ### get_variable_lower_bound(::ActivePowerVariable, d::PSY.InterconnectingConverter, ::AbstractConverterFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ConverterCurrent, d::PSY.InterconnectingConverter, ::AbstractConverterFormulation) = PSY.get_dc_current_limits(d).min + +### Upper Bounds ### get_variable_upper_bound(::ActivePowerVariable, d::PSY.InterconnectingConverter, ::AbstractConverterFormulation) = PSY.get_active_power_limits(d).max +get_variable_upper_bound(::ConverterCurrent, d::PSY.InterconnectingConverter, ::AbstractConverterFormulation) = PSY.get_dc_current_limits(d).max + get_variable_multiplier(_, ::Type{PSY.InterconnectingConverter}, ::AbstractConverterFormulation) = 1.0 @@ -59,8 +88,8 @@ end function get_initial_conditions_device_model( ::OperationModel, - model::DeviceModel{PSY.TModelHVDCLine, LossLessLine}, -) + model::DeviceModel{PSY.TModelHVDCLine, D}, +) where {D <: Union{LossLessLine, DCLossyLine}} return model end @@ -317,11 +346,213 @@ function add_to_expression!( return end +########################## +###### Constraints ####### +########################## + +function add_constraints!( + container::OptimizationContainer, + sys::PSY.System, + ::Type{ConverterCurrentBalanceConstraint}, + devices::IS.FlattenIteratorWrapper{U}, + model::DeviceModel{U, V}, + network_model::NetworkModel{X}, +) where { + U <: PSY.InterconnectingConverter, + V <: QuadraticLossConverter, + X <: PM.AbstractActivePowerModel, +} + time_steps = get_time_steps(container) + varcurrent = get_variable(container, ConverterCurrent(), U) + var_dcvoltage = get_variable(container, DCVoltage(), PSY.DCBus) + ipc_names = axes(varcurrent, 1) + constraint = + add_constraints_container!(container, ConverterCurrentBalanceConstraint(), U, ipc_names, time_steps) + + for device in devices + name = PSY.get_name(device) + dc_bus = PSY.get_dc_bus(device) + dc_bus_name = PSY.get_name(dc_bus) + from_branches = PSY.get_components(x-> x.available && (x.arc.from == dc_bus), PSY.DCBranch, sys) + to_branches = PSY.get_components(x-> x.available && (x.arc.to == dc_bus), PSY.DCBranch, sys) + for t in time_steps + total_current_flow = JuMP.AffExpr() + for br in from_branches + r = PSY.get_r(br) + to_bus_name = PSY.get_name(br.arc.to) + if r <= 0.0 + error("Series resistance of DCBranch $(PSY.get_name(br)) is non-positive. Consider updating your data") + end + total_current_flow += (1.0 / r) * (var_dcvoltage[dc_bus_name, t] - var_dcvoltage[to_bus_name, t]) + end + for br in to_branches + r = PSY.get_r(br) + from_bus_name = PSY.get_name(br.arc.from) + if r <= 0.0 + error("Series resistance of DCBranch $(PSY.get_name(br)) is non-positive. Consider updating your data") + end + total_current_flow += (1.0 / r) * (var_dcvoltage[dc_bus_name, t] - var_dcvoltage[from_bus_name, t]) + end + constraint[name, t] = JuMP.@constraint( + get_jump_model(container), + varcurrent[name, t] == total_current_flow + ) + end + end + return +end + +function add_constraints!( + container::OptimizationContainer, + ::Type{ConverterPowerCalculationConstraint}, + devices::IS.FlattenIteratorWrapper{U}, + model::DeviceModel{U, V}, + network_model::NetworkModel{X}, +) where { + U <: PSY.InterconnectingConverter, + V <: QuadraticLossConverter, + X <: PM.AbstractActivePowerModel, +} + time_steps = get_time_steps(container) + varcurrent = get_variable(container, ConverterCurrent(), U) + var_dcvoltage = get_variable(container, DCVoltage(), PSY.DCBus) + var_sq_current = get_variable(container, SquaredConverterCurrent(), U) + var_sq_voltage = get_variable(container, SquaredDCVoltage(), U) + var_bilinear = get_variable(container, AuxBilinearConverterVariable(), U) + var_sq_bilinear = get_variable(container, AuxBilinearSquaredConverterVariable(), U) + var_dc_power = get_variable(container, ActivePowerVariable(), U) + ipc_names = axes(varcurrent, 1) + constraint = + add_constraints_container!(container, ConverterPowerCalculationConstraint(), U, ipc_names, time_steps) + constraint_aux = + add_constraints_container!(container, ConverterPowerCalculationConstraint(), U, ipc_names, time_steps; meta = "aux") + + for device in devices + name = PSY.get_name(device) + dc_bus_name = PSY.get_name(PSY.get_dc_bus(device)) + for t in time_steps + constraint[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] == 0.5 * (var_sq_bilinear[name, t] - var_sq_voltage[name, t] - var_sq_current[name, t]) + ) + constraint_aux[name, t] = JuMP.@constraint( + get_jump_model(container), + var_bilinear[name, t] == var_dcvoltage[dc_bus_name, t] + varcurrent[name, t] + ) + end + end + return +end + +function add_constraints!( + container::OptimizationContainer, + ::Type{ConverterDirectionConstraint}, + devices::IS.FlattenIteratorWrapper{U}, + model::DeviceModel{U, V}, + network_model::NetworkModel{X}, +) where { + U <: PSY.InterconnectingConverter, + V <: QuadraticLossConverter, + X <: PM.AbstractActivePowerModel, +} + time_steps = get_time_steps(container) + varcurrent = get_variable(container, ConverterCurrent(), U) + var_dc_power = get_variable(container, ActivePowerVariable(), U) + var_binary = get_variable(container, ConverterPowerDirection(), U) + ipc_names = axes(varcurrent, 1) + constraint_i_ub = + add_constraints_container!(container, ConverterDirectionConstraint(), U, ipc_names, time_steps; meta = "current_ub") + constraint_i_lb = + add_constraints_container!(container, ConverterDirectionConstraint(), U, ipc_names, time_steps; meta = "current_lb") + constraint_p_ub = + add_constraints_container!(container, ConverterDirectionConstraint(), U, ipc_names, time_steps; meta = "power_ub") + constraint_p_lb = + add_constraints_container!(container, ConverterDirectionConstraint(), U, ipc_names, time_steps; meta = "power_lb") + + for device in devices + name = PSY.get_name(device) + P_min, P_max = PSY.get_active_power_limits(device) + I_min, I_max = PSY.get_dc_current_limits(device) + for t in time_steps + constraint_i_ub[name, t] = JuMP.@constraint( + get_jump_model(container), + varcurrent[name, t] <= var_binary[name, t] * I_max + ) + constraint_i_lb[name, t] = JuMP.@constraint( + get_jump_model(container), + varcurrent[name, t] >= (1 - var_binary[name, t]) * I_min + ) + constraint_p_ub[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] <= var_binary[name, t] * P_max + ) + constraint_p_lb[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] >= (1 - var_binary[name, t]) * P_min + ) + end + end + return +end + +function add_constraints!( + container::OptimizationContainer, + ::Type{ConverterMcCormickEnvelopes}, + devices::IS.FlattenIteratorWrapper{U}, + model::DeviceModel{U, V}, + network_model::NetworkModel{X}, +) where { + U <: PSY.InterconnectingConverter, + V <: QuadraticLossConverter, + X <: PM.AbstractActivePowerModel, +} + time_steps = get_time_steps(container) + varcurrent = get_variable(container, ConverterCurrent(), U) + var_dcvoltage = get_variable(container, DCVoltage(), PSY.DCBus) + var_dc_power = get_variable(container, ActivePowerVariable(), U) + ipc_names = axes(varcurrent, 1) + constraint1_under = + add_constraints_container!(container, ConverterMcCormickEnvelopes(), U, ipc_names, time_steps; meta = "under_1") + constraint2_under = + add_constraints_container!(container, ConverterMcCormickEnvelopes(), U, ipc_names, time_steps; meta = "under_2") + constraint1_over = + add_constraints_container!(container, ConverterMcCormickEnvelopes(), U, ipc_names, time_steps; meta = "over_1") + constraint2_over = + add_constraints_container!(container, ConverterMcCormickEnvelopes(), U, ipc_names, time_steps; meta = "over_2") + + for device in devices + name = PSY.get_name(device) + dc_bus = PSY.get_dc_bus(device) + dc_bus_name = PSY.get_name(dc_bus) + V_min, V_max = PSY.get_voltage_limits(dc_bus) + I_min, I_max = PSY.get_dc_current_limits(device) + for t in time_steps + constraint1_under[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] >= V_min * varcurrent[name, t] + var_dcvoltage[dc_bus_name, t] * I_min - I_min * V_min + ) + constraint2_under[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] >= V_max * varcurrent[name, t] + var_dcvoltage[dc_bus_name, t] * I_max - I_max * V_max + ) + constraint1_over[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] <= V_max * varcurrent[name, t] + var_dcvoltage[dc_bus_name, t] * I_min - I_min * V_max + ) + constraint2_over[name, t] = JuMP.@constraint( + get_jump_model(container), + var_dc_power[name, t] <= V_min * varcurrent[name, t] + var_dcvoltage[dc_bus_name, t] * I_max - I_max * V_min + ) + end + end + return +end + function objective_function!( ::OptimizationContainer, ::IS.FlattenIteratorWrapper{PSY.InterconnectingConverter}, - ::DeviceModel{PSY.InterconnectingConverter, LossLessConverter}, + ::DeviceModel{PSY.InterconnectingConverter, T}, ::Type{<:PM.AbstractPowerModel}, -) +) where {T <: Union{LossLessConverter, QuadraticLossConverter}} return end