From c064d2d5418e0b4d27e7cc33b7fdd642f4fab31e Mon Sep 17 00:00:00 2001 From: Cameron Wade Date: Fri, 18 Aug 2023 10:13:04 -0300 Subject: [PATCH 1/2] Add Min/MaxNewCapacity Constraint. This constraint allows the model user to define maximum and/or minimum new capacity for a given technology in a given year. --- data_files/temoa_schema.sql | 26 +++++++++++++++++++-- temoa_model/temoa_config.py | 4 +++- temoa_model/temoa_model.py | 44 ++++++++++++++++++++++++------------ temoa_model/temoa_rules.py | 45 ++++++++++++++++++++++++++++--------- 4 files changed, 92 insertions(+), 27 deletions(-) diff --git a/data_files/temoa_schema.sql b/data_files/temoa_schema.sql index 6d9f9471..a1a4d328 100644 --- a/data_files/temoa_schema.sql +++ b/data_files/temoa_schema.sql @@ -297,7 +297,7 @@ CREATE TABLE "Output_CapacityByPeriodAndTech" ( ); CREATE TABLE "MyopicBaseyear" ( "year" real - "notes" text + "notes" text ); CREATE TABLE "MinGenGroupWeight" ( "regions" text, @@ -326,6 +326,17 @@ CREATE TABLE "MinCapacity" ( FOREIGN KEY("tech") REFERENCES "technologies"("tech"), FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods") ); +CREATE TABLE "MinNewCapacity" ( + "regions" text, + "periods" integer, + "tech" text, + "mincap" real, + "mincap_units" text, + "mincap_notes" text, + PRIMARY KEY("regions","periods","tech"), + FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), + FOREIGN KEY("tech") REFERENCES "technologies"("tech") +); CREATE TABLE "MinActivity" ( "regions" text, "periods" integer, @@ -348,6 +359,17 @@ CREATE TABLE "MaxCapacity" ( FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), FOREIGN KEY("tech") REFERENCES "technologies"("tech") ); +CREATE TABLE "MaxNewCapacity" ( + "regions" text, + "periods" integer, + "tech" text, + "maxcap" real, + "maxcap_units" text, + "maxcap_notes" text, + PRIMARY KEY("regions","periods","tech"), + FOREIGN KEY("periods") REFERENCES "time_periods"("t_periods"), + FOREIGN KEY("tech") REFERENCES "technologies"("tech") +); CREATE TABLE "MaxActivity" ( "regions" text, "periods" integer, @@ -582,7 +604,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"), diff --git a/temoa_model/temoa_config.py b/temoa_model/temoa_config.py index 29760d76..87e4790f 100644 --- a/temoa_model/temoa_config.py +++ b/temoa_model/temoa_config.py @@ -146,6 +146,8 @@ def query_table (t_properties, f): ['param','TechInputSplitAverage', '', '', 4], ['param','MinCapacity', '', '', 3], ['param','MaxCapacity', '', '', 3], + ['param', 'MinNewCapacity', '', '', 3], + ['param', 'MaxNewCapacity', '', '', 3], ['param','MaxActivity', '', '', 3], ['param','MinActivity', '', '', 3], ['param','MaxResource', '', '', 2], @@ -507,4 +509,4 @@ def build(self,**kwargs): f.close() sys.stdout = sys.__stdout__ if counter > 0: - sys.stderr.write("\n{} .db DD file(s) converted\n".format(counter)) \ No newline at end of file + sys.stderr.write("\n{} .db DD file(s) converted\n".format(counter)) diff --git a/temoa_model/temoa_model.py b/temoa_model/temoa_model.py index a4c14f06..e1701997 100755 --- a/temoa_model/temoa_model.py +++ b/temoa_model/temoa_model.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Tools for Energy Model Optimization and Analysis (Temoa): +Tools for Energy Model Optimization and Analysis (Temoa): An open source framework for energy systems optimization modeling Copyright (C) 2015, NC State University @@ -16,8 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -A complete copy of the GNU General Public License v2 (GPLv2) is available -in LICENSE.txt. Users uncompressing this from an archive may not have +A complete copy of the GNU General Public License v2 (GPLv2) is available +in LICENSE.txt. Users uncompressing this from an archive may not have received this license file. If not, see . """ @@ -37,12 +37,12 @@ def temoa_create_model(name="Temoa"): M = TemoaModel(name) # --------------------------------------------------------------- - # Define sets. + # Define sets. # Sets are collections of items used to index parameters and variables # --------------------------------------------------------------- # Define time periods - M.time_exist = Set(ordered=True) + M.time_exist = Set(ordered=True) M.time_future = Set(ordered=True) M.time_optimize = Set(ordered=True, initialize=init_set_time_optimize) # Define time period vintages to track capacity installation @@ -58,7 +58,7 @@ def temoa_create_model(name="Temoa"): # Define regions M.regions = Set() - # RegionalIndices is the set of all the possible combinations of interregional + # RegionalIndices is the set of all the possible combinations of interregional # exhanges plus original region indices. If tech_exchange is empty, RegionalIndices =regions. M.RegionalIndices = Set(initialize=CreateRegionalIndices) @@ -126,12 +126,12 @@ def temoa_create_model(name="Temoa"): M.Demand = Param(M.regions, M.time_optimize, M.commodity_demand) M.initialize_Demands = BuildAction(rule=CreateDemands) - + M.ResourceBound = Param(M.regions, M.time_optimize, M.commodity_physical) # Define technology performance parameters M.CapacityToActivity = Param(M.RegionalIndices, M.tech_all, default=1) - + M.ExistingCapacity = Param(M.RegionalIndices, M.tech_all, M.vintage_exist) M.Efficiency = Param( @@ -194,12 +194,12 @@ def temoa_create_model(name="Temoa"): M.Loan_rtv = Set(dimen=3, initialize=lambda M: M.CostInvest.keys()) M.LoanAnnualize = Param(M.Loan_rtv, initialize=ParamLoanAnnualize_rule) - + M.ModelProcessLife_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) M.ModelProcessLife = Param( M.ModelProcessLife_rptv, initialize=ParamModelProcessLife_rule ) - + M.ProcessLifeFrac_rptv = Set(dimen=4, initialize=ModelProcessLifeIndices) M.ProcessLifeFrac = Param( M.ProcessLifeFrac_rptv, initialize=ParamProcessLifeFraction_rule @@ -209,6 +209,8 @@ def temoa_create_model(name="Temoa"): M.RegionalGlobalIndices = Set(initialize=RegionalGlobalInitializedIndices) M.MinCapacity = Param(M.RegionalIndices, M.time_optimize, M.tech_all) M.MaxCapacity = Param(M.RegionalIndices, M.time_optimize, M.tech_all) + M.MinNewCapacity = Param(M.RegionalIndices, M.time_optimize, M.tech_all) + M.MaxNewCapacity = Param(M.RegionalIndices, M.time_optimize, M.tech_all) M.MaxResource = Param(M.RegionalIndices, M.tech_all) M.MinCapacitySum = Param(M.time_optimize) # for techs in tech_capacity M.MaxCapacitySum = Param(M.time_optimize) # for techs in tech_capacity @@ -336,7 +338,7 @@ def temoa_create_model(name="Temoa"): ) M.CommodityBalanceAnnualConstraint = Constraint( M.CommodityBalanceAnnualConstraint_rpc, rule=CommodityBalanceAnnual_Constraint - ) + ) M.ResourceConstraint_rpr = Set( dimen=3, initialize=lambda M: M.ResourceBound.sparse_iterkeys() @@ -461,6 +463,13 @@ def temoa_create_model(name="Temoa"): M.MaxCapacityConstraint_rpt, rule=MaxCapacity_Constraint ) + M.MaxNewCapacityConstraint_rpt = Set( + dimen=3, initialize=lambda M: M.MaxNewCapacity.sparse_iterkeys() + ) + M.MaxNewCapacityConstraint = Constraint( + M.MaxNewCapacityConstraint_rpt, rule=MaxNewCapacity_Constraint + ) + M.MaxResourceConstraint_rt = Set( dimen=2, initialize=lambda M: M.MaxResource.sparse_iterkeys() ) @@ -482,6 +491,13 @@ def temoa_create_model(name="Temoa"): M.MinCapacityConstraint_rpt, rule=MinCapacity_Constraint ) + M.MinNewCapacityConstraint_rpt = Set( + dimen=3, initialize=lambda M: M.MinNewCapacity.sparse_iterkeys() + ) + M.MinNewCapacityConstraint = Constraint( + M.MinNewCapacityConstraint_rpt, rule=MinNewCapacity_Constraint + ) + M.MinCapacitySetConstraint_rp = Set( dimen=2, initialize=lambda M: M.MinCapacitySum.sparse_iterkeys() ) @@ -502,14 +518,14 @@ def temoa_create_model(name="Temoa"): M.TechInputSplitAnnualConstraint = Constraint( M.TechInputSplitAnnualConstraint_rpitv, rule=TechInputSplitAnnual_Constraint ) - + M.TechInputSplitAverageConstraint_rpitv = Set( dimen=5, initialize=TechInputSplitAverageConstraintIndices ) M.TechInputSplitAverageConstraint = Constraint( M.TechInputSplitAverageConstraint_rpitv, rule=TechInputSplitAverage_Constraint ) - + M.TechOutputSplitConstraint_rpsdtvo = Set( dimen=7, initialize=TechOutputSplitConstraintIndices ) @@ -556,4 +572,4 @@ def runModel(): command line as follows: $ python temoa_model/temoa_model.py path/to/dat/file""" dummy = "" # If calling from command line, send empty string - model = runModel() \ No newline at end of file + model = runModel() diff --git a/temoa_model/temoa_rules.py b/temoa_model/temoa_rules.py index 64cd401e..c3c07afb 100644 --- a/temoa_model/temoa_rules.py +++ b/temoa_model/temoa_rules.py @@ -259,8 +259,8 @@ def TotalCost_rule(M): at the global discount rate and technology lifetime. Fourth, loan payments beyond the model time horizon are removed and the lump sum recalculated. The terms used in Steps 3-4 are :math:`\frac{ GDR }{ 1-(1+GDR)^{-LTP_{r,t,v} } }\cdot -\frac{ 1-(1+GDR)^{-LPA_{t,v}} }{ GDR }`. The product simplifies to -:math:`\frac{ 1-(1+GDR)^{-LPA_{r,t,v}} }{ 1-(1+GDR)^{-LTP_{r,t,v}} }`, where +\frac{ 1-(1+GDR)^{-LPA_{t,v}} }{ GDR }`. The product simplifies to +:math:`\frac{ 1-(1+GDR)^{-LPA_{r,t,v}} }{ 1-(1+GDR)^{-LTP_{r,t,v}} }`, where :math:`LPA_{r,t,v}` represents the active lifetime of process t in region r :math:`(r,t,v)` before the end of the model horizon, and :math:`LTP_{r,t,v}` represents the full lifetime of a regional process :math:`(r,t,v)`. Fifth, the lump sum is discounted back to the @@ -539,9 +539,9 @@ def CommodityBalance_Constraint(M, r, p, s, d, c): This constraint also accounts for imports and exports between regions when solving multi-regional systems. The import (:math:`\textbf{FIM}`) and export -(:math:`\textbf{FEX}`) variables are created on-the-fly by summing the +(:math:`\textbf{FEX}`) variables are created on-the-fly by summing the :math:`\textbf{FO}` variables over the appropriate import and export regions, -respectively, which are defined in :code:`temoa_initialize.py` by parsing the +respectively, which are defined in :code:`temoa_initialize.py` by parsing the :code:`tech_exchange` processes. Finally, for commodities that are exclusively produced at a constant annual rate, the @@ -1533,7 +1533,7 @@ def EmissionLimit_Constraint(M, r, p, e): # r can be an individual region (r='US'), or a combination of regions separated by a + (r='Mexico+US+Canada'), or 'global'. # Note that regions!=M.regions. We iterate over regions to find actual_emissions and actual_emissions_annual. - + # if r == 'global', the constraint is system-wide @@ -1812,6 +1812,19 @@ def MinActivityGroup_Constraint(M, p, g): return expr +def MaxNewCapacity_Constraint(M, r, p, t): + r""" +The MaxNewCapacity constraint sets a limit on the maximum newly installed capacity of a +given technology in a given year. Note that the indices for these constraints are region, +period and tech. +.. math:: + :label: MaxNewCapacity + \textbf{CAP}_{r, t, p} \le MAX_{r, p, t} +""" + max_cap = value(M.MaxNewCapacity[r, p, t]) + expr = M.V_Capacity[r, t, p] <= max_cap + return expr + def MaxCapacity_Constraint(M, r, p, t): r""" @@ -1884,6 +1897,19 @@ def MaxCapacitySet_Constraint(M, p): expr = aggcap <= max_cap return expr +def MinNewCapacity_Constraint(M, r, p, t): + r""" +The MinNewCapacity constraint sets a limit on the minimum newly installed capacity of a +given technology in a given year. Note that the indices for these constraints are region, +period, and tech. +.. math:: + :label: MaxMinCapacity + \textbf{CAP}_{r, t, p} \ge MIN_{r, p, t} +""" + min_cap = value(M.MinNewCapacity[r, p, t]) + expr = M.V_Capacity[r, t, p] >= min_cap + return expr + def MinCapacity_Constraint(M, r, p, t): r""" @@ -1968,8 +1994,8 @@ def TechInputSplitAverage_Constraint(M, r, p, i, t, v): producing a single output. Under this constraint, only the technologies with variable output at the timeslice level (i.e., NOT in the :code:`tech_annual` set) are considered. This constraint differs from TechInputSplit as it specifies shares on an annual basis, -so even though it applies to technologies with variable output at the timeslice level, -the constraint only fixes the input shares over the course of a year. +so even though it applies to technologies with variable output at the timeslice level, +the constraint only fixes the input shares over the course of a year. """ inp = sum( @@ -1989,7 +2015,7 @@ def TechInputSplitAverage_Constraint(M, r, p, i, t, v): expr = inp >= M.TechInputSplitAverage[r, p, i, t] * total_inp - return expr + return expr def TechOutputSplit_Constraint(M, r, p, s, d, t, v, o): r""" @@ -2151,7 +2177,7 @@ def LinkedEmissionsTech_Constraint(M, r, p, s, d, t, v, e): in the :code:`LinkedTechs` table. Note that the primary and linked technologies cannot be part of the :code:`tech_annual` set. It is implicit that the primary region corresponds to the linked technology as well. The lifetimes -of the primary and linked technologies should be specified and identical. +of the primary and linked technologies should be specified and identical. """ linked_t = M.LinkedTechs[r, t, e] if (r,t,v) in M.LifetimeProcess.keys() and M.LifetimeProcess[r, linked_t,v] != M.LifetimeProcess[r, t,v]: @@ -2177,4 +2203,3 @@ def LinkedEmissionsTech_Constraint(M, r, p, s, d, t, v, e): expr = -primary_flow == linked_flow return expr - From db753c7cb74a69df50584410336f62dc0f0c0f09 Mon Sep 17 00:00:00 2001 From: Cameron Wade Date: Fri, 18 Aug 2023 10:31:40 -0300 Subject: [PATCH 2/2] Add Min/MaxAnnualCapacityFactor Constraint This constraint allows the user to set minimum and/or maximum annual capacity factors for a given technology. --- data_files/temoa_schema.sql | 26 ++++++++++ temoa_model/temoa_config.py | 6 ++- temoa_model/temoa_model.py | 16 +++++++ temoa_model/temoa_rules.py | 94 +++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 2 deletions(-) diff --git a/data_files/temoa_schema.sql b/data_files/temoa_schema.sql index a1a4d328..7a295795 100644 --- a/data_files/temoa_schema.sql +++ b/data_files/temoa_schema.sql @@ -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, diff --git a/temoa_model/temoa_config.py b/temoa_model/temoa_config.py index 87e4790f..5be85665 100644 --- a/temoa_model/temoa_config.py +++ b/temoa_model/temoa_config.py @@ -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], diff --git a/temoa_model/temoa_model.py b/temoa_model/temoa_model.py index e1701997..95e3c11b 100755 --- a/temoa_model/temoa_model.py +++ b/temoa_model/temoa_model.py @@ -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) @@ -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 ) diff --git a/temoa_model/temoa_rules.py b/temoa_model/temoa_rules.py index c3c07afb..1e512884 100644 --- a/temoa_model/temoa_rules.py +++ b/temoa_model/temoa_rules.py @@ -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"""