Skip to content

Commit

Permalink
update FF models
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigomha committed May 3, 2024
1 parent 0404d82 commit cd6eb6b
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 25 deletions.
4 changes: 4 additions & 0 deletions src/HybridSystemsSimulations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ export TotalReserve

# Auxiliary variables

# FeedForward
export CyclingChargeLimitFeedforward
export CyclingDischargeLimitFeedforward

# Constraints
export OptConditionRenewablePower
export OptConditionBatteryCharge
Expand Down
14 changes: 8 additions & 6 deletions src/add_aux_variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ function PSI.calculate_aux_variable_value!(
resolution = PSI.get_resolution(container)
fraction_of_hour = Dates.value(Dates.Minute(resolution)) / PSI.MINUTES_IN_HOUR
charge_var = PSI.get_variable(container, BatteryCharge(), T)
ch_served_reg_up = PSI.get_expression(container, ChargeServedReserveUpExpression(), T)
ch_served_reg_dn = PSI.get_expression(container, ChargeServedReserveDownExpression(), T)
aux_variable_container = PSI.get_aux_variable(container, CumulativeCyclingCharge(), T)
for d in devices
name = PSY.get_name(d)
Expand All @@ -23,6 +21,10 @@ function PSI.calculate_aux_variable_value!(
fraction_of_hour *
sum(PSI.jump_value(charge_var[name, k]) for k in 1:t)
else
ch_served_reg_up =
PSI.get_expression(container, ChargeServedReserveUpExpression(), T)
ch_served_reg_dn =
PSI.get_expression(container, ChargeServedReserveDownExpression(), T)
aux_variable_container[name, t] =
efficiency.in *
fraction_of_hour *
Expand All @@ -49,10 +51,6 @@ function PSI.calculate_aux_variable_value!(
resolution = PSI.get_resolution(container)
fraction_of_hour = Dates.value(Dates.Minute(resolution)) / PSI.MINUTES_IN_HOUR
discharge_var = PSI.get_variable(container, BatteryDischarge(), T)
ds_served_reg_up =
PSI.get_expression(container, DischargeServedReserveUpExpression(), T)
ds_served_reg_dn =
PSI.get_expression(container, DischargeServedReserveDownExpression(), T)
aux_variable_container =
PSI.get_aux_variable(container, CumulativeCyclingDischarge(), T)
for d in devices
Expand All @@ -66,6 +64,10 @@ function PSI.calculate_aux_variable_value!(
fraction_of_hour *
sum(PSI.jump_value(discharge_var[name, k]) for k in 1:t)
else
ds_served_reg_up =
PSI.get_expression(container, DischargeServedReserveUpExpression(), T)
ds_served_reg_dn =
PSI.get_expression(container, DischargeServedReserveDownExpression(), T)
aux_variable_container[name, t] =
(1.0 / efficiency.out) *
fraction_of_hour *
Expand Down
55 changes: 40 additions & 15 deletions src/add_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,20 @@ function _add_constraints_cyclingcharge_withreserves!(
ci_name = PSY.get_name(device)
storage = PSY.get_storage(device)
efficiency = PSY.get_efficiency(storage)
E_max = PSY.get_state_of_charge_limits(storage).max
cycles_per_day = PSY.get_cycle_limits(storage)
cycles_in_horizon =
cycles_per_day * fraction_of_hour * length(time_steps) / HOURS_IN_DAY
con_cycling_ch[ci_name] = JuMP.@constraint(
PSI.get_jump_model(container),
efficiency.in *
fraction_of_hour *
sum(
charge_var[ci_name, :] + ch_served_reg_dn[ci_name, :] -
ch_served_reg_up[ci_name, :],
) <= cycles_in_horizon * E_max
)
#=
if PSI.built_for_recurrent_solves(container)
param_value =
PSI.get_parameter_array(container, CyclingChargeLimitParameter(), D)[ci_name]
Expand Down Expand Up @@ -962,6 +976,7 @@ function _add_constraints_cyclingcharge_withreserves!(
) <= cycles_in_horizon * E_max
)
end
=#
end
return
end
Expand Down Expand Up @@ -1087,6 +1102,20 @@ function _add_constraints_cyclingdischarge_withreserves!(
ci_name = PSY.get_name(device)
storage = PSY.get_storage(device)
efficiency = PSY.get_efficiency(storage)
E_max = PSY.get_state_of_charge_limits(storage).max
cycles_per_day = PSY.get_cycle_limits(storage)
cycles_in_horizon =
cycles_per_day * fraction_of_hour * length(time_steps) / HOURS_IN_DAY
con_cycling_ds[ci_name] = JuMP.@constraint(
PSI.get_jump_model(container),
(1.0 / efficiency.out) *
fraction_of_hour *
sum(
discharge_var[ci_name, :] + ds_served_reg_up[ci_name, :] -
ds_served_reg_dn[ci_name, :],
) <= cycles_in_horizon * E_max
)
#=
if PSI.built_for_recurrent_solves(container)
param_value =
PSI.get_parameter_array(container, CyclingDischargeLimitParameter(), D)[ci_name]
Expand Down Expand Up @@ -1114,6 +1143,7 @@ function _add_constraints_cyclingdischarge_withreserves!(
) <= cycles_in_horizon * E_max
)
end
=#
end
return
end
Expand Down Expand Up @@ -1221,11 +1251,10 @@ function PSI.add_constraints!(
names = [PSY.get_name(x) for x in devices]
time_steps = PSI.get_time_steps(container)
reg_var = PSI.get_variable(container, ChargeRegularizationVariable(), V)
ch_served_reg_up = PSI.get_expression(container, ChargeServedReserveUpExpression(), V)
ch_served_reg_dn = PSI.get_expression(container, ChargeServedReserveDownExpression(), V)
powerin_var = PSI.get_variable(container, BatteryCharge(), V)
has_services = PSI.has_service_model(model)

if has_services
end
constraint_ub = PSI.add_constraints_container!(
container,
ChargeRegularizationConstraint(),
Expand All @@ -1245,10 +1274,10 @@ function PSI.add_constraints!(
)

if has_services
services = Set()
for d in devices
union!(services, PSY.get_services(d))
end
ch_served_reg_up =
PSI.get_expression(container, ChargeServedReserveUpExpression(), V)
ch_served_reg_dn =
PSI.get_expression(container, ChargeServedReserveDownExpression(), V)
for device in devices
ci_name = PSY.get_name(device)
constraint_ub[ci_name, 1] =
Expand Down Expand Up @@ -1317,10 +1346,6 @@ function PSI.add_constraints!(
time_steps = PSI.get_time_steps(container)
reg_var = PSI.get_variable(container, DischargeRegularizationVariable(), V)
powerout_var = PSI.get_variable(container, BatteryDischarge(), V)
ds_served_reg_up =
PSI.get_expression(container, DischargeServedReserveUpExpression(), V)
ds_served_reg_dn =
PSI.get_expression(container, DischargeServedReserveDownExpression(), V)
has_services = PSI.has_service_model(model)

constraint_ub = PSI.add_constraints_container!(
Expand All @@ -1342,10 +1367,10 @@ function PSI.add_constraints!(
)

if has_services
services = Set()
for d in devices
union!(services, PSY.get_services(d))
end
ds_served_reg_up =
PSI.get_expression(container, DischargeServedReserveUpExpression(), V)
ds_served_reg_dn =
PSI.get_expression(container, DischargeServedReserveDownExpression(), V)
for device in devices
ci_name = PSY.get_name(device)
constraint_ub[ci_name, 1] =
Expand Down
7 changes: 7 additions & 0 deletions src/core/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ struct DischargeRegularizationConstraint <: PSI.ConstraintType end
struct StateofChargeTargetConstraint <: PSI.ConstraintType end
struct RenewableActivePowerLimitConstraint <: PSI.ConstraintType end

###################
### Feedforwards ###
###################

struct FeedForwardCyclingChargeConstraint <: PSI.ConstraintType end
struct FeedForwardCyclingDischargeConstraint <: PSI.ConstraintType end

##############################################
### Dual Optimality Conditions Constraints ###
##############################################
Expand Down
1 change: 1 addition & 0 deletions src/core/variables.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,4 @@ struct ComplementarySlackVarCyclingDischarge <: MerchantModelComplementarySlackV

# implement below
#PSI.convert_result_to_natural_units() = false
PSI.should_write_resulting_value(::Type{TotalReserve}) = false
170 changes: 166 additions & 4 deletions src/feedforwards.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ struct CyclingChargeLimitFeedforward <: PSI.AbstractAffectFeedforward
penalty_cost::Float64,
meta=PSI.CONTAINER_KEY_EMPTY_META,
) where {T}
values_vector = Vector{PSI.VariableKey}(undef, length(affected_values))
values_vector = Vector{PSI.ParameterKey}(undef, length(affected_values))
for (ix, v) in enumerate(affected_values)
if v <: PSI.VariableType
if v <: PSI.ParameterType
values_vector[ix] =
PSI.get_optimization_container_key(v(), component_type, meta)
else
Expand Down Expand Up @@ -48,9 +48,9 @@ struct CyclingDischargeLimitFeedforward <: PSI.AbstractAffectFeedforward
penalty_cost::Float64,
meta=PSI.CONTAINER_KEY_EMPTY_META,
) where {T}
values_vector = Vector{PSI.VariableKey}(undef, length(affected_values))
values_vector = Vector{PSI.ParameterKey}(undef, length(affected_values))
for (ix, v) in enumerate(affected_values)
if v <: PSI.VariableType
if v <: PSI.ParameterType
values_vector[ix] =
PSI.get_optimization_container_key(v(), component_type, meta)
else
Expand All @@ -72,6 +72,168 @@ PSI.get_default_parameter_type(::CyclingDischargeLimitFeedforward, _) =
PSI.get_optimization_container_key(ff::CyclingDischargeLimitFeedforward) =
ff.optimization_container_key

#=
function PSI.add_feedforward_arguments!(
container::PSI.OptimizationContainer,
model::PSI.DeviceModel,
devices::Union{Vector{D}, IS.FlattenIteratorWrapper{D}},
) where {D <: PSY.HybridSystem}
for ff in PSI.get_feedforwards(model)
PSI._add_feedforward_arguments!(container, model, devices, ff)
end
return
end
=#

function PSI._add_feedforward_arguments!(
container::PSI.OptimizationContainer,
model::PSI.DeviceModel,
devices::Vector{D},
ff::U,
) where {
D <: PSY.HybridSystem,
U <: Union{CyclingChargeLimitFeedforward, CyclingDischargeLimitFeedforward},
}
parameter_type = PSI.get_default_parameter_type(ff, D)
PSI.add_parameters!(container, parameter_type, devices, model)
return
end

function PSI.add_feedforward_constraints!(
container::PSI.OptimizationContainer,
model::PSI.DeviceModel,
devices::Vector{V},
) where {V <: PSY.HybridSystem}
for ff in PSI.get_feedforwards(model)
PSI.add_feedforward_constraints!(container, model, devices, ff)
end
return
end

function PSI.add_feedforward_constraints!(
container::PSI.OptimizationContainer,
device_model::PSI.DeviceModel,
devices::Union{Vector{D}, IS.FlattenIteratorWrapper{D}},
ff::CyclingChargeLimitFeedforward,
) where {D <: PSY.HybridSystem}
if PSI.get_attribute(device_model, "cycling")
throw(
IS.ConflictingInputsError(
"Cycling Attribute not allowed with Cycling Limit Feedforwards",
),
)
end
time_steps = PSI.get_time_steps(container)
resolution = PSI.get_resolution(container)
fraction_of_hour = Dates.value(Dates.Minute(resolution)) / PSI.MINUTES_IN_HOUR
names = [PSY.get_name(d) for d in devices]
charge_var = PSI.get_variable(container, BatteryCharge(), D)
ch_served_reg_up = PSI.get_expression(container, ChargeServedReserveUpExpression(), D)
ch_served_reg_dn = PSI.get_expression(container, ChargeServedReserveDownExpression(), D)
T = FeedForwardCyclingChargeConstraint
con_cycling_ch = PSI.add_constraints_container!(container, T(), D, names)
for device in devices
ci_name = PSY.get_name(device)
storage = PSY.get_storage(device)
efficiency = PSY.get_efficiency(storage)
E_max = PSY.get_state_of_charge_limits(storage).max
cycles_per_day = PSY.get_cycle_limits(storage)
cycles_in_horizon =
cycles_per_day * fraction_of_hour * length(time_steps) / HOURS_IN_DAY
if PSI.built_for_recurrent_solves(container)
param_value =
PSI.get_parameter_array(container, CyclingChargeLimitParameter(), D)[ci_name]
con_cycling_ch[ci_name] = JuMP.@constraint(
PSI.get_jump_model(container),
efficiency.in *
fraction_of_hour *
sum(
charge_var[ci_name, :] + ch_served_reg_dn[ci_name, :] -
ch_served_reg_up[ci_name, :],
) <= param_value
)
else
E_max = PSY.get_state_of_charge_limits(storage).max
cycles_per_day = PSY.get_cycle_limits(storage)
cycles_in_horizon =
cycles_per_day * fraction_of_hour * length(time_steps) / HOURS_IN_DAY
con_cycling_ch[ci_name] = JuMP.@constraint(
PSI.get_jump_model(container),
efficiency.in *
fraction_of_hour *
sum(
charge_var[ci_name, :] + ch_served_reg_dn[ci_name, :] -
ch_served_reg_up[ci_name, :],
) <= cycles_in_horizon * E_max
)
end
end
return
end

function PSI.add_feedforward_constraints!(
container::PSI.OptimizationContainer,
device_model::PSI.DeviceModel,
devices::Union{Vector{D}, IS.FlattenIteratorWrapper{D}},
ff::CyclingDischargeLimitFeedforward,
) where {D <: PSY.HybridSystem}
if PSI.get_attribute(device_model, "cycling")
throw(
IS.ConflictingInputsError(
"Cycling Attribute not allowed with Cycling Limit Feedforwards",
),
)
end
time_steps = PSI.get_time_steps(container)
resolution = PSI.get_resolution(container)
fraction_of_hour = Dates.value(Dates.Minute(resolution)) / PSI.MINUTES_IN_HOUR
names = [PSY.get_name(d) for d in devices]
discharge_var = PSI.get_variable(container, BatteryDischarge(), D)
ds_served_reg_up =
PSI.get_expression(container, DischargeServedReserveUpExpression(), D)
ds_served_reg_dn =
PSI.get_expression(container, DischargeServedReserveDownExpression(), D)
T = FeedForwardCyclingDischargeConstraint
con_cycling_ds = PSI.add_constraints_container!(container, T(), D, names)
for device in devices
ci_name = PSY.get_name(device)
storage = PSY.get_storage(device)
efficiency = PSY.get_efficiency(storage)
E_max = PSY.get_state_of_charge_limits(storage).max
cycles_per_day = PSY.get_cycle_limits(storage)
cycles_in_horizon =
cycles_per_day * fraction_of_hour * length(time_steps) / HOURS_IN_DAY
if PSI.built_for_recurrent_solves(container)
param_value =
PSI.get_parameter_array(container, CyclingDischargeLimitParameter(), D)[ci_name]
con_cycling_ds[ci_name] = JuMP.@constraint(
PSI.get_jump_model(container),
(1.0 / efficiency.out) *
fraction_of_hour *
sum(
discharge_var[ci_name, :] + ds_served_reg_up[ci_name, :] -
ds_served_reg_dn[ci_name, :],
) <= param_value
)
else
E_max = PSY.get_state_of_charge_limits(storage).max
cycles_per_day = PSY.get_cycle_limits(storage)
cycles_in_horizon =
cycles_per_day * fraction_of_hour * length(time_steps) / HOURS_IN_DAY
con_cycling_ds[ci_name] = JuMP.@constraint(
PSI.get_jump_model(container),
(1.0 / efficiency.out) *
fraction_of_hour *
sum(
discharge_var[ci_name, :] + ds_served_reg_up[ci_name, :] -
ds_served_reg_dn[ci_name, :],
) <= cycles_in_horizon * E_max
)
end
end
return
end

function PSI.update_parameter_values!(
model::PSI.DecisionModel,
key::PSI.ParameterKey{T, U},
Expand Down

0 comments on commit cd6eb6b

Please sign in to comment.