Skip to content

Commit

Permalink
Add Min/MaxAnnualCapacityFactor Constraint
Browse files Browse the repository at this point in the history
This constraint allows the user to set minimum and/or maximum
annual capacity factors for a given technology.
  • Loading branch information
SutubraResearch committed Aug 18, 2023
1 parent c064d2d commit db753c7
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 2 deletions.
26 changes: 26 additions & 0 deletions data_files/temoa_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,32 @@ CREATE TABLE "MaxActivity" (
FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech")
);
CREATE TABLE IF NOT EXISTS "MinAnnualCapacityFactor" (
"regions" text,
"periods" integer,
"tech" text,
"output_comm" text,
"min_acf" real CHECK("min_acf" >= 0 AND "min_acf" <= 1),
"source" text,
"min_acf_notes" text,
PRIMARY KEY("regions","periods","tech"),
FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name")
);
CREATE TABLE IF NOT EXISTS "MaxAnnualCapacityFactor" (
"regions" text,
"periods" integer,
"tech" text,
"output_comm" text,
"max_acf" real CHECK("max_acf" >= 0 AND "max_acf" <= 1),
"source" text,
"max_acf_notes" text,
PRIMARY KEY("regions","periods","tech"),
FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"),
FOREIGN KEY("tech") REFERENCES "technologies"("tech"),
FOREIGN KEY("output_comm") REFERENCES "commodities"("comm_name")
);
CREATE TABLE "LifetimeTech" (
"regions" text,
"tech" text,
Expand Down
6 changes: 4 additions & 2 deletions temoa_model/temoa_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,12 @@ def query_table (t_properties, f):
['param','TechInputSplitAverage', '', '', 4],
['param','MinCapacity', '', '', 3],
['param','MaxCapacity', '', '', 3],
['param', 'MinNewCapacity', '', '', 3],
['param', 'MaxNewCapacity', '', '', 3],
['param','MinNewCapacity', '', '', 3],
['param','MaxNewCapacity', '', '', 3],
['param','MaxActivity', '', '', 3],
['param','MinActivity', '', '', 3],
['param','MinAnnualCapacityFactor', '', '', 4],
['param','MaxAnnualCapacityFactor', '', '', 4],
['param','MaxResource', '', '', 2],
['param','GrowthRateMax', '', '', 2],
['param','GrowthRateSeed', '', '', 2],
Expand Down
16 changes: 16 additions & 0 deletions temoa_model/temoa_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ def temoa_create_model(name="Temoa"):
M.MaxCapacitySum = Param(M.time_optimize) # for techs in tech_capacity
M.MaxActivity = Param(M.RegionalGlobalIndices, M.time_optimize, M.tech_all)
M.MinActivity = Param(M.RegionalGlobalIndices, M.time_optimize, M.tech_all)
M.MinAnnualCapacityFactor = Param(M.RegionalGlobalIndices, M.time_optimize, M.tech_all, M.commodity_carrier)
M.MaxAnnualCapacityFactor = Param(M.RegionalGlobalIndices, M.time_optimize, M.tech_all, M.commodity_carrier)
M.GrowthRateMax = Param(M.RegionalIndices, M.tech_all)
M.GrowthRateSeed = Param(M.RegionalIndices, M.tech_all)
M.EmissionLimit = Param(M.RegionalGlobalIndices, M.time_optimize, M.commodity_emissions)
Expand Down Expand Up @@ -505,6 +507,20 @@ def temoa_create_model(name="Temoa"):
M.MinCapacitySetConstraint_rp, rule=MinCapacitySet_Constraint
)

M.MinAnnualCapacityFactorConstraint_rpto = Set(
dimen=4, initialize=lambda M: M.MinAnnualCapacityFactor.sparse_iterkeys()
)
M.MinAnnualCapacityFactorConstraint = Constraint(
M.MinAnnualCapacityFactorConstraint_rpto, rule=MinAnnualCapacityFactor_Constraint
)

M.MaxAnnualCapacityFactorConstraint_rpto = Set(
dimen=4, initialize=lambda M: M.MaxAnnualCapacityFactor.sparse_iterkeys()
)
M.MaxAnnualCapacityFactorConstraint = Constraint(
M.MaxAnnualCapacityFactorConstraint_rpto, rule=MaxAnnualCapacityFactor_Constraint
)

M.TechInputSplitConstraint_rpsditv = Set(
dimen=7, initialize=TechInputSplitConstraintIndices
)
Expand Down
94 changes: 94 additions & 0 deletions temoa_model/temoa_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -1943,6 +1943,100 @@ def MinCapacitySet_Constraint(M, p):
expr = aggcap >= min_cap
return expr

def MinAnnualCapacityFactor_Constraint(M, r, p, t, o):
r"""
The MinAnnualCapacityFactor sets a lower bound on the annual capacity factor
from a specific technology. The first portion of the constraint pertains to
technologies with variable output at the time slice level, and the second portion
pertains to technologies with constant annual output belonging to the
:code:`tech_annual` set.
.. math::
:label: MinAnnualCapacityFactor
\sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \ge MINCF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t}
\forall \{r, p, t, o\} \in \Theta_{\text{MinAnnualCapacityFactor}}
\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge MINCF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t}
\forall \{r, p, t, o \in T^{a}\} \in \Theta_{\text{MinAnnualCapacityFactor}}
"""
# r can be an individual region (r='US'), or a combination of regions separated by comma (r='Mexico,US,Canada'), or 'global'.
# if r == 'global', the constraint is system-wide
if r == 'global':
reg = M.regions
else:
reg = [r]

try:
activity_rpt = sum(
M.V_FlowOut[r, p, s, d, S_i, t, S_v, o]
for r in reg if ',' not in r
for S_v in M.processVintages[r, p, t]
for S_i in M.processInputs[r, p, t, S_v]
for S_o in M.ProcessOutputsByInput[r, p, t, S_v, S_i]
for s in M.time_season
for d in M.time_of_day
)
except:
activity_rpt = sum(
M.V_FlowOutAnnual[r, p, S_i, t, S_v, o]
for r in reg if ',' not in r
for S_v in M.processVintages[r, p, t]
for S_i in M.processInputs[r, p, t, S_v]
for S_o in M.ProcessOutputsByInput[r, p, t, S_v, S_i]
)

max_possible_activity_rpt = M.V_CapacityAvailableByPeriodAndTech[r, p, t] * M.CapacityToActivity[r, t]
min_annual_cf = value(M.MinAnnualCapacityFactor[r, p, t, o])
expr = activity_rpt >= min_annual_cf * max_possible_activity_rpt
return expr


def MaxAnnualCapacityFactor_Constraint(M, r, p, t, o):
r"""
The MaxAnnualCapacityFactor sets an upper bound on the annual capacity factor
from a specific technology. The first portion of the constraint pertains to
technologies with variable output at the time slice level, and the second portion
pertains to technologies with constant annual output belonging to the
:code:`tech_annual` set.
.. math::
:label: MaxAnnualCapacityFactor
\sum_{S,D,I,V,O} \textbf{FO}_{r, p, s, d, i, t, v, o} \le MAXCF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t}
\forall \{r, p, t, o\} \in \Theta_{\text{MaxAnnualCapacityFactor}}
\sum_{I,V,O} \textbf{FOA}_{r, p, i, t, v, o} \ge MAXCF_{r, p, t} * \textbf{CAPAVL}_{r, p, t} * \text{C2A}_{r, t}
\forall \{r, p, t, o \in T^{a}\} \in \Theta_{\text{MaxAnnualCapacityFactor}}
"""
# r can be an individual region (r='US'), or a combination of regions separated by comma (r='Mexico,US,Canada'), or 'global'.
# if r == 'global', the constraint is system-wide
if r == 'global':
reg = M.regions
else:
reg = [r]

try:
activity_rpt = sum(
M.V_FlowOut[r, p, s, d, S_i, t, S_v, o]
for r in reg if ',' not in r
for S_v in M.processVintages[r, p, t]
for S_i in M.processInputs[r, p, t, S_v]
for S_o in M.ProcessOutputsByInput[r, p, t, S_v, S_i]
for s in M.time_season
for d in M.time_of_day
)
except:
activity_rpt = sum(
M.V_FlowOutAnnual[r, p, S_i, t, S_v, o]
for r in reg if ',' not in r
for S_v in M.processVintages[r, p, t]
for S_i in M.processInputs[r, p, t, S_v]
for S_o in M.ProcessOutputsByInput[r, p, t, S_v, S_i]
)

max_possible_activity_rpt = M.V_CapacityAvailableByPeriodAndTech[r, p, t] * M.CapacityToActivity[r, t]
max_annual_cf = value(M.MaxAnnualCapacityFactor[r, p, t, o])
expr = activity_rpt <= max_annual_cf * max_possible_activity_rpt
return expr





def TechInputSplit_Constraint(M, r, p, s, d, i, t, v):
r"""
Expand Down

0 comments on commit db753c7

Please sign in to comment.