Skip to content

Commit

Permalink
Fixed computation of cumulative minimum retirements in multistage cod…
Browse files Browse the repository at this point in the history
…e. Previously, minimum capacity retirement parameters were not added up and this resulted in the minimum retirement constraints enforcing wrong lower bounds
  • Loading branch information
filippopecci committed Sep 27, 2023
1 parent b7d819a commit fa1fc0f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 29 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- Fix computation of cumulative minimum capacity retirements in multistage GenX (#514)

### Added
- Feature electrolysis basic (#525)
Adds hydrogen electrolyzer model which enables the addition of hydrogen electrolyzer
Expand Down
2 changes: 2 additions & 0 deletions src/case_runners/case_runner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ function run_genx_case_multistage!(case::AbstractString, mysetup::Dict)
inputs_dict[t] = load_inputs(mysetup, inpath_sub)
inputs_dict[t] = configure_multi_stage_inputs(inputs_dict[t],mysetup["MultiStageSettingsDict"],mysetup["NetworkExpansion"])

compute_cumulative_min_retirements!(inputs_dict,t)

# Step 2) Generate model
model_dict[t] = generate_model(mysetup, inputs_dict[t], OPTIMIZER)
end
Expand Down
95 changes: 66 additions & 29 deletions src/multi_stage/endogenous_retirement.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,51 @@ function get_retirement_stage(cur_stage::Int, lifetime::Int, stage_lens::Array{I
return Int(ret_stage)
end

function update_cumulative_min_ret!(inputs_d::Dict,t::Int,Resource_Set::String,dfGen_Name::String,RetCap::Symbol)

CumRetCap = Symbol("Cum_"*String(RetCap));

if !isempty(inputs_d[1][Resource_Set])
if t==1
inputs_d[t][dfGen_Name][!,CumRetCap] = inputs_d[t][dfGen_Name][!,RetCap];
else
inputs_d[t][dfGen_Name][!,CumRetCap] = inputs_d[t-1][dfGen_Name][!,CumRetCap] + inputs_d[t][dfGen_Name][!,RetCap];
end
end

end


function compute_cumulative_min_retirements!(inputs_d::Dict,t::Int)

if isempty(inputs_d[1]["VRE_STOR"])
mytab =[("G","dfGen",:Min_Retired_Cap_MW),
("STOR_ALL","dfGen",:Min_Retired_Energy_Cap_MW),
("STOR_ASYMMETRIC","dfGen",:Min_Retired_Charge_Cap_MW)
]
else
mytab =[("G","dfGen",:Min_Retired_Cap_MW),
("STOR_ALL","dfGen",:Min_Retired_Energy_Cap_MW),
("STOR_ASYMMETRIC","dfGen",:Min_Retired_Charge_Cap_MW),
("VS_DC","dfVRE_STOR",:Min_Retired_Cap_Inverter_MW),
("VS_SOLAR","dfVRE_STOR",:Min_Retired_Cap_Solar_MW),
("VS_WIND","dfVRE_STOR",:Min_Retired_Cap_Wind_MW),
("VS_STOR","dfGen",:Min_Retired_Energy_Cap_MW),
("VS_ASYM_DC_DISCHARGE","dfVRE_STOR",:Min_Retired_Cap_Discharge_DC_MW),
("VS_ASYM_DC_CHARGE","dfVRE_STOR",:Min_Retired_Cap_Charge_DC_MW),
("VS_ASYM_AC_DISCHARGE","dfVRE_STOR",:Min_Retired_Cap_Discharge_AC_MW),
("VS_ASYM_AC_CHARGE","dfVRE_STOR",:Min_Retired_Cap_Charge_AC_MW)
]
end

for (Resource_Set,dfGen_Name,RetCap) in mytab
update_cumulative_min_ret!(inputs_d,t,Resource_Set,dfGen_Name,RetCap)
end


end


function endogenous_retirement!(EP::Model, inputs::Dict, setup::Dict)
multi_stage_settings = setup["MultiStageSettingsDict"]

Expand Down Expand Up @@ -112,9 +157,9 @@ function endogenous_retirement_discharge!(EP::Model, inputs::Dict, num_stages::I
@expression(EP, eNewCapTrack[y in RET_CAP], sum(EP[:vCAPTRACK][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrack[y in RET_CAP],
if y in COMMIT
sum((dfGen[!,Symbol("Min_Retired_Cap_MW")][y]/dfGen[!,:Cap_Size][y]) for p=1:cur_stage)
dfGen[y,:Cum_Min_Retired_Cap_MW]/dfGen[y,:Cap_Size]
else
sum((dfGen[!,Symbol("Min_Retired_Cap_MW")][y]) for p=1:cur_stage)
dfGen[y,:Cum_Min_Retired_Cap_MW]
end
)

Expand Down Expand Up @@ -166,7 +211,7 @@ function endogenous_retirement_charge!(EP::Model, inputs::Dict, num_stages::Int,
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackCharge[y in RET_CAP_CHARGE], sum(EP[:vRETCAPTRACKCHARGE][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackCharge[y in RET_CAP_CHARGE], sum(EP[:vCAPTRACKCHARGE][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackCharge[y in RET_CAP_CHARGE], sum((dfGen[!,Symbol("Min_Retired_Charge_Cap_MW")][y]) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackCharge[y in RET_CAP_CHARGE], dfGen[y,:Cum_Min_Retired_Charge_Cap_MW])

### Constratints ###

Expand Down Expand Up @@ -215,7 +260,7 @@ function endogenous_retirement_energy!(EP::Model, inputs::Dict, num_stages::Int,
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackEnergy[y in RET_CAP_ENERGY], sum(EP[:vRETCAPTRACKENERGY][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackEnergy[y in RET_CAP_ENERGY], sum(EP[:vCAPTRACKENERGY][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackEnergy[y in RET_CAP_ENERGY], sum((dfGen[!,Symbol("Min_Retired_Energy_Cap_MW")][y]) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackEnergy[y in RET_CAP_ENERGY], dfGen[y,:Cum_Min_Retired_Energy_Cap_MW])

### Constratints ###

Expand All @@ -238,11 +283,11 @@ function endogenous_retirement_vre_stor_dc!(EP::Model, inputs::Dict, num_stages:

dfGen = inputs["dfGen"]

dfVRE_STOR = inputs["dfVRE_STOR"];

NEW_CAP_DC = inputs["NEW_CAP_DC"] # Set of all resources eligible for new capacity
RET_CAP_DC = inputs["RET_CAP_DC"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -264,7 +309,7 @@ function endogenous_retirement_vre_stor_dc!(EP::Model, inputs::Dict, num_stages:
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackDC[y in RET_CAP_DC], sum(EP[:vRETCAPTRACKDC][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackDC[y in RET_CAP_DC], sum(EP[:vCAPTRACKDC][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackDC[y in RET_CAP_DC], sum((by_rid(y,Symbol("Min_Retired_Cap_Inverter_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackDC[y in RET_CAP_DC], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Inverter_MW])

### Constraints ###

Expand All @@ -286,12 +331,11 @@ function endogenous_retirement_vre_stor_solar!(EP::Model, inputs::Dict, num_stag
println("Endogenous Retirement (VRE-Storage Solar) Module")

dfGen = inputs["dfGen"]
dfVRE_STOR = inputs["dfVRE_STOR"];

NEW_CAP_SOLAR = inputs["NEW_CAP_SOLAR"] # Set of all resources eligible for new capacity
RET_CAP_SOLAR = inputs["RET_CAP_SOLAR"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -313,7 +357,7 @@ function endogenous_retirement_vre_stor_solar!(EP::Model, inputs::Dict, num_stag
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackSolar[y in RET_CAP_SOLAR], sum(EP[:vRETCAPTRACKSOLAR][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackSolar[y in RET_CAP_SOLAR], sum(EP[:vCAPTRACKSOLAR][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackSolar[y in RET_CAP_SOLAR], sum((by_rid(y,Symbol("Min_Retired_Cap_Solar_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackSolar[y in RET_CAP_SOLAR], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Solar_MW])

### Constraints ###

Expand All @@ -335,12 +379,11 @@ function endogenous_retirement_vre_stor_wind!(EP::Model, inputs::Dict, num_stage
println("Endogenous Retirement (VRE-Storage Wind) Module")

dfGen = inputs["dfGen"]
dfVRE_STOR = inputs["dfVRE_STOR"];

NEW_CAP_WIND = inputs["NEW_CAP_WIND"] # Set of all resources eligible for new capacity
RET_CAP_WIND = inputs["RET_CAP_WIND"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -362,7 +405,7 @@ function endogenous_retirement_vre_stor_wind!(EP::Model, inputs::Dict, num_stage
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackWind[y in RET_CAP_WIND], sum(EP[:vRETCAPTRACKWIND][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackWind[y in RET_CAP_WIND], sum(EP[:vCAPTRACKWIND][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackWind[y in RET_CAP_WIND], sum((by_rid(y,Symbol("Min_Retired_Cap_Wind_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackWind[y in RET_CAP_WIND], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Wind_MW])

### Constraints ###

Expand Down Expand Up @@ -409,7 +452,7 @@ function endogenous_retirement_vre_stor_stor!(EP::Model, inputs::Dict, num_stage
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackEnergy_VS[y in RET_CAP_STOR], sum(EP[:vRETCAPTRACKENERGY_VS][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackEnergy_VS[y in RET_CAP_STOR], sum(EP[:vCAPTRACKENERGY_VS][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackEnergy_VS[y in RET_CAP_STOR], sum((dfGen[!,Symbol("Min_Retired_Energy_Cap_MW")][y]) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackEnergy_VS[y in RET_CAP_STOR], dfGen[y,:Cum_Min_Retired_Energy_Cap_MW])

### Constratints ###

Expand All @@ -432,11 +475,11 @@ function endogenous_retirement_vre_stor_discharge_dc!(EP::Model, inputs::Dict, n

dfGen = inputs["dfGen"]

dfVRE_STOR = inputs["dfVRE_STOR"]

NEW_CAP_DISCHARGE_DC = inputs["NEW_CAP_DISCHARGE_DC"] # Set of all resources eligible for new capacity
RET_CAP_DISCHARGE_DC = inputs["RET_CAP_DISCHARGE_DC"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -458,7 +501,7 @@ function endogenous_retirement_vre_stor_discharge_dc!(EP::Model, inputs::Dict, n
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackDischargeDC[y in RET_CAP_DISCHARGE_DC], sum(EP[:vRETCAPTRACKDISCHARGEDC][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackDischargeDC[y in RET_CAP_DISCHARGE_DC], sum(EP[:vCAPTRACKDISCHARGEDC][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackDischargeDC[y in RET_CAP_DISCHARGE_DC], sum((by_rid(y,Symbol("Min_Retired_Cap_Discharge_DC_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackDischargeDC[y in RET_CAP_DISCHARGE_DC], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Discharge_DC_MW])

### Constraints ###

Expand All @@ -480,12 +523,10 @@ function endogenous_retirement_vre_stor_charge_dc!(EP::Model, inputs::Dict, num_
println("Endogenous Retirement (VRE-Storage Charge DC) Module")

dfGen = inputs["dfGen"]

dfVRE_STOR = inputs["dfVRE_STOR"];
NEW_CAP_CHARGE_DC = inputs["NEW_CAP_CHARGE_DC"] # Set of all resources eligible for new capacity
RET_CAP_CHARGE_DC = inputs["RET_CAP_CHARGE_DC"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -507,7 +548,7 @@ function endogenous_retirement_vre_stor_charge_dc!(EP::Model, inputs::Dict, num_
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackChargeDC[y in RET_CAP_CHARGE_DC], sum(EP[:vRETCAPTRACKCHARGEDC][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackChargeDC[y in RET_CAP_CHARGE_DC], sum(EP[:vCAPTRACKCHARGEDC][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackChargeDC[y in RET_CAP_CHARGE_DC], sum((by_rid(y,Symbol("Min_Retired_Cap_Charge_DC_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackChargeDC[y in RET_CAP_CHARGE_DC], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Charge_DC_MW])

### Constraints ###

Expand All @@ -529,12 +570,10 @@ function endogenous_retirement_vre_stor_discharge_ac!(EP::Model, inputs::Dict, n
println("Endogenous Retirement (VRE-Storage Discharge AC) Module")

dfGen = inputs["dfGen"]

dfVRE_STOR = inputs["dfVRE_STOR"];
NEW_CAP_DISCHARGE_AC = inputs["NEW_CAP_DISCHARGE_AC"] # Set of all resources eligible for new capacity
RET_CAP_DISCHARGE_AC = inputs["RET_CAP_DISCHARGE_AC"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -556,7 +595,7 @@ function endogenous_retirement_vre_stor_discharge_ac!(EP::Model, inputs::Dict, n
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackDischargeAC[y in RET_CAP_DISCHARGE_AC], sum(EP[:vRETCAPTRACKDISCHARGEAC][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackDischargeAC[y in RET_CAP_DISCHARGE_AC], sum(EP[:vCAPTRACKDISCHARGEAC][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackDischargeAC[y in RET_CAP_DISCHARGE_AC], sum((by_rid(y,Symbol("Min_Retired_Cap_Discharge_AC_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackDischargeAC[y in RET_CAP_DISCHARGE_AC], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Discharge_AC_MW])

### Constraints ###

Expand All @@ -578,12 +617,10 @@ function endogenous_retirement_vre_stor_charge_ac!(EP::Model, inputs::Dict, num_
println("Endogenous Retirement (VRE-Storage Charge AC) Module")

dfGen = inputs["dfGen"]

dfVRE_STOR = inputs["dfVRE_STOR"]
NEW_CAP_CHARGE_AC = inputs["NEW_CAP_CHARGE_AC"] # Set of all resources eligible for new capacity
RET_CAP_CHARGE_AC = inputs["RET_CAP_CHARGE_AC"] # Set of all resources eligible for capacity retirements

by_rid(rid, sym) = by_rid_df(rid, sym, inputs["dfVRE_STOR"])

### Variables ###

# Keep track of all new and retired capacity from all stages
Expand All @@ -605,7 +642,7 @@ function endogenous_retirement_vre_stor_charge_ac!(EP::Model, inputs::Dict, num_
# Construct and add the endogenous retirement constraint expressions
@expression(EP, eRetCapTrackChargeAC[y in RET_CAP_CHARGE_AC], sum(EP[:vRETCAPTRACKCHARGEAC][y,p] for p=1:cur_stage))
@expression(EP, eNewCapTrackChargeAC[y in RET_CAP_CHARGE_AC], sum(EP[:vCAPTRACKCHARGEAC][y,p] for p=1:get_retirement_stage(cur_stage, dfGen[!,:Lifetime][y], stage_lens)))
@expression(EP, eMinRetCapTrackChargeAC[y in RET_CAP_CHARGE_AC], sum((by_rid(y,Symbol("Min_Retired_Cap_Charge_AC_MW"))) for p=1:cur_stage))
@expression(EP, eMinRetCapTrackChargeAC[y in RET_CAP_CHARGE_AC], dfVRE_STOR[y,:Cum_Min_Retired_Cap_Charge_AC_MW])

### Constraints ###

Expand Down

0 comments on commit fa1fc0f

Please sign in to comment.