From e5a987053114f794a89d937bc250a41a0f87c39b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 001/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++++ src/devices_models/devices/thermal_generation.jl | 5 ++++- src/parameters/add_parameters.jl | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2946dd68f..e772d6e37 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 5225586c4..00269bc0a 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -731,6 +731,10 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 66809d18d..3f3be9f01 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,6 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -193,7 +194,9 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}() + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", + ) end function get_default_attributes( diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 76f1ef209..ae39d01d4 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -197,6 +197,9 @@ function _add_time_series_parameters!( device_names = String[] initial_values = Dict{String, AbstractArray}() for device in devices + if !PSY.has_time_series(device) + continue + end push!(device_names, PSY.get_name(device)) ts_uuid = string(IS.get_time_series_uuid(ts_type, device, ts_name)) if !(ts_uuid in keys(initial_values)) @@ -226,6 +229,9 @@ function _add_time_series_parameters!( end for device in devices + if !PSY.has_time_series(device) + continue + end name = PSY.get_name(device) multiplier = get_multiplier_value(T(), device, W()) for step in time_steps From 677a8a3dea806eb06f28419881a16d288180b450 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 12:10:13 -0600 Subject: [PATCH 002/162] change file name to avoid confussion --- src/PowerSimulations.jl | 2 +- .../devices/{interfaces.jl => default_interface_methods.jl} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/devices_models/devices/{interfaces.jl => default_interface_methods.jl} (100%) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 0a36addcd..cd8544a63 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -556,7 +556,7 @@ include("devices_models/devices/common/duration_constraints.jl") include("devices_models/devices/common/get_time_series.jl") # Device Modeling components -include("devices_models/devices/interfaces.jl") +include("devices_models/devices/default_interface_methods.jl") include("devices_models/devices/common/add_to_expression.jl") include("devices_models/devices/common/set_expression.jl") include("devices_models/devices/renewable_generation.jl") diff --git a/src/devices_models/devices/interfaces.jl b/src/devices_models/devices/default_interface_methods.jl similarity index 100% rename from src/devices_models/devices/interfaces.jl rename to src/devices_models/devices/default_interface_methods.jl From e74a1394454670f233aeb27d318a41d3778401ca Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:03 -0600 Subject: [PATCH 003/162] add ts parameter calls in constructor --- .../thermalgeneration_constructor.jl | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 00269bc0a..bbb169b86 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -56,6 +56,10 @@ function construct_device!( initial_conditions!(container, devices, D()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -135,6 +139,17 @@ function construct_device!( add_constraints!(container, RampConstraint, devices, model, network_model) add_constraints!(container, DurationConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end + add_feedforward_constraints!(container, model, devices) objective_function!(container, devices, model, get_network_formulation(network_model)) @@ -164,6 +179,10 @@ function construct_device!( initial_conditions!(container, devices, D()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -227,6 +246,16 @@ function construct_device!( add_constraints!(container, CommitmentConstraint, devices, model, network_model) add_constraints!(container, RampConstraint, devices, model, network_model) add_constraints!(container, DurationConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -256,6 +285,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalBasicUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -335,6 +368,17 @@ function construct_device!( ) add_constraints!(container, CommitmentConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end + add_feedforward_constraints!(container, model, devices) objective_function!(container, devices, model, get_network_formulation(network_model)) @@ -361,6 +405,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalBasicUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -423,6 +471,16 @@ function construct_device!( ) add_constraints!(container, CommitmentConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -833,6 +891,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalMultiStartUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -935,6 +997,16 @@ function construct_device!( network_model, ) add_constraints!(container, ActiveRangeICConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -969,6 +1041,10 @@ function construct_device!( add_variables!(container, TimeDurationOff, devices, ThermalMultiStartUnitCommitment()) add_variables!(container, PowerOutput, devices, ThermalMultiStartUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -1057,6 +1133,16 @@ function construct_device!( network_model, ) add_constraints!(container, ActiveRangeICConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -1096,6 +1182,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalCompactUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -1173,6 +1263,16 @@ function construct_device!( add_constraints!(container, CommitmentConstraint, devices, model, network_model) add_constraints!(container, RampConstraint, devices, model, network_model) add_constraints!(container, DurationConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -1206,6 +1306,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalCompactUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -1274,6 +1378,16 @@ function construct_device!( add_constraints!(container, CommitmentConstraint, devices, model, network_model) add_constraints!(container, RampConstraint, devices, model, network_model) add_constraints!(container, DurationConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -1311,6 +1425,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalBasicCompactUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -1386,6 +1504,16 @@ function construct_device!( network_model, ) add_constraints!(container, CommitmentConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) @@ -1417,6 +1545,10 @@ function construct_device!( initial_conditions!(container, devices, ThermalBasicCompactUnitCommitment()) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -1483,6 +1615,16 @@ function construct_device!( ) add_constraints!(container, CommitmentConstraint, devices, model, network_model) + if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) + add_constraints!( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + end add_feedforward_constraints!(container, model, devices) From a8d9f28c63a953b5f387ede8ea59addf71784899 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:24 -0600 Subject: [PATCH 004/162] add constraint call --- .../devices/thermal_generation.jl | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 3f3be9f01..9cde131af 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -445,6 +445,30 @@ function _get_data_for_range_ic( return ini_conds end +function add_constraints!( + container::OptimizationContainer, + ::Type{ActivePowerVariableTimeSeriesLimitsConstraint}, + U::Type{<:Union{ActivePowerVariable, ActivePowerRangeExpressionUB}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.ThermalGen, + W <: AbstractThermalUnitCommitment, + X <: PM.AbstractPowerModel, +} + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + """ This function adds range constraint for the first time period. Constraint (10) from PGLIB formulation """ From 4c29c68f5deea60e4f27d52053264ae00ae39a8f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:37 -0600 Subject: [PATCH 005/162] add checks for ts property --- .../devices/common/range_constraint.jl | 19 ++++++++++++++++--- src/services_models/services_constructor.jl | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/common/range_constraint.jl b/src/devices_models/devices/common/range_constraint.jl index 0a7c4b804..37e5495ca 100644 --- a/src/devices_models/devices/common/range_constraint.jl +++ b/src/devices_models/devices/common/range_constraint.jl @@ -706,6 +706,9 @@ function lower_bound_range_with_parameter!( jump_model = get_jump_model(container) time_steps = axes(constraint_container)[2] for device in devices + if !(PSY.has_time_series(device)) + continue + end name = PSY.get_name(device) param = get_parameter_column_refs(param_container, name) for t in time_steps @@ -730,8 +733,11 @@ function _add_parameterized_lower_bound_range_constraints_impl!( W <: AbstractDeviceFormulation, } time_steps = get_time_steps(container) - names = [PSY.get_name(d) for d in devices] - + names = [PSY.get_name(d) for d in devices if PSY.has_time_series(d)] + if isempty(names) + @debug "There are no $V devices with time series data" + return + end constraint = add_constraints_container!(container, T(), V, names, time_steps; meta = "lb") @@ -842,6 +848,9 @@ function upper_bound_range_with_parameter!( time_steps = axes(constraint_container)[2] for device in devices name = PSY.get_name(device) + if !(PSY.has_time_series(device)) + continue + end param = get_parameter_column_refs(param_container, name) for t in time_steps constraint_container[name, t] = @@ -865,7 +874,11 @@ function _add_parameterized_upper_bound_range_constraints_impl!( W <: AbstractDeviceFormulation, } time_steps = get_time_steps(container) - names = [PSY.get_name(d) for d in devices] + names = [PSY.get_name(d) for d in devices if PSY.has_time_series(d)] + if isempty(names) + @debug "There are no $V devices with time series data" + return + end constraint = add_constraints_container!(container, T(), V, names, time_steps; meta = "ub") diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 6deb80d30..8b02409f0 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - #add_feedforward_arguments!(container, model, service) + add_feedforward_arguments!(container, model, service) return end From 9324ae7bbcce11fa3af751fec32ddc11906234cf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:58:25 -0600 Subject: [PATCH 006/162] improve error print --- src/devices_models/devices/default_interface_methods.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/default_interface_methods.jl b/src/devices_models/devices/default_interface_methods.jl index 0fd71e624..5391344ae 100644 --- a/src/devices_models/devices/default_interface_methods.jl +++ b/src/devices_models/devices/default_interface_methods.jl @@ -11,7 +11,7 @@ get_variable_lower_bound(_, ::PSY.Component, __) = nothing get_variable_upper_bound(_, ::PSY.Component, __) = nothing get_multiplier_value(x, y::PSY.Component, z) = - error("Unable to get parameter $x for device $y for formulation $z") + error("Unable to get parameter $x for device $(IS.summary(y)) for formulation $z") get_expression_type_for_reserve(_, y::Type{<:PSY.Component}, z) = error("`get_expression_type_for_reserve` must be implemented for $y and $z") From b4ac3d634d3e7cdff5c94b5fb66ba58f0d39c58a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:58:37 -0600 Subject: [PATCH 007/162] add multiplier function --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 9cde131af..ebe8bedf9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From f409dcf90aea8511e64ef685f985e622f0db1b06 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:58:55 -0600 Subject: [PATCH 008/162] add constructor test --- ..._device_thermal_generation_constructors.jl | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index cdb3a3881..9197bcd5e 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -921,3 +921,49 @@ end end end end + +@testset "Thermal with max_active_power time series" begin + device_model = DeviceModel( + ThermalStandard, + ThermalStandardUnitCommitment; + time_series_names = Dict(ActivePowerTimeSeriesParameter => "max_active_power")) + c_sys5 = PSB.build_system(PSITestSystems, "c_sys5") + + derate_data = SortedDict{Dates.DateTime, TimeSeries.TimeArray}() + data_ts = collect( + DateTime("1/1/2024 0:00:00", "d/m/y H:M:S"):Hour(1):DateTime( + "1/1/2024 23:00:00", + "d/m/y H:M:S", + ), + ) + for t in 1:2 + ini_time = data_ts[1] + Day(t - 1) + derate_data[ini_time] = + TimeArray(data_ts + Day(t - 1), fill!(Vector{Float64}(undef, 24), 0.8)) + end + solitude = get_component(ThermalStandard, c_sys5, "Solitude") + PSY.add_time_series!( + c_sys5, + solitude, + PSY.Deterministic("max_active_power", derate_data), + ) + + model = DecisionModel( + MockOperationProblem, + DCPPowerModel, + c_sys5) + + mock_construct_device!(model, device_model) + moi_tests(model, 480, 0, 504, 120, 120, true) + key = PSI.ConstraintKey( + ActivePowerVariableTimeSeriesLimitsConstraint, + ThermalStandard, + "ub", + ) + constraint = PSI.get_constraint(PSI.get_optimization_container(model), key) + ub_value = get_max_active_power(solitude) * 0.8 + for ix in eachindex(constraint) + @test JuMP.normalized_rhs(constraint[ix]) == ub_value + end + psi_checkobjfun_test(model, GAEVF) +end From 5bd5dffd872c01ecc967ad82e116d302ffb44d5b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:00:43 -0600 Subject: [PATCH 009/162] fix test --- src/services_models/services_constructor.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 8b02409f0..e645c2cf8 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -534,9 +534,9 @@ function construct_service!( network_model::NetworkModel{<:PM.AbstractPowerModel}, ) where {T <: PSY.TransmissionInterface} interfaces = get_available_components(model, sys) + interface = PSY.get_component(T, sys, get_service_name(model)) if get_use_slacks(model) # Adding the slacks can be done in a cleaner fashion - interface = PSY.get_component(T, sys, get_service_name(model)) @assert PSY.get_available(interface) transmission_interface_slacks!(container, interface) end @@ -548,7 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + add_feedforward_arguments!(container, model, interface) return end From 792e5471c75a8e5e543de32bbbee4b4dec94b19b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:52:39 -0600 Subject: [PATCH 010/162] comment out unrelated broken method --- src/services_models/services_constructor.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index e645c2cf8..f547d622b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,8 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, interface) + # TODO:broken + # add_feedforward_arguments!(container, model, interface) return end From 46085e76ad33071bab96a0087a5dda025fdb32d3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 17:55:41 -0600 Subject: [PATCH 011/162] add missing ts check --- src/parameters/update_container_parameter_values.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/parameters/update_container_parameter_values.jl b/src/parameters/update_container_parameter_values.jl index 5784c0964..be42d2b00 100644 --- a/src/parameters/update_container_parameter_values.jl +++ b/src/parameters/update_container_parameter_values.jl @@ -50,6 +50,9 @@ function _update_parameter_values!( components = get_available_components(device_model, get_system(model)) ts_uuids = Set{String}() for component in components + if !PSY.has_time_series(component) + continue + end ts_uuid = string(IS.get_time_series_uuid(U, component, ts_name)) if !(ts_uuid in ts_uuids) ts_vector = get_time_series_values!( From 4ba5a3bdd3219a610d7a3359189cde2881bf813a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 012/162] update fuelcost param changes --- src/devices_models/devices/thermal_generation.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ebe8bedf9..b3573d405 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,6 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From f69b942f1009e9773e2de548a38811a6e900af15 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 013/162] add new params and exprs --- src/core/expressions.jl | 1 + src/core/parameters.jl | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index f5ad354a7..173cfe7f4 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -8,6 +8,7 @@ struct EmergencyUp <: ExpressionType end struct EmergencyDown <: ExpressionType end struct RawACE <: ExpressionType end struct ProductionCostExpression <: CostExpressions end +struct FuelConsumptionExpression <: ExpressionType end struct ActivePowerRangeExpressionLB <: RangeConstraintLBExpressions end struct ActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end diff --git a/src/core/parameters.jl b/src/core/parameters.jl index e772d6e37..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ @@ -308,6 +303,11 @@ Parameter to define cost function coefficient """ struct CostFunctionParameter <: ObjectiveFunctionParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostParameter <: ObjectiveFunctionParameter end + abstract type AuxVariableValueParameter <: RightHandSideParameter end struct EventParameter <: ParameterType end From 27d80fcc78aafdbffdc69637425cf4d0f6300091 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:29 -0700 Subject: [PATCH 014/162] update device model to take any parameter type --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index edc65bba8..1d30dd888 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -49,7 +49,7 @@ mutable struct DeviceModel{D <: PSY.Device, B <: AbstractDeviceFormulation} use_slacks::Bool duals::Vector{DataType} services::Vector{ServiceModel} - time_series_names::Dict{Type{<:TimeSeriesParameter}, String} + time_series_names::Dict{Type{<:PSI.ParameterType}, String} attributes::Dict{String, Any} subsystem::Union{Nothing, String} From 93a8fa2d9163d945c4d05797d54cbeb9a9bc94c8 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 015/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../thermalgeneration_constructor.jl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index bbb169b86..6d5d19fa6 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,8 +789,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -804,6 +804,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, @@ -820,6 +822,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return From deef888dba9e620d894858e7184af8d21fad613c Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 016/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index b3573d405..ac6d3e3e3 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,7 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -195,8 +195,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From 10d60f32e9fca11368ca5715603bfafa358083a8 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:34 -0700 Subject: [PATCH 017/162] update expression for fuel consumption --- .../devices/common/add_to_expression.jl | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 9c53a40e0..533267abc 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -26,6 +26,25 @@ function add_expressions!( return end +function add_expressions!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelConsumptionExpression, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + time_steps = get_time_steps(container) + names = [ + PSY.get_name(d) for + d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve + ] + add_expression_container!(container, T(), D, names, time_steps) + return +end + function add_expressions!( container::OptimizationContainer, ::Type{T}, @@ -1533,6 +1552,52 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: ActivePowerVariable, + V <: PSY.ThermalGen, + W <: AbstractThermalDispatchFormulation, +} + expression = get_expression(container, T(), V) + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + else + error("Not implemented yet") + end + end +end + #= function add_to_expression!( container::OptimizationContainer, From 97156f5df67a049ac2ca2fc3a34f963afa4d9062 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:55 -0700 Subject: [PATCH 018/162] add fuel cost timeseries for linear --- .../common/objective_function/linear_curve.jl | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 06d47c9b2..7d76ecdb0 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -115,12 +115,26 @@ end function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, - component::PSY.Component, - fuel_curve::Float64, + component::V, + heat_rate::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, -) where {T <: VariableType} - error("Not implemented yet") - _add_linearcurve_variable_cost!(container, T(), component, fuel_curve) +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end """ From 8ecdd2163bc12847e81c98f1c9e887263c0b7d72 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:37:06 -0700 Subject: [PATCH 019/162] add fuel cost params methods --- src/parameters/add_parameters.jl | 64 +++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index ae39d01d4..4024848fd 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,6 +34,23 @@ function add_parameters!( return end +function add_parameters!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelCostParameter, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + if get_rebuild_model(get_settings(container)) && has_container_key(container, T, D) + return + end + _add_parameters!(container, T(), devices, model) + return +end + function add_parameters!( container::OptimizationContainer, ::Type{T}, @@ -256,7 +273,52 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - _add_time_series_parameters!(container, param, devices, model) + #error("here") + ts_type = get_default_time_series_type(container) + if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) + error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + end + time_steps = get_time_steps(container) + # TODO: Check for timeseries only for fuel cost + device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + jump_model = get_jump_model(container) + + param_container = add_param_container!( + container, + param, + D, + ActivePowerVariable, + PSI.SOSStatusVariable.NO_VARIABLE, + false, + Float64, + device_names, + time_steps, + ) + + ts_name = get_time_series_names(model)[T] + + for device in devices + if !PSY.has_time_series(device) + continue + end + ts_vals = get_time_series_initial_values!(container, ts_type, device, ts_name) + name = PSY.get_name(device) + for step in time_steps + PSI.set_parameter!( + param_container, + jump_model, + ts_vals[step], + name, + step, + ) + PSI.set_multiplier!( + param_container, + get_multiplier_value(T(), device, W()), + name, + step, + ) + end + end return end From 73528eb16fc2f3803dd2be1c4fd165bb75bbb303 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:39:52 -0700 Subject: [PATCH 020/162] remove commented error --- src/parameters/add_parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 4024848fd..d06881d0c 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -273,7 +273,6 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - #error("here") ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") From 06a4253a95c76e714e7f79ac9a9836b6e14201b0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:47 -0700 Subject: [PATCH 021/162] add export --- src/PowerSimulations.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index cd8544a63..3b3fe5246 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -323,6 +323,7 @@ export EmergencyUp export EmergencyDown export RawACE export ProductionCostExpression +export FuelConsumptionExpression export ActivePowerRangeExpressionLB export ActivePowerRangeExpressionUB From 3582a85f73936780121b1ebfe1fbc3d42db8496b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:57 -0700 Subject: [PATCH 022/162] add write result --- src/core/expressions.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 173cfe7f4..e1e8454eb 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -17,6 +17,7 @@ struct InterfaceTotalFlow <: ExpressionType end struct PTDFBranchFlow <: ExpressionType end should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{FuelConsumptionExpression}) = true should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true should_write_resulting_value(::Type{ActivePowerBalance}) = true From 97f6de34c10929e78ff10e1a02f6a366d16b0765 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:45:41 -0700 Subject: [PATCH 023/162] avoid mutation of invariant terms --- src/core/optimization_container.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index b94438f9b..c2702c64c 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -35,8 +35,12 @@ function get_objective_expression(v::ObjectiveFunction) else # JuMP doesn't support expression conversion from Affn to QuadExpressions if isa(v.invariant_terms, JuMP.GenericQuadExpr) - return JuMP.add_to_expression!(v.invariant_terms, v.variant_terms) + # Avoid mutation of invariant term + temp_expr = JuMP.QuadExpr() + JuMP.add_to_expression!(temp_expr, v.invariant_terms) + return JuMP.add_to_expression!(temp_expr, v.variant_terms) else + # This will mutate the variant terms, but these are reseted at each step. return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) end end From 2aecfd5c6b3ee32249b62e50d7b702ed656b95b2 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:46:16 -0700 Subject: [PATCH 024/162] add quadratic and dt to fuel consumption --- .../devices/common/add_to_expression.jl | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 533267abc..9c053de1e 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1522,7 +1522,7 @@ function add_to_expression!( cost_expression::Union{JuMP.AbstractJuMPScalar, Float64}, component::T, time_period::Int, -) where {S <: CostExpressions, T <: PSY.Component} +) where {S <: Union{CostExpressions, FuelConsumptionExpression}, T <: PSY.Component} if has_container_key(container, S, T) device_cost_expression = get_expression(container, S(), T) component_name = PSY.get_name(component) @@ -1568,6 +1568,8 @@ function add_to_expression!( variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR for d in devices var_cost = PSY.get_variable(PSY.get_operation_cost(d)) if !(var_cost isa PSY.FuelCurve) @@ -1586,14 +1588,39 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - else - error("Not implemented yet") end end end From 04b4dc4d72bc11fecba19995e8fce8826bdde2bd Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:51:37 -0700 Subject: [PATCH 025/162] Add parameter for fuel cost Co-authored-by: jd-lara --- src/parameters/add_parameters.jl | 7 +- src/parameters/update_cost_parameters.jl | 104 ++++++++++++++++++----- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index d06881d0c..d4c7a3cd6 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -275,11 +275,16 @@ function _add_parameters!( } where {D <: PSY.Component} ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) - error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + error( + "add_parameters! for ObjectiveFunctionParameter is not compatible with $ts_type", + ) end time_steps = get_time_steps(container) # TODO: Check for timeseries only for fuel cost device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + if isempty(device_names) + return + end jump_model = get_jump_model(container) param_container = add_param_container!( diff --git a/src/parameters/update_cost_parameters.jl b/src/parameters/update_cost_parameters.jl index 600eca675..6adc85707 100644 --- a/src/parameters/update_cost_parameters.jl +++ b/src/parameters/update_cost_parameters.jl @@ -14,31 +14,62 @@ function _update_parameter_values!( 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, + op_cost = PSY.get_operation_cost(component) + if op_cost isa PSY.MarketBidCost + ts_vector = PSY.get_variable_cost( component, - t, + 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 + elseif op_cost isa PSY.ThermalGenerationCost + fuel_curve = PSY.get_variable(op_cost) + ts_vector = PSY.get_fuel_cost( + component; + start_time = initial_forecast_time, + len = horizon, + ) + fuel_cost_forecast_values = TimeSeries.values(ts_vector) + for (t, value) in enumerate(fuel_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, + fuel_curve, + t, + ) + end + else + error( + "Update Cost Function Parameter not implemented for $(typeof(op_cost))", ) end end @@ -50,6 +81,15 @@ _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 _has_variable_cost_parameter(cost::T) where {T <: PSY.ThermalGenerationCost} + var_cost = PSY.get_variable(cost) + if var_cost isa PSY.FuelCurve + if PSY.get_fuel_cost(var_cost) isa IS.TimeSeriesKey + return true + end + end + return false +end function _update_pwl_cost_expression( container::OptimizationContainer, @@ -123,3 +163,25 @@ function update_variable_cost!( set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) return end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::JuMPFloatArray, + parameter_multiplier::JuMPFloatArray, + ::CostFunctionAttributes{Float64}, + component::T, + fuel_curve::PSY.FuelCurve, + time_period::Int, +) where {T <: PSY.Component} + component_name = PSY.get_name(component) + fuel_cost = parameter_array[component_name, time_period] + if all(iszero.(last.(fuel_cost))) + return + end + mult_ = parameter_multiplier[component_name, time_period] + expression = get_expression(container, FuelConsumptionExpression(), T) + cost_expr = expression[component_name, time_period] * fuel_cost * mult_ + add_to_objective_variant_expression!(container, cost_expr) + set_expression!(container, ProductionCostExpression, cost_expr, component, time_period) + return +end From 50f7ed494437c3c9232409f0aa3677669ab5fd7b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:53:39 -0700 Subject: [PATCH 026/162] update getter for fuel cost pwl Co-authored-by: jd-lara --- .../common/objective_function/common.jl | 44 ++++++++--- .../objective_function/piecewise_linear.jl | 77 ++++++++++++++++--- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index c02b55a51..84297bca4 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -265,18 +265,42 @@ end ################################################## function _get_fuel_cost_value( - ::OptimizationContainer, - fuel_cost::Float64, - ::Int, -) - return fuel_cost + container::OptimizationContainer, + component::T, + time_period::Int, +) where {T <: PSY.Component} + # TODO: Check time series for derating to work later + if PSY.has_time_series(component) + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(component) + return parameter_array[name, time_period] * parameter_multiplier[name, time_period] + else + return PSY.get_fuel_cost(component) + end end -function _get_fuel_cost_value( +function _add_time_varying_fuel_variable_cost!( container::OptimizationContainer, + ::T, + component::V, fuel_cost::IS.TimeSeriesKey, - time_period::Int, -) - error("Not implemented yet fuel cost") - return fuel_cost +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end 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 d173cd85d..f39378f2c 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -320,22 +320,18 @@ function _get_pwl_cost_expression( base_power, device_base_power, ) - fuel_cost = PSY.get_fuel_cost(cost_function) - fuel_cost_value = _get_fuel_cost_value( - container, - fuel_cost, - time_period, - ) # Multiplier is not necessary here. There is no negative cost for fuel curves. resolution = get_resolution(container) dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - return _get_pwl_cost_expression( + # TODO: Update name get_pwl_cost_expression + fuel_consumption_expression = _get_pwl_cost_expression( container, component, time_period, cost_data_normalized, - dt * fuel_cost_value, + dt, ) + return fuel_consumption_expression end ################################################## @@ -484,10 +480,7 @@ function _add_variable_cost_to_objective!( container::OptimizationContainer, ::T, component::PSY.Component, - cost_function::Union{ - PSY.CostCurve{PSY.PiecewisePointCurve}, - PSY.FuelCurve{PSY.PiecewisePointCurve}, - }, + cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, ::U, ) where {T <: VariableType, U <: AbstractDeviceFormulation} component_name = PSY.get_name(component) @@ -515,6 +508,66 @@ function _add_variable_cost_to_objective!( return end +""" +Creates piecewise linear cost function using a sum of variables and expression with sign and time step included. + +# Arguments + + - container::OptimizationContainer : the optimization_container model built in PowerSimulations + - var_key::VariableKey: The variable name + - component_name::String: The component_name of the variable container + - cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}: container for piecewise linear cost +""" +function _add_variable_cost_to_objective!( + container::OptimizationContainer, + ::T, + component::PSY.Component, + cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, + ::U, +) where {T <: VariableType, U <: AbstractDeviceFormulation} + component_name = PSY.get_name(component) + @debug "PWL Variable Cost" _group = LOG_GROUP_COST_FUNCTIONS component_name + # If array is full of tuples with zeros return 0.0 + value_curve = PSY.get_value_curve(cost_function) + cost_component = PSY.get_function_data(value_curve) + if all(iszero.((point -> point.y).(PSY.get_points(cost_component)))) # TODO I think this should have been first. before? + @debug "All cost terms for component $(component_name) are 0.0" _group = + LOG_GROUP_COST_FUNCTIONS + return + end + pwl_fuel_consumption_expressions = + _add_pwl_term!(container, component, cost_function, T(), U()) + is_time_variant = PSY.has_time_series(component) + for t in get_time_steps(container) + fuel_cost_value = _get_fuel_cost_value( + container, + component, + t, + ) + pwl_cost_expression = pwl_fuel_consumption_expressions[t] * fuel_cost_value + add_to_expression!( + container, + ProductionCostExpression, + pwl_cost_expression, + component, + t, + ) + add_to_expression!( + container, + FuelConsumptionExpression, + pwl_fuel_consumption_expressions[t], + component, + t, + ) + if is_time_variant + add_to_objective_variant_expression!(container, pwl_cost_expression) + else + add_to_objective_invariant_expression!(container, pwl_cost_expression) + end + end + return +end + ################################################## ###### CostCurve: PiecewiseIncrementalCurve ###### ######### and PiecewiseAverageCurve ############## From 3d74a48d65529a120f14be4cdcdbc523d8f54605 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:54:02 -0700 Subject: [PATCH 027/162] update linear and quadratic methods to use new function --- .../common/objective_function/linear_curve.jl | 18 ++---------------- .../objective_function/quadratic_curve.jl | 9 +-------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 7d76ecdb0..91e2a9eed 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -116,24 +116,10 @@ function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, component::V, - heat_rate::Float64, # already normalized in MMBTU/p.u. + ::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType, V <: PSY.Component} - parameter = get_parameter_array(container, FuelCostParameter(), V) - multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) - expression = get_expression(container, FuelConsumptionExpression(), V) - name = PSY.get_name(component) - for t in get_time_steps(container) - cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] - add_to_expression!( - container, - ProductionCostExpression, - cost_expr, - component, - t, - ) - add_to_objective_variant_expression!(container, cost_expr) - end + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) return end diff --git a/src/devices_models/devices/common/objective_function/quadratic_curve.jl b/src/devices_models/devices/common/objective_function/quadratic_curve.jl index 686dc0d23..0bc31bbe5 100644 --- a/src/devices_models/devices/common/objective_function/quadratic_curve.jl +++ b/src/devices_models/devices/common/objective_function/quadratic_curve.jl @@ -212,14 +212,7 @@ function _add_fuel_quadratic_variable_cost!( quadratic_fuel_curve::Float64, fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType} - error("Not implemented yet") - _add_quadraticcurve_variable_cost!( - container, - T(), - component, - proportional_fuel_curve, - quadratic_fuel_curve, - ) + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) end @doc raw""" From d20061c6f990a9d2fd6dd533da9ca40e5bba602e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 028/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 145 +++++++++++++++++- .../devices/common/add_to_expression.jl | 90 ++++++++++- 2 files changed, 231 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 6d5d19fa6..37a5332e2 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -78,6 +78,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -95,6 +96,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return end @@ -193,6 +201,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -210,6 +219,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -307,6 +323,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -324,6 +341,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -419,6 +443,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -436,6 +461,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -524,6 +556,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -541,6 +574,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -618,6 +658,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -635,6 +676,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -711,6 +759,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -728,6 +777,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -803,7 +859,6 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( @@ -931,6 +986,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -948,6 +1004,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1073,6 +1139,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1090,6 +1157,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1213,6 +1290,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1230,6 +1308,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1337,6 +1425,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1354,6 +1443,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1456,6 +1555,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1473,6 +1573,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1576,6 +1686,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1593,6 +1704,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1672,6 +1793,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1705,6 +1827,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end @@ -1789,6 +1921,7 @@ function construct_device!( initial_conditions!(container, devices, ThermalCompactDispatch()) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1806,6 +1939,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 9c053de1e..b0a74234d 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -41,7 +41,9 @@ function add_expressions!( PSY.get_name(d) for d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve ] - add_expression_container!(container, T(), D, names, time_steps) + if !isempty(names) + add_expression_container!(container, T(), D, names, time_steps) + end return end @@ -1562,9 +1564,86 @@ function add_to_expression!( T <: FuelConsumptionExpression, U <: ActivePowerVariable, V <: PSY.ThermalGen, - W <: AbstractThermalDispatchFormulation, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end + +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, } - expression = get_expression(container, T(), V) variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) @@ -1575,6 +1654,7 @@ function add_to_expression!( if !(var_cost isa PSY.FuelCurve) continue end + expression = get_expression(container, T(), V) name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) @@ -1610,6 +1690,8 @@ function add_to_expression!( base_power, device_base_power, ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= for t in time_steps fuel_expr = ( @@ -1621,9 +1703,11 @@ function add_to_expression!( fuel_expr, ) end + =# end end end +=# #= function add_to_expression!( From 33017ab59002dc0a9c65ffae8efc59f0bd9af985 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 17 Oct 2024 14:52:56 -0700 Subject: [PATCH 029/162] add fuel cost test --- ..._device_thermal_generation_constructors.jl | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 9197bcd5e..45809467d 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -967,3 +967,63 @@ end end psi_checkobjfun_test(model, GAEVF) end + +@testset "Thermal with fuel cost time series" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + set_device_model!(template, ThermalStandard, ThermalDispatchNoMin) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + moi_tests(model, 432, 0, 192, 120, 72, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] + + @test sum(p_brighton[1:24]) < 50.0 # Barely used when expensive + @test sum(p_brighton[25:48]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive +end From 1108b6b80fbbc22cebbef70750f84e407b205058 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:37 -0800 Subject: [PATCH 030/162] move cost term around to update objective function with variable fuel cost --- .../common/objective_function/common.jl | 4 ++-- .../devices/thermal_generation.jl | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 84297bca4..b3318a5e9 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -107,9 +107,9 @@ function add_proportional_cost!( multiplier = objective_function_multiplier(U(), V()) for d in devices op_cost_data = PSY.get_operation_cost(d) - cost_term = proportional_cost(op_cost_data, U(), d, V()) - iszero(cost_term) && continue for t in get_time_steps(container) + cost_term = proportional_cost(container, op_cost_data, U(), d, V(), t) + iszero(cost_term) && continue if !PSY.get_must_run(d) exp = _add_proportional_term!(container, U(), d, cost_term * multiplier, t) add_to_expression!(container, ProductionCostExpression, exp, d, t) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ac6d3e3e3..ae11c88a9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -77,8 +77,8 @@ initial_condition_variable(::InitialTimeDurationOff, d::PSY.ThermalGen, ::Abstra ########################Objective Function################################################## # TODO: Decide what is the cost for OnVariable, if fixed or constant term in variable -function proportional_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation) - return onvar_cost(cost, S, T, U) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) +function proportional_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return onvar_cost(container, cost, S, T, U, t) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) end proportional_cost(cost::PSY.MarketBidCost, ::OnVariable, ::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_no_load_cost(cost) @@ -113,8 +113,8 @@ variable_cost(cost::PSY.OperationalCost, ::PowerAboveMinimumVariable, ::PSY.Ther """ Theoretical Cost at power output zero. Mathematically is the intercept with the y-axis """ -function onvar_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation) - return _onvar_cost(PSY.get_variable(cost), d) +function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return _onvar_cost(container, PSY.get_variable(cost), d, t) end function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) @@ -122,7 +122,7 @@ function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::P return 0.0 end -function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen, ::Int) value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # Always in \$/h @@ -130,22 +130,22 @@ function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.Co return constant_term end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(container::OptimizationContainer, cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::T, t::Int) where {T <: PSY.ThermalGen} value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # In Unit/h (unit typically in ) @@ -154,7 +154,11 @@ function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.Fu if typeof(fuel_cost) <: Float64 return constant_term * fuel_cost else - error("Time series not implemented yet") + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(d) + return constant_term * parameter_array[name, t] * parameter_multiplier[name, t] end end From e7ab9a49dfc484fcc318901475fcbd34c2b3467d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 031/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 74 +++++++++++-------- .../devices/common/add_to_expression.jl | 50 +++++-------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 37a5332e2..eb6f041c3 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -958,6 +958,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1004,16 +1007,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1119,6 +1120,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1157,16 +1161,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1271,6 +1273,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1308,16 +1313,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1406,6 +1409,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1443,16 +1449,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return end @@ -1536,6 +1540,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1573,16 +1580,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1667,6 +1672,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1704,16 +1712,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + add_feedforward_arguments!(container, model, devices) return end @@ -1778,6 +1785,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1827,16 +1837,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + return end @@ -1897,6 +1906,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1939,16 +1951,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index b0a74234d..1df33b5a2 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1630,8 +1630,6 @@ function add_to_expression!( end end -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= function add_to_expression!( container::OptimizationContainer, ::Type{T}, @@ -1658,6 +1656,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1668,46 +1667,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From a6aae9dbba96d0dd7bddda993bb7e0b8379b49a9 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:59:34 -0800 Subject: [PATCH 032/162] update function call for onvar cost --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ae11c88a9..506282e89 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -117,7 +117,7 @@ function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGeneratio return _onvar_cost(container, PSY.get_variable(cost), d, t) end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end From 8cf452da75700631c802e5068050edffa9b19f67 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 16:33:49 -0800 Subject: [PATCH 033/162] add test quad + pwl --- .../devices/common/add_to_expression.jl | 1 + ..._device_thermal_generation_constructors.jl | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 1df33b5a2..d14956b26 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1612,6 +1612,7 @@ function add_to_expression!( base_power, device_base_power, ) + error("TODO: Implement FuelConsumptionExpression AffExpr to QuadExpr") # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr #= for t in time_steps diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 45809467d..c1e36abe9 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1027,3 +1027,81 @@ end @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive end + +@testset "Thermal with fuel cost time series with Quadratic and PWL" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + solitude = get_component(ThermalStandard, sys, "Solitude") + op_cost = get_operation_cost(solitude) + ts = deepcopy(get_time_series(Deterministic, solitude, "fuel_cost")) + remove_time_series!(sys, Deterministic, solitude, "fuel_cost") + quad_curve = QuadraticCurve(0.05, 1.0, 0.0) + new_th_cost = ThermalGenerationCost(; + variable = FuelCurve(; + value_curve = quad_curve, + fuel_cost = 1.0, + ), + fixed = op_cost.fixed, + start_up = op_cost.start_up, + shut_down = op_cost.shut_down, + ) + + set_operation_cost!(solitude, new_th_cost) + add_time_series!( + sys, + solitude, + ts, + ) + + set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + # TODO Tests + moi_tests(model, 1, 2, 3, 4, 5, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] +end From f481ae312c5d700ffeee64f1af550f5ca7f1d629 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 034/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++++ src/devices_models/devices/thermal_generation.jl | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2946dd68f..e772d6e37 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 3c6f50c09..bbb169b86 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,6 +789,10 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 536d54ead..9cde131af 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -194,7 +194,9 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}() + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", + ) end function get_default_attributes( From 04611f799fa14f0200fee0142c4a5685435a95e3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:37 -0600 Subject: [PATCH 035/162] add checks for ts property --- src/services_models/services_constructor.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index f547d622b..b7999dd2b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,8 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - # TODO:broken - # add_feedforward_arguments!(container, model, interface) + add_feedforward_arguments!(container, model, service) return end From c89a61860cd3a7ecfe12197fea3a55a03563cb32 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:58:37 -0600 Subject: [PATCH 036/162] add multiplier function --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 9cde131af..ebe8bedf9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From cbc0dead9039175f5e9e6488d900c7cdc8722eb0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 037/162] update fuelcost param changes --- src/devices_models/devices/thermal_generation.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ebe8bedf9..b3573d405 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,6 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From 8492c1e9babeacaa7f5d18ae718c745ffcf4a8da Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 038/162] add new params and exprs --- src/core/expressions.jl | 1 + src/core/parameters.jl | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index f5ad354a7..173cfe7f4 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -8,6 +8,7 @@ struct EmergencyUp <: ExpressionType end struct EmergencyDown <: ExpressionType end struct RawACE <: ExpressionType end struct ProductionCostExpression <: CostExpressions end +struct FuelConsumptionExpression <: ExpressionType end struct ActivePowerRangeExpressionLB <: RangeConstraintLBExpressions end struct ActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end diff --git a/src/core/parameters.jl b/src/core/parameters.jl index e772d6e37..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ @@ -308,6 +303,11 @@ Parameter to define cost function coefficient """ struct CostFunctionParameter <: ObjectiveFunctionParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostParameter <: ObjectiveFunctionParameter end + abstract type AuxVariableValueParameter <: RightHandSideParameter end struct EventParameter <: ParameterType end From c1a183e217a670a2e86047cf12a58d825a345f6b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:29 -0700 Subject: [PATCH 039/162] update device model to take any parameter type --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index edc65bba8..1d30dd888 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -49,7 +49,7 @@ mutable struct DeviceModel{D <: PSY.Device, B <: AbstractDeviceFormulation} use_slacks::Bool duals::Vector{DataType} services::Vector{ServiceModel} - time_series_names::Dict{Type{<:TimeSeriesParameter}, String} + time_series_names::Dict{Type{<:PSI.ParameterType}, String} attributes::Dict{String, Any} subsystem::Union{Nothing, String} From 5e990912afa37b3d3880d61c39d0ff30b0ce5f08 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 040/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../thermalgeneration_constructor.jl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index bbb169b86..6d5d19fa6 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,8 +789,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -804,6 +804,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, @@ -820,6 +822,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return From 570d40aa3ec3c2fc22d769d3dcbad94d730b1991 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 041/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index b3573d405..ac6d3e3e3 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,7 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -195,8 +195,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From 07db4435aa841ce2f1885db5e99bf028c12e42b7 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:34 -0700 Subject: [PATCH 042/162] update expression for fuel consumption --- .../devices/common/add_to_expression.jl | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 0d9902e9b..a76800e5f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -26,6 +26,25 @@ function add_expressions!( return end +function add_expressions!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelConsumptionExpression, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + time_steps = get_time_steps(container) + names = [ + PSY.get_name(d) for + d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve + ] + add_expression_container!(container, T(), D, names, time_steps) + return +end + function add_expressions!( container::OptimizationContainer, ::Type{T}, @@ -1533,6 +1552,52 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: ActivePowerVariable, + V <: PSY.ThermalGen, + W <: AbstractThermalDispatchFormulation, +} + expression = get_expression(container, T(), V) + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + else + error("Not implemented yet") + end + end +end + #= function add_to_expression!( container::OptimizationContainer, From 1e551fc17a1dc51864dc174ae2b1d6c945dcf017 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:55 -0700 Subject: [PATCH 043/162] add fuel cost timeseries for linear --- .../common/objective_function/linear_curve.jl | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 06d47c9b2..7d76ecdb0 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -115,12 +115,26 @@ end function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, - component::PSY.Component, - fuel_curve::Float64, + component::V, + heat_rate::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, -) where {T <: VariableType} - error("Not implemented yet") - _add_linearcurve_variable_cost!(container, T(), component, fuel_curve) +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end """ From a558a7c3e02da2c1d99254468c12d6ead1713092 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:37:06 -0700 Subject: [PATCH 044/162] add fuel cost params methods --- src/parameters/add_parameters.jl | 64 +++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 15ebf6e78..9ddd13bdb 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,6 +34,23 @@ function add_parameters!( return end +function add_parameters!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelCostParameter, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + if get_rebuild_model(get_settings(container)) && has_container_key(container, T, D) + return + end + _add_parameters!(container, T(), devices, model) + return +end + function add_parameters!( container::OptimizationContainer, ::Type{T}, @@ -257,7 +274,52 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - _add_time_series_parameters!(container, param, devices, model) + #error("here") + ts_type = get_default_time_series_type(container) + if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) + error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + end + time_steps = get_time_steps(container) + # TODO: Check for timeseries only for fuel cost + device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + jump_model = get_jump_model(container) + + param_container = add_param_container!( + container, + param, + D, + ActivePowerVariable, + PSI.SOSStatusVariable.NO_VARIABLE, + false, + Float64, + device_names, + time_steps, + ) + + ts_name = get_time_series_names(model)[T] + + for device in devices + if !PSY.has_time_series(device) + continue + end + ts_vals = get_time_series_initial_values!(container, ts_type, device, ts_name) + name = PSY.get_name(device) + for step in time_steps + PSI.set_parameter!( + param_container, + jump_model, + ts_vals[step], + name, + step, + ) + PSI.set_multiplier!( + param_container, + get_multiplier_value(T(), device, W()), + name, + step, + ) + end + end return end From 77ffe6ad7932b326bfc2d65c73eaa8b4093fd6a4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:39:52 -0700 Subject: [PATCH 045/162] remove commented error --- src/parameters/add_parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 9ddd13bdb..59c401eb8 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -274,7 +274,6 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - #error("here") ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") From dd52f07147ffbd4151caca1121e927728f990f14 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:47 -0700 Subject: [PATCH 046/162] add export --- src/PowerSimulations.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index cd8544a63..3b3fe5246 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -323,6 +323,7 @@ export EmergencyUp export EmergencyDown export RawACE export ProductionCostExpression +export FuelConsumptionExpression export ActivePowerRangeExpressionLB export ActivePowerRangeExpressionUB From 9d40def2821c60abcc0d8ebdd8145bb383e66592 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:57 -0700 Subject: [PATCH 047/162] add write result --- src/core/expressions.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 173cfe7f4..e1e8454eb 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -17,6 +17,7 @@ struct InterfaceTotalFlow <: ExpressionType end struct PTDFBranchFlow <: ExpressionType end should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{FuelConsumptionExpression}) = true should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true should_write_resulting_value(::Type{ActivePowerBalance}) = true From f6a354fcee282f180b7b269a568f6a5c2fe165e7 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:45:41 -0700 Subject: [PATCH 048/162] avoid mutation of invariant terms --- src/core/optimization_container.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index b94438f9b..c2702c64c 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -35,8 +35,12 @@ function get_objective_expression(v::ObjectiveFunction) else # JuMP doesn't support expression conversion from Affn to QuadExpressions if isa(v.invariant_terms, JuMP.GenericQuadExpr) - return JuMP.add_to_expression!(v.invariant_terms, v.variant_terms) + # Avoid mutation of invariant term + temp_expr = JuMP.QuadExpr() + JuMP.add_to_expression!(temp_expr, v.invariant_terms) + return JuMP.add_to_expression!(temp_expr, v.variant_terms) else + # This will mutate the variant terms, but these are reseted at each step. return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) end end From 601552fb7ee082bdf0441e6822300565e673a5d7 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:46:16 -0700 Subject: [PATCH 049/162] add quadratic and dt to fuel consumption --- .../devices/common/add_to_expression.jl | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index a76800e5f..1a81832cd 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1522,7 +1522,7 @@ function add_to_expression!( cost_expression::Union{JuMP.AbstractJuMPScalar, Float64}, component::T, time_period::Int, -) where {S <: CostExpressions, T <: PSY.Component} +) where {S <: Union{CostExpressions, FuelConsumptionExpression}, T <: PSY.Component} if has_container_key(container, S, T) device_cost_expression = get_expression(container, S(), T) component_name = PSY.get_name(component) @@ -1568,6 +1568,8 @@ function add_to_expression!( variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR for d in devices var_cost = PSY.get_variable(PSY.get_operation_cost(d)) if !(var_cost isa PSY.FuelCurve) @@ -1586,14 +1588,39 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - else - error("Not implemented yet") end end end From 7021b68b22184b4fb3c3d6b194052aa44ce8a6f0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:51:37 -0700 Subject: [PATCH 050/162] Add parameter for fuel cost Co-authored-by: jd-lara --- src/parameters/add_parameters.jl | 7 +- src/parameters/update_cost_parameters.jl | 104 ++++++++++++++++++----- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 59c401eb8..61262fc6f 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -276,11 +276,16 @@ function _add_parameters!( } where {D <: PSY.Component} ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) - error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + error( + "add_parameters! for ObjectiveFunctionParameter is not compatible with $ts_type", + ) end time_steps = get_time_steps(container) # TODO: Check for timeseries only for fuel cost device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + if isempty(device_names) + return + end jump_model = get_jump_model(container) param_container = add_param_container!( diff --git a/src/parameters/update_cost_parameters.jl b/src/parameters/update_cost_parameters.jl index 600eca675..6adc85707 100644 --- a/src/parameters/update_cost_parameters.jl +++ b/src/parameters/update_cost_parameters.jl @@ -14,31 +14,62 @@ function _update_parameter_values!( 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, + op_cost = PSY.get_operation_cost(component) + if op_cost isa PSY.MarketBidCost + ts_vector = PSY.get_variable_cost( component, - t, + 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 + elseif op_cost isa PSY.ThermalGenerationCost + fuel_curve = PSY.get_variable(op_cost) + ts_vector = PSY.get_fuel_cost( + component; + start_time = initial_forecast_time, + len = horizon, + ) + fuel_cost_forecast_values = TimeSeries.values(ts_vector) + for (t, value) in enumerate(fuel_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, + fuel_curve, + t, + ) + end + else + error( + "Update Cost Function Parameter not implemented for $(typeof(op_cost))", ) end end @@ -50,6 +81,15 @@ _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 _has_variable_cost_parameter(cost::T) where {T <: PSY.ThermalGenerationCost} + var_cost = PSY.get_variable(cost) + if var_cost isa PSY.FuelCurve + if PSY.get_fuel_cost(var_cost) isa IS.TimeSeriesKey + return true + end + end + return false +end function _update_pwl_cost_expression( container::OptimizationContainer, @@ -123,3 +163,25 @@ function update_variable_cost!( set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) return end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::JuMPFloatArray, + parameter_multiplier::JuMPFloatArray, + ::CostFunctionAttributes{Float64}, + component::T, + fuel_curve::PSY.FuelCurve, + time_period::Int, +) where {T <: PSY.Component} + component_name = PSY.get_name(component) + fuel_cost = parameter_array[component_name, time_period] + if all(iszero.(last.(fuel_cost))) + return + end + mult_ = parameter_multiplier[component_name, time_period] + expression = get_expression(container, FuelConsumptionExpression(), T) + cost_expr = expression[component_name, time_period] * fuel_cost * mult_ + add_to_objective_variant_expression!(container, cost_expr) + set_expression!(container, ProductionCostExpression, cost_expr, component, time_period) + return +end From 04ba101f914080ff9c89adbdfa6544c1835a45ba Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:53:39 -0700 Subject: [PATCH 051/162] update getter for fuel cost pwl Co-authored-by: jd-lara --- .../common/objective_function/common.jl | 44 ++++++++--- .../objective_function/piecewise_linear.jl | 77 ++++++++++++++++--- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 064b68977..9d08fd234 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -271,18 +271,42 @@ end ################################################## function _get_fuel_cost_value( - ::OptimizationContainer, - fuel_cost::Float64, - ::Int, -) - return fuel_cost + container::OptimizationContainer, + component::T, + time_period::Int, +) where {T <: PSY.Component} + # TODO: Check time series for derating to work later + if PSY.has_time_series(component) + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(component) + return parameter_array[name, time_period] * parameter_multiplier[name, time_period] + else + return PSY.get_fuel_cost(component) + end end -function _get_fuel_cost_value( +function _add_time_varying_fuel_variable_cost!( container::OptimizationContainer, + ::T, + component::V, fuel_cost::IS.TimeSeriesKey, - time_period::Int, -) - error("Not implemented yet fuel cost") - return fuel_cost +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end 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 d173cd85d..f39378f2c 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -320,22 +320,18 @@ function _get_pwl_cost_expression( base_power, device_base_power, ) - fuel_cost = PSY.get_fuel_cost(cost_function) - fuel_cost_value = _get_fuel_cost_value( - container, - fuel_cost, - time_period, - ) # Multiplier is not necessary here. There is no negative cost for fuel curves. resolution = get_resolution(container) dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - return _get_pwl_cost_expression( + # TODO: Update name get_pwl_cost_expression + fuel_consumption_expression = _get_pwl_cost_expression( container, component, time_period, cost_data_normalized, - dt * fuel_cost_value, + dt, ) + return fuel_consumption_expression end ################################################## @@ -484,10 +480,7 @@ function _add_variable_cost_to_objective!( container::OptimizationContainer, ::T, component::PSY.Component, - cost_function::Union{ - PSY.CostCurve{PSY.PiecewisePointCurve}, - PSY.FuelCurve{PSY.PiecewisePointCurve}, - }, + cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, ::U, ) where {T <: VariableType, U <: AbstractDeviceFormulation} component_name = PSY.get_name(component) @@ -515,6 +508,66 @@ function _add_variable_cost_to_objective!( return end +""" +Creates piecewise linear cost function using a sum of variables and expression with sign and time step included. + +# Arguments + + - container::OptimizationContainer : the optimization_container model built in PowerSimulations + - var_key::VariableKey: The variable name + - component_name::String: The component_name of the variable container + - cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}: container for piecewise linear cost +""" +function _add_variable_cost_to_objective!( + container::OptimizationContainer, + ::T, + component::PSY.Component, + cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, + ::U, +) where {T <: VariableType, U <: AbstractDeviceFormulation} + component_name = PSY.get_name(component) + @debug "PWL Variable Cost" _group = LOG_GROUP_COST_FUNCTIONS component_name + # If array is full of tuples with zeros return 0.0 + value_curve = PSY.get_value_curve(cost_function) + cost_component = PSY.get_function_data(value_curve) + if all(iszero.((point -> point.y).(PSY.get_points(cost_component)))) # TODO I think this should have been first. before? + @debug "All cost terms for component $(component_name) are 0.0" _group = + LOG_GROUP_COST_FUNCTIONS + return + end + pwl_fuel_consumption_expressions = + _add_pwl_term!(container, component, cost_function, T(), U()) + is_time_variant = PSY.has_time_series(component) + for t in get_time_steps(container) + fuel_cost_value = _get_fuel_cost_value( + container, + component, + t, + ) + pwl_cost_expression = pwl_fuel_consumption_expressions[t] * fuel_cost_value + add_to_expression!( + container, + ProductionCostExpression, + pwl_cost_expression, + component, + t, + ) + add_to_expression!( + container, + FuelConsumptionExpression, + pwl_fuel_consumption_expressions[t], + component, + t, + ) + if is_time_variant + add_to_objective_variant_expression!(container, pwl_cost_expression) + else + add_to_objective_invariant_expression!(container, pwl_cost_expression) + end + end + return +end + ################################################## ###### CostCurve: PiecewiseIncrementalCurve ###### ######### and PiecewiseAverageCurve ############## From 2f48f70d830d7886be8fb2a6a74588f5a91c208d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:54:02 -0700 Subject: [PATCH 052/162] update linear and quadratic methods to use new function --- .../common/objective_function/linear_curve.jl | 18 ++---------------- .../objective_function/quadratic_curve.jl | 9 +-------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 7d76ecdb0..91e2a9eed 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -116,24 +116,10 @@ function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, component::V, - heat_rate::Float64, # already normalized in MMBTU/p.u. + ::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType, V <: PSY.Component} - parameter = get_parameter_array(container, FuelCostParameter(), V) - multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) - expression = get_expression(container, FuelConsumptionExpression(), V) - name = PSY.get_name(component) - for t in get_time_steps(container) - cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] - add_to_expression!( - container, - ProductionCostExpression, - cost_expr, - component, - t, - ) - add_to_objective_variant_expression!(container, cost_expr) - end + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) return end diff --git a/src/devices_models/devices/common/objective_function/quadratic_curve.jl b/src/devices_models/devices/common/objective_function/quadratic_curve.jl index 686dc0d23..0bc31bbe5 100644 --- a/src/devices_models/devices/common/objective_function/quadratic_curve.jl +++ b/src/devices_models/devices/common/objective_function/quadratic_curve.jl @@ -212,14 +212,7 @@ function _add_fuel_quadratic_variable_cost!( quadratic_fuel_curve::Float64, fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType} - error("Not implemented yet") - _add_quadraticcurve_variable_cost!( - container, - T(), - component, - proportional_fuel_curve, - quadratic_fuel_curve, - ) + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) end @doc raw""" From 56f50fcc3e26cb511e6a3dab16b4ad5a387b4406 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 053/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 145 +++++++++++++++++- .../devices/common/add_to_expression.jl | 90 ++++++++++- 2 files changed, 231 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 6d5d19fa6..37a5332e2 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -78,6 +78,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -95,6 +96,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return end @@ -193,6 +201,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -210,6 +219,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -307,6 +323,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -324,6 +341,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -419,6 +443,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -436,6 +461,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -524,6 +556,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -541,6 +574,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -618,6 +658,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -635,6 +676,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -711,6 +759,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -728,6 +777,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -803,7 +859,6 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( @@ -931,6 +986,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -948,6 +1004,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1073,6 +1139,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1090,6 +1157,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1213,6 +1290,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1230,6 +1308,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1337,6 +1425,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1354,6 +1443,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1456,6 +1555,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1473,6 +1573,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1576,6 +1686,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1593,6 +1704,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1672,6 +1793,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1705,6 +1827,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end @@ -1789,6 +1921,7 @@ function construct_device!( initial_conditions!(container, devices, ThermalCompactDispatch()) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1806,6 +1939,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 1a81832cd..f2c2ead6f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -41,7 +41,9 @@ function add_expressions!( PSY.get_name(d) for d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve ] - add_expression_container!(container, T(), D, names, time_steps) + if !isempty(names) + add_expression_container!(container, T(), D, names, time_steps) + end return end @@ -1562,9 +1564,86 @@ function add_to_expression!( T <: FuelConsumptionExpression, U <: ActivePowerVariable, V <: PSY.ThermalGen, - W <: AbstractThermalDispatchFormulation, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end + +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, } - expression = get_expression(container, T(), V) variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) @@ -1575,6 +1654,7 @@ function add_to_expression!( if !(var_cost isa PSY.FuelCurve) continue end + expression = get_expression(container, T(), V) name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) @@ -1610,6 +1690,8 @@ function add_to_expression!( base_power, device_base_power, ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= for t in time_steps fuel_expr = ( @@ -1621,9 +1703,11 @@ function add_to_expression!( fuel_expr, ) end + =# end end end +=# #= function add_to_expression!( From 87b37f68de5f345450899679610c4c4712d46d30 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 17 Oct 2024 14:52:56 -0700 Subject: [PATCH 054/162] add fuel cost test --- ..._device_thermal_generation_constructors.jl | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 9197bcd5e..45809467d 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -967,3 +967,63 @@ end end psi_checkobjfun_test(model, GAEVF) end + +@testset "Thermal with fuel cost time series" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + set_device_model!(template, ThermalStandard, ThermalDispatchNoMin) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + moi_tests(model, 432, 0, 192, 120, 72, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] + + @test sum(p_brighton[1:24]) < 50.0 # Barely used when expensive + @test sum(p_brighton[25:48]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive +end From 9bb282537d85f7f5beb7a88fa16aedb409e3e03d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:37 -0800 Subject: [PATCH 055/162] move cost term around to update objective function with variable fuel cost --- .../common/objective_function/common.jl | 4 ++-- .../devices/thermal_generation.jl | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 9d08fd234..8b4c884b8 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -113,9 +113,9 @@ function add_proportional_cost!( multiplier = objective_function_multiplier(U(), V()) for d in devices op_cost_data = PSY.get_operation_cost(d) - cost_term = proportional_cost(op_cost_data, U(), d, V()) - iszero(cost_term) && continue for t in get_time_steps(container) + cost_term = proportional_cost(container, op_cost_data, U(), d, V(), t) + iszero(cost_term) && continue if !PSY.get_must_run(d) exp = _add_proportional_term!(container, U(), d, cost_term * multiplier, t) add_to_expression!(container, ProductionCostExpression, exp, d, t) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ac6d3e3e3..ae11c88a9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -77,8 +77,8 @@ initial_condition_variable(::InitialTimeDurationOff, d::PSY.ThermalGen, ::Abstra ########################Objective Function################################################## # TODO: Decide what is the cost for OnVariable, if fixed or constant term in variable -function proportional_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation) - return onvar_cost(cost, S, T, U) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) +function proportional_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return onvar_cost(container, cost, S, T, U, t) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) end proportional_cost(cost::PSY.MarketBidCost, ::OnVariable, ::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_no_load_cost(cost) @@ -113,8 +113,8 @@ variable_cost(cost::PSY.OperationalCost, ::PowerAboveMinimumVariable, ::PSY.Ther """ Theoretical Cost at power output zero. Mathematically is the intercept with the y-axis """ -function onvar_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation) - return _onvar_cost(PSY.get_variable(cost), d) +function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return _onvar_cost(container, PSY.get_variable(cost), d, t) end function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) @@ -122,7 +122,7 @@ function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::P return 0.0 end -function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen, ::Int) value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # Always in \$/h @@ -130,22 +130,22 @@ function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.Co return constant_term end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(container::OptimizationContainer, cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::T, t::Int) where {T <: PSY.ThermalGen} value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # In Unit/h (unit typically in ) @@ -154,7 +154,11 @@ function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.Fu if typeof(fuel_cost) <: Float64 return constant_term * fuel_cost else - error("Time series not implemented yet") + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(d) + return constant_term * parameter_array[name, t] * parameter_multiplier[name, t] end end From 0d379e36ef515598c91a8e6d74d9017eca6a0700 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 056/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 74 +++++++++++-------- .../devices/common/add_to_expression.jl | 50 +++++-------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 37a5332e2..eb6f041c3 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -958,6 +958,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1004,16 +1007,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1119,6 +1120,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1157,16 +1161,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1271,6 +1273,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1308,16 +1313,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1406,6 +1409,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1443,16 +1449,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return end @@ -1536,6 +1540,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1573,16 +1580,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1667,6 +1672,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1704,16 +1712,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + add_feedforward_arguments!(container, model, devices) return end @@ -1778,6 +1785,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1827,16 +1837,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + return end @@ -1897,6 +1906,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1939,16 +1951,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index f2c2ead6f..b1e6f1cad 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1630,8 +1630,6 @@ function add_to_expression!( end end -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= function add_to_expression!( container::OptimizationContainer, ::Type{T}, @@ -1658,6 +1656,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1668,46 +1667,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From 5bd6c5ce74a803d1f2d5d5f622c63666f8543042 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:59:34 -0800 Subject: [PATCH 057/162] update function call for onvar cost --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ae11c88a9..506282e89 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -117,7 +117,7 @@ function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGeneratio return _onvar_cost(container, PSY.get_variable(cost), d, t) end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end From 271a08f064d10b1d54605f85b3aa514ee0bbb5db Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 16:33:49 -0800 Subject: [PATCH 058/162] add test quad + pwl --- .../devices/common/add_to_expression.jl | 1 + ..._device_thermal_generation_constructors.jl | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index b1e6f1cad..22c49b7ce 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1612,6 +1612,7 @@ function add_to_expression!( base_power, device_base_power, ) + error("TODO: Implement FuelConsumptionExpression AffExpr to QuadExpr") # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr #= for t in time_steps diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 45809467d..c1e36abe9 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1027,3 +1027,81 @@ end @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive end + +@testset "Thermal with fuel cost time series with Quadratic and PWL" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + solitude = get_component(ThermalStandard, sys, "Solitude") + op_cost = get_operation_cost(solitude) + ts = deepcopy(get_time_series(Deterministic, solitude, "fuel_cost")) + remove_time_series!(sys, Deterministic, solitude, "fuel_cost") + quad_curve = QuadraticCurve(0.05, 1.0, 0.0) + new_th_cost = ThermalGenerationCost(; + variable = FuelCurve(; + value_curve = quad_curve, + fuel_cost = 1.0, + ), + fixed = op_cost.fixed, + start_up = op_cost.start_up, + shut_down = op_cost.shut_down, + ) + + set_operation_cost!(solitude, new_th_cost) + add_time_series!( + sys, + solitude, + ts, + ) + + set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + # TODO Tests + moi_tests(model, 1, 2, 3, 4, 5, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] +end From 30e24778f562c52da57d6d81ec89f70438730e71 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 14:19:14 -0700 Subject: [PATCH 059/162] change time variant check --- .../devices/common/objective_function/piecewise_linear.jl | 3 ++- src/utils/powersystems_utils.jl | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 f39378f2c..ce3928201 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -537,7 +537,8 @@ function _add_variable_cost_to_objective!( end pwl_fuel_consumption_expressions = _add_pwl_term!(container, component, cost_function, T(), U()) - is_time_variant = PSY.has_time_series(component) + + is_time_variant = is_time_variant(cost_function) for t in get_time_steps(container) fuel_cost_value = _get_fuel_cost_value( container, diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index 5d7fedf43..b7fd19292 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -338,6 +338,10 @@ function _get_piecewise_incrementalcurve_per_system_unit( return PSY.PiecewiseStepData(x_coords_normalized, y_coords_normalized) end +function is_time_variant(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}) + return isa(PSY.get_fuel_cost(cost_function), IS.TimeSeriesKey) +end + function get_deterministic_time_series_type(sys::PSY.System) time_series_types = IS.get_time_series_counts_by_type(sys.data) @show existing_types = Set(d["type"] for d in time_series_types) From cc0fae331b404963a83748b438dff159897be616 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 060/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++++ src/devices_models/devices/thermal_generation.jl | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2946dd68f..e772d6e37 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 3c6f50c09..bbb169b86 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,6 +789,10 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 536d54ead..9cde131af 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -194,7 +194,9 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}() + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", + ) end function get_default_attributes( From 0dbadb557a89982b1253fc0fe7ab189bb65fc6c2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:37 -0600 Subject: [PATCH 061/162] add checks for ts property --- src/services_models/services_constructor.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index f547d622b..b7999dd2b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,8 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - # TODO:broken - # add_feedforward_arguments!(container, model, interface) + add_feedforward_arguments!(container, model, service) return end From cf14b5fcb36acd949bf7834c182314d76ea60b87 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:58:37 -0600 Subject: [PATCH 062/162] add multiplier function --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 9cde131af..ebe8bedf9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From 00e31dc33a484b72763f4f133c7e4de64c01f4b6 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 063/162] update fuelcost param changes --- src/devices_models/devices/thermal_generation.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ebe8bedf9..b3573d405 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,6 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From b79192d87c4524cf653cc1ccaaf6928f30a087f4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 064/162] add new params and exprs --- src/core/expressions.jl | 1 + src/core/parameters.jl | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index f5ad354a7..173cfe7f4 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -8,6 +8,7 @@ struct EmergencyUp <: ExpressionType end struct EmergencyDown <: ExpressionType end struct RawACE <: ExpressionType end struct ProductionCostExpression <: CostExpressions end +struct FuelConsumptionExpression <: ExpressionType end struct ActivePowerRangeExpressionLB <: RangeConstraintLBExpressions end struct ActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end diff --git a/src/core/parameters.jl b/src/core/parameters.jl index e772d6e37..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ @@ -308,6 +303,11 @@ Parameter to define cost function coefficient """ struct CostFunctionParameter <: ObjectiveFunctionParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostParameter <: ObjectiveFunctionParameter end + abstract type AuxVariableValueParameter <: RightHandSideParameter end struct EventParameter <: ParameterType end From edac1fb25a0e0f625c4737d5fb877f097cd0da4a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:29 -0700 Subject: [PATCH 065/162] update device model to take any parameter type --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index edc65bba8..1d30dd888 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -49,7 +49,7 @@ mutable struct DeviceModel{D <: PSY.Device, B <: AbstractDeviceFormulation} use_slacks::Bool duals::Vector{DataType} services::Vector{ServiceModel} - time_series_names::Dict{Type{<:TimeSeriesParameter}, String} + time_series_names::Dict{Type{<:PSI.ParameterType}, String} attributes::Dict{String, Any} subsystem::Union{Nothing, String} From aef24c368dd40d8984553adc4876f12ce54a0558 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 066/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../thermalgeneration_constructor.jl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index bbb169b86..6d5d19fa6 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,8 +789,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -804,6 +804,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, @@ -820,6 +822,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return From fc8a812714e195d424aae667c2ff31d319b6bd76 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 067/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index b3573d405..ac6d3e3e3 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,7 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -195,8 +195,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From 1c5d06ae782352ef12f76f0c6a85bbc83444cbf0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:34 -0700 Subject: [PATCH 068/162] update expression for fuel consumption --- .../devices/common/add_to_expression.jl | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 0d9902e9b..a76800e5f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -26,6 +26,25 @@ function add_expressions!( return end +function add_expressions!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelConsumptionExpression, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + time_steps = get_time_steps(container) + names = [ + PSY.get_name(d) for + d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve + ] + add_expression_container!(container, T(), D, names, time_steps) + return +end + function add_expressions!( container::OptimizationContainer, ::Type{T}, @@ -1533,6 +1552,52 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: ActivePowerVariable, + V <: PSY.ThermalGen, + W <: AbstractThermalDispatchFormulation, +} + expression = get_expression(container, T(), V) + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + else + error("Not implemented yet") + end + end +end + #= function add_to_expression!( container::OptimizationContainer, From 5c657140ce4aff208dc788c3a6ae907633c8c620 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:55 -0700 Subject: [PATCH 069/162] add fuel cost timeseries for linear --- .../common/objective_function/linear_curve.jl | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 06d47c9b2..7d76ecdb0 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -115,12 +115,26 @@ end function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, - component::PSY.Component, - fuel_curve::Float64, + component::V, + heat_rate::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, -) where {T <: VariableType} - error("Not implemented yet") - _add_linearcurve_variable_cost!(container, T(), component, fuel_curve) +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end """ From 52806cc92afe64b4b301b7fb91a2264f414e0aa4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:37:06 -0700 Subject: [PATCH 070/162] add fuel cost params methods --- src/parameters/add_parameters.jl | 64 +++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 15ebf6e78..9ddd13bdb 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,6 +34,23 @@ function add_parameters!( return end +function add_parameters!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelCostParameter, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + if get_rebuild_model(get_settings(container)) && has_container_key(container, T, D) + return + end + _add_parameters!(container, T(), devices, model) + return +end + function add_parameters!( container::OptimizationContainer, ::Type{T}, @@ -257,7 +274,52 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - _add_time_series_parameters!(container, param, devices, model) + #error("here") + ts_type = get_default_time_series_type(container) + if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) + error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + end + time_steps = get_time_steps(container) + # TODO: Check for timeseries only for fuel cost + device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + jump_model = get_jump_model(container) + + param_container = add_param_container!( + container, + param, + D, + ActivePowerVariable, + PSI.SOSStatusVariable.NO_VARIABLE, + false, + Float64, + device_names, + time_steps, + ) + + ts_name = get_time_series_names(model)[T] + + for device in devices + if !PSY.has_time_series(device) + continue + end + ts_vals = get_time_series_initial_values!(container, ts_type, device, ts_name) + name = PSY.get_name(device) + for step in time_steps + PSI.set_parameter!( + param_container, + jump_model, + ts_vals[step], + name, + step, + ) + PSI.set_multiplier!( + param_container, + get_multiplier_value(T(), device, W()), + name, + step, + ) + end + end return end From 832843a358fdc1bf4b0dc326ac0c46bd834e7fd5 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:39:52 -0700 Subject: [PATCH 071/162] remove commented error --- src/parameters/add_parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 9ddd13bdb..59c401eb8 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -274,7 +274,6 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - #error("here") ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") From cbf0ce522db0303f3c5efb1bfb094cb7f938e2f0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:47 -0700 Subject: [PATCH 072/162] add export --- src/PowerSimulations.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index cd8544a63..3b3fe5246 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -323,6 +323,7 @@ export EmergencyUp export EmergencyDown export RawACE export ProductionCostExpression +export FuelConsumptionExpression export ActivePowerRangeExpressionLB export ActivePowerRangeExpressionUB From cfb6b2191864e21950e9a35759bed0d88a83a6b1 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:57 -0700 Subject: [PATCH 073/162] add write result --- src/core/expressions.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 173cfe7f4..e1e8454eb 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -17,6 +17,7 @@ struct InterfaceTotalFlow <: ExpressionType end struct PTDFBranchFlow <: ExpressionType end should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{FuelConsumptionExpression}) = true should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true should_write_resulting_value(::Type{ActivePowerBalance}) = true From 206ebf9c9fa2439c76bdb9e6972ac909c97f6716 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:45:41 -0700 Subject: [PATCH 074/162] avoid mutation of invariant terms --- src/core/optimization_container.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index b94438f9b..c2702c64c 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -35,8 +35,12 @@ function get_objective_expression(v::ObjectiveFunction) else # JuMP doesn't support expression conversion from Affn to QuadExpressions if isa(v.invariant_terms, JuMP.GenericQuadExpr) - return JuMP.add_to_expression!(v.invariant_terms, v.variant_terms) + # Avoid mutation of invariant term + temp_expr = JuMP.QuadExpr() + JuMP.add_to_expression!(temp_expr, v.invariant_terms) + return JuMP.add_to_expression!(temp_expr, v.variant_terms) else + # This will mutate the variant terms, but these are reseted at each step. return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) end end From 6f3db17d536b877ba48292f22ea1d2bd0e0d5603 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:46:16 -0700 Subject: [PATCH 075/162] add quadratic and dt to fuel consumption --- .../devices/common/add_to_expression.jl | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index a76800e5f..1a81832cd 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1522,7 +1522,7 @@ function add_to_expression!( cost_expression::Union{JuMP.AbstractJuMPScalar, Float64}, component::T, time_period::Int, -) where {S <: CostExpressions, T <: PSY.Component} +) where {S <: Union{CostExpressions, FuelConsumptionExpression}, T <: PSY.Component} if has_container_key(container, S, T) device_cost_expression = get_expression(container, S(), T) component_name = PSY.get_name(component) @@ -1568,6 +1568,8 @@ function add_to_expression!( variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR for d in devices var_cost = PSY.get_variable(PSY.get_operation_cost(d)) if !(var_cost isa PSY.FuelCurve) @@ -1586,14 +1588,39 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - else - error("Not implemented yet") end end end From ea427fdf39335d2297c1774365b9adc096a1670e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:51:37 -0700 Subject: [PATCH 076/162] Add parameter for fuel cost Co-authored-by: jd-lara --- src/parameters/add_parameters.jl | 7 +- src/parameters/update_cost_parameters.jl | 104 ++++++++++++++++++----- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 59c401eb8..61262fc6f 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -276,11 +276,16 @@ function _add_parameters!( } where {D <: PSY.Component} ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) - error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + error( + "add_parameters! for ObjectiveFunctionParameter is not compatible with $ts_type", + ) end time_steps = get_time_steps(container) # TODO: Check for timeseries only for fuel cost device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + if isempty(device_names) + return + end jump_model = get_jump_model(container) param_container = add_param_container!( diff --git a/src/parameters/update_cost_parameters.jl b/src/parameters/update_cost_parameters.jl index 600eca675..6adc85707 100644 --- a/src/parameters/update_cost_parameters.jl +++ b/src/parameters/update_cost_parameters.jl @@ -14,31 +14,62 @@ function _update_parameter_values!( 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, + op_cost = PSY.get_operation_cost(component) + if op_cost isa PSY.MarketBidCost + ts_vector = PSY.get_variable_cost( component, - t, + 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 + elseif op_cost isa PSY.ThermalGenerationCost + fuel_curve = PSY.get_variable(op_cost) + ts_vector = PSY.get_fuel_cost( + component; + start_time = initial_forecast_time, + len = horizon, + ) + fuel_cost_forecast_values = TimeSeries.values(ts_vector) + for (t, value) in enumerate(fuel_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, + fuel_curve, + t, + ) + end + else + error( + "Update Cost Function Parameter not implemented for $(typeof(op_cost))", ) end end @@ -50,6 +81,15 @@ _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 _has_variable_cost_parameter(cost::T) where {T <: PSY.ThermalGenerationCost} + var_cost = PSY.get_variable(cost) + if var_cost isa PSY.FuelCurve + if PSY.get_fuel_cost(var_cost) isa IS.TimeSeriesKey + return true + end + end + return false +end function _update_pwl_cost_expression( container::OptimizationContainer, @@ -123,3 +163,25 @@ function update_variable_cost!( set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) return end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::JuMPFloatArray, + parameter_multiplier::JuMPFloatArray, + ::CostFunctionAttributes{Float64}, + component::T, + fuel_curve::PSY.FuelCurve, + time_period::Int, +) where {T <: PSY.Component} + component_name = PSY.get_name(component) + fuel_cost = parameter_array[component_name, time_period] + if all(iszero.(last.(fuel_cost))) + return + end + mult_ = parameter_multiplier[component_name, time_period] + expression = get_expression(container, FuelConsumptionExpression(), T) + cost_expr = expression[component_name, time_period] * fuel_cost * mult_ + add_to_objective_variant_expression!(container, cost_expr) + set_expression!(container, ProductionCostExpression, cost_expr, component, time_period) + return +end From 2c858be667efa2f4707709c0342204eb5592fe51 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:53:39 -0700 Subject: [PATCH 077/162] update getter for fuel cost pwl Co-authored-by: jd-lara --- .../common/objective_function/common.jl | 44 ++++++++--- .../objective_function/piecewise_linear.jl | 77 ++++++++++++++++--- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 064b68977..9d08fd234 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -271,18 +271,42 @@ end ################################################## function _get_fuel_cost_value( - ::OptimizationContainer, - fuel_cost::Float64, - ::Int, -) - return fuel_cost + container::OptimizationContainer, + component::T, + time_period::Int, +) where {T <: PSY.Component} + # TODO: Check time series for derating to work later + if PSY.has_time_series(component) + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(component) + return parameter_array[name, time_period] * parameter_multiplier[name, time_period] + else + return PSY.get_fuel_cost(component) + end end -function _get_fuel_cost_value( +function _add_time_varying_fuel_variable_cost!( container::OptimizationContainer, + ::T, + component::V, fuel_cost::IS.TimeSeriesKey, - time_period::Int, -) - error("Not implemented yet fuel cost") - return fuel_cost +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end 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 d173cd85d..f39378f2c 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -320,22 +320,18 @@ function _get_pwl_cost_expression( base_power, device_base_power, ) - fuel_cost = PSY.get_fuel_cost(cost_function) - fuel_cost_value = _get_fuel_cost_value( - container, - fuel_cost, - time_period, - ) # Multiplier is not necessary here. There is no negative cost for fuel curves. resolution = get_resolution(container) dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - return _get_pwl_cost_expression( + # TODO: Update name get_pwl_cost_expression + fuel_consumption_expression = _get_pwl_cost_expression( container, component, time_period, cost_data_normalized, - dt * fuel_cost_value, + dt, ) + return fuel_consumption_expression end ################################################## @@ -484,10 +480,7 @@ function _add_variable_cost_to_objective!( container::OptimizationContainer, ::T, component::PSY.Component, - cost_function::Union{ - PSY.CostCurve{PSY.PiecewisePointCurve}, - PSY.FuelCurve{PSY.PiecewisePointCurve}, - }, + cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, ::U, ) where {T <: VariableType, U <: AbstractDeviceFormulation} component_name = PSY.get_name(component) @@ -515,6 +508,66 @@ function _add_variable_cost_to_objective!( return end +""" +Creates piecewise linear cost function using a sum of variables and expression with sign and time step included. + +# Arguments + + - container::OptimizationContainer : the optimization_container model built in PowerSimulations + - var_key::VariableKey: The variable name + - component_name::String: The component_name of the variable container + - cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}: container for piecewise linear cost +""" +function _add_variable_cost_to_objective!( + container::OptimizationContainer, + ::T, + component::PSY.Component, + cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, + ::U, +) where {T <: VariableType, U <: AbstractDeviceFormulation} + component_name = PSY.get_name(component) + @debug "PWL Variable Cost" _group = LOG_GROUP_COST_FUNCTIONS component_name + # If array is full of tuples with zeros return 0.0 + value_curve = PSY.get_value_curve(cost_function) + cost_component = PSY.get_function_data(value_curve) + if all(iszero.((point -> point.y).(PSY.get_points(cost_component)))) # TODO I think this should have been first. before? + @debug "All cost terms for component $(component_name) are 0.0" _group = + LOG_GROUP_COST_FUNCTIONS + return + end + pwl_fuel_consumption_expressions = + _add_pwl_term!(container, component, cost_function, T(), U()) + is_time_variant = PSY.has_time_series(component) + for t in get_time_steps(container) + fuel_cost_value = _get_fuel_cost_value( + container, + component, + t, + ) + pwl_cost_expression = pwl_fuel_consumption_expressions[t] * fuel_cost_value + add_to_expression!( + container, + ProductionCostExpression, + pwl_cost_expression, + component, + t, + ) + add_to_expression!( + container, + FuelConsumptionExpression, + pwl_fuel_consumption_expressions[t], + component, + t, + ) + if is_time_variant + add_to_objective_variant_expression!(container, pwl_cost_expression) + else + add_to_objective_invariant_expression!(container, pwl_cost_expression) + end + end + return +end + ################################################## ###### CostCurve: PiecewiseIncrementalCurve ###### ######### and PiecewiseAverageCurve ############## From d09adbbaf00d712cc3d9a839f7e6d2500ea76284 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:54:02 -0700 Subject: [PATCH 078/162] update linear and quadratic methods to use new function --- .../common/objective_function/linear_curve.jl | 18 ++---------------- .../objective_function/quadratic_curve.jl | 9 +-------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 7d76ecdb0..91e2a9eed 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -116,24 +116,10 @@ function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, component::V, - heat_rate::Float64, # already normalized in MMBTU/p.u. + ::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType, V <: PSY.Component} - parameter = get_parameter_array(container, FuelCostParameter(), V) - multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) - expression = get_expression(container, FuelConsumptionExpression(), V) - name = PSY.get_name(component) - for t in get_time_steps(container) - cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] - add_to_expression!( - container, - ProductionCostExpression, - cost_expr, - component, - t, - ) - add_to_objective_variant_expression!(container, cost_expr) - end + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) return end diff --git a/src/devices_models/devices/common/objective_function/quadratic_curve.jl b/src/devices_models/devices/common/objective_function/quadratic_curve.jl index 686dc0d23..0bc31bbe5 100644 --- a/src/devices_models/devices/common/objective_function/quadratic_curve.jl +++ b/src/devices_models/devices/common/objective_function/quadratic_curve.jl @@ -212,14 +212,7 @@ function _add_fuel_quadratic_variable_cost!( quadratic_fuel_curve::Float64, fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType} - error("Not implemented yet") - _add_quadraticcurve_variable_cost!( - container, - T(), - component, - proportional_fuel_curve, - quadratic_fuel_curve, - ) + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) end @doc raw""" From bf741f6a324c62c865974059c3bc41f044efea1a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 079/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 145 +++++++++++++++++- .../devices/common/add_to_expression.jl | 90 ++++++++++- 2 files changed, 231 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 6d5d19fa6..37a5332e2 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -78,6 +78,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -95,6 +96,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return end @@ -193,6 +201,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -210,6 +219,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -307,6 +323,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -324,6 +341,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -419,6 +443,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -436,6 +461,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -524,6 +556,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -541,6 +574,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -618,6 +658,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -635,6 +676,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -711,6 +759,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -728,6 +777,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -803,7 +859,6 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( @@ -931,6 +986,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -948,6 +1004,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1073,6 +1139,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1090,6 +1157,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1213,6 +1290,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1230,6 +1308,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1337,6 +1425,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1354,6 +1443,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1456,6 +1555,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1473,6 +1573,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1576,6 +1686,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1593,6 +1704,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1672,6 +1793,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1705,6 +1827,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end @@ -1789,6 +1921,7 @@ function construct_device!( initial_conditions!(container, devices, ThermalCompactDispatch()) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1806,6 +1939,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 1a81832cd..f2c2ead6f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -41,7 +41,9 @@ function add_expressions!( PSY.get_name(d) for d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve ] - add_expression_container!(container, T(), D, names, time_steps) + if !isempty(names) + add_expression_container!(container, T(), D, names, time_steps) + end return end @@ -1562,9 +1564,86 @@ function add_to_expression!( T <: FuelConsumptionExpression, U <: ActivePowerVariable, V <: PSY.ThermalGen, - W <: AbstractThermalDispatchFormulation, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end + +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, } - expression = get_expression(container, T(), V) variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) @@ -1575,6 +1654,7 @@ function add_to_expression!( if !(var_cost isa PSY.FuelCurve) continue end + expression = get_expression(container, T(), V) name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) @@ -1610,6 +1690,8 @@ function add_to_expression!( base_power, device_base_power, ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= for t in time_steps fuel_expr = ( @@ -1621,9 +1703,11 @@ function add_to_expression!( fuel_expr, ) end + =# end end end +=# #= function add_to_expression!( From 403618909f11803d346772ca45290bb739b0d548 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 17 Oct 2024 14:52:56 -0700 Subject: [PATCH 080/162] add fuel cost test --- ..._device_thermal_generation_constructors.jl | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 9197bcd5e..45809467d 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -967,3 +967,63 @@ end end psi_checkobjfun_test(model, GAEVF) end + +@testset "Thermal with fuel cost time series" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + set_device_model!(template, ThermalStandard, ThermalDispatchNoMin) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + moi_tests(model, 432, 0, 192, 120, 72, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] + + @test sum(p_brighton[1:24]) < 50.0 # Barely used when expensive + @test sum(p_brighton[25:48]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive +end From 14dd6add38ffe80c24c4ba15172f74b71e666366 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:37 -0800 Subject: [PATCH 081/162] move cost term around to update objective function with variable fuel cost --- .../common/objective_function/common.jl | 4 ++-- .../devices/thermal_generation.jl | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 9d08fd234..8b4c884b8 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -113,9 +113,9 @@ function add_proportional_cost!( multiplier = objective_function_multiplier(U(), V()) for d in devices op_cost_data = PSY.get_operation_cost(d) - cost_term = proportional_cost(op_cost_data, U(), d, V()) - iszero(cost_term) && continue for t in get_time_steps(container) + cost_term = proportional_cost(container, op_cost_data, U(), d, V(), t) + iszero(cost_term) && continue if !PSY.get_must_run(d) exp = _add_proportional_term!(container, U(), d, cost_term * multiplier, t) add_to_expression!(container, ProductionCostExpression, exp, d, t) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ac6d3e3e3..ae11c88a9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -77,8 +77,8 @@ initial_condition_variable(::InitialTimeDurationOff, d::PSY.ThermalGen, ::Abstra ########################Objective Function################################################## # TODO: Decide what is the cost for OnVariable, if fixed or constant term in variable -function proportional_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation) - return onvar_cost(cost, S, T, U) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) +function proportional_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return onvar_cost(container, cost, S, T, U, t) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) end proportional_cost(cost::PSY.MarketBidCost, ::OnVariable, ::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_no_load_cost(cost) @@ -113,8 +113,8 @@ variable_cost(cost::PSY.OperationalCost, ::PowerAboveMinimumVariable, ::PSY.Ther """ Theoretical Cost at power output zero. Mathematically is the intercept with the y-axis """ -function onvar_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation) - return _onvar_cost(PSY.get_variable(cost), d) +function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return _onvar_cost(container, PSY.get_variable(cost), d, t) end function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) @@ -122,7 +122,7 @@ function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::P return 0.0 end -function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen, ::Int) value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # Always in \$/h @@ -130,22 +130,22 @@ function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.Co return constant_term end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(container::OptimizationContainer, cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::T, t::Int) where {T <: PSY.ThermalGen} value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # In Unit/h (unit typically in ) @@ -154,7 +154,11 @@ function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.Fu if typeof(fuel_cost) <: Float64 return constant_term * fuel_cost else - error("Time series not implemented yet") + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(d) + return constant_term * parameter_array[name, t] * parameter_multiplier[name, t] end end From d1e3c165ec6e4e6346e30d15010ccb18e4fd965e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 082/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 74 +++++++++++-------- .../devices/common/add_to_expression.jl | 50 +++++-------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 37a5332e2..eb6f041c3 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -958,6 +958,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1004,16 +1007,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1119,6 +1120,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1157,16 +1161,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1271,6 +1273,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1308,16 +1313,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1406,6 +1409,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1443,16 +1449,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return end @@ -1536,6 +1540,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1573,16 +1580,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1667,6 +1672,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1704,16 +1712,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + add_feedforward_arguments!(container, model, devices) return end @@ -1778,6 +1785,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1827,16 +1837,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + return end @@ -1897,6 +1906,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1939,16 +1951,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index f2c2ead6f..b1e6f1cad 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1630,8 +1630,6 @@ function add_to_expression!( end end -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= function add_to_expression!( container::OptimizationContainer, ::Type{T}, @@ -1658,6 +1656,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1668,46 +1667,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From 2f97e2b7f669ddff988db23dd9f09bd4911a4e10 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:59:34 -0800 Subject: [PATCH 083/162] update function call for onvar cost --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ae11c88a9..506282e89 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -117,7 +117,7 @@ function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGeneratio return _onvar_cost(container, PSY.get_variable(cost), d, t) end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end From 74fca02b94567fb809e866cf0d108b44bc5fecec Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 16:33:49 -0800 Subject: [PATCH 084/162] add test quad + pwl --- .../devices/common/add_to_expression.jl | 1 + ..._device_thermal_generation_constructors.jl | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index b1e6f1cad..22c49b7ce 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1612,6 +1612,7 @@ function add_to_expression!( base_power, device_base_power, ) + error("TODO: Implement FuelConsumptionExpression AffExpr to QuadExpr") # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr #= for t in time_steps diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 45809467d..c1e36abe9 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1027,3 +1027,81 @@ end @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive end + +@testset "Thermal with fuel cost time series with Quadratic and PWL" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + solitude = get_component(ThermalStandard, sys, "Solitude") + op_cost = get_operation_cost(solitude) + ts = deepcopy(get_time_series(Deterministic, solitude, "fuel_cost")) + remove_time_series!(sys, Deterministic, solitude, "fuel_cost") + quad_curve = QuadraticCurve(0.05, 1.0, 0.0) + new_th_cost = ThermalGenerationCost(; + variable = FuelCurve(; + value_curve = quad_curve, + fuel_cost = 1.0, + ), + fixed = op_cost.fixed, + start_up = op_cost.start_up, + shut_down = op_cost.shut_down, + ) + + set_operation_cost!(solitude, new_th_cost) + add_time_series!( + sys, + solitude, + ts, + ) + + set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + # TODO Tests + moi_tests(model, 1, 2, 3, 4, 5, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] +end From 2920c61065a152e263331a108b76c24ed2628b07 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 085/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++-- src/devices_models/devices/thermal_generation.jl | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index ae90e880c..2812f868f 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index eb6f041c3..26a5ac79a 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) end add_to_expression!( diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 506282e89..7688b609f 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -52,6 +52,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -199,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Any, String}( - FuelCostParameter => "fuel_cost", + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", ) end From 9a2f870654cc267abd37c415c8cc3716bef789eb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:03 -0600 Subject: [PATCH 086/162] add ts parameter calls in constructor --- .../device_constructors/thermalgeneration_constructor.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 26a5ac79a..edf98c7ae 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -958,6 +958,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1120,6 +1121,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1273,6 +1275,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1409,6 +1412,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1540,6 +1544,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1672,6 +1677,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end From 1e2a3adeb6fb82f7445339b87c250fb2e4024751 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:00:43 -0600 Subject: [PATCH 087/162] fix test --- src/services_models/services_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index b7999dd2b..e645c2cf8 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + add_feedforward_arguments!(container, model, interface) return end From 922b4c8de8fd30bd2c944f73e4ae10b7c69045f0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:52:39 -0600 Subject: [PATCH 088/162] comment out unrelated broken method --- src/services_models/services_constructor.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index e645c2cf8..f547d622b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,8 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, interface) + # TODO:broken + # add_feedforward_arguments!(container, model, interface) return end From 067d29aa3068c0a2d863a7a504d04b9e02109b9f Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 089/162] add new params and exprs --- src/core/parameters.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2812f868f..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ From 6615a868681171176519d1a7a6ead3eb545b3e60 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 090/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../device_constructors/thermalgeneration_constructor.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index edf98c7ae..2a68e9214 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -861,6 +861,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) add_expressions!(container, FuelConsumptionExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, From 9c6434f694a6a66d58ac951dea0df2413c3daa51 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 091/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 7688b609f..df1f0efef 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -200,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From d3ffc0871183e96ccb31bc90ea7345fbf4dade4e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 092/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 40 ++++++++++ .../devices/common/add_to_expression.jl | 79 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 2a68e9214..dd5301a6c 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -1010,6 +1010,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1165,6 +1175,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1318,6 +1338,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1587,6 +1617,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 22c49b7ce..b17fb2811 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1694,6 +1694,85 @@ function add_to_expression!( end end +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end +=# + #= function add_to_expression!( container::OptimizationContainer, From d68c408d58905c759e80e8d657fcbe068c380a37 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 093/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 42 +++++++++------- .../devices/common/add_to_expression.jl | 48 +++++++------------ 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index dd5301a6c..e00067d63 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -960,6 +960,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1010,16 +1013,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1133,6 +1134,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1175,16 +1179,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1297,6 +1299,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1338,16 +1343,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1444,6 +1447,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1576,6 +1582,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1617,16 +1626,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1719,6 +1726,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index b17fb2811..7409e64ad 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1722,6 +1722,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1732,46 +1733,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From 43f6048023b2767655cb9400fbf1615be6e36708 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 14:19:14 -0700 Subject: [PATCH 094/162] change time variant check --- .../devices/common/objective_function/piecewise_linear.jl | 3 ++- src/utils/powersystems_utils.jl | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 f39378f2c..ce3928201 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -537,7 +537,8 @@ function _add_variable_cost_to_objective!( end pwl_fuel_consumption_expressions = _add_pwl_term!(container, component, cost_function, T(), U()) - is_time_variant = PSY.has_time_series(component) + + is_time_variant = is_time_variant(cost_function) for t in get_time_steps(container) fuel_cost_value = _get_fuel_cost_value( container, diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index d49cebb5a..587786272 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -338,6 +338,10 @@ function _get_piecewise_incrementalcurve_per_system_unit( return PSY.PiecewiseStepData(x_coords_normalized, y_coords_normalized) end +function is_time_variant(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}) + return isa(PSY.get_fuel_cost(cost_function), IS.TimeSeriesKey) +end + function get_deterministic_time_series_type(sys::PSY.System) time_series_types = IS.get_time_series_counts_by_type(sys.data) existing_types = Set(d["type"] for d in time_series_types) From 84f1624d712137e73ce46ce0f40e61cec959f36f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:08:35 -0700 Subject: [PATCH 095/162] remove duplicate call --- .../device_constructors/thermalgeneration_constructor.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index e00067d63..6d0cb6ef0 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -861,8 +861,6 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) add_expressions!(container, FuelConsumptionExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) - add_to_expression!( container, ActivePowerRangeExpressionLB, From c992da5025c88b4a11aca420a5172094350c92f0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:40:26 -0700 Subject: [PATCH 096/162] change variable name --- .../devices/common/objective_function/piecewise_linear.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 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 ce3928201..9694157e9 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -538,7 +538,7 @@ function _add_variable_cost_to_objective!( pwl_fuel_consumption_expressions = _add_pwl_term!(container, component, cost_function, T(), U()) - is_time_variant = is_time_variant(cost_function) + is_time_variant_ = is_time_variant(cost_function) for t in get_time_steps(container) fuel_cost_value = _get_fuel_cost_value( container, @@ -560,7 +560,7 @@ function _add_variable_cost_to_objective!( component, t, ) - if is_time_variant + if is_time_variant_ add_to_objective_variant_expression!(container, pwl_cost_expression) else add_to_objective_invariant_expression!(container, pwl_cost_expression) From 1e2bdabd789c2b7bc84b1a555bf9eb98ece66b8a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:40:39 -0700 Subject: [PATCH 097/162] change expression addition dispatch --- src/core/optimization_container.jl | 3 ++- .../devices/common/add_to_expression.jl | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index c2702c64c..64cb14427 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -1442,11 +1442,12 @@ function add_expression_container!( ::T, ::Type{U}, axs...; + expr_type = GAE, sparse = false, meta = IS.Optimization.CONTAINER_KEY_EMPTY_META, ) where {T <: ExpressionType, U <: Union{PSY.Component, PSY.System}} expr_key = ExpressionKey(T, U, meta) - return _add_expression_container!(container, expr_key, GAE, axs...; sparse = sparse) + return _add_expression_container!(container, expr_key, expr_type, axs...; sparse = sparse) end function add_expression_container!( diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 7409e64ad..02e505b0b 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -37,12 +37,21 @@ function add_expressions!( W <: AbstractDeviceFormulation, } where {D <: PSY.Component} time_steps = get_time_steps(container) - names = [ - PSY.get_name(d) for - d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve - ] + names = String[] + found_quad_fuel_functions = false + for d in devices + fuel_curve = PSY.get_variable(PSY.get_operation_cost(d)) + if fuel_curve isa PSY.FuelCurve + push!(names, PSY.get_name(d)) + if !found_quad_fuel_functions + found_quad_fuel_functions = PSY.get_value_curve(fuel_curve) isa PSY.QuadraticCurve + end + end + end + if !isempty(names) - add_expression_container!(container, T(), D, names, time_steps) + expr_type = found_quad_fuel_functions ? JuMP.QuadExpr : GAE + add_expression_container!(container, T(), D, names, time_steps; expr_type = expr_type) end return end @@ -1612,9 +1621,6 @@ function add_to_expression!( base_power, device_base_power, ) - error("TODO: Implement FuelConsumptionExpression AffExpr to QuadExpr") - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= for t in time_steps fuel_expr = ( @@ -1626,7 +1632,6 @@ function add_to_expression!( fuel_expr, ) end - =# end end end @@ -1758,6 +1763,7 @@ function add_to_expression!( end end end +=# #= function add_to_expression!( From 04b7d07a0f7234f3272435e2fbcfa0624a3b30af Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:40:48 -0700 Subject: [PATCH 098/162] remove unused parameter call --- src/devices_models/devices/thermal_generation.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index df1f0efef..506282e89 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -52,7 +52,6 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From bf76d0570a90202d67230ba4d456ac34b3da44e4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:47:14 -0700 Subject: [PATCH 099/162] formatter --- src/core/optimization_container.jl | 8 +++++++- .../devices/common/add_to_expression.jl | 12 ++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 64cb14427..a0a549d9d 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -1447,7 +1447,13 @@ function add_expression_container!( meta = IS.Optimization.CONTAINER_KEY_EMPTY_META, ) where {T <: ExpressionType, U <: Union{PSY.Component, PSY.System}} expr_key = ExpressionKey(T, U, meta) - return _add_expression_container!(container, expr_key, expr_type, axs...; sparse = sparse) + return _add_expression_container!( + container, + expr_key, + expr_type, + axs...; + sparse = sparse, + ) end function add_expression_container!( diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 02e505b0b..68354b398 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -44,14 +44,22 @@ function add_expressions!( if fuel_curve isa PSY.FuelCurve push!(names, PSY.get_name(d)) if !found_quad_fuel_functions - found_quad_fuel_functions = PSY.get_value_curve(fuel_curve) isa PSY.QuadraticCurve + found_quad_fuel_functions = + PSY.get_value_curve(fuel_curve) isa PSY.QuadraticCurve end end end if !isempty(names) expr_type = found_quad_fuel_functions ? JuMP.QuadExpr : GAE - add_expression_container!(container, T(), D, names, time_steps; expr_type = expr_type) + add_expression_container!( + container, + T(), + D, + names, + time_steps; + expr_type = expr_type, + ) end return end From 8f13a5aa195c36be2bec098db297255078d58a41 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:23:04 -0700 Subject: [PATCH 100/162] add missing parameter additions --- .../thermalgeneration_constructor.jl | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 6d0cb6ef0..d54087e5d 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -60,6 +60,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -191,6 +195,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -305,6 +313,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -433,6 +445,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -958,9 +974,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1132,9 +1145,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1297,9 +1307,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1445,9 +1452,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1580,9 +1584,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1724,9 +1725,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) From 5e7a3cbbe8a1451df76edfffcc2781ea86d6cc26 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:31:45 -0700 Subject: [PATCH 101/162] update test --- ..._device_thermal_generation_constructors.jl | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index c1e36abe9..6dfe3f793 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1073,35 +1073,8 @@ end store_variable_names = true, optimizer_solve_log_print = false, ) - models = SimulationModels(; - decision_models = [ - model, - ], - ) - sequence = SimulationSequence(; - models = models, - feedforwards = Dict( - ), - ini_cond_chronology = InterProblemChronology(), - ) - - sim = Simulation(; - name = "compact_sim", - steps = 2, - models = models, - sequence = sequence, - initial_time = DateTime("2024-01-01T00:00:00"), - simulation_folder = mktempdir(), - ) - - build!(sim; console_level = Logging.Error, serialize = false) - # TODO Tests - moi_tests(model, 1, 2, 3, 4, 5, false) - execute!(sim; enable_progress_bar = true) - - sim_res = SimulationResults(sim) - res_uc = get_decision_problem_results(sim_res, "UC") - th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") - p_brighton = th_uc[!, "Brighton"] - p_solitude = th_uc[!, "Solitude"] + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.ModelBuildStatus.BUILT + moi_tests(model, 648, 0, 312, 120, 192, true) + container = PSI.get_optimization_container(model) + @test isa(PSI.get_invariant_terms(PSI.get_objective_expression(container)), JuMP.QuadExpr) end From ed6210d6e438c22f7d6ff8cb615eba180a1a330e Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:34:07 -0700 Subject: [PATCH 102/162] update test --- test/test_device_thermal_generation_constructors.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 6dfe3f793..7d2124d17 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1060,7 +1060,8 @@ end ts, ) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) + # There is no free MIQP solver, we need to use ThermalDisptchNoMin for testing + set_device_model!(template, ThermalStandard, ThermalDispatchNoMin) set_device_model!(template, PowerLoad, StaticPowerLoad) set_device_model!(template, RenewableDispatch, RenewableFullDispatch) @@ -1068,13 +1069,14 @@ end template, sys; name = "UC", - optimizer = HiGHS_optimizer, + optimizer = ipopt_optimizer, system_to_file = false, store_variable_names = true, optimizer_solve_log_print = false, ) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.ModelBuildStatus.BUILT - moi_tests(model, 648, 0, 312, 120, 192, true) + solve!(model) + moi_tests(model, 288, 0, 192, 120, 72, false) container = PSI.get_optimization_container(model) @test isa(PSI.get_invariant_terms(PSI.get_objective_expression(container)), JuMP.QuadExpr) end From f57fb0de4e1eca93dfa1c1e40fe82dda33aac487 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:52:05 -0700 Subject: [PATCH 103/162] update has series checks --- .../common/objective_function/common.jl | 27 +++++++++++-------- .../objective_function/piecewise_linear.jl | 3 ++- src/parameters/add_parameters.jl | 9 +++---- ..._device_thermal_generation_constructors.jl | 8 ++++-- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 8b4c884b8..fc4806f3a 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -270,21 +270,26 @@ end ################## Fuel Cost ##################### ################################################## -function _get_fuel_cost_value( +function get_fuel_cost_value( container::OptimizationContainer, component::T, time_period::Int, + ::Val{true}, ) where {T <: PSY.Component} - # TODO: Check time series for derating to work later - if PSY.has_time_series(component) - parameter_array = get_parameter_array(container, FuelCostParameter(), T) - parameter_multiplier = - get_parameter_multiplier_array(container, FuelCostParameter(), T) - name = PSY.get_name(component) - return parameter_array[name, time_period] * parameter_multiplier[name, time_period] - else - return PSY.get_fuel_cost(component) - end + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(component) + return parameter_array[name, time_period] * parameter_multiplier[name, time_period] +end + +function get_fuel_cost_value( + ::OptimizationContainer, + component::T, + ::Int, + ::Val{false}, +) where {T <: PSY.Component} + return PSY.get_fuel_cost(component) end function _add_time_varying_fuel_variable_cost!( 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 9694157e9..037de134a 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -540,10 +540,11 @@ function _add_variable_cost_to_objective!( is_time_variant_ = is_time_variant(cost_function) for t in get_time_steps(container) - fuel_cost_value = _get_fuel_cost_value( + fuel_cost_value = get_fuel_cost_value( container, component, t, + Val{is_time_variant_}(), ) pwl_cost_expression = pwl_fuel_consumption_expressions[t] * fuel_cost_value add_to_expression!( diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 61262fc6f..631a42fbc 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -281,8 +281,9 @@ function _add_parameters!( ) end time_steps = get_time_steps(container) - # TODO: Check for timeseries only for fuel cost - device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + ts_name = get_time_series_names(model)[T] + device_names = + [PSY.get_name(x) for x in devices if PSY.has_time_series(x, ts_type, ts_name)] if isempty(device_names) return end @@ -300,10 +301,8 @@ function _add_parameters!( time_steps, ) - ts_name = get_time_series_names(model)[T] - for device in devices - if !PSY.has_time_series(device) + if !PSY.has_time_series(device, ts_type, ts_name) continue end ts_vals = get_time_series_initial_values!(container, ts_type, device, ts_name) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 7d2124d17..70b330bb4 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1074,9 +1074,13 @@ end store_variable_names = true, optimizer_solve_log_print = false, ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.ModelBuildStatus.BUILT + @test build!(model; output_dir = mktempdir(; cleanup = true)) == + PSI.ModelBuildStatus.BUILT solve!(model) moi_tests(model, 288, 0, 192, 120, 72, false) container = PSI.get_optimization_container(model) - @test isa(PSI.get_invariant_terms(PSI.get_objective_expression(container)), JuMP.QuadExpr) + @test isa( + PSI.get_invariant_terms(PSI.get_objective_expression(container)), + JuMP.QuadExpr, + ) end From 8f82b1bfa9da59c115c15ef9ccebdd9e58968406 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 104/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++++ src/devices_models/devices/thermal_generation.jl | 6 ++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2946dd68f..e772d6e37 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 3c6f50c09..bbb169b86 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,6 +789,10 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 536d54ead..9cde131af 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -194,7 +194,9 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}() + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", + ) end function get_default_attributes( From 31b80a8f5223083d4293eab6bccb507a742ffea8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:37 -0600 Subject: [PATCH 105/162] add checks for ts property --- src/services_models/services_constructor.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index f547d622b..b7999dd2b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,8 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - # TODO:broken - # add_feedforward_arguments!(container, model, interface) + add_feedforward_arguments!(container, model, service) return end From cc043ba626f9fd809d77d71938152a440db53a83 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:58:37 -0600 Subject: [PATCH 106/162] add multiplier function --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 9cde131af..ebe8bedf9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -50,7 +50,7 @@ get_variable_upper_bound(::StartVariable, d::PSY.ThermalGen, ::AbstractThermalFo get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariable}, ::Type{PSY.ThermalMultiStart}, ::AbstractThermalFormulation) = true ########################### Parameter related set functions ################################ -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From 5dec088c83a9f273f2227b6a3132dc373cd3f9f4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 107/162] update fuelcost param changes --- src/devices_models/devices/thermal_generation.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ebe8bedf9..b3573d405 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,6 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From c6ede7f1ab025f7e2a577e4ba02da3b55227677e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 108/162] add new params and exprs --- src/core/expressions.jl | 1 + src/core/parameters.jl | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index f5ad354a7..173cfe7f4 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -8,6 +8,7 @@ struct EmergencyUp <: ExpressionType end struct EmergencyDown <: ExpressionType end struct RawACE <: ExpressionType end struct ProductionCostExpression <: CostExpressions end +struct FuelConsumptionExpression <: ExpressionType end struct ActivePowerRangeExpressionLB <: RangeConstraintLBExpressions end struct ActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end diff --git a/src/core/parameters.jl b/src/core/parameters.jl index e772d6e37..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ @@ -308,6 +303,11 @@ Parameter to define cost function coefficient """ struct CostFunctionParameter <: ObjectiveFunctionParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostParameter <: ObjectiveFunctionParameter end + abstract type AuxVariableValueParameter <: RightHandSideParameter end struct EventParameter <: ParameterType end From 66f8e4e59184655ded017eb6edb2e577d7fcd6a4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:29 -0700 Subject: [PATCH 109/162] update device model to take any parameter type --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index edc65bba8..1d30dd888 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -49,7 +49,7 @@ mutable struct DeviceModel{D <: PSY.Device, B <: AbstractDeviceFormulation} use_slacks::Bool duals::Vector{DataType} services::Vector{ServiceModel} - time_series_names::Dict{Type{<:TimeSeriesParameter}, String} + time_series_names::Dict{Type{<:PSI.ParameterType}, String} attributes::Dict{String, Any} subsystem::Union{Nothing, String} From 36658129cc05b9d75024418bf1b4b2bd51975df0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 110/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../thermalgeneration_constructor.jl | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index bbb169b86..6d5d19fa6 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -789,8 +789,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -804,6 +804,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, @@ -820,6 +822,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return From 6e0cdeedb673bb0daae45883b9148af4de37b66e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 111/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index b3573d405..ac6d3e3e3 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -51,7 +51,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) +get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -195,8 +195,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From 2d622722430d785ff82752f5c81c06346d884220 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:34 -0700 Subject: [PATCH 112/162] update expression for fuel consumption --- .../devices/common/add_to_expression.jl | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 0d9902e9b..a76800e5f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -26,6 +26,25 @@ function add_expressions!( return end +function add_expressions!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelConsumptionExpression, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + time_steps = get_time_steps(container) + names = [ + PSY.get_name(d) for + d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve + ] + add_expression_container!(container, T(), D, names, time_steps) + return +end + function add_expressions!( container::OptimizationContainer, ::Type{T}, @@ -1533,6 +1552,52 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: ActivePowerVariable, + V <: PSY.ThermalGen, + W <: AbstractThermalDispatchFormulation, +} + expression = get_expression(container, T(), V) + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + else + error("Not implemented yet") + end + end +end + #= function add_to_expression!( container::OptimizationContainer, From 0266fcb95559eecfcde5220a2aafc9f2fa3e1b06 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:55 -0700 Subject: [PATCH 113/162] add fuel cost timeseries for linear --- .../common/objective_function/linear_curve.jl | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 06d47c9b2..7d76ecdb0 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -115,12 +115,26 @@ end function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, - component::PSY.Component, - fuel_curve::Float64, + component::V, + heat_rate::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, -) where {T <: VariableType} - error("Not implemented yet") - _add_linearcurve_variable_cost!(container, T(), component, fuel_curve) +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end """ From f70978fc033b6ca83e2a2dfeb1ffd751ddadd70d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:37:06 -0700 Subject: [PATCH 114/162] add fuel cost params methods --- src/parameters/add_parameters.jl | 64 +++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 15ebf6e78..9ddd13bdb 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,6 +34,23 @@ function add_parameters!( return end +function add_parameters!( + container::OptimizationContainer, + ::Type{T}, + devices::U, + model::DeviceModel{D, W}, +) where { + T <: FuelCostParameter, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractDeviceFormulation, +} where {D <: PSY.Component} + if get_rebuild_model(get_settings(container)) && has_container_key(container, T, D) + return + end + _add_parameters!(container, T(), devices, model) + return +end + function add_parameters!( container::OptimizationContainer, ::Type{T}, @@ -257,7 +274,52 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - _add_time_series_parameters!(container, param, devices, model) + #error("here") + ts_type = get_default_time_series_type(container) + if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) + error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + end + time_steps = get_time_steps(container) + # TODO: Check for timeseries only for fuel cost + device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + jump_model = get_jump_model(container) + + param_container = add_param_container!( + container, + param, + D, + ActivePowerVariable, + PSI.SOSStatusVariable.NO_VARIABLE, + false, + Float64, + device_names, + time_steps, + ) + + ts_name = get_time_series_names(model)[T] + + for device in devices + if !PSY.has_time_series(device) + continue + end + ts_vals = get_time_series_initial_values!(container, ts_type, device, ts_name) + name = PSY.get_name(device) + for step in time_steps + PSI.set_parameter!( + param_container, + jump_model, + ts_vals[step], + name, + step, + ) + PSI.set_multiplier!( + param_container, + get_multiplier_value(T(), device, W()), + name, + step, + ) + end + end return end From 043392f101b82476e9083259ff2f1c7a2c42005f Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:39:52 -0700 Subject: [PATCH 115/162] remove commented error --- src/parameters/add_parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 9ddd13bdb..59c401eb8 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -274,7 +274,6 @@ function _add_parameters!( U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, W <: AbstractDeviceFormulation, } where {D <: PSY.Component} - #error("here") ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") From 5bba013fc9a0f19fbd6d88c3b91674fb00d69851 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:47 -0700 Subject: [PATCH 116/162] add export --- src/PowerSimulations.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index cd8544a63..3b3fe5246 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -323,6 +323,7 @@ export EmergencyUp export EmergencyDown export RawACE export ProductionCostExpression +export FuelConsumptionExpression export ActivePowerRangeExpressionLB export ActivePowerRangeExpressionUB From 2c6936e4f2aecc7e8f1efb179d4dd644bba245ac Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:44:57 -0700 Subject: [PATCH 117/162] add write result --- src/core/expressions.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 173cfe7f4..e1e8454eb 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -17,6 +17,7 @@ struct InterfaceTotalFlow <: ExpressionType end struct PTDFBranchFlow <: ExpressionType end should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{FuelConsumptionExpression}) = true should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true should_write_resulting_value(::Type{ActivePowerBalance}) = true From 1a3030892d56652cb3c9868470eb96082162c917 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:45:41 -0700 Subject: [PATCH 118/162] avoid mutation of invariant terms --- src/core/optimization_container.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index b94438f9b..c2702c64c 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -35,8 +35,12 @@ function get_objective_expression(v::ObjectiveFunction) else # JuMP doesn't support expression conversion from Affn to QuadExpressions if isa(v.invariant_terms, JuMP.GenericQuadExpr) - return JuMP.add_to_expression!(v.invariant_terms, v.variant_terms) + # Avoid mutation of invariant term + temp_expr = JuMP.QuadExpr() + JuMP.add_to_expression!(temp_expr, v.invariant_terms) + return JuMP.add_to_expression!(temp_expr, v.variant_terms) else + # This will mutate the variant terms, but these are reseted at each step. return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) end end From ab5e77efe1c8a18c38d4dc8e91a52e0d3ce4d130 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:46:16 -0700 Subject: [PATCH 119/162] add quadratic and dt to fuel consumption --- .../devices/common/add_to_expression.jl | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index a76800e5f..1a81832cd 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1522,7 +1522,7 @@ function add_to_expression!( cost_expression::Union{JuMP.AbstractJuMPScalar, Float64}, component::T, time_period::Int, -) where {S <: CostExpressions, T <: PSY.Component} +) where {S <: Union{CostExpressions, FuelConsumptionExpression}, T <: PSY.Component} if has_container_key(container, S, T) device_cost_expression = get_expression(container, S(), T) component_name = PSY.get_name(component) @@ -1568,6 +1568,8 @@ function add_to_expression!( variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR for d in devices var_cost = PSY.get_variable(PSY.get_operation_cost(d)) if !(var_cost isa PSY.FuelCurve) @@ -1586,14 +1588,39 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - else - error("Not implemented yet") end end end From bda36e62d198327c8b544e4561a532e27dae9d08 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:51:37 -0700 Subject: [PATCH 120/162] Add parameter for fuel cost Co-authored-by: jd-lara --- src/parameters/add_parameters.jl | 7 +- src/parameters/update_cost_parameters.jl | 104 ++++++++++++++++++----- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 59c401eb8..61262fc6f 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -276,11 +276,16 @@ function _add_parameters!( } where {D <: PSY.Component} ts_type = get_default_time_series_type(container) if !(ts_type <: Union{PSY.AbstractDeterministic, PSY.StaticTimeSeries}) - error("add_parameters! for TimeSeriesParameter is not compatible with $ts_type") + error( + "add_parameters! for ObjectiveFunctionParameter is not compatible with $ts_type", + ) end time_steps = get_time_steps(container) # TODO: Check for timeseries only for fuel cost device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + if isempty(device_names) + return + end jump_model = get_jump_model(container) param_container = add_param_container!( diff --git a/src/parameters/update_cost_parameters.jl b/src/parameters/update_cost_parameters.jl index 600eca675..6adc85707 100644 --- a/src/parameters/update_cost_parameters.jl +++ b/src/parameters/update_cost_parameters.jl @@ -14,31 +14,62 @@ function _update_parameter_values!( 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, + op_cost = PSY.get_operation_cost(component) + if op_cost isa PSY.MarketBidCost + ts_vector = PSY.get_variable_cost( component, - t, + 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 + elseif op_cost isa PSY.ThermalGenerationCost + fuel_curve = PSY.get_variable(op_cost) + ts_vector = PSY.get_fuel_cost( + component; + start_time = initial_forecast_time, + len = horizon, + ) + fuel_cost_forecast_values = TimeSeries.values(ts_vector) + for (t, value) in enumerate(fuel_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, + fuel_curve, + t, + ) + end + else + error( + "Update Cost Function Parameter not implemented for $(typeof(op_cost))", ) end end @@ -50,6 +81,15 @@ _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 _has_variable_cost_parameter(cost::T) where {T <: PSY.ThermalGenerationCost} + var_cost = PSY.get_variable(cost) + if var_cost isa PSY.FuelCurve + if PSY.get_fuel_cost(var_cost) isa IS.TimeSeriesKey + return true + end + end + return false +end function _update_pwl_cost_expression( container::OptimizationContainer, @@ -123,3 +163,25 @@ function update_variable_cost!( set_expression!(container, ProductionCostExpression, gen_cost, component, time_period) return end + +function update_variable_cost!( + container::OptimizationContainer, + parameter_array::JuMPFloatArray, + parameter_multiplier::JuMPFloatArray, + ::CostFunctionAttributes{Float64}, + component::T, + fuel_curve::PSY.FuelCurve, + time_period::Int, +) where {T <: PSY.Component} + component_name = PSY.get_name(component) + fuel_cost = parameter_array[component_name, time_period] + if all(iszero.(last.(fuel_cost))) + return + end + mult_ = parameter_multiplier[component_name, time_period] + expression = get_expression(container, FuelConsumptionExpression(), T) + cost_expr = expression[component_name, time_period] * fuel_cost * mult_ + add_to_objective_variant_expression!(container, cost_expr) + set_expression!(container, ProductionCostExpression, cost_expr, component, time_period) + return +end From e684e7bdbdafe2bb21be7b7734c4c38dbe2afbe7 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:53:39 -0700 Subject: [PATCH 121/162] update getter for fuel cost pwl Co-authored-by: jd-lara --- .../common/objective_function/common.jl | 44 ++++++++--- .../objective_function/piecewise_linear.jl | 77 ++++++++++++++++--- 2 files changed, 99 insertions(+), 22 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 064b68977..9d08fd234 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -271,18 +271,42 @@ end ################################################## function _get_fuel_cost_value( - ::OptimizationContainer, - fuel_cost::Float64, - ::Int, -) - return fuel_cost + container::OptimizationContainer, + component::T, + time_period::Int, +) where {T <: PSY.Component} + # TODO: Check time series for derating to work later + if PSY.has_time_series(component) + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(component) + return parameter_array[name, time_period] * parameter_multiplier[name, time_period] + else + return PSY.get_fuel_cost(component) + end end -function _get_fuel_cost_value( +function _add_time_varying_fuel_variable_cost!( container::OptimizationContainer, + ::T, + component::V, fuel_cost::IS.TimeSeriesKey, - time_period::Int, -) - error("Not implemented yet fuel cost") - return fuel_cost +) where {T <: VariableType, V <: PSY.Component} + parameter = get_parameter_array(container, FuelCostParameter(), V) + multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) + expression = get_expression(container, FuelConsumptionExpression(), V) + name = PSY.get_name(component) + for t in get_time_steps(container) + cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] + add_to_expression!( + container, + ProductionCostExpression, + cost_expr, + component, + t, + ) + add_to_objective_variant_expression!(container, cost_expr) + end + return end 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 d173cd85d..f39378f2c 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -320,22 +320,18 @@ function _get_pwl_cost_expression( base_power, device_base_power, ) - fuel_cost = PSY.get_fuel_cost(cost_function) - fuel_cost_value = _get_fuel_cost_value( - container, - fuel_cost, - time_period, - ) # Multiplier is not necessary here. There is no negative cost for fuel curves. resolution = get_resolution(container) dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - return _get_pwl_cost_expression( + # TODO: Update name get_pwl_cost_expression + fuel_consumption_expression = _get_pwl_cost_expression( container, component, time_period, cost_data_normalized, - dt * fuel_cost_value, + dt, ) + return fuel_consumption_expression end ################################################## @@ -484,10 +480,7 @@ function _add_variable_cost_to_objective!( container::OptimizationContainer, ::T, component::PSY.Component, - cost_function::Union{ - PSY.CostCurve{PSY.PiecewisePointCurve}, - PSY.FuelCurve{PSY.PiecewisePointCurve}, - }, + cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, ::U, ) where {T <: VariableType, U <: AbstractDeviceFormulation} component_name = PSY.get_name(component) @@ -515,6 +508,66 @@ function _add_variable_cost_to_objective!( return end +""" +Creates piecewise linear cost function using a sum of variables and expression with sign and time step included. + +# Arguments + + - container::OptimizationContainer : the optimization_container model built in PowerSimulations + - var_key::VariableKey: The variable name + - component_name::String: The component_name of the variable container + - cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}: container for piecewise linear cost +""" +function _add_variable_cost_to_objective!( + container::OptimizationContainer, + ::T, + component::PSY.Component, + cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, + ::U, +) where {T <: VariableType, U <: AbstractDeviceFormulation} + component_name = PSY.get_name(component) + @debug "PWL Variable Cost" _group = LOG_GROUP_COST_FUNCTIONS component_name + # If array is full of tuples with zeros return 0.0 + value_curve = PSY.get_value_curve(cost_function) + cost_component = PSY.get_function_data(value_curve) + if all(iszero.((point -> point.y).(PSY.get_points(cost_component)))) # TODO I think this should have been first. before? + @debug "All cost terms for component $(component_name) are 0.0" _group = + LOG_GROUP_COST_FUNCTIONS + return + end + pwl_fuel_consumption_expressions = + _add_pwl_term!(container, component, cost_function, T(), U()) + is_time_variant = PSY.has_time_series(component) + for t in get_time_steps(container) + fuel_cost_value = _get_fuel_cost_value( + container, + component, + t, + ) + pwl_cost_expression = pwl_fuel_consumption_expressions[t] * fuel_cost_value + add_to_expression!( + container, + ProductionCostExpression, + pwl_cost_expression, + component, + t, + ) + add_to_expression!( + container, + FuelConsumptionExpression, + pwl_fuel_consumption_expressions[t], + component, + t, + ) + if is_time_variant + add_to_objective_variant_expression!(container, pwl_cost_expression) + else + add_to_objective_invariant_expression!(container, pwl_cost_expression) + end + end + return +end + ################################################## ###### CostCurve: PiecewiseIncrementalCurve ###### ######### and PiecewiseAverageCurve ############## From 7e2189060e0f0e62346b9c2f7d5d470929a45524 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 16:54:02 -0700 Subject: [PATCH 122/162] update linear and quadratic methods to use new function --- .../common/objective_function/linear_curve.jl | 18 ++---------------- .../objective_function/quadratic_curve.jl | 9 +-------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/linear_curve.jl b/src/devices_models/devices/common/objective_function/linear_curve.jl index 7d76ecdb0..91e2a9eed 100644 --- a/src/devices_models/devices/common/objective_function/linear_curve.jl +++ b/src/devices_models/devices/common/objective_function/linear_curve.jl @@ -116,24 +116,10 @@ function _add_fuel_linear_variable_cost!( container::OptimizationContainer, ::T, component::V, - heat_rate::Float64, # already normalized in MMBTU/p.u. + ::Float64, # already normalized in MMBTU/p.u. fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType, V <: PSY.Component} - parameter = get_parameter_array(container, FuelCostParameter(), V) - multiplier = get_parameter_multiplier_array(container, FuelCostParameter(), V) - expression = get_expression(container, FuelConsumptionExpression(), V) - name = PSY.get_name(component) - for t in get_time_steps(container) - cost_expr = expression[name, t] * parameter[name, t] * multiplier[name, t] - add_to_expression!( - container, - ProductionCostExpression, - cost_expr, - component, - t, - ) - add_to_objective_variant_expression!(container, cost_expr) - end + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) return end diff --git a/src/devices_models/devices/common/objective_function/quadratic_curve.jl b/src/devices_models/devices/common/objective_function/quadratic_curve.jl index 686dc0d23..0bc31bbe5 100644 --- a/src/devices_models/devices/common/objective_function/quadratic_curve.jl +++ b/src/devices_models/devices/common/objective_function/quadratic_curve.jl @@ -212,14 +212,7 @@ function _add_fuel_quadratic_variable_cost!( quadratic_fuel_curve::Float64, fuel_cost::IS.TimeSeriesKey, ) where {T <: VariableType} - error("Not implemented yet") - _add_quadraticcurve_variable_cost!( - container, - T(), - component, - proportional_fuel_curve, - quadratic_fuel_curve, - ) + _add_time_varying_fuel_variable_cost!(container, T(), component, fuel_cost) end @doc raw""" From d5010612b9f2e770b66cee240002a5b7e9e10d16 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 123/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 145 +++++++++++++++++- .../devices/common/add_to_expression.jl | 90 ++++++++++- 2 files changed, 231 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 6d5d19fa6..37a5332e2 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -78,6 +78,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -95,6 +96,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return end @@ -193,6 +201,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -210,6 +219,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -307,6 +323,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -324,6 +341,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -419,6 +443,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -436,6 +461,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -524,6 +556,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -541,6 +574,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -618,6 +658,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -635,6 +676,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -711,6 +759,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -728,6 +777,13 @@ function construct_device!( model, network_model, ) + add_to_expression!( + container, + FuelConsumptionExpression, + ActivePowerVariable, + devices, + model, + ) add_feedforward_arguments!(container, model, devices) return @@ -803,7 +859,6 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( @@ -931,6 +986,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -948,6 +1004,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1073,6 +1139,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1090,6 +1157,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1213,6 +1290,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1230,6 +1308,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1337,6 +1425,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1354,6 +1443,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1456,6 +1555,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1473,6 +1573,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return @@ -1576,6 +1686,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1593,6 +1704,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_feedforward_arguments!(container, model, devices) return end @@ -1672,6 +1793,7 @@ function construct_device!( ) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1705,6 +1827,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end @@ -1789,6 +1921,7 @@ function construct_device!( initial_conditions!(container, devices, ThermalCompactDispatch()) add_expressions!(container, ProductionCostExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) add_to_expression!( container, @@ -1806,6 +1939,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 1a81832cd..f2c2ead6f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -41,7 +41,9 @@ function add_expressions!( PSY.get_name(d) for d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve ] - add_expression_container!(container, T(), D, names, time_steps) + if !isempty(names) + add_expression_container!(container, T(), D, names, time_steps) + end return end @@ -1562,9 +1564,86 @@ function add_to_expression!( T <: FuelConsumptionExpression, U <: ActivePowerVariable, V <: PSY.ThermalGen, - W <: AbstractThermalDispatchFormulation, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end + +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, } - expression = get_expression(container, T(), V) variable = get_variable(container, U(), V) time_steps = get_time_steps(container) base_power = get_base_power(container) @@ -1575,6 +1654,7 @@ function add_to_expression!( if !(var_cost isa PSY.FuelCurve) continue end + expression = get_expression(container, T(), V) name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) @@ -1610,6 +1690,8 @@ function add_to_expression!( base_power, device_base_power, ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= for t in time_steps fuel_expr = ( @@ -1621,9 +1703,11 @@ function add_to_expression!( fuel_expr, ) end + =# end end end +=# #= function add_to_expression!( From ef7d41b1ce4d5917b9f6ff5f5f053b19e8133173 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 17 Oct 2024 14:52:56 -0700 Subject: [PATCH 124/162] add fuel cost test --- ..._device_thermal_generation_constructors.jl | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 907edd597..43d04df9a 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -967,3 +967,63 @@ end end psi_checkobjfun_test(model, GAEVF) end + +@testset "Thermal with fuel cost time series" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + set_device_model!(template, ThermalStandard, ThermalDispatchNoMin) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + moi_tests(model, 432, 0, 192, 120, 72, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] + + @test sum(p_brighton[1:24]) < 50.0 # Barely used when expensive + @test sum(p_brighton[25:48]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap + @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive +end From 15eb3bb5c62270316d95e642299907d7f943c758 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:37 -0800 Subject: [PATCH 125/162] move cost term around to update objective function with variable fuel cost --- .../common/objective_function/common.jl | 4 ++-- .../devices/thermal_generation.jl | 24 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 9d08fd234..8b4c884b8 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -113,9 +113,9 @@ function add_proportional_cost!( multiplier = objective_function_multiplier(U(), V()) for d in devices op_cost_data = PSY.get_operation_cost(d) - cost_term = proportional_cost(op_cost_data, U(), d, V()) - iszero(cost_term) && continue for t in get_time_steps(container) + cost_term = proportional_cost(container, op_cost_data, U(), d, V(), t) + iszero(cost_term) && continue if !PSY.get_must_run(d) exp = _add_proportional_term!(container, U(), d, cost_term * multiplier, t) add_to_expression!(container, ProductionCostExpression, exp, d, t) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ac6d3e3e3..ae11c88a9 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -77,8 +77,8 @@ initial_condition_variable(::InitialTimeDurationOff, d::PSY.ThermalGen, ::Abstra ########################Objective Function################################################## # TODO: Decide what is the cost for OnVariable, if fixed or constant term in variable -function proportional_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation) - return onvar_cost(cost, S, T, U) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) +function proportional_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, T::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return onvar_cost(container, cost, S, T, U, t) + PSY.get_constant_term(PSY.get_vom_cost(PSY.get_variable(cost))) + PSY.get_fixed(cost) end proportional_cost(cost::PSY.MarketBidCost, ::OnVariable, ::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_no_load_cost(cost) @@ -113,8 +113,8 @@ variable_cost(cost::PSY.OperationalCost, ::PowerAboveMinimumVariable, ::PSY.Ther """ Theoretical Cost at power output zero. Mathematically is the intercept with the y-axis """ -function onvar_cost(cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation) - return _onvar_cost(PSY.get_variable(cost), d) +function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGenerationCost, S::OnVariable, d::PSY.ThermalGen, U::AbstractThermalFormulation, t::Int) + return _onvar_cost(container, PSY.get_variable(cost), d, t) end function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) @@ -122,7 +122,7 @@ function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::P return 0.0 end -function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.CostCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen, ::Int) value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # Always in \$/h @@ -130,22 +130,22 @@ function _onvar_cost(cost_function::Union{PSY.CostCurve{PSY.LinearCurve}, PSY.Co return constant_term end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end -function _onvar_cost(cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.FuelCurve{PSY.PiecewiseIncrementalCurve}, d::PSY.ThermalGen, ::Int) # Input at min is used to transform to InputOutputCurve return 0.0 end -function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::PSY.ThermalGen) +function _onvar_cost(container::OptimizationContainer, cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.FuelCurve{PSY.QuadraticCurve}}, d::T, t::Int) where {T <: PSY.ThermalGen} value_curve = PSY.get_value_curve(cost_function) cost_component = PSY.get_function_data(value_curve) # In Unit/h (unit typically in ) @@ -154,7 +154,11 @@ function _onvar_cost(cost_function::Union{PSY.FuelCurve{PSY.LinearCurve}, PSY.Fu if typeof(fuel_cost) <: Float64 return constant_term * fuel_cost else - error("Time series not implemented yet") + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(d) + return constant_term * parameter_array[name, t] * parameter_multiplier[name, t] end end From 1bf25254e3cb95c1069e53b39b5cd0c3acb515e0 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 126/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 74 +++++++++++-------- .../devices/common/add_to_expression.jl | 50 +++++-------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 37a5332e2..eb6f041c3 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -958,6 +958,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1004,16 +1007,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1119,6 +1120,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1157,16 +1161,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1271,6 +1273,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1308,16 +1313,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1406,6 +1409,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1443,16 +1449,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return end @@ -1536,6 +1540,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1573,16 +1580,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_feedforward_arguments!(container, model, devices) return @@ -1667,6 +1672,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_to_expression!( container, @@ -1704,16 +1712,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + add_feedforward_arguments!(container, model, devices) return end @@ -1778,6 +1785,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1827,16 +1837,15 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# + return end @@ -1897,6 +1906,9 @@ function construct_device!( add_variables!(container, PowerOutput, devices, ThermalCompactDispatch()) add_parameters!(container, OnStatusParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end add_feedforward_arguments!(container, model, devices) @@ -1939,16 +1951,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# return end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index f2c2ead6f..b1e6f1cad 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1630,8 +1630,6 @@ function add_to_expression!( end end -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= function add_to_expression!( container::OptimizationContainer, ::Type{T}, @@ -1658,6 +1656,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1668,46 +1667,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From b06ab22fd495ae2ec1697f7c07557ef563229824 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:59:34 -0800 Subject: [PATCH 127/162] update function call for onvar cost --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index ae11c88a9..506282e89 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -117,7 +117,7 @@ function onvar_cost(container::OptimizationContainer, cost::PSY.ThermalGeneratio return _onvar_cost(container, PSY.get_variable(cost), d, t) end -function _onvar_cost(cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen) +function _onvar_cost(::OptimizationContainer, cost_function::PSY.CostCurve{PSY.PiecewisePointCurve}, d::PSY.ThermalGen, ::Int) # OnVariableCost is included in the Point itself for PiecewisePointCurve return 0.0 end From 09ed67ea9a11b2c33064744a03e673814fb94f21 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 16:33:49 -0800 Subject: [PATCH 128/162] add test quad + pwl --- .../devices/common/add_to_expression.jl | 1 + ..._device_thermal_generation_constructors.jl | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index b1e6f1cad..22c49b7ce 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1612,6 +1612,7 @@ function add_to_expression!( base_power, device_base_power, ) + error("TODO: Implement FuelConsumptionExpression AffExpr to QuadExpr") # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr #= for t in time_steps diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 43d04df9a..b84f00f9d 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1027,3 +1027,81 @@ end @test sum(p_solitude[1:24]) > 5000.0 # Used a lot when cheap @test sum(p_solitude[25:48]) < 50.0 # Barely used when expensive end + +@testset "Thermal with fuel cost time series with Quadratic and PWL" begin + sys = PSB.build_system(PSITestSystems, "c_sys5_re_fuel_cost") + + template = ProblemTemplate( + NetworkModel( + CopperPlatePowerModel; + duals = [CopperPlateBalanceConstraint], + ), + ) + + solitude = get_component(ThermalStandard, sys, "Solitude") + op_cost = get_operation_cost(solitude) + ts = deepcopy(get_time_series(Deterministic, solitude, "fuel_cost")) + remove_time_series!(sys, Deterministic, solitude, "fuel_cost") + quad_curve = QuadraticCurve(0.05, 1.0, 0.0) + new_th_cost = ThermalGenerationCost(; + variable = FuelCurve(; + value_curve = quad_curve, + fuel_cost = 1.0, + ), + fixed = op_cost.fixed, + start_up = op_cost.start_up, + shut_down = op_cost.shut_down, + ) + + set_operation_cost!(solitude, new_th_cost) + add_time_series!( + sys, + solitude, + ts, + ) + + set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, RenewableDispatch, RenewableFullDispatch) + + model = DecisionModel( + template, + sys; + name = "UC", + optimizer = HiGHS_optimizer, + system_to_file = false, + store_variable_names = true, + optimizer_solve_log_print = false, + ) + models = SimulationModels(; + decision_models = [ + model, + ], + ) + sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + ), + ini_cond_chronology = InterProblemChronology(), + ) + + sim = Simulation(; + name = "compact_sim", + steps = 2, + models = models, + sequence = sequence, + initial_time = DateTime("2024-01-01T00:00:00"), + simulation_folder = mktempdir(), + ) + + build!(sim; console_level = Logging.Error, serialize = false) + # TODO Tests + moi_tests(model, 1, 2, 3, 4, 5, false) + execute!(sim; enable_progress_bar = true) + + sim_res = SimulationResults(sim) + res_uc = get_decision_problem_results(sim_res, "UC") + th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") + p_brighton = th_uc[!, "Brighton"] + p_solitude = th_uc[!, "Solitude"] +end From 5afd7161e77ac4077886acbefaee0d41216074ff Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 129/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++-- src/devices_models/devices/thermal_generation.jl | 5 +++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index ae90e880c..2812f868f 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index eb6f041c3..26a5ac79a 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) end add_to_expression!( diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 506282e89..7688b609f 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -52,6 +52,7 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 +get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max @@ -199,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Any, String}( - FuelCostParameter => "fuel_cost", + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", ) end From 21dc6ae2d782e263df2becfb2b9666ff53a597ba Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:03 -0600 Subject: [PATCH 130/162] add ts parameter calls in constructor --- .../device_constructors/thermalgeneration_constructor.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 26a5ac79a..edf98c7ae 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -958,6 +958,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1120,6 +1121,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1273,6 +1275,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1409,6 +1412,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1540,6 +1544,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end @@ -1672,6 +1677,7 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) end From 0d9c443325c5c9c26e0b652526ce7dfdbce2155a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:00:43 -0600 Subject: [PATCH 131/162] fix test --- src/services_models/services_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index b7999dd2b..e645c2cf8 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + add_feedforward_arguments!(container, model, interface) return end From 4b0cb8e5be8ce4bc253d1a612e6a82570b46ffb4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:52:39 -0600 Subject: [PATCH 132/162] comment out unrelated broken method --- src/services_models/services_constructor.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index e645c2cf8..f547d622b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,8 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, interface) + # TODO:broken + # add_feedforward_arguments!(container, model, interface) return end From 9b3a774d6848553c469513e9986bba75ab0927cd Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 133/162] add new params and exprs --- src/core/parameters.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2812f868f..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ From 53f15c9eec13c408d071907e3653cb34cf35696b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 134/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../device_constructors/thermalgeneration_constructor.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index edf98c7ae..2a68e9214 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -861,6 +861,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) add_expressions!(container, FuelConsumptionExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, From 38bb16db49c59335f01d23ea7360700eff143f98 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 135/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 7688b609f..df1f0efef 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -200,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From 0ea26a2b8bf1853c081fa295bc008e7b06af6499 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 136/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 40 ++++++++++ .../devices/common/add_to_expression.jl | 79 +++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 2a68e9214..dd5301a6c 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -1010,6 +1010,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1165,6 +1175,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1318,6 +1338,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1587,6 +1617,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 22c49b7ce..b17fb2811 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1694,6 +1694,85 @@ function add_to_expression!( end end +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end +=# + #= function add_to_expression!( container::OptimizationContainer, From 40d092051e84878460d7733b37b51edfcfc2e5ce Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 137/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 42 +++++++++------- .../devices/common/add_to_expression.jl | 48 +++++++------------ 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index dd5301a6c..e00067d63 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -960,6 +960,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1010,16 +1013,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1133,6 +1134,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1175,16 +1179,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1297,6 +1299,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1338,16 +1343,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1444,6 +1447,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1576,6 +1582,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) @@ -1617,16 +1626,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1719,6 +1726,9 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end if haskey(get_time_series_names(model), FuelCostParameter) add_parameters!(container, FuelCostParameter, devices, model) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index b17fb2811..7409e64ad 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1722,6 +1722,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1732,46 +1733,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From 170d4b07f37b0af89e90b6c2c1007f14157960ae Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 14:19:14 -0700 Subject: [PATCH 138/162] change time variant check --- .../devices/common/objective_function/piecewise_linear.jl | 3 ++- src/utils/powersystems_utils.jl | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 f39378f2c..ce3928201 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -537,7 +537,8 @@ function _add_variable_cost_to_objective!( end pwl_fuel_consumption_expressions = _add_pwl_term!(container, component, cost_function, T(), U()) - is_time_variant = PSY.has_time_series(component) + + is_time_variant = is_time_variant(cost_function) for t in get_time_steps(container) fuel_cost_value = _get_fuel_cost_value( container, diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index d49cebb5a..587786272 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -338,6 +338,10 @@ function _get_piecewise_incrementalcurve_per_system_unit( return PSY.PiecewiseStepData(x_coords_normalized, y_coords_normalized) end +function is_time_variant(cost_function::PSY.FuelCurve{PSY.PiecewisePointCurve}) + return isa(PSY.get_fuel_cost(cost_function), IS.TimeSeriesKey) +end + function get_deterministic_time_series_type(sys::PSY.System) time_series_types = IS.get_time_series_counts_by_type(sys.data) existing_types = Set(d["type"] for d in time_series_types) From 9254592e234443671b647c4335e07286b3192069 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 139/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++-- src/devices_models/devices/thermal_generation.jl | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index ae90e880c..2812f868f 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index e00067d63..e1a35d66d 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) end add_to_expression!( diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index df1f0efef..7688b609f 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -200,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Any, String}( - FuelCostParameter => "fuel_cost", + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", ) end From a24db574036a0ae2da9a052ee7ec6f6fcabf331e Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 14:09:37 -0600 Subject: [PATCH 140/162] add checks for ts property --- src/services_models/services_constructor.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index f547d622b..b7999dd2b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,8 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - # TODO:broken - # add_feedforward_arguments!(container, model, interface) + add_feedforward_arguments!(container, model, service) return end From c916e234404ed26fcacb3bba53fffd78003356eb Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 141/162] add new params and exprs --- src/core/parameters.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2812f868f..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ From 2f4c56a14bd048cd60a2f150b95b31e107a926a5 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 142/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../device_constructors/thermalgeneration_constructor.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index e1a35d66d..adc6a6e1d 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -863,6 +863,8 @@ function construct_device!( add_expressions!(container, FuelConsumptionExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, From 1e9f0e972e993335db48206c3ddfcc558a20b13f Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 143/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 7688b609f..df1f0efef 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -200,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From bdd49574ae69c33abbe1142f18d29b6924014616 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 144/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 44 ++++++++++- .../devices/common/add_to_expression.jl | 79 +++++++++++++++++++ 2 files changed, 119 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index adc6a6e1d..b0f6a42e0 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -861,10 +861,6 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) add_expressions!(container, FuelConsumptionExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) - - add_expressions!(container, FuelConsumptionExpression, devices, model) - add_to_expression!( container, ActivePowerRangeExpressionLB, @@ -1015,6 +1011,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1181,6 +1187,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1345,6 +1361,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1628,6 +1654,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 7409e64ad..2c2751019 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1759,6 +1759,85 @@ function add_to_expression!( end end +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end +=# + #= function add_to_expression!( container::OptimizationContainer, From faeeb292a849a27b7e9da63a65d1d88993084b64 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 145/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 48 ++++--------------- .../devices/common/add_to_expression.jl | 48 +++++++------------ 2 files changed, 25 insertions(+), 71 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index b0f6a42e0..c749a893e 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -962,10 +962,6 @@ function construct_device!( add_parameters!(container, FuelCostParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end - add_to_expression!( container, ActivePowerBalance, @@ -1011,16 +1007,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1146,10 +1140,6 @@ function construct_device!( add_parameters!(container, FuelCostParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end - add_to_expression!( container, ActivePowerBalance, @@ -1187,16 +1177,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1321,10 +1309,6 @@ function construct_device!( add_parameters!(container, FuelCostParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end - add_to_expression!( container, ActivePowerBalance, @@ -1361,16 +1345,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1479,10 +1461,6 @@ function construct_device!( add_parameters!(container, FuelCostParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end - add_to_expression!( container, ActivePowerBalance, @@ -1614,10 +1592,6 @@ function construct_device!( add_parameters!(container, FuelCostParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end - add_to_expression!( container, ActivePowerBalance, @@ -1654,16 +1628,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1768,10 +1740,6 @@ function construct_device!( add_parameters!(container, FuelCostParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end - add_to_expression!( container, ActivePowerBalance, diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 2c2751019..e7ca878d7 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1787,6 +1787,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1797,46 +1798,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From 013938137b4b56bc03d9b4b297f49a2e910579a8 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 10:59:26 -0700 Subject: [PATCH 146/162] update fuelcost param changes --- src/core/parameters.jl | 5 +++++ .../device_constructors/thermalgeneration_constructor.jl | 4 ++-- src/devices_models/devices/thermal_generation.jl | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index ae90e880c..2812f868f 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,6 +276,11 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end +""" +Parameter to define fuel cost time series +""" +struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end + abstract type VariableValueParameter <: RightHandSideParameter end """ diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index c749a893e..1ec29bc74 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) + add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) end add_to_expression!( diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index df1f0efef..7688b609f 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -200,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Any, String}( - FuelCostParameter => "fuel_cost", + return Dict{Type{<:TimeSeriesParameter}, String}( + FuelCostTimeSeriesParameter => "fuel_cost", ) end From 7511abe40028b40973f7276da8552a67265aef81 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:00:43 -0600 Subject: [PATCH 147/162] fix test --- src/services_models/services_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index b7999dd2b..e645c2cf8 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,7 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + add_feedforward_arguments!(container, model, interface) return end From a233ea9ff98265b01c7689ba94af8ed43acf220f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Sun, 13 Oct 2024 15:52:39 -0600 Subject: [PATCH 148/162] comment out unrelated broken method --- src/services_models/services_constructor.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index e645c2cf8..f547d622b 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -548,7 +548,8 @@ function construct_service!( PSY.get_name.(interfaces), get_time_steps(container), ) - add_feedforward_arguments!(container, model, interface) + # TODO:broken + # add_feedforward_arguments!(container, model, interface) return end From 9c072023fede6b0d2b56fa5d1e38312ca9018059 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:35:14 -0700 Subject: [PATCH 149/162] add new params and exprs --- src/core/parameters.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2812f868f..ae90e880c 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -276,11 +276,6 @@ Parameter to define Min Flow limit for interface time series """ struct MinInterfaceFlowLimitParameter <: TimeSeriesParameter end -""" -Parameter to define fuel cost time series -""" -struct FuelCostTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ From 90c9751684fdc024329bf8558a676fadb8d2e6cc Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:02 -0700 Subject: [PATCH 150/162] [WIP] update abstract thermal dispatch to include fuel expressions --- .../device_constructors/thermalgeneration_constructor.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 1ec29bc74..7b91ea0bc 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -845,8 +845,8 @@ function construct_device!( add_variables!(container, ActivePowerVariable, devices, D()) - if haskey(get_time_series_names(model), FuelCostTimeSeriesParameter) - add_parameters!(container, FuelCostTimeSeriesParameter, devices, model) + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) end add_to_expression!( @@ -861,6 +861,8 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) add_expressions!(container, FuelConsumptionExpression, devices, model) + add_expressions!(container, FuelConsumptionExpression, devices, model) + add_to_expression!( container, ActivePowerRangeExpressionLB, From d10613bb65dcd8b196e94972bbd1555a428759ed Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 15 Oct 2024 16:36:14 -0700 Subject: [PATCH 151/162] update thermal time series --- src/devices_models/devices/thermal_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 7688b609f..df1f0efef 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -200,8 +200,8 @@ function get_default_time_series_names( ::Type{U}, ::Type{V}, ) where {U <: PSY.ThermalGen, V <: Union{FixedOutput, AbstractThermalFormulation}} - return Dict{Type{<:TimeSeriesParameter}, String}( - FuelCostTimeSeriesParameter => "fuel_cost", + return Dict{Any, String}( + FuelCostParameter => "fuel_cost", ) end From d9d06e0283c2820e331ef91a51883436311789e7 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 16 Oct 2024 20:58:55 -0700 Subject: [PATCH 152/162] add expressions for all formulations --- .../thermalgeneration_constructor.jl | 42 +++++++++- .../devices/common/add_to_expression.jl | 79 +++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 7b91ea0bc..67b4ad039 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -861,8 +861,6 @@ function construct_device!( add_expressions!(container, ProductionCostExpression, devices, model) add_expressions!(container, FuelConsumptionExpression, devices, model) - add_expressions!(container, FuelConsumptionExpression, devices, model) - add_to_expression!( container, ActivePowerRangeExpressionLB, @@ -1009,6 +1007,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1179,6 +1187,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1347,6 +1365,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, @@ -1630,6 +1658,16 @@ function construct_device!( model, network_model, ) + #TODO: Implement for AbovePowerMinimum + #= + add_to_expression!( + container, + FuelConsumptionExpression, + PowerAboveMinimumVariable,, + devices, + model, + ) + =# add_to_expression!( container, diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index e7ca878d7..bf0e4ac65 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1824,6 +1824,85 @@ function add_to_expression!( end end +#TODO: FuelConsumption for PowerAboveMinimumVariable +#= +function add_to_expression!( + container::OptimizationContainer, + ::Type{T}, + ::Type{U}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, +) where { + T <: FuelConsumptionExpression, + U <: PowerAboveMinimumVariable, + V <: PSY.ThermalGen, + W <: AbstractDeviceFormulation, +} + variable = get_variable(container, U(), V) + time_steps = get_time_steps(container) + base_power = get_base_power(container) + resolution = get_resolution(container) + dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR + for d in devices + var_cost = PSY.get_variable(PSY.get_operation_cost(d)) + if !(var_cost isa PSY.FuelCurve) + continue + end + expression = get_expression(container, T(), V) + name = PSY.get_name(d) + device_base_power = PSY.get_base_power(d) + value_curve = PSY.get_value_curve(var_cost) + if value_curve isa PSY.LinearCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + for t in time_steps + fuel_expr = variable[name, t] * prop_term_per_unit * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + elseif value_curve isa PSY.QuadraticCurve + power_units = PSY.get_power_units(var_cost) + proportional_term = PSY.get_proportional_term(value_curve) + quadratic_term = PSY.get_quadratic_term(value_curve) + prop_term_per_unit = get_proportional_cost_per_system_unit( + proportional_term, + power_units, + base_power, + device_base_power, + ) + quad_term_per_unit = get_quadratic_cost_per_system_unit( + quadratic_term, + power_units, + base_power, + device_base_power, + ) + # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr + #= + for t in time_steps + fuel_expr = + ( + variable[name, t] .^ 2 * quad_term_per_unit + + variable[name, t] * prop_term_per_unit + ) * dt + JuMP.add_to_expression!( + expression[name, t], + fuel_expr, + ) + end + =# + end + end +end +=# + #= function add_to_expression!( container::OptimizationContainer, From f984b615ba28108cef6003c08da4508b6e0f3fcf Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 5 Nov 2024 15:52:51 -0800 Subject: [PATCH 153/162] update add to expression for fuel consumption using compact model --- .../thermalgeneration_constructor.jl | 24 ++++------ .../devices/common/add_to_expression.jl | 48 +++++++------------ 2 files changed, 25 insertions(+), 47 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 67b4ad039..73062f703 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -1007,16 +1007,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1187,16 +1185,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1365,16 +1361,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, @@ -1658,16 +1652,14 @@ function construct_device!( model, network_model, ) - #TODO: Implement for AbovePowerMinimum - #= + add_to_expression!( container, FuelConsumptionExpression, - PowerAboveMinimumVariable,, + PowerAboveMinimumVariable, devices, model, ) - =# add_to_expression!( container, diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index bf0e4ac65..4bb1388bc 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1852,6 +1852,7 @@ function add_to_expression!( name = PSY.get_name(d) device_base_power = PSY.get_base_power(d) value_curve = PSY.get_value_curve(var_cost) + P_min = PSY.get_active_power_limits(d).min if value_curve isa PSY.LinearCurve power_units = PSY.get_power_units(var_cost) proportional_term = PSY.get_proportional_term(value_curve) @@ -1862,46 +1863,31 @@ function add_to_expression!( device_base_power, ) for t in time_steps - fuel_expr = variable[name, t] * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - quadratic_term = PSY.get_quadratic_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - quad_term_per_unit = get_quadratic_cost_per_system_unit( - quadratic_term, - power_units, - base_power, - device_base_power, - ) - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= - for t in time_steps + sos_status = _get_sos_value(container, W, d) + if sos_status == SOSStatusVariable.NO_VARIABLE + bin = 1.0 + elseif sos_status == SOSStatusVariable.PARAMETER + param = get_default_on_parameter(d) + bin = get_parameter(container, param, V).parameter_array[name, t] + elseif sos_status == SOSStatusVariable.VARIABLE + var = get_default_on_variable(d) + bin = get_variable(container, var, V)[name, t] + else + @assert false + end fuel_expr = - ( - variable[name, t] .^ 2 * quad_term_per_unit + - variable[name, t] * prop_term_per_unit - ) * dt + variable[name, t] * prop_term_per_unit * dt + + P_min * bin * prop_term_per_unit * dt JuMP.add_to_expression!( expression[name, t], fuel_expr, ) end - =# + elseif value_curve isa PSY.QuadraticCurve + error("Quadratic Curves are not accepted with Compact Formulation: $W") end end end -=# #= function add_to_expression!( From 43412779da222754e20d29a3408b646bb6fc812f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:40:26 -0700 Subject: [PATCH 154/162] change variable name --- .../devices/common/objective_function/piecewise_linear.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 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 ce3928201..9694157e9 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -538,7 +538,7 @@ function _add_variable_cost_to_objective!( pwl_fuel_consumption_expressions = _add_pwl_term!(container, component, cost_function, T(), U()) - is_time_variant = is_time_variant(cost_function) + is_time_variant_ = is_time_variant(cost_function) for t in get_time_steps(container) fuel_cost_value = _get_fuel_cost_value( container, @@ -560,7 +560,7 @@ function _add_variable_cost_to_objective!( component, t, ) - if is_time_variant + if is_time_variant_ add_to_objective_variant_expression!(container, pwl_cost_expression) else add_to_objective_invariant_expression!(container, pwl_cost_expression) From 8e25260503726be33227a94ca6d70d32c6e8a9e4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:40:39 -0700 Subject: [PATCH 155/162] change expression addition dispatch --- src/core/optimization_container.jl | 3 ++- .../devices/common/add_to_expression.jl | 24 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index c2702c64c..64cb14427 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -1442,11 +1442,12 @@ function add_expression_container!( ::T, ::Type{U}, axs...; + expr_type = GAE, sparse = false, meta = IS.Optimization.CONTAINER_KEY_EMPTY_META, ) where {T <: ExpressionType, U <: Union{PSY.Component, PSY.System}} expr_key = ExpressionKey(T, U, meta) - return _add_expression_container!(container, expr_key, GAE, axs...; sparse = sparse) + return _add_expression_container!(container, expr_key, expr_type, axs...; sparse = sparse) end function add_expression_container!( diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 4bb1388bc..aaf91232f 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -37,12 +37,21 @@ function add_expressions!( W <: AbstractDeviceFormulation, } where {D <: PSY.Component} time_steps = get_time_steps(container) - names = [ - PSY.get_name(d) for - d in devices if PSY.get_variable(PSY.get_operation_cost(d)) isa PSY.FuelCurve - ] + names = String[] + found_quad_fuel_functions = false + for d in devices + fuel_curve = PSY.get_variable(PSY.get_operation_cost(d)) + if fuel_curve isa PSY.FuelCurve + push!(names, PSY.get_name(d)) + if !found_quad_fuel_functions + found_quad_fuel_functions = PSY.get_value_curve(fuel_curve) isa PSY.QuadraticCurve + end + end + end + if !isempty(names) - add_expression_container!(container, T(), D, names, time_steps) + expr_type = found_quad_fuel_functions ? JuMP.QuadExpr : GAE + add_expression_container!(container, T(), D, names, time_steps; expr_type = expr_type) end return end @@ -1612,9 +1621,6 @@ function add_to_expression!( base_power, device_base_power, ) - error("TODO: Implement FuelConsumptionExpression AffExpr to QuadExpr") - # TODO: Fix this FuelConsumptionExpression AffExpr to QuadExpr - #= for t in time_steps fuel_expr = ( @@ -1626,7 +1632,6 @@ function add_to_expression!( fuel_expr, ) end - =# end end end @@ -1758,6 +1763,7 @@ function add_to_expression!( end end end +=# #TODO: FuelConsumption for PowerAboveMinimumVariable #= From f30e8c1c4ef06e9d5c71c7aa26a864888ed5dee8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:40:48 -0700 Subject: [PATCH 156/162] remove unused parameter call --- src/devices_models/devices/thermal_generation.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index df1f0efef..506282e89 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -52,7 +52,6 @@ get_variable_binary(::Union{ColdStartVariable, WarmStartVariable, HotStartVariab ########################### Parameter related set functions ################################ get_multiplier_value(::ActivePowerTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_max_active_power(d) get_multiplier_value(::FuelCostParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 -get_multiplier_value(::FuelCostTimeSeriesParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_proportional_term(d.operation_cost.variable.value_curve) get_parameter_multiplier(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_initial_parameter_value(::VariableValueParameter, d::PSY.ThermalGen, ::AbstractThermalFormulation) = 1.0 get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_active_power_limits(d).max From b9db7c78d9151c331d8c376d6757e1613876a4e7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 15:47:14 -0700 Subject: [PATCH 157/162] formatter --- src/core/optimization_container.jl | 8 +++++++- .../devices/common/add_to_expression.jl | 12 ++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 64cb14427..a0a549d9d 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -1447,7 +1447,13 @@ function add_expression_container!( meta = IS.Optimization.CONTAINER_KEY_EMPTY_META, ) where {T <: ExpressionType, U <: Union{PSY.Component, PSY.System}} expr_key = ExpressionKey(T, U, meta) - return _add_expression_container!(container, expr_key, expr_type, axs...; sparse = sparse) + return _add_expression_container!( + container, + expr_key, + expr_type, + axs...; + sparse = sparse, + ) end function add_expression_container!( diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index aaf91232f..ca5a1b3af 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -44,14 +44,22 @@ function add_expressions!( if fuel_curve isa PSY.FuelCurve push!(names, PSY.get_name(d)) if !found_quad_fuel_functions - found_quad_fuel_functions = PSY.get_value_curve(fuel_curve) isa PSY.QuadraticCurve + found_quad_fuel_functions = + PSY.get_value_curve(fuel_curve) isa PSY.QuadraticCurve end end end if !isempty(names) expr_type = found_quad_fuel_functions ? JuMP.QuadExpr : GAE - add_expression_container!(container, T(), D, names, time_steps; expr_type = expr_type) + add_expression_container!( + container, + T(), + D, + names, + time_steps; + expr_type = expr_type, + ) end return end From 4e1ffbb0a4a178d03891f9656ad3f0e033ba3a6f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:23:04 -0700 Subject: [PATCH 158/162] add missing parameter additions --- .../thermalgeneration_constructor.jl | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 73062f703..78ef78037 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -60,6 +60,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -191,6 +195,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -305,6 +313,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -433,6 +445,10 @@ function construct_device!( add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end + if haskey(get_time_series_names(model), FuelCostParameter) + add_parameters!(container, FuelCostParameter, devices, model) + end + add_to_expression!( container, ActivePowerBalance, @@ -958,9 +974,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end add_to_expression!( container, @@ -1144,9 +1157,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end add_to_expression!( container, @@ -1321,9 +1331,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end add_to_expression!( container, @@ -1481,9 +1488,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end add_to_expression!( container, @@ -1612,9 +1616,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end add_to_expression!( container, @@ -1768,9 +1769,6 @@ function construct_device!( if haskey(get_time_series_names(model), ActivePowerTimeSeriesParameter) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) end - if haskey(get_time_series_names(model), FuelCostParameter) - add_parameters!(container, FuelCostParameter, devices, model) - end add_to_expression!( container, From f902467fcb302ac1696d8c4715c6cf728c34b633 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:31:45 -0700 Subject: [PATCH 159/162] update test --- ..._device_thermal_generation_constructors.jl | 35 +++---------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index b84f00f9d..8867fdfe4 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1073,35 +1073,8 @@ end store_variable_names = true, optimizer_solve_log_print = false, ) - models = SimulationModels(; - decision_models = [ - model, - ], - ) - sequence = SimulationSequence(; - models = models, - feedforwards = Dict( - ), - ini_cond_chronology = InterProblemChronology(), - ) - - sim = Simulation(; - name = "compact_sim", - steps = 2, - models = models, - sequence = sequence, - initial_time = DateTime("2024-01-01T00:00:00"), - simulation_folder = mktempdir(), - ) - - build!(sim; console_level = Logging.Error, serialize = false) - # TODO Tests - moi_tests(model, 1, 2, 3, 4, 5, false) - execute!(sim; enable_progress_bar = true) - - sim_res = SimulationResults(sim) - res_uc = get_decision_problem_results(sim_res, "UC") - th_uc = read_realized_variable(res_uc, "ActivePowerVariable__ThermalStandard") - p_brighton = th_uc[!, "Brighton"] - p_solitude = th_uc[!, "Solitude"] + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.ModelBuildStatus.BUILT + moi_tests(model, 648, 0, 312, 120, 192, true) + container = PSI.get_optimization_container(model) + @test isa(PSI.get_invariant_terms(PSI.get_objective_expression(container)), JuMP.QuadExpr) end From 78d74105d193400ad5641e30ed2e0014b4d6a558 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:34:07 -0700 Subject: [PATCH 160/162] update test --- test/test_device_thermal_generation_constructors.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 8867fdfe4..12b3deb1d 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1060,7 +1060,8 @@ end ts, ) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) + # There is no free MIQP solver, we need to use ThermalDisptchNoMin for testing + set_device_model!(template, ThermalStandard, ThermalDispatchNoMin) set_device_model!(template, PowerLoad, StaticPowerLoad) set_device_model!(template, RenewableDispatch, RenewableFullDispatch) @@ -1068,13 +1069,14 @@ end template, sys; name = "UC", - optimizer = HiGHS_optimizer, + optimizer = ipopt_optimizer, system_to_file = false, store_variable_names = true, optimizer_solve_log_print = false, ) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.ModelBuildStatus.BUILT - moi_tests(model, 648, 0, 312, 120, 192, true) + solve!(model) + moi_tests(model, 288, 0, 192, 120, 72, false) container = PSI.get_optimization_container(model) @test isa(PSI.get_invariant_terms(PSI.get_objective_expression(container)), JuMP.QuadExpr) end From 96641ef105cf4c685e055cbe112243424835e2fc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 29 Nov 2024 17:52:05 -0700 Subject: [PATCH 161/162] update has series checks --- .../common/objective_function/common.jl | 27 +++++++++++-------- .../objective_function/piecewise_linear.jl | 3 ++- src/parameters/add_parameters.jl | 9 +++---- ..._device_thermal_generation_constructors.jl | 8 ++++-- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/devices_models/devices/common/objective_function/common.jl b/src/devices_models/devices/common/objective_function/common.jl index 8b4c884b8..fc4806f3a 100644 --- a/src/devices_models/devices/common/objective_function/common.jl +++ b/src/devices_models/devices/common/objective_function/common.jl @@ -270,21 +270,26 @@ end ################## Fuel Cost ##################### ################################################## -function _get_fuel_cost_value( +function get_fuel_cost_value( container::OptimizationContainer, component::T, time_period::Int, + ::Val{true}, ) where {T <: PSY.Component} - # TODO: Check time series for derating to work later - if PSY.has_time_series(component) - parameter_array = get_parameter_array(container, FuelCostParameter(), T) - parameter_multiplier = - get_parameter_multiplier_array(container, FuelCostParameter(), T) - name = PSY.get_name(component) - return parameter_array[name, time_period] * parameter_multiplier[name, time_period] - else - return PSY.get_fuel_cost(component) - end + parameter_array = get_parameter_array(container, FuelCostParameter(), T) + parameter_multiplier = + get_parameter_multiplier_array(container, FuelCostParameter(), T) + name = PSY.get_name(component) + return parameter_array[name, time_period] * parameter_multiplier[name, time_period] +end + +function get_fuel_cost_value( + ::OptimizationContainer, + component::T, + ::Int, + ::Val{false}, +) where {T <: PSY.Component} + return PSY.get_fuel_cost(component) end function _add_time_varying_fuel_variable_cost!( 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 9694157e9..037de134a 100644 --- a/src/devices_models/devices/common/objective_function/piecewise_linear.jl +++ b/src/devices_models/devices/common/objective_function/piecewise_linear.jl @@ -540,10 +540,11 @@ function _add_variable_cost_to_objective!( is_time_variant_ = is_time_variant(cost_function) for t in get_time_steps(container) - fuel_cost_value = _get_fuel_cost_value( + fuel_cost_value = get_fuel_cost_value( container, component, t, + Val{is_time_variant_}(), ) pwl_cost_expression = pwl_fuel_consumption_expressions[t] * fuel_cost_value add_to_expression!( diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 61262fc6f..631a42fbc 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -281,8 +281,9 @@ function _add_parameters!( ) end time_steps = get_time_steps(container) - # TODO: Check for timeseries only for fuel cost - device_names = [PSY.get_name(x) for x in devices if PSY.has_time_series(x)] + ts_name = get_time_series_names(model)[T] + device_names = + [PSY.get_name(x) for x in devices if PSY.has_time_series(x, ts_type, ts_name)] if isempty(device_names) return end @@ -300,10 +301,8 @@ function _add_parameters!( time_steps, ) - ts_name = get_time_series_names(model)[T] - for device in devices - if !PSY.has_time_series(device) + if !PSY.has_time_series(device, ts_type, ts_name) continue end ts_vals = get_time_series_initial_values!(container, ts_type, device, ts_name) diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 12b3deb1d..868e0bc9f 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -1074,9 +1074,13 @@ end store_variable_names = true, optimizer_solve_log_print = false, ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.ModelBuildStatus.BUILT + @test build!(model; output_dir = mktempdir(; cleanup = true)) == + PSI.ModelBuildStatus.BUILT solve!(model) moi_tests(model, 288, 0, 192, 120, 72, false) container = PSI.get_optimization_container(model) - @test isa(PSI.get_invariant_terms(PSI.get_objective_expression(container)), JuMP.QuadExpr) + @test isa( + PSI.get_invariant_terms(PSI.get_objective_expression(container)), + JuMP.QuadExpr, + ) end From f839665efeef9007048513c18f4d79593e3f04db Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 4 Dec 2024 11:30:38 -0800 Subject: [PATCH 162/162] remove stale code --- .../devices/common/add_to_expression.jl | 196 ------------------ 1 file changed, 196 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index ca5a1b3af..ad8848ea5 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1707,202 +1707,6 @@ function add_to_expression!( end end -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= -function add_to_expression!( - container::OptimizationContainer, - ::Type{T}, - ::Type{U}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, -) where { - T <: FuelConsumptionExpression, - U <: PowerAboveMinimumVariable, - V <: PSY.ThermalGen, - W <: AbstractDeviceFormulation, -} - variable = get_variable(container, U(), V) - time_steps = get_time_steps(container) - base_power = get_base_power(container) - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - for d in devices - var_cost = PSY.get_variable(PSY.get_operation_cost(d)) - if !(var_cost isa PSY.FuelCurve) - continue - end - expression = get_expression(container, T(), V) - name = PSY.get_name(d) - device_base_power = PSY.get_base_power(d) - value_curve = PSY.get_value_curve(var_cost) - P_min = PSY.get_active_power_limits(d).min - if value_curve isa PSY.LinearCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - for t in time_steps - sos_status = _get_sos_value(container, W, d) - if sos_status == SOSStatusVariable.NO_VARIABLE - bin = 1.0 - elseif sos_status == SOSStatusVariable.PARAMETER - param = get_default_on_parameter(d) - bin = get_parameter(container, param, V).parameter_array[name, t] - elseif sos_status == SOSStatusVariable.VARIABLE - var = get_default_on_variable(d) - bin = get_variable(container, var, V)[name, t] - else - @assert false - end - fuel_expr = - variable[name, t] * prop_term_per_unit * dt + - P_min * bin * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - error("Quadratic Curves are not accepted with Compact Formulation: $W") - end - end -end -=# - -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= -function add_to_expression!( - container::OptimizationContainer, - ::Type{T}, - ::Type{U}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, -) where { - T <: FuelConsumptionExpression, - U <: PowerAboveMinimumVariable, - V <: PSY.ThermalGen, - W <: AbstractDeviceFormulation, -} - variable = get_variable(container, U(), V) - time_steps = get_time_steps(container) - base_power = get_base_power(container) - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - for d in devices - var_cost = PSY.get_variable(PSY.get_operation_cost(d)) - if !(var_cost isa PSY.FuelCurve) - continue - end - expression = get_expression(container, T(), V) - name = PSY.get_name(d) - device_base_power = PSY.get_base_power(d) - value_curve = PSY.get_value_curve(var_cost) - P_min = PSY.get_active_power_limits(d).min - if value_curve isa PSY.LinearCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - for t in time_steps - sos_status = _get_sos_value(container, W, d) - if sos_status == SOSStatusVariable.NO_VARIABLE - bin = 1.0 - elseif sos_status == SOSStatusVariable.PARAMETER - param = get_default_on_parameter(d) - bin = get_parameter(container, param, V).parameter_array[name, t] - elseif sos_status == SOSStatusVariable.VARIABLE - var = get_default_on_variable(d) - bin = get_variable(container, var, V)[name, t] - else - @assert false - end - fuel_expr = - variable[name, t] * prop_term_per_unit * dt + - P_min * bin * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - error("Quadratic Curves are not accepted with Compact Formulation: $W") - end - end -end - -#TODO: FuelConsumption for PowerAboveMinimumVariable -#= -function add_to_expression!( - container::OptimizationContainer, - ::Type{T}, - ::Type{U}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, -) where { - T <: FuelConsumptionExpression, - U <: PowerAboveMinimumVariable, - V <: PSY.ThermalGen, - W <: AbstractDeviceFormulation, -} - variable = get_variable(container, U(), V) - time_steps = get_time_steps(container) - base_power = get_base_power(container) - resolution = get_resolution(container) - dt = Dates.value(resolution) / MILLISECONDS_IN_HOUR - for d in devices - var_cost = PSY.get_variable(PSY.get_operation_cost(d)) - if !(var_cost isa PSY.FuelCurve) - continue - end - expression = get_expression(container, T(), V) - name = PSY.get_name(d) - device_base_power = PSY.get_base_power(d) - value_curve = PSY.get_value_curve(var_cost) - P_min = PSY.get_active_power_limits(d).min - if value_curve isa PSY.LinearCurve - power_units = PSY.get_power_units(var_cost) - proportional_term = PSY.get_proportional_term(value_curve) - prop_term_per_unit = get_proportional_cost_per_system_unit( - proportional_term, - power_units, - base_power, - device_base_power, - ) - for t in time_steps - sos_status = _get_sos_value(container, W, d) - if sos_status == SOSStatusVariable.NO_VARIABLE - bin = 1.0 - elseif sos_status == SOSStatusVariable.PARAMETER - param = get_default_on_parameter(d) - bin = get_parameter(container, param, V).parameter_array[name, t] - elseif sos_status == SOSStatusVariable.VARIABLE - var = get_default_on_variable(d) - bin = get_variable(container, var, V)[name, t] - else - @assert false - end - fuel_expr = - variable[name, t] * prop_term_per_unit * dt + - P_min * bin * prop_term_per_unit * dt - JuMP.add_to_expression!( - expression[name, t], - fuel_expr, - ) - end - elseif value_curve isa PSY.QuadraticCurve - error("Quadratic Curves are not accepted with Compact Formulation: $W") - end - end -end - #= function add_to_expression!( container::OptimizationContainer,