From 6a91b109fd328e5059ed6032d22a5bb70c7d1c38 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Tue, 21 Nov 2023 22:02:58 -0500 Subject: [PATCH 01/15] Start to rewrite for readability --- .../write_capacity_value.jl | 72 ++++++++++++------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index ec1968ca4b..c9b24b67f0 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -11,6 +11,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E FLEX = inputs["FLEX"] MUST_RUN = inputs["MUST_RUN"] VRE_STOR = inputs["VRE_STOR"] + minimum_plant_size = 1 # megawatt if setup["ParameterScale"] == 1 existingplant_position = findall(x -> x >= 1, (value.(EP[:eTotalCap])) * ModelScalingFactor) else @@ -39,43 +40,60 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] temp_dfCapValue = DataFrame(Resource = inputs["RESOURCES"], Zone = dfGen[!, :Zone], Reserve = fill(Symbol("CapRes_$i"), G)) - temp_capvalue = zeros(G, T) - temp_riskyhour = zeros(G, T) - temp_cap_derate = zeros(G, T) - if setup["ParameterScale"] == 1 - riskyhour_position = findall(x -> x >= 1, ((dual.(EP[:cCapacityResMargin][i, :])) ./ inputs["omega"] * ModelScalingFactor)) - else - riskyhour_position = findall(x -> x >= 1, ((dual.(EP[:cCapacityResMargin][i, :])) ./ inputs["omega"])) - end - temp_riskyhour[:, riskyhour_position] = ones(Int, G, length(riskyhour_position)) - temp_cap_derate[existingplant_position, :] = repeat(dfGen[existingplant_position, Symbol("CapRes_$i")], 1, T) + capvalue = zeros(G, T) + riskyhour = zeros(G, T) + cap_derate = zeros(G, T) + riskyhour_position = findall(>=(1), capacity_reserve_margin_price(EP, inputs, setup, i)) + riskyhour[:, riskyhour_position] = ones(Int, G, length(riskyhour_position)) + cap_derate[existingplant_position, :] = repeat(dfGen[existingplant_position, Symbol("CapRes_$i")], 1, T) - temp_capvalue[THERM_ALL_EX, :] = temp_cap_derate[THERM_ALL_EX, :] .* temp_riskyhour[THERM_ALL_EX, :] - temp_capvalue[VRE_EX, :] = temp_cap_derate[VRE_EX, :] .* (inputs["pP_Max"][VRE_EX, :]) .* temp_riskyhour[VRE_EX, :] - temp_capvalue[MUST_RUN_EX, :] = temp_cap_derate[MUST_RUN_EX, :] .* (inputs["pP_Max"][MUST_RUN_EX, :]) .* temp_riskyhour[MUST_RUN_EX, :] - temp_capvalue[HYDRO_RES_EX, :] = temp_cap_derate[HYDRO_RES_EX, :] .* (value.(EP[:vP][HYDRO_RES_EX, :])) .* temp_riskyhour[HYDRO_RES_EX, :] ./ totalcap[HYDRO_RES_EX, :] + capvalue[THERM_ALL_EX, :] = cap_derate[THERM_ALL_EX, :] .* riskyhour[THERM_ALL_EX, :] + capvalue[VRE_EX, :] = cap_derate[VRE_EX, :] .* (inputs["pP_Max"][VRE_EX, :]) .* riskyhour[VRE_EX, :] + capvalue[MUST_RUN_EX, :] = cap_derate[MUST_RUN_EX, :] .* (inputs["pP_Max"][MUST_RUN_EX, :]) .* riskyhour[MUST_RUN_EX, :] + capvalue[HYDRO_RES_EX, :] = cap_derate[HYDRO_RES_EX, :] .* (value.(EP[:vP][HYDRO_RES_EX, :])) .* riskyhour[HYDRO_RES_EX, :] ./ totalcap[HYDRO_RES_EX, :] if !isempty(STOR_ALL_EX) - temp_capvalue[STOR_ALL_EX, :] = temp_cap_derate[STOR_ALL_EX, :] .* ((value.(EP[:vP][STOR_ALL_EX, :]) - value.(EP[:vCHARGE][STOR_ALL_EX, :]).data + value.(EP[:vCAPRES_discharge][STOR_ALL_EX, :]).data - value.(EP[:vCAPRES_charge][STOR_ALL_EX, :]).data)) .* temp_riskyhour[STOR_ALL_EX, :] ./ totalcap[STOR_ALL_EX, :] + capvalue[STOR_ALL_EX, :] = cap_derate[STOR_ALL_EX, :] .* ((value.(EP[:vP][STOR_ALL_EX, :]) - value.(EP[:vCHARGE][STOR_ALL_EX, :]).data + value.(EP[:vCAPRES_discharge][STOR_ALL_EX, :]).data - value.(EP[:vCAPRES_charge][STOR_ALL_EX, :]).data)) .* riskyhour[STOR_ALL_EX, :] ./ totalcap[STOR_ALL_EX, :] end if !isempty(FLEX_EX) - temp_capvalue[FLEX_EX, :] = temp_cap_derate[FLEX_EX, :] .* ((value.(EP[:vCHARGE_FLEX][FLEX_EX, :]).data - value.(EP[:vP][FLEX_EX, :]))) .* temp_riskyhour[FLEX_EX, :] ./ totalcap[FLEX_EX, :] + capvalue[FLEX_EX, :] = cap_derate[FLEX_EX, :] .* ((value.(EP[:vCHARGE_FLEX][FLEX_EX, :]).data - value.(EP[:vP][FLEX_EX, :]))) .* riskyhour[FLEX_EX, :] ./ totalcap[FLEX_EX, :] end if !isempty(VRE_STOR_EX) - temp_capvalue_dc_discharge = zeros(G, T) - temp_capvalue_dc_discharge[DC_DISCHARGE, :] = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, :].data) .* dfVRE_STOR[(dfVRE_STOR.STOR_DC_DISCHARGE.!=0), :EtaInverter] - temp_capvalue_dc_charge = zeros(G, T) - temp_capvalue_dc_charge[DC_CHARGE, :] = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, :].data) ./ dfVRE_STOR[(dfVRE_STOR.STOR_DC_CHARGE.!=0), :EtaInverter] - temp_capvalue[VRE_STOR_EX, :] = temp_cap_derate[VRE_STOR_EX, :] .* (value.(EP[:vP][VRE_STOR_EX, :])) .* temp_riskyhour[VRE_STOR_EX, :] ./ totalcap[VRE_STOR_EX, :] - temp_capvalue[VRE_STOR_STOR_EX, :] .-= temp_cap_derate[VRE_STOR_STOR_EX, :] .* (value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)) .* temp_riskyhour[VRE_STOR_STOR_EX, :] ./ totalcap[VRE_STOR_STOR_EX, :] - temp_capvalue[DC_DISCHARGE_EX, :] .+= temp_cap_derate[DC_DISCHARGE_EX, :] .* temp_capvalue_dc_discharge[DC_DISCHARGE_EX, :] .* temp_riskyhour[DC_DISCHARGE_EX, :] ./ totalcap[DC_DISCHARGE_EX, :] - temp_capvalue[AC_DISCHARGE_EX, :] .+= temp_cap_derate[AC_DISCHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :]).data) .* temp_riskyhour[AC_DISCHARGE_EX, :] ./ totalcap[AC_DISCHARGE_EX, :] - temp_capvalue[DC_CHARGE_EX, :] .-= temp_cap_derate[DC_CHARGE_EX, :] .* temp_capvalue_dc_charge[DC_CHARGE_EX, :] .* temp_riskyhour[DC_CHARGE_EX, :] ./ totalcap[DC_CHARGE_EX, :] - temp_capvalue[AC_CHARGE_EX, :] .-= temp_cap_derate[AC_CHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :]).data) .* temp_riskyhour[AC_CHARGE_EX, :] ./ totalcap[AC_CHARGE_EX, :] + capvalue_dc_discharge = zeros(G, T) + capvalue_dc_discharge[DC_DISCHARGE, :] = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, :].data) .* dfVRE_STOR[(dfVRE_STOR.STOR_DC_DISCHARGE.!=0), :EtaInverter] + capvalue_dc_charge = zeros(G, T) + capvalue_dc_charge[DC_CHARGE, :] = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, :].data) ./ dfVRE_STOR[(dfVRE_STOR.STOR_DC_CHARGE.!=0), :EtaInverter] + capvalue[VRE_STOR_EX, :] = cap_derate[VRE_STOR_EX, :] .* (value.(EP[:vP][VRE_STOR_EX, :])) .* riskyhour[VRE_STOR_EX, :] ./ totalcap[VRE_STOR_EX, :] + capvalue[VRE_STOR_STOR_EX, :] .-= cap_derate[VRE_STOR_STOR_EX, :] .* (value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)) .* riskyhour[VRE_STOR_STOR_EX, :] ./ totalcap[VRE_STOR_STOR_EX, :] + capvalue[DC_DISCHARGE_EX, :] .+= cap_derate[DC_DISCHARGE_EX, :] .* capvalue_dc_discharge[DC_DISCHARGE_EX, :] .* riskyhour[DC_DISCHARGE_EX, :] ./ totalcap[DC_DISCHARGE_EX, :] + capvalue[AC_DISCHARGE_EX, :] .+= cap_derate[AC_DISCHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :]).data) .* riskyhour[AC_DISCHARGE_EX, :] ./ totalcap[AC_DISCHARGE_EX, :] + capvalue[DC_CHARGE_EX, :] .-= cap_derate[DC_CHARGE_EX, :] .* capvalue_dc_charge[DC_CHARGE_EX, :] .* riskyhour[DC_CHARGE_EX, :] ./ totalcap[DC_CHARGE_EX, :] + capvalue[AC_CHARGE_EX, :] .-= cap_derate[AC_CHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :]).data) .* riskyhour[AC_CHARGE_EX, :] ./ totalcap[AC_CHARGE_EX, :] end - temp_dfCapValue = hcat(temp_dfCapValue, DataFrame(temp_capvalue, :auto)) + temp_dfCapValue = hcat(temp_dfCapValue, DataFrame(capvalue, :auto)) auxNew_Names = [Symbol("Resource"); Symbol("Zone"); Symbol("Reserve"); [Symbol("t$t") for t in 1:T]] rename!(temp_dfCapValue, auxNew_Names) append!(dfCapValue, temp_dfCapValue) end CSV.write(joinpath(path, "CapacityValue.csv"), dfCapValue) end + +@doc raw""" + capacity_reserve_margin_price(EP::Model, + inputs::Dict, + setup::Dict, + capres_zone::Int)::Vector{Float64} + +Marginal electricity price for each model zone and time step. +This is equal to the dual variable of the power balance constraint. +When solving a linear program (i.e. linearized unit commitment or economic dispatch) +this output is always available; when solving a mixed integer linear program, this can +be calculated only if `WriteShadowPrices` is activated. + + Returns a vector. + Values have units of $/MW +""" +function capacity_reserve_margin_price(EP::Model, inputs::Dict, setup::Dict, capres_zone::Int)::Matrix{Float64} + ω = inputs["omega"] + scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 + return dual.(EP[:cCapacityResMargin][i, :]) ./ ω * scale_factor +end From 0540e1045e690381bcc50c7fd74397ab20bcece9 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 06:38:39 -0500 Subject: [PATCH 02/15] Redo doc --- .../capacity_reserve_margin/write_capacity_value.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index c9b24b67f0..1b3082650e 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -89,8 +89,7 @@ When solving a linear program (i.e. linearized unit commitment or economic dispa this output is always available; when solving a mixed integer linear program, this can be calculated only if `WriteShadowPrices` is activated. - Returns a vector. - Values have units of $/MW + Returns a vector, with units of $/MW """ function capacity_reserve_margin_price(EP::Model, inputs::Dict, setup::Dict, capres_zone::Int)::Matrix{Float64} ω = inputs["omega"] From 491eed14e3aedfb66efe804db498f059e27d02de Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 06:40:00 -0500 Subject: [PATCH 03/15] use write_simple_csv --- .../capacity_reserve_margin/write_capacity_value.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 1b3082650e..483eec4783 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -74,7 +74,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E rename!(temp_dfCapValue, auxNew_Names) append!(dfCapValue, temp_dfCapValue) end - CSV.write(joinpath(path, "CapacityValue.csv"), dfCapValue) + write_simple_csv(joinpath(path, "CapacityValue.csv"), dfCapValue) end @doc raw""" From 6ea579c6a2d21dc278099b4f191bfb0fcf3bfd39 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 06:41:20 -0500 Subject: [PATCH 04/15] Remove unneeded data keys --- .../capacity_reserve_margin/write_capacity_value.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 483eec4783..21e653e14f 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -2,8 +2,6 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfGen = inputs["dfGen"] G = inputs["G"] # Number of resources (generators, storage, DR, and DERs) T = inputs["T"] # Number of time steps (hours) - SEG = inputs["SEG"] # Number of lines - L = inputs["L"] # Number of lines THERM_ALL = inputs["THERM_ALL"] VRE = inputs["VRE"] HYDRO_RES = inputs["HYDRO_RES"] From 3982e70f6b03e44f3ff3278728dd8e49f145b779 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 06:52:38 -0500 Subject: [PATCH 05/15] Rename and shorten some things existingplant_position -> large_plants i.e. plants large enough to contribute to the CRM. This is just 1MW. make a temporary eTotalCap for brevity. --- .../write_capacity_value.jl | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 21e653e14f..42e994432c 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -9,20 +9,20 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E FLEX = inputs["FLEX"] MUST_RUN = inputs["MUST_RUN"] VRE_STOR = inputs["VRE_STOR"] + minimum_plant_size = 1 # megawatt - if setup["ParameterScale"] == 1 - existingplant_position = findall(x -> x >= 1, (value.(EP[:eTotalCap])) * ModelScalingFactor) - else - existingplant_position = findall(x -> x >= 1, (value.(EP[:eTotalCap]))) - end - THERM_ALL_EX = intersect(THERM_ALL, existingplant_position) - VRE_EX = intersect(VRE, existingplant_position) - HYDRO_RES_EX = intersect(HYDRO_RES, existingplant_position) - STOR_ALL_EX = intersect(STOR_ALL, existingplant_position) - FLEX_EX = intersect(FLEX, existingplant_position) - MUST_RUN_EX = intersect(MUST_RUN, existingplant_position) + scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 + eTotalCap = value.(EP[:eTotalCap]) + large_plants = findall(>=(minimum_plant_size), eTotalCap * scale_factor) + + THERM_ALL_EX = intersect(THERM_ALL, large_plants) + VRE_EX = intersect(VRE, large_plants) + HYDRO_RES_EX = intersect(HYDRO_RES, large_plants) + STOR_ALL_EX = intersect(STOR_ALL, large_plants) + FLEX_EX = intersect(FLEX, large_plants) + MUST_RUN_EX = intersect(MUST_RUN, large_plants) # Will only be activated if grid connection capacity exists (because may build standalone storage/VRE, which will only be telling by grid connection capacity) - VRE_STOR_EX = intersect(VRE_STOR, existingplant_position) + VRE_STOR_EX = intersect(VRE_STOR, large_plants) if !isempty(VRE_STOR_EX) DC_DISCHARGE = inputs["VS_STOR_DC_DISCHARGE"] DC_CHARGE = inputs["VS_STOR_DC_CHARGE"] @@ -34,7 +34,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfVRE_STOR = inputs["dfVRE_STOR"] end - totalcap = repeat((value.(EP[:eTotalCap])), 1, T) + totalcap = repeat(eTotalCap, 1, T) dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] temp_dfCapValue = DataFrame(Resource = inputs["RESOURCES"], Zone = dfGen[!, :Zone], Reserve = fill(Symbol("CapRes_$i"), G)) @@ -43,7 +43,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E cap_derate = zeros(G, T) riskyhour_position = findall(>=(1), capacity_reserve_margin_price(EP, inputs, setup, i)) riskyhour[:, riskyhour_position] = ones(Int, G, length(riskyhour_position)) - cap_derate[existingplant_position, :] = repeat(dfGen[existingplant_position, Symbol("CapRes_$i")], 1, T) + cap_derate[large_plants, :] = repeat(dfGen[large_plants, Symbol("CapRes_$i")], 1, T) capvalue[THERM_ALL_EX, :] = cap_derate[THERM_ALL_EX, :] .* riskyhour[THERM_ALL_EX, :] capvalue[VRE_EX, :] = cap_derate[VRE_EX, :] .* (inputs["pP_Max"][VRE_EX, :]) .* riskyhour[VRE_EX, :] From 2a7e4798418fe06d404d4fbc8974d1c5af26c777 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 07:11:38 -0500 Subject: [PATCH 06/15] Continue adding meaning --- .../capacity_reserve_margin/write_capacity_value.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 42e994432c..0561ebbc7c 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -10,7 +10,8 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E MUST_RUN = inputs["MUST_RUN"] VRE_STOR = inputs["VRE_STOR"] - minimum_plant_size = 1 # megawatt + minimum_plant_size = 1 # MW + minimum_crm_price = 1 # $/MW scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 eTotalCap = value.(EP[:eTotalCap]) large_plants = findall(>=(minimum_plant_size), eTotalCap * scale_factor) @@ -33,6 +34,8 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E AC_CHARGE_EX = intersect(inputs["VS_STOR_AC_CHARGE"], VRE_STOR_EX) dfVRE_STOR = inputs["dfVRE_STOR"] end + + crm_derating(i, y)::Float64 = dfGen[y, Symbol("CapRes_$i")] totalcap = repeat(eTotalCap, 1, T) dfCapValue = DataFrame() @@ -41,9 +44,9 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E capvalue = zeros(G, T) riskyhour = zeros(G, T) cap_derate = zeros(G, T) - riskyhour_position = findall(>=(1), capacity_reserve_margin_price(EP, inputs, setup, i)) + riskyhour_position = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) riskyhour[:, riskyhour_position] = ones(Int, G, length(riskyhour_position)) - cap_derate[large_plants, :] = repeat(dfGen[large_plants, Symbol("CapRes_$i")], 1, T) + cap_derate[large_plants, :] = repeat(crm_derating(i, large_plants), 1, T) capvalue[THERM_ALL_EX, :] = cap_derate[THERM_ALL_EX, :] .* riskyhour[THERM_ALL_EX, :] capvalue[VRE_EX, :] = cap_derate[VRE_EX, :] .* (inputs["pP_Max"][VRE_EX, :]) .* riskyhour[VRE_EX, :] @@ -92,5 +95,5 @@ be calculated only if `WriteShadowPrices` is activated. function capacity_reserve_margin_price(EP::Model, inputs::Dict, setup::Dict, capres_zone::Int)::Matrix{Float64} ω = inputs["omega"] scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 - return dual.(EP[:cCapacityResMargin][i, :]) ./ ω * scale_factor + return dual.(EP[:cCapacityResMargin][capres_zone, :]) ./ ω * scale_factor end From 82f49fa538bf78408c9bc07594b5a05c48dd7f97 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 07:30:25 -0500 Subject: [PATCH 07/15] fix bugs --- .../capacity_reserve_margin/write_capacity_value.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 0561ebbc7c..48a2005641 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -35,7 +35,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfVRE_STOR = inputs["dfVRE_STOR"] end - crm_derating(i, y)::Float64 = dfGen[y, Symbol("CapRes_$i")] + crm_derating(i, y::Vector{Int})::Vector{Float64} = dfGen[y, Symbol("CapRes_$i")] totalcap = repeat(eTotalCap, 1, T) dfCapValue = DataFrame() @@ -92,7 +92,7 @@ be calculated only if `WriteShadowPrices` is activated. Returns a vector, with units of $/MW """ -function capacity_reserve_margin_price(EP::Model, inputs::Dict, setup::Dict, capres_zone::Int)::Matrix{Float64} +function capacity_reserve_margin_price(EP::Model, inputs::Dict, setup::Dict, capres_zone::Int)::Vector{Float64} ω = inputs["omega"] scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 return dual.(EP[:cCapacityResMargin][capres_zone, :]) ./ ω * scale_factor From 0fdce3a774a391d7a18f4fddb3f6875a5c0800dc Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 09:08:13 -0500 Subject: [PATCH 08/15] Start replacing capvalue with capvalue_new --- .../write_capacity_value.jl | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 48a2005641..2f6c4baf2f 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -35,40 +35,51 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfVRE_STOR = inputs["dfVRE_STOR"] end - crm_derating(i, y::Vector{Int})::Vector{Float64} = dfGen[y, Symbol("CapRes_$i")] + crm_derating(i, y::Vector{Int}) = dfGen[y, Symbol("CapRes_$i")]' + max_power(t::Vector{Int}, y::Vector{Int}) = inputs["pP_Max"][y, t]' totalcap = repeat(eTotalCap, 1, T) dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] temp_dfCapValue = DataFrame(Resource = inputs["RESOURCES"], Zone = dfGen[!, :Zone], Reserve = fill(Symbol("CapRes_$i"), G)) capvalue = zeros(G, T) - riskyhour = zeros(G, T) + capvalue_new = zeros(T, G) + is_risky = zeros(G, T) cap_derate = zeros(G, T) - riskyhour_position = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) - riskyhour[:, riskyhour_position] = ones(Int, G, length(riskyhour_position)) + riskyhour = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) + is_risky[:, riskyhour] = ones(Int, G, length(riskyhour)) + + power(y) = value.(EP[:vP][riskyhour, y])' + cap_derate[large_plants, :] = repeat(crm_derating(i, large_plants), 1, T) - capvalue[THERM_ALL_EX, :] = cap_derate[THERM_ALL_EX, :] .* riskyhour[THERM_ALL_EX, :] - capvalue[VRE_EX, :] = cap_derate[VRE_EX, :] .* (inputs["pP_Max"][VRE_EX, :]) .* riskyhour[VRE_EX, :] - capvalue[MUST_RUN_EX, :] = cap_derate[MUST_RUN_EX, :] .* (inputs["pP_Max"][MUST_RUN_EX, :]) .* riskyhour[MUST_RUN_EX, :] - capvalue[HYDRO_RES_EX, :] = cap_derate[HYDRO_RES_EX, :] .* (value.(EP[:vP][HYDRO_RES_EX, :])) .* riskyhour[HYDRO_RES_EX, :] ./ totalcap[HYDRO_RES_EX, :] + capvalue_new[riskyhour, THERM_ALL_EX] .= crm_derating(i, THERM_ALL_EX) + + capvalue_new[riskyhour, VRE_EX] .= crm_derating(i, VRE_EX) .* max_power(riskyhour, VRE_EX) + + capvalue_new[riskyhour, MUST_RUN_EX] = crm_derating(i, MUST_RUN_EX) .* max_power(riskyhour, VRE_EX) + + capvalue_new[riskyhour, HYDRO_RES_EX] = crm_derating(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ eTotalCap[HYDRO_RES_EX]' + + capvalue .+= collect(transpose(capvalue_new)) + if !isempty(STOR_ALL_EX) - capvalue[STOR_ALL_EX, :] = cap_derate[STOR_ALL_EX, :] .* ((value.(EP[:vP][STOR_ALL_EX, :]) - value.(EP[:vCHARGE][STOR_ALL_EX, :]).data + value.(EP[:vCAPRES_discharge][STOR_ALL_EX, :]).data - value.(EP[:vCAPRES_charge][STOR_ALL_EX, :]).data)) .* riskyhour[STOR_ALL_EX, :] ./ totalcap[STOR_ALL_EX, :] + capvalue[STOR_ALL_EX, :] = cap_derate[STOR_ALL_EX, :] .* ((value.(EP[:vP][STOR_ALL_EX, :]) - value.(EP[:vCHARGE][STOR_ALL_EX, :]).data + value.(EP[:vCAPRES_discharge][STOR_ALL_EX, :]).data - value.(EP[:vCAPRES_charge][STOR_ALL_EX, :]).data)) .* is_risky[STOR_ALL_EX, :] ./ totalcap[STOR_ALL_EX, :] end if !isempty(FLEX_EX) - capvalue[FLEX_EX, :] = cap_derate[FLEX_EX, :] .* ((value.(EP[:vCHARGE_FLEX][FLEX_EX, :]).data - value.(EP[:vP][FLEX_EX, :]))) .* riskyhour[FLEX_EX, :] ./ totalcap[FLEX_EX, :] + capvalue[FLEX_EX, :] = cap_derate[FLEX_EX, :] .* ((value.(EP[:vCHARGE_FLEX][FLEX_EX, :]).data - value.(EP[:vP][FLEX_EX, :]))) .* is_risky[FLEX_EX, :] ./ totalcap[FLEX_EX, :] end if !isempty(VRE_STOR_EX) capvalue_dc_discharge = zeros(G, T) capvalue_dc_discharge[DC_DISCHARGE, :] = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, :].data) .* dfVRE_STOR[(dfVRE_STOR.STOR_DC_DISCHARGE.!=0), :EtaInverter] capvalue_dc_charge = zeros(G, T) capvalue_dc_charge[DC_CHARGE, :] = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, :].data) ./ dfVRE_STOR[(dfVRE_STOR.STOR_DC_CHARGE.!=0), :EtaInverter] - capvalue[VRE_STOR_EX, :] = cap_derate[VRE_STOR_EX, :] .* (value.(EP[:vP][VRE_STOR_EX, :])) .* riskyhour[VRE_STOR_EX, :] ./ totalcap[VRE_STOR_EX, :] - capvalue[VRE_STOR_STOR_EX, :] .-= cap_derate[VRE_STOR_STOR_EX, :] .* (value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)) .* riskyhour[VRE_STOR_STOR_EX, :] ./ totalcap[VRE_STOR_STOR_EX, :] - capvalue[DC_DISCHARGE_EX, :] .+= cap_derate[DC_DISCHARGE_EX, :] .* capvalue_dc_discharge[DC_DISCHARGE_EX, :] .* riskyhour[DC_DISCHARGE_EX, :] ./ totalcap[DC_DISCHARGE_EX, :] - capvalue[AC_DISCHARGE_EX, :] .+= cap_derate[AC_DISCHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :]).data) .* riskyhour[AC_DISCHARGE_EX, :] ./ totalcap[AC_DISCHARGE_EX, :] - capvalue[DC_CHARGE_EX, :] .-= cap_derate[DC_CHARGE_EX, :] .* capvalue_dc_charge[DC_CHARGE_EX, :] .* riskyhour[DC_CHARGE_EX, :] ./ totalcap[DC_CHARGE_EX, :] - capvalue[AC_CHARGE_EX, :] .-= cap_derate[AC_CHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :]).data) .* riskyhour[AC_CHARGE_EX, :] ./ totalcap[AC_CHARGE_EX, :] + capvalue[VRE_STOR_EX, :] = cap_derate[VRE_STOR_EX, :] .* (value.(EP[:vP][VRE_STOR_EX, :])) .* is_risky[VRE_STOR_EX, :] ./ totalcap[VRE_STOR_EX, :] + capvalue[VRE_STOR_STOR_EX, :] .-= cap_derate[VRE_STOR_STOR_EX, :] .* (value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)) .* is_risky[VRE_STOR_STOR_EX, :] ./ totalcap[VRE_STOR_STOR_EX, :] + capvalue[DC_DISCHARGE_EX, :] .+= cap_derate[DC_DISCHARGE_EX, :] .* capvalue_dc_discharge[DC_DISCHARGE_EX, :] .* is_risky[DC_DISCHARGE_EX, :] ./ totalcap[DC_DISCHARGE_EX, :] + capvalue[AC_DISCHARGE_EX, :] .+= cap_derate[AC_DISCHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :]).data) .* is_risky[AC_DISCHARGE_EX, :] ./ totalcap[AC_DISCHARGE_EX, :] + capvalue[DC_CHARGE_EX, :] .-= cap_derate[DC_CHARGE_EX, :] .* capvalue_dc_charge[DC_CHARGE_EX, :] .* is_risky[DC_CHARGE_EX, :] ./ totalcap[DC_CHARGE_EX, :] + capvalue[AC_CHARGE_EX, :] .-= cap_derate[AC_CHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :]).data) .* is_risky[AC_CHARGE_EX, :] ./ totalcap[AC_CHARGE_EX, :] end temp_dfCapValue = hcat(temp_dfCapValue, DataFrame(capvalue, :auto)) auxNew_Names = [Symbol("Resource"); Symbol("Zone"); Symbol("Reserve"); [Symbol("t$t") for t in 1:T]] From 6b440abd61f7ab4310348f3dcc2941c952499b33 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 10:25:42 -0500 Subject: [PATCH 09/15] Refactor write_capacity_value Standard resources, not touched VRE_STOR yet --- .../write_capacity_value.jl | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 2f6c4baf2f..757447c8d1 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -49,7 +49,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E riskyhour = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) is_risky[:, riskyhour] = ones(Int, G, length(riskyhour)) - power(y) = value.(EP[:vP][riskyhour, y])' + power(y) = value.(EP[:vP][y, riskyhour])' cap_derate[large_plants, :] = repeat(crm_derating(i, large_plants), 1, T) @@ -57,18 +57,23 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E capvalue_new[riskyhour, VRE_EX] .= crm_derating(i, VRE_EX) .* max_power(riskyhour, VRE_EX) - capvalue_new[riskyhour, MUST_RUN_EX] = crm_derating(i, MUST_RUN_EX) .* max_power(riskyhour, VRE_EX) + capvalue_new[riskyhour, MUST_RUN_EX] .= crm_derating(i, MUST_RUN_EX) .* max_power(riskyhour, MUST_RUN_EX) - capvalue_new[riskyhour, HYDRO_RES_EX] = crm_derating(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ eTotalCap[HYDRO_RES_EX]' - - capvalue .+= collect(transpose(capvalue_new)) + capvalue_new[riskyhour, HYDRO_RES_EX] .= crm_derating(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ eTotalCap[HYDRO_RES_EX]' if !isempty(STOR_ALL_EX) - capvalue[STOR_ALL_EX, :] = cap_derate[STOR_ALL_EX, :] .* ((value.(EP[:vP][STOR_ALL_EX, :]) - value.(EP[:vCHARGE][STOR_ALL_EX, :]).data + value.(EP[:vCAPRES_discharge][STOR_ALL_EX, :]).data - value.(EP[:vCAPRES_charge][STOR_ALL_EX, :]).data)) .* is_risky[STOR_ALL_EX, :] ./ totalcap[STOR_ALL_EX, :] + charge = value.(EP[:vCHARGE][STOR_ALL_EX, riskyhour]).data' + capres_discharge = value.(EP[:vCAPRES_discharge][STOR_ALL_EX, riskyhour]).data' + capres_charge = value.(EP[:vCAPRES_charge][STOR_ALL_EX, riskyhour]).data' + + capvalue_new[riskyhour, STOR_ALL_EX] .= crm_derating(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) /. eTotalCap[STOR_ALL_EX]' end + if !isempty(FLEX_EX) - capvalue[FLEX_EX, :] = cap_derate[FLEX_EX, :] .* ((value.(EP[:vCHARGE_FLEX][FLEX_EX, :]).data - value.(EP[:vP][FLEX_EX, :]))) .* is_risky[FLEX_EX, :] ./ totalcap[FLEX_EX, :] + charge = value.(EP[:vCHARGE_FLEX][FLEX_EX, riskyhour]).data' + capvalue_new[riskyhour, FLEX_EX] = crm_derating(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ eTotalCap[FLEX_EX] end + capvalue .+= collect(transpose(capvalue_new)) if !isempty(VRE_STOR_EX) capvalue_dc_discharge = zeros(G, T) capvalue_dc_discharge[DC_DISCHARGE, :] = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, :].data) .* dfVRE_STOR[(dfVRE_STOR.STOR_DC_DISCHARGE.!=0), :EtaInverter] From 3b4ca48e98be31e86d3fb75448be9dba2f17d2b3 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 10:51:24 -0500 Subject: [PATCH 10/15] start converting VRESTOR --- .../write_capacity_value.jl | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 757447c8d1..cb48ef8b0f 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -62,23 +62,31 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E capvalue_new[riskyhour, HYDRO_RES_EX] .= crm_derating(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ eTotalCap[HYDRO_RES_EX]' if !isempty(STOR_ALL_EX) - charge = value.(EP[:vCHARGE][STOR_ALL_EX, riskyhour]).data' - capres_discharge = value.(EP[:vCAPRES_discharge][STOR_ALL_EX, riskyhour]).data' - capres_charge = value.(EP[:vCAPRES_charge][STOR_ALL_EX, riskyhour]).data' + charge = value.(EP[:vCHARGE][STOR_ALL_EX, riskyhour].data)' + capres_discharge = value.(EP[:vCAPRES_discharge][STOR_ALL_EX, riskyhour].data)' + capres_charge = value.(EP[:vCAPRES_charge][STOR_ALL_EX, riskyhour].data)' - capvalue_new[riskyhour, STOR_ALL_EX] .= crm_derating(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) /. eTotalCap[STOR_ALL_EX]' + capvalue_new[riskyhour, STOR_ALL_EX] .= crm_derating(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) ./ eTotalCap[STOR_ALL_EX]' end if !isempty(FLEX_EX) - charge = value.(EP[:vCHARGE_FLEX][FLEX_EX, riskyhour]).data' - capvalue_new[riskyhour, FLEX_EX] = crm_derating(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ eTotalCap[FLEX_EX] + charge = value.(EP[:vCHARGE_FLEX][FLEX_EX, riskyhour].data)' + capvalue_new[riskyhour, FLEX_EX] .= crm_derating(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ eTotalCap[FLEX_EX]' end capvalue .+= collect(transpose(capvalue_new)) if !isempty(VRE_STOR_EX) - capvalue_dc_discharge = zeros(G, T) - capvalue_dc_discharge[DC_DISCHARGE, :] = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, :].data) .* dfVRE_STOR[(dfVRE_STOR.STOR_DC_DISCHARGE.!=0), :EtaInverter] - capvalue_dc_charge = zeros(G, T) - capvalue_dc_charge[DC_CHARGE, :] = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, :].data) ./ dfVRE_STOR[(dfVRE_STOR.STOR_DC_CHARGE.!=0), :EtaInverter] + capvalue_dc_discharge_new = zeros(T, G) + capres_dc_discharge = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, riskyhour].data)' + discharge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_DISCHARGE .!= 0, :EtaInverter]' + capvalue_dc_discharge_new[riskyhour, DC_DISCHARGE] .= capres_dc_discharge .* discharge_eff + capvalue_dc_discharge = collect(transpose(capvalue_dc_discharge_new)) + + capvalue_dc_charge_new = zeros(T, G) + capres_dc_charge = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, riskyhour].data)' + charge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_CHARGE .!= 0, :EtaInverter]' + capvalue_dc_charge_new[riskyhour, DC_CHARGE] .= capres_dc_charge ./ charge_eff + capvalue_dc_charge = collect(transpose(capvalue_dc_charge_new)) + capvalue[VRE_STOR_EX, :] = cap_derate[VRE_STOR_EX, :] .* (value.(EP[:vP][VRE_STOR_EX, :])) .* is_risky[VRE_STOR_EX, :] ./ totalcap[VRE_STOR_EX, :] capvalue[VRE_STOR_STOR_EX, :] .-= cap_derate[VRE_STOR_STOR_EX, :] .* (value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)) .* is_risky[VRE_STOR_STOR_EX, :] ./ totalcap[VRE_STOR_STOR_EX, :] capvalue[DC_DISCHARGE_EX, :] .+= cap_derate[DC_DISCHARGE_EX, :] .* capvalue_dc_discharge[DC_DISCHARGE_EX, :] .* is_risky[DC_DISCHARGE_EX, :] ./ totalcap[DC_DISCHARGE_EX, :] From d86f87992cada18eb8ca323628e7c78e9fea6694 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 12:41:28 -0500 Subject: [PATCH 11/15] Finish applying changes --- .../write_capacity_value.jl | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index cb48ef8b0f..754c950007 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -35,65 +35,63 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfVRE_STOR = inputs["dfVRE_STOR"] end - crm_derating(i, y::Vector{Int}) = dfGen[y, Symbol("CapRes_$i")]' + crm_derate(i, y::Vector{Int}) = dfGen[y, Symbol("CapRes_$i")]' max_power(t::Vector{Int}, y::Vector{Int}) = inputs["pP_Max"][y, t]' - - totalcap = repeat(eTotalCap, 1, T) + total_cap(resources::Vector{Int})::Vector{Float} = eTotalCap[resources]' + dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] temp_dfCapValue = DataFrame(Resource = inputs["RESOURCES"], Zone = dfGen[!, :Zone], Reserve = fill(Symbol("CapRes_$i"), G)) - capvalue = zeros(G, T) - capvalue_new = zeros(T, G) - is_risky = zeros(G, T) - cap_derate = zeros(G, T) + capvalue = zeros(T, G) riskyhour = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) - is_risky[:, riskyhour] = ones(Int, G, length(riskyhour)) power(y) = value.(EP[:vP][y, riskyhour])' - cap_derate[large_plants, :] = repeat(crm_derating(i, large_plants), 1, T) - - capvalue_new[riskyhour, THERM_ALL_EX] .= crm_derating(i, THERM_ALL_EX) + capvalue[riskyhour, THERM_ALL_EX] .= crm_derate(i, THERM_ALL_EX) - capvalue_new[riskyhour, VRE_EX] .= crm_derating(i, VRE_EX) .* max_power(riskyhour, VRE_EX) + capvalue[riskyhour, VRE_EX] .= crm_derate(i, VRE_EX) .* max_power(riskyhour, VRE_EX) - capvalue_new[riskyhour, MUST_RUN_EX] .= crm_derating(i, MUST_RUN_EX) .* max_power(riskyhour, MUST_RUN_EX) + capvalue[riskyhour, MUST_RUN_EX] .= crm_derate(i, MUST_RUN_EX) .* max_power(riskyhour, MUST_RUN_EX) - capvalue_new[riskyhour, HYDRO_RES_EX] .= crm_derating(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ eTotalCap[HYDRO_RES_EX]' + capvalue[riskyhour, HYDRO_RES_EX] .= crm_derate(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ total_cap(HYDRO_RES_EX) if !isempty(STOR_ALL_EX) charge = value.(EP[:vCHARGE][STOR_ALL_EX, riskyhour].data)' capres_discharge = value.(EP[:vCAPRES_discharge][STOR_ALL_EX, riskyhour].data)' capres_charge = value.(EP[:vCAPRES_charge][STOR_ALL_EX, riskyhour].data)' - capvalue_new[riskyhour, STOR_ALL_EX] .= crm_derating(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) ./ eTotalCap[STOR_ALL_EX]' + capvalue[riskyhour, STOR_ALL_EX] .= crm_derate(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) ./ total_cap(STOR_ALL_EX) end if !isempty(FLEX_EX) charge = value.(EP[:vCHARGE_FLEX][FLEX_EX, riskyhour].data)' - capvalue_new[riskyhour, FLEX_EX] .= crm_derating(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ eTotalCap[FLEX_EX]' + capvalue[riskyhour, FLEX_EX] .= crm_derate(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ total_cap(FLEX_EX) end - capvalue .+= collect(transpose(capvalue_new)) if !isempty(VRE_STOR_EX) - capvalue_dc_discharge_new = zeros(T, G) - capres_dc_discharge = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, riskyhour].data)' + capvalue_dc_discharge = zeros(T, G) + capres_dc_discharge = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE_EX, riskyhour].data)' discharge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_DISCHARGE .!= 0, :EtaInverter]' - capvalue_dc_discharge_new[riskyhour, DC_DISCHARGE] .= capres_dc_discharge .* discharge_eff - capvalue_dc_discharge = collect(transpose(capvalue_dc_discharge_new)) + capvalue_dc_discharge[riskyhour, DC_DISCHARGE_EX] .= capres_dc_discharge .* discharge_eff - capvalue_dc_charge_new = zeros(T, G) - capres_dc_charge = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, riskyhour].data)' + capvalue_dc_charge = zeros(T, G) + capres_dc_charge = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE_EX, riskyhour].data)' charge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_CHARGE .!= 0, :EtaInverter]' - capvalue_dc_charge_new[riskyhour, DC_CHARGE] .= capres_dc_charge ./ charge_eff - capvalue_dc_charge = collect(transpose(capvalue_dc_charge_new)) - - capvalue[VRE_STOR_EX, :] = cap_derate[VRE_STOR_EX, :] .* (value.(EP[:vP][VRE_STOR_EX, :])) .* is_risky[VRE_STOR_EX, :] ./ totalcap[VRE_STOR_EX, :] - capvalue[VRE_STOR_STOR_EX, :] .-= cap_derate[VRE_STOR_STOR_EX, :] .* (value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)) .* is_risky[VRE_STOR_STOR_EX, :] ./ totalcap[VRE_STOR_STOR_EX, :] - capvalue[DC_DISCHARGE_EX, :] .+= cap_derate[DC_DISCHARGE_EX, :] .* capvalue_dc_discharge[DC_DISCHARGE_EX, :] .* is_risky[DC_DISCHARGE_EX, :] ./ totalcap[DC_DISCHARGE_EX, :] - capvalue[AC_DISCHARGE_EX, :] .+= cap_derate[AC_DISCHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :]).data) .* is_risky[AC_DISCHARGE_EX, :] ./ totalcap[AC_DISCHARGE_EX, :] - capvalue[DC_CHARGE_EX, :] .-= cap_derate[DC_CHARGE_EX, :] .* capvalue_dc_charge[DC_CHARGE_EX, :] .* is_risky[DC_CHARGE_EX, :] ./ totalcap[DC_CHARGE_EX, :] - capvalue[AC_CHARGE_EX, :] .-= cap_derate[AC_CHARGE_EX, :] .* (value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :]).data) .* is_risky[AC_CHARGE_EX, :] ./ totalcap[AC_CHARGE_EX, :] + capvalue_dc_charge[riskyhour, DC_CHARGE_EX] .= capres_dc_charge ./ charge_eff + + capvalue[riskyhour, VRE_STOR_EX] .= crm_derate(i, VRE_STOR_EX) .* power(VRE_STOR_EX) ./ total_cap(VRE_STOR_STOR_EX) + + charge_vre_stor = value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)' + capvalue[riskyhour, VRE_STOR_STOR_EX] .-= crm_derate(i, VRE_STOR_STOR_EX) .* charge_vre_stor ./ total_cap(VRE_STOR_STOR_EX) + + capvalue[riskyhour, DC_DISCHARGE_EX] .+= crm_derate(i, DC_DISCHARGE_EX) .* capvalue_dc_discharge[riskyhour, DC_DISCHARGE_EX] ./ total_cap(DC_DISCHARGE_EX) + capres_ac_discharge = value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :].data)' + capvalue[riskyhour, AC_DISCHARGE_EX] .+= crm_derate(i, AC_DISCHARGE_EX) .* capres_ac_discharge ./ total_cap(AC_DISCHARGE_EX) + + capvalue[riskyhour, DC_CHARGE_EX] .-= crm_derate(i, DC_CHARGE_EX) .* capvalue_dc_charge[riskyhour, DC_CHARGE_EX] ./ total_cap(DC_CHARGE_EX) + capres_ac_charge = value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :].data)' + capvalue[riskyhour, AC_CHARGE_EX] .-= crm_derate(i, AC_CHARGE_EX) .* capres_ac_charge ./ total_cap(AC_CHARGE_EX) end + capvalue .+= collect(transpose(capvalue)) temp_dfCapValue = hcat(temp_dfCapValue, DataFrame(capvalue, :auto)) auxNew_Names = [Symbol("Resource"); Symbol("Zone"); Symbol("Reserve"); [Symbol("t$t") for t in 1:T]] rename!(temp_dfCapValue, auxNew_Names) From 138b2ed5b70130cbddc269a7cb67ce416997a667 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 13:50:33 -0500 Subject: [PATCH 12/15] Fix bugs --- .../write_capacity_value.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 754c950007..e00162e016 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -37,7 +37,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E crm_derate(i, y::Vector{Int}) = dfGen[y, Symbol("CapRes_$i")]' max_power(t::Vector{Int}, y::Vector{Int}) = inputs["pP_Max"][y, t]' - total_cap(resources::Vector{Int})::Vector{Float} = eTotalCap[resources]' + total_cap(resources::Vector{Int}) = eTotalCap[resources]' dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] @@ -68,17 +68,17 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E capvalue[riskyhour, FLEX_EX] .= crm_derate(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ total_cap(FLEX_EX) end if !isempty(VRE_STOR_EX) - capvalue_dc_discharge = zeros(T, G) - capres_dc_discharge = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE_EX, riskyhour].data)' + capres_dc_discharge = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, riskyhour].data)' discharge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_DISCHARGE .!= 0, :EtaInverter]' - capvalue_dc_discharge[riskyhour, DC_DISCHARGE_EX] .= capres_dc_discharge .* discharge_eff + capvalue_dc_discharge = zeros(T, G) + capvalue_dc_discharge[riskyhour, DC_DISCHARGE] .= capres_dc_discharge .* discharge_eff - capvalue_dc_charge = zeros(T, G) - capres_dc_charge = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE_EX, riskyhour].data)' + capres_dc_charge = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, riskyhour].data)' charge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_CHARGE .!= 0, :EtaInverter]' - capvalue_dc_charge[riskyhour, DC_CHARGE_EX] .= capres_dc_charge ./ charge_eff + capvalue_dc_charge = zeros(T, G) + capvalue_dc_charge[riskyhour, DC_CHARGE] .= capres_dc_charge ./ charge_eff - capvalue[riskyhour, VRE_STOR_EX] .= crm_derate(i, VRE_STOR_EX) .* power(VRE_STOR_EX) ./ total_cap(VRE_STOR_STOR_EX) + capvalue[riskyhour, VRE_STOR_EX] .= crm_derate(i, VRE_STOR_EX) .* power(VRE_STOR_EX) ./ total_cap(VRE_STOR_EX) charge_vre_stor = value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)' capvalue[riskyhour, VRE_STOR_STOR_EX] .-= crm_derate(i, VRE_STOR_STOR_EX) .* charge_vre_stor ./ total_cap(VRE_STOR_STOR_EX) From 264258a64ce5de22ce50b848163e04b06a2d5035 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Wed, 22 Nov 2023 14:19:21 -0500 Subject: [PATCH 13/15] Polishing --- .../write_capacity_value.jl | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index e00162e016..4d374fa702 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -10,10 +10,10 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E MUST_RUN = inputs["MUST_RUN"] VRE_STOR = inputs["VRE_STOR"] - minimum_plant_size = 1 # MW - minimum_crm_price = 1 # $/MW scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 eTotalCap = value.(EP[:eTotalCap]) + + minimum_plant_size = 1 # MW large_plants = findall(>=(minimum_plant_size), eTotalCap * scale_factor) THERM_ALL_EX = intersect(THERM_ALL, large_plants) @@ -41,63 +41,65 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] - temp_dfCapValue = DataFrame(Resource = inputs["RESOURCES"], Zone = dfGen[!, :Zone], Reserve = fill(Symbol("CapRes_$i"), G)) - capvalue = zeros(T, G) - riskyhour = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) + capvalue = zeros(T, G) + + minimum_crm_price = 1 # $/MW + riskyhour = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) power(y) = value.(EP[:vP][y, riskyhour])' - capvalue[riskyhour, THERM_ALL_EX] .= crm_derate(i, THERM_ALL_EX) + capvalue[riskyhour, THERM_ALL_EX] = crm_derate(i, THERM_ALL_EX) - capvalue[riskyhour, VRE_EX] .= crm_derate(i, VRE_EX) .* max_power(riskyhour, VRE_EX) + capvalue[riskyhour, VRE_EX] = crm_derate(i, VRE_EX) .* max_power(riskyhour, VRE_EX) - capvalue[riskyhour, MUST_RUN_EX] .= crm_derate(i, MUST_RUN_EX) .* max_power(riskyhour, MUST_RUN_EX) + capvalue[riskyhour, MUST_RUN_EX] = crm_derate(i, MUST_RUN_EX) .* max_power(riskyhour, MUST_RUN_EX) - capvalue[riskyhour, HYDRO_RES_EX] .= crm_derate(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ total_cap(HYDRO_RES_EX) + capvalue[riskyhour, HYDRO_RES_EX] = crm_derate(i, HYDRO_RES_EX) .* power(HYDRO_RES_EX) ./ total_cap(HYDRO_RES_EX) if !isempty(STOR_ALL_EX) charge = value.(EP[:vCHARGE][STOR_ALL_EX, riskyhour].data)' capres_discharge = value.(EP[:vCAPRES_discharge][STOR_ALL_EX, riskyhour].data)' capres_charge = value.(EP[:vCAPRES_charge][STOR_ALL_EX, riskyhour].data)' - capvalue[riskyhour, STOR_ALL_EX] .= crm_derate(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) ./ total_cap(STOR_ALL_EX) + capvalue[riskyhour, STOR_ALL_EX] = crm_derate(i, STOR_ALL_EX) .* (power(STOR_ALL_EX) - charge + capres_discharge - capres_charge) ./ total_cap(STOR_ALL_EX) end if !isempty(FLEX_EX) charge = value.(EP[:vCHARGE_FLEX][FLEX_EX, riskyhour].data)' - capvalue[riskyhour, FLEX_EX] .= crm_derate(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ total_cap(FLEX_EX) + capvalue[riskyhour, FLEX_EX] = crm_derate(i, FLEX_EX) .* (charge - power(FLEX_EX)) ./ total_cap(FLEX_EX) end if !isempty(VRE_STOR_EX) capres_dc_discharge = value.(EP[:vCAPRES_DC_DISCHARGE][DC_DISCHARGE, riskyhour].data)' discharge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_DISCHARGE .!= 0, :EtaInverter]' capvalue_dc_discharge = zeros(T, G) - capvalue_dc_discharge[riskyhour, DC_DISCHARGE] .= capres_dc_discharge .* discharge_eff + capvalue_dc_discharge[riskyhour, DC_DISCHARGE] = capres_dc_discharge .* discharge_eff capres_dc_charge = value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, riskyhour].data)' charge_eff = dfVRE_STOR[dfVRE_STOR.STOR_DC_CHARGE .!= 0, :EtaInverter]' capvalue_dc_charge = zeros(T, G) - capvalue_dc_charge[riskyhour, DC_CHARGE] .= capres_dc_charge ./ charge_eff + capvalue_dc_charge[riskyhour, DC_CHARGE] = capres_dc_charge ./ charge_eff - capvalue[riskyhour, VRE_STOR_EX] .= crm_derate(i, VRE_STOR_EX) .* power(VRE_STOR_EX) ./ total_cap(VRE_STOR_EX) + capvalue[riskyhour, VRE_STOR_EX] = crm_derate(i, VRE_STOR_EX) .* power(VRE_STOR_EX) ./ total_cap(VRE_STOR_EX) - charge_vre_stor = value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, :].data)' - capvalue[riskyhour, VRE_STOR_STOR_EX] .-= crm_derate(i, VRE_STOR_STOR_EX) .* charge_vre_stor ./ total_cap(VRE_STOR_STOR_EX) + charge_vre_stor = value.(EP[:vCHARGE_VRE_STOR][VRE_STOR_STOR_EX, riskyhour].data)' + capvalue[riskyhour, VRE_STOR_STOR_EX] -= crm_derate(i, VRE_STOR_STOR_EX) .* charge_vre_stor ./ total_cap(VRE_STOR_STOR_EX) - capvalue[riskyhour, DC_DISCHARGE_EX] .+= crm_derate(i, DC_DISCHARGE_EX) .* capvalue_dc_discharge[riskyhour, DC_DISCHARGE_EX] ./ total_cap(DC_DISCHARGE_EX) - capres_ac_discharge = value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, :].data)' - capvalue[riskyhour, AC_DISCHARGE_EX] .+= crm_derate(i, AC_DISCHARGE_EX) .* capres_ac_discharge ./ total_cap(AC_DISCHARGE_EX) + capvalue[riskyhour, DC_DISCHARGE_EX] += crm_derate(i, DC_DISCHARGE_EX) .* capvalue_dc_discharge[riskyhour, DC_DISCHARGE_EX] ./ total_cap(DC_DISCHARGE_EX) + capres_ac_discharge = value.(EP[:vCAPRES_AC_DISCHARGE][AC_DISCHARGE_EX, riskyhour].data)' + capvalue[riskyhour, AC_DISCHARGE_EX] += crm_derate(i, AC_DISCHARGE_EX) .* capres_ac_discharge ./ total_cap(AC_DISCHARGE_EX) - capvalue[riskyhour, DC_CHARGE_EX] .-= crm_derate(i, DC_CHARGE_EX) .* capvalue_dc_charge[riskyhour, DC_CHARGE_EX] ./ total_cap(DC_CHARGE_EX) - capres_ac_charge = value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, :].data)' - capvalue[riskyhour, AC_CHARGE_EX] .-= crm_derate(i, AC_CHARGE_EX) .* capres_ac_charge ./ total_cap(AC_CHARGE_EX) + capvalue[riskyhour, DC_CHARGE_EX] -= crm_derate(i, DC_CHARGE_EX) .* capvalue_dc_charge[riskyhour, DC_CHARGE_EX] ./ total_cap(DC_CHARGE_EX) + capres_ac_charge = value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE_EX, riskyhour].data)' + capvalue[riskyhour, AC_CHARGE_EX] -= crm_derate(i, AC_CHARGE_EX) .* capres_ac_charge ./ total_cap(AC_CHARGE_EX) end - capvalue .+= collect(transpose(capvalue)) + capvalue = collect(transpose(capvalue)) + temp_dfCapValue = DataFrame(Resource = inputs["RESOURCES"], Zone = dfGen.Zone, Reserve = fill(Symbol("CapRes_$i"), G)) temp_dfCapValue = hcat(temp_dfCapValue, DataFrame(capvalue, :auto)) auxNew_Names = [Symbol("Resource"); Symbol("Zone"); Symbol("Reserve"); [Symbol("t$t") for t in 1:T]] rename!(temp_dfCapValue, auxNew_Names) append!(dfCapValue, temp_dfCapValue) end - write_simple_csv(joinpath(path, "CapacityValue.csv"), dfCapValue) + write_simple_csv(joinpath(path, "CapacityValue.csv"), dfCapValue) end @doc raw""" From 35431d9c870f5645cc05652f2c8117349a0cb9e5 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Tue, 28 Nov 2023 10:37:11 -0500 Subject: [PATCH 14/15] Update src/write_outputs/capacity_reserve_margin/write_capacity_value.jl Co-authored-by: Luca Bonaldo <39280783+lbonaldo@users.noreply.github.com> --- .../capacity_reserve_margin/write_capacity_value.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index 4d374fa702..f7cbdaf96f 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -37,7 +37,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E crm_derate(i, y::Vector{Int}) = dfGen[y, Symbol("CapRes_$i")]' max_power(t::Vector{Int}, y::Vector{Int}) = inputs["pP_Max"][y, t]' - total_cap(resources::Vector{Int}) = eTotalCap[resources]' + total_cap(y::Vector{Int}) = eTotalCap[y]' dfCapValue = DataFrame() for i in 1:inputs["NCapacityReserveMargin"] From 4289ea13dc1ff2eca629369a27807260b336dca4 Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Tue, 28 Nov 2023 10:39:31 -0500 Subject: [PATCH 15/15] Update src/write_outputs/capacity_reserve_margin/write_capacity_value.jl Co-authored-by: Luca Bonaldo <39280783+lbonaldo@users.noreply.github.com> --- .../capacity_reserve_margin/write_capacity_value.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl index f7cbdaf96f..a8f6b2fc58 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -46,7 +46,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E minimum_crm_price = 1 # $/MW riskyhour = findall(>=(minimum_crm_price), capacity_reserve_margin_price(EP, inputs, setup, i)) - power(y) = value.(EP[:vP][y, riskyhour])' + power(y::Vector{Int}) = value.(EP[:vP][y, riskyhour])' capvalue[riskyhour, THERM_ALL_EX] = crm_derate(i, THERM_ALL_EX)