From b4e9635016cc1ee66857a16fdea6a4904393a55a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:13 -0600 Subject: [PATCH 01/26] move code for dependency conflicts --- src/PowerSimulations.jl | 3 ++- src/operation/decision_model.jl | 16 ------------ src/operation/operation_model_interface.jl | 10 -------- .../operation_model_simulation_interface.jl | 25 +++++++++++++++++++ 4 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 src/operation/operation_model_simulation_interface.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 36af71cee2..8048ad7d4f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -511,7 +511,6 @@ include("feedforward/feedforward_arguments.jl") include("feedforward/feedforward_constraints.jl") include("parameters/add_parameters.jl") -include("parameters/update_parameters.jl") include("simulation/optimization_output_cache.jl") include("simulation/optimization_output_caches.jl") @@ -532,6 +531,8 @@ include("simulation/simulation_internal.jl") include("simulation/simulation.jl") include("simulation/simulation_results_export.jl") include("simulation/simulation_results.jl") +include("operation/operation_model_simulation_interface.jl") +include("parameters/update_parameters.jl") include("devices_models/devices/common/objective_function/common.jl") include("devices_models/devices/common/objective_function/linear_curve.jl") diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index b0718de645..1597868dd2 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -558,19 +558,3 @@ function solve!( end return get_run_status(model) end - -function update_parameters!( - model::DecisionModel, - decision_states::DatasetContainer{InMemoryDataset}, -) - cost_function_unsynch(get_optimization_container(model)) - for key in keys(get_parameters(model)) - update_parameter_values!(model, key, decision_states) - end - if !is_synchronized(model) - update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_expression(get_optimization_container(model)) - set_synchronized_status!(obj_func, true) - end - return -end diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 1eb0e8ecc3..4c0bb8a9d0 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -432,16 +432,6 @@ function serialize_optimization_model(model::OperationModel) return end -function update_model!(model::OperationModel, source, ini_cond_chronology) - TimerOutputs.@timeit RUN_SIMULATION_TIMER "Parameter Updates" begin - update_parameters!(model, get_decision_states(source)) - end - TimerOutputs.@timeit RUN_SIMULATION_TIMER "Ini Cond Updates" begin - update_initial_conditions!(model, source, ini_cond_chronology) - end - return -end - function instantiate_network_model(model::OperationModel) template = get_template(model) network_model = get_network_model(template) diff --git a/src/operation/operation_model_simulation_interface.jl b/src/operation/operation_model_simulation_interface.jl new file mode 100644 index 0000000000..99d45c7149 --- /dev/null +++ b/src/operation/operation_model_simulation_interface.jl @@ -0,0 +1,25 @@ +function update_model!(model::OperationModel, source::SimulationState, ini_cond_chronology) + TimerOutputs.@timeit RUN_SIMULATION_TIMER "Parameter Updates" begin + update_parameters!(model, source) + end + TimerOutputs.@timeit RUN_SIMULATION_TIMER "Ini Cond Updates" begin + update_initial_conditions!(model, source, ini_cond_chronology) + end + return +end + +function update_parameters!( + model::DecisionModel, + simulation_state::SimulationState, +) + cost_function_unsynch(get_optimization_container(model)) + for key in keys(get_parameters(model)) + update_parameter_values!(model, key, simulation_state) + end + if !is_synchronized(model) + update_objective_function!(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) + set_synchronized_status!(obj_func, true) + end + return +end From d29cf30f992d47db1ef12bbedab0107545ef7103 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:30 -0600 Subject: [PATCH 02/26] use simulation state in the parameter updating --- src/parameters/update_parameters.jl | 49 +++++++++++++++-------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 64abfa1159..4cf48231fc 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -78,7 +78,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, service::V, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -111,7 +111,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::EmulationModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) template = get_template(model) @@ -147,8 +147,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Device}, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -190,8 +191,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::PSY.Reserve, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -233,8 +235,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{U}, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -340,7 +343,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -348,7 +351,7 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) return end @@ -356,7 +359,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -370,7 +373,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input, + simulation_state, ) return end @@ -379,7 +382,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -393,7 +396,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input, + simulation_state, ) return end @@ -402,13 +405,13 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {U <: PSY.Component} # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end @@ -417,7 +420,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {U <: PSY.Service} # 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 @@ -428,7 +431,7 @@ function update_container_parameter_values!( parameter_attributes, FixValueParameter, model, - input, + simulation_state, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -438,7 +441,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Service} # 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 @@ -446,7 +449,7 @@ function update_container_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(U, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) return end @@ -456,12 +459,12 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin optimization_container = get_optimization_container(model) - update_container_parameter_values!(optimization_container, model, key, input) + update_container_parameter_values!(optimization_container, model, key, simulation_state) parameter_attributes = get_parameter_attributes(optimization_container, key) IS.@record :execution ParameterUpdateEvent( T, @@ -494,7 +497,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{FixValueParameter, T}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: PSY.Service} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -505,7 +508,7 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( FixValueParameter, @@ -524,7 +527,7 @@ function _update_parameter_values!( attributes::CostFunctionAttributes, ::Type{V}, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where {V <: PSY.Component} initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels time_steps = get_time_steps(get_optimization_container(model)) From 798042147c993f252b3c44340f5ec3915eecf1ec Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:13 -0600 Subject: [PATCH 03/26] move code for dependency conflicts --- src/PowerSimulations.jl | 3 ++- src/operation/decision_model.jl | 16 ------------ src/operation/operation_model_interface.jl | 10 -------- .../operation_model_simulation_interface.jl | 25 +++++++++++++++++++ 4 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 src/operation/operation_model_simulation_interface.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 36af71cee2..8048ad7d4f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -511,7 +511,6 @@ include("feedforward/feedforward_arguments.jl") include("feedforward/feedforward_constraints.jl") include("parameters/add_parameters.jl") -include("parameters/update_parameters.jl") include("simulation/optimization_output_cache.jl") include("simulation/optimization_output_caches.jl") @@ -532,6 +531,8 @@ include("simulation/simulation_internal.jl") include("simulation/simulation.jl") include("simulation/simulation_results_export.jl") include("simulation/simulation_results.jl") +include("operation/operation_model_simulation_interface.jl") +include("parameters/update_parameters.jl") include("devices_models/devices/common/objective_function/common.jl") include("devices_models/devices/common/objective_function/linear_curve.jl") diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index b0718de645..1597868dd2 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -558,19 +558,3 @@ function solve!( end return get_run_status(model) end - -function update_parameters!( - model::DecisionModel, - decision_states::DatasetContainer{InMemoryDataset}, -) - cost_function_unsynch(get_optimization_container(model)) - for key in keys(get_parameters(model)) - update_parameter_values!(model, key, decision_states) - end - if !is_synchronized(model) - update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_expression(get_optimization_container(model)) - set_synchronized_status!(obj_func, true) - end - return -end diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 1eb0e8ecc3..4c0bb8a9d0 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -432,16 +432,6 @@ function serialize_optimization_model(model::OperationModel) return end -function update_model!(model::OperationModel, source, ini_cond_chronology) - TimerOutputs.@timeit RUN_SIMULATION_TIMER "Parameter Updates" begin - update_parameters!(model, get_decision_states(source)) - end - TimerOutputs.@timeit RUN_SIMULATION_TIMER "Ini Cond Updates" begin - update_initial_conditions!(model, source, ini_cond_chronology) - end - return -end - function instantiate_network_model(model::OperationModel) template = get_template(model) network_model = get_network_model(template) diff --git a/src/operation/operation_model_simulation_interface.jl b/src/operation/operation_model_simulation_interface.jl new file mode 100644 index 0000000000..99d45c7149 --- /dev/null +++ b/src/operation/operation_model_simulation_interface.jl @@ -0,0 +1,25 @@ +function update_model!(model::OperationModel, source::SimulationState, ini_cond_chronology) + TimerOutputs.@timeit RUN_SIMULATION_TIMER "Parameter Updates" begin + update_parameters!(model, source) + end + TimerOutputs.@timeit RUN_SIMULATION_TIMER "Ini Cond Updates" begin + update_initial_conditions!(model, source, ini_cond_chronology) + end + return +end + +function update_parameters!( + model::DecisionModel, + simulation_state::SimulationState, +) + cost_function_unsynch(get_optimization_container(model)) + for key in keys(get_parameters(model)) + update_parameter_values!(model, key, simulation_state) + end + if !is_synchronized(model) + update_objective_function!(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) + set_synchronized_status!(obj_func, true) + end + return +end From 087aa0840da02ffc2e25e1250f91030ff7d90ad9 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:30 -0600 Subject: [PATCH 04/26] use simulation state in the parameter updating --- src/parameters/update_parameters.jl | 49 +++++++++++++++-------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 64abfa1159..4cf48231fc 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -78,7 +78,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, service::V, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -111,7 +111,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::EmulationModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) template = get_template(model) @@ -147,8 +147,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Device}, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -190,8 +191,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::PSY.Reserve, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -233,8 +235,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{U}, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -340,7 +343,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -348,7 +351,7 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) return end @@ -356,7 +359,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -370,7 +373,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input, + simulation_state, ) return end @@ -379,7 +382,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -393,7 +396,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input, + simulation_state, ) return end @@ -402,13 +405,13 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {U <: PSY.Component} # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end @@ -417,7 +420,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {U <: PSY.Service} # 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 @@ -428,7 +431,7 @@ function update_container_parameter_values!( parameter_attributes, FixValueParameter, model, - input, + simulation_state, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -438,7 +441,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Service} # 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 @@ -446,7 +449,7 @@ function update_container_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(U, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) return end @@ -456,12 +459,12 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin optimization_container = get_optimization_container(model) - update_container_parameter_values!(optimization_container, model, key, input) + update_container_parameter_values!(optimization_container, model, key, simulation_state) parameter_attributes = get_parameter_attributes(optimization_container, key) IS.@record :execution ParameterUpdateEvent( T, @@ -494,7 +497,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{FixValueParameter, T}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: PSY.Service} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -505,7 +508,7 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( FixValueParameter, @@ -524,7 +527,7 @@ function _update_parameter_values!( attributes::CostFunctionAttributes, ::Type{V}, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where {V <: PSY.Component} initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels time_steps = get_time_steps(get_optimization_container(model)) From 328f180caaa2f5e3ee2c462213d691ffd9b06fb8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 9 Sep 2024 13:18:00 -0400 Subject: [PATCH 05/26] add ff test --- src/parameters/update_parameters.jl | 48 +++++++++++++----- test/test_simulation_build.jl | 77 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 4cf48231fc..7d9cda8a7f 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::SimulationState + ::SimulationState, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -343,7 +343,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -351,7 +351,13 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + U, + model, + simulation_state, + ) return end @@ -359,7 +365,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -382,7 +388,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -405,13 +411,19 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {U <: PSY.Component} # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + U, + model, + simulation_state, + ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end @@ -420,7 +432,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {U <: PSY.Service} # 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 @@ -441,7 +453,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ParameterType, U <: PSY.Service} # 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 @@ -449,7 +461,13 @@ function update_container_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(U, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + service, + model, + simulation_state, + ) return end @@ -459,7 +477,7 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -508,7 +526,13 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + service, + model, + simulation_state, + ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( FixValueParameter, diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index d6d4293cab..db4b9e6be2 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -320,3 +320,80 @@ end ) @test !isempty(c) end + +@testset "Test FixValue Feedforwards" begin + template_uc = get_template_basic_uc_simulation() + set_network_model!(template_uc, NetworkModel(PTDFPowerModel; use_slacks = true)) + set_device_model!(template_uc, DeviceModel(Line, StaticBranchUnbounded)) + set_service_model!(template_uc, ServiceModel(VariableReserve{ReserveUp}, RangeReserve)) + template_ed = + get_template_nomin_ed_simulation(NetworkModel(PTDFPowerModel; use_slacks = true)) + set_device_model!(template_ed, DeviceModel(Line, StaticBranchUnbounded)) + set_service_model!(template_ed, ServiceModel(VariableReserve{ReserveUp}, RangeReserve)) + c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_uc"; add_reserves = true) + c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_ed"; add_reserves = true) + models = SimulationModels(; + decision_models = [ + DecisionModel( + template_uc, + c_sys5_hy_uc; + name = "UC", + optimizer = HiGHS_optimizer, + initialize_model = false, + ), + DecisionModel( + template_ed, + c_sys5_hy_ed; + name = "ED", + optimizer = ipopt_optimizer, + initialize_model = false, + ), + ], + ) + + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + "ED" => [ + SemiContinuousFeedforward(; + component_type = ThermalStandard, + source = OnVariable, + affected_values = [ActivePowerVariable], + ), + FixValueFeedforward(; + component_type = VariableReserve{ReserveUp}, + source = ActivePowerReserveVariable, + affected_values = [ActivePowerReserveVariable], + ), + ], + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "reserve_feedforward", + steps = 2, + models = models, + sequence = sequence, + simulation_folder = mktempdir(; cleanup = true), + ) + build_out = build!(sim) + @test build_out == PSI.SimulationBuildStatus.BUILT + ed_power_model = PSI.get_simulation_model(PSI.get_models(sim), :ED) + c = PSI.get_parameter( + PSI.get_optimization_container(ed_power_model), + FixValueParameter(), + VariableReserve{ReserveUp}, + "Reserve1", + ) + @test !isempty(c.multiplier_array) + @test !isempty(c.parameter_array) + c = PSI.get_parameter( + PSI.get_optimization_container(ed_power_model), + FixValueParameter(), + VariableReserve{ReserveUp}, + "Reserve11", + ) + @test !isempty(c.multiplier_array) + @test !isempty(c.parameter_array) +end From ba113d0142bad77d458c092fff9cf9fdf93fb682 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 10:45:04 -0600 Subject: [PATCH 06/26] add keywords to the settings --- src/core/settings.jl | 4 ++++ src/operation/decision_model.jl | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/core/settings.jl b/src/core/settings.jl index d9dd095cbc..063ad1cce0 100644 --- a/src/core/settings.jl +++ b/src/core/settings.jl @@ -16,6 +16,7 @@ struct Settings export_pwl_vars::Bool allow_fails::Bool rebuild_model::Bool + export_optimization_model::Bool store_variable_names::Bool check_numerical_bounds::Bool ext::Dict{String, Any} @@ -41,6 +42,7 @@ function Settings( allow_fails::Bool = false, check_numerical_bounds = true, rebuild_model = false, + export_optimization_model = false, store_variable_names = false, ext = Dict{String, Any}(), ) @@ -77,6 +79,7 @@ function Settings( export_pwl_vars, allow_fails, rebuild_model, + export_optimization_model, store_variable_names, check_numerical_bounds, ext, @@ -151,6 +154,7 @@ get_detailed_optimizer_stats(settings::Settings) = settings.detailed_optimizer_s get_direct_mode_optimizer(settings::Settings) = settings.direct_mode_optimizer get_store_variable_names(settings::Settings) = settings.store_variable_names get_rebuild_model(settings::Settings) = settings.rebuild_model +get_export_optimization_model(settings::Settings) = settings.export_optimization_model use_time_series_cache(settings::Settings) = settings.time_series_cache_size > 0 function set_horizon!(settings::Settings, horizon::Dates.TimePeriod) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index b0718de645..83dfe253d3 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -114,6 +114,7 @@ function DecisionModel{M}( direct_mode_optimizer = false, store_variable_names = false, rebuild_model = false, + export_optimization_model = false, check_numerical_bounds = true, initial_time = UNSET_INI_TIME, time_series_cache_size::Int = IS.TIME_SERIES_CACHE_SIZE_BYTES, @@ -139,6 +140,7 @@ function DecisionModel{M}( check_numerical_bounds = check_numerical_bounds, store_variable_names = store_variable_names, rebuild_model = rebuild_model, + export_optimization_model = export_optimization_model, ) return DecisionModel{M}(template, sys, settings, jump_model; name = name) end @@ -444,7 +446,7 @@ keyword arguments to that function. - `console_level = Logging.Error`: - `file_level = Logging.Info`: - `disable_timer_outputs = false` : Enable/Disable timing outputs - - `serialize::Bool = true`: If true, serialize the model to a file to allow re-execution later. + - `export_optimization_problem::Bool = true`: If true, serialize the model to a file to allow re-execution later. # Examples @@ -459,7 +461,7 @@ function solve!( console_level = Logging.Error, file_level = Logging.Info, disable_timer_outputs = false, - serialize = true, + export_optimization_problem = true, kwargs..., ) build_if_not_already_built!( @@ -500,7 +502,7 @@ function solve!( current_time, ) end - if serialize + if export_optimization_problem TimerOutputs.@timeit RUN_OPERATION_MODEL_TIMER "Serialize" begin serialize_problem(model; optimizer = optimizer) serialize_optimization_model(model) From 02c57b87c8a822ae7f652b3145cd321f5b8158f2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 10:45:17 -0600 Subject: [PATCH 07/26] match interface for em --- src/operation/emulation_model.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index c635cf35b6..079ea31573 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -507,7 +507,7 @@ keyword arguments to that function. - `export_problem_results::Bool`: If true, export OptimizationProblemResults DataFrames to CSV files. - `output_dir::String`: Required if the model is not already built, otherwise ignored - `enable_progress_bar::Bool`: Enables/Disable progress bar printing - - `serialize::Bool`: If true, serialize the model to a file to allow re-execution later. + - `export_optimization_model::Bool`: If true, serialize the model to a file to allow re-execution later. # Examples @@ -522,7 +522,7 @@ function run!( console_level = Logging.Error, file_level = Logging.Info, disable_timer_outputs = false, - serialize = true, + export_optimization_model = true, kwargs..., ) build_if_not_already_built!( @@ -555,7 +555,7 @@ function run!( run_impl!(model; kwargs...) set_run_status!(model, RunStatus.SUCCESSFULLY_FINALIZED) end - if serialize + if export_optimization_model TimerOutputs.@timeit RUN_OPERATION_MODEL_TIMER "Serialize" begin optimizer = get(kwargs, :optimizer, nothing) serialize_problem(model; optimizer = optimizer) From c675fd5e06dbe302081a462fbb1f6ef223e10376 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 10:45:25 -0600 Subject: [PATCH 08/26] add export at each run --- src/operation/operation_model_interface.jl | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 1eb0e8ecc3..e833b5e522 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -104,13 +104,23 @@ end function solve_impl!(model::OperationModel) container = get_optimization_container(model) + model_name = get_name(model) + ts = get_current_timestamp(model) + output_dir = get_output_dir(model) + + if get_export_optimization_model(get_settings(model)) + model_output_dir = joinpath(output_dir, "optimization_model_exports") + if !ispath(model_output_dir) + mkdir(model_output_dir) + end + model_export_path = joinpath(model_output_dir, "exported_$(model_name)_$(ts).json") + serialize_optimization_model(container, model_export_path) + end + status = solve_impl!(container, get_system(model)) set_run_status!(model, status) if status != RunStatus.SUCCESSFULLY_FINALIZED settings = get_settings(model) - model_name = get_name(model) - ts = get_current_timestamp(model) - output_dir = get_output_dir(model) infeasible_opt_path = joinpath(output_dir, "infeasible_$(model_name).json") @error("Serializing Infeasible Problem at $(infeasible_opt_path)") serialize_optimization_model(container, infeasible_opt_path) From a194f20f073c577a1260717a72a6baff49bcb7f1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 10:45:31 -0600 Subject: [PATCH 09/26] add new tests --- test/test_simulation_execute.jl | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/test/test_simulation_execute.jl b/test/test_simulation_execute.jl index 6bc4581769..22b8cbb251 100644 --- a/test/test_simulation_execute.jl +++ b/test/test_simulation_execute.jl @@ -1,4 +1,5 @@ -function test_single_stage_sequential(in_memory, rebuild) +function test_single_stage_sequential(in_memory, rebuild, export_model) + tmp_dir = mktempdir(; cleanup = true) template_ed = get_template_nomin_ed_simulation() c_sys = PSB.build_system(PSITestSystems, "c_sys5_uc") models = SimulationModels([ @@ -8,6 +9,7 @@ function test_single_stage_sequential(in_memory, rebuild) name = "ED", optimizer = ipopt_optimizer, rebuild_model = rebuild, + export_optimization_model = export_model, ), ]) test_sequence = @@ -20,20 +22,29 @@ function test_single_stage_sequential(in_memory, rebuild) steps = 2, models = models, sequence = test_sequence, - simulation_folder = mktempdir(; cleanup = true), + simulation_folder = tmp_dir, ) build_out = build!(sim_single) @test build_out == PSI.SimulationBuildStatus.BUILT execute_out = execute!(sim_single; in_memory = in_memory) @test execute_out == PSI.RunStatus.SUCCESSFULLY_FINALIZED + return tmp_dir end @testset "Single stage sequential tests" begin for in_memory in (true, false), rebuild in (true, false) - test_single_stage_sequential(in_memory, rebuild) + test_single_stage_sequential(in_memory, rebuild, false) end end +@testset "Test model export at each solve" begin + folder = test_single_stage_sequential(true, false, true) + test_path = + joinpath(folder, "consecutive", "problems", "ED", "optimization_model_exports") + @test ispath(test_path) + @test length(readdir(test_path)) == 2 +end + function test_2_stage_decision_models_with_feedforwards(in_memory) template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() From ed9ea74bd0d787c99f8f30b3f8578f5e369f6bd6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 11:04:29 -0600 Subject: [PATCH 10/26] fix em model --- test/test_model_emulation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_model_emulation.jl b/test/test_model_emulation.jl index f824c7ec4b..9688073310 100644 --- a/test/test_model_emulation.jl +++ b/test/test_model_emulation.jl @@ -223,7 +223,7 @@ end model; executions = 10, output_dir = mktempdir(; cleanup = true), - serialize = serialize, + export_optimization_model = serialize, ) == PSI.RunStatus.SUCCESSFULLY_FINALIZED end end From 5855e2b72ff10f750f164af6e4340bc87ed1141f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 12:08:32 -0600 Subject: [PATCH 11/26] replace colon for windows compat --- src/operation/operation_model_interface.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index e833b5e522..1250bcc1ab 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -113,7 +113,8 @@ function solve_impl!(model::OperationModel) if !ispath(model_output_dir) mkdir(model_output_dir) end - model_export_path = joinpath(model_output_dir, "exported_$(model_name)_$(ts).json") + tss = replace!("$(ts)", ":" => "_") + model_export_path = joinpath(model_output_dir, "exported_$(model_name)_$(tss).json") serialize_optimization_model(container, model_export_path) end From 9b1727b23eb0b190cd1a113d0d1c72bcc8707eba Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 13:37:35 -0600 Subject: [PATCH 12/26] remove bang --- src/operation/operation_model_interface.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 1250bcc1ab..0ae14105e0 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -113,7 +113,7 @@ function solve_impl!(model::OperationModel) if !ispath(model_output_dir) mkdir(model_output_dir) end - tss = replace!("$(ts)", ":" => "_") + tss = replace("$(ts)", ":" => "_") model_export_path = joinpath(model_output_dir, "exported_$(model_name)_$(tss).json") serialize_optimization_model(container, model_export_path) end From 0ae7426e50186caee45a984406148e57591711fc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 15:06:19 -0600 Subject: [PATCH 13/26] use mkpath --- src/operation/operation_model_interface.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 0ae14105e0..739648573b 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -111,7 +111,7 @@ function solve_impl!(model::OperationModel) if get_export_optimization_model(get_settings(model)) model_output_dir = joinpath(output_dir, "optimization_model_exports") if !ispath(model_output_dir) - mkdir(model_output_dir) + mkpath(model_output_dir) end tss = replace("$(ts)", ":" => "_") model_export_path = joinpath(model_output_dir, "exported_$(model_name)_$(tss).json") From 2b45701aab6f050b96b62c4aa995b718b25e264a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 11 Sep 2024 15:41:48 -0600 Subject: [PATCH 14/26] remove if condition --- src/operation/operation_model_interface.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 739648573b..10efe61f36 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -110,9 +110,7 @@ function solve_impl!(model::OperationModel) if get_export_optimization_model(get_settings(model)) model_output_dir = joinpath(output_dir, "optimization_model_exports") - if !ispath(model_output_dir) - mkpath(model_output_dir) - end + mkpath(model_output_dir) tss = replace("$(ts)", ":" => "_") model_export_path = joinpath(model_output_dir, "exported_$(model_name)_$(tss).json") serialize_optimization_model(container, model_export_path) From ca977ae3cd6f6bf4f3f42b8822313fbf226e83fa Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 12 Sep 2024 11:22:16 -0600 Subject: [PATCH 15/26] fix tests --- src/operation/emulation_model.jl | 24 +++++++++++++++ src/parameters/update_parameters.jl | 46 ++++++++++++----------------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index c635cf35b6..dd13646253 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -454,6 +454,30 @@ function update_model!( return end +""" +Update parameter function an OperationModel +""" +function update_parameter_values!( + model::EmulationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ParameterType, U <: PSY.Component} + # Enable again for detailed debugging + # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin + optimization_container = get_optimization_container(model) + update_container_parameter_values!(optimization_container, model, key, input) + parameter_attributes = get_parameter_attributes(optimization_container, key) + IS.@record :execution ParameterUpdateEvent( + T, + U, + parameter_attributes, + get_current_timestamp(model), + get_name(model), + ) + #end + return +end + function update_model!(model::EmulationModel) update_model!(model, get_store(model), InterProblemChronology()) return diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 7d9cda8a7f..f9f7654bb3 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::SimulationState, + ::DatasetContainer{InMemoryDataset}, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -78,7 +78,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, service::V, model::DecisionModel, - ::SimulationState, + ::DatasetContainer{InMemoryDataset}, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -111,7 +111,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::EmulationModel, - ::SimulationState, + ::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) template = get_template(model) @@ -147,9 +147,8 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Device}, model::DecisionModel, - simulation_state::SimulationState, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} - state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -191,9 +190,8 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::PSY.Reserve, model::DecisionModel, - simulation_state::SimulationState, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} - state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -235,9 +233,8 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{U}, model::DecisionModel, - simulation_state::SimulationState, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} - state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -343,7 +340,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -351,13 +348,7 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!( - parameter_array, - parameter_attributes, - U, - model, - simulation_state, - ) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) return end @@ -365,7 +356,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -379,7 +370,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - simulation_state, + input ) return end @@ -388,7 +379,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -402,7 +393,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - simulation_state, + input, ) return end @@ -411,7 +402,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {U <: PSY.Component} # 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 @@ -422,7 +413,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - simulation_state, + input, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -432,7 +423,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {U <: PSY.Service} # 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 @@ -443,7 +434,7 @@ function update_container_parameter_values!( parameter_attributes, FixValueParameter, model, - simulation_state, + input, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -482,7 +473,8 @@ function update_parameter_values!( # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin optimization_container = get_optimization_container(model) - update_container_parameter_values!(optimization_container, model, key, simulation_state) + input = get_decision_states(simulation_state) + update_container_parameter_values!(optimization_container, model, key, input) parameter_attributes = get_parameter_attributes(optimization_container, key) IS.@record :execution ParameterUpdateEvent( T, @@ -531,7 +523,7 @@ function update_parameter_values!( parameter_attributes, service, model, - simulation_state, + input, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( From d8cf51ababf6a449aa544621d184dec3662bda5b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 13 Sep 2024 10:48:34 -0600 Subject: [PATCH 16/26] fix parameter passing with the state --- src/PowerSimulations.jl | 2 + .../update_container_parameter_values.jl | 447 +++++++++++++ src/parameters/update_cost_parameters.jl | 125 ++++ src/parameters/update_parameters.jl | 591 +----------------- 4 files changed, 575 insertions(+), 590 deletions(-) create mode 100644 src/parameters/update_container_parameter_values.jl create mode 100644 src/parameters/update_cost_parameters.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 8048ad7d4f..44b9b6a07f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -532,6 +532,8 @@ include("simulation/simulation.jl") include("simulation/simulation_results_export.jl") include("simulation/simulation_results.jl") include("operation/operation_model_simulation_interface.jl") +include("parameters/update_container_parameter_values.jl") +include("parameters/update_cost_parameters.jl") include("parameters/update_parameters.jl") include("devices_models/devices/common/objective_function/common.jl") diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl new file mode 100644 index 0000000000..0c16d621c8 --- /dev/null +++ b/src/parameters/update_container_parameter_values.jl @@ -0,0 +1,447 @@ +function _update_parameter_values!( + ::AbstractArray{T}, + ::NoAttributes, + args..., +) where {T <: Union{Float64, JuMP.VariableRef}} end + +######################## Methods to update Parameters from Time Series ##################### +function _set_param_value!(param::JuMPVariableMatrix, value::Float64, name::String, t::Int) + fix_parameter_value(param[name, t], value) + return +end + +function _set_param_value!( + param::DenseAxisArray{Vector{NTuple{2, Float64}}}, + value::Vector{NTuple{2, Float64}}, + name::String, + t::Int, +) + param[name, t] = value + return +end + +function _set_param_value!(param::JuMPFloatArray, value::Float64, name::String, t::Int) + param[name, t] = value + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::TimeSeriesAttributes{U}, + ::Type{V}, + model::DecisionModel, + ::DatasetContainer{InMemoryDataset}, +) where { + T <: Union{JuMP.VariableRef, Float64}, + U <: PSY.AbstractDeterministic, + V <: PSY.Component, +} + initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels + horizon = get_time_steps(get_optimization_container(model))[end] + ts_name = get_time_series_name(attributes) + multiplier_id = get_time_series_multiplier_id(attributes) + subsystem = get_subsystem(attributes) + template = get_template(model) + if isempty(subsystem) + device_model = get_model(template, V) + else + device_model = get_model(template, V, subsystem) + end + components = get_available_components(device_model, get_system(model)) + ts_uuids = Set{String}() + for component in components + ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) + if !(ts_uuid in ts_uuids) + ts_vector = get_time_series_values!( + U, + model, + component, + ts_name, + multiplier_id, + initial_forecast_time, + horizon, + ) + for (t, value) in enumerate(ts_vector) + if !isfinite(value) + error("The value for the time series $(ts_name) is not finite. \ + Check that the data in the time series is valid.") + end + _set_param_value!(parameter_array, value, ts_uuid, t) + end + push!(ts_uuids, ts_uuid) + end + end +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::TimeSeriesAttributes{U}, + service::V, + model::DecisionModel, + ::DatasetContainer{InMemoryDataset}, +) where { + T <: Union{JuMP.VariableRef, Float64}, + U <: PSY.AbstractDeterministic, + V <: PSY.Service, +} + initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels + horizon = get_time_steps(get_optimization_container(model))[end] + ts_name = get_time_series_name(attributes) + ts_uuid = string(IS.get_time_series_uuid(U, service, ts_name)) + ts_vector = get_time_series_values!( + U, + model, + service, + get_time_series_name(attributes), + get_time_series_multiplier_id(attributes), + initial_forecast_time, + horizon, + ) + for (t, value) in enumerate(ts_vector) + if !isfinite(value) + error("The value for the time series $(ts_name) is not finite. \ + Check that the data in the time series is valid.") + end + _set_param_value!(parameter_array, value, ts_uuid, t) + end +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::TimeSeriesAttributes{U}, + ::Type{V}, + model::EmulationModel, + ::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} + initial_forecast_time = get_current_time(model) + template = get_template(model) + device_model = get_model(template, V) + components = get_available_components(device_model, get_system(model)) + ts_name = get_time_series_name(attributes) + ts_uuids = Set{String}() + for component in components + ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) + if !(ts_uuid in ts_uuids) + # Note: This interface reads one single value per component at a time. + value = get_time_series_values!( + U, + model, + component, + get_time_series_name(attributes), + get_time_series_multiplier_id(attributes), + initial_forecast_time, + )[1] + if !isfinite(value) + error("The value for the time series $(ts_name) is not finite. \ + Check that the data in the time series is valid.") + end + _set_param_value!(parameter_array, value, ts_uuid, 1) + push!(ts_uuids, ts_uuid) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::Type{<:PSY.Device}, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + model_resolution = get_resolution(model) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + if model_resolution < state_data.resolution + t_step = 1 + else + t_step = model_resolution ÷ state_data.resolution + end + state_data_index = find_timestamp_index(state_timestamps, current_time) + sim_timestamps = range(current_time; step = model_resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + t_step) + @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 + # 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(get_attribute_key(attributes))) 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) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::PSY.Reserve, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + model_resolution = get_resolution(model) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + if model_resolution < state_data.resolution + t_step = 1 + else + t_step = model_resolution ÷ state_data.resolution + end + state_data_index = find_timestamp_index(state_timestamps, current_time) + sim_timestamps = range(current_time; step = model_resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + t_step) + @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 + # 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(get_attribute_key(attributes))) 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) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, + ::Type{U}, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + model_resolution = get_resolution(model) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + if model_resolution < state_data.resolution + t_step = 1 + else + t_step = model_resolution ÷ state_data.resolution + end + state_data_index = find_timestamp_index(state_timestamps, current_time) + + sim_timestamps = range(current_time; step = model_resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + t_step) + @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 + # Pass indices in this way since JuMP DenseAxisArray don't support view() + value = round(state_values[name, state_data_index]) + @assert 0.0 <= value <= 1.0 + if !isfinite(value) + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, t) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::Type{<:PSY.Component}, + model::EmulationModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, _ = axes(parameter_array) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + state_data_index = find_timestamp_index(state_timestamps, current_time) + for name in component_names + # Pass indices in this way since JuMP DenseAxisArray don't support view() + _set_param_value!(parameter_array, state_values[name, state_data_index], name, 1) + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, + ::Type{<:PSY.Component}, + model::EmulationModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, _ = axes(parameter_array) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + state_data_index = find_timestamp_index(state_timestamps, current_time) + for name in component_names + # Pass indices in this way since JuMP DenseAxisArray don't support view() + value = round(state_values[name, state_data_index]) + @assert 0.0 <= value <= 1.0 + if !isfinite(value) + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, 1) + end + return +end + +function _update_parameter_values!( + ::AbstractArray{T}, + ::VariableValueAttributes, + ::Type{<:PSY.Component}, + ::EmulationModel, + ::EmulationModelStore, +) where {T <: Union{JuMP.VariableRef, Float64}} + error("The emulation model has parameters that can't be updated from its results") + return +end + +""" +Update parameter function an OperationModel +""" +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ParameterType, U <: PSY.Component} + # Enable again for detailed debugging + # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin + # 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) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} + # 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) + # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function + parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) + parameter_attributes = get_parameter_attributes(optimization_container, key) + _update_parameter_values!( + parameter_array, + parameter_multiplier, + parameter_attributes, + U, + model, + input + ) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} + # 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) + # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function + parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) + parameter_attributes = get_parameter_attributes(optimization_container, key) + _update_parameter_values!( + parameter_array, + parameter_multiplier, + parameter_attributes, + U, + model, + input, + ) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{FixValueParameter, U}, + input::DatasetContainer{InMemoryDataset}, +) where {U <: PSY.Component} + # 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) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{FixValueParameter, U}, + input::DatasetContainer{InMemoryDataset}, +) where {U <: PSY.Service} + # 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) + service = PSY.get_component(U, get_system(model), key.meta) + @assert service !== nothing + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ParameterType, U <: PSY.Service} + # 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) + service = PSY.get_component(U, get_system(model), key.meta) + @assert service !== nothing + _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + return +end diff --git a/src/parameters/update_cost_parameters.jl b/src/parameters/update_cost_parameters.jl new file mode 100644 index 0000000000..600eca675c --- /dev/null +++ b/src/parameters/update_cost_parameters.jl @@ -0,0 +1,125 @@ +function _update_parameter_values!( + parameter_array::DenseAxisArray, + parameter_multiplier::JuMPFloatArray, + attributes::CostFunctionAttributes, + ::Type{V}, + model::DecisionModel, + ::DatasetContainer{InMemoryDataset}, +) where {V <: PSY.Component} + initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels + time_steps = get_time_steps(get_optimization_container(model)) + horizon = time_steps[end] + container = get_optimization_container(model) + @assert !is_synchronized(container) + template = get_template(model) + device_model = get_model(template, V) + components = get_available_components(device_model, get_system(model)) + + for component in components + if _has_variable_cost_parameter(component) + name = PSY.get_name(component) + ts_vector = PSY.get_variable_cost( + component, + PSY.get_operation_cost(component); + start_time = initial_forecast_time, + len = horizon, + ) + variable_cost_forecast_values = TimeSeries.values(ts_vector) + for (t, value) in enumerate(variable_cost_forecast_values) + if attributes.uses_compact_power + # TODO implement this + value, _ = _convert_variable_cost(value) + end + # TODO removed an apparently unused block of code here? + _set_param_value!(parameter_array, value, name, t) + update_variable_cost!( + container, + parameter_array, + parameter_multiplier, + attributes, + component, + t, + ) + end + end + end + return +end + +_has_variable_cost_parameter(component::PSY.Component) = + _has_variable_cost_parameter(PSY.get_operation_cost(component)) +_has_variable_cost_parameter(::PSY.MarketBidCost) = true +_has_variable_cost_parameter(::T) where {T <: PSY.OperationalCost} = false + +function _update_pwl_cost_expression( + container::OptimizationContainer, + ::Type{T}, + component_name::String, + time_period::Int, + cost_data::PSY.PiecewiseLinearData, +) where {T <: PSY.Component} + pwl_var_container = get_variable(container, PieceWiseLinearCostVariable(), T) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + gen_cost = JuMP.AffExpr(0.0) + slopes = PSY.get_slopes(cost_data) + upb = get_breakpoint_upper_bounds(cost_data) + for i in 1:length(cost_data) + JuMP.add_to_expression!( + gen_cost, + slopes[i] * upb[i] * dt * pwl_var_container[(component_name, i, time_period)], + ) + end + return gen_cost +end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::JuMPFloatArray, + parameter_multiplier::JuMPFloatArray, + attributes::CostFunctionAttributes{Float64}, + component::T, + time_period::Int, +) where {T <: PSY.Component} + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + base_power = get_base_power(container) + component_name = PSY.get_name(component) + cost_data = parameter_array[component_name, time_period] # TODO is this a new-style cost? + if iszero(cost_data) + return + end + mult_ = parameter_multiplier[component_name, time_period] + variable = get_variable(container, get_variable_type(attributes)(), T) + gen_cost = variable[component_name, time_period] * mult_ * cost_data * base_power * dt + add_to_objective_variant_expression!(container, gen_cost) + set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) + return +end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::DenseAxisArray{Vector{NTuple{2, Float64}}}, + parameter_multiplier::JuMPFloatArray, + ::CostFunctionAttributes{Vector{NTuple{2, Float64}}}, + component::T, + time_period::Int, +) where {T <: PSY.Component} + component_name = PSY.get_name(component) + cost_data = parameter_array[component_name, time_period] + if all(iszero.(last.(cost_data))) + return + end + mult_ = parameter_multiplier[component_name, time_period] + gen_cost = + _update_pwl_cost_expression( + container, + T, + component_name, + time_period, + PSY.PiecewiseLinearData(cost_data), + ) + add_to_objective_variant_expression!(container, mult_ * gen_cost) + set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) + return +end diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index f9f7654bb3..53e3f4d35b 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -1,467 +1,3 @@ -function _update_parameter_values!( - ::AbstractArray{T}, - ::NoAttributes, - args..., -) where {T <: Union{Float64, JuMP.VariableRef}} end - -######################## Methods to update Parameters from Time Series ##################### -function _set_param_value!(param::JuMPVariableMatrix, value::Float64, name::String, t::Int) - fix_parameter_value(param[name, t], value) - return -end - -function _set_param_value!( - param::DenseAxisArray{Vector{NTuple{2, Float64}}}, - value::Vector{NTuple{2, Float64}}, - name::String, - t::Int, -) - param[name, t] = value - return -end - -function _set_param_value!(param::JuMPFloatArray, value::Float64, name::String, t::Int) - param[name, t] = value - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::TimeSeriesAttributes{U}, - ::Type{V}, - model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, -) where { - T <: Union{JuMP.VariableRef, Float64}, - U <: PSY.AbstractDeterministic, - V <: PSY.Component, -} - initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels - horizon = get_time_steps(get_optimization_container(model))[end] - ts_name = get_time_series_name(attributes) - multiplier_id = get_time_series_multiplier_id(attributes) - subsystem = get_subsystem(attributes) - template = get_template(model) - if isempty(subsystem) - device_model = get_model(template, V) - else - device_model = get_model(template, V, subsystem) - end - components = get_available_components(device_model, get_system(model)) - ts_uuids = Set{String}() - for component in components - ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) - if !(ts_uuid in ts_uuids) - ts_vector = get_time_series_values!( - U, - model, - component, - ts_name, - multiplier_id, - initial_forecast_time, - horizon, - ) - for (t, value) in enumerate(ts_vector) - if !isfinite(value) - error("The value for the time series $(ts_name) is not finite. \ - Check that the data in the time series is valid.") - end - _set_param_value!(parameter_array, value, ts_uuid, t) - end - push!(ts_uuids, ts_uuid) - end - end -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::TimeSeriesAttributes{U}, - service::V, - model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, -) where { - T <: Union{JuMP.VariableRef, Float64}, - U <: PSY.AbstractDeterministic, - V <: PSY.Service, -} - initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels - horizon = get_time_steps(get_optimization_container(model))[end] - ts_name = get_time_series_name(attributes) - ts_uuid = string(IS.get_time_series_uuid(U, service, ts_name)) - ts_vector = get_time_series_values!( - U, - model, - service, - get_time_series_name(attributes), - get_time_series_multiplier_id(attributes), - initial_forecast_time, - horizon, - ) - for (t, value) in enumerate(ts_vector) - if !isfinite(value) - error("The value for the time series $(ts_name) is not finite. \ - Check that the data in the time series is valid.") - end - _set_param_value!(parameter_array, value, ts_uuid, t) - end -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::TimeSeriesAttributes{U}, - ::Type{V}, - model::EmulationModel, - ::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} - initial_forecast_time = get_current_time(model) - template = get_template(model) - device_model = get_model(template, V) - components = get_available_components(device_model, get_system(model)) - ts_name = get_time_series_name(attributes) - ts_uuids = Set{String}() - for component in components - ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) - if !(ts_uuid in ts_uuids) - # Note: This interface reads one single value per component at a time. - value = get_time_series_values!( - U, - model, - component, - get_time_series_name(attributes), - get_time_series_multiplier_id(attributes), - initial_forecast_time, - )[1] - if !isfinite(value) - error("The value for the time series $(ts_name) is not finite. \ - Check that the data in the time series is valid.") - end - _set_param_value!(parameter_array, value, ts_uuid, 1) - push!(ts_uuids, ts_uuid) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes, - ::Type{<:PSY.Device}, - model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, time = axes(parameter_array) - model_resolution = get_resolution(model) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - max_state_index = get_num_rows(state_data) - if model_resolution < state_data.resolution - t_step = 1 - else - t_step = model_resolution ÷ state_data.resolution - end - state_data_index = find_timestamp_index(state_timestamps, current_time) - sim_timestamps = range(current_time; step = model_resolution, length = time[end]) - for t in time - timestamp_ix = min(max_state_index, state_data_index + t_step) - @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 - # 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(get_attribute_key(attributes))) 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) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes, - ::PSY.Reserve, - model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, time = axes(parameter_array) - model_resolution = get_resolution(model) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - max_state_index = get_num_rows(state_data) - if model_resolution < state_data.resolution - t_step = 1 - else - t_step = model_resolution ÷ state_data.resolution - end - state_data_index = find_timestamp_index(state_timestamps, current_time) - sim_timestamps = range(current_time; step = model_resolution, length = time[end]) - for t in time - timestamp_ix = min(max_state_index, state_data_index + t_step) - @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 - # 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(get_attribute_key(attributes))) 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) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, - ::Type{U}, - model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, time = axes(parameter_array) - model_resolution = get_resolution(model) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - max_state_index = get_num_rows(state_data) - if model_resolution < state_data.resolution - t_step = 1 - else - t_step = model_resolution ÷ state_data.resolution - end - state_data_index = find_timestamp_index(state_timestamps, current_time) - - sim_timestamps = range(current_time; step = model_resolution, length = time[end]) - for t in time - timestamp_ix = min(max_state_index, state_data_index + t_step) - @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 - # Pass indices in this way since JuMP DenseAxisArray don't support view() - value = round(state_values[name, state_data_index]) - @assert 0.0 <= value <= 1.0 - if !isfinite(value) - error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, t) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes, - ::Type{<:PSY.Component}, - model::EmulationModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, _ = axes(parameter_array) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - state_data_index = find_timestamp_index(state_timestamps, current_time) - for name in component_names - # Pass indices in this way since JuMP DenseAxisArray don't support view() - _set_param_value!(parameter_array, state_values[name, state_data_index], name, 1) - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, - ::Type{<:PSY.Component}, - model::EmulationModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, _ = axes(parameter_array) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - state_data_index = find_timestamp_index(state_timestamps, current_time) - for name in component_names - # Pass indices in this way since JuMP DenseAxisArray don't support view() - value = round(state_values[name, state_data_index]) - @assert 0.0 <= value <= 1.0 - if !isfinite(value) - error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, 1) - end - return -end - -function _update_parameter_values!( - ::AbstractArray{T}, - ::VariableValueAttributes, - ::Type{<:PSY.Component}, - ::EmulationModel, - ::EmulationModelStore, -) where {T <: Union{JuMP.VariableRef, Float64}} - error("The emulation model has parameters that can't be updated from its results") - return -end - -""" -Update parameter function an OperationModel -""" -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, -) where {T <: ParameterType, U <: PSY.Component} - # Enable again for detailed debugging - # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin - # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, -) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} - # 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) - # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function - parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) - parameter_attributes = get_parameter_attributes(optimization_container, key) - _update_parameter_values!( - parameter_array, - parameter_multiplier, - parameter_attributes, - U, - model, - input - ) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, -) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} - # 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) - # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function - parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) - parameter_attributes = get_parameter_attributes(optimization_container, key) - _update_parameter_values!( - parameter_array, - parameter_multiplier, - parameter_attributes, - U, - model, - input, - ) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, -) where {U <: PSY.Component} - # 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) - _update_parameter_values!( - parameter_array, - parameter_attributes, - U, - model, - input, - ) - _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, -) where {U <: PSY.Service} - # 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) - _update_parameter_values!( - parameter_array, - parameter_attributes, - FixValueParameter, - model, - input, - ) - _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - simulation_state::SimulationState, -) where {T <: ParameterType, U <: PSY.Service} - # 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) - service = PSY.get_component(U, get_system(model), key.meta) - @assert service !== nothing - _update_parameter_values!( - parameter_array, - parameter_attributes, - service, - model, - simulation_state, - ) - return -end - """ Update parameter function an OperationModel """ @@ -518,6 +54,7 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing + input = get_decision_states(simulation_state) _update_parameter_values!( parameter_array, parameter_attributes, @@ -536,129 +73,3 @@ function update_parameter_values!( #end return end - -function _update_parameter_values!( - parameter_array::DenseAxisArray, - parameter_multiplier::JuMPFloatArray, - attributes::CostFunctionAttributes, - ::Type{V}, - model::DecisionModel, - ::SimulationState, -) where {V <: PSY.Component} - initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels - time_steps = get_time_steps(get_optimization_container(model)) - horizon = time_steps[end] - container = get_optimization_container(model) - @assert !is_synchronized(container) - template = get_template(model) - device_model = get_model(template, V) - components = get_available_components(device_model, get_system(model)) - - for component in components - if _has_variable_cost_parameter(component) - name = PSY.get_name(component) - ts_vector = PSY.get_variable_cost( - component, - PSY.get_operation_cost(component); - start_time = initial_forecast_time, - len = horizon, - ) - variable_cost_forecast_values = TimeSeries.values(ts_vector) - for (t, value) in enumerate(variable_cost_forecast_values) - if attributes.uses_compact_power - # TODO implement this - value, _ = _convert_variable_cost(value) - end - # TODO removed an apparently unused block of code here? - _set_param_value!(parameter_array, value, name, t) - update_variable_cost!( - container, - parameter_array, - parameter_multiplier, - attributes, - component, - t, - ) - end - end - end - return -end - -_has_variable_cost_parameter(component::PSY.Component) = - _has_variable_cost_parameter(PSY.get_operation_cost(component)) -_has_variable_cost_parameter(::PSY.MarketBidCost) = true -_has_variable_cost_parameter(::T) where {T <: PSY.OperationalCost} = false - -function _update_pwl_cost_expression( - container::OptimizationContainer, - ::Type{T}, - component_name::String, - time_period::Int, - cost_data::PSY.PiecewiseLinearData, -) where {T <: PSY.Component} - pwl_var_container = get_variable(container, PieceWiseLinearCostVariable(), T) - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - gen_cost = JuMP.AffExpr(0.0) - slopes = PSY.get_slopes(cost_data) - upb = get_breakpoint_upper_bounds(cost_data) - for i in 1:length(cost_data) - JuMP.add_to_expression!( - gen_cost, - slopes[i] * upb[i] * dt * pwl_var_container[(component_name, i, time_period)], - ) - end - return gen_cost -end - -function update_variable_cost!( - container::OptimizationContainer, - parameter_array::JuMPFloatArray, - parameter_multiplier::JuMPFloatArray, - attributes::CostFunctionAttributes{Float64}, - component::T, - time_period::Int, -) where {T <: PSY.Component} - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - base_power = get_base_power(container) - component_name = PSY.get_name(component) - cost_data = parameter_array[component_name, time_period] # TODO is this a new-style cost? - if iszero(cost_data) - return - end - mult_ = parameter_multiplier[component_name, time_period] - variable = get_variable(container, get_variable_type(attributes)(), T) - gen_cost = variable[component_name, time_period] * mult_ * cost_data * base_power * dt - add_to_objective_variant_expression!(container, gen_cost) - set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) - return -end - -function update_variable_cost!( - container::OptimizationContainer, - parameter_array::DenseAxisArray{Vector{NTuple{2, Float64}}}, - parameter_multiplier::JuMPFloatArray, - ::CostFunctionAttributes{Vector{NTuple{2, Float64}}}, - component::T, - time_period::Int, -) where {T <: PSY.Component} - component_name = PSY.get_name(component) - cost_data = parameter_array[component_name, time_period] - if all(iszero.(last.(cost_data))) - return - end - mult_ = parameter_multiplier[component_name, time_period] - gen_cost = - _update_pwl_cost_expression( - container, - T, - component_name, - time_period, - PSY.PiecewiseLinearData(cost_data), - ) - add_to_objective_variant_expression!(container, mult_ * gen_cost) - set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) - return -end From 410f32cc0743f95b61495fe6796e1f8a19c0cf23 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:13 -0600 Subject: [PATCH 17/26] move code for dependency conflicts --- src/PowerSimulations.jl | 3 ++- src/operation/decision_model.jl | 16 ------------ src/operation/operation_model_interface.jl | 10 -------- .../operation_model_simulation_interface.jl | 25 +++++++++++++++++++ 4 files changed, 27 insertions(+), 27 deletions(-) create mode 100644 src/operation/operation_model_simulation_interface.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index e3a3eb9fb9..25a83a1557 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -513,7 +513,6 @@ include("feedforward/feedforward_arguments.jl") include("feedforward/feedforward_constraints.jl") include("parameters/add_parameters.jl") -include("parameters/update_parameters.jl") include("simulation/optimization_output_cache.jl") include("simulation/optimization_output_caches.jl") @@ -534,6 +533,8 @@ include("simulation/simulation_internal.jl") include("simulation/simulation.jl") include("simulation/simulation_results_export.jl") include("simulation/simulation_results.jl") +include("operation/operation_model_simulation_interface.jl") +include("parameters/update_parameters.jl") include("devices_models/devices/common/objective_function/common.jl") include("devices_models/devices/common/objective_function/linear_curve.jl") diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 83dfe253d3..785742ac72 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -560,19 +560,3 @@ function solve!( end return get_run_status(model) end - -function update_parameters!( - model::DecisionModel, - decision_states::DatasetContainer{InMemoryDataset}, -) - cost_function_unsynch(get_optimization_container(model)) - for key in keys(get_parameters(model)) - update_parameter_values!(model, key, decision_states) - end - if !is_synchronized(model) - update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_expression(get_optimization_container(model)) - set_synchronized_status!(obj_func, true) - end - return -end diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 10efe61f36..d2157ee967 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -441,16 +441,6 @@ function serialize_optimization_model(model::OperationModel) return end -function update_model!(model::OperationModel, source, ini_cond_chronology) - TimerOutputs.@timeit RUN_SIMULATION_TIMER "Parameter Updates" begin - update_parameters!(model, get_decision_states(source)) - end - TimerOutputs.@timeit RUN_SIMULATION_TIMER "Ini Cond Updates" begin - update_initial_conditions!(model, source, ini_cond_chronology) - end - return -end - function instantiate_network_model(model::OperationModel) template = get_template(model) network_model = get_network_model(template) diff --git a/src/operation/operation_model_simulation_interface.jl b/src/operation/operation_model_simulation_interface.jl new file mode 100644 index 0000000000..99d45c7149 --- /dev/null +++ b/src/operation/operation_model_simulation_interface.jl @@ -0,0 +1,25 @@ +function update_model!(model::OperationModel, source::SimulationState, ini_cond_chronology) + TimerOutputs.@timeit RUN_SIMULATION_TIMER "Parameter Updates" begin + update_parameters!(model, source) + end + TimerOutputs.@timeit RUN_SIMULATION_TIMER "Ini Cond Updates" begin + update_initial_conditions!(model, source, ini_cond_chronology) + end + return +end + +function update_parameters!( + model::DecisionModel, + simulation_state::SimulationState, +) + cost_function_unsynch(get_optimization_container(model)) + for key in keys(get_parameters(model)) + update_parameter_values!(model, key, simulation_state) + end + if !is_synchronized(model) + update_objective_function!(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) + set_synchronized_status!(obj_func, true) + end + return +end From 5050c16b44db3a5c1f2aeb9c8c037b3b26eb7c3c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:30 -0600 Subject: [PATCH 18/26] use simulation state in the parameter updating --- src/parameters/update_parameters.jl | 49 +++++++++++++++-------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 958cc8e278..98242401fd 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -78,7 +78,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, service::V, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -111,7 +111,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::EmulationModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) template = get_template(model) @@ -147,8 +147,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Device}, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -190,8 +191,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::PSY.Reserve, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -233,8 +235,9 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{U}, model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} + state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -344,7 +347,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -352,7 +355,7 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) return end @@ -360,7 +363,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -374,7 +377,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input, + simulation_state, ) return end @@ -383,7 +386,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -397,7 +400,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input, + simulation_state, ) return end @@ -406,13 +409,13 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {U <: PSY.Component} # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end @@ -421,7 +424,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {U <: PSY.Service} # 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 @@ -432,7 +435,7 @@ function update_container_parameter_values!( parameter_attributes, FixValueParameter, model, - input, + simulation_state, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -442,7 +445,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Service} # 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 @@ -450,7 +453,7 @@ function update_container_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(U, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) return end @@ -460,12 +463,12 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin optimization_container = get_optimization_container(model) - update_container_parameter_values!(optimization_container, model, key, input) + update_container_parameter_values!(optimization_container, model, key, simulation_state) parameter_attributes = get_parameter_attributes(optimization_container, key) IS.@record :execution ParameterUpdateEvent( T, @@ -498,7 +501,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{FixValueParameter, T}, - input::DatasetContainer{InMemoryDataset}, + simulation_state::SimulationState, ) where {T <: PSY.Service} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -509,7 +512,7 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( FixValueParameter, @@ -528,7 +531,7 @@ function _update_parameter_values!( attributes::CostFunctionAttributes, ::Type{V}, model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, + ::SimulationState, ) where {V <: PSY.Component} initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels time_steps = get_time_steps(get_optimization_container(model)) From e02e9ccb7114dcd9371f817843248b7bc7c60c97 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 9 Sep 2024 13:18:00 -0400 Subject: [PATCH 19/26] add ff test --- src/parameters/update_parameters.jl | 48 +++++++++++++----- test/test_simulation_build.jl | 77 +++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 98242401fd..015b0992b4 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::SimulationState + ::SimulationState, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -347,7 +347,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -355,7 +355,13 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + U, + model, + simulation_state, + ) return end @@ -363,7 +369,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -386,7 +392,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -409,13 +415,19 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {U <: PSY.Component} # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + U, + model, + simulation_state, + ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end @@ -424,7 +436,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {U <: PSY.Service} # 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 @@ -445,7 +457,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ParameterType, U <: PSY.Service} # 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 @@ -453,7 +465,13 @@ function update_container_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(U, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + service, + model, + simulation_state, + ) return end @@ -463,7 +481,7 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState + simulation_state::SimulationState, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -512,7 +530,13 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing - _update_parameter_values!(parameter_array, parameter_attributes, service, model, simulation_state) + _update_parameter_values!( + parameter_array, + parameter_attributes, + service, + model, + simulation_state, + ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( FixValueParameter, diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index d6d4293cab..db4b9e6be2 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -320,3 +320,80 @@ end ) @test !isempty(c) end + +@testset "Test FixValue Feedforwards" begin + template_uc = get_template_basic_uc_simulation() + set_network_model!(template_uc, NetworkModel(PTDFPowerModel; use_slacks = true)) + set_device_model!(template_uc, DeviceModel(Line, StaticBranchUnbounded)) + set_service_model!(template_uc, ServiceModel(VariableReserve{ReserveUp}, RangeReserve)) + template_ed = + get_template_nomin_ed_simulation(NetworkModel(PTDFPowerModel; use_slacks = true)) + set_device_model!(template_ed, DeviceModel(Line, StaticBranchUnbounded)) + set_service_model!(template_ed, ServiceModel(VariableReserve{ReserveUp}, RangeReserve)) + c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_uc"; add_reserves = true) + c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_ed"; add_reserves = true) + models = SimulationModels(; + decision_models = [ + DecisionModel( + template_uc, + c_sys5_hy_uc; + name = "UC", + optimizer = HiGHS_optimizer, + initialize_model = false, + ), + DecisionModel( + template_ed, + c_sys5_hy_ed; + name = "ED", + optimizer = ipopt_optimizer, + initialize_model = false, + ), + ], + ) + + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + "ED" => [ + SemiContinuousFeedforward(; + component_type = ThermalStandard, + source = OnVariable, + affected_values = [ActivePowerVariable], + ), + FixValueFeedforward(; + component_type = VariableReserve{ReserveUp}, + source = ActivePowerReserveVariable, + affected_values = [ActivePowerReserveVariable], + ), + ], + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "reserve_feedforward", + steps = 2, + models = models, + sequence = sequence, + simulation_folder = mktempdir(; cleanup = true), + ) + build_out = build!(sim) + @test build_out == PSI.SimulationBuildStatus.BUILT + ed_power_model = PSI.get_simulation_model(PSI.get_models(sim), :ED) + c = PSI.get_parameter( + PSI.get_optimization_container(ed_power_model), + FixValueParameter(), + VariableReserve{ReserveUp}, + "Reserve1", + ) + @test !isempty(c.multiplier_array) + @test !isempty(c.parameter_array) + c = PSI.get_parameter( + PSI.get_optimization_container(ed_power_model), + FixValueParameter(), + VariableReserve{ReserveUp}, + "Reserve11", + ) + @test !isempty(c.multiplier_array) + @test !isempty(c.parameter_array) +end From b17c2a736bd7100d56bfe2b4812d0ca6c7041fdc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 12 Sep 2024 11:22:16 -0600 Subject: [PATCH 20/26] fix tests --- src/operation/emulation_model.jl | 24 +++++++++++++++ src/parameters/update_parameters.jl | 46 ++++++++++++----------------- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 079ea31573..cd42d60ec9 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -454,6 +454,30 @@ function update_model!( return end +""" +Update parameter function an OperationModel +""" +function update_parameter_values!( + model::EmulationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ParameterType, U <: PSY.Component} + # Enable again for detailed debugging + # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin + optimization_container = get_optimization_container(model) + update_container_parameter_values!(optimization_container, model, key, input) + parameter_attributes = get_parameter_attributes(optimization_container, key) + IS.@record :execution ParameterUpdateEvent( + T, + U, + parameter_attributes, + get_current_timestamp(model), + get_name(model), + ) + #end + return +end + function update_model!(model::EmulationModel) update_model!(model, get_store(model), InterProblemChronology()) return diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 015b0992b4..82e5f5c3f9 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -30,7 +30,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::SimulationState, + ::DatasetContainer{InMemoryDataset}, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -78,7 +78,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, service::V, model::DecisionModel, - ::SimulationState, + ::DatasetContainer{InMemoryDataset}, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -111,7 +111,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::EmulationModel, - ::SimulationState, + ::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) template = get_template(model) @@ -147,9 +147,8 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Device}, model::DecisionModel, - simulation_state::SimulationState, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} - state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -191,9 +190,8 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::PSY.Reserve, model::DecisionModel, - simulation_state::SimulationState, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} - state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -235,9 +233,8 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{U}, model::DecisionModel, - simulation_state::SimulationState, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} - state = get_decision_states(simulation_state) current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) @@ -347,7 +344,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -355,13 +352,7 @@ function update_container_parameter_values!( # 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) - _update_parameter_values!( - parameter_array, - parameter_attributes, - U, - model, - simulation_state, - ) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) return end @@ -369,7 +360,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # 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 @@ -383,7 +374,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - simulation_state, + input ) return end @@ -392,7 +383,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{T, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # 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 @@ -406,7 +397,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - simulation_state, + input, ) return end @@ -415,7 +406,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {U <: PSY.Component} # 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 @@ -426,7 +417,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - simulation_state, + input, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -436,7 +427,7 @@ function update_container_parameter_values!( optimization_container::OptimizationContainer, model::OperationModel, key::ParameterKey{FixValueParameter, U}, - simulation_state::SimulationState, + input::DatasetContainer{InMemoryDataset}, ) where {U <: PSY.Service} # 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 @@ -447,7 +438,7 @@ function update_container_parameter_values!( parameter_attributes, FixValueParameter, model, - simulation_state, + input, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return @@ -486,7 +477,8 @@ function update_parameter_values!( # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin optimization_container = get_optimization_container(model) - update_container_parameter_values!(optimization_container, model, key, simulation_state) + input = get_decision_states(simulation_state) + update_container_parameter_values!(optimization_container, model, key, input) parameter_attributes = get_parameter_attributes(optimization_container, key) IS.@record :execution ParameterUpdateEvent( T, @@ -535,7 +527,7 @@ function update_parameter_values!( parameter_attributes, service, model, - simulation_state, + input, ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) IS.@record :execution ParameterUpdateEvent( From e1247dbb324ce1edd843691a8aa736e23fea8e1d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 13 Sep 2024 10:48:34 -0600 Subject: [PATCH 21/26] fix parameter passing with the state --- src/PowerSimulations.jl | 2 + .../update_container_parameter_values.jl | 447 +++++++++++++ src/parameters/update_cost_parameters.jl | 125 ++++ src/parameters/update_parameters.jl | 595 +----------------- 4 files changed, 575 insertions(+), 594 deletions(-) create mode 100644 src/parameters/update_container_parameter_values.jl create mode 100644 src/parameters/update_cost_parameters.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 25a83a1557..f4d882d98d 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -534,6 +534,8 @@ include("simulation/simulation.jl") include("simulation/simulation_results_export.jl") include("simulation/simulation_results.jl") include("operation/operation_model_simulation_interface.jl") +include("parameters/update_container_parameter_values.jl") +include("parameters/update_cost_parameters.jl") include("parameters/update_parameters.jl") include("devices_models/devices/common/objective_function/common.jl") diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl new file mode 100644 index 0000000000..0c16d621c8 --- /dev/null +++ b/src/parameters/update_container_parameter_values.jl @@ -0,0 +1,447 @@ +function _update_parameter_values!( + ::AbstractArray{T}, + ::NoAttributes, + args..., +) where {T <: Union{Float64, JuMP.VariableRef}} end + +######################## Methods to update Parameters from Time Series ##################### +function _set_param_value!(param::JuMPVariableMatrix, value::Float64, name::String, t::Int) + fix_parameter_value(param[name, t], value) + return +end + +function _set_param_value!( + param::DenseAxisArray{Vector{NTuple{2, Float64}}}, + value::Vector{NTuple{2, Float64}}, + name::String, + t::Int, +) + param[name, t] = value + return +end + +function _set_param_value!(param::JuMPFloatArray, value::Float64, name::String, t::Int) + param[name, t] = value + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::TimeSeriesAttributes{U}, + ::Type{V}, + model::DecisionModel, + ::DatasetContainer{InMemoryDataset}, +) where { + T <: Union{JuMP.VariableRef, Float64}, + U <: PSY.AbstractDeterministic, + V <: PSY.Component, +} + initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels + horizon = get_time_steps(get_optimization_container(model))[end] + ts_name = get_time_series_name(attributes) + multiplier_id = get_time_series_multiplier_id(attributes) + subsystem = get_subsystem(attributes) + template = get_template(model) + if isempty(subsystem) + device_model = get_model(template, V) + else + device_model = get_model(template, V, subsystem) + end + components = get_available_components(device_model, get_system(model)) + ts_uuids = Set{String}() + for component in components + ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) + if !(ts_uuid in ts_uuids) + ts_vector = get_time_series_values!( + U, + model, + component, + ts_name, + multiplier_id, + initial_forecast_time, + horizon, + ) + for (t, value) in enumerate(ts_vector) + if !isfinite(value) + error("The value for the time series $(ts_name) is not finite. \ + Check that the data in the time series is valid.") + end + _set_param_value!(parameter_array, value, ts_uuid, t) + end + push!(ts_uuids, ts_uuid) + end + end +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::TimeSeriesAttributes{U}, + service::V, + model::DecisionModel, + ::DatasetContainer{InMemoryDataset}, +) where { + T <: Union{JuMP.VariableRef, Float64}, + U <: PSY.AbstractDeterministic, + V <: PSY.Service, +} + initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels + horizon = get_time_steps(get_optimization_container(model))[end] + ts_name = get_time_series_name(attributes) + ts_uuid = string(IS.get_time_series_uuid(U, service, ts_name)) + ts_vector = get_time_series_values!( + U, + model, + service, + get_time_series_name(attributes), + get_time_series_multiplier_id(attributes), + initial_forecast_time, + horizon, + ) + for (t, value) in enumerate(ts_vector) + if !isfinite(value) + error("The value for the time series $(ts_name) is not finite. \ + Check that the data in the time series is valid.") + end + _set_param_value!(parameter_array, value, ts_uuid, t) + end +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::TimeSeriesAttributes{U}, + ::Type{V}, + model::EmulationModel, + ::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} + initial_forecast_time = get_current_time(model) + template = get_template(model) + device_model = get_model(template, V) + components = get_available_components(device_model, get_system(model)) + ts_name = get_time_series_name(attributes) + ts_uuids = Set{String}() + for component in components + ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) + if !(ts_uuid in ts_uuids) + # Note: This interface reads one single value per component at a time. + value = get_time_series_values!( + U, + model, + component, + get_time_series_name(attributes), + get_time_series_multiplier_id(attributes), + initial_forecast_time, + )[1] + if !isfinite(value) + error("The value for the time series $(ts_name) is not finite. \ + Check that the data in the time series is valid.") + end + _set_param_value!(parameter_array, value, ts_uuid, 1) + push!(ts_uuids, ts_uuid) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::Type{<:PSY.Device}, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + model_resolution = get_resolution(model) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + if model_resolution < state_data.resolution + t_step = 1 + else + t_step = model_resolution ÷ state_data.resolution + end + state_data_index = find_timestamp_index(state_timestamps, current_time) + sim_timestamps = range(current_time; step = model_resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + t_step) + @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 + # 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(get_attribute_key(attributes))) 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) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::PSY.Reserve, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + model_resolution = get_resolution(model) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + if model_resolution < state_data.resolution + t_step = 1 + else + t_step = model_resolution ÷ state_data.resolution + end + state_data_index = find_timestamp_index(state_timestamps, current_time) + sim_timestamps = range(current_time; step = model_resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + t_step) + @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 + # 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(get_attribute_key(attributes))) 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) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, + ::Type{U}, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + model_resolution = get_resolution(model) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + if model_resolution < state_data.resolution + t_step = 1 + else + t_step = model_resolution ÷ state_data.resolution + end + state_data_index = find_timestamp_index(state_timestamps, current_time) + + sim_timestamps = range(current_time; step = model_resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + t_step) + @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 + # Pass indices in this way since JuMP DenseAxisArray don't support view() + value = round(state_values[name, state_data_index]) + @assert 0.0 <= value <= 1.0 + if !isfinite(value) + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, t) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::Type{<:PSY.Component}, + model::EmulationModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, _ = axes(parameter_array) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + state_data_index = find_timestamp_index(state_timestamps, current_time) + for name in component_names + # Pass indices in this way since JuMP DenseAxisArray don't support view() + _set_param_value!(parameter_array, state_values[name, state_data_index], name, 1) + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, + ::Type{<:PSY.Component}, + model::EmulationModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, _ = axes(parameter_array) + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + state_data_index = find_timestamp_index(state_timestamps, current_time) + for name in component_names + # Pass indices in this way since JuMP DenseAxisArray don't support view() + value = round(state_values[name, state_data_index]) + @assert 0.0 <= value <= 1.0 + if !isfinite(value) + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, 1) + end + return +end + +function _update_parameter_values!( + ::AbstractArray{T}, + ::VariableValueAttributes, + ::Type{<:PSY.Component}, + ::EmulationModel, + ::EmulationModelStore, +) where {T <: Union{JuMP.VariableRef, Float64}} + error("The emulation model has parameters that can't be updated from its results") + return +end + +""" +Update parameter function an OperationModel +""" +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ParameterType, U <: PSY.Component} + # Enable again for detailed debugging + # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin + # 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) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} + # 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) + # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function + parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) + parameter_attributes = get_parameter_attributes(optimization_container, key) + _update_parameter_values!( + parameter_array, + parameter_multiplier, + parameter_attributes, + U, + model, + input + ) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} + # 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) + # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function + parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) + parameter_attributes = get_parameter_attributes(optimization_container, key) + _update_parameter_values!( + parameter_array, + parameter_multiplier, + parameter_attributes, + U, + model, + input, + ) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{FixValueParameter, U}, + input::DatasetContainer{InMemoryDataset}, +) where {U <: PSY.Component} + # 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) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{FixValueParameter, U}, + input::DatasetContainer{InMemoryDataset}, +) where {U <: PSY.Service} + # 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) + service = PSY.get_component(U, get_system(model), key.meta) + @assert service !== nothing + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) + _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) + return +end + +function update_container_parameter_values!( + optimization_container::OptimizationContainer, + model::OperationModel, + key::ParameterKey{T, U}, + input::DatasetContainer{InMemoryDataset}, +) where {T <: ParameterType, U <: PSY.Service} + # 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) + service = PSY.get_component(U, get_system(model), key.meta) + @assert service !== nothing + _update_parameter_values!(parameter_array, parameter_attributes, service, model, input) + return +end diff --git a/src/parameters/update_cost_parameters.jl b/src/parameters/update_cost_parameters.jl new file mode 100644 index 0000000000..600eca675c --- /dev/null +++ b/src/parameters/update_cost_parameters.jl @@ -0,0 +1,125 @@ +function _update_parameter_values!( + parameter_array::DenseAxisArray, + parameter_multiplier::JuMPFloatArray, + attributes::CostFunctionAttributes, + ::Type{V}, + model::DecisionModel, + ::DatasetContainer{InMemoryDataset}, +) where {V <: PSY.Component} + initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels + time_steps = get_time_steps(get_optimization_container(model)) + horizon = time_steps[end] + container = get_optimization_container(model) + @assert !is_synchronized(container) + template = get_template(model) + device_model = get_model(template, V) + components = get_available_components(device_model, get_system(model)) + + for component in components + if _has_variable_cost_parameter(component) + name = PSY.get_name(component) + ts_vector = PSY.get_variable_cost( + component, + PSY.get_operation_cost(component); + start_time = initial_forecast_time, + len = horizon, + ) + variable_cost_forecast_values = TimeSeries.values(ts_vector) + for (t, value) in enumerate(variable_cost_forecast_values) + if attributes.uses_compact_power + # TODO implement this + value, _ = _convert_variable_cost(value) + end + # TODO removed an apparently unused block of code here? + _set_param_value!(parameter_array, value, name, t) + update_variable_cost!( + container, + parameter_array, + parameter_multiplier, + attributes, + component, + t, + ) + end + end + end + return +end + +_has_variable_cost_parameter(component::PSY.Component) = + _has_variable_cost_parameter(PSY.get_operation_cost(component)) +_has_variable_cost_parameter(::PSY.MarketBidCost) = true +_has_variable_cost_parameter(::T) where {T <: PSY.OperationalCost} = false + +function _update_pwl_cost_expression( + container::OptimizationContainer, + ::Type{T}, + component_name::String, + time_period::Int, + cost_data::PSY.PiecewiseLinearData, +) where {T <: PSY.Component} + pwl_var_container = get_variable(container, PieceWiseLinearCostVariable(), T) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + gen_cost = JuMP.AffExpr(0.0) + slopes = PSY.get_slopes(cost_data) + upb = get_breakpoint_upper_bounds(cost_data) + for i in 1:length(cost_data) + JuMP.add_to_expression!( + gen_cost, + slopes[i] * upb[i] * dt * pwl_var_container[(component_name, i, time_period)], + ) + end + return gen_cost +end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::JuMPFloatArray, + parameter_multiplier::JuMPFloatArray, + attributes::CostFunctionAttributes{Float64}, + component::T, + time_period::Int, +) where {T <: PSY.Component} + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + base_power = get_base_power(container) + component_name = PSY.get_name(component) + cost_data = parameter_array[component_name, time_period] # TODO is this a new-style cost? + if iszero(cost_data) + return + end + mult_ = parameter_multiplier[component_name, time_period] + variable = get_variable(container, get_variable_type(attributes)(), T) + gen_cost = variable[component_name, time_period] * mult_ * cost_data * base_power * dt + add_to_objective_variant_expression!(container, gen_cost) + set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) + return +end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::DenseAxisArray{Vector{NTuple{2, Float64}}}, + parameter_multiplier::JuMPFloatArray, + ::CostFunctionAttributes{Vector{NTuple{2, Float64}}}, + component::T, + time_period::Int, +) where {T <: PSY.Component} + component_name = PSY.get_name(component) + cost_data = parameter_array[component_name, time_period] + if all(iszero.(last.(cost_data))) + return + end + mult_ = parameter_multiplier[component_name, time_period] + gen_cost = + _update_pwl_cost_expression( + container, + T, + component_name, + time_period, + PSY.PiecewiseLinearData(cost_data), + ) + add_to_objective_variant_expression!(container, mult_ * gen_cost) + set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) + return +end diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 82e5f5c3f9..53e3f4d35b 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -1,471 +1,3 @@ -function _update_parameter_values!( - ::AbstractArray{T}, - ::NoAttributes, - args..., -) where {T <: Union{Float64, JuMP.VariableRef}} end - -######################## Methods to update Parameters from Time Series ##################### -function _set_param_value!(param::JuMPVariableMatrix, value::Float64, name::String, t::Int) - fix_parameter_value(param[name, t], value) - return -end - -function _set_param_value!( - param::DenseAxisArray{Vector{NTuple{2, Float64}}}, - value::Vector{NTuple{2, Float64}}, - name::String, - t::Int, -) - param[name, t] = value - return -end - -function _set_param_value!(param::JuMPFloatArray, value::Float64, name::String, t::Int) - param[name, t] = value - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::TimeSeriesAttributes{U}, - ::Type{V}, - model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, -) where { - T <: Union{JuMP.VariableRef, Float64}, - U <: PSY.AbstractDeterministic, - V <: PSY.Component, -} - initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels - horizon = get_time_steps(get_optimization_container(model))[end] - ts_name = get_time_series_name(attributes) - multiplier_id = get_time_series_multiplier_id(attributes) - subsystem = get_subsystem(attributes) - template = get_template(model) - if isempty(subsystem) - device_model = get_model(template, V) - else - device_model = get_model(template, V, subsystem) - end - components = get_available_components(device_model, get_system(model)) - ts_uuids = Set{String}() - for component in components - ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) - if !(ts_uuid in ts_uuids) - ts_vector = get_time_series_values!( - U, - model, - component, - ts_name, - multiplier_id, - initial_forecast_time, - horizon, - ) - for (t, value) in enumerate(ts_vector) - if !isfinite(value) - error("The value for the time series $(ts_name) is not finite. \ - Check that the data in the time series is valid.") - end - _set_param_value!(parameter_array, value, ts_uuid, t) - end - push!(ts_uuids, ts_uuid) - end - end -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::TimeSeriesAttributes{U}, - service::V, - model::DecisionModel, - ::DatasetContainer{InMemoryDataset}, -) where { - T <: Union{JuMP.VariableRef, Float64}, - U <: PSY.AbstractDeterministic, - V <: PSY.Service, -} - initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels - horizon = get_time_steps(get_optimization_container(model))[end] - ts_name = get_time_series_name(attributes) - ts_uuid = string(IS.get_time_series_uuid(U, service, ts_name)) - ts_vector = get_time_series_values!( - U, - model, - service, - get_time_series_name(attributes), - get_time_series_multiplier_id(attributes), - initial_forecast_time, - horizon, - ) - for (t, value) in enumerate(ts_vector) - if !isfinite(value) - error("The value for the time series $(ts_name) is not finite. \ - Check that the data in the time series is valid.") - end - _set_param_value!(parameter_array, value, ts_uuid, t) - end -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::TimeSeriesAttributes{U}, - ::Type{V}, - model::EmulationModel, - ::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} - initial_forecast_time = get_current_time(model) - template = get_template(model) - device_model = get_model(template, V) - components = get_available_components(device_model, get_system(model)) - ts_name = get_time_series_name(attributes) - ts_uuids = Set{String}() - for component in components - ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) - if !(ts_uuid in ts_uuids) - # Note: This interface reads one single value per component at a time. - value = get_time_series_values!( - U, - model, - component, - get_time_series_name(attributes), - get_time_series_multiplier_id(attributes), - initial_forecast_time, - )[1] - if !isfinite(value) - error("The value for the time series $(ts_name) is not finite. \ - Check that the data in the time series is valid.") - end - _set_param_value!(parameter_array, value, ts_uuid, 1) - push!(ts_uuids, ts_uuid) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes, - ::Type{<:PSY.Device}, - model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, time = axes(parameter_array) - model_resolution = get_resolution(model) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - max_state_index = get_num_rows(state_data) - if model_resolution < state_data.resolution - t_step = 1 - else - t_step = model_resolution ÷ state_data.resolution - end - state_data_index = find_timestamp_index(state_timestamps, current_time) - sim_timestamps = range(current_time; step = model_resolution, length = time[end]) - for t in time - timestamp_ix = min(max_state_index, state_data_index + t_step) - @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 - # 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(get_attribute_key(attributes))) 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) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes, - ::PSY.Reserve, - model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, time = axes(parameter_array) - model_resolution = get_resolution(model) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - max_state_index = get_num_rows(state_data) - if model_resolution < state_data.resolution - t_step = 1 - else - t_step = model_resolution ÷ state_data.resolution - end - state_data_index = find_timestamp_index(state_timestamps, current_time) - sim_timestamps = range(current_time; step = model_resolution, length = time[end]) - for t in time - timestamp_ix = min(max_state_index, state_data_index + t_step) - @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 - # 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(get_attribute_key(attributes))) 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) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, - ::Type{U}, - model::DecisionModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, time = axes(parameter_array) - model_resolution = get_resolution(model) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - max_state_index = get_num_rows(state_data) - if model_resolution < state_data.resolution - t_step = 1 - else - t_step = model_resolution ÷ state_data.resolution - end - state_data_index = find_timestamp_index(state_timestamps, current_time) - - sim_timestamps = range(current_time; step = model_resolution, length = time[end]) - for t in time - timestamp_ix = min(max_state_index, state_data_index + t_step) - @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 - # Pass indices in this way since JuMP DenseAxisArray don't support view() - value = round(state_values[name, state_data_index]) - if !isfinite(value) - error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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 - if 0.0 > value || value > 1.0 - error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range", - ) - end - _set_param_value!(parameter_array, value, name, t) - end - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes, - ::Type{<:PSY.Component}, - model::EmulationModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, _ = axes(parameter_array) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - state_data_index = find_timestamp_index(state_timestamps, current_time) - for name in component_names - # Pass indices in this way since JuMP DenseAxisArray don't support view() - _set_param_value!(parameter_array, state_values[name, state_data_index], name, 1) - end - return -end - -function _update_parameter_values!( - parameter_array::AbstractArray{T}, - attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, - ::Type{<:PSY.Component}, - model::EmulationModel, - state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} - current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) - component_names, _ = axes(parameter_array) - state_data = get_dataset(state, get_attribute_key(attributes)) - state_timestamps = state_data.timestamps - state_data_index = find_timestamp_index(state_timestamps, current_time) - for name in component_names - # Pass indices in this way since JuMP DenseAxisArray don't support view() - value = round(state_values[name, state_data_index]) - @assert 0.0 <= value <= 1.0 - if !isfinite(value) - error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(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, value, name, 1) - end - return -end - -function _update_parameter_values!( - ::AbstractArray{T}, - ::VariableValueAttributes, - ::Type{<:PSY.Component}, - ::EmulationModel, - ::EmulationModelStore, -) where {T <: Union{JuMP.VariableRef, Float64}} - error("The emulation model has parameters that can't be updated from its results") - return -end - -""" -Update parameter function an OperationModel -""" -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, -) where {T <: ParameterType, U <: PSY.Component} - # Enable again for detailed debugging - # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin - # 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) - _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, -) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} - # 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) - # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function - parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) - parameter_attributes = get_parameter_attributes(optimization_container, key) - _update_parameter_values!( - parameter_array, - parameter_multiplier, - parameter_attributes, - U, - model, - input - ) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - input::DatasetContainer{InMemoryDataset}, -) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} - # 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) - # Multiplier is only needed for the objective function since `_update_parameter_values!` also updates the objective function - parameter_multiplier = get_parameter_multiplier_array(optimization_container, key) - parameter_attributes = get_parameter_attributes(optimization_container, key) - _update_parameter_values!( - parameter_array, - parameter_multiplier, - parameter_attributes, - U, - model, - input, - ) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, -) where {U <: PSY.Component} - # 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) - _update_parameter_values!( - parameter_array, - parameter_attributes, - U, - model, - input, - ) - _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{FixValueParameter, U}, - input::DatasetContainer{InMemoryDataset}, -) where {U <: PSY.Service} - # 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) - _update_parameter_values!( - parameter_array, - parameter_attributes, - FixValueParameter, - model, - input, - ) - _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) - return -end - -function update_container_parameter_values!( - optimization_container::OptimizationContainer, - model::OperationModel, - key::ParameterKey{T, U}, - simulation_state::SimulationState, -) where {T <: ParameterType, U <: PSY.Service} - # 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) - service = PSY.get_component(U, get_system(model), key.meta) - @assert service !== nothing - _update_parameter_values!( - parameter_array, - parameter_attributes, - service, - model, - simulation_state, - ) - return -end - """ Update parameter function an OperationModel """ @@ -522,6 +54,7 @@ function update_parameter_values!( parameter_attributes = get_parameter_attributes(optimization_container, key) service = PSY.get_component(T, get_system(model), key.meta) @assert service !== nothing + input = get_decision_states(simulation_state) _update_parameter_values!( parameter_array, parameter_attributes, @@ -540,129 +73,3 @@ function update_parameter_values!( #end return end - -function _update_parameter_values!( - parameter_array::DenseAxisArray, - parameter_multiplier::JuMPFloatArray, - attributes::CostFunctionAttributes, - ::Type{V}, - model::DecisionModel, - ::SimulationState, -) where {V <: PSY.Component} - initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels - time_steps = get_time_steps(get_optimization_container(model)) - horizon = time_steps[end] - container = get_optimization_container(model) - @assert !is_synchronized(container) - template = get_template(model) - device_model = get_model(template, V) - components = get_available_components(device_model, get_system(model)) - - for component in components - if _has_variable_cost_parameter(component) - name = PSY.get_name(component) - ts_vector = PSY.get_variable_cost( - component, - PSY.get_operation_cost(component); - start_time = initial_forecast_time, - len = horizon, - ) - variable_cost_forecast_values = TimeSeries.values(ts_vector) - for (t, value) in enumerate(variable_cost_forecast_values) - if attributes.uses_compact_power - # TODO implement this - value, _ = _convert_variable_cost(value) - end - # TODO removed an apparently unused block of code here? - _set_param_value!(parameter_array, value, name, t) - update_variable_cost!( - container, - parameter_array, - parameter_multiplier, - attributes, - component, - t, - ) - end - end - end - return -end - -_has_variable_cost_parameter(component::PSY.Component) = - _has_variable_cost_parameter(PSY.get_operation_cost(component)) -_has_variable_cost_parameter(::PSY.MarketBidCost) = true -_has_variable_cost_parameter(::T) where {T <: PSY.OperationalCost} = false - -function _update_pwl_cost_expression( - container::OptimizationContainer, - ::Type{T}, - component_name::String, - time_period::Int, - cost_data::PSY.PiecewiseLinearData, -) where {T <: PSY.Component} - pwl_var_container = get_variable(container, PieceWiseLinearCostVariable(), T) - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - gen_cost = JuMP.AffExpr(0.0) - slopes = PSY.get_slopes(cost_data) - upb = get_breakpoint_upper_bounds(cost_data) - for i in 1:length(cost_data) - JuMP.add_to_expression!( - gen_cost, - slopes[i] * upb[i] * dt * pwl_var_container[(component_name, i, time_period)], - ) - end - return gen_cost -end - -function update_variable_cost!( - container::OptimizationContainer, - parameter_array::JuMPFloatArray, - parameter_multiplier::JuMPFloatArray, - attributes::CostFunctionAttributes{Float64}, - component::T, - time_period::Int, -) where {T <: PSY.Component} - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - base_power = get_base_power(container) - component_name = PSY.get_name(component) - cost_data = parameter_array[component_name, time_period] # TODO is this a new-style cost? - if iszero(cost_data) - return - end - mult_ = parameter_multiplier[component_name, time_period] - variable = get_variable(container, get_variable_type(attributes)(), T) - gen_cost = variable[component_name, time_period] * mult_ * cost_data * base_power * dt - add_to_objective_variant_expression!(container, gen_cost) - set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) - return -end - -function update_variable_cost!( - container::OptimizationContainer, - parameter_array::DenseAxisArray{Vector{NTuple{2, Float64}}}, - parameter_multiplier::JuMPFloatArray, - ::CostFunctionAttributes{Vector{NTuple{2, Float64}}}, - component::T, - time_period::Int, -) where {T <: PSY.Component} - component_name = PSY.get_name(component) - cost_data = parameter_array[component_name, time_period] - if all(iszero.(last.(cost_data))) - return - end - mult_ = parameter_multiplier[component_name, time_period] - gen_cost = - _update_pwl_cost_expression( - container, - T, - component_name, - time_period, - PSY.PiecewiseLinearData(cost_data), - ) - add_to_objective_variant_expression!(container, mult_ * gen_cost) - set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) - return -end From 0d3bb47209902f47577f8c12e184311fc49e0475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Henr=C3=ADquez-Auba?= Date: Fri, 13 Sep 2024 12:03:17 -0700 Subject: [PATCH 22/26] Update src/parameters/update_container_parameter_values.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/parameters/update_container_parameter_values.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl index 0c16d621c8..c900ff5f3a 100644 --- a/src/parameters/update_container_parameter_values.jl +++ b/src/parameters/update_container_parameter_values.jl @@ -370,7 +370,7 @@ function update_container_parameter_values!( parameter_attributes, U, model, - input + input, ) return end From 683e431325f83cf9ea944840d94ee4a015e9b9f2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 17 Sep 2024 14:16:17 -0600 Subject: [PATCH 23/26] param updating --- .../operation_model_simulation_interface.jl | 6 ++++++ src/parameters/update_container_parameter_values.jl | 12 +++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/operation/operation_model_simulation_interface.jl b/src/operation/operation_model_simulation_interface.jl index 99d45c7149..e857af8eb3 100644 --- a/src/operation/operation_model_simulation_interface.jl +++ b/src/operation/operation_model_simulation_interface.jl @@ -8,6 +8,12 @@ function update_model!(model::OperationModel, source::SimulationState, ini_cond_ return end +function update_parameters!(model::EmulationModel, state::SimulationState) + data = get_system_states(state) + update_parameters!(model, data) + return +end + function update_parameters!( model::DecisionModel, simulation_state::SimulationState, diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl index c900ff5f3a..7d78a777e1 100644 --- a/src/parameters/update_container_parameter_values.jl +++ b/src/parameters/update_container_parameter_values.jl @@ -259,7 +259,6 @@ function _update_parameter_values!( for name in component_names # Pass indices in this way since JuMP DenseAxisArray don't support view() value = round(state_values[name, state_data_index]) - @assert 0.0 <= value <= 1.0 if !isfinite(value) error( "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(value) \ @@ -267,6 +266,10 @@ function _update_parameter_values!( Consider reviewing your models' horizon and interval definitions", ) end + if 0.0 > value || value > 1.0 + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range") + end _set_param_value!(parameter_array, value, name, t) end end @@ -309,7 +312,6 @@ function _update_parameter_values!( for name in component_names # Pass indices in this way since JuMP DenseAxisArray don't support view() value = round(state_values[name, state_data_index]) - @assert 0.0 <= value <= 1.0 if !isfinite(value) error( "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(value) \ @@ -317,7 +319,11 @@ function _update_parameter_values!( Consider reviewing your models' horizon and interval definitions", ) end - _set_param_value!(parameter_array, value, name, 1) + if 0.0 > value || value > 1.0 + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range") + end + _set_param_value!(parameter_array, value, name, t) end return end From 244a857b545ccf966887863c6a70975dccef6b97 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 17 Sep 2024 16:01:00 -0600 Subject: [PATCH 24/26] formatter --- src/parameters/update_container_parameter_values.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl index 7d78a777e1..a61e7bdf05 100644 --- a/src/parameters/update_container_parameter_values.jl +++ b/src/parameters/update_container_parameter_values.jl @@ -268,7 +268,8 @@ function _update_parameter_values!( end if 0.0 > value || value > 1.0 error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range") + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range", + ) end _set_param_value!(parameter_array, value, name, t) end @@ -304,7 +305,7 @@ function _update_parameter_values!( state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} current_time = get_current_time(model) - state_values = get_dataset_values(state, get_attribute_key(attributes)) + @show state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, _ = axes(parameter_array) state_data = get_dataset(state, get_attribute_key(attributes)) state_timestamps = state_data.timestamps @@ -321,7 +322,8 @@ function _update_parameter_values!( end if 0.0 > value || value > 1.0 error( - "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range") + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range", + ) end _set_param_value!(parameter_array, value, name, t) end From 1b099061a3631d66a6a35759aedef72012ac83c7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 20 Sep 2024 19:25:53 -0600 Subject: [PATCH 25/26] fix emulation model updating --- src/operation/operation_model_simulation_interface.jl | 2 +- src/parameters/update_container_parameter_values.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operation/operation_model_simulation_interface.jl b/src/operation/operation_model_simulation_interface.jl index e857af8eb3..3ec50b2c92 100644 --- a/src/operation/operation_model_simulation_interface.jl +++ b/src/operation/operation_model_simulation_interface.jl @@ -9,7 +9,7 @@ function update_model!(model::OperationModel, source::SimulationState, ini_cond_ end function update_parameters!(model::EmulationModel, state::SimulationState) - data = get_system_states(state) + data = get_decision_states(state) update_parameters!(model, data) return end diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl index a61e7bdf05..5784c0964f 100644 --- a/src/parameters/update_container_parameter_values.jl +++ b/src/parameters/update_container_parameter_values.jl @@ -305,7 +305,7 @@ function _update_parameter_values!( state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} current_time = get_current_time(model) - @show state_values = get_dataset_values(state, get_attribute_key(attributes)) + state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, _ = axes(parameter_array) state_data = get_dataset(state, get_attribute_key(attributes)) state_timestamps = state_data.timestamps @@ -325,7 +325,7 @@ function _update_parameter_values!( "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))): $(value) is out of the [0, 1] range", ) end - _set_param_value!(parameter_array, value, name, t) + _set_param_value!(parameter_array, value, name, 1) end return end From f6375053af0b6191dc8f59d14d54e559f1a1b53e Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 23 Sep 2024 13:08:56 -0600 Subject: [PATCH 26/26] bump pnm version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 01523f9175..53a901c19e 100644 --- a/Project.toml +++ b/Project.toml @@ -45,7 +45,7 @@ LinearAlgebra = "1" Logging = "1" MathOptInterface = "1" PowerModels = "^0.21" -PowerNetworkMatrices = "^0.11" +PowerNetworkMatrices = "^0.11.1" PowerSystems = "4" PrettyTables = "2" ProgressMeter = "^1.5"