From bc66c61e3f6601f26b295b6e77dab5788c149ba8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 16 Jul 2024 17:24:06 -0600 Subject: [PATCH 01/62] allow inter-area models for other network models --- .../device_constructors/branch_constructor.jl | 7 +++---- src/devices_models/devices/area_interchange.jl | 4 ++-- src/devices_models/devices/common/add_to_expression.jl | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index baa4768200..7e6b909919 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -867,9 +867,8 @@ function construct_device!( ::PSY.System, ::ArgumentConstructStage, model::DeviceModel{PSY.AreaInterchange, U}, - network_model::NetworkModel{T}, -) where {T <: PM.AbstractPowerModel, U <: Union{StaticBranchUnbounded, StaticBranch}} - error("AreaInterchange is not yet implemented for $T") + network_model::NetworkModel{CopperPlatePowerModel}, +) where {U <: Union{StaticBranchUnbounded, StaticBranch}} return end @@ -881,7 +880,7 @@ function construct_device!( network_model::NetworkModel{U}, ) where { T <: Union{StaticBranchUnbounded, StaticBranch}, - U <: Union{AreaBalancePowerModel, AreaPTDFPowerModel}, + U <: PM.AbstractActivePowerModel } if get_use_slacks(model) add_variables!( diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index 4233f9c7c0..f610601ea9 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -26,7 +26,7 @@ function add_variables!( model::NetworkModel{T}, devices::IS.FlattenIteratorWrapper{PSY.AreaInterchange}, formulation::AbstractBranchFormulation, -) where {T <: Union{AreaBalancePowerModel, AreaPTDFPowerModel}} +) where {T <: PM.AbstractActivePowerModel} time_steps = get_time_steps(container) variable = add_variable_container!( @@ -56,7 +56,7 @@ function add_constraints!( devices::IS.FlattenIteratorWrapper{PSY.AreaInterchange}, model::DeviceModel{PSY.AreaInterchange, StaticBranch}, ::NetworkModel{T}, -) where {T <: Union{AreaBalancePowerModel, AreaPTDFPowerModel}} +) where {T <: PM.AbstractActivePowerModel} time_steps = get_time_steps(container) device_names = [PSY.get_name(d) for d in devices] diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index eb7702ed08..efbda4845c 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -933,7 +933,7 @@ function add_to_expression!( network_model::NetworkModel{U}, ) where { T <: ActivePowerBalance, - U <: Union{AreaBalancePowerModel, AreaPTDFPowerModel}, + U <: PM.AbstractActivePowerModel, W <: AbstractBranchFormulation, } flow_variable = get_variable(container, FlowActivePowerVariable(), PSY.AreaInterchange) From 57af12e5020b653342593ba25af41af3bf066c18 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 17 Jul 2024 09:53:48 -0600 Subject: [PATCH 02/62] add missing code for initialization --- .../device_constructors/branch_constructor.jl | 4 ++-- src/devices_models/devices/area_interchange.jl | 10 ++++++++-- src/initial_conditions/initialization.jl | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 7e6b909919..7aa4cfe093 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -950,7 +950,7 @@ end function _get_branch_map( container::OptimizationContainer, - network_model::NetworkModel{AreaPTDFPowerModel}, + network_model::NetworkModel, sys::PSY.System, ) @assert !isempty(network_model.modeled_branch_types) @@ -993,7 +993,7 @@ function construct_device!( ::ModelConstructStage, model::DeviceModel{PSY.AreaInterchange, StaticBranch}, network_model::NetworkModel{T}, -) where {T <: AreaPTDFPowerModel} +) where {T <: PSI.AbstractPTDFModel} devices = get_available_components(model, sys) add_constraints!(container, FlowLimitConstraint, devices, model, network_model) # Not ideal to do this here, but it is a not terrible workaround diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index f610601ea9..b01df8fdfb 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -1,6 +1,12 @@ #! format: off get_multiplier_value(::FromToFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = -1.0 * PSY.get_from_to_flow_limit(d) get_multiplier_value(::ToFromFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = PSY.get_to_from_flow_limit(d) + +get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{PSY.AreaInterchange, T}, +) where {T <: AbstractBranchFormulation} = DeviceModel(PSY.AreaInterchange, T) + #! format: on function get_default_time_series_names( @@ -139,12 +145,12 @@ function add_constraints!( ::Type{LineFlowBoundConstraint}, devices::IS.FlattenIteratorWrapper{PSY.AreaInterchange}, model::DeviceModel{PSY.AreaInterchange, <:AbstractBranchFormulation}, - network_model::NetworkModel{AreaPTDFPowerModel}, + network_model::NetworkModel{T}, inter_area_branch_map::Dict{ Tuple{PSY.Area, PSY.Area}, Dict{DataType, Vector{<:PSY.ACBranch}}, }, -) +) where {T <: AbstractPTDFModel} @assert !isempty(inter_area_branch_map) time_steps = get_time_steps(container) device_names = [PSY.get_name(d) for d in devices] diff --git a/src/initial_conditions/initialization.jl b/src/initial_conditions/initialization.jl index e375b25c12..b597e1eb15 100644 --- a/src/initial_conditions/initialization.jl +++ b/src/initial_conditions/initialization.jl @@ -13,10 +13,11 @@ function get_initial_conditions_template(model::OperationModel) get_radial_network_reduction(get_network_model(model.template)) network_model.subnetworks = get_subnetworks(get_network_model(model.template)) bus_area_map = get_bus_area_map(get_network_model(model.template)) + if !isempty(bus_area_map) network_model.bus_area_map = get_bus_area_map(get_network_model(model.template)) end - + network_model.modeled_branch_types = get_network_model(model.template).modeled_branch_types ic_template = ProblemTemplate(network_model) for device_model in values(model.template.devices) base_model = get_initial_conditions_device_model(model, device_model) From a6a90848d0fa03010c38c607701397ffbf9948d4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 17 Jul 2024 09:53:56 -0600 Subject: [PATCH 03/62] improve error message --- src/simulation/initial_condition_update_simulation.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/simulation/initial_condition_update_simulation.jl b/src/simulation/initial_condition_update_simulation.jl index 7d444cf609..5a0b6b2f6a 100644 --- a/src/simulation/initial_condition_update_simulation.jl +++ b/src/simulation/initial_condition_update_simulation.jl @@ -89,7 +89,11 @@ function update_initial_conditions!( $(comp_type)-$(comp_name) is out of bounds [$(min), $(max)].") end else - @assert isapprox(var_val, 0.0, atol = ABSOLUTE_TOLERANCE) "status and power don't match" + if !isapprox(var_val, 0.0, atol = ABSOLUTE_TOLERANCE) + error("Status and Power variables don't match for $comp_name. \\ + ActivePowerVariable: $(var_val)\\ + Status value: $(status_val) for OnVariable") + end set_ic_quantity!(ic, 0.0) end end From 1c388a0e90411c022d966937c9319bbd36bea19a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:03:41 -0400 Subject: [PATCH 04/62] add missing feedforward calls --- .../device_constructors/branch_constructor.jl | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 7aa4cfe093..8a53545399 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -46,6 +46,7 @@ function construct_device!( network_model, ) end + add_feedforward_arguments!(container, model, devices) return end @@ -71,6 +72,7 @@ function construct_device!( ) add_constraint_dual!(container, sys, model) end + add_feedforward_constraints!(container, model, devices) return end @@ -106,6 +108,7 @@ function construct_device!( network_model, ) end + add_feedforward_arguments!(container, model, devices) return end @@ -129,6 +132,7 @@ function construct_device!( network_model, ) end + add_feedforward_constraints!(container, model, devices) return end @@ -161,6 +165,7 @@ function construct_device!( network_model, ) end + add_feedforward_arguments!(container, model, devices) return end @@ -174,6 +179,7 @@ function construct_device!( NetworkModel{AreaBalancePowerModel}, }, ) + add_feedforward_constraints!(container, model, devices) return end @@ -217,8 +223,7 @@ function construct_device!( ) end add_feedforward_arguments!(container, device_model, devices) - - add_feedforward_arguments!(container, device_model, devices) + return end # For DC Power only. Implements constraints @@ -272,6 +277,7 @@ function construct_device!( devices, StaticBranch(), ) + add_feedforward_arguments!(container, model, devices) return end @@ -285,6 +291,7 @@ function construct_device!( devices = get_available_components(model, sys) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) add_constraints!(container, RateLimitConstraint, devices, model, network_model) + add_feedforward_constraints!(container, model, devices) objective_function!(container, devices, model, PTDFPowerModel) add_constraint_dual!(container, sys, model) return @@ -310,6 +317,7 @@ function construct_device!( devices, StaticBranchBounds(), ) + add_feedforward_arguments!(container, model, devices) return end @@ -329,6 +337,7 @@ function construct_device!( model, network_model, ) + add_feedforward_constraints!(container, model, devices) add_constraint_dual!(container, sys, model) return end @@ -349,6 +358,7 @@ function construct_device!( devices, StaticBranchUnbounded(), ) + add_feedforward_arguments!(container, model, devices) return end @@ -361,7 +371,7 @@ function construct_device!( ) where {T <: PSY.ACBranch} devices = get_available_components(model, sys) - + add_feedforward_constraints!(container, model, devices) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) return @@ -386,7 +396,7 @@ function construct_device!( StaticBranch(), ) end - + add_feedforward_arguments!(container, device_model, devices) return end @@ -400,7 +410,7 @@ function construct_device!( devices = get_available_components(model, sys) branch_rate_bounds!(container, devices, model, network_model) - + add_feedforward_constraints!(container, model, devices) add_constraints!(container, RateLimitConstraintFromTo, devices, model, network_model) add_constraints!(container, RateLimitConstraintToFrom, devices, model, network_model) add_constraint_dual!(container, sys, model) @@ -880,8 +890,10 @@ function construct_device!( network_model::NetworkModel{U}, ) where { T <: Union{StaticBranchUnbounded, StaticBranch}, - U <: PM.AbstractActivePowerModel + U <: PM.AbstractActivePowerModel, } + devices = get_available_components(model, sys) + has_ts = PSY.has_time_series.(devices) if get_use_slacks(model) add_variables!( container, @@ -898,8 +910,6 @@ function construct_device!( T(), ) end - devices = get_available_components(model, sys) - has_ts = PSY.has_time_series.(devices) if any(has_ts) && !all(has_ts) error( "Not all AreaInterchange devices have time series. Check data to complete (or remove) time series.", From f1323c2e80e963fec886712cd0e39f59eec84efb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:03:49 -0400 Subject: [PATCH 05/62] add missing getters --- src/devices_models/devices/AC_branches.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/devices_models/devices/AC_branches.jl b/src/devices_models/devices/AC_branches.jl index fc7b1e1e51..e6cb1c74dc 100644 --- a/src/devices_models/devices/AC_branches.jl +++ b/src/devices_models/devices/AC_branches.jl @@ -21,9 +21,14 @@ get_variable_binary(::FlowActivePowerVariable, ::Type{<:PSY.ACBranch}, ::AbstractBranchFormulation,) = false get_variable_binary(::PhaseShifterAngle, ::Type{PSY.PhaseShiftingTransformer}, ::AbstractBranchFormulation,) = false -get_parameter_multiplier(::FixValueParameter, ::PSY.ACBranch, ::StaticBranch) = 1.0 +get_parameter_multiplier(::FixValueParameter, ::PSY.ACBranch, ::AbstractBranchFormulation) = 1.0 +get_parameter_multiplier(::LowerBoundValueParameter, ::PSY.ACBranch, ::AbstractBranchFormulation) = 1.0 +get_parameter_multiplier(::UpperBoundValueParameter, ::PSY.ACBranch, ::AbstractBranchFormulation) = 1.0 + get_variable_multiplier(::PhaseShifterAngle, d::PSY.PhaseShiftingTransformer, ::PhaseAngleControl) = 1.0/PSY.get_x(d) + + get_initial_conditions_device_model(::OperationModel, ::DeviceModel{T, U}) where {T <: PSY.ACBranch, U <: AbstractBranchFormulation} = DeviceModel(T, U) #### Properties of slack variables From a9baa62a3d100439d3f4d38749df7d8ba0624a1c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:04:04 -0400 Subject: [PATCH 06/62] fix implementation errors in ff slacks --- src/feedforward/feedforward_arguments.jl | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index 20fdd57767..25e40081b9 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -109,9 +109,10 @@ function _add_feedforward_slack_variables!( var_type = get_entry_type(var) variable = add_variable_container!( container, - T, + T(), U, - [PSY.get_name(d) for d in devices]; + [PSY.get_name(d) for d in devices], + time_steps; meta = "$(var_type)", ) @@ -135,11 +136,12 @@ function _add_feedforward_arguments!( parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, devices) if get_slacks(ff) - add_feedforward_slack_variables!( + _add_feedforward_slack_variables!( container, - UpperBoundFeedForwardSlack, - devices, + UpperBoundFeedForwardSlack(), + ff, model, + devices, ) end return @@ -154,11 +156,12 @@ function _add_feedforward_arguments!( parameter_type = get_default_parameter_type(ff, SR) add_parameters!(container, parameter_type, ff, model, contributing_devices) if get_slacks(ff) - add_feedforward_slack_variables!( + _add_feedforward_slack_variables!( container, - UpperBoundFeedForwardSlack, - contributing_devices, + UpperBoundFeedForwardSlack(), + ff, model, + contributing_devices, ) end return @@ -175,7 +178,7 @@ function _add_feedforward_arguments!( if get_slacks(ff) _add_feedforward_slack_variables!( container, - LowerBoundFeedForwardSlack, + LowerBoundFeedForwardSlack(), ff, model, devices, From 9f3e4add635fcfe6cad1710cf35cba5c10b89602 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:04:38 -0400 Subject: [PATCH 07/62] remove assertion not required anymore --- src/feedforward/feedforward_constraints.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 2acac1dfb7..a85333b85f 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -456,7 +456,6 @@ function add_feedforward_constraints!( devices::Union{Vector{T}, IS.FlattenIteratorWrapper{T}}, ff::FixValueFeedforward, ) where {T <: PSY.Component} - time_steps = get_time_steps(container) parameter_type = get_default_parameter_type(ff, T) source_key = get_optimization_container_key(ff) var_type = get_entry_type(source_key) @@ -466,7 +465,6 @@ function add_feedforward_constraints!( variable = get_variable(container, var) set_name, set_time = JuMP.axes(variable) IS.@assert_op set_name == [PSY.get_name(d) for d in devices] - #IS.@assert_op set_time == time_steps for t in set_time, name in set_name JuMP.fix(variable[name, t], param[name, t] * multiplier[name, t]; force = true) From 222a4e6d284f97cdf3f63b32143cc0901af3e727 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:05:10 -0400 Subject: [PATCH 08/62] fix template for initialization --- src/initial_conditions/initialization.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/initial_conditions/initialization.jl b/src/initial_conditions/initialization.jl index b597e1eb15..cff6e81ed0 100644 --- a/src/initial_conditions/initialization.jl +++ b/src/initial_conditions/initialization.jl @@ -17,7 +17,8 @@ function get_initial_conditions_template(model::OperationModel) if !isempty(bus_area_map) network_model.bus_area_map = get_bus_area_map(get_network_model(model.template)) end - network_model.modeled_branch_types = get_network_model(model.template).modeled_branch_types + network_model.modeled_branch_types = + get_network_model(model.template).modeled_branch_types ic_template = ProblemTemplate(network_model) for device_model in values(model.template.devices) base_model = get_initial_conditions_device_model(model, device_model) From 169bc1939095056f9d0148e2dd220a62959abf1d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:05:38 -0400 Subject: [PATCH 09/62] parameter update bug fix --- src/parameters/update_parameters.jl | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 39e4b8f996..3a659129dc 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -403,7 +403,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, T, model, input) + _update_parameter_values!(parameter_array, parameter_attributes, U, model, input) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end @@ -418,7 +418,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, T, model, input) + _update_parameter_values!( + parameter_array, + parameter_attributes, + FixValueParameter, + model, + input, + ) _fix_parameter_value!(optimization_container, parameter_array, parameter_attributes) return end From bd97b54aaf7ab7034a1e964183b496699a51396e Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 19 Jul 2024 09:05:52 -0400 Subject: [PATCH 10/62] change assertion for error message --- src/simulation/initial_condition_update_simulation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/simulation/initial_condition_update_simulation.jl b/src/simulation/initial_condition_update_simulation.jl index 5a0b6b2f6a..4f4a46559e 100644 --- a/src/simulation/initial_condition_update_simulation.jl +++ b/src/simulation/initial_condition_update_simulation.jl @@ -89,7 +89,7 @@ function update_initial_conditions!( $(comp_type)-$(comp_name) is out of bounds [$(min), $(max)].") end else - if !isapprox(var_val, 0.0, atol = ABSOLUTE_TOLERANCE) + if !isapprox(var_val, 0.0; atol = ABSOLUTE_TOLERANCE) error("Status and Power variables don't match for $comp_name. \\ ActivePowerVariable: $(var_val)\\ Status value: $(status_val) for OnVariable") From 3581adc2d261ab4b82acc0b63063116692139f69 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 29 Jul 2024 17:09:48 -0600 Subject: [PATCH 11/62] add devices in the correct spot --- src/devices_models/device_constructors/branch_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 8a53545399..54c968959b 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -10,8 +10,8 @@ function construct_device!( NetworkModel{AreaBalancePowerModel}, }, ) where {T <: PSY.ACBranch} + devices = get_available_components(model, sys) if has_subnetworks(network_model) - devices = get_available_components(model, sys) if get_use_slacks(model) add_variables!( From c357684b9a8cbc371404a057b4241575388a0ed8 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 29 Jul 2024 16:47:44 -0700 Subject: [PATCH 12/62] add devices missing --- src/devices_models/device_constructors/branch_constructor.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 54c968959b..704e5935ad 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -60,6 +60,7 @@ function construct_device!( NetworkModel{AreaBalancePowerModel}, }, ) where {T <: PSY.ACBranch} + devices = get_available_components(model, sys) if has_subnetworks(network_model) devices = get_available_components(model, sys) From 950fdb0237dd7818edf1279e35e6f5e9228b4ef9 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 29 Jul 2024 16:50:06 -0700 Subject: [PATCH 13/62] formatter --- src/devices_models/device_constructors/branch_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 704e5935ad..99d70fc46c 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -12,7 +12,6 @@ function construct_device!( ) where {T <: PSY.ACBranch} devices = get_available_components(model, sys) if has_subnetworks(network_model) - if get_use_slacks(model) add_variables!( container, From e5b304df47b28163bd5f7fb9589e748228f43168 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 29 Jul 2024 18:18:17 -0600 Subject: [PATCH 14/62] add subsystem to parameter attributes --- src/core/parameters.jl | 9 +++++++++ src/operation/time_series_interface.jl | 4 ++-- src/parameters/add_parameters.jl | 2 ++ src/parameters/update_parameters.jl | 7 ++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 7e2e60afe2..2946dd68fe 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -6,6 +6,7 @@ struct TimeSeriesAttributes{T <: PSY.TimeSeriesData} <: ParameterAttributes name::String multiplier_id::Base.RefValue{Int} component_name_to_ts_uuid::Dict{String, String} + subsystem::Base.RefValue{String} end function TimeSeriesAttributes( @@ -18,6 +19,7 @@ function TimeSeriesAttributes( name, Base.RefValue{Int}(multiplier_id), component_name_to_ts_uuid, + Base.RefValue{String}(""), ) end @@ -29,6 +31,13 @@ function set_time_series_multiplier_id!(attr::TimeSeriesAttributes, val::Int) return end +get_subsystem(attr::TimeSeriesAttributes) = attr.subsystem[] +function set_subsystem!(attr::TimeSeriesAttributes, val::String) + attr.subsystem[] = val + return +end +set_subsystem!(::TimeSeriesAttributes, ::Nothing) = nothing + function add_component_name!(attr::TimeSeriesAttributes, name::String, uuid::String) if haskey(attr.component_name_to_ts_uuid, name) throw(ArgumentError("$name is already stored")) diff --git a/src/operation/time_series_interface.jl b/src/operation/time_series_interface.jl index 040f7b2e1d..990e6dff7f 100644 --- a/src/operation/time_series_interface.jl +++ b/src/operation/time_series_interface.jl @@ -2,9 +2,9 @@ function get_time_series_values!( time_series_type::Type{T}, model::DecisionModel, component, - name, + name::String, multiplier_id::Int, - initial_time, + initial_time::Dates.DateTime, horizon::Int; ignore_scaling_factors = true, ) where {T <: PSY.Forecast} diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index b581893ed0..4d3e1cf2a5 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -216,6 +216,7 @@ function _add_time_series_parameters!( time_steps, ) set_time_series_multiplier_id!(get_attributes(param_container), time_series_mult_id) + set_subsystem!(get_attributes(param_container), get_subsystem(model)) jump_model = get_jump_model(container) for (ts_uuid, ts_values) in initial_values @@ -282,6 +283,7 @@ function _add_parameters!( ) set_time_series_multiplier_id!(get_attributes(parameter_container), time_series_mult_id) + set_subsystem!(get_attributes(param_container), get_subsystem(model)) jump_model = get_jump_model(container) ts_vector = get_time_series(container, service, T(), name) multiplier = get_multiplier_value(T(), service, V()) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 3a659129dc..64abfa1159 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -40,8 +40,13 @@ function _update_parameter_values!( 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) - device_model = get_model(template, V) + 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 From 8e4ed7bc42b7217012fa7b021c91d4789aa8cce4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 29 Jul 2024 18:23:54 -0600 Subject: [PATCH 15/62] fix bad naming --- src/parameters/add_parameters.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 4d3e1cf2a5..6261ded49c 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -283,7 +283,7 @@ function _add_parameters!( ) set_time_series_multiplier_id!(get_attributes(parameter_container), time_series_mult_id) - set_subsystem!(get_attributes(param_container), get_subsystem(model)) + set_subsystem!(get_attributes(parameter_container), get_subsystem(model)) jump_model = get_jump_model(container) ts_vector = get_time_series(container, service, T(), name) multiplier = get_multiplier_value(T(), service, V()) From b6c8219f5e80636920108447bb539e5c0a2396b5 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 31 Jul 2024 13:02:34 -0600 Subject: [PATCH 16/62] add missing constraints and arguments --- .../device_constructors/branch_constructor.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 99d70fc46c..aba7e29ed4 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -458,6 +458,7 @@ function construct_device!( network_model, ) add_constraint_dual!(container, sys, device_model) + return end @@ -808,6 +809,7 @@ function construct_device!( model, network_model, ) + add_feedforward_arguments!(container, model, devices) return end @@ -832,6 +834,7 @@ function construct_device!( model, network_model, ) + add_feedforward_arguments!(container, model, devices) return end @@ -850,6 +853,7 @@ function construct_device!( add_constraints!(container, PhaseAngleControlLimit, devices, model, network_model) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) + add_feedforward_constraints!(container, model, devices) return end @@ -868,6 +872,7 @@ function construct_device!( add_constraints!(container, PhaseAngleControlLimit, devices, model, network_model) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) + add_feedforward_constraints!(container, model, devices) return end @@ -879,6 +884,7 @@ function construct_device!( model::DeviceModel{PSY.AreaInterchange, U}, network_model::NetworkModel{CopperPlatePowerModel}, ) where {U <: Union{StaticBranchUnbounded, StaticBranch}} + add_feedforward_arguments!(container, model, devices) return end @@ -943,6 +949,7 @@ function construct_device!( add_parameters!(container, FromToFlowLimitParameter, devices, model) add_parameters!(container, ToFromFlowLimitParameter, devices, model) end + add_feedforward_arguments!(container, model, devices) return end @@ -955,6 +962,7 @@ function construct_device!( ) where {T <: AreaBalancePowerModel} devices = get_available_components(model, sys) add_constraints!(container, FlowLimitConstraint, devices, model, network_model) + add_feedforward_constraints!(container, model, devices) return end @@ -1019,6 +1027,7 @@ function construct_device!( network_model, inter_area_branch_map, ) + add_feedforward_constraints!(container, model, devices) return end @@ -1029,6 +1038,7 @@ function construct_device!( model::DeviceModel{PSY.AreaInterchange, StaticBranchUnbounded}, network_model::NetworkModel{AreaBalancePowerModel}, ) + add_feedforward_constraints!(container, model, devices) return end @@ -1051,5 +1061,6 @@ function construct_device!( network_model, inter_area_branch_map, ) + add_feedforward_constraints!(container, model, devices) return end From 07b8f2bb7de5c96b36447d3802b4d892b8392b96 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 31 Jul 2024 14:27:42 -0600 Subject: [PATCH 17/62] fix FF problems --- .../device_constructors/branch_constructor.jl | 14 ++++++-------- src/devices_models/devices/area_interchange.jl | 12 +++++++++++- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index aba7e29ed4..d0cdf897b9 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -89,9 +89,8 @@ function construct_device!( if get_use_slacks(model) throw(ArgumentError("StaticBranchBounds is not compatible with the use of slacks")) end + devices = get_available_components(model, sys) if has_subnetworks(network_model) - devices = - get_available_components(model, sys) add_variables!( container, FlowActivePowerVariable, @@ -122,9 +121,8 @@ function construct_device!( NetworkModel{AreaBalancePowerModel}, }, ) where {T <: PSY.ACBranch} + devices = get_available_components(model, sys) if has_subnetworks(network_model) - devices = - get_available_components(model, sys) branch_rate_bounds!( container, devices, @@ -146,9 +144,8 @@ function construct_device!( NetworkModel{AreaBalancePowerModel}, }, ) where {T <: PSY.ACBranch} + devices = get_available_components(model, sys) if has_subnetworks(network_model) - devices = - get_available_components(model, sys) add_variables!( container, FlowActivePowerVariable, @@ -171,14 +168,15 @@ end function construct_device!( ::OptimizationContainer, - ::PSY.System, + sys::PSY.System, ::ModelConstructStage, - ::DeviceModel{<:PSY.ACBranch, StaticBranchUnbounded}, + model::DeviceModel{<:PSY.ACBranch, StaticBranchUnbounded}, network_model::Union{ NetworkModel{CopperPlatePowerModel}, NetworkModel{AreaBalancePowerModel}, }, ) + devices = get_available_components(model, sys) add_feedforward_constraints!(container, model, devices) return end diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index b01df8fdfb..1fdde8cee0 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -32,7 +32,7 @@ function add_variables!( model::NetworkModel{T}, devices::IS.FlattenIteratorWrapper{PSY.AreaInterchange}, formulation::AbstractBranchFormulation, -) where {T <: PM.AbstractActivePowerModel} +) where {T <: PM.AbstractPowerModel} time_steps = get_time_steps(container) variable = add_variable_container!( @@ -53,6 +53,16 @@ function add_variables!( return end +function add_variables!( + container::OptimizationContainer, + ::Type{FlowActivePowerVariable}, + model::NetworkModel{CopperPlatePowerModel}, + devices::IS.FlattenIteratorWrapper{PSY.AreaInterchange}, + formulation::AbstractBranchFormulation, +) + @warn("CopperPlatePowerModel ignores AreaInterchanges. Instead use AreaBalancePowerModel.") +end + """ Add flow constraints for area interchanges """ From 6eaef2f450afc9353f51b85d4494d00f591a0878 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 31 Jul 2024 14:46:56 -0600 Subject: [PATCH 18/62] add missing method --- src/devices_models/devices/area_interchange.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index 1fdde8cee0..0d7d933235 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -2,6 +2,8 @@ get_multiplier_value(::FromToFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = -1.0 * PSY.get_from_to_flow_limit(d) get_multiplier_value(::ToFromFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = PSY.get_to_from_flow_limit(d) +get_parameter_multiplier(::FixValueParameter, ::AreaInterchange, ::StaticBranch) = 1.0 + get_initial_conditions_device_model( ::OperationModel, model::DeviceModel{PSY.AreaInterchange, T}, From 5b5bd742dc1ffa0e78ac33dd18e72dfdf4cf314d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 31 Jul 2024 14:51:26 -0600 Subject: [PATCH 19/62] add PSY predicate --- src/devices_models/devices/area_interchange.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index 0d7d933235..8c60313d52 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -2,7 +2,7 @@ get_multiplier_value(::FromToFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = -1.0 * PSY.get_from_to_flow_limit(d) get_multiplier_value(::ToFromFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = PSY.get_to_from_flow_limit(d) -get_parameter_multiplier(::FixValueParameter, ::AreaInterchange, ::StaticBranch) = 1.0 +get_parameter_multiplier(::FixValueParameter, ::PSY.AreaInterchange, ::StaticBranch) = 1.0 get_initial_conditions_device_model( ::OperationModel, From 466362d260f0698fb1363f8003b32435f4e33e5b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 31 Jul 2024 15:00:09 -0600 Subject: [PATCH 20/62] formatter --- src/devices_models/devices/area_interchange.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index 8c60313d52..8e5160c9f4 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -62,7 +62,9 @@ function add_variables!( devices::IS.FlattenIteratorWrapper{PSY.AreaInterchange}, formulation::AbstractBranchFormulation, ) - @warn("CopperPlatePowerModel ignores AreaInterchanges. Instead use AreaBalancePowerModel.") + @warn( + "CopperPlatePowerModel ignores AreaInterchanges. Instead use AreaBalancePowerModel." + ) end """ From 228ff3cb0cb81da05714d0fa20b107f6eafd6578 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 1 Aug 2024 12:07:16 -0600 Subject: [PATCH 21/62] add missing methods --- .../device_constructors/branch_constructor.jl | 14 +++++++++++++- src/devices_models/devices/area_interchange.jl | 4 +++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index d0cdf897b9..92b8b1b6a4 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -886,6 +886,18 @@ function construct_device!( return end +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{PSY.AreaInterchange, StaticBranchUnbounded}, + network_model::NetworkModel{T}, +) where {T <: PM.AbstractActivePowerModel} + devices = get_available_components(model, sys) + add_feedforward_constraints!(container, model, devices) + return +end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -957,7 +969,7 @@ function construct_device!( ::ModelConstructStage, model::DeviceModel{PSY.AreaInterchange, StaticBranch}, network_model::NetworkModel{T}, -) where {T <: AreaBalancePowerModel} +) where {T <: PM.AbstractActivePowerModel} devices = get_available_components(model, sys) add_constraints!(container, FlowLimitConstraint, devices, model, network_model) add_feedforward_constraints!(container, model, devices) diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index 8e5160c9f4..ac763f3f18 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -2,7 +2,9 @@ get_multiplier_value(::FromToFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = -1.0 * PSY.get_from_to_flow_limit(d) get_multiplier_value(::ToFromFlowLimitParameter, d::PSY.AreaInterchange, ::AbstractBranchFormulation) = PSY.get_to_from_flow_limit(d) -get_parameter_multiplier(::FixValueParameter, ::PSY.AreaInterchange, ::StaticBranch) = 1.0 +get_parameter_multiplier(::FixValueParameter, ::PSY.AreaInterchange, ::AbstractBranchFormulation) = 1.0 +get_parameter_multiplier(::LowerBoundValueParameter, ::PSY.AreaInterchange, ::AbstractBranchFormulation) = 1.0 +get_parameter_multiplier(::UpperBoundValueParameter, ::PSY.AreaInterchange, ::AbstractBranchFormulation) = 1.0 get_initial_conditions_device_model( ::OperationModel, From 5662db18283073521339d1a5987fa5965b990574 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 6 Aug 2024 13:03:28 -0600 Subject: [PATCH 22/62] formatter --- .../device_constructors/branch_constructor.jl | 39 +++------ .../renewablegeneration_constructor.jl | 18 ++-- .../thermalgeneration_constructor.jl | 87 +++++++------------ 3 files changed, 48 insertions(+), 96 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 92b8b1b6a4..87546cfe9d 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -326,8 +326,7 @@ function construct_device!( model::DeviceModel{T, StaticBranchBounds}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: PSY.ACBranch} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) branch_rate_bounds!( container, @@ -347,8 +346,7 @@ function construct_device!( model::DeviceModel{T, StaticBranchUnbounded}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: PSY.ACBranch} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, FlowActivePowerVariable, @@ -367,8 +365,7 @@ function construct_device!( model::DeviceModel{T, StaticBranchUnbounded}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: PSY.ACBranch} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_feedforward_constraints!(container, model, devices) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) @@ -405,8 +402,7 @@ function construct_device!( model::DeviceModel{T, StaticBranch}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ACBranch} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) branch_rate_bounds!(container, devices, model, network_model) add_feedforward_constraints!(container, model, devices) add_constraints!(container, RateLimitConstraintFromTo, devices, model, network_model) @@ -553,8 +549,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalUnbounded}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, FlowActivePowerVariable, devices, HVDCTwoTerminalUnbounded()) add_to_expression!( container, @@ -596,8 +591,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalLossless}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!(container, FlowRateConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) return @@ -611,8 +605,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalLossless}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, FlowActivePowerVariable, devices, HVDCTwoTerminalLossless()) add_to_expression!( container, @@ -635,8 +628,7 @@ function construct_device!( ) where { T <: TwoTerminalHVDCTypes, } - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!(container, FlowRateConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) return @@ -649,8 +641,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalDispatch}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, FlowActivePowerToFromVariable, @@ -699,8 +690,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalDispatch}, network_model::NetworkModel{<:AbstractPTDFModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!(container, FlowRateConstraintFromTo, devices, model, network_model) add_constraints!(container, FlowRateConstraintToFrom, devices, model, network_model) add_constraints!(container, HVDCPowerBalance, devices, model, network_model) @@ -715,8 +705,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalDispatch}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, FlowActivePowerToFromVariable, @@ -757,8 +746,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalDispatch}, network_model::NetworkModel{CopperPlatePowerModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) @warn "CopperPlatePowerModel models with HVDC ignores inter-area losses" add_constraints!(container, FlowRateConstraintFromTo, devices, model, network_model) add_constraints!(container, FlowRateConstraintToFrom, devices, model, network_model) @@ -773,8 +761,7 @@ function construct_device!( model::DeviceModel{T, HVDCTwoTerminalDispatch}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: TwoTerminalHVDCTypes} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!(container, FlowRateConstraintFromTo, devices, model, network_model) add_constraints!(container, FlowRateConstraintToFrom, devices, model, network_model) add_constraints!(container, HVDCPowerBalance, devices, model, network_model) diff --git a/src/devices_models/device_constructors/renewablegeneration_constructor.jl b/src/devices_models/device_constructors/renewablegeneration_constructor.jl index 7c05d30ceb..10939d52ea 100644 --- a/src/devices_models/device_constructors/renewablegeneration_constructor.jl +++ b/src/devices_models/device_constructors/renewablegeneration_constructor.jl @@ -8,8 +8,7 @@ function construct_device!( R <: PSY.RenewableGen, D <: AbstractRenewableDispatchFormulation, } - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -62,8 +61,7 @@ function construct_device!( model::DeviceModel{R, <:AbstractRenewableDispatchFormulation}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {R <: PSY.RenewableGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) if has_service_model(model) add_constraints!( @@ -119,8 +117,7 @@ function construct_device!( R <: PSY.RenewableGen, D <: AbstractRenewableDispatchFormulation, } - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, D()) @@ -164,8 +161,7 @@ function construct_device!( model::DeviceModel{R, <:AbstractRenewableDispatchFormulation}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {R <: PSY.RenewableGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) if has_service_model(model) add_constraints!( @@ -210,8 +206,7 @@ function construct_device!( model::DeviceModel{R, FixedOutput}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {R <: PSY.RenewableGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) @@ -242,8 +237,7 @@ function construct_device!( model::DeviceModel{R, FixedOutput}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {R <: PSY.RenewableGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_to_expression!( diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index f24d154b08..8831cd3aa4 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -5,8 +5,7 @@ function construct_device!( device_model::DeviceModel{T, FixedOutput}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, device_model) add_to_expression!( container, @@ -44,8 +43,7 @@ function construct_device!( T <: PSY.ThermalGen, D <: AbstractStandardUnitCommitment, } - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -107,8 +105,7 @@ function construct_device!( model::DeviceModel{T, <:AbstractStandardUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -155,8 +152,7 @@ function construct_device!( model::DeviceModel{T, D}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen, D <: AbstractStandardUnitCommitment} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, OnVariable, devices, D()) @@ -210,8 +206,7 @@ function construct_device!( model::DeviceModel{T, <:AbstractStandardUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, ActivePowerVariableLimitsConstraint, @@ -251,8 +246,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, ThermalBasicUnitCommitment()) add_variables!(container, ReactivePowerVariable, devices, ThermalBasicUnitCommitment()) @@ -312,8 +306,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -359,8 +352,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, ThermalBasicUnitCommitment()) add_variables!(container, OnVariable, devices, ThermalBasicUnitCommitment()) @@ -411,8 +403,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -450,8 +441,7 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, ThermalStandardDispatch()) add_variables!(container, ReactivePowerVariable, devices, ThermalStandardDispatch()) @@ -508,8 +498,7 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -555,8 +544,7 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, ThermalStandardDispatch()) @@ -604,8 +592,7 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -643,8 +630,7 @@ function construct_device!( T <: PSY.ThermalGen, D <: AbstractThermalDispatchFormulation, } - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -696,8 +682,7 @@ function construct_device!( model::DeviceModel{T, <:AbstractThermalDispatchFormulation}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -742,8 +727,7 @@ function construct_device!( T <: PSY.ThermalGen, D <: AbstractThermalDispatchFormulation, } - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, ActivePowerVariable, devices, D()) @@ -786,8 +770,7 @@ function construct_device!( model::DeviceModel{T, <:AbstractThermalDispatchFormulation}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -1085,8 +1068,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, @@ -1157,8 +1139,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -1203,8 +1184,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, @@ -1268,8 +1248,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -1306,8 +1285,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, @@ -1376,8 +1354,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -1420,8 +1397,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!( container, @@ -1483,8 +1459,7 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -1519,8 +1494,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, PowerAboveMinimumVariable, devices, ThermalCompactDispatch()) add_variables!(container, ReactivePowerVariable, devices, ThermalCompactDispatch()) @@ -1603,8 +1577,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, @@ -1647,8 +1620,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_variables!(container, PowerAboveMinimumVariable, devices, ThermalCompactDispatch()) @@ -1706,8 +1678,7 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{<:PM.AbstractActivePowerModel}, ) where {T <: PSY.ThermalGen} - devices = - get_available_components(model, sys) + devices = get_available_components(model, sys) add_constraints!( container, From ae1d9ba1967837fe3a21bc78653616b35cfc845b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 7 Aug 2024 11:57:24 -0600 Subject: [PATCH 23/62] change error checking --- src/parameters/update_parameters.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index bc81e0259c..9e6e9fdaa2 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -256,7 +256,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) \ @@ -264,6 +263,9 @@ 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 From 205edc3bdf2b1f77e63d0eacc724214ff4ec7fa4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 12 Aug 2024 13:31:36 -0600 Subject: [PATCH 24/62] Update src/parameters/update_parameters.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/parameters/update_parameters.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 9e6e9fdaa2..3bff573823 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -262,7 +262,9 @@ function _update_parameter_values!( 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 + 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", + ) 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 From 7314623a2499d3e8321ed1d8140f44f60fbac867 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 20 Aug 2024 14:56:38 -0600 Subject: [PATCH 25/62] add missing end --- src/parameters/update_parameters.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 3bff573823..73fd646d91 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -262,11 +262,11 @@ function _update_parameter_values!( 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", ) - 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 From b4e9635016cc1ee66857a16fdea6a4904393a55a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:13 -0600 Subject: [PATCH 26/62] 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 27/62] 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 682d6a7e914d6419e19d5c37691d4354619b4125 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 30 Aug 2024 13:11:20 -0600 Subject: [PATCH 28/62] fix missing devices --- src/devices_models/device_constructors/branch_constructor.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 87546cfe9d..e6c93daef5 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -1046,6 +1046,7 @@ function construct_device!( model::DeviceModel{PSY.AreaInterchange, StaticBranchUnbounded}, network_model::NetworkModel{AreaPTDFPowerModel}, ) + devices = get_available_components(model, sys) inter_area_branch_map = _get_branch_map(container, network_model, sys) # Not ideal to do this here, but it is a not terrible workaround # The area interchanges are like a services/device mix. From 24368a91cbcb8a2a6de6a78062d662842df515fe Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 30 Aug 2024 12:34:17 -0700 Subject: [PATCH 29/62] remove duplicate add expression --- .../thermalgeneration_constructor.jl | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 8831cd3aa4..5225586c43 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -1534,23 +1534,6 @@ function construct_device!( model, network_model, ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - OnStatusParameter, - devices, - model, - network_model, - ) - add_to_expression!( container, ActivePowerRangeExpressionLB, From 93624fb549c3d63e76fdf5059427643d3adde91a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 30 Aug 2024 13:46:26 -0600 Subject: [PATCH 30/62] add missing arguments --- src/devices_models/device_constructors/branch_constructor.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index e6c93daef5..8f5d3c87fc 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -863,12 +863,13 @@ end ################################# AreaInterchange Models ################################ function construct_device!( - ::OptimizationContainer, + container::OptimizationContainer, ::PSY.System, ::ArgumentConstructStage, model::DeviceModel{PSY.AreaInterchange, U}, network_model::NetworkModel{CopperPlatePowerModel}, ) where {U <: Union{StaticBranchUnbounded, StaticBranch}} + devices = get_available_components(model, sys) add_feedforward_arguments!(container, model, devices) return end From 390123b2e76bb140d73d6deab8e0f0a1c1fb708e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 30 Aug 2024 12:49:44 -0700 Subject: [PATCH 31/62] remove unavailable services from constructor --- src/services_models/services_constructor.jl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 09d9c9d2ec..6deb80d300 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -104,6 +104,7 @@ function construct_service!( ) where {SR <: PSY.Reserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return add_parameters!(container, RequirementTimeSeriesParameter, service, model) contributing_devices = get_contributing_devices(model) @@ -130,6 +131,7 @@ function construct_service!( ) where {SR <: PSY.Reserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) @@ -160,6 +162,7 @@ function construct_service!( ) where {SR <: PSY.ConstantReserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_variables!( @@ -185,6 +188,7 @@ function construct_service!( ) where {SR <: PSY.ConstantReserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) @@ -214,6 +218,7 @@ function construct_service!( ) where {SR <: PSY.Reserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_variable!(container, ServiceRequirementVariable(), service, StepwiseCostReserve()) add_variables!( @@ -239,6 +244,7 @@ function construct_service!( ) where {SR <: PSY.Reserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) @@ -251,6 +257,7 @@ function construct_service!( return end +#= function construct_service!( container::OptimizationContainer, sys::PSY.System, @@ -343,6 +350,7 @@ function construct_service!( objective_function!(container, services, model) return end +=# """ Constructs a service for ConstantReserveGroup. @@ -358,6 +366,7 @@ function construct_service!( ) where {SR <: PSY.ConstantReserveGroup} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_services = PSY.get_contributing_services(service) # check if variables exist check_activeservice_variables(container, contributing_services) @@ -376,6 +385,7 @@ function construct_service!( ) where {SR <: PSY.ConstantReserveGroup} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_services = PSY.get_contributing_services(service) add_constraints!( @@ -401,6 +411,7 @@ function construct_service!( ) where {SR <: PSY.Reserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_parameters!(container, RequirementTimeSeriesParameter, service, model) @@ -427,6 +438,7 @@ function construct_service!( ) where {SR <: PSY.Reserve} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) @@ -458,6 +470,7 @@ function construct_service!( ) where {SR <: PSY.ReserveNonSpinning} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_parameters!(container, RequirementTimeSeriesParameter, service, model) @@ -483,6 +496,7 @@ function construct_service!( ) where {SR <: PSY.ReserveNonSpinning} name = get_service_name(model) service = PSY.get_component(SR, sys, name) + !PSY.get_available(service) && return contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) @@ -549,6 +563,7 @@ function construct_service!( ) where {T <: PSY.TransmissionInterface} name = get_service_name(model) service = PSY.get_component(T, sys, name) + !PSY.get_available(service) && return add_to_expression!( container, @@ -640,6 +655,7 @@ function construct_service!( ) where {T <: PSY.TransmissionInterface} name = get_service_name(model) service = PSY.get_component(T, sys, name) + !PSY.get_available(service) && return add_to_expression!( container, From 666ec920731feccf35bcc5e5e1437d1c708388aa Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 30 Aug 2024 13:53:08 -0600 Subject: [PATCH 32/62] add missing argument --- src/devices_models/device_constructors/branch_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index 8f5d3c87fc..9aff973682 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -864,7 +864,7 @@ end ################################# AreaInterchange Models ################################ function construct_device!( container::OptimizationContainer, - ::PSY.System, + sys::PSY.System, ::ArgumentConstructStage, model::DeviceModel{PSY.AreaInterchange, U}, network_model::NetworkModel{CopperPlatePowerModel}, From a1f762ff4b02a363b19407ef48d44ed91e308f84 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 30 Aug 2024 12:57:05 -0700 Subject: [PATCH 33/62] fix upper bound and lower bound --- src/devices_models/devices/electric_loads.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/electric_loads.jl b/src/devices_models/devices/electric_loads.jl index 2452b18f7d..6725b2bd3e 100644 --- a/src/devices_models/devices/electric_loads.jl +++ b/src/devices_models/devices/electric_loads.jl @@ -7,14 +7,14 @@ get_variable_multiplier(_, ::Type{<:PSY.ElectricLoad}, ::AbstractLoadFormulation get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.ElectricLoad}, ::AbstractLoadFormulation) = false get_variable_lower_bound(::ActivePowerVariable, d::PSY.ElectricLoad, ::AbstractLoadFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.ElectricLoad, ::AbstractLoadFormulation) = PSY.get_active_power(d) +get_variable_upper_bound(::ActivePowerVariable, d::PSY.ElectricLoad, ::AbstractLoadFormulation) = PSY.get_max_active_power(d) ########################### ReactivePowerVariable, ElectricLoad #################################### get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.ElectricLoad}, ::AbstractLoadFormulation) = false get_variable_lower_bound(::ReactivePowerVariable, d::PSY.ElectricLoad, ::AbstractLoadFormulation) = 0.0 -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.ElectricLoad, ::AbstractLoadFormulation) = PSY.get_reactive_power(d) +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.ElectricLoad, ::AbstractLoadFormulation) = PSY.get_max_reactive_power(d) ########################### ReactivePowerVariable, ElectricLoad #################################### From b3634e8fe09ccb54b51c4fbd13d07c9aa535536a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 30 Aug 2024 13:44:24 -0700 Subject: [PATCH 34/62] fix pwl nomin --- .../objective_function/piecewise_linear.jl | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/piecewise_linear.jl b/src/devices_models/devices/common/objective_function/piecewise_linear.jl index 37ae04b62d..7292be3c03 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -408,13 +408,20 @@ function _add_pwl_term!( end # Compact PWL data does not exists anymore - - if slopes[1] != 0.0 - @debug "PWL has no 0.0 intercept for generator $(component_name)" - # adds a first intercept a x = 0.0 and y below the intercept of the first tuple to make convex equivalent - intercept_point = (x = 0.0, y = first(data).y - COST_EPSILON) - data = PSY.PiecewiseLinearData(vcat(intercept_point, get_points(data))) - @assert PSY.is_convex(slopes) + x_coords = PSY.get_x_coords(data) + if x_coords[1] != 0.0 + y_coords = PSY.get_y_coords(data) + x_first = round(x_coords[1]; digits = 3) + y_first = round(y_coords[1]; digits = 3) + slope_first = round(slopes[1]; digits = 3) + guess_y_zero = y_coords[1] - slopes[1] * x_coords[1] + @warn( + "PWL has no 0.0 intercept for generator $(name). First point is given at (x = $(x_first), y = $(y_first)). Adding a first intercept at (x = 0.0, y = $(round(guess_y_zero, digits = 3)) to have equal initial slope $(slope_first)" + ) + # adds a first intercept a x = 0.0 and y above the intercept of the first tuple to make convex equivalent (avoid floating point issues of almost equal slopes) + intercept_point = (x = 0.0, y = guess_y_zero + COST_EPSILON) + data = PSY.PiecewiseLinearData(vcat(intercept_point, PSY.get_points(data))) + @assert PSY.is_convex(data) end time_steps = get_time_steps(container) @@ -422,7 +429,7 @@ function _add_pwl_term!( break_points = PSY.get_x_coords(data) sos_val = _get_sos_value(container, V, component) for t in time_steps - _add_pwl_variables!(container, T, component_name, t, data) + _add_pwl_variables!(container, T, name, t, data) _add_pwl_constraint!(container, component, U(), break_points, sos_val, t) pwl_cost = _get_pwl_cost_expression(container, component, t, cost_function, U(), V()) From bd8b9581b0f27cf6ae3efe31eb505b47b75b4256 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 30 Aug 2024 14:00:48 -0700 Subject: [PATCH 35/62] add error for negative intercept --- .../devices/common/objective_function/piecewise_linear.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/devices_models/devices/common/objective_function/piecewise_linear.jl b/src/devices_models/devices/common/objective_function/piecewise_linear.jl index 7292be3c03..bc184fb972 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -418,6 +418,11 @@ function _add_pwl_term!( @warn( "PWL has no 0.0 intercept for generator $(name). First point is given at (x = $(x_first), y = $(y_first)). Adding a first intercept at (x = 0.0, y = $(round(guess_y_zero, digits = 3)) to have equal initial slope $(slope_first)" ) + if guess_y_zero < 0.0 + error( + "Added zero intercept has negative cost for generator $(name). Consider using other formulation or improve data.", + ) + end # adds a first intercept a x = 0.0 and y above the intercept of the first tuple to make convex equivalent (avoid floating point issues of almost equal slopes) intercept_point = (x = 0.0, y = guess_y_zero + COST_EPSILON) data = PSY.PiecewiseLinearData(vcat(intercept_point, PSY.get_points(data))) From d3203e339389e0bc3b3e25d9b47548525d0a83a1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 3 Sep 2024 22:53:09 -0600 Subject: [PATCH 36/62] fix interchange overwrite --- .../devices/area_interchange.jl | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/devices_models/devices/area_interchange.jl b/src/devices_models/devices/area_interchange.jl index ac763f3f18..84c953e54b 100644 --- a/src/devices_models/devices/area_interchange.jl +++ b/src/devices_models/devices/area_interchange.jl @@ -168,6 +168,7 @@ function add_constraints!( }, ) where {T <: AbstractPTDFModel} @assert !isempty(inter_area_branch_map) + time_steps = get_time_steps(container) device_names = [PSY.get_name(d) for d in devices] @@ -195,13 +196,16 @@ function add_constraints!( inter_change_name = PSY.get_name(area_interchange) area_from = PSY.get_from_area(area_interchange) area_to = PSY.get_to_area(area_interchange) + direction_branch_map = Dict{Float64, Dict{DataType, Vector{<:PSY.ACBranch}}}() if haskey(inter_area_branch_map, (area_from, area_to)) - inter_area_branches = inter_area_branch_map[(area_from, area_to)] - mult = 1.0 - elseif haskey(inter_area_branch_map, (area_to, area_from)) - inter_area_branches = inter_area_branch_map[(area_to, area_from)] - mult = -1.0 - else + # 1 is the multiplier + direction_branch_map[1.0] = inter_area_branch_map[(area_from, area_to)] + end + if haskey(inter_area_branch_map, (area_to, area_from)) + # -1 is the multiplier because the direction is reversed + direction_branch_map[-1.0] = inter_area_branch_map[(area_to, area_from)] + end + if isempty(direction_branch_map) @warn( "There are no branches modeled in Area InterChange $(summary(area_interchange)) \ LineFlowBoundConstraint not created" @@ -211,11 +215,13 @@ function add_constraints!( for t in time_steps sum_of_flows = JuMP.AffExpr() - for (type, branches) in inter_area_branches - flow_vars = get_variable(container, FlowActivePowerVariable(), type) - for b in branches - b_name = PSY.get_name(b) - _add_to_jump_expression!(sum_of_flows, flow_vars[b_name, t], mult) + for (mult, inter_area_branches) in direction_branch_map + for (type, branches) in inter_area_branches + flow_vars = get_variable(container, FlowActivePowerVariable(), type) + for b in branches + b_name = PSY.get_name(b) + _add_to_jump_expression!(sum_of_flows, flow_vars[b_name, t], mult) + end end end con_ub[inter_change_name, t] = From 192dc3c02a1fbc41631abf9d6f41fca946efd826 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 3 Sep 2024 23:23:52 -0600 Subject: [PATCH 37/62] add missing tests --- test/test_simulation_build.jl | 108 ++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 0b3f2e4d7c..d6d4293cab 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -212,3 +212,111 @@ end ) @test !isempty(c) end + +@testset "Test Upper/Lower Bound 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)) + template_ed = + get_template_nomin_ed_simulation(NetworkModel(PTDFPowerModel; use_slacks = true)) + set_device_model!(template_ed, DeviceModel(Line, StaticBranchUnbounded)) + c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc") + c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed") + 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], + ), + LowerBoundFeedforward(; + component_type = Line, + source = FlowActivePowerVariable, + affected_values = [FlowActivePowerVariable], + add_slacks = true, + ), + UpperBoundFeedforward(; + component_type = Line, + source = FlowActivePowerVariable, + affected_values = [FlowActivePowerVariable], + add_slacks = true, + ), + ], + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "reactive_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_constraint( + PSI.get_optimization_container(ed_power_model), + FeedforwardSemiContinuousConstraint(), + ThermalStandard, + "ActivePowerVariable_ub", + ) + @test !isempty(c) + c = PSI.get_constraint( + PSI.get_optimization_container(ed_power_model), + FeedforwardSemiContinuousConstraint(), + ThermalStandard, + "ActivePowerVariable_lb", + ) + @test !isempty(c) + c = PSI.get_constraint( + PSI.get_optimization_container(ed_power_model), + FeedforwardLowerBoundConstraint(), + Line, + "FlowActivePowerVariablelb", + ) + @test !isempty(c) + c = PSI.get_constraint( + PSI.get_optimization_container(ed_power_model), + FeedforwardUpperBoundConstraint(), + Line, + "FlowActivePowerVariableub", + ) + @test !isempty(c) + c = PSI.get_variable( + PSI.get_optimization_container(ed_power_model), + UpperBoundFeedForwardSlack(), + Line, + "FlowActivePowerVariable", + ) + @test !isempty(c) + c = PSI.get_variable( + PSI.get_optimization_container(ed_power_model), + LowerBoundFeedForwardSlack(), + Line, + "FlowActivePowerVariable", + ) + @test !isempty(c) +end From 53fc0900f0852c89adaf96b03d3f3d18761ee801 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 4 Sep 2024 17:15:04 -0600 Subject: [PATCH 38/62] fix tests --- test/test_network_constructors.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_network_constructors.jl b/test/test_network_constructors.jl index 62be7f13f6..28e40011c8 100644 --- a/test/test_network_constructors.jl +++ b/test/test_network_constructors.jl @@ -964,7 +964,7 @@ end PSI.get_constraint(opt_container, CopperPlateBalanceConstraint(), PSY.Area) @test size(copper_plate_constraints) == (2, 24) - psi_checksolve_test(ps_model, [MOI.OPTIMAL], 662467, 1) + psi_checksolve_test(ps_model, [MOI.OPTIMAL], 671937, 1) results = OptimizationProblemResults(ps_model) interarea_flow = read_variable(results, "FlowActivePowerVariable__AreaInterchange") From 798042147c993f252b3c44340f5ec3915eecf1ec Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 22 Aug 2024 09:45:13 -0600 Subject: [PATCH 39/62] 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 40/62] 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 41/62] 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 42/62] 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 43/62] 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 44/62] 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 45/62] 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 46/62] 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 47/62] 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 48/62] 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 49/62] 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 50/62] 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 51/62] 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 52/62] 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 53/62] 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 54/62] 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 55/62] 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 56/62] 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 57/62] 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 58/62] 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 59/62] 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 60/62] 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 61/62] 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 62/62] 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"