Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jd/move energy limit ff out #1014

Merged
merged 4 commits into from
Oct 25, 2023
Merged
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
9 changes: 1 addition & 8 deletions src/core/parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,8 @@ Parameter to define unit commitment status
struct OnStatusParameter <: VariableValueParameter end

"""
Parameter to define energy limit
Parameter to FixValueParameter
"""
struct EnergyLimitParameter <: VariableValueParameter end
# TODO: Check if EnergyTargetParameter and EnergyLimitParameter should be removed
# This affects feedforwards that can break if not defined
struct EnergyTargetParameter <: VariableValueParameter end
struct FixValueParameter <: VariableValueParameter end

"""
Expand All @@ -324,6 +320,3 @@ convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true
convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true
convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true
convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true
# TODO: Check if EnergyLimitParameter and EnergyTargetParameter should be removed
convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true
convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true
71 changes: 0 additions & 71 deletions src/feedforward/feedforward_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -422,77 +422,6 @@ function add_feedforward_constraints!(
return
end

@doc raw"""
add_feedforward_constraints(container::OptimizationContainer,
cons_name::Symbol,
param_reference,
var_key::VariableKey)

Constructs a parameterized integral limit constraint to implement feedforward from other models.
The Parameters are initialized using the upper boundary values of the provided variables.


``` sum(variable[var_name, t] for t in 1:affected_periods)/affected_periods <= param_reference[var_name] ```

# LaTeX

`` \sum_{t} x \leq param^{max}``

# Arguments
* container::OptimizationContainer : the optimization_container model built in PowerSimulations
* model::DeviceModel : the device model
* devices::IS.FlattenIteratorWrapper{T} : list of devices
* ff::FixValueFeedforward : a instance of the FixValue Feedforward
"""
function add_feedforward_constraints!(
container::OptimizationContainer,
::DeviceModel,
devices::IS.FlattenIteratorWrapper{T},
ff::EnergyLimitFeedforward,
) where {T <: PSY.Component}
time_steps = get_time_steps(container)
parameter_type = get_default_parameter_type(ff, T)
param = get_parameter_array(container, parameter_type(), T)
multiplier = get_parameter_multiplier_array(container, parameter_type(), T)
affected_periods = get_number_of_periods(ff)
for var in get_affected_values(ff)
variable = get_variable(container, var)
set_name, set_time = JuMP.axes(variable)
IS.@assert_op set_name == [PSY.get_name(d) for d in devices]
IS.@assert_op set_time == time_steps

if affected_periods > set_time[end]
error(
"The number of affected periods $affected_periods is larger than the periods available $(set_time[end])",
)
end
no_trenches = set_time[end] ÷ affected_periods
var_type = get_entry_type(var)
con_ub = add_constraints_container!(
container,
FeedforwardIntegralLimitConstraint(),
T,
set_name,
1:no_trenches;
meta = "$(var_type)integral",
)

for name in set_name, i in 1:no_trenches
con_ub[name, i] = JuMP.@constraint(
container.JuMPmodel,
sum(
variable[name, t] for
t in (1 + (i - 1) * affected_periods):(i * affected_periods)
) <= sum(
param[name, t] * multiplier[name, t] for
t in (1 + (i - 1) * affected_periods):(i * affected_periods)
)
)
end
end
return
end

@doc raw"""
add_feedforward_constraints(
container::OptimizationContainer,
Expand Down
76 changes: 0 additions & 76 deletions src/feedforward/feedforwards.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,43 +202,6 @@ function has_semicontinuous_feedforward(
return has_semicontinuous_feedforward(model, ActivePowerVariable)
end

"""
Adds a constraint to limit the sum of a variable over the number of periods to the source value
"""
struct EnergyLimitFeedforward <: AbstractAffectFeedforward
optimization_container_key::OptimizationContainerKey
affected_values::Vector{<:OptimizationContainerKey}
number_of_periods::Int
function EnergyLimitFeedforward(;
component_type::Type{<:PSY.Component},
source::Type{T},
affected_values::Vector{DataType},
number_of_periods::Int,
meta = CONTAINER_KEY_EMPTY_META,
) where {T}
values_vector = Vector{VariableKey}(undef, length(affected_values))
for (ix, v) in enumerate(affected_values)
if v <: VariableType
values_vector[ix] =
get_optimization_container_key(v(), component_type, meta)
else
error(
"EnergyLimitFeedforward is only compatible with VariableType or ParamterType affected values",
)
end
end
new(
get_optimization_container_key(T(), component_type, meta),
values_vector,
number_of_periods,
)
end
end

get_default_parameter_type(::EnergyLimitFeedforward, _) = EnergyLimitParameter
get_optimization_container_key(ff) = ff.optimization_container_key
get_number_of_periods(ff) = ff.number_of_periods

"""
Fixes a Variable or Parameter Value in the model. Is the only Feed Forward that can be used
with a Parameter or a Variable as the affected value.
Expand Down Expand Up @@ -269,42 +232,3 @@ end

get_default_parameter_type(::FixValueFeedforward, _) = FixValueParameter
get_optimization_container_key(ff::FixValueFeedforward) = ff.optimization_container_key

"""
Adds a constraint to enforce a minimum energy level target with a slack variable associated witha penalty term.
"""
struct EnergyTargetFeedforward <: AbstractAffectFeedforward
optimization_container_key::OptimizationContainerKey
affected_values::Vector{<:OptimizationContainerKey}
target_period::Int
penalty_cost::Float64
function EnergyTargetFeedforward(;
component_type::Type{<:PSY.Component},
source::Type{T},
affected_values::Vector{DataType},
target_period::Int,
penalty_cost::Float64,
meta = CONTAINER_KEY_EMPTY_META,
) where {T}
values_vector = Vector{VariableKey}(undef, length(affected_values))
for (ix, v) in enumerate(affected_values)
if v <: VariableType
values_vector[ix] =
get_optimization_container_key(v(), component_type, meta)
else
error(
"EnergyTargetFeedforward is only compatible with VariableType or ParamterType affected values",
)
end
end
new(
get_optimization_container_key(T(), component_type, meta),
values_vector,
target_period,
penalty_cost,
)
end
end

get_default_parameter_type(::EnergyTargetFeedforward, _) = EnergyTargetParameter
get_optimization_container_key(ff::EnergyTargetFeedforward) = ff.optimization_container_key
82 changes: 0 additions & 82 deletions src/parameters/update_parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -428,88 +428,6 @@ function update_parameter_values!(
return
end

function update_parameter_values!(
model::OperationModel,
key::ParameterKey{T, U},
input::DatasetContainer{InMemoryDataset},
) where {T <: EnergyLimitParameter, U <: PSY.Generator}
# Enable again for detailed debugging
# TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin
optimization_container = get_optimization_container(model)
# Note: Do not instantite a new key here because it might not match the param keys in the container
# if the keys have strings in the meta fields
parameter_array = get_parameter_array(optimization_container, key)
parameter_attributes = get_parameter_attributes(optimization_container, key)
internal = get_internal(model)
execution_count = internal.execution_count
current_time = get_current_time(model)
state_values = get_dataset_values(input, get_attribute_key(parameter_attributes))
component_names, time = axes(parameter_array)
resolution = get_resolution(model)
interval_time_steps = Int(get_interval(model.internal.store_parameters) / resolution)
state_data = get_dataset(input, get_attribute_key(parameter_attributes))
state_timestamps = state_data.timestamps
max_state_index = get_num_rows(state_data)

state_data_index = find_timestamp_index(state_timestamps, current_time)
sim_timestamps = range(current_time; step = resolution, length = time[end])
old_parameter_values = jump_value.(parameter_array)
# The current method uses older parameter values because when passing the energy output from one stage
# to the next, the aux variable values gets over-written by the lower level model after its solve.
# This approach is a temporary hack and will be replaced in future versions.
for t in time
timestamp_ix = min(max_state_index, state_data_index + 1)
@debug "parameter horizon is over the step" max_state_index > state_data_index + 1
if state_timestamps[timestamp_ix] <= sim_timestamps[t]
state_data_index = timestamp_ix
end
for name in component_names
# the if statement checks if its the first solve of the model and uses the values stored in the state
# and for subsequent solves uses the state data to update the parameter values for the last set of time periods
# that are equal to the length of the interval i.e. the time periods that dont overlap between each solves.
if execution_count == 0 || t > time[end] - interval_time_steps
# Pass indices in this way since JuMP DenseAxisArray don't support view()
state_value = state_values[name, state_data_index]
if !isfinite(state_value)
error(
"The value for the system state used in $(encode_key_as_string(key)) is not a finite value $(state_value) \
This is commonly caused by referencing a state value at a time when such decision hasn't been made. \
Consider reviewing your models' horizon and interval definitions",
)
end
_set_param_value!(parameter_array, state_value, name, t)
else
# Currently the update method relies on using older parameter values of the EnergyLimitParameter
# to update the parameter for overlapping periods between solves i.e. we ingoring the parameter values
# in the model interval time periods.
state_value = state_values[name, state_data_index]
if !isfinite(state_value)
error(
"The value for the system state used in $(encode_key_as_string(key)) is not a finite value $(state_value) \
This is commonly caused by referencing a state value at a time when such decision hasn't been made. \
Consider reviewing your models' horizon and interval definitions",
)
end
_set_param_value!(
parameter_array,
old_parameter_values[name, t + interval_time_steps],
name,
t,
)
end
end
end

IS.@record :execution ParameterUpdateEvent(
T,
U,
parameter_attributes,
get_current_timestamp(model),
get_name(model),
)
return
end

"""
Update parameter function an OperationModel
"""
Expand Down
Loading