From 9676021210529a2ea11ae9189c83eb51a385ab1d Mon Sep 17 00:00:00 2001 From: Jacob Schwartz Date: Thu, 30 Nov 2023 15:01:29 -0500 Subject: [PATCH] Use thermal_effective_capacity function --- .../effective_capacity.jl | 38 +++++++++++++++++++ .../write_capacity_value.jl | 21 +--------- .../write_reserve_margin_revenue.jl | 8 ++-- 3 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 src/write_outputs/capacity_reserve_margin/effective_capacity.jl diff --git a/src/write_outputs/capacity_reserve_margin/effective_capacity.jl b/src/write_outputs/capacity_reserve_margin/effective_capacity.jl new file mode 100644 index 0000000000..4b1b27450a --- /dev/null +++ b/src/write_outputs/capacity_reserve_margin/effective_capacity.jl @@ -0,0 +1,38 @@ +@doc raw""" + thermal_plant_effective_capacity(EP::Model, + inputs::Dict, + resources::Vector{Int}, + capres_zone::Int, + timesteps::Vector{Int})::Matrix{Float64} + + Effective capacity in a capacity reserve margin zone for certain resources in the given timesteps. +""" +function thermal_plant_effective_capacity(EP, inputs, resources::Vector{Int}, capres_zone::Int, timesteps::Vector{Int})::Matrix{Float64} + eff_cap = thermal_plant_effective_capacity.(Ref(EP), Ref(inputs), resources, Ref(capres_zone), Ref(timesteps)) + return reduce(hcat, eff_cap) +end + +function thermal_plant_effective_capacity(EP::Model, inputs::Dict, y, capres_zone::Int) + T = inputs["T"] + timesteps = collect(1:T) + return thermal_plant_effective_capacity(EP, inputs, y, capres_zone, timesteps) +end + +function thermal_plant_effective_capacity(EP::Model, inputs::Dict, r_id::Int, capres_zone::Int, timesteps::Vector{Int})::Vector{Float64} + y = r_id + dfGen = inputs["dfGen"] + capresfactor(y, capres) = dfGen[y, Symbol("CapRes_$capres")] + eTotalCap = value.(EP[:eTotalCap][y]) + + effective_capacity = capresfactor(y, capres_zone) * eTotalCap * one.(timesteps) + + if has_maintenance(inputs) && y in resources_with_maintenance(dfGen) + resource_component = dfGen[y, :Resource] + cap_size = dfGen[y, :Cap_Size] + down_var = EP[Symbol(maintenance_down_name(resource_component))] + vDOWN = value.(down_var[timesteps]) + effective_capacity = effective_capacity .- capresfactor(y, capres_zone) * vDOWN * cap_size + end + + return effective_capacity +end 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 e310fd3b95..cbefad6c83 100644 --- a/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl +++ b/src/write_outputs/capacity_reserve_margin/write_capacity_value.jl @@ -48,7 +48,7 @@ function write_capacity_value(path::AbstractString, inputs::Dict, setup::Dict, E power(y::Vector{Int}) = value.(EP[:vP][y, riskyhour])' - capvalue[riskyhour, THERM_ALL_EX] = crm_derate(i, THERM_ALL_EX) + capvalue[riskyhour, THERM_ALL_EX] = thermal_plant_effective_capacity(EP, inputs, THERM_ALL_EX, i, riskyhour) ./ total_cap(THERM_ALL_EX) capvalue[riskyhour, VRE_EX] = crm_derate(i, VRE_EX) .* max_power(riskyhour, VRE_EX) @@ -122,22 +122,3 @@ function capacity_reserve_margin_price(EP::Model, inputs::Dict, setup::Dict, cap return dual.(EP[:cCapacityResMargin][capres_zone, :]) ./ ω * scale_factor end -function thermal_plant_effective_capacity(EP::Model, inputs::Dict, r_id::Int, capres_zone::Int)::Vector{Float} - y = r_id - T = inputs["T"] - dfGen = inputs["dfGen"] - capresfactor(y, capres) = dfGen[y, Symbol("CapRes_$capres")] - eTotalCap = value.(EP[:eTotalCap][y]) - - effective_capacity = capresfactor(y, capres_zone) * eTotalCap * ones(T) - - if has_maintenance(inputs) - resource_component(y) = dfGen[y, :Resource] - cap_size = dfGen[y, :Cap_Size] - down_var(y) = EP[Symbol(maintenance_down_name(resource_component(y)))] - vDOWN = value.(down_var(y)) - effective_capacity -= capresfactor(y, capres) * vDOWN * cap_size - end - - return effective_capacity -end diff --git a/src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl b/src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl index e2bfc70153..f40877ac78 100644 --- a/src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl +++ b/src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl @@ -9,6 +9,7 @@ Function for reporting the capacity revenue earned by each generator listed in t As a reminder, GenX models the capacity reserve margin (aka capacity market) at the time-dependent level, and each constraint either stands for an overall market or a locality constraint. """ function write_reserve_margin_revenue(path::AbstractString, inputs::Dict, setup::Dict, EP::Model) + scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1 dfGen = inputs["dfGen"] G = inputs["G"] # Number of resources (generators, storage, DR, and DERs) T = inputs["T"] # Number of time steps (hours) @@ -31,9 +32,10 @@ function write_reserve_margin_revenue(path::AbstractString, inputs::Dict, setup: dfResRevenue = DataFrame(Region = dfGen.region, Resource = inputs["RESOURCES"], Zone = dfGen.Zone, Cluster = dfGen.cluster) annual_sum = zeros(G) for i in 1:inputs["NCapacityReserveMargin"] + weighted_price = capacity_reserve_margin_price(EP, inputs, setup, i) .* inputs["omega"] / scale_factor sym = Symbol("CapRes_$i") tempresrev = zeros(G) - tempresrev[THERM_ALL] = dfGen[THERM_ALL, sym] .* (value.(EP[:eTotalCap][THERM_ALL])) * sum(dual.(EP[:cCapacityResMargin][i, :])) + tempresrev[THERM_ALL] = thermal_plant_effective_capacity(EP, inputs, THERM_ALL, i)' * weighted_price tempresrev[VRE] = dfGen[VRE, sym] .* (value.(EP[:eTotalCap][VRE])) .* (inputs["pP_Max"][VRE, :] * (dual.(EP[:cCapacityResMargin][i, :]))) tempresrev[MUST_RUN] = dfGen[MUST_RUN, sym] .* (value.(EP[:eTotalCap][MUST_RUN])) .* (inputs["pP_Max"][MUST_RUN, :] * (dual.(EP[:cCapacityResMargin][i, :]))) tempresrev[HYDRO_RES] = dfGen[HYDRO_RES, sym] .* (value.(EP[:vP][HYDRO_RES, :]) * (dual.(EP[:cCapacityResMargin][i, :]))) @@ -52,9 +54,7 @@ function write_reserve_margin_revenue(path::AbstractString, inputs::Dict, setup: tempresrev[DC_CHARGE] .-= dfVRE_STOR[(dfVRE_STOR.STOR_DC_CHARGE.!=0), sym_vs] .* ((value.(EP[:vCAPRES_DC_CHARGE][DC_CHARGE, :]).data ./ dfVRE_STOR[(dfVRE_STOR.STOR_DC_CHARGE.!=0), :EtaInverter]) * (dual.(EP[:cCapacityResMargin][i, :]))) tempresrev[AC_CHARGE] .-= dfVRE_STOR[(dfVRE_STOR.STOR_AC_CHARGE.!=0), sym_vs] .* ((value.(EP[:vCAPRES_AC_CHARGE][AC_CHARGE, :]).data) * (dual.(EP[:cCapacityResMargin][i, :]))) end - if setup["ParameterScale"] == 1 - tempresrev *= ModelScalingFactor^2 - end + tempresrev *= scale_factor^2 annual_sum .+= tempresrev dfResRevenue = hcat(dfResRevenue, DataFrame([tempresrev], [sym])) end