Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Output correct CRM values for THERM plants with maintenance #589

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/model/resources/thermal/thermal_commit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,20 @@
MAINT = resources_with_maintenance(dfGen)
applicable_resources = intersect(MAINT, THERM_COMMIT)

resource_component(y) = dfGen[y, :Resource]
capresfactor(y, capres) = dfGen[y, Symbol("CapRes_$capres")]
cap_size(y) = dfGen[y, :Cap_Size]
down_var(y) = EP[Symbol(maintenance_down_name(resource_component(y)))]
maint_adj = @expression(EP, [capres in 1:ncapres, t in 1:T],
-sum(capresfactor(y, capres) * down_var(y)[t] * cap_size(y) for y in applicable_resources))
sum(thermal_maintenance_capacity_reserve_margin_adjustment(EP, inputs, y, capres, t) for y in applicable_resources))
add_similar_to_expression!(EP[:eCapResMarBalance], maint_adj)
end

function thermal_maintenance_capacity_reserve_margin_adjustment(EP::Model,

Check warning on line 369 in src/model/resources/thermal/thermal_commit.jl

View check run for this annotation

Codecov / codecov/patch

src/model/resources/thermal/thermal_commit.jl#L369

Added line #L369 was not covered by tests
inputs::Dict,
y::Int,
capres::Int,
t)
dfGen = inputs["dfGen"]
resource_component = dfGen[y, :Resource]
capresfactor = dfGen[y, Symbol("CapRes_$capres")]
cap_size = dfGen[y, :Cap_Size]
down_var = EP[Symbol(maintenance_down_name(resource_component))]
return -capresfactor * down_var[t] * cap_size

Check warning on line 379 in src/model/resources/thermal/thermal_commit.jl

View check run for this annotation

Codecov / codecov/patch

src/model/resources/thermal/thermal_commit.jl#L374-L379

Added lines #L374 - L379 were not covered by tests
end
54 changes: 54 additions & 0 deletions src/write_outputs/capacity_reserve_margin/effective_capacity.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@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(

Check warning on line 10 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L10

Added line #L10 was not covered by tests
EP,
inputs,
resources::Vector{Int},
capres_zone::Int,
timesteps::Vector{Int},
)::Matrix{Float64}
eff_cap =

Check warning on line 17 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L17

Added line #L17 was not covered by tests
thermal_plant_effective_capacity.(
Ref(EP),
Ref(inputs),
resources,
Ref(capres_zone),
Ref(timesteps),
)
return reduce(hcat, eff_cap)

Check warning on line 25 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L25

Added line #L25 was not covered by tests
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)

Check warning on line 31 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L28-L31

Added lines #L28 - L31 were not covered by tests
end

function thermal_plant_effective_capacity(

Check warning on line 34 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L34

Added line #L34 was not covered by tests
EP::Model,
inputs::Dict,
r_id::Int,
capres_zone::Int,
timesteps::Vector{Int},
)::Vector{Float64}
y = r_id
dfGen = inputs["dfGen"]
capresfactor = dfGen[y, Symbol("CapRes_$capres_zone")]
eTotalCap = value.(EP[:eTotalCap][y])

Check warning on line 44 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L41-L44

Added lines #L41 - L44 were not covered by tests

effective_capacity = fill(capresfactor * eTotalCap, length(timesteps))

Check warning on line 46 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L46

Added line #L46 was not covered by tests

if has_maintenance(inputs) && y in resources_with_maintenance(dfGen)
adjustment = thermal_maintenance_capacity_reserve_margin_adjustment(EP, inputs, y, capres_zone, timesteps)
effective_capacity = effective_capacity .+ value.(adjustment)

Check warning on line 50 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L48-L50

Added lines #L48 - L50 were not covered by tests
end

return effective_capacity

Check warning on line 53 in src/write_outputs/capacity_reserve_margin/effective_capacity.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/effective_capacity.jl#L53

Added line #L53 was not covered by tests
end
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@

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)

Check warning on line 51 in src/write_outputs/capacity_reserve_margin/write_capacity_value.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/write_capacity_value.jl#L51

Added line #L51 was not covered by tests

capvalue[riskyhour, VRE_EX] = crm_derate(i, VRE_EX) .* max_power(riskyhour, VRE_EX)

Expand Down Expand Up @@ -121,3 +121,4 @@
scale_factor = setup["ParameterScale"] == 1 ? ModelScalingFactor : 1
return dual.(EP[:cCapacityResMargin][capres_zone, :]) ./ ω * scale_factor
end

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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

Check warning on line 12 in src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl#L12

Added line #L12 was not covered by tests
dfGen = inputs["dfGen"]
G = inputs["G"] # Number of resources (generators, storage, DR, and DERs)
T = inputs["T"] # Number of time steps (hours)
Expand All @@ -31,9 +32,10 @@
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

Check warning on line 35 in src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl#L35

Added line #L35 was not covered by tests
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

Check warning on line 38 in src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl#L38

Added line #L38 was not covered by tests
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, :])))
Expand All @@ -52,9 +54,7 @@
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, :])))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could similarly use weighted_price to replace calls to dual.(EP[:cCapResMargin][i, :]) on other lines but I felt that would be better as a separate "refactor" PR.

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

Check warning on line 57 in src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl

View check run for this annotation

Codecov / codecov/patch

src/write_outputs/capacity_reserve_margin/write_reserve_margin_revenue.jl#L57

Added line #L57 was not covered by tests
annual_sum .+= tempresrev
dfResRevenue = hcat(dfResRevenue, DataFrame([tempresrev], [sym]))
end
Expand Down