Skip to content

Commit

Permalink
Add Endogenous Retirements to Temoa (#48)
Browse files Browse the repository at this point in the history
This commit adds an endogenous retirement feature to Temoa.

Users can add a list of technologies for which they would like to enable
endogenous retirements to the 'tech_retirement' set.

Prior to this commit, the decision variables of Temoa were:
- Capacity additions
- Operational decision at the time step level

This commit adds an additional decision variable of
- Retirement decisions

Keep in mind that enabling the endogenous retirement feature will add to model
size, complexity and compute time. As a result, users are advised to only include
technologies for which they explicitly want to enable endogenous retirements to the
'tech_retirement' set.
  • Loading branch information
SutubraResearch authored Sep 14, 2023
1 parent 4412ac0 commit b31be57
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 72 deletions.
35 changes: 34 additions & 1 deletion data_files/temoa_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ CREATE TABLE IF NOT EXISTS "tech_groups" (
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
FOREIGN KEY("group_name") REFERENCES "groups"("group_name")
);
CREATE TABLE "tech_retirement" (
"tech" text,
"notes" TEXT,
PRIMARY KEY("tech"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);
CREATE TABLE "sector_labels" (
"sector" text,
PRIMARY KEY("sector")
Expand Down Expand Up @@ -175,8 +181,21 @@ CREATE TABLE "RampUp" (
PRIMARY KEY("regions", "tech"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);

CREATE TABLE "Output_V_Capacity" (
"regions" text,
"scenario" text,
"sector" text,
"t_periods" integer,
"tech" text,
"vintage" integer,
"capacity" real,
FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
PRIMARY KEY("regions","scenario","t_periods","tech","vintage")
);
CREATE TABLE "Output_V_NewCapacity" (
"regions" text,
"scenario" text,
"sector" text,
Expand All @@ -188,6 +207,20 @@ CREATE TABLE "Output_V_Capacity" (
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods")
);
CREATE TABLE "Output_V_RetiredCapacity" (
"regions" text,
"scenario" text,
"sector" text,
"t_periods" integer,
"tech" text,
"vintage" integer,
"capacity" real,
FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
PRIMARY KEY("regions","scenario","t_periods","tech","vintage")
);
CREATE TABLE "Output_VFlow_Out" (
"regions" text,
"scenario" text,
Expand Down
Binary file modified data_files/temoa_schema.sqlite
Binary file not shown.
40 changes: 37 additions & 3 deletions data_files/temoa_test_system.sql
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ CREATE TABLE "tech_annual" (
PRIMARY KEY("tech"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);
CREATE TABLE "tech_retirement" (
"tech" text,
"notes" TEXT,
PRIMARY KEY("tech"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);
CREATE TABLE "sector_labels" (
"sector" text,
PRIMARY KEY("sector")
Expand Down Expand Up @@ -231,14 +237,42 @@ CREATE TABLE "Output_V_Capacity" (
"regions" text,
"scenario" text,
"sector" text,
"t_periods" integer,
"tech" text,
"vintage" integer,
"capacity" real,
PRIMARY KEY("regions","scenario","tech","vintage"),
FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
PRIMARY KEY("regions","scenario","t_periods","tech","vintage")
);
CREATE TABLE "Output_V_NewCapacity" (
"regions" text,
"scenario" text,
"sector" text,
"tech" text,
"vintage" integer,
"capacity" real,
PRIMARY KEY("regions","scenario","tech","vintage"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods")
);
CREATE TABLE "Output_V_RetiredCapacity" (
"regions" text,
"scenario" text,
"sector" text,
"t_periods" integer,
"tech" text,
"vintage" integer,
"capacity" real,
FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
PRIMARY KEY("regions","scenario","t_periods","tech","vintage")
);
CREATE TABLE "Output_VFlow_Out" (
"regions" text,
"scenario" text,
Expand Down Expand Up @@ -358,7 +392,7 @@ CREATE TABLE "Output_CapacityByPeriodAndTech" (
);
CREATE TABLE "MyopicBaseyear" (
"year" real
"notes" text
"notes" text
);
CREATE TABLE "MinGenGroupWeight" (
"regions" text,
Expand Down Expand Up @@ -1034,7 +1068,7 @@ CREATE TABLE "MaxResource" (
CREATE TABLE "LinkedTechs" (
"primary_region" text,
"primary_tech" text,
"emis_comm" text,
"emis_comm" text,
"linked_tech" text,
"tech_linked_notes" text,
FOREIGN KEY("primary_tech") REFERENCES "technologies"("tech"),
Expand Down
Binary file modified data_files/temoa_test_system.sqlite
Binary file not shown.
36 changes: 35 additions & 1 deletion data_files/temoa_utopia.sql
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ CREATE TABLE "tech_annual" (
PRIMARY KEY("tech"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);
CREATE TABLE "tech_retirement" (
"tech" text,
"notes" TEXT,
PRIMARY KEY("tech"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);
CREATE TABLE "sector_labels" (
"sector" text,
PRIMARY KEY("sector")
Expand Down Expand Up @@ -210,13 +216,41 @@ CREATE TABLE "Output_V_Capacity" (
"regions" text,
"scenario" text,
"sector" text,
"t_periods" integer,
"tech" text,
"vintage" integer,
"capacity" real,
FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
PRIMARY KEY("regions","scenario","t_periods","tech","vintage")
);
CREATE TABLE "Output_V_NewCapacity" (
"regions" text,
"scenario" text,
"sector" text,
"tech" text,
"vintage" integer,
"capacity" real,
PRIMARY KEY("regions","scenario","tech","vintage"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods")
);
CREATE TABLE "Output_V_RetiredCapacity" (
"regions" text,
"scenario" text,
"sector" text,
"t_periods" integer,
"tech" text,
"vintage" integer,
"capacity" real,
FOREIGN KEY("t_periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("sector") REFERENCES "sector_labels"("sector"),
PRIMARY KEY("regions","scenario","tech","vintage")
FOREIGN KEY("vintage") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
PRIMARY KEY("regions","scenario","t_periods","tech","vintage")
);
CREATE TABLE "Output_VFlow_Out" (
"regions" text,
Expand Down
Binary file modified data_files/temoa_utopia.sqlite
Binary file not shown.
48 changes: 37 additions & 11 deletions temoa_model/pformat_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,16 +235,40 @@ def collect_result_data( cgroup, clist, epsilon):

# Extract optimal decision variable values related to capacity:
if hasattr(options, 'file_location') and os.path.join('temoa_model', 'config_sample_myopic') not in options.file_location:
for r, t, v in m.V_Capacity:
val = value( m.V_Capacity[r, t, v] )
for r, p, t, v in m.V_Capacity:
val = value( m.V_Capacity[r, p, t, v] )
if abs(val) < capacity_epsilon: continue
svars['V_Capacity'][r, t, v] = val
svars['V_Capacity'][r, p, t, v] = val
else:
for r, t, v in m.V_Capacity:
for r, p, t, v in m.V_Capacity:
if p in m.time_optimize:
val = value( m.V_Capacity[r, p, t, v] )
if abs(val) < capacity_epsilon: continue
svars['V_Capacity'][r, p, t, v] = val

if hasattr(options, 'file_location') and os.path.join('temoa_model', 'config_sample_myopic') not in options.file_location:
for r, t, v in m.V_NewCapacity:
val = value( m.V_NewCapacity[r, t, v] )
if abs(val) < capacity_epsilon: continue
svars['V_NewCapacity'][r, t, v] = val
else:
for r, t, v in m.V_NewCapacity:
if v in m.time_optimize:
val = value( m.V_Capacity[r, t, v] )
val = value( m.V_NewCapacity[r, t, v] )
if abs(val) < capacity_epsilon: continue
svars['V_NewCapacity'][r, t, v] = val

if hasattr(options, 'file_location') and os.path.join('temoa_model', 'config_sample_myopic') not in options.file_location:
for r, p, t, v in m.V_RetiredCapacity:
val = value( m.V_RetiredCapacity[r, p, t, v] )
if abs(val) < capacity_epsilon: continue
svars['V_RetiredCapacity'][r, p, t, v] = val
else:
for r, p, t, v in m.V_RetiredCapacity:
if p in m.time_optimize:
val = value( m.V_RetiredCapacity[r, p, t, v] )
if abs(val) < capacity_epsilon: continue
svars['V_Capacity'][r, t, v] = val
svars['V_RetiredCapacity'][r, p, t, v] = val

for r, p, t in m.V_CapacityAvailableByPeriodAndTech:
val = value( m.V_CapacityAvailableByPeriodAndTech[r, p, t] )
Expand All @@ -260,7 +284,7 @@ def collect_result_data( cgroup, clist, epsilon):

for r, t, v in m.CostInvest.sparse_iterkeys(): # Returns only non-zero values

icost = value( m.V_Capacity[r, t, v] )
icost = value( m.V_NewCapacity[r, t, v] )
if abs(icost) < epsilon: continue
icost *= value( m.CostInvest[r, t, v] )*(
(
Expand All @@ -281,7 +305,7 @@ def collect_result_data( cgroup, clist, epsilon):


for r, p, t, v in m.CostFixed.sparse_iterkeys():
fcost = value( m.V_Capacity[r, t, v] )
fcost = value( m.V_Capacity[r, p, t, v] )
if abs(fcost) < epsilon: continue

fcost *= value( m.CostFixed[r, p, t, v] )
Expand Down Expand Up @@ -332,11 +356,11 @@ def collect_result_data( cgroup, clist, epsilon):
# assumption 3: Unlike other output tables in which Ri-Rj and Rj-Ri entries
# are allowed in the region column, for the Output_Costs table the region
#to the right of the hyphen sign gets the costs.
for i in m.RegionalExchangeCapacityConstraint_rrtv.iterkeys():
for i in m.RegionalExchangeCapacityConstraint_rrptv.iterkeys():
reg_dir1 = i[0]+"-"+i[1]
reg_dir2 = i[1]+"-"+i[0]
tech = i[2]
vintage = i[3]
tech = i[3]
vintage = i[4]
key = (reg_dir1, tech, vintage)
try:
act_dir1 = value (sum(m.V_FlowOut[reg_dir1, p, s, d, S_i, tech, vintage, S_o]
Expand Down Expand Up @@ -429,6 +453,8 @@ def make_var_list ( variables ):
"V_FlowOut" : "Output_VFlow_Out", \
"V_Curtailment" : "Output_Curtailment", \
"V_Capacity" : "Output_V_Capacity", \
"V_NewCapacity" : "Output_V_NewCapacity", \
"V_RetiredCapacity" : "Output_V_RetiredCapacity", \
"V_CapacityAvailableByPeriodAndTech" : "Output_CapacityByPeriodAndTech", \
"V_EmissionActivityByPeriodAndProcess" : "Output_Emissions", \
"Objective" : "Output_Objective", \
Expand Down
3 changes: 3 additions & 0 deletions temoa_model/temoa_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ def query_table (t_properties, f):
['set', 'tech_groups', '', '', 2],
['set', 'tech_annual', '', '', 0],
['set', 'tech_variable', '', '', 0],
['set', 'tech_retirement', '', '', 0],
['set', 'groups', '', '', 0],
['param','LinkedTechs', '', '', 3],
['param','SegFrac', '', '', 2],
Expand Down Expand Up @@ -211,6 +212,8 @@ def query_table (t_properties, f):
cur.execute("DELETE FROM Output_VFlow_In WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("DELETE FROM Output_VFlow_Out WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("DELETE FROM Output_V_Capacity WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("DELETE FROM Output_V_NewCapacity WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("DELETE FROM Output_V_RetiredCapacity WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("DELETE FROM Output_Curtailment WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("DELETE FROM Output_Duals WHERE scenario="+"'"+str(options.scenario)+"'")
cur.execute("VACUUM")
Expand Down
12 changes: 11 additions & 1 deletion temoa_model/temoa_initialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,16 @@ def LifetimeLoanProcessIndices ( M ):
def CapacityVariableIndices ( M ):
return M.activeCapacity_rtv

def RetiredCapacityVariableIndices ( M ):
return set(
(r, p, t, v)

for r,p,t in M.processVintages.keys()
if t in M.tech_retirement
for v in M.processVintages[ r, p, t ]
if p > v
)

def CapacityAvailableVariableIndices ( M ):
return M.activeCapacityAvailable_rpt

Expand Down Expand Up @@ -1071,7 +1081,7 @@ def BaseloadDiurnalConstraintIndices ( M ):

def RegionalExchangeCapacityConstraintIndices ( M ):
indices = set(
(r_e, r_i, t, v)
(r_e, r_i, p, t, v)

for r_e, p, i in M.exportRegions.keys()
for r_i, t, v, o in M.exportRegions[r_e, p, i]
Expand Down
25 changes: 16 additions & 9 deletions temoa_model/temoa_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def temoa_create_model(name="Temoa"):
M.tech_groups = Set(within=M.RegionalIndices * M.groups * M.tech_all)
M.tech_annual = Set(within=M.tech_all) # Define techs with constant output
M.tech_variable = Set(within=M.tech_all) # Define techs for use with TechInputSplitAverage constraint, where techs have variable annual output but the user wishes to constrain them annually
M.tech_retirement = Set(within=M.tech_all) # Define techs for which economic retirement is an option

# Define commodity-related sets
M.commodity_demand = Set()
Expand Down Expand Up @@ -285,8 +286,14 @@ def temoa_create_model(name="Temoa"):

# Derived decision variables

M.CapacityVar_rtv = Set(dimen=3, initialize=CapacityVariableIndices)
M.V_Capacity = Var(M.CapacityVar_rtv, domain=NonNegativeReals)
M.CapacityVar_rptv = Set(dimen=4, initialize=CostFixedIndices)
M.V_Capacity = Var(M.CapacityVar_rptv, domain=NonNegativeReals)

M.NewCapacityVar_rtv = Set(dimen=3, initialize=CapacityVariableIndices)
M.V_NewCapacity = Var(M.NewCapacityVar_rtv, domain=NonNegativeReals, initialize=0)

M.RetiredCapacityVar_rptv = Set(dimen=4, initialize=RetiredCapacityVariableIndices)
M.V_RetiredCapacity = Var(M.RetiredCapacityVar_rptv, domain=NonNegativeReals, initialize=0)

M.CapacityAvailableVar_rpt = Set(
dimen=3, initialize=CapacityAvailableVariableIndices
Expand Down Expand Up @@ -322,11 +329,11 @@ def temoa_create_model(name="Temoa"):
M.CapacityAvailableVar_rpt, rule=CapacityAvailableByPeriodAndTech_Constraint
)

M.ExistingCapacityConstraint_rtv = Set(
dimen=3, initialize=lambda M: M.ExistingCapacity.sparse_iterkeys()
M.RetiredCapacityConstraint = Constraint(
M.RetiredCapacityVar_rptv, rule=RetiredCapacity_Constraint
)
M.ExistingCapacityConstraint = Constraint(
M.ExistingCapacityConstraint_rtv, rule=ExistingCapacity_Constraint
M.AdjustedCapacityConstraint = Constraint(
M.CostFixed_rptv, rule=AdjustedCapacity_Constraint
)

# Declare core model constraints that ensure proper system functioning
Expand Down Expand Up @@ -370,11 +377,11 @@ def temoa_create_model(name="Temoa"):
M.BaseloadDiurnalConstraint_rpsdtv, rule=BaseloadDiurnal_Constraint
)

M.RegionalExchangeCapacityConstraint_rrtv = Set(
dimen=4, initialize=RegionalExchangeCapacityConstraintIndices
M.RegionalExchangeCapacityConstraint_rrptv = Set(
dimen=5, initialize=RegionalExchangeCapacityConstraintIndices
)
M.RegionalExchangeCapacityConstraint = Constraint(
M.RegionalExchangeCapacityConstraint_rrtv, rule=RegionalExchangeCapacity_Constraint)
M.RegionalExchangeCapacityConstraint_rrptv, rule=RegionalExchangeCapacity_Constraint)

# This set works for all the storage-related constraints
M.StorageConstraints_rpsdtv = Set(dimen=6, initialize=StorageVariableIndices)
Expand Down
Loading

0 comments on commit b31be57

Please sign in to comment.